Linux下4种uid

linux下有4种uid:
真实uid(real user id)
有效uid(effective user id)
被保存的uid(saved user id)
文件系统的uid

首先需要明确一点,这几个概念都是和进程相关的。
real user ID表示的是实际上进程的执行者是谁,effective user ID主要用于校验该进程在执行时所获得的文件访问权限,也就是说当进程访问文件时检查权限时实际上检查的该进程的"effective user ID",saved set-user-ID 仅在effective user ID发生改变时保存。

一般情况下,real user ID就是进程的effective user ID,但是当要运行的可执行程序设置了"set-user-ID"位之后,进程的effective user ID变成该文件的属主用户id;同时该进程的"saved set-user-ID"变成此时进程的"effective user ID",也就是该可执行程序的属主用户ID。该进程在执行一些与文件访问权限相关的操作时系统检查的是进程的effective user ID。
为什么需要一个"saved set-user-ID"?因为当进程没有超级用户权限的时候,进程在设置"effective user ID"时需要将需要设置的ID和该进程的"real user ID"或者"saved set-user-ID"进行比较。

** setuid(uid)首先请求内核将本进程的[真实uid],[有效uid]和[被保存的uid]都设置成函数指定的uid, 若权限不够则请求只将effective uid设置成uid, 再不行则调用失败。
再具体来说setuid函数的话是这样的规则:
1)当调用之前用户effective uid具有超级用户权限的时候,setuid 函数设置的id对三者都起效.【规则一】
2)否则,仅当该id为real user ID 或者saved set-user-ID时,该id对effective user ID起效.【规则二】
3)否则,setuid函数调用失败.
** seteuid(uid)仅请求内核将本进程的[有效uid]设置成函数指定的uid.

也就是说,这个saved set-user-ID更多的作用是在进程切换自己的effective user ID起作用。
需要特别提醒的是:并没有任何的API可以获取到进程的saved set-user-ID,它仅仅是系统在调用setuid函数时进行比较而起作用的。

举一个例子说明问题,假设这样的一种情况,系统中有两个用户A、B,还有一个由B创建的可执行程序proc,该可执行程序的set-user-id位已经进行了设置。当A用户执行程序proc时,
1)程序的real user ID = A的用户ID,effective user ID = B的用户ID,  saved set-user-ID=B的用户ID.
假如在该进程结束了对某些限制只能由用户B访问的文件操作后,程序将effective user ID设置回A,也就是说此时:
2)程序的real user ID = A的用户ID,effective user ID = A的用户ID,  saved set-user-ID=B的用户ID.
这个改动之所以能成功,原因在于上面列举出的情况2):该ID为进程的real user ID,满足规则二。

最后,假设由于种种原因进程需要再次切换effective user ID为B,可是因为不能通过API获取进程的saved set-user-ID(该值为B的用户ID),所以只能通过两种途径获得(可能还有别的途径):
a)在设置effective user ID变回A之前保存effective user ID,它的值为B的用户ID.
b)调用函数getpwnam( "B"),在返回的struct passwd *指针中成员pw_uid存放的就是用户B的ID.
这样,这个调用setuid(B的用户ID)就会成功,原因也在于上面说的情况2):该ID与进程的saved set-user-ID相同,切换effective user ID为B时满足规则二。

第二个例子:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main() {
    printf("real uid is %d\n", getuid());
    printf("effective uid is %d\n", geteuid());
    getchar();
    if (seteuid(1001) == -1)    /* zzz = 1001 */
    {
        perror("seteuid");
        return -1;
    }
    printf("real uid is %d\n", getuid());
    printf("effective uid is %d\n", geteuid());
    getchar();
    if (seteuid(0) == -1)       /* root = 0 */
    {
        perror("seteuid");
        return -1;
    }
    printf("real uid is %d\n", getuid());
    printf("effective uid is %d\n", geteuid());
    getchar();
}

然后编译代码, 并把可执行文件的属主改为root, 然后添加上set-user-ID位:

gcc uid.c -o uid
sudo chown root:root uid
sudo chmod u+s uid


执行uid之后会打印出如下:

real uid is 1001
effective uid is 0
real uid is 1001
effective uid is 1001
real uid is 1001
effective uid is 0


可以看出, 我们先把effective uid改成了zzz. 之后又可以改回root.这就是saved uid的作用.
另外这个程序中使用的是seteuid而不是setuid, 这是因为如果改成setuid的话, 执行第一个setuid时, 因为当前effective uid为root, 第一个规则就满足, 所以把real uid, effective uid和saved uid都改成zzz了, 因为这样更改了saved uid, 执行第二个setuid时, 规则一&规则二都不满足,调用失败,我们就回不去root了。所以这里使用seteuid函数调用。

一个可执行文件是普通用户B创建的,特权用户A通过chmod u+s ,可执行文件由绿色变为红色,像普通用户B一样执行可执行文件时提示引用的库文件找不到,是什么原因?

在类Unix操作系统中,如果设置了SETUID位的可执行文件在执行时提示“引用的库文件找不到”,这通常意味着以下几种情况之一:

  1. 动态链接库路径问题:如果可执行文件依赖于动态链接库(.so文件),并且这些库文件不在系统默认的库文件搜索路径中,那么即使设置了SETUID位,执行时也可能会找不到这些库文件。系统的库文件搜索路径通常包括几个标准目录,如/lib/usr/lib等,以及通过环境变量LD_LIBRARY_PATH指定的目录。

  2. 权限问题即使库文件位于正确的路径,如果它们没有执行权限,或者执行用户没有读取权限,那么系统也无法加载这些库文件。在设置了SETUID位的情况下,执行时的有效用户ID(euid)是文件所有者的ID,而实际用户ID(uid)是执行者的ID。因此,系统会检查库文件的权限是否允许文件所有者(即设置了SETUID位的用户)读取和执行。

  3. 安全机制某些系统为了安全可能会限制SETUID程序的动态链接。例如,某些系统配置可能会禁止SETUID程序使用LD_LIBRARY_PATH环境变量,以防止通过库注入攻击。在这种情况下,即使库文件存在,也可能因为这种安全机制而无法加载。

  4. 环境问题:如果执行环境与创建环境不一致,可能会导致库文件找不到。例如,如果可执行文件在某个特定的环境下编译,而执行时环境变量设置不同,可能会导致库文件路径解析出错。

为了解决这个问题,可以尝试以下步骤:

  • 确保所有依赖的库文件都位于系统库文件搜索路径中,或者通过LD_LIBRARY_PATH环境变量指定正确的路径。
  • 检查库文件的权限,确保它们对文件所有者(即设置了SETUID位的用户)是可读和可执行的。
  • 如果可能,尝试以文件所有者的身份手动执行该程序,看看是否能够找到库文件,以排除安全机制的限制。
  • 检查执行环境是否与创建环境一致,特别是与库文件路径相关的环境变量设置。

如果问题仍然存在,可能需要更详细地检查系统的日志文件,或者使用调试工具来获取更具体的错误信息。

参考:
【Linux学习笔记】4. 进程的用户/组id
https://blog.csdn.net/weixin_45636061/article/details/123829836
【Linux学习笔记】5. setuid和seteuid详解
https://blog.csdn.net/weixin_45636061/article/details/123832415
chmod u+s权限理解
https://blog.csdn.net/modi000/article/details/114574583

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值