Linux的capability深入分析(1)【转】
转自:https://blog.csdn.net/wangpengqi/article/details/9821227
一)概述:1)从2.1版开始,Linux内核有了能力(capability)的概念,即它打破了UNIX/LINUX操作系统中超级用户/普通用户的概念,由普通用户也可以做只有超级用户可以完成的工作. 2)capability可以作用在进程上(受限),也可以作用在程序文件上,它与sudo不同,sudo只针对用户/程序/文件的概述,即sudo可以配置某个用户可以执行某个命令,可以更改某个文件,而capability是让某个程序拥有某种能力,例如: capability让/tmp/testkill程序可以kill掉其它进程,但它不能mount设备节点到目录,也不能重启系统,因为我们只指定了它kill的能力,即使程序有问题也不会超出能力范围. 3)每个进程有三个和能力有关的位图:inheritable(I),permitted(P)和effective(E),对应进程描述符task_struct(include/linux/sched.h)里面的cap_effective, cap_inheritable, cap_permitted,所以我们可以查看/proc/PID/status来查看进程的能力. 4)cap_effective:当一个进程要进行某个特权操作时,操作系统会检查cap_effective的对应位是否有效,而不再是检查进程的有效UID是否为0. 例如,如果一个进程要设置系统的时钟,Linux的内核就会检查cap_effective的CAP_SYS_TIME位(第25位)是否有效. 5)cap_permitted:表示进程能够使用的能力,在cap_permitted中可以包含cap_effective中没有的能力,这些能力是被进程自己临时放弃的,也可以说cap_effective是cap_permitted的一个子集. 6)cap_inheritable:表示能够被当前进程执行的程序继承的能力.二)capability的设定与清除我们在下面的程序中给当前的进程设定能力,最后我们清除掉所设定的能力,源程序如下:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <unistd.h>#undef _POSIX_SOURCE#include <sys/capability.h>extern int errno;void whoami(void){printf("uid=%i euid=%i gid=%i\n", getuid(), geteuid(), getgid());}void listCaps(){cap_t caps = cap_get_proc();ssize_t y = 0;printf("The process %d was give capabilities %s\n",(int) getpid(), cap_to_text(caps, &y));fflush(0);cap_free(caps);}int main(int argc, char **argv){int stat;whoami();stat = setuid(geteuid());pid_t parentPid = getpid();if(!parentPid)return 1;cap_t caps = cap_init();cap_value_t capList[5] ={ CAP_NET_RAW, CAP_NET_BIND_SERVICE , CAP_SETUID, CAP_SETGID,CAP_SETPCAP } ;unsigned num_caps = 5;cap_set_flag(caps, CAP_EFFECTIVE, num_caps, capList, CAP_SET);cap_set_flag(caps, CAP_INHERITABLE, num_caps, capList, CAP_SET);cap_set_flag(caps, CAP_PERMITTED, num_caps, capList, CAP_SET);if (cap_set_proc(caps)) {perror("capset()");return EXIT_FAILURE;}listCaps();printf("dropping caps\n");cap_clear(caps); // resetting caps storageif (cap_set_proc(caps)) {perror("capset()");return EXIT_FAILURE;}listCaps();cap_free(caps);return 0;}编译: gcc capsettest.c -o capsettest -lcap运行: ./capsettest uid=0 euid=0 gid=0 The process 2383 was give capabilities = cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw+eip dropping caps The process 2383 was give capabilities =注: 1)我们对该进程增加了5种能力,随后又清除了所有能力. 2)首先通过cap_init()初始化存放cap能力值的状态,随后通过cap_set_flag函数的调用,将三种位图的能力设置给了变量caps,再通过cap_set_proc(caps)设定当前进程的能力值,通过cap_get_proc()返回当前进程的能力值,最后通过cap_free(caps)释放能力值. 3)cap_set_flag函数的原型是: int cap_set_flag(cap_t cap_p, cap_flag_t flag, int ncap,const cap_value_t *caps, cap_flag_value_t value);我们这里的调用语句是:cap_set_flag(caps, CAP_PERMITTED, num_caps, capList, CAP_SET); 第一个参数cap_p是存放能力值的变量,是被设定值.这里是caps. 第二个参数flag是是三种能力位图,这里是CAP_PERMITTED. 第三个参数ncap是要设定能力的个数,这里是num_caps,也就是5. 第四个参数*caps是要设定的能力值,这里是capList数组,也就是CAP_NET_RAW, CAP_NET_BIND_SERVICE , CAP_SETUID, CAP_SETGID,CAP_SETPCAP. 第五个参数value是决定要设定还是清除,这里是CAP_SET.4)cap_set_proc函数的原型是:int cap_set_proc(cap_t cap_p); cap_set_proc函数通过cap_p中的能力值设定给当前的进程.5)cap_get_proc函数的原型是:cap_t cap_get_proc(void); cap_get_proc函数返回当前进程的能力值给cap变量.6)cap_free函数的原型是:cap_free(caps); cap_free函数清理/释放cap变量.7)如果我们fork()了子进程,那么子进程继承父进程的所有能力.8)不能单独设定CAP_EFFECTIVE,CAP_INHERITABLE位图,必须要和CAP_PERMITTED联用,且CAP_PERMITTED一定要是其它两个位图的超集.9)如果两次调用cap_set_proc函数,第二次调用的值力值不能少于或多于第一次调用.如第一次我们授权chown,setuid能力,第二次只能是chown,setuid不能是其它的能力值.10)普通用户不能给进程设定能力.三)进程的能力掩码: 我们可以通过下面的程序获取当前进程的掩码,它是通过capget函数来获取指定进程的能力掩码,当然我们也可以用capset来设定掩码,下面获取掩码的体现:#undef _POSIX_SOURCE#include <stdlib.h>#include <stdio.h>#include <sys/types.h>#include <unistd.h>#include <linux/capability.h>#include <errno.h>int main(){struct __user_cap_header_struct cap_header_data;cap_user_header_t cap_header = &cap_header_data;struct __user_cap_data_struct cap_data_data;cap_user_data_t cap_data = &cap_data_data;cap_header->pid = getpid();cap_header->version = _LINUX_CAPABILITY_VERSION_1;if (capget(cap_header, cap_data) < 0) {perror("Failed capget");exit(1);}printf("Cap data 0x%x, 0x%x, 0x%x\n", cap_data->effective,cap_data->permitted, cap_data->inheritable);}gcc capget0.c -o capget0 -lcap普通用户: ./capget0 Cap data 0x0, 0x0, 0x0超级用户: /home/test/capget0 Cap data 0xffffffff, 0xffffffff, 0x0这也说明了默认情况下,root运行的进程是什么权限都有,而普通用户则什么权限都没有.我们可以将本程序与上面的程序进行整合,如下:#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <unistd.h>#undef _POSIX_SOURCE#include <sys/capability.h>extern int errno;void whoami(void){printf("uid=%i euid=%i gid=%i\n", getuid(), geteuid(), getgid());}void listCaps(){cap_t caps = cap_get_proc();ssize_t y = 0;printf("The process %d was give capabilities %s\n",(int) getpid(), cap_to_text(caps, &y));fflush(0);cap_free(caps);}int main(int argc, char **argv){int stat;whoami();stat = setuid(geteuid());pid_t parentPid = getpid();if(!parentPid)return 1;cap_t caps = cap_init();cap_value_t capList[5] ={ CAP_NET_RAW, CAP_NET_BIND_SERVICE , CAP_SETUID, CAP_SETGID,CAP_SETPCAP } ;unsigned num_caps = 5;cap_set_flag(caps, CAP_EFFECTIVE, num_caps, capList, CAP_SET);cap_set_flag(caps, CAP_INHERITABLE, num_caps, capList, CAP_SET);cap_set_flag(caps, CAP_PERMITTED, num_caps, capList, CAP_SET);if (cap_set_proc(caps)) {perror("capset()");return EXIT_FAILURE;}listCaps();cap_free(caps);struct __user_cap_header_struct cap_header_data;cap_user_header_t cap_header = &cap_header_data;struct __user_cap_data_struct cap_data_data;cap_user_data_t cap_data = &cap_data_data;cap_header->pid = getpid();cap_header->version = _LINUX_CAPABILITY_VERSION_1;if (capget(cap_header, cap_data) < 0) {perror("Failed capget");exit(1);}printf("Cap data 0x%x, 0x%x, 0x%x\n", cap_data->effective,cap_data->permitted, cap_data->inheritable);sleep(60);return 0;}编译并执行: gcc capsettest.c -o capsettest -lcap./capsettest uid=0 euid=0 gid=0 The process 3101 was give capabilities = cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw+eip Cap data 0x25c0, 0x25c0, 0x25c0注:0x25c0=10 0101 1100 0000(二进制) 对映的能力如下: cap_setgid=6(位) cap_setuid=7(位) cap_setpcap=8(位) cap_net_bind_service=10(位) cap_net_raw=13(位)在程序sleep的时候,我们查看一下进程的status,如下: cat /proc/`pgrep capsettest`/status略 CapInh: 00000000000025c0 CapPrm: 00000000000025c0 CapEff: 00000000000025c0 CapBnd: ffffffffffffffff 略我们看到进程的status也反映了它的能力状态. CapBnd是系统的边界能力,我们无法改变它.
转载于:https://www.cnblogs.com/sky-heaven/p/9481310.html
Linux的capability深入分析(1)【转】相关推荐
- Linux的capability深入分析(2)
一)capability的工具介绍 在我们的试验环境是RHEL6,libcap-2.16软件包中包含了相关的capability设置及查看工作,如下: rpm -ql libcap-2.16-5.2. ...
- Linux的capability深入分析(1)
一)概述: 1)从2.1版开始,Linux内核有了能力(capability)的概念,即它打破了UNIX/LINUX操作系统中超级用户/普通用户的概念,由普通用户也可以做只有超级用户可以完成的工作. ...
- Linux的奖励机制是啥意思,Linux能力(capability)机制的继承
1.Linux能力机制概述 在以往的UNIX系统上,为了做进程的权限检查,把进程分为两类:特权进程(有效用户ID是0)和非特权进程(有效用户ID是非0).特权进程可以通过内核所有的权限检查,而非特权进 ...
- linux系统存储文件系统,Linux文件系统的深入分析
[IT168 技术]本人很喜欢Linux,在工作中也很喜欢总结关于Linux文件系统的经验,下面就这个问题来详细说说吧.Linux支持多种文件系统,包括ext2.iso9660.jffs.ext3.v ...
- setuid与capability
课程作业: 1.解释"passwd","sudo", "ping"等命令为什么需要setuid位,去掉s位试运行,添加权能试运行. 2.指出 ...
- Linux进程调度切换和虚拟空间管理深入分析
Linux进程调度切换和虚拟空间管理深入分析 一.Linux进程切换深入分析 #define CLONE_KERNEL (CLONE_FS | CLONE_FILES | CLONE_SIGHA ...
- linux内核数据结构之链表
1.前言 最近写代码需用到链表结构,正好公共库有关于链表的.第一眼看时,觉得有点新鲜,和我之前见到的链表结构不一样,只有前驱和后继指针,而没有数据域.后来看代码注释发现该代码来自linux内核,在li ...
- Linux内核跟踪eBPF:bpftrace 参考指南
bpftrace Reference Guide 推荐阅读:Linux内核跟踪eBPF:bpftrace一行教程 For a reference summary, see the README.md ...
- Linux沙箱技术 - Setuid Sandbox
Setuid Sandbox主要基于Linux Kernel所提供的安全机制来实现.简单地说,就是利用 random uid/gid + chroot() + capability 来达到限制不可信进 ...
最新文章
- [14] 薪酬迅速翻倍的13条跳槽原则
- php 未定义偏移,未定义的偏移PHP错误,尝试从文件读取
- Android利用Looper在子线程中改变UI
- 【mybatis】IF判断的坑 (实现if test= status == 'zhangsan')
- javascript在第三个文本框中显示文字_一段中的个别文字,显示在目录中
- 陌屿授权系统v2.0源码
- 用python计算准确率_Python 学习 scikit-learn 预测准确率计算
- C# 调用Excel组件生成excel文件
- python学习之文件处理
- [Linux] 使用 SCP 指令,讓您傳送檔案至遠端、下載檔案
- 初次了解struts的action类
- 推荐一款安卓抓包工具(抓包精灵)
- 中国荧光探针市场应用前景与投资动态预测报告(2022-2027年)
- 学生端极域课堂万能密码
- 计算机软件服务费入哪个科目,软件服务费计入什么科目?
- 最短剩余时间调度算法_LRTF:最长剩余时间优先调度算法
- 砥砺前行,匠心致远|袋鼠云联合创始人、易知微CEO宁海元荣获“数字工匠 ”
- Java GridBagLayout(网格包布局管理器)
- 番外篇(1)模块次序表、代数环及其检测算法
- 择偶标准与黑名单了解一下