Linux系统之所以安全,很重要的原因是它完善的权限管理。这里又有两个概念很重要,一是进程ID,一是文件权限。
鉴于俺已经被绕得头昏眼花,所以用此文疏理一遍:
Section 1: What is Process ID.
与进程相关的ID6个:
实际用户ID 实际组ID
有效用户ID 有效组ID 附加组ID
保存的设置用户ID 保存的设置组ID
 
进程是什么?是程序运行的实例。运行两次./hello就会产生两个进程。
实际用户/ID:我们究竟是谁;
有效用户//附加组ID:我们可以访问谁的文件;
保存的设置用户/ID:在执行程序时包含的有效用户/ID的副本;
 
打个比方,在一栋公寓里面,住着MariaLinGuest等等用户,他们每个人养了许多宠物:
Maria创建了cat 1cat 2,那么它们的实际用户/ID就是Maria,实际用户/ID在登陆时确定(root有办法改变它,但通常不需要);
cat 1cat 2的有效用户/ID通常也是Maria,意味着cat 1cat 2只能访问Maria的房间;
 
还有一种特殊的情况,“当执行此文件时,将进程的有效用户/ID设置为文件所有者的用户/ID”,什么意思呢?
cat 1cat 2的创建,需要执行./cat,假设catroot所有,由Maria执行:
如果没有设置catst_mode的特殊标志set-usr-ID/set-group-ID
cat 1cat 2的实际用户/IDMaria
cat 1cat 2的有效用户/IDMaria
如果已经设置catst_mode的特殊标志set-usr-ID/set-group-ID
cat 1cat 2的实际用户/IDMaria
cat 1cat 2的有效用户/IDroot
 
这是危险的,因为cat 1cat 2现在拥有root的权力,它们可以闯进任何房间,吃任何人的东西,睡任何人的床;
但这也是某些情景下的需要,比如root的房间里面放了一大盆猫粮,这样cat 1cat 2才可以吃到它们;
 
Section 2: What is File Access Permission.
与进程ID相对应的,每个文件都有权限,执行ls -al命令的时候,可以观察到:
[maria@localhost primer-unix]$ ls -al hello
-rwxrwxrwx. 1 maria maria 114 Apr 10 11:44 hello
chmod命令可以用来更改文件的权限:
[maria@localhost primer-unix]$ chmod 755 hello
[maria@localhost primer-unix]$ ls -al hello
-rwxr-xr-x. 1 maria maria 114 Apr 10 11:44 hello
 
chmod命令中的755,对应着文件的9个权限访问位“rwxr-xr-x”hello可以看成是Maria房间里面的一台电视机:
Maria(本人)可以查看电视机的配置(r),可以更改电视机的配置(w),可以打开电视机看节目(x);
Lin(同组)可以查看电视机的配置(r),不能更改电视机的配置(w),可以打开电视机看节目(x);
Guest(不同组)可以查看电视机的配置(r),不能更改电视机的配置(w),可以打开电视机看节目(x);
 
规则一:如果Maria可以r|w|x这台电视机,她必须可以打开房间、打开电视柜、打开第二层电视柜、打开第三层电视柜。。。
就是说,她必须对电视机所在路径的所有目录具备执行权限(x):
/home/maria/maria_work/workon_fedora/programs/primer-unix/hello
 
读目录的意思是,获取目录下文件的列表,如果只有读权限,那么可以知道primer-unix有哪些文件,但不能搜索它的子目录。
为了在目录中创建/删除文件,必须对目录具备写/执行权限;
这和通常的理解是不是有些差别呢?如果目录下有文件,不论它是属于rootMaria还是Lin,只要Maria对这个目录具备写/执行权限,它就可以被创建和删除。
 
Section 3: How does Process access files.
理解了进程ID的概念,再理解了文件访问权限的概念,现在来看看进程是按照什么样的规则来访问文件。
NO 1:若进程的有效用户ID0(超级用户),则允许访问。这给予了超级用户对整个文件系统进行处理的最充分的自由。
如果cat属于root,而且cat 1cat 2也由root创建(或者cat属于rootcat 1cat 2Maria创建,且catst_mode的特殊标志set-usr-ID/set-group-ID被设置),则cat1 cat 2可以访问任何房间。
 
NO 2::若进行的有效用户ID等于文件的所有者ID(也就是该进程拥有此文件),那么:若所有者适当的访问权限位被设置,则允许访问,否则拒绝访问。适当的访问权限位指的是,若进程为读而打开该文件,则用户读位应为1;若进程为写而打开该文件,则用户写位应为1;若进程将执行该文件,则用户执行位应为1.
如果cat 1cat 2Maria创建,且它们要玩的电视机也属于Maria,那么如果电视机可以被r/w/xcat 1cat 2就可以把电视机r/w/x,如果电视机被Maria设置成不能被r/w/x,那么cat 1cat 2也就不能对电视机操作了。
 
NO 3:若进程的有效ID或进程的附加组ID之一等于文件的组ID,那么:若组适当的访问权限位被设置,则允许访问,否则拒绝访问。
如果cat 1cat 2Maria创建,且它们要玩的收音机属于MariaLin公共所有,如果收音机可以被Maria或者Lin中任何一个r/w/xcat 1cat 2就可以把收音机r/w/x,否则就不能操作收音机。
 
NO 4:若其他用户适当的访问权限位被设置,则允许访问,否则拒绝访问。
如果cat 1cat 2Maria创建,且它们要玩的毛线球属于Guest,但是Guest说毛线球谁都可以r/w/x,那cat 1cat 2就可以玩这个毛线球,否则就不能操作它。
 
Section 4: Change Process ID.
在进程运行的过程中,更改ID是非常常见的。“一般而言,在设计应用程序时,我们总是使用最小特权(least privilege)模型。依照此模型,我们的程序应当只具有为完成给定任务所需的最小特权。”
 
setuidsetgid函数用来更改实际用户ID和有效用户ID
#include <unistd.h>
int setuid(uid_t uid);
int setgid(gid_t gid);
只有一个入口参数,那如何更改实际和有效两个概念呢?
NO 1:若进程具有超级用户特权,则setuid函数将实际用户ID、有效用户ID,以及保存的设置用户ID设置为uid
如果cat 1cat 2具有超级用户特权,也就是它们的实际用户IDroot,那么执行这个函数之后,实际用户ID、有效用户ID和保存的设置用户ID都会被设置为uid
如果uid0,则被设置为000
如果uid1000Maria),则被设置为100010001000
 
NO 2::若进程没有超级用户特权,但是uid等于实际用户ID或保存的设置用户ID,则setuid只将有效用户ID设置为uid。不改变实际用户ID和保存的设置用户ID
如果cat 1cat 2具有Maria用户特权,也就是它们的实际用户IDMaria,那么执行这个函数之后,如果uid也是1000Maria)或者保存的设置用户(如果存在),则有效用户会变成Maria,其他的不会变化。
如果uid0,且保存设置为0,则被设置为100000
如果uid1000,且保存用户设置为x,则被设置为10001000x
 
NO 3:如果上面两个条件都不满足,则将errno设置为EPERM,并返回-1
 
如果cat 1或者cat 2具备root的用户特权,那它们想把自己的实际/有效/保存设置ID换成什么,就可以换成什么,随意换,无障碍。
如果cat 1或者cat 2具备Maria的用户特权,那它们只能把非Maria的有效用户ID换成Maria,或者cat的设置用户ID允许的人,比如Lin
它不能更改自己的实际用户,也就是实际用户永远是Maria
它不能更改自己的设置用户,也就是cat保存的是谁就是谁;
它可以更改自己的有效用户,但是需要和实际用户一样,或者cat的设置用户允许;
 
NOTE:只有超级用户进程可以更改实际用户ID
NOTE:仅当对程序文件设置了设置用户ID位时,exec函数才会设置有效用户ID
NOTE:保存的设置用户ID是由exec复制有效用户ID而得来的。
 
交换实际用户和有效用户的值:
#include <unistd.h>
int setreuid(uid_t ruid, uit_t euid);
int setregid(gid_t rgid, gid_t euid);
 
如果cat 1cat 2Maria创建,而它通过保存的设置用户ID获得的有效用户IDroot,则Mariaroot可以互相交换,这样cat 1cat 2只能访问Maria所属的文件了,直到交换回来才可访问root所属的文件。
 
Section 5: Conclusion
Linux系统的权限管理是非常完善的,这是它之所以安全的原因之一。
进程ID是程序运行的身份证,文件权限则是文件本身的特征,文件被执行时产生进程,进程可能需要访问文件。
其实还是晕晕乎乎的,以后再练习吧^_^