root linux进程用root权限需要申请capability permissions吗

1585人阅读
Android(3)
SELinux(3)
先结论:Android中的root进程,在使用到capability时,也需要在sepolicy中定义 allow capability规则,以申请capability permissions。
备注:如果不引入SELinux,例如在Ubuntu环境下,capability的主要作用不是对root进程本身直接施加限制,而是:通过授予最小的capability,使需要特权操作的程序,可以在非root状态下完成工作。
在分析AndroidL的sepolicy规则时,我们发现,即使有效集和许可集满装的root进程,也仍需要在规则定义 allow capability权限。
以capability:dac_overrride为例,具有dac_override权限的系统服务主要包括:
ueventd.te(7):allow ueventd self:capability { chown mknod net_admin setgid fsetid sys_rawio dac_override fowner };
zygote.te(7):allow zygote self:capability { dac_override setgid setuid fowner chown };
netd.te(44):allow netd self:capability { dac_override chown fowner };
runas.te(14):dontaudit runas self:capability dac_
vold.te(20):allow vold self:capability { net_admin dac_override mknod sys_admin chown fowner fsetid };
installd.te(6):allow installd self:capability { chown dac_override fowner fsetid setgid setuid };
tee.te(9):allow tee self:capability { dac_override };
我们可以发现,上述申请了dac_override 的域各自对应的进程中,除了installd,其他进程实际上都是root进程。
对于这些由init启动的root进程,实际上,其有效集、许可集的所有bit都是为1的:
CapInh: 0000
CapPrm: 0000001fffffffff
CapEff: 0000001fffffffff
CapBnd: 0000001fffffffff
dac_override提供的是旁路所有DAC检查的能力,普通进程有此能力后就可以访问任意的文件。而对于root进程,天然可以读写任意文件,旁路任意DAC检查,况且其dac_override
也是默认为1的。但是为什么这些进程域还需要额外申请capability:dac_override 了?
难道这些规则是多余的吗?
root进程也需要申请dac_override ?
比较难于理解,但是验证发现的确如此。
你需要将root进程的uid和gid号“去特权化”,不再认为其具有旁路DAC检查的特权。这时候,如果客体的DAC访问掩码设置 并未容许other的访问权限,你就需要为该进程申请dac_override capability了。
root进程pMonitor 希望访问/sys/power/state,其各自的安全标签如下:
u:r:powermanager:s0
/system/usr/bin/pMonitor
-rw-rw—- system
u:object_r:sysfs:s0 state
虽然已经定义了powermanager域对sysfs的读写规则,但是我们仍观察到如下日志:
22.962939] type=1400 audit(.139:63): avc: denied { dac_override } for pid=634 comm=”pMonitor” capability=1 scontext=u:r:tios_powermanager:s0 tcontext=u:r:tios_powermanager:s0 tclass=capability permissive=1
解决方法很简单,让pMonitor在启动时以system用户启动:
u:r:tios_powermanager:s0
/system/usr/bin/pMonitor
问题解决了
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:30195次
排名:千里之外
原创:16篇
(3)(1)(2)(1)(3)(1)(1)(4)(3)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'一)capability的工具介绍
在我们的试验环境是RHEL6,libcap-2.16软件包中包含了相关的capability设置及查看工作,如下:
rpm -ql libcap-2.16-5.2.el6.i686&
/lib/libcap.so.2
/lib/libcap.so.2.16
/lib/security/pam_cap.so
/usr/sbin/capsh
/usr/sbin/getcap
/usr/sbin/getpcaps
/usr/sbin/setcap
/usr/share/doc/libcap-2.16
/usr/share/doc/libcap-2.16/License
/usr/share/doc/libcap-2.16/capability.notes
/usr/share/man/man8/getcap.8.gz
/usr/share/man/man8/setcap.8.gz
getcap可以获得程序文件所具有的能力(CAP).
getpcaps可以获得进程所具有的能力(CAP).
setcap可以设置程序文件的能力(CAP).
我们下面主要用setcap来进行调试.
二)CAP_CHOWN 0(允许改变文件的所有权)
授权普通用户可以用/bin/chown程序更改任意文件的owner,如下:
setcap cap_chown=eip /bin/chown&
查看/bin/chown程序的能力值,如下:
getcap /bin/chown & & & & & & &&
/bin/chown = cap_chown+eip
切换到test用户,将/bin/ls程序的owner改为test,如下:
chown test.test /bin/ls
ls -l /bin/ls
-rwxr-xr-x. 1 test test 118736 Jun 14 &2010 /bin/ls
1)cap_chown=eip是将chown的能力以cap_effective(e),cap_inheritable(i),cap_permitted(p)三种位图的方式授权给相关的程序文件.
2)如果改变文件名,则能力保留到新文件.
3)用setcap -r /bin/chown可以删除掉文件的能力.
4)重新用setcap授权将覆盖之前的能力.&
三)CAP_DAC_OVERRIDE 1(忽略对文件的所有DAC访问限制)
授权普通用户可以用/usr/bin/vim程序修改所有文件的内容,如下:
setcap cap_dac_override=eip /usr/bin/vim&
切换到普通用户
修改/etc/shadow文件内容
vim /etc/shadow
root:$6$3hJf.BoIVU/cdLKb$JxLXcQScrLS032aFPAQvVc4RzKYNadcIIzxmzAIw.jejrYOHhqdr0oV7sNBL.IhGBo.mMOYEdevlnCp2OGku8.:99:7:::
bin:*:99:7:::
daemon:*:99:7:::
adm:*:99:7:::
DAC_OVERRIDE能力是DAC_READ_SEARCH能力的超集.
四)CAP_DAC_READ_SEARCH 2(忽略所有对读、搜索操作的限制)
授权普通用户可以用/bin/cat程序查看所有文件的内容,如下:
setcap cap_dac_read_search=eip /bin/cat
切换到普通用户
查看/etc/shadow,如下:
cat /etc/shadow
root:$6$3hJf.BoIVU/cdLKb$JxLXcQScrLS032aFPAQvVc4RzKYNadcIIzxmzAIw.jejrYOHhqdr0oV7sNBL.IhGBo.mMOYEdevlnCp2OGku8.:99:7:::
bin:*:99:7:::
daemon:*:99:7:::
adm:*:99:7:::
五)CAP_FOWNER 3(以最后操作的UID,覆盖文件的先前的UID)
cp /etc/passwd /tmp/
ls -l /tmp/passwd &&
-rw-r--r-- 1 root root -29 19:21 /tmp/passwd
授权cap_fowner权限给/usr/bin/vim
setcap cap_fowner=eip /usr/bin/vim
切换到test用户
编辑/tmp/passwd文件,存盘退出.
vi /tmp/passwd
修改文件,并保存退出.
查看/tmp/passwd,发现owner已经变成test
-rw-r--r-- 1 test test -29 19:21 /tmp/passwd
六)CAP_FSETID 4(确保在文件被修改后不修改setuid/setgid位)
起因是当文件被修改后,会清除掉文件的setuid/setgid位,而设定CAP_FSETID后将保证setuid/setgid位不被清除.但这对chown函数无用.
测试程序如下:
#include &sys/types.h&
#include &sys/types.h&
#include &sys/stat.h&
#include &fcntl.h&
#include &sys/stat.h&
#include &stdio.h&
#include &stdlib.h&
#include &string.h&
&& & & &char string[40];
&& & & &int length,
&& & & &if ((handle = open(&/tmp/passwd&, O_WRONLY | O_CREAT | O_TRUNC,S_IREAD | S_IWRITE)) == -1)
&& & & & & & & &printf(&Error opening file.\n&);
&& & & & & & & &exit(1);
&& & & &strcpy(string, &Hello, world!\n&);
&& & & &length = strlen(string);
&& & & &if ((res = write(handle, string, length)) != length)
&& & & & & & & &printf(&Error writing to the file.\n&);
&& & & & & & & &exit(1);
&& & & &printf(&Wrote %d bytes to the file.\n&, res);
&& & & &close(handle);
gcc fsetid.c -o fsetid
先测试没有设FSETID的情况,如下:
chmod 6777 /tmp/passwd
ls -l /tmp/passwd
-rwsrwsrwx 1 test test 14
14:22 /tmp/passwd
/tmp/fsetid&
Wrote 14 bytes to the file.
ls -l /tmp/passwd
-rwxrwxrwx 1 test test 14
14:25 /tmp/passwd
我们看到setuid/setgid位被清除了.
下面是设定FSETID,如下:
chmod 6777 /tmp/passwd
ls -l /tmp/passwd & &&
-rwsrwsrwx 1 test test 14
14:25 /tmp/passwd
切换到root用户,给/tmp/fsetid程序授权CAP_FSETID能力,如下:
setcap cap_fsetid=eip /tmp/fsetid
切换到普通用户
/tmp/fsetid
Wrote 14 bytes to the file.
ls -l /tmp/passwd
-rwsrwsrwx 1 test test 14
14:28 /tmp/passwd
七)CAP_KILL 5 (允许对不属于自己的进程发送信号)
我们先模拟没有加CAP_KILL能力的情况,如下:
终端1,用root用户启用top程序,如下:
终端2,用test用户kill之前的top进程,如下:
pgrep top & &&
/bin/kill 3114
kill: Operation not permitted
我们发现无法对不属于自己的进程发送信号.
下面我们用CAP_KILL能力的程序向不属于自己的进程发送信号,如下:
设定kill命令的kill位,如下:
setcap cap_kill=eip /bin/kill&
杀掉3114进程,没有问题,如下:
/bin/kill 3114
普通用户要用/bin/kill这种绝对路径的方式,而不能用kill这种方式.
八)CAP_SETGID 6 (设定程序允许普通用户使用setgid函数,这与文件的setgid权限位无关)
cp /etc/shadow /tmp/
chown root.root /tmp/shadow
chmod 640 /tmp/shadow
切换到普通用户test,并编写setgid测试程序,如下:
#include &unistd.h&
&& & & &gid_t gid = 0;
&& & & &setgid(gid);
&& & & &system(&/bin/cat /tmp/shadow&);
&& & & &return 0;
gcc setgid.c -o setgid
更改setgid程序为CAP_SETGID
setcap cap_setgid=eip /tmp/setgid
切换到普通用户,运行/tmp/setgid程序,如下:
/tmp/setgid&
root:$1$S9AmPHY8$ZIdORp6aLnYleb5EORxw8/:99:7:::
daemon:*:99:7:::
bin:*:99:7:::
sys:*:99:7:::
sync:*:99:7:::
games:*:99:7:::
man:*:99:7:::
lp:*:99:7:::
mail:*:99:7:::
news:*:99:7:::
uucp:*:99:7:::
proxy:*:99:7:::
www-data:*:99:7:::
backup:*:99:7:::
list:*:99:7:::
我们看到普通用户可以查看/tmp/shadow文件,而取消CAP_SETGID则使程序不能拥有setgid的权限,如下:
setcap -r /tmp/setgid
/tmp/setgid&
/bin/cat: /tmp/shadow: Permission denied
九)CAP_SETUID 7 (设定程序允许普通用户使用setuid函数,这也文件的setuid权限位无关)
cp /etc/shadow /tmp/
chown root.root /tmp/shadow
chmod 640 /tmp/shadow
切换到普通用户test,并编写setuid测试程序,如下:
vi setuid.c
#include &unistd.h&
&& & & &uid_t uid = 0;
&& & & &setuid(uid);
&& & & &system(&/bin/cat /tmp/shadow&);
&& & & &return 0;
gcc setuid.c -o setuid
切换到root用户,更改setuid程序为CAP_SETUID
setcap cap_setuid=eip /tmp/setuid
切换到test用户,运行/tmp/setuid程序,如下:
/tmp/setuid
root:$1$S9AmPHY8$ZIdORp6aLnYleb5EORxw8/:99:7:::
daemon:*:99:7:::
bin:*:99:7:::
sys:*:99:7:::
sync:*:99:7:::
games:*:99:7:::
man:*:99:7:::
lp:*:99:7:::
我们看到普通用户可以查看/tmp/shadow文件,而取消CAP_SETUID则使程序不能拥有setuid的权限,如下:
setcap -r /tmp/setuid
/tmp/setuid&
/bin/cat: /tmp/shadow: Permission denied
十)CAP_SETPCAP 8 (允许向其它进程转移能力以及删除其它进程的任意能力)
事实上只有init进程可以设定其它进程的能力,而其它程序无权对进程授权,root用户也不能对其它进程的能力进行修改,只能对当前进程通过cap_set_proc等函数进行修改,而子进程也会继承这种能力.
所以即使使用了CAP_SETPCAP能力,也不会起到真正的作用.
十一)CAP_LINUX_IMMUTABLE 9 (允许修改文件的不可修改(IMMUTABLE)和只添加(APPEND-ONLY)属性)
普通用户不能通过chattr对文件设置IMMUTABLE(chattr +i)和APPEND-ONLY(chattr +a)权限,而通过CAP_LINUX_IMMUTABLE可以使普通用户通过自己增减(immutable/append-only)权限.
普通用户通过chattr给文件增加immutable权限,如下:
touch /tmp/test
chattr +i /tmp/test
chattr: Operation not permitted while setting flags on /tmp/test
我们看到授权失败了,而如果我们对chattr增加了LINUX_IMMUTABLE权限,则可以成功,如下:
此时切换到root用户:
setcap cap_linux_immutable=eip /usr/bin/chattr&
切换到普通用户:
chattr +i /tmp/test
lsattr /tmp/test&
----i-------------- /tmp/test
我们看到授权成功了,注意,这里只能对自己的文件授权(immutable/append-only)权限,对于其它用户的权限LINUX_IMMUTABLE不起作用(root除外),如下:
chattr +i /etc/passwd
chattr: Permission denied while setting flags on /etc/passwd
十二)CAP_NET_BIND_SERVICE 10(允许绑定到小于1024的端口)
普通用户不能通过bind函数绑定小于1024的端口,而root用户可以做到,CAP_NET_BIND_SERVICE的作用就是让普通用户也可以绑端口到1024以下.
普通用户通过nc绑定端口500,如下:
nc -l -p 500
Can't grab 0.0.0.0:500 with bind : Permission denied
增加CAP_NET_BIND_SERVICE能力到nc程序,如下:
setcap cap_net_bind_service=eip /usr/bin/nc
再切换到普通用户,通过nc绑定端口500,如下:
nc -l -p 500
查看该端口:
netstat -tulnp|grep nc
tcp & & & &0 & & &0 0.0.0.0:500 & & & & & & 0.0.0.0:* & & & & & & & LISTEN & & &2523/nc & & &&
十三)CAP_NET_BROADCAST 11(允许网络广播和多播访问)
事实上它并没有被应用,普通用户也可以使用ping -b 192.168.0.255也发送广播包
十四)CAP_NET_ADMIN 12(允许执行网络管理任务:接口,防火墙和路由等)
普通用户不能创建新的网络接口(interface),不能更改ip地址,而CAP_NET_ADMIN可以帮助普通用户完成这项工作,如下:
用普通用户创建新的网卡接口eth0:1失败
/sbin/ifconfig eth0:1 172.16.27.133 netmask 255.255.255.0
SIOCSIFADDR: Permission denied
SIOCSIFFLAGS: Permission denied
SIOCSIFNETMASK: Permission denied
此时我们把CAP_NET_ADMIN能力授权给ifconfig程序,如下:
setcap cap_net_admin=eip /sbin/ifconfig
我们再次用普通用户即可以新建网络接口eth0:1,并可以DOWN掉接口,如下:
/sbin/ifconfig eth0:1 172.16.27.133 netmask 255.255.255.0
/sbin/ifconfig eth0:1
eth0:1 & &Link encap:Ethernet &HWaddr 00:0c:29:f9:5e:06 &
&& & & & &inet addr:172.16.27.133 &Bcast:172.16.27.255 &Mask:255.255.255.0
&& & & & &UP BROADCAST RUNNING MULTICAST &MTU:1500 &Metric:1
&& & & & &Interrupt:18 Base address:0x1080&
/sbin/ifconfig eth0:1 down&
同样CAP_NET_ADMIN可以让普通用户增加/删除路由,如下:
/sbin/route add -host 192.168.27.139 gw 192.168.27.2
SIOCADDRT: Operation not permitted
授权NET_ADMIN,如下:
setcap cap_net_admin=eip /sbin/route
再次用普通用户增加路由,如下:
/sbin/route add -host 192.168.27.139 gw 192.168.27.2
/sbin/route &-n
Kernel IP routing table
Destination & & Gateway & & & & Genmask & & & & Flags Metric Ref & &Use Iface
192.168.27.139 &192.168.27.2 & &255.255.255.255 UGH & 0 & & &0 & & & &0 eth0
192.168.27.0 & &0.0.0.0 & & & & 255.255.255.0 & U & & 0 & & &0 & & & &0 eth0
0.0.0.0 & & & & 192.168.27.2 & &0.0.0.0 & & & & UG & &0 & & &0 & & & &0 eth0
/sbin/route del -host 192.168.27.139 gw 192.168.27.2 &&
我们看到我们除了可以增加路由之外,也可以删除路由.
最后NET_ADMIN可以帮助我们让普通用户来管理防火墙.
普通用户不能用iptables来管理防火墙,如下:
/sbin/iptables -L -n
iptables v1.4.2: can't initialize iptables table `filter': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.
我们将CAP_NET_ADMIN授权给iptables程序,注意我们也要将CAP_NET_RAW授权给iptables,CAP_NET_RAW我们后面再解释,如下:
setcap cap_net_admin,cap_net_raw=eip /sbin/iptables-multi
此时就可以用普通用户来管理防火墙了,如下:
/sbin/iptables -A INPUT -p tcp -j ACCEPT
/sbin/iptables -L -n
Chain INPUT (policy ACCEPT)
target & & prot opt source & & & & & & & destination & & & &&
ACCEPT & & tcp &-- &0.0.0.0/0 & & & & & &0.0.0.0/0 & & & & &&
Chain FORWARD (policy ACCEPT)
target & & prot opt source & & & & & & & destination & & & &&
Chain OUTPUT (policy ACCEPT)
target & & prot opt source & & & & & & & destination & &&
我们也可以删除防火墙策略,并清空当前的数据流量,如下:
/sbin/iptables -F
/sbin/iptables -Z
/sbin/iptables -X
十五)CAP_NET_RAW 13 (允许使用原始(raw)套接字)
原始套接字编程可以接收到本机网卡上的数据帧或者数据包,对监控网络流量和分析是很有作用的.
最常见的就是ping的实现,如下:
socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3
我们先把ping的setuid权限去掉
chmod u-s /bin/ping
ls -l /bin/ping
-rwxr-xr-x 1 root root -12-09 23:03 /bin/ping
用普通用户使用ping
ping &192.168.27.2 &
ping: icmp open socket: Operation not permitted
提示没有权限,我们将ping授权CAP_NET_RAW能力,如下:
setcap cap_net_raw=eip /bin/ping
切换到普通用户再次ping 192.168.27.2,发现可以ping通,如下:
ping &192.168.27.2
PING 192.168.27.2 (192.168.27.2) 56(84) bytes of data.
64 bytes from 192.168.27.2: icmp_seq=1 ttl=128 time=0.266 ms
64 bytes from 192.168.27.2: icmp_seq=2 ttl=128 time=0.280 ms
64 bytes from 192.168.27.2: icmp_seq=3 ttl=128 time=0.319 ms
NET_RAW也同样用于tcpdump/iftop,一个普通用户无法使用tcpdump/iftop,而CAP_NET_RAW可以解决这个问题,方式同ping一样,所以我们不做演示.
十六)CAP_IPC_LOCK 14 (在允许锁定内存片段)
root和普通用户都可以用mlock来锁定内存,区别是root不受ulimit下的锁定内存大小限制,而普通用户会受到影响.
测试程序如下:
#include &stdio.h&
#include &sys/mman.h&
int main(int argc, char* argv[])
&& & & &int array[2048];
&& & & &if (mlock((const void *)array, sizeof(array)) == -1) {
&& & & & & & & &perror(&mlock: &);
&& & & & & & & &return -1;
&& & & &printf(&success to lock stack mem at: %p, len=%zd\n&,
&& & & & & & & & & & & &array, sizeof(array));
&& & & &if (munlock((const void *)array, sizeof(array)) == -1) {
&& & & & & & & &perror(&munlock: &);
&& & & & & & & &return -1;
&& & & &printf(&success to unlock stack mem at: %p, len=%zd\n&,
&& & & & & & & & & & & &array, sizeof(array));
&& & & &return 0;
gcc mlock.c -o mlock
切换到普通用户,我们看到mlock是不受限制
max locked memory & & & (kbytes, -l) unlimited
我们运行程序
success to lock stack mem at: 0xbfd94914, len=8192
success to unlock stack mem at: 0xbfd94914, len=8192
我们将限制改为1KB,再次运行程序,如下:
ulimit -l 1
mlock: : Cannot allocate memory
切换到root用户,将CAP_IPC_LOCK能力授权给mlock测试程序,如下:
setcap cap_ipc_lock=eip /tmp/mlock
用普通用户再次运行程序,执行成功:
success to lock stack mem at: 0xbfec1584, len=8192
success to unlock stack mem at: 0xbfec1584, len=8192
十七)CAP_IPC_OWNER 15 (忽略IPC所有权检查)
这个能力对普通用户有作用,如果用root用户创建共享内存(shmget),权限为600,而普通用户不能读取该段共享内存.
通过CAP_IPC_OWNER可以让普通用户的程序可以读取/更改共享内存.
我们用下面的程序创建共享内存段,并写入0xdeadbeef到共享内存段中.
#include &stdio.h&
#include &string.h&
#include &stdlib.h&
#include &unistd.h&
#include &sys/ipc.h&
#include &sys/shm.h&
#include &sys/wait.h&
void error_out(const char *msg)
&& & & &perror(msg);
&& & & &exit(EXIT_FAILURE);
int main (int argc, char *argv[])
&& & & &key_t mykey = ;
&& & & &const size_t region_size = sysconf(_SC_PAGE_SIZE);
&& & & &int smid = shmget(mykey, region_size, IPC_CREAT|0600);
&& & & &if(smid == -1)
&& & & & & & & &error_out(&shmget&);
&& & & &void *
&& & & &ptr = shmat(smid, NULL, 0);
&& & & &if (ptr == (void *) -1)
&& & & & & & & &error_out(&shmat&);
&& & & &u_long *d = (u_long *)
&& & & &*d = 0
&& & & &printf(&ipc mem %#lx\n&, *(u_long *)ptr);
&& & & &return 0;
gcc test.c -o test -lrt
我们用root用户来执行本程序,创建共享内存,如下:
ipc mem 0xdeadbeef
查看当前的共享内存
------ Shared Memory Segments --------
key & & & &shmid & & &owner & & &perms & & &bytes & & &nattch & & status & & &
0x00bc614e 458752 & & root & & &600 & & & &4096 & & & 0 & & & & & & &
修改程序,将*d = 0改为*d = 0
再编译,用普通用户运行程序,如下:
gcc test.c -o test -lrt
shmget: Permission denied
我们看到没有权限更改共享内存.
用root用户把CAP_IPC_OWNER能力授权给test程序,如下:
setcap cap_ipc_owner=eip /tmp/test
再次用普通用户运行程序test,更改共享内存,如下:
ipc mem 0xffffffff
我们看到修改成功,但要说明CAP_IPC_OWNER不能让进程/程序删除/脱离共享内存
十八)CAP_SYS_MODULE 16 (允许普通用户插入和删除内核模块)
由于普通用户不能插入/删除内核模块,而CAP_SYS_MODULE可以帮助普通用户做到这点
例如,用户test插入内核模块nvram
/sbin/modprobe nvram & & &
FATAL: Error inserting nvram (/lib/modules/2.6.38.4/kernel/drivers/char/nvram.ko): Operation not permitted
系统提示权限不足.
我们把CAP_SYS_MODULE能力授权给modprobe程序,如下:
setcap cap_sys_module=eip /sbin/modprobe
再用普通用户加载内核模块,如下:
/sbin/modprobe nvram
lsmod |grep nvram
nvram & & & & & & & & & 3861 &0&
我们看到可以加载.
同样我们可以将CAP_SYS_MODULE授权给rmmod程序,让其可以删除模块,如下:
setcap cap_sys_module=eip /sbin/rmmod
/sbin/rmmod nvram
lsmod |grep nvram
十九)CAP_SYS_RAWIO 17 (允许用户打开端口,并读取修改端口数据,一般用ioperm/iopl函数)
ioperm只有低端的[0-0x3ff] I/O端口可被设置,且普通用户不能使用.
iopl可以用于所有的65536个端口,因此ioperm相当于iopl调用的一个子集.
下面的程序首先设置0x3FF端口的读写权限,然后读出原先的值,然后将原值的LSB翻转并写回端口,并在此读取端口值.
#include &unistd.h&
#include &sys/io.h&
#define PORT_ADDR 0x3FF
int main(void)
&& & &char port_
&& & &/*set r/w permission of all 65536 ports*/
&& & &ret = iopl(3);
&& & &if(ret & 0){
&& & & & & perror(&iopl set error&);
&& & & & & return 0;
&& & &port_val = inb(PORT_ADDR);
&& & &printf(&Original value of port 0x%x is : %.2x\n&, PORT_ADDR, port_val);
&& & &/*reverse the least significant bit */
&& & &outb(port_val^0x01, PORT_ADDR);
&& & &port_val = inb(PORT_ADDR);
&& & &printf(&Current value of port 0x%x is : %.2x\n&, PORT_ADDR, port_val);
&& & &/*set r/w permission of &all 65536 ports*/
&& & &ret = iopl(0);
&& & &if(ret & 0){
&& & & & & perror(&iopl set error&);
&& & & & & return 0;
&& & &return 0;
gcc iopl.c -o iopl
普通用户运行iopl程序,提示没有权限.
/tmp/iopl&
iopl set error: Operation not permitted
给程序iopl授权CAP_SYS_RAWIO能力,此时普通用户可以执行iopl程序,如下:
setcap cap_sys_rawio=eip /tmp/iopl
/tmp/iopl&
Original value of port 0x3ff is : 01
Current value of port 0x3ff is : 00
/tmp/iopl&
Original value of port 0x3ff is : 00
Current value of port 0x3ff is : 01
二十)CAP_SYS_CHROOT 18 (允许使用chroot()系统调用)
普通用户不能通过chroot系统调用更改程式执行时所参考的根目录位置,而CAP_SYS_CHROOT可以帮助普通用户做到这一点.
普通用户使用chroot,如下:
/usr/sbin/chroot / /bin/bash
/usr/sbin/chroot: cannot change root directory to /: Operation not permitted
通过root授权CAP_SYS_CHROOT能力给chroot程序,如下:
capset cap_sys_chroot=eip /usr/sbin/chroot
普通用户再次用chroot切换根目录,如下:
/usr/sbin/chroot / /bin/sh
二十一)CAP_SYS_PTRACE 19 (允许跟踪任何进程)
普通用户不能跟踪任何进程,不包括它自己的进程,而CAP_SYS_PTRACE可以帮助普通用户跟踪任何进程.
切换到普通用户,跟踪PID1的进程.
strace -p 1
attach: ptrace(PTRACE_ATTACH, ...): Operation not permitted
切换到root用户,将CAP_SYS_PTRACE能力授权给strace程序,用于跟踪进程,如下:
setcap cap_sys_ptrace=eip /usr/bin/strace
切换到普通用户,跟踪PID1的进程,如下:
strace -p 1
Process 1 attached - interrupt to quit
select(11, [10], NULL, NULL, {3, 771381}) = 0 (Timeout)
time(NULL) & & & & & & & & & & & & & & &=
stat64(&/dev/initctl&, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
fstat64(10, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
stat64(&/dev/initctl&, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
select(11, [10], NULL, NULL, {5, 0}) & &= 0 (Timeout)
time(NULL) & & & & & & & & & & & & & & &=
二十二)CAP_SYS_PACCT 20 (允许配置进程记帐process accounting)&
要完成进程记帐,要保证有写入文件的权限,这里我们将进程记录写入到/home/test/log/psacct.
mkdir /home/test/log/
touch /home/test/log/psacct
程序通过acct函数,将进程的记帐写入到指定文件中,如果acct函数的参数为NULL,则关闭进程记帐.
#include &stdlib.h&
#include &sys/acct.h&
&& & & &ret = acct(&/home/test/log/pacct&);
&& & & &if(ret & 0){
&& & & & & perror(&acct on error&);
&& & & & & return 0;
&& & & &system(&/bin/ls -l&);
&& & & &acct(NULL);
&& & & &if(ret & 0){
&& & & & & perror(&acct off error&);
&& & & & & return 0;
&& & & &return 0;
gcc psacct.c -o psacct
acct on error: Operation not permitted
给psacct程序授权CAP_SYS_PACCT能力,如下:
setcap cap_sys_psacct /home/test/psacct
注意这里的能力是sys_psacct,而不是sys_pacct
回到普通用户,执行psacct
drwxr-xr-x 2 test test -02 13:28 log
-rw-r--r-- 1 test test & 64
13:25 pacct
-rwxr-xr-x 1 test test -02 13:31 psacct
-rw-r--r-- 1 test test &314
13:31 psacct.c
我们看到已经执行成功,下面我们再看下进程记录,如下:
lastcomm -f /home/test/log/pacct&
ls & & & & & & & & & & test & & pts/0 & & &0.03 secs Mon May &2 13:33
二十三)CAP_SYS_ADMIN 21 (允许执行系统管理任务,如挂载/卸载文件系统,设置磁盘配额,开/关交换设备和文件等)
下面是普通用户拥有相关管理权限的测试
1)更改主机名
setcap cap_sys_admin=eip /bin/hostname
hostname test2
2)挂载/卸载文件系统
这里我们注意,系统的mount命令不能做这个试验,因为程序中做了判断,如果不是root用户请退出.所以我们用mount()函数来完成这个试验,程序如下:
#include &stdlib.h&
#include &sys/mount.h&
&& & & &ret = mount(&/dev/sda1&, &/mnt/&, &ext3&, MS_MGC_VAL, NULL);
&& & & &if(ret & 0){
&& & & & & perror(&mount error&);
&& & & & & return 0;
&& & & &return 0;
用普通用户编译运行:
gcc mounttest.c -o mounttest
./mounttest&
mount error: Operation not permitted
我们看到普通用户不能完成mount操作,而CAP_SYS_ADMIN可以帮助普通用户完成该操作,如下:
setcap cap_sys_admin=eip /home/test/mounttest&
切换到普通用户,执行mounttest程序,如下:
./mounttest&
cat /proc/mounts&
/dev/sda1 /mnt ext3 rw,relatime,errors=remount-ro,barrier=0,data=writeback 0 0
umount和mount一样,我们在这里不做演示.
3)swapon/swapoff
普通用户不能进行swapon/swapoff操作,而CAP_SYS_ADMIN可以帮助普通用户完成swapon/swapoff操作,如下:
dd if=/dev/zero of=/tmp/testdb bs=10M count=1
1+0 records in
1+0 records out
bytes (10 MB) copied, 0.164669 s, 63.7 MB/s
/sbin/mkswap /tmp/testdb
Setting up swapspace version 1, size = 10481 kB
no label, UUID=0ff46dc8-781c-4c3f-81b3-fe860f74793e
/sbin/swapon /tmp/testdb
swapon: /tmp/testdb: Operation not permitted
我们看到swapon操作被拒绝,这里我们对swapon进行授权,如下:
setcap cap_sys_admin /sbin/swapon
普通用户再次swapon,如下:
/sbin/swapon /tmp/testdb
/sbin/swapon&
/sbin/swapon -s
Filename & & & & & & & & & & & & & & & &Type & & & & & &Size & &Used & &Priority
/dev/sda6 & & & & & & & & & & & & & & & partition & & &
/tmp/testdb & & & & & & & & & & & & & & file & & & & & &10236 & 0 & & & -2
我们看到swapon操作成功.因为swapoff是swapon的软链接,所以可以直接swapoff掉交换分区,如下:
/sbin/swapoff /tmp/testdb
/sbin/swapon -s
Filename & & & & & & & & & & & & & & & &Type & & & & & &Size & &Used & &Priority
/dev/sda6 & & & & & & & & & & & & & & & partition & & &
ls -l /sbin/swapoff & &
lrwxrwxrwx 1 root root 6
07:49 /sbin/swapoff -& swapon
二十四) CAP_SYS_BOOT 22 (允许普通用使用reboot()函数)
这里我们无法用reboot命令来做测试,因为reboot命令做了判断,只允许root(UID=0)的用户可以使用.
我们用下面的程序进行测试.
#include &unistd.h&
#include &sys/reboot.h&
int main()
&& &sync();&
&& &return reboot(RB_AUTOBOOT);
gcc reboot1.c -o reboot1
这时系统没有重启.
我们查看程序的返回码,这里是255,说明程序没有运行成功.
我们用CAP_SYS_BOOT能力使reboot1程序可以被普通用户重启,如下:
setcap cap_sys_boot=eip /home/test/reboot1
用普通用户再试运行reboot1,如下:
此时系统被重启了.
二十五)CAP_SYS_NICE 23(允许提升优先级,设置其它进程的优先级)
对于普通用户程序的NICE优先级,不能超过ulimit对它的限制,如下:
nice -n -5 ls&
nice: cannot set niceness: Permission denied
而CAP_SYS_NICE可以帮助普通用户设置一个想要的一个任意优先级.
setcap cap_sys_nice=eip /usr/bin/nice
切换到普通用户,指定优先级,如下:
nice -n -5 ls&
log &mnt &mount.c &mounttest &pacct &psacct &psacct.c &reboot1 &reboot1.c &test
普通用户也不能给指定进程指定NICE优先级,而CAP_SYS_NICE也可以做的,如下:
renice -5 2255
renice: 2255: setpriority: Operation not permitted
setcap cap_sys_nice=eip /usr/bin/renice
renice -5 2255
2255: old priority 0, new priority -5
我们甚至可以用CAP_SYS_NICE来指定实时优先级
chrt -f 50 &ls
chrt: failed to set pid 0's policy: Operation not permitted
给/usr/bin/chrt命令授权CAP_SYS_NICE能力,如下:
setcap &cap_sys_nice=eip &/usr/bin/chrt
切换到普通用户,如下:
chrt -f 50 &ls
log &mnt &setulimit &setulimit.c
我们也可以指定它的CPU亲和性,如下:
taskset -p 1 2255
pid 2255's current affinity mask: 1
sched_setaffinity: Operation not permitted
failed to set pid 2255's affinity.
给/usr/bin/taskset命令授权CAP_SYS_NICE能力,如下:
setcap &cap_sys_nice=eip &/usr/bin/taskset
切换到普通用户,再次运行taskset,可以成功的设置CPU亲和性
taskset -p 1 2255
pid 2255's current affinity mask: 1
pid 2255's new affinity mask: 1
二十六) CAP_SYS_RESOURCE 24 忽略资源限制
普通用户不能用setrlimit()来突破ulimit的限制
我们用下面的程序进行测试,普通用户是无法修改RLIMIT_STACK(堆栈大小)的.如下:
#include &signal.h&
#include &stdio.h&
#include &string.h&
#include &stdlib.h&
#include &limits.h&
#include &unistd.h&
#include &sys/types.h&
#include &sys/stat.h&
#include &sys/resource.h&
main (int argc, char *argv[])
int r = 0;
getrlimit (RLIMIT_STACK,&rl);
printf(&crrent hard limit is %ld\n&,
(u_long) rl.rlim_max);
rl.rlim_max = rl.rlim_max+1;
r = setrlimit (RLIMIT_STACK, &rl);
perror(&setrlimit&);
return -1;
printf(&limit set to %ld \n&, (u_long) rl.rlim_max+1);
gcc setulimit.c -o setulimit
我们先来查看当前的限制,这里是10MB,如下:
ulimit -H -s&
./setulimit & &
crrent hard limit is
setrlimit: Operation not permitted
我们给setulimit程序以CAP_SYS_RESOURCE的能力,如下:
setcap cap_sys_resource=eip /home/test/setulimit&
用普通用户再次运行程序,已经可以通过setrlimit()设定超过限额了,如下:
./setulimit&
crrent hard limit is
limit set to &
同样我们也可以用CAP_SYS_RESOURCE能力使程序超出磁盘限额,如下:
quotacheck -avug
quotaon -avug
edquota -u test
Filesystem & & & & & & & & & blocks & & & soft & & & hard & & inodes & & soft & & hard
&&/dev/sda7 & & & & & & & & & & & & 0 & & & & &3 & & & & &5 & & & & &0 & & & &0 & & & &0
mkdir /export/test
chown -R test.test /export/test/
切换到普通用户,用dd命令产生3MB的文件,这明显超过了5kb的限制,如下:
dd if=/dev/zero of=/export/test/test bs=1M count=3
sda7: warning, user block quota exceeded.
sda7: write failed, user block limit reached.
dd: writing `test': Disk quota exceeded
1+0 records in
0+0 records out
4096 bytes (4.1 kB) copied, 0.0117371 s, 349 kB/s
授权CAP_SYS_RESOURCE能力给/bin/dd命令,如下:
setcap cap_sys_resource=eip /bin/dd
再次用普通用户运行dd命令,即可以超过5kb的限额了.
dd if=/dev/zero of=test bs=1M count=3
sda7: warning, user block quota exceeded.
3+0 records in
3+0 records out
3145728 bytes (3.1 MB) copied, 0.423662 s, 7.4 MB/s
二十七)CAP_SYS_TIME 25(允许改变系统时钟)
普通用户不能改变系统时钟,如下:
date: cannot set date: Operation not permitted
Sun Jan &1 00:00:00 EST 2012
CAP_SYS_TIME可以帮助普通用户改变系统时钟,如下:
setcap cap_sys_time=eip /bin/date
切换到普通用户再次改变时间,发现已经可以改变了
Sun Jan &1 00:00:00 EST 2012
Sun Jan &1 00:00:02 EST 2012
二十八)CAP_SYS_TTY_CONFIG 26(允许配置TTY设备)
我们下面用vhangup()函数来挂起当前的tty
#include &stdio.h&
#include &unistd.h&
int main ()
&&r=vhangup();
&&if (r){&
&&perror (&vhanguo&);
&&return 0;
gcc vhup.c -o vhup
vhanguo: Operation not permitted
我们给vhup程序设定CAP_SYS_TTY_CONFIG能力,如下:
setcap cap_sys_tty_config=eip /home/test/vhup
再次用普通用户执行程序vhup,tty被挂起,如下:
此时当前tty被挂起.
二十九) CAP_MKNOD 27 (允许使用mknod系统调用)
普通用户不能用mknod()来创建设备文件,而CAP_MKNOD可以帮助普通用户做到这一点,如下:
mknod /tmp/tnod1 c 1 5
mknod: `/tmp/tnod1': Operation not permitted
setcap cap_mknod=eip /bin/mknod
切换到普通用户,再次用mknod命令创建设备文件,如下:
mknod /tmp/tnod1 c 1 5
ls -l /tmp/tnod1&
crw-r--r-- 1 test test 1, 5
00:31 /tmp/tnod1
三十) CAP_LEASE 28(允许在文件上建立租借锁)
系统调用fcntl()可以用于租借锁,此时采用的函数原型如下:
&& & & int fcntl(int fd, int cmd, long arg);
与租借锁相关的 cmd 参数的取值有两种:F_SETLEASE 和 F_GETLEASE。其含义如下所示:
F_SETLEASE:根据下面所描述的 arg 参数指定的值来建立或者删除租约:
F_RDLCK:设置读租约。当文件被另一个进程以写的方式打开时,拥有该租约的当前进程会收到通知
F_WRLCK:设置写租约。当文件被另一个进程以读或者写的方式打开时,拥有该租约的当前进程会收到通知
F_UNLCK:删除以前建立的租约
F_GETLEASE:表明调用进程拥有文件上哪种类型的锁,这需要通过返回值来确定,返回值有三种:F_RDLCK、F_WRLCK和F_UNLCK,分别表明调用进程对文件拥有读租借、写租借或者根本没有租借
某个进程可能会对文件执行其他一些系统调用(比如 OPEN() 或者 TRUNCATE()),如果这些系统调用与该文件上由 F_SETLEASE 所设置的租借锁相冲突,内核就会阻塞这个系统调用;
同时,内核会给拥有这个租借锁的进程发信号,告知此事。拥有此租借锁的进程会对该信号进行反馈,它可能会删除这个租借锁,也可能会减短这个租借锁的租约,从而可以使得该文件可以被其他进程所访问。
如果拥有租借锁的进程不能在给定时间内完成上述操作,那么系统会强制帮它完成。通过 F_SETLEASE 命令将 arg 参数指定为 F_UNLCK 就可以删除这个租借锁。
不管对该租借锁减短租约或者干脆删除的操作是进程自愿的还是内核强迫的,只要被阻塞的系统调用还没有被发出该调用的进程解除阻塞,那么系统就会允许这个系统调用执行。
即使被阻塞的系统调用因为某些原因被解除阻塞,但是上面对租借锁减短租约或者删除这个过程还是会执行的。
源程序如下:
#define _GNU_SOURCE&
#include &unistd.h&
#include &fcntl.h&
#include &stdio.h&
#include &sys/file.h&
static void show_lease(int fd)
&& & & &res = fcntl(fd, F_GETLEASE);
&& & & &switch (res) {
&& & & & & & & &case F_RDLCK:
&& & & & & & & & & & & &printf(&Read lease\n&);
&& & & & & & & & & & & &
&& & & & & & & &case F_WRLCK:
&& & & & & & & & & & & &printf(&Write lease\n&);
&& & & & & & & & & & & &
&& & & & & & & &case F_UNLCK:
&& & & & & & & & & & & &printf(&No leases\n&);
&& & & & & & & & & & & &
&& & & & & & & &default:
&& & & & & & & & & & & &printf(&Some shit\n&);
&& & & & & & & & & & & &
int main(int argc, char **argv)
&& & & &int fd,
&& & & &fd = open(argv[1], O_RDONLY);
&& & & &if (fd == -1) {
&& & & & & & & &perror(&Can't open file&);
&& & & & & & & &return 1;
&& & & &res = fcntl(fd, F_SETLEASE, F_WRLCK);
&& & & &if (res == -1) {
&& & & & & & & &perror(&Can't set lease&);
&& & & & & & & &return 1;
&& & & &show_lease(fd);
&& & & &if (flock(fd, LOCK_SH) == -1) {
&& & & & & & & &perror(&Can't flock shared&);
&& & & & & & & &return 1;
&& & & &show_lease(fd);
&& & & &return 0;
gcc fcntl.c -o fcntl
我们使用普通用户在/etc/passwd文件上建立租借锁,由于普通用户没有/etc/passwd上建租借锁的权限,故而报错,如下:
/tmp/fcntl /etc/passwd
Can't set lease: Permission denied
普通用户可以在自己的文件上(owner)建立租借锁.
授权lease给/tmp/fcntl文件,如下:
setcap cap_lease=eip /tmp/fcntl
再次运行/tmp/fcntl,可以建立租借锁了,如下:
/tmp/fcntl /etc/passwd
Write lease
Write lease
三十一)CAP_SETFCAP 31 (允许在指定的程序上授权能力给其它程序)
例如我们让普通用户也能用setcap给其它程序授权,如下:
setcap CAP_SETFCAP=eip /usr/sbin/setcap&
setcap CAP_SETPCAP=eip /bin/ls
getcap /bin/ls & & & & & & & &
/bin/ls = cap_setpcap+eip
三十二)其它的能力
CAP_AUDIT_WRITE
CAP_AUDIT_CONTROL
CAP_MAC_OVERRIDE
CAP_MAC_ADMIN
CAP_SYSLOG
这五组只能涉及到syslog,audit,mac等安全模块,以后专门对其进行分析.
三十三)总结:
CAP_CHOWN 0 允许改变文件的所有权&
CAP_DAC_OVERRIDE 1 忽略对文件的所有DAC访问限制&
CAP_DAC_READ_SEARCH 2 忽略所有对读、搜索操作的限制&
CAP_FOWNER 3 以最后操作的UID,覆盖文件的先前的UID
CAP_FSETID 4 确保在文件被修改后不修改setuid/setgid位
CAP_KILL 5 允许对不属于自己的进程发送信号&
CAP_SETGID 6 允许改变组ID&
CAP_SETUID 7 允许改变用户ID&
CAP_SETPCAP 8 允许向其它进程转移能力以及删除其它进程的任意能力(只限init进程)
CAP_LINUX_IMMUTABLE 9 允许修改文件的不可修改(IMMUTABLE)和只添加(APPEND-ONLY)属性&
CAP_NET_BIND_SERVICE 10 允许绑定到小于1024的端口&
CAP_NET_BROADCAST 11 允许网络广播和多播访问(未使用)&
CAP_NET_ADMIN 12 允许执行网络管理任务:接口、防火墙和路由等.
CAP_NET_RAW 13 允许使用原始(raw)套接字&
CAP_IPC_LOCK 14 允许锁定共享内存片段&
CAP_IPC_OWNER 15 忽略IPC所有权检查&
CAP_SYS_MODULE 16 插入和删除内核模块&
CAP_SYS_RAWIO 17 允许对ioperm/iopl的访问&
CAP_SYS_CHROOT 18 允许使用chroot()系统调用&
CAP_SYS_PTRACE 19 允许跟踪任何进程&
CAP_SYS_PACCT 20 允许配置进程记帐(process accounting)&
CAP_SYS_ADMIN 21 允许执行系统管理任务:加载/卸载文件系统、设置磁盘配额、开/关交换设备和文件等.
CAP_SYS_BOOT 22 允许重新启动系统&
CAP_SYS_NICE 23 允许提升优先级,设置其它进程的优先级&
CAP_SYS_RESOURCE 24 忽略资源限制&
CAP_SYS_TIME 25 允许改变系统时钟&
CAP_SYS_TTY_CONFIG 26 允许配置TTY设备&
CAP_MKNOD 27 允许使用mknod()系统调用&
CAP_LEASE 28 允许在文件上建立租借锁
CAP_SETFCAP 31 允许在指定的程序上授权能力给其它程序
man capabilities
linux-2.6.38.5/include/linux/capability.h
本文已收录于以下专栏:
相关文章推荐
Windows系统下安装
Windows 下可以使用 .msi 后缀(在下载列表中可以找到该文件,如go1.8.1.windows-amd64.msi)的安装包来安装。
安装包下载地址为:http...
1、下载go语言安装包
下载地址:https://golang.org/dl/ ,我是win7
64-bit环境,下载包为go1.8.1.windows-amd64.zip
2、安装go和配置...
程序后台运行的另类方法,支持windows、linux、...
Linux支持Capability的主要目的是细化root的特权,使一个进程能够以“最小权限原则”去执行任务。比如拿ping程序来说,它需要使用原始套接字(raw_sockets),如果没有Capab...
Android应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是ActivityThread.main,二是进程天然支持Binder进程间通信机制;这两个特点都是在进程的初始化过程中实...
Capabilities的主要思想在于分割root用户的特权
转自:/question/720405.htmlLinux是一种安全操作系统,它给普通用户尽可能低的权限,而把全部的系统权限赋予...
1)从2.1版开始,Linux内核有了能力(capability)的概念,即它打破了UNIX/LINUX操作系统中超级用户/普通用户的概念,由普通用户也可以做只有超级用户可以...
LINUX系统调用原理-既应用层如何调用内核层函数之软件中断
SWI:software interrupt
ARM Linux系统利用SWI指令来从用户空间进入内核...
1)从2.1版开始,Linux内核有了能力(capability)的概念,即它打破了UNIX/LINUX操作系统中超级用户/普通用户的概念,由普通用户也可以做只有超级用户可以...
他的最新文章
讲师:王哲涵
讲师:韦玮
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 capability approach 的文章

 

随机推荐