权限和linux的capabilities
inux的capabilities有多少个?
如何调用api来设置进程的capabilities?
capability是线程的么?
如何检测进程的对linux内核调用的检测?
如果该进程有多个线程 strace还有用么?
linux 进程通讯有多少种方式?
权限最小化,是让系统更加安全的一条原则,就是让所有进程处于能正常运行,且特权和访问权限是最小的。
且权限最小化,是一个时间比较长的工作,需要对齐各个阶段的目标,才能把这件事做好。
目标当然是1 切换uid,2 降低cap 3 限制文件目录权限。
但是这里各个阶段都是这三个问题,uid&gid,cap,文件目录权限互相糅杂在一起的。、
1 第一阶段,用户id的切换。
原来公司很多业务的进程,都是root起来的。 root是超级用户,需要把这些进程的用户切换成普通用户。
首先从三个地方分析,代码量,这里的代码量着实不多,就是第一从配置文件读取uid,有切换uid gid函数的直接切,没有就自己实现一个,切换uid gid函数到处都有参考代码。然后就是调用函数,切换。代码量至多100以内。
坑,切uid水很深,如果就以为完成了100行左右代码然后就可以切换成功,那就大错特错了。
坑1,切换uid从root到普通用户会导致进程的capablity的p位,e位,a位的丢失,一下子进程降权到几乎为0,系统肯定会挂。
如何解决?只能是使用prctl 函数,设置一个保住p位不丢失的flag,在切换以后马上把cap设置回来。
坑2,把cap设置回来,这里很多人思维都可能默认capablity是进程级别的,其实capablity是线程粒度,同一进程不同线程的cap都不一样,这个时候设置回来的时机要选对,首先是设置回来的时机最好选在进程main函数,开始阶段,什么都没做之前就设置回来。也就是要在主线程把用户uid,gid切换后,再马上把cap给设置回来。
如果在不考虑线程问题,在进程随意选个地方把cap设置回来会有大问题。
坑3,切换uid后,cap的设置问题,在笔者这个工作里,切换uid后设置cap是根据linux的系统的算法来实现的,不是简单的一个赋值行为。
P’(ambient) = (file is privileged) ? 0 : P(ambient)
P'(permitted) = (P(inheritable) & F(inheritable)) |
(F(permitted) & P(bounding)) | P'(ambient)
P'(effective) = F(effective) ? P'(permitted) : P'(ambient)
P'(inheritable) = P(inheritable) [i.e., unchanged]
P'(bounding) = P(bounding) [i.e., unchanged]
这里我大白话解释一下,非常简单。
就是一般设置cap,一般都是这样的一个场景: 管理进程(已经是普通用户)fork一个子进程,子进程然后切换uid,切后设置cap,然后exec()可执行文件变成业务进程。
此时父进程的p位,e位,a位,fork之后完整的给了子进程,子进程切uid后从普通用户到另一个普通用户则丢失e位,然后设置A位,接着执行exec
根据规则1,执行exec后, 我们的可执行文件没有设置文件cap(公司内部文档已说明文件cap是不能设上去),所以A位直接原封不动。
根据规则2,A位原封不动,和可执行文件的文件cap都为0,所以变成, (0 & P-inheritable) | (0 & P-bouding) | P-ambient = P-ambient ,所以P位就被此时A位给赋值了。
根据规则3, A为直接赋值给E位。
最后当你填满所有的坑,把读取uid,gid代码切换uid,gid的上库了,读cap,设置cap的机制也上库了,才能做第一步去root化。
第一阶段切换每个进程用户id,然后把每个进程的cap配高,先完成去root化,后续再慢慢降cap才是可行之路。不能一步登天会出问题。