转至http://www.cnblogs.com/iamfy/archive/2012/09/20/2694977.html

一)概述:

 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:表示能够被当前进程执行的程序继承的能力.
 
#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 storage

  if (cap_set_proc(caps)) {
    perror("capset()");
    return EXIT_FAILURE;
  }
  listCaps();   
  cap_free(caps);
  return 0;}

编译:

gcc capsettest.c -o capsettest -lcap
 编译时找不到sys/capability.h 需要安装libcap(http://www.man7.org/linux/man-pages/man8/setcap.8.html)或者apt-get install libcap-dev
运行:
./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运行的进程是什么权限都有,而普通用户则什么权限都没有.
 

转载:linux capability深入分析的更多相关文章

  1. Linux的capability深入分析

    Linux的capability深入分析详见:http://blog.csdn.net/u014338577/article/details/48791953 lxd中对容器能力的限制: 普通用户不能 ...

  2. Linux的capability深入分析(1)

    一)概述:     1)从2.1版开始,Linux内核有了能力(capability)的概念,即它打破了UNIX/LINUX操作系统中超级用户/普通用户的概念,由普通用户也可以做只有超级用户可以完成的 ...

  3. Linux的capability深入分析(2)【转】

    转自:https://blog.csdn.net/wangpengqi/article/details/9821231 rpm -ql libcap-2.16-5.2.el6.i686  /lib/l ...

  4. Linux的capability深入分析(1)【转】

    转自:https://blog.csdn.net/wangpengqi/article/details/9821227 一)概述: )从2.1版开始,Linux内核有了能力(capability)的概 ...

  5. 拾遗:『Linux Capability』

    『Linux Capability』 For the purpose of performing permission checks, traditional UNIX implementations ...

  6. Linux Capability探索实验

    Linux内核从2.1版本开始,就开始支持Capabilities的安全机制.Capabilities安全机制提出的目的在于实现系统特权操作的更加细粒度的访问控制,使用户能够根据实际的安全需求来控制r ...

  7. [转载]Linux进程调度原理

    [转载]Linux进程调度原理 Linux进程调度原理 Linux进程调度的目标 1.高效性:高效意味着在相同的时间下要完成更多的任务.调度程序会被频繁的执行,所以调度程序要尽可能的高效: 2.加强交 ...

  8. [转载]Linux下非root用户如何安装软件

    [转载]Linux下非root用户如何安装软件 来源:https://tlanyan.me/work-with-linux-without-root-permission/ 这是本人遇到的实际问题,之 ...

  9. [转载]Linux 命令详解:./configure、make、make install 命令

    [转载]Linux 命令详解:./configure.make.make install 命令 来源:https://www.cnblogs.com/tinywan/p/7230039.html 这些 ...

随机推荐

  1. 查看Jquery版本

    1. $.fn.jquery > "1.11.1" 2. 通过这样可以 判断一个对象是否是jquery对象!!

  2. C#快速导入海量XML数据至SQL Server数据库

    #region 将Xml中的数据读到Dataset中,然后用SqlBulkCopy类把数据copy到目的表中using (XmlTextReader xmlReader = new XmlTextRe ...

  3. HTML5中的Range对象的研究(转载)

    一:Range对象的概念 Range对象代表页面上的一段连续区域,通过Range对象,可以获取或修改页面上的任何区域,可以通过如下创建一个空的Range对象,如下: var  range = docu ...

  4. PHP之验证码识别

    首先推荐几篇有关验证码识别的文章,觉得不错 php实现验证码的识别(初级篇) 关于bp神经网格识别验证码 一.思路 碰见一个验证码,如果我们想要识别它,我们需要的是做什么呢? 我们先观察几个验证码.. ...

  5. Python 的“+”和append在添加字符串时候的区别

    对于一个空的Python列表,往后添加内容有很多种,其中两种一个是用“+”直接添加内容,另外一种是Listname.append(x)来添加内容 其中,如果处理字符串 在使用“+”的时候,会将字符串拆 ...

  6. 造成session丢失的原因和解决方法

    win2003 server下的IIS6默认设置下对每个运行在默认应用池中的工作者进程都会经过20多个小时后自动回收该进程,   造成保存在该进程中的session丢失. 因为Session,Appl ...

  7. BZOJ 3872 Ant colony

    Description There is an entrance to the ant hill in every chamber with only one corridor leading int ...

  8. BZOJ 1057 棋盘制作

    Description 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴 ...

  9. HDU1106

    为了给学弟学妹讲课,我又水了一题-- 1: import java.util.*; 2: import java.io.*; 3: 4: public class HDU1106 5: { 6: pu ...

  10. Browsing History

    hdu4464:http://acm.hdu.edu.cn/showproblem.php?pid=4464 题意:就是统计n个字符串中每个字符串每个字符对印的Asci,然后输出最大的长度. 题解:水 ...