强制位权限
当程序需要读取限制访问权限的文件时,一般都会通过合理的设计,使用seteuid()来达到访问受限文件的目的。
为什么不用setuid()e呢?
先以普通用户的身份来说,普通用户执行setuid()e,通常是返回失败的,即使在执行成功的情况下,也是相当于只执行了seteuid()。
以root用户的身份来说,执行setuid()e切换到普通用户,然后呢?想再切换回root或别的用户的话,那可就困难了,已经没有权限了。
real-user-id: 表示进程的实际执行者
effective-user-id: 表示进程访问文件时的身份
saved-user-id: effective-user-id
的一份拷贝,进程启动时拷贝
set-user-id: 二进制可执行程序的一个标志位,可通过ls命令查看,可通过chmod命令设置该标志位
一般情况下,(real uid)=(effective uid)=进程的用户ID,当设置了set-user-id时,进程的有效ID是其二进制文件的属主。
表1:程序启动时的真实ID和有效ID
owner : A
set-user-id | user A exec | user B exec | user root exec |
---|---|---|---|
off (---x--x--x) | (real uid : A) (effective uid : A) | (real uid : B) (effective uid : B) | (real uid : 0) (effective uid : 0) |
on (---s--x--x) | (real uid : A) (effective uid : A) | (real uid : B) (effective uid : A) | (real uid : 0) (effective uid : A) |
当未设置set-user-id时,非root用户无权改变有效用户。
表2:不同用户执行seteuid
owner : A
set-user-id : off
=
号表示未改变,其值维持启动时的状态
set-user-id | user A exec | user B exec | user root exec |
---|---|---|---|
seteuid(A) | = | Operation not permitted | (effective uid : A) |
seteuid(B) | Operation not permitted | = | (effective uid : B) |
seteuid(0) | Operation not permitted | Operation not permitted | (effective uid : 0) |
上表中,当用户B运行一个程序,当程序里执行seteuid(A)
时,会报告操作未授权,并且程序会在此退出。
同理,当用户A在运行的程序里执行seteuid(B)
时,也会报告同样的错误。
当设置了set-user-id时,非root用户可以将有效用户设置为真实用户(在此处也可理解为当前用户)或者saved-user-id。
表3:不同用户执行seteuid
owner : A
set-user-id : on
=
号表示未改变,其值维持启动时的状态
set-user-id | user A exec | user B exec | user root exec |
---|---|---|---|
seteuid(A) | = | = | (effective uid : A) |
seteuid(B) | Operation not permitted | (effective uid : B) | (effective uid : B) |
seteuid(0) | Operation not permitted | Operation not permitted | (effective uid : 0) |
上表中,用户B运行起来的程序,真实用户和有效用户分别是B和A,这时程序里执行seteuid(B)
是可以执行成功的。
但是用户A运行起来的程序,执行seteuid(B)
是未授权的,因为B即不是当前用户也不是有效用户。
应用举例:
有一台小型终端,其上接着一个类似输入设备的外设,基于系统的安全设计,只允许P用户去读写该外设的设备文件,所有对硬件的控制和运算都只能以P的身份去执行,P是一个nologin用户;
该外设的驱动程序需要根据情况向图形(DISPLAY)发送信号;
图形以用户G的身份运行,那么获取DISPLAY文件句柄的操作只能以G的身份去执行才能获取到,向DISPLAY发送信号也只能以G的身份运行才能成功,所以驱动程序内需要在P用户和G用户间不停切换。
可以这样设计程序,使用chmod u+s xxx
将外设驱动程序的强制位权限打开,将驱动程序的属主设置为P,将驱动程序的启动服务交给G,在DISPLAY启动后运行。这样驱动运行时的real-user-id就是G,effective-user-id就是P,可以在G和P间来回切换。