华大基因 网站建设公司南京网站建设公司开发

当前位置: 首页 > news >正文

华大基因 网站建设公司,南京网站建设公司开发,望城网站建设,最好网站建设公司哪家好from:https://www.cnblogs.com/iamfy/archive/2012/09/20/2694977.html 一)概述: 1)从2.1版开始,Linux内核有了能力(capability)的概念,即它打破了UNIX/LINUX操作系统中超级用户/普通用户的概念,由普通用户也可以做只有超级用户可以完成的工作. 2)capability可以作用在进程上…from:https://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:表示能够被当前进程执行的程序继承的能力. 二)capability的设定与清除 我们在下面的程序中给当前的进程设定能力,最后我们清除掉所设定的能力,源程序如下: 1 #include stdio.h  2 #include stdlib.h  3 #include string.h  4 #include sys/types.h  5 #include unistd.h  6    7 #undef _POSIX_SOURCE  8 #include sys/capability.h  9   10 extern int errno; 11    12 void whoami(void) 13 { 14   printf(uid%i  euid%i  gid%i\n, getuid(), geteuid(), getgid()); 15 } 16   17 void listCaps() 18 { 19   cap_t caps  cap_get_proc(); 20   ssize_t y  0; 21   printf(The process %d was give capabilities %s\n, 22          (int) getpid(), cap_to_text(caps, y)); 23   fflush(0); 24   cap_free(caps); 25 } 26    27 int main(int argc, char argv) 28 { 29   int stat; 30   whoami(); 31   stat  setuid(geteuid()); 32   pid_t parentPid  getpid(); 33   34   if(!parentPid) 35     return 1; 36   cap_t caps  cap_init(); 37   38   39   cap_value_t capList[5]  40   { CAP_NET_RAW, CAP_NET_BIND_SERVICE , CAP_SETUID, CAP_SETGID,CAP_SETPCAP } ; 41   unsigned num_caps  5; 42   cap_set_flag(caps, CAP_EFFECTIVE, num_caps, capList, CAP_SET); 43   cap_set_flag(caps, CAP_INHERITABLE, num_caps, capList, CAP_SET); 44   cap_set_flag(caps, CAP_PERMITTED, num_caps, capList, CAP_SET); 45   46   if (cap_set_proc(caps)) { 47     perror(capset()); 48   49     return EXIT_FAILURE; 50   } 51   listCaps(); 52  53   printf(dropping caps\n); 54   cap_clear(caps);  // resetting caps storage 55   56   if (cap_set_proc(caps)) { 57     perror(capset()); 58     return EXIT_FAILURE; 59   } 60   listCaps(); 61  62   cap_free(caps); 63   return 0; 64  65 } 编译: gcc capsettest.c -o capsettest -lcap 运行: ./capsettest  uid0  euid0  gid0 The process 2383 was give capabilities cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raweip 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来设定掩码,下面获取掩码的体现: 1 #undef _POSIX_SOURCE  2 #include stdlib.h  3 #include stdio.h  4 #include sys/types.h  5 #include unistd.h  6 #include linux/capability.h  7 #include errno.h  8   9 int main() 10 { 11      struct user_cap_header_struct cap_header_data; 12      cap_user_header_t cap_header  cap_header_data; 13  14      struct user_cap_data_struct cap_data_data; 15      cap_user_data_t cap_data  cap_data_data; 16  17      cap_header-pid  getpid(); 18      cap_header-version  _LINUX_CAPABILITY_VERSION_1; 19  20      if (capget(cap_header, cap_data)  0) { 21          perror(Failed capget); 22          exit(1); 23      } 24      printf(Cap data 0x%x, 0x%x, 0x%x\n, cap_data-effective, 25          cap_data-permitted, cap_data-inheritable); 26 } gcc capget0.c -o capget0 -lcap 普通用户: ./capget0  Cap data 0x0, 0x0, 0x0 超级用户: /home/test/capget0  Cap data 0xffffffff, 0xffffffff, 0x0 这也说明了默认情况下,root运行的进程是什么权限都有,而普通用户则什么权限都没有. 我们可以将本程序与上面的程序进行整合,如下: 1 #include stdio.h  2 #include stdlib.h  3 #include string.h  4 #include sys/types.h  5 #include unistd.h  6    7 #undef _POSIX_SOURCE  8 #include sys/capability.h  9   10 extern int errno; 11    12 void whoami(void) 13 { 14   printf(uid%i  euid%i  gid%i\n, getuid(), geteuid(), getgid()); 15 } 16   17 void listCaps() 18 { 19   cap_t caps  cap_get_proc(); 20   ssize_t y  0; 21   printf(The process %d was give capabilities %s\n, 22          (int) getpid(), cap_to_text(caps, y)); 23   fflush(0); 24   cap_free(caps); 25 } 26   27   28 int main(int argc, char 
argv) 29 { 30   int stat; 31   whoami(); 32   stat  setuid(geteuid()); 33   pid_t parentPid  getpid(); 34   35   if(!parentPid) 36     return 1; 37   cap_t caps  cap_init(); 38   39   cap_value_t capList[5]  40   { CAP_NET_RAW, CAP_NET_BIND_SERVICE , CAP_SETUID, CAP_SETGID,CAP_SETPCAP } ; 41   unsigned num_caps  5; 42   cap_set_flag(caps, CAP_EFFECTIVE, num_caps, capList, CAP_SET); 43   cap_set_flag(caps, CAP_INHERITABLE, num_caps, capList, CAP_SET); 44   cap_set_flag(caps, CAP_PERMITTED, num_caps, capList, CAP_SET); 45   46   if (cap_set_proc(caps)) { 47     perror(capset()); 48   49     return EXIT_FAILURE; 50   } 51   listCaps(); 52  53   cap_free(caps); 54  55   struct user_cap_header_struct cap_header_data; 56   cap_user_header_t cap_header  cap_header_data; 57  58   struct user_cap_data_struct cap_data_data; 59   cap_user_data_t cap_data  cap_data_data; 60  61   cap_header-pid  getpid(); 62   cap_header-version  _LINUX_CAPABILITY_VERSION_1; 63  64   if (capget(cap_header, cap_data)  0) { 65       perror(Failed capget); 66       exit(1); 67   } 68   printf(Cap data 0x%x, 0x%x, 0x%x\n, cap_data-effective, 69   cap_data-permitted, cap_data-inheritable); 70  71   sleep(60); 72   return 0; 73 } 编译并执行: gcc capsettest.c -o capsettest -lcap ./capsettest uid0  euid0  gid0 The process 3101 was give capabilities cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raweip Cap data 0x25c0, 0x25c0, 0x25c0 注:0x25c010 0101 1100 0000(二进制) 对映的能力如下: cap_setgid6(位) cap_setuid7(位) cap_setpcap8(位) cap_net_bind_service10(位) cap_net_raw13(位) 在程序sleep的时候,我们查看一下进程的status,如下: cat /proc/pgrep capsettest/status 略 CapInh: 00000000000025c0 CapPrm: 00000000000025c0 CapEff: 00000000000025c0 CapBnd: ffffffffffffffff 略 我们看到进程的status也反映了它的能力状态. CapBnd是系统的边界能力,我们无法改变它. 四)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_chowneip /bin/chown  查看/bin/chown程序的能力值,如下: getcap /bin/chown                /bin/chown cap_chowneip 切换到test用户,将/bin/ls程序的owner改为test,如下: su - test chown test.test /bin/ls ls -l /bin/ls -rwxr-xr-x. 1 test test 118736 Jun 14  2010 /bin/ls 注: 1)cap_chowneip是将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_overrideeip /usr/bin/vim  切换到普通用户 su - test 修改/etc/shadow文件内容 vim /etc/shadow root:\(6\)3hJf.BoIVU/cdLKb\(JxLXcQScrLS032aFPAQvVc4RzKYNadcIIzxmzAIw.jejrYOHhqdr0oV7sNBL.IhGBo.mMOYEdevlnCp2OGku8.:15094:0:99999:7::: bin:*:14790:0:99999:7::: daemon:*:14790:0:99999:7::: adm:*:14790:0:99999:7::: 注: DAC_OVERRIDE能力是DAC_READ_SEARCH能力的超集. 七)CAP_DAC_READ_SEARCH 2(忽略所有对读、搜索操作的限制) 授权普通用户可以用/bin/cat程序查看所有文件的内容,如下: setcap cap_dac_read_searcheip /bin/cat 切换到普通用户 su - test 查看/etc/shadow,如下: cat /etc/shadow root:\)6\(3hJf.BoIVU/cdLKb\)JxLXcQScrLS032aFPAQvVc4RzKYNadcIIzxmzAIw.jejrYOHhqdr0oV7sNBL.IhGBo.mMOYEdevlnCp2OGku8.:15094:0:99999:7::: bin::14790:0:99999:7::: daemon::14790:0:99999:7::: adm::14790:0:99999:7::: 八)CAP_FOWNER 3(以最后操作的UID,覆盖文件的先前的UID) cp /etc/passwd /tmp/ ls -l /tmp/passwd    -rw-r–r– 1 root root 1171 2011-04-29 19:21 /tmp/passwd 授权cap_fowner权限给/usr/bin/vim setcap cap_fownereip /usr/bin/vim 切换到test用户 su - test 编辑/tmp/passwd文件,存盘退出. vi /tmp/passwd 修改文件,并保存退出. 查看/tmp/passwd,发现owner已经变成test -rw-r–r– 1 test test 1176 2011-04-29 19:21 /tmp/passwd 九)CAP_FSETID 4(确保在文件被修改后不修改setuid/setgid位) 起因是当文件被修改后,会清除掉文件的setuid/setgid位,而设定CAP_FSETID后将保证setuid/setgid位不被清除.但这对chown函数无用. 测试程序如下: 1 #include sys/types.h  2 #include sys/types.h  3 #include sys/stat.h  4 #include fcntl.h  5 #include sys/stat.h  6 #include stdio.h  7 #include stdlib.h  8 #include string.h  9 main() 10 { 11         int handle; 12         char string[40]; 13         int length, res; 14  15         if ((handle  open(/tmp/passwd, O_WRONLY | O_CREAT | O_TRUNC,S_IREAD | S_IWRITE))  -1) 16         { 17                 printf(Error opening file.\n); 18                 exit(1); 19         } 20         strcpy(string, Hello, world!\n); 21         length  strlen(string); 22         if ((res  write(handle, string, length)) ! length) 23         { 24                 printf(Error writing to the file.\n); 25                 exit(1); 26         } 27         printf(Wrote %d bytes to the file.\n, res); 28         close(handle); 29 } gcc fsetid.c -o fsetid 先测试没有设FSETID的情况,如下: chmod 6777 /tmp/passwd ls -l /tmp/passwd -rwsrwsrwx 1 test test 14 2011-04-30 14:22 /tmp/passwd /tmp/fsetid  Wrote 14 bytes to the file. ls -l /tmp/passwd -rwxrwxrwx 1 test test 14 2011-04-30 14:25 /tmp/passwd 我们看到setuid/setgid位被清除了. 下面是设定FSETID,如下: chmod 6777 /tmp/passwd ls -l /tmp/passwd      -rwsrwsrwx 1 test test 14 2011-04-30 14:25 /tmp/passwd 切换到root用户,给/tmp/fsetid程序授权CAP_FSETID能力,如下: setcap cap_fsetideip /tmp/fsetid 切换到普通用户 /tmp/fsetid Wrote 14 bytes to the file. ls -l /tmp/passwd -rwsrwsrwx 1 test test 14 2011-04-30 14:28 /tmp/passwd 十)CAP_KILL 5 (允许对不属于自己的进程发送信号) 我们先模拟没有加CAP_KILL能力的情况,如下: 终端1,用root用户启用top程序,如下: su - root top 终端2,用test用户kill之前的top进程,如下: pgrep top      3114 /bin/kill 3114 kill: Operation not permitted 我们发现无法对不属于自己的进程发送信号. 下面我们用CAP_KILL能力的程序向不属于自己的进程发送信号,如下: 设定kill命令的kill位,如下: setcap cap_killeip /bin/kill  杀掉3114进程,没有问题,如下: /bin/kill 3114 echo \(? 0 注意: 普通用户要用/bin/kill这种绝对路径的方式,而不能用kill这种方式. 十一)CAP_SETGID 6 (设定程序允许普通用户使用setgid函数,这与文件的setgid权限位无关) cp /etc/shadow /tmp/ chown root.root /tmp/shadow chmod 640 /tmp/shadow 切换到普通用户test,并编写setgid测试程序,如下: su - test 1 #include unistd.h 2 int 3 main () 4 { 5         gid_t gid  0; 6         setgid(gid); 7         system(/bin/cat /tmp/shadow); 8         return 0; 9 } gcc setgid.c -o setgid 更改setgid程序为CAP_SETGID setcap cap_setgideip /tmp/setgid 切换到普通用户,运行/tmp/setgid程序,如下: su - test /tmp/setgid  root:\)1\(S9AmPHY8\)ZIdORp6aLnYleb5EORxw8/:14479:0:99999:7::: daemon::14479:0:99999:7::: bin::14479:0:99999:7::: sys::14479:0:99999:7::: sync::14479:0:99999:7::: games::14479:0:99999:7::: man::14479:0:99999:7::: lp::14479:0:99999:7::: mail::14479:0:99999:7::: news::14479:0:99999:7::: uucp::14479:0:99999:7::: proxy::14479:0:99999:7::: www-data::14479:0:99999:7::: backup::14479:0:99999:7::: list::14479:0:99999:7::: 我们看到普通用户可以查看/tmp/shadow文件,而取消CAP_SETGID则使程序不能拥有setgid的权限,如下: setcap -r /tmp/setgid su - test /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测试程序,如下: su - test cd /tmp/ vi setuid.c 1 #include unistd.h 2 int 3 main () 4 { 5         uid_t uid  0; 6         setuid(uid); 7         system(/bin/cat /tmp/shadow); 8         return 0; 9 } gcc setuid.c -o setuid 切换到root用户,更改setuid程序为CAP_SETUID su - root setcap cap_setuideip /tmp/setuid 切换到test用户,运行/tmp/setuid程序,如下: su - test /tmp/setuid root:\(1\)S9AmPHY8$ZIdORp6aLnYleb5EORxw8/:14479:0:99999:7::: daemon::14479:0:99999:7::: bin::14479:0:99999:7::: sys::14479:0:99999:7::: sync::14479:0:99999:7::: games::14479:0:99999:7::: man::14479:0:99999:7::: lp::14479:0:99999:7::: 我们看到普通用户可以查看/tmp/shadow文件,而取消CAP_SETUID则使程序不能拥有setuid的权限,如下: setcap -r /tmp/setuid su - test /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用户: su -  setcap cap_linux_immutableeip /usr/bin/chattr  切换到普通用户: su - test chattr i /tmp/test lsattr /tmp/test  —-i————– /tmp/test 我们看到授权成功了,注意,这里只能对自己的文件授权(immutable/append-only)权限,对于其它用户的权限LINUX_IMMUTABLE不起作用(root除外),如下: su - test 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 Cant grab 0.0.0.0:500 with bind : Permission denied 增加CAP_NET_BIND_SERVICE能力到nc程序,如下: setcap cap_net_bind_serviceeip /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_admineip /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_admineip /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: cant 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_raweip /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 30788 2007-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_raweip /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_seq1 ttl128 time0.266 ms 64 bytes from 192.168.27.2: icmp_seq2 ttl128 time0.280 ms 64 bytes from 192.168.27.2: icmp_seq3 ttl128 time0.319 ms NET_RAW也同样用于tcpdump/iftop,一个普通用户无法使用tcpdump/iftop,而CAP_NET_RAW可以解决这个问题,方式同ping一样,所以我们不做演示. 十九)CAP_IPC_LOCK 14 (在允许锁定内存片段) root和普通用户都可以用mlock来锁定内存,区别是root不受ulimit下的锁定内存大小限制,而普通用户会受到影响. 测试程序如下: 1 #include stdio.h  2 #include sys/mman.h  3   4 int main(int argc, char argv[])  5 {  6         int array[2048];  7   8         if (mlock((const void )array, sizeof(array))  -1) {  9                 perror(mlock: ); 10                 return -1; 11         } 12  13         printf(success to lock stack mem at: %p, len%zd\n, 14                         array, sizeof(array)); 15  16  17         if (munlock((const void *)array, sizeof(array))  -1) { 18                 perror(munlock: ); 19                 return -1; 20         } 21  22         printf(success to unlock stack mem at: %p, len%zd\n, 23                         array, sizeof(array)); 24  25         return 0; 26 } gcc mlock.c -o mlock 切换到普通用户,我们看到mlock是不受限制 ulimit -a max locked memory       (kbytes, -l) unlimited 我们运行程序 ./mlock success to lock stack mem at: 0xbfd94914, len8192 success to unlock stack mem at: 0xbfd94914, len8192 我们将限制改为1KB,再次运行程序,如下: ulimit -l 1 ./mlock mlock: : Cannot allocate memory 切换到root用户,将CAP_IPC_LOCK能力授权给mlock测试程序,如下: setcap cap_ipc_lockeip /tmp/mlock 用普通用户再次运行程序,执行成功: ./mlock success to lock stack mem at: 0xbfec1584, len8192 success to unlock stack mem at: 0xbfec1584, len8192 二十)CAP_IPC_OWNER 15 (忽略IPC所有权检查) 这个能力对普通用户有作用,如果用root用户创建共享内存(shmget),权限为600,而普通用户不能读取该段共享内存. 通过CAP_IPC_OWNER可以让普通用户的程序可以读取/更改共享内存. 我们用下面的程序创建共享内存段,并写入0xdeadbeef到共享内存段中. 1 #include stdio.h  2 #include string.h  3 #include stdlib.h  4 #include unistd.h  5 #include sys/ipc.h  6 #include sys/shm.h  7 #include sys/wait.h  8   9 void error_out(const char *msg) 10 { 11         perror(msg); 12         exit(EXIT_FAILURE); 13 } 14  15  16 int main (int argc, char *argv[]) 17 { 18         key_t mykey  12345678; 19  20         const size_t region_size  sysconf(_SC_PAGE_SIZE); 21         int smid  shmget(mykey, region_size, IPC_CREAT|0600); 22         if(smid  -1) 23                 error_out(shmget); 24  25         void ptr; 26         ptr  shmat(smid, NULL, 0); 27         if (ptr  (void ) -1) 28                 error_out(shmat); 29         u_long d  (u_long )ptr; 30         d  0xdeadbeef; 31         printf(ipc mem %#lx\n, (u_long *)ptr); 32  33         return 0; 34 } gcc test.c -o test -lrt 我们用root用户来执行本程序,创建共享内存,如下: /tmp/test ipc mem 0xdeadbeef 查看当前的共享内存 ipcs -m —— Shared Memory Segments ——– key        shmid      owner      perms      bytes      nattch     status       0x00bc614e 458752     root      600        4096       0               修改程序,将*d 0xdeadbeef;改为*d 0xffffffff; 再编译,用普通用户运行程序,如下: gcc test.c -o test -lrt su - test /tmp/test shmget: Permission denied 我们看到没有权限更改共享内存. 用root用户把CAP_IPC_OWNER能力授权给test程序,如下: setcap cap_ipc_ownereip /tmp/test 再次用普通用户运行程序test,更改共享内存,如下: /tmp/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_moduleeip /sbin/modprobe 再用普通用户加载内核模块,如下: /sbin/modprobe nvram lsmod |grep nvram nvram                   3861  0  我们看到可以加载. 同样我们可以将CAP_SYS_MODULE授权给rmmod程序,让其可以删除模块,如下: setcap cap_sys_moduleeip /sbin/rmmod su - test /sbin/rmmod nvram lsmod |grep nvram 二十二)CAP_SYS_RAWIO 17 (允许用户打开端口,并读取修改端口数据,一般用ioperm/iopl函数) ioperm只有低端的[0-0x3ff] I/O端口可被设置,且普通用户不能使用. iopl可以用于所有的65536个端口,因此ioperm相当于iopl调用的一个子集. 下面的程序首先设置0x3FF端口的读写权限,然后读出原先的值,然后将原值的LSB翻转并写回端口,并在此读取端口值. 1 #include unistd.h  2 #include sys/io.h  3   4 #define PORT_ADDR 0x3FF  5   6 int main(void)  7 {  8       int ret;  9       char port_val; 10        11       /set r/w permission of all 65536 ports/ 12       ret  iopl(3); 13       if(ret  0){ 14            perror(iopl set error); 15            return 0; 16       } 17  18       port_val  inb(PORT_ADDR); 19       printf(Original value of port 0x%x is : %.2x\n, PORT_ADDR, port_val); 20        21       /reverse the least significant bit / 22  23       outb(port_val^0x01, PORT_ADDR); 24       port_val  inb(PORT_ADDR); 25       printf(Current value of port 0x%x is : %.2x\n, PORT_ADDR, port_val); 26        27       /set r/w permission of  all 65536 ports/ 28        29       ret  iopl(0); 30       if(ret  0){ 31            perror(iopl set error); 32            return 0; 33       } 34       return 0; 35 } 编译: gcc iopl.c -o iopl 普通用户运行iopl程序,提示没有权限. /tmp/iopl  iopl set error: Operation not permitted 给程序iopl授权CAP_SYS_RAWIO能力,此时普通用户可以执行iopl程序,如下: setcap cap_sys_rawioeip /tmp/iopl su - test /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_chrooteip /usr/sbin/chroot 普通用户再次用chroot切换根目录,如下: /usr/sbin/chroot / /bin/sh sh-3.2\( 二十四)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_ptraceeip /usr/bin/strace 切换到普通用户,跟踪PID1的进程,如下: strace -p 1 Process 1 attached - interrupt to quit select(11, [10], NULL, NULL, {3, 771381}) 0 (Timeout) time(NULL)                               1304348451 stat64(/dev/initctl, {st_modeS_IFIFO|0600, st_size0, ...}) 0 fstat64(10, {st_modeS_IFIFO|0600, st_size0, ...}) 0 stat64(/dev/initctl, {st_modeS_IFIFO|0600, st_size0, ...}) 0 select(11, [10], NULL, NULL, {5, 0})     0 (Timeout) time(NULL)                               1304348456 二十五)CAP_SYS_PACCT 20 (允许配置进程记帐process accounting)  要完成进程记帐,要保证有写入文件的权限,这里我们将进程记录写入到/home/test/log/psacct. mkdir /home/test/log/ touch /home/test/log/psacct 程序通过acct函数,将进程的记帐写入到指定文件中,如果acct函数的参数为NULL,则关闭进程记帐. 1 #include stdlib.h  2 #include sys/acct.h  3   4 int  5 main()  6 {  7         int ret;  8         ret  acct(/home/test/log/pacct);  9         if(ret  0){ 10            perror(acct on error); 11            return 0; 12         } 13         system(/bin/ls -l); 14         acct(NULL); 15         if(ret  0){ 16            perror(acct off error); 17            return 0; 18         } 19         return 0; 20 } gcc psacct.c -o psacct ./psacct  acct on error: Operation not permitted 给psacct程序授权CAP_SYS_PACCT能力,如下: setcap cap_sys_psacct /home/test/psacct 注意这里的能力是sys_psacct,而不是sys_pacct 回到普通用户,执行psacct ./psacct  total 24 drwxr-xr-x 2 test test 4096 2011-05-02 13:28 log -rw-r--r-- 1 test test   64 2011-05-02 13:25 pacct -rwxr-xr-x 1 test test 6590 2011-05-02 13:31 psacct -rw-r--r-- 1 test test  314 2011-05-02 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_admineip /bin/hostname su - test hostname test2 hostname test2 2)挂载/卸载文件系统 这里我们注意,系统的mount命令不能做这个试验,因为程序中做了判断,如果不是root用户请退出.所以我们用mount()函数来完成这个试验,程序如下: 1 #include stdlib.h  2 #include sys/mount.h  3 int  4 main ()  5 {  6         int ret;  7         ret  mount(/dev/sda1, /mnt/, ext3, MS_MGC_VAL, NULL);  8         if(ret  0){  9            perror(mount error); 10            return 0; 11         } 12         return 0; 13 } 用普通用户编译运行: gcc mounttest.c -o mounttest ./mounttest  mount error: Operation not permitted 我们看到普通用户不能完成mount操作,而CAP_SYS_ADMIN可以帮助普通用户完成该操作,如下: setcap cap_sys_admineip /home/test/mounttest  切换到普通用户,执行mounttest程序,如下: ./mounttest  cat /proc/mounts  略 /dev/sda1 /mnt ext3 rw,relatime,errorsremount-ro,barrier0,datawriteback 0 0 umount和mount一样,我们在这里不做演示. 3)swapon/swapoff 普通用户不能进行swapon/swapoff操作,而CAP_SYS_ADMIN可以帮助普通用户完成swapon/swapoff操作,如下: dd if/dev/zero of/tmp/testdb bs10M count1 10 records in 10 records out 10485760 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, UUID0ff46dc8-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       7815584 0       -1 /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       7815584 0       -1 ls -l /sbin/swapoff     lrwxrwxrwx 1 root root 6 2009-08-23 07:49 /sbin/swapoff - swapon 二十七) CAP_SYS_BOOT 22 (允许普通用使用reboot()函数) 这里我们无法用reboot命令来做测试,因为reboot命令做了判断,只允许root(UID0)的用户可以使用. 我们用下面的程序进行测试. 1 #include unistd.h 2 #include sys/reboot.h 3 int main() 4 { 5     sync();  6     return reboot(RB_AUTOBOOT); 7 } 编译: gcc reboot1.c -o reboot1 ./reboot1 这时系统没有重启. 我们查看程序的返回码,这里是255,说明程序没有运行成功. echo \)? 255 我们用CAP_SYS_BOOT能力使reboot1程序可以被普通用户重启,如下: setcap cap_sys_booteip /home/test/reboot1 用普通用户再试运行reboot1,如下: reboot1 此时系统被重启了. 二十八)CAP_SYS_NICE 23(允许提升优先级,设置其它进程的优先级) 对于普通用户程序的NICE优先级,不能超过ulimit对它的限制,如下: nice -n -5 ls  nice: cannot set niceness: Permission denied 而CAP_SYS_NICE可以帮助普通用户设置一个想要的一个任意优先级. setcap cap_sys_niceeip /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_niceeip /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 0s policy: Operation not permitted 给/usr/bin/chrt命令授权CAP_SYS_NICE能力,如下: setcap  cap_sys_niceeip  /usr/bin/chrt 切换到普通用户,如下: chrt -f 50  ls log  mnt  setulimit  setulimit.c 我们也可以指定它的CPU亲和性,如下: taskset -p 1 2255 pid 2255s current affinity mask: 1 sched_setaffinity: Operation not permitted failed to set pid 2255s affinity. 给/usr/bin/taskset命令授权CAP_SYS_NICE能力,如下: setcap  cap_sys_niceeip  /usr/bin/taskset 切换到普通用户,再次运行taskset,可以成功的设置CPU亲和性 taskset -p 1 2255 pid 2255s current affinity mask: 1 pid 2255s new affinity mask: 1 二十九) CAP_SYS_RESOURCE 24 忽略资源限制 普通用户不能用setrlimit()来突破ulimit的限制 我们用下面的程序进行测试,普通用户是无法修改RLIMIT_STACK(堆栈大小)的.如下: 1 #include signal.h  2 #include stdio.h  3 #include string.h  4 #include stdlib.h  5 #include limits.h  6 #include unistd.h  7 #include sys/types.h  8 #include sys/stat.h  9 #include sys/resource.h 10  11 int 12 main (int argc, char *argv[]) 13 { 14 int r  0; 15 struct rlimit rl; 16  17 getrlimit (RLIMIT_STACK,rl); 18  19 printf(crrent hard limit is %ld\n, 20 (u_long) rl.rlim_max); 21  22 rl.rlim_max  rl.rlim_max1; 23 r  setrlimit (RLIMIT_STACK, rl); 24 if ®{ 25 perror(setrlimit); 26 return -1; 27 } 28  29 printf(limit set to %ld \n, (u_long) rl.rlim_max1); 30 return 0; 31 } gcc setulimit.c -o setulimit 我们先来查看当前的限制,这里是10MB,如下: ulimit -H -s  10240 ./setulimit     crrent hard limit is 10485760 setrlimit: Operation not permitted 我们给setulimit程序以CAP_SYS_RESOURCE的能力,如下: setcap cap_sys_resourceeip /home/test/setulimit  用普通用户再次运行程序,已经可以通过setrlimit()设定超过限额了,如下: ./setulimit  crrent hard limit is 10485760 limit set to 10485762  同样我们也可以用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的限制,如下: su - test dd if/dev/zero of/export/test/test bs1M count3 sda7: warning, user block quota exceeded. sda7: write failed, user block limit reached. dd: writing test: Disk quota exceeded 10 records in 00 records out 4096 bytes (4.1 kB) copied, 0.0117371 s, 349 kB/s 授权CAP_SYS_RESOURCE能力给/bin/dd命令,如下: setcap cap_sys_resourceeip /bin/dd 再次用普通用户运行dd命令,即可以超过5kb的限额了. su - test dd if/dev/zero oftest bs1M count3 sda7: warning, user block quota exceeded. 30 records in 30 records out 3145728 bytes (3.1 MB) copied, 0.423662 s, 7.4 MB/s 三十)CAP_SYS_TIME 25(允许改变系统时钟) 普通用户不能改变系统时钟,如下: date -s 2012-01-01 date: cannot set date: Operation not permitted Sun Jan  1 00:00:00 EST 2012 CAP_SYS_TIME可以帮助普通用户改变系统时钟,如下: setcap cap_sys_timeeip /bin/date 切换到普通用户再次改变时间,发现已经可以改变了 su - test date -s 2012-01-01 Sun Jan  1 00:00:00 EST 2012 date Sun Jan  1 00:00:02 EST 2012 三十一)CAP_SYS_TTY_CONFIG 26(允许配置TTY设备) 我们下面用vhangup()函数来挂起当前的tty 程序如下: 1 #include stdio.h  2 #include unistd.h  3   4 int main ()  5 {  6   int r;  7   rvhangup();  8   if ®{   9   perror (vhanguo); 10   } 11   return 0; 12 } gcc vhup.c -o vhup ./vhup  vhanguo: Operation not permitted 我们给vhup程序设定CAP_SYS_TTY_CONFIG能力,如下: setcap cap_sys_tty_configeip /home/test/vhup 再次用普通用户执行程序vhup,tty被挂起,如下: ./vhup  此时当前tty被挂起. 三十二) CAP_MKNOD 27 (允许使用mknod系统调用) 普通用户不能用mknod()来创建设备文件,而CAP_MKNOD可以帮助普通用户做到这一点,如下: mknod /tmp/tnod1 c 1 5 mknod: /tmp/tnod1: Operation not permitted setcap cap_mknodeip /bin/mknod 切换到普通用户,再次用mknod命令创建设备文件,如下: mknod /tmp/tnod1 c 1 5 ls -l /tmp/tnod1  crw-r–r– 1 test test 1, 5 2012-01-01 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 就可以删除这个租借锁。 不管对该租借锁减短租约或者干脆删除的操作是进程自愿的还是内核强迫的只要被阻塞的系统调用还没有被发出该调用的进程解除阻塞那么系统就会允许这个系统调用执行。 即使被阻塞的系统调用因为某些原因被解除阻塞但是上面对租借锁减短租约或者删除这个过程还是会执行的。 源程序如下: 1 #define _GNU_SOURCE   2   3 #include unistd.h  4 #include fcntl.h  5 #include stdio.h  6 #include sys/file.h  7 static void show_lease(int fd)  8 {  9         int res; 10  11         res  fcntl(fd, F_GETLEASE); 12         switch (res) { 13                 case F_RDLCK: 14                         printf(Read lease\n); 15                         break; 16                 case F_WRLCK: 17                         printf(Write lease\n); 18                         break; 19                 case F_UNLCK: 20                         printf(No leases\n); 21                         break; 22                 default: 23                         printf(Some shit\n); 24                         break; 25         } 26 } 27  28 int main(int argc, char **argv) 29 { 30         int fd, res; 31  32         fd  open(argv[1], O_RDONLY); 33         if (fd  -1) { 34                 perror(Cant open file); 35                 return 1; 36         } 37  38         res  fcntl(fd, F_SETLEASE, F_WRLCK); 39         if (res  -1) { 40                 perror(Cant set lease); 41                 return 1; 42         } 43  44         show_lease(fd); 45  46         if (flock(fd, LOCK_SH)  -1) { 47                 perror(Cant flock shared); 48                 return 1; 49         } 50  51         show_lease(fd); 52  53         return 0; 54 } 编译: gcc fcntl.c -o fcntl 我们使用普通用户在/etc/passwd文件上建立租借锁,由于普通用户没有/etc/passwd上建租借锁的权限,故而报错,如下: su - test /tmp/fcntl /etc/passwd Cant set lease: Permission denied 注: 普通用户可以在自己的文件上(owner)建立租借锁. 授权lease给/tmp/fcntl文件,如下: setcap cap_leaseeip /tmp/fcntl 再次运行/tmp/fcntl,可以建立租借锁了,如下: /tmp/fcntl /etc/passwd Write lease Write lease 三十四)CAP_SETFCAP 31 (允许在指定的程序上授权能力给其它程序) 例如我们让普通用户也能用setcap给其它程序授权,如下: setcap CAP_SETFCAPeip /usr/sbin/setcap  su - test setcap CAP_SETPCAPeip /bin/ls getcap /bin/ls                 /bin/ls cap_setpcapeip 三十六)其它的能力 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  Linux系统调用列表 from:https://blog.csdn.net/wwwdc1012/article/details/78759326 一、进程控制 函数名描述文件fork创建一个新进程kernel/fork.cclone按指定条件创建子进程kernel/fork.cexecve运行可执行文件fs/exec.cexit中止进程kernel/exit.c_exit立即中止当前进程getdtablesize进程所能打开的最大文件数kernel/sys.cgetpgid获取指定进程组标识号kernel/sys.csetpgid设置指定进程组标志号kernel/sys.cgetpgrp获取当前进程组标识号kernel/sys.csetpgrp设置当前进程组标志号kernel/sys.cgetpid获取进程标识号kernel/sys.cgetppid获取父进程标识号kernel/sys.cgetpriority获取调度优先级kernel/sys.csetpriority设置调度优先级kernel/sys.cmodify_ldt读写进程的本地描述表arch/x86/um/ldt.cnanosleep使进程睡眠指定的时间kernel/hrtimer.cnice改变分时进程的优先级pause挂起进程等待信号kernel/signal.cpersonality设置进程运行域kernel/exec_domain.cprctl对进程进行特定操作kernel/sys.cptrace进程跟踪kernel/ptrace.csched_get_priority_max取得静态优先级的上限kernel/sched/core.csched_get_priority_min取得静态优先级的下限kernel/sched/core.csched_getparam取得进程的调度参数kernel/sched/core.csched_getscheduler取得指定进程的调度策略kernel/sched/core.csched_rr_get_interval取得按RR算法调度的实时进程的时间片长度kernel/sched/core.csched_setparam设置进程的调度参数kernel/sched/core.csched_setscheduler设置指定进程的调度策略和参数kernel/sched/core.csched_yield进程主动让出处理器,并将自己等候调度队列队尾kernel/sched/core.cvfork创建一个子进程以供执行新程序常与execve等同时使用kernel/fork.cwait等待子进程终止wait3参见waitwaitpid等待指定子进程终止wait4参见waitpidkernel/exit.ccapget获取进程权限kernel/capability.ccapset设置进程权限kernel/capability.cgetsid获取会晤标识号kernel/sys.csetsid设置会晤标识号kernel/sys.c 二、文件系统控制 函数名描述文件fcntl文件控制fs/fcntl.copen打开文件fs/open.ccreat创建新文件fs/open.cclose关闭文件描述字fs/open.cread读文件fs/read_write.cwrite写文件fs/read_write.creadv从文件读入数据到缓冲数组中fs/read_write.cwritev将缓冲数组里的数据写入文件fs/read_write.cpread对文件随机读fs/read_write.cpwrite对文件随机写fs/read_write.clseek移动文件指针fs/read_write.c_llseek在64位地址空间里移动文件指针dup复制已打开的文件描述字fs/file.cdup2按指定条件复制文件描述字fs/file.cflock文件加/解锁fs/locks.cpollI/O多路转换fs/select.ctruncate截断文件fs/open.cftruncate参见truncatefs/open.cumask设置文件权限掩码kernel/sys.cfsync把文件在内存中的部分写回磁盘fs/sync.caccess确定文件的可存取性fs/open.cchdir改变当前工作目录fs/open.cfchdir参见chdirfs/open.cchmod改变文件方式fs/open.cfchmod参见chmodfs/open.cchown改变文件的属主或用户组fs/open.cfchown参见chownfs/open.clchown参见chownfs/open.cchroot改变根目录fs/open.cstat取文件状态信息fs/stat.clstat参见statfs/stat.cfstat参见statfs/stat.cstatfs取文件系统信息fs/statfs.cfstatfs参见statfsfs/statfs.creaddir读取目录项getdents读取目录项fs/readdir.cmkdir创建目录fs/namei.cmknod创建索引节点fs/namei.crmdir删除目录fs/namei.crename文件改名fs/namei.clink创建链接fs/namei.csymlink创建符号链接fs/namei.cunlink删除链接fs/namei.creadlink读符号链接的值fs/stat.cmount安装文件系统fs/namespace.cumount卸下文件系统ustat取文件系统信息fs/statfs.cutime改变文件的访问修改时间fs/utimes.cutimes参见utimefs/utimes.cquotactl控制磁盘配额fs/quota/quota.c 三、系统控制 函数名描述文件ioctlI/O总控制函数fs/ioctl.c_sysctl读/写系统参数kernel/sysctl_binary.cacct启用或禁止进程记账kernel/acct.cgetrlimit获取系统资源上限kernel/sys.csetrlimit设置系统资源上限kernel/sys.cgetrusage获取系统资源使用情况kernel/sys.cuselib选择要使用的二进制函数库fs/exec.cioperm设置端口I/O权限arch/x86/kernel/ioport.ciopl改变进程I/O权限级别arch/x86/kernel/ioport.coutb低级端口操作reboot重新启动kernel/reboot.cswapon打开交换文件和设备mm/swapfile.cswapoff关闭交换文件和设备mm/swapfile.cbdflush控制bdflush守护进程sysfs取核心支持的文件系统类型fs/filesystems.csysinfo取得系统信息kernel/sys.cadjtimex调整系统时钟kernel/time.calarm设置进程的闹钟kernel/timer.cgetitimer获取计时器值kernel/itimer.csetitimer设置计时器值kernel/itimer.cgettimeofday取时间和时区kernel/time.csettimeofday设置时间和时区kernel/time.cstime设置系统日期和时间time取得系统时间times取进程运行时间kernel/sys.cuname获取当前UNIX系统的名称、版本和主机等信息kernel/sys.cvhangup挂起当前终端fs/open.cnfsservctl对NFS守护进程进行控制vm86进入模拟8086模式create_module创建可装载的模块项delete_module删除可装载的模块项kernel/module.cinit_module初始化模块kernel/module.cquery_module查询模块信息*get_kernel_syms取得核心符号,已被query_module代替 四、内存管理 函数名描述文件brk改变数据段空间的分配mm/mmap.csbrk参见brkmlock内存页面加锁mm/mlock.cmunlock内存页面解锁mm/mlock.cmlockall调用进程所有内存页面加锁mm/mlock.cmunlockall调用进程所有内存页面解锁mm/mlock.cmmap映射虚拟内存页arch/x86/kernel/sys_x86_64.cmunmap去除内存页映射mm/mmap.cmremap重新映射虚拟内存地址mm/mmap.cmsync将映射内存中的数据写回磁盘mm/msync.cmprotect设置内存映像保护mm/mprotect.cgetpagesize获取页面大小sync将内存缓冲区数据写回硬盘fs/sync.ccacheflush将指定缓冲区中的内容写回磁盘 五、网络管理 函数名描述文件getdomainname取域名setdomainname设置域名kernel/sys.cgethostid获取主机标识号sethostid设置主机标识号gethostname获取本主机名称sethostname设置主机名称kernel/sys.c 六、socket控制 函数名描述文件socketcallsocket系统调用socket建立socketnet/socket.cbind绑定socket到端口net/socket.cconnect连接远程主机net/socket.caccept响应socket连接请求net/socket.csend通过socket发送信息sendto发送UDP信息net/socket.csendmsg参见sendnet/socket.crecv通过socket接收信息recvfrom接收UDP信息net/socket.crecvmsg参见recvnet/socket.clisten监听socket端口net/socket.cselect对多路同步I/O进行轮询fs/select.cshutdown关闭socket上的连接net/socket.cgetsockname取得本地socket名字net/socket.cgetpeername获取通信对方的socket名字net/socket.cgetsockopt取端口设置net/socket.csetsockopt设置端口参数net/socket.csendfile在文件或端口间传输数据fs/read_write.csocketpair创建一对已联接的无名socketnet/socket.c 七、用户管理 函数名描述文件getuid获取用户标识号kernel/sys.csetuid设置用户标志号kernel/sys.cgetgid获取组标识号kernel/sys.csetgid设置组标志号kernel/sys.cgetegid获取有效组标识号kernel/sys.csetegid设置有效组标识号kernel/sys.cgeteuid获取有效用户标识号kernel/sys.cseteuid设置有效用户标识号kernel/sys.csetregid分别设置真实和有效的的组标识号kernel/sys.csetreuid分别设置真实和有效的用户标识号kernel/sys.cgetresgid分别获取真实的,有效的和保存过的组标识号kernel/sys.csetresgid分别设置真实的,有效的和保存过的组标识号kernel/sys.cgetresuid分别获取真实的,有效的和保存过的用户标识号kernel/sys.csetresuid分别设置真实的,有效的和保存过的用户标识号kernel/sys.csetfsgid设置文件系统检查时使用的组标识号kernel/sys.csetfsuid设置文件系统检查时使用的用户标识号kernel/sys.cgetgroups获取后补组标志清单kernel/groups.csetgroups设置后补组标志清单kernel/groups.c 八、进程间通信 函数名描述文件ipc进程间通信总控制调用信号sigaction设置对指定信号的处理方法sigprocmask根据参数对信号集中的信号执行阻塞/解除阻塞等操作sigpending为指定的被阻塞信号设置队列sigsuspend挂起进程等待特定信号signal参见signalkill向进程或进程组发信号kernel/signal.c*sigblock向被阻塞信号掩码中添加信号,已被sigprocmask代替*siggetmask取得现有阻塞信号掩码,已被sigprocmask代替*sigsetmask*sigmask将给定的信号转化为掩码,已被sigprocmask代替*sigpause作用同sigsuspend,已被sigsuspend代替sigvec为兼容BSD而设的信号处理函数,作用类似sigactionssetmaskANSI C的信号处理函数,作用类似sigaction2、消息msgctl消息控制操作ipc/msg.cmsgget获取消息队列ipc/msg.cmsgsnd发消息ipc/msg.cmsgrcv取消息ipc/msg.c3、管道pipe创建管道fs/pipe.c4、信号量semctl信号量控制ipc/sem.csemget获取一组信号量ipc/sem.csemop信号量操作ipc/sem.c5、共享内存shmctl控制共享内存ipc/shm.cshmget获取共享内存ipc/shm.cshmat连接共享内存ipc/shm.cshmdt拆卸共享内存ipc/shm.c 转自 https://www.ibm.com/developerworks/cn/linux/kernel/syscall/part1/appendix.html http://blog.csdn.net/sinat_26227857/article/details/44244433 chroot 与 jail from:https://blog.csdn.net/cheng_fangang/article/details/9333037 所谓“监牢”就是指通过chroot机制来更改某个进程所能看到的根目录即将某进程限制在指定目录中保证该进程只能对该目录及其子目录的文件有所动作从而保证整个服务器的安全。 创建chroot“监牢” 以前Unix/Linux上的daemon都是以root权限启动的。当时这似乎是一件理所当然的事情因为像Apache这样的服务器软件需要绑定到“众所周知”的端口上小于1024来监听HTTP请求而root是惟一有这种权限的用户。 但是随着攻击者活动的日益频繁尤其是缓冲区溢出漏洞数量的激增使服务器安全受到了更大的威胁。一旦某个网络服务存在漏洞攻击者就能够访问并控制整个系统。因此为了减缓这种攻击所带来的负面影响现在服务器软件通常设计为以root权限启动然后服务器进程自行放弃root再以某个低权限的系统账号来运行进程。这种方式的好处在于一旦该服务被攻击者利用漏洞入侵由于进程权限很低攻击者得到的访问权限又是基于这个较低权限的对系统造成的危害比以前减轻了许多。 有些攻击者会试图找到系统其它的漏洞来提升权限直至达到root。由于本地安全性远低于远程安全保护因此攻击者很有可能在系统中找到可以提升权限的东西。即使没有找到本地漏洞攻击者也可能会造成其它损害如删除文件、涂改主页等。 为了进一步提高系统安全性Linux内核引入了chroot机制。chroot是内核中的一个系统调用软件可以通过调用库函数chroot来更改某个进程所能见到的根目录。比如Apache软件安装在/usr/local/httpd/目录下以root用户或具有相同权限的其它账号启动Apache这个root权限的父进程会派生数个以nobody权限运行的子进程具体情况取决于个人设置。父进程监听请求自80端口的tcp数据流然后根据内部算法将这个请求分配给某个子进程来处理。这时Apache子进程所处的目录继承自父进程即/usr/local/httpd/。 但是一旦目录权限设定失误被攻击的Apache子进程可以访问/usr/local、/usr、/tmp甚至整个文件系统因为Apache进程所处的根目录仍是整个文件系统的根。如果能够利用chroot将Apache限制在/usr/local/httpd/那么Apache所能存取的文件都是/usr/local/httpd/下的文件或其子目录下的文件。创建chroot“监牢”的作用就是将进程权限限制在文件系统目录树中的某一子树中。 为什么需要jail 将软件chroot化的一个问题是该软件运行时需要的所有程序、配置文件和库文件都必须事先安装到chroot目录中通常称这个目录为chroot jailchroot“监牢”。如果要在“监牢”中运行/sbin/httpd而事实上根本看不到文件系统中那个真正的/sbin目录。因此需要事先创建/sbin目录并将httpd复制到其中。同时httpd需要几个库文件执行如下命令可以看到这些库文件在真实的文件系统下运行。 #ldd /sbin/httpd libaprutil-0.so.0 /usr/local/httpd/lib/libaprutil-0.so.0 (0x40017000) libgdbm.so.2 /usr/lib/libgdbm.so.2 (0x4003c000) libdb-4.0.so /lib/libdb-4.0.so (0x40043000) libpthread.so.0 /lib/tls/libpthread.so.0 (0x400eb000) libexpat.so.0 /usr/lib/libexpat.so.0 (0x400f8000) libapr-0.so.0 /usr/local/httpd/lib/libapr-0.so.0 (0x40118000) librt.so.1 /lib/librt.so.1 (0x40139000) lIBM.so.6 /lib/tls/lIBM.so.6 (0x4014b000) libcrypt.so.1 /lib/libcrypt.so.1 (0x4016d000) libnsl.so.1 /lib/libnsl.so.1 (0x4019a000) libdl.so.2 /lib/libdl.so.2 (0x401af000) libc.so.6 /lib/tls/libc.so.6 (0x42000000) /lib/ld-linux.so.2 /lib/ld-linux.so.2 (0x40000000) 这意味着还需要在“监牢”中创建lib目录并将库文件复制到其中。这一工作可以交由计算机完成用jail等软件包来帮助简化chroot“监牢”建立的过程。 编译和安装jail 从http://www.jmcresearch.com/static/dwn/projects/jail/jail.tar.gz可以下载到jail的最新版本它是由位于http://www.jmcresearch.com/projects/jail/的jail chroot项目小组开发的。该软件包包含了帮助自动创建chroot“监牢”的C程序、Perl程序和Bash脚本。 首先将jail.tar.gz置于任意目录然后执行命令     #tar xzvf jail.tar.gz cd jail/src 按照个人实际情况修改makefile文件尤其是安装路径默认安装路径是/usr/local、体系结构jail支持Linux、FreeBSD、IRIX和Solaris以及编译选项等。最后执行命令     #make make install 为jail创建chroot“监牢” 现在创建一个目录作为chroot“监牢”以/var/chroot/为例。执行下面的命令为chroot“监牢”创建环境     #/usr/local/bin/mkjailenv /var/chroot 这样“监牢”就建好了。jail软件包提供了几个Perl脚本作为其核心命令包括mkjailenv、addjailuser和addjailsw。如addjailsw会从真实文件系统中拷贝二进制可执行文件及其相关的其它文件包括库文件、辅助性文件和设备文件到该“监牢”中。 为jail“监牢”添加软件 接下来需要为这个“监牢”增加一些软件以便让它运行起来。执行以下命令安装一些基本的软件包括ls、cat、cp等程序和ld-linux.so.2等库文件。     #/usr/local/bin/addjailsw /var/chroot 事实上仅有这些基本软件是不够的还需要把一些真正有用的东西限制起来。下面的例子展示了为“监牢”添加arp程序的过程 #/usr/local/bin/addjailsw /var/chroot -P arpaddjailsw A component of Jail (version 1.9 for linux) http://www.jmcresearch.com/projects/jail/ Juan M. Casillas juanm.casillasjmcresearch.comGuessing arp args(0) Warning: file .//lib/tls/libc.so.6 exists. Overwritting it Warning: file .//lib/ld-linux.so.2 exists. Overwritting it Warning: file .//etc/ld.so.cache exists. Overwritting it Warning: file .//usr/lib/locale/locale-archive exists. Overwritting it Warning: file .//usr/share/locale/locale.alias exists. Overwritting it Warning: cant create /proc/net/arp from the /proc filesystemDone. 再以Apache服务器软件为例 #addjailsw /var/chroot/ -P /usr/local/httpd/bin/httpdaddjailsw A component of Jail (version 1.9 for linux) http://www.jmcresearch.com/projects/jail/ Juan M. Casillas juanm.casillasjmcresearch.comGuessing /usr/local/httpd/bin/httpd args(0) Warning: file /var/chroot//lib/libssl.so.4 exists. Overwritting it Warning: file /var/chroot//lib/libcrypto.so.4 exists. Overwritting it Warning: file /var/chroot//lib/libresolv.so.2 exists. Overwritting it ……Done. 不用在意那些警告信息因为jail会调用ldd检查httpd用到的库文件。而几乎所有基于共享库的二进制可执行文件都需要上述的几个库文件。 接下来将Apache的相关文件拷贝到“监牢”中     #cp -a /usr/local/httpd/ /var/chroot/usr/local/ 可根据个人情况依次将Apache需要的文件复制到“监牢”中。 “监禁”囚犯 有时候需要为chroot“监牢”创建新的用户比如Apache要求创建nobody用户作为子进程用户。鉴于可能有其它进程使用nobody还可以使用另一用户——httpd。首先需要在真实系统中创建httpd用户     #useradd -d /var/chroot -s /usr/local/bin/jail httpd 然后执行以下命令在chroot“监牢”中创建httpd用户     #/usr/local/bin/addjailuser /var/chroot /usr/local/httpd /usr/sbin/httpd httpd 接下来修改/var/chroot/usr/local/httpd/conf/httpd.conf将User nobody替换为User httpd。由于chroot后Apache将以httpd身份启动进程只有root有权将Apache绑定在低端口上通常为80因此还需要修改端口值该值必须大于1024假设为8080。这个修改要应用到Apache的所有配置文件中包括虚拟主机的配置。至于Apache的其它设置与在真实文件系统时一样配置即可。 接下来需要复制一些其它的文件。启动Apache最常见的方式就是调用apachectl这是个Bash脚本。查看这个文件会发现如下行 HTTPD/usr/local/httpd/bin/httpd LYNXlynx -dump ULIMIT_MAX_FILESulimit -S -n ulimit -H -n ARGV-h \(HTTPD -k \)ARGV \(HTTPD -k start -DSSL \)HTTPD -t \(LYNX \)STATUSURL | awk /process$/ { print; exit } { print } 其中ulimit、lynx和awk是辅助性的程序。另外需要注意的是程序使用不同的参数时可能会使用不同的库文件因此为了让Apache完整运行使用下面的命令来跟踪所有可能的文件     #/usr/local/bin/addjailsw /var/chroot -P httpd -k start -DSSL 用上述的参数替换引号中的参数完成全部的工作。 最后让成功jail的Apache运行起来     #su - httpd 打开浏览器进行测试访问Web服务器时记住加上8080端口号。 jail高级应用 在前面的介绍中使用了jail软件包中的三个Perl脚本。这里详细介绍这三个脚本的使用以便高级用户使用。 mkjailenv     用法mkjailenv chrootdir     作用创建chroot“监牢”目录并且从真实文件系统中拷贝基本的软件环境。     参数     chrootdir指定chroot“监牢”的路径。 addjailsw     用法addjailsw chrootdir [-D] [-P program args]      作用从真实文件系统中拷贝指定的文件及其相关文件。         参数     chrootdir指定chroot“监牢”的路径。     -D显示详细信息。     -P program args指定要添加到“监牢”中的软件。program可以是个文件名也可以是文件的完整路径args是参数。比如可以这样执行addjailsw     #addjailsw /var/chroot -P vi -c q addjailuser     用法addjailuser chrootdir userdir usershell username      作用创建新的chroot“监牢”用户。         参数     chrootdir指定chroot“监牢”的路径。     userdir指定新添加用户的主目录相对于chroot“监牢”目录。     usershell指定新用户使用的Shell的完整路径比如/bin/bash。     username为新添加的用户名。 比如     #addjailuser /var/chroot /home/ftp /bin/csh ftp 这个脚本会自动修改“监牢”中的/etc/passwd、/etc/group和/etc/shadow文件。 从上文看如果仅使Apache一个软件运行在“监牢”中mkjailenv似乎过于“热心”了因此可以不运行mkjailenv /var/chroot命令而只运行addjailsw /var/chroot P httpd或在调试完chroot“监牢”后删除多余的文件并修改/etc/passwd中多余的用户信息。由此想到现在大多数流行的Web站点都采用ApachePHPMySQLSSL的搭配可能还会有FTP、Mail、Perl等组件因此完全可以建立一个综合的Web“监牢”。系统管理员可以为这个“监牢”设置软件环境当然这个环境只包括维护ApachePHPMySQLSSL这些组件的必备工具如使用Bash、SSH、编译软件或上传等。这可能是一个浩大的工程但是却非常有意义。参考上面的方法大家可以尝试jail出完美的服务器来。