Unix进程相关用户ID、用户组ID详解

简介: 我们在使用类UNIX系统时,经常会涉及到各种ID,比如,文件属性相关的用户ID、组ID,进程运行时相关的6个ID:实际ID、实际组ID、有效ID、有效组ID、保存的用户设置ID、保存的设置组ID。

我们在使用类UNIX系统时,经常会涉及到各种ID,比如,文件属性相关的用户ID、组ID,进程运行时相关的6个ID:实际ID、实际组ID、有效ID、有效组ID、保存的用户设置ID、保存的设置组ID。


实际使用过程中,我们经常搞混各个ID基本概念和使用方式,所以,本文用于记录相关内容,方便查阅和使用。


Unix文件相关属性


“一切皆文件”是Unix的基本哲学,Unix系统的所资源都可以用文件来表示。具体到每个文件,其都会有相关的文件属性,本文要说的文件的用户ID、组ID,文件的访问权限就包括在文件的属性中。


文件属性操作相关命令


通过stat命令查看文件的所有属性:


lhl@ubuntu18:~/develops/linux$ stat test
   文件:test
   大小:0   块:0  IO 块:4096   普通空文件
 设备:801h/2049d  Inode:5769793 硬链接:1
 权限:(0644/-rw-r--r--)  Uid:( 1000/ lhl)   Gid:( 1000/ lhl)
 最近访问:2020-02-12 12:54:38.006718573 +0800
 最近更改:2020-02-12 12:54:38.006718573 +0800
 最近改动:2020-02-12 12:54:38.006718573 +0800
 创建时间:-


可以看到,文件的权限、用户ID、组ID。


通过id命令查看某个用户的相关信息,默认为当前用户。


lhl@ubuntu18:~/develops/linux$ id root
 uid=0(root) gid=0(root) 组=0(root)


通过chown命令修改文件所属的用户和组。


hl@ubuntu18:~/develops/linux$ chown --help
 用法:chown [选项]... [所有者][:[组]] 文件...
 -R选项:用于递归修改各级目录下的文件所属用户和用户组。


通过chmod修改文件相关权限。


lhl@ubuntu18:~/develops/linux$ chmod --help
 用法:chmod [选项]... 模式[,模式]... 文件...
 其中,模式来自于'[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=][0-7]+'.


通过usermod修改用户相关的信息。


比如,将用户lhl添加到docker用户组中。
 lhl@ubuntu18:~/develops/docker/docs$ sudo usermod -aG docker lhl
 [sudo] lhl 的密码: 
 lhl@ubuntu18:~/develops/docker/docs$ id lhl
 uid=1000(lhl) gid=1000(lhl) 组=1000(lhl),127(docker)


进程相关ID


与一个进程相关的ID有6个或更多,表示如下:


网络异常,图片无法展示
|


下面分别解析一下各种ID:


  • 首先,必须明确上述个ID是依赖于进程存在的,每当谈到这些ID时,都是相对于进程来说的。


  • 实际用户ID和实际组ID标识我是谁。那么,在Unix系统中,这个“谁”是如何来的呢?答案就是,我们登陆系统时,肯定会指定登陆用户,那么这个登陆用户就是这里的“我“。用户登陆成功后,在整个登陆会话期间,这个“我”不会改变。


  • 有效用户ID和有效组ID决定了进程在访问文件时可以获得权限。


  • 保存的设置用户ID和保存的设置组ID在执行一个程序时包含了有效用户ID和有效组ID的副本。


设置用户ID和设置组ID


通常情况下,进程的有效用户ID等于实际用户ID,进程的有效组ID等于实际组ID。每个文件都有自己的所有者和组所有者,可以通过stat命令查看。


由上文可知,进程依赖于有效用户ID和有效组ID来提供对于文件的访问权限的能力

Unix文件系统提供一种这样的能力,那就是,通过在可执行文件的模式字st_mode中设置一个特殊的标志,即"设置用户ID"来实现进程运行时的有效用户ID的切换,即由实际用户ID转换为可执行文件的所有者ID。对于有效用户组,在st_mode中同样有“设置用户组ID”标志位。


举个例子,Unix的系统passwd命令,用户可以使用该命令修改指定用户的密码,该可执行程序文件的权限如下所示:


lhl@ubuntu18:/usr/bin$ stat passwd 
  文件:passwd
  大小:59640      块:120        IO 块:4096   普通文件
设备:801h/2049d Inode:3408705     硬链接:1
权限:(4755/-rwsr-xr-x)  Uid:(    0/    root)   Gid:(    0/    root)


注意,passwd所有者权限中的那个s,表示启用了“设置用户ID”,而且passwd的所有者ID和所有者组ID都为0(root)。


passwd最终修改/etc/passwd和/etc/shadow两个文件来达到用户密码修改目的,/etc/passwd和/ect/shadow两个文件的用户ID和用户组ID都是root。普通用户是没有权限需改这个两个文件的,但是,通过给passwd增加“设置用户ID“标志之后,就可以实现任何普通用户修改/etc/passwd和/etc/shadow文件的目的。


做一个实验,如果将passwd的“设置用户ID”标志位去掉,那么普通用户也就失去了密码的修改能力了。


去掉passwd的“设置用户ID”标志位。


lhl@ubuntu18:/usr/bin$ sudo chmod u-s passwd 
 [sudo] lhl 的密码: 
 lhl@ubuntu18:/usr/bin$ stat passwd
   文件:passwd
   大小:59640       块:120        IO 块:4096   普通文件
 设备:801h/2049d  Inode:3408705     硬链接:1
 权限:(0755/-rwxr-xr-x)  Uid:(    0/    root)   Gid:(    0/    root)


通过stat passwd可以看到“设置用户ID”标志位已经去掉了。


尝试修改用户密码。


lhl@ubuntu18:/usr/bin$ passwd lhl
 更改 lhl 的密码。
 (当前)UNIX 密码: 
 输入新的 UNIX 密码: 
 重新输入新的 UNIX 密码: 
 passwd:认证令牌操作错误
 passwd:密码未更改


可以看到普通用户lhl,失去了修改其用户密码的能力。


注意,由于给可执行文件增加”设置用户ID“或”设置用户组ID”权限之后,普通用户获得了额外的权限,所以,在使用这项能力时,要特别的谨慎,否则极有可能会造成系统安全问题。


文件访问权限


上面提到过,任何文件都有访问权限,这些对于文件的访问权限保存在文件的模式字st_mode中,Unix系统为三类用户:文件用户,文件用户组,其他用户,分别提供三种权限:可读、可写、可执行,所以共9种权限。


对于文件权限的理解,应该注意一下几个方面:


  • 目录文件:Unix系统把目录当做一种文件,称为目录文件。目录文件的三种权限的含义,经常引起误解,正确的含义如下:


  • 读权限:读取当前目录下所有文件名的权限,所谓的当前目录就是指的具有相应权限的目录。
  • 写权限:修改当前目录下所有文件名的权限,所以在一个目录下创建一个新的文件,或者删除一个文件时,需要对该文件所在的目录具有写权限和执行权限。
  • 执行权限:搜索当前目录下所有文件名的权限,所谓搜索,即 进入目录的权限。对于这个权限,需要注意的PATH环境变量中命令目录,如果引用了一个没有可执行权限的目录,那么shell就不会在该目录下搜索到想要的命令。


  • 对一个文件的读权限决定了我们能够打开该文件进行读操作,这与open函数的O_RSONLY和O_RDWR标志相关。


  • 对一个文件的写权限决定了我们能够打开该文件进行写操作,这与open函数的O_WRONLY和O_RDWR标志相关。


  • 函数族exec执行任何一个普通文件时,必须要有对于该文件的可执行权限。


进程操作文件权限


进程每次打开、创建、删除文件时,内核都会匹配文件访问权限。下图对展示了进程foo访问文件file1时,内核所做的访问权限检验过程。


网络异常,图片无法展示
|


可以看到,由于进程的有效用户ID和有效用户组ID为101,而文件的用户ID和用户组ID为100,所以,进程匹配到的文件访问权限为r-x,而进程foo调用open系统调用打开文件file1时,需要的访问权限是O_RDWR,所以,进程打开文件失败,失败原因是权限不足。


更改用户ID和组ID


Unix系统中,进程的权限依赖于文件本身的权限、进程的有效用户ID、有效组ID以及内核中进程关于文件权限的验证系统。实际情况下,进程可能为了获得对于某些资源的访问权限,需要提权;同样,为了系统安全,进程也会放弃对于某些敏感资源的访问权限,所以,需要降权。一般情况下,在设计应用程序时,我们应该本着“最小特权”的原则设计我们的应用程序,即,应用程序应该只具有完成自身任务所需的最小特权。

那么,Unix如何实现“提权”和“降权”呢?主要依赖于两个函数和一套规则,先说两个函数。


设置函数


#include <unistd.h>
 int setuid(uid_t uid);
 int setguid(uid_t gid);
      两个函数,执行成功返回0,出错返回-1,可以通过perror查看具体的错误信息。


规则


  • 若进程具有root权限,则setuid函数将实际用户ID、有效用户ID,以及保存的设置用户ID设置为uid;
  • 若进程没有root权限,但uid等于实际用户ID或保存的设置用户ID,则setuid只将有效用户ID设置为uid,不改变实际用户ID和保存的设置用户ID;
  • 若上面两个条件都不满足,则将errno设置为EPERM,并返回-1。


注意事项


  • 只有root用户可以修改进程的实际用户ID;
  • 仅当进程文件设置了设置用户ID标志位时,exec函数才会设置有效用户ID,并且将有效用户ID设置为文件的用户ID。否则,exec不会改变有效用户ID,而是将其维持原值。任何时候,都可以调用setuid,将有效用户ID设置为实际用户ID和保存的设置用户ID。自然,有效用户ID不能任意设置值;


修改进程的实际用户ID;


  • 保存的设置用户ID是由exec复制有效用户ID而来的。若设置了进程文件的设置用户ID位,则在执行exec时,其会将文件的用户ID设置为保存的设置用户ID,然后保存这个副本。


相关文章
|
4月前
|
网络协议
Mac根据端口查询进程id的命令
这篇文章介绍了在Mac操作系统上如何使用两种命令来查询监听特定端口的进程ID。第一种方法是使用`netstat -anp tcp -v | grep 端口号`,例如`netstat -anp tcp -v | grep 80`,这将列出所有使用端口80的TCP连接及其相关信息。第二种方法是使用`lsof -P -n -i:端口号`,例如`lsof -P -n -i:8080`,这将显示使用指定端口的进程列表,包括进程ID、用户、文件描述符等信息。文章通过示例展示了如何使用这些命令,并提供了输出结果的截图。
334 2
|
6月前
|
SQL Cloud Native 关系型数据库
云原生数据仓库AnalyticDB操作报错合集之执行sql的进程报错:"unknown connection id",是什么导致的
阿里云AnalyticDB提供了全面的数据导入、查询分析、数据管理、运维监控等功能,并通过扩展功能支持与AI平台集成、跨地域复制与联邦查询等高级应用场景,为企业构建实时、高效、可扩展的数据仓库解决方案。以下是对AnalyticDB产品使用合集的概述,包括数据导入、查询分析、数据管理、运维监控、扩展功能等方面。
808 3
|
7月前
|
Linux Shell C语言
如何在 Linux 中查找父进程 ID (PPID)?
【5月更文挑战第4天】
875 4
如何在 Linux 中查找父进程 ID (PPID)?
进程管理,每一个程序运行,都会有一个独有的ID,进程号
进程管理,每一个程序运行,都会有一个独有的ID,进程号
|
7月前
|
Linux Shell
【Linux】解决:为什么重复创建同一个【进程pid会变化,而ppid父进程id不变?】
【Linux】解决:为什么重复创建同一个【进程pid会变化,而ppid父进程id不变?】
|
7月前
|
弹性计算 运维 Shell
|
7月前
|
弹性计算 运维 Shell
|
Unix Shell API
Unix 进程 API 介绍
Unix 进程 API 介绍
146 0
|
Unix Shell Linux
Unix 设置用户ID和文件访问权限
Unix 设置用户ID和文件访问权限
291 0

相关实验场景

更多