linux内核安全随记

以3.14-rc4内核版本为主,代码在线阅读地址:https://elixir.bootlin.com/linux/v3.14-rc4/source

主体标记与进程凭证

进程凭证

主要以uid与gid为主,进程的控制结构中有两个凭证,一个为real_cred,另一个叫cred

其中read_cred被称为客体凭证,而cred被称为主体凭证

比如A->B发信息,A就是主体,而B是客体

凭证的数据结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//include/linux/cred.h

struct cred {
atomic_t usage;
#ifdef CONFIG_DEBUG_CREDENTIALS
atomic_t subscribers; /* number of processes subscribed */
void *put_addr;
unsigned magic;
#define CRED_MAGIC 0x43736564
#define CRED_MAGIC_DEAD 0x44656144
#endif
kuid_t uid; /* real UID of the task */
kgid_t gid; /* real GID of the task */
kuid_t suid; /* saved UID of the task */
kgid_t sgid; /* saved GID of the task */
kuid_t euid; /* effective UID of the task */
kgid_t egid; /* effective GID of the task */
kuid_t fsuid; /* UID for VFS ops */
kgid_t fsgid; /* GID for VFS ops */
unsigned securebits; /* SUID-less security management */
kernel_cap_t cap_inheritable; /* caps our children can inherit */
kernel_cap_t cap_permitted; /* caps we're permitted */
kernel_cap_t cap_effective; /* caps we can actually use */
kernel_cap_t cap_bset; /* capability bounding set */
#ifdef CONFIG_KEYS
unsigned char jit_keyring; /* default keyring to attach requested
* keys to */

struct key __rcu *session_keyring; /* keyring inherited over fork */
struct key *process_keyring; /* keyring private to this process */
struct key *thread_keyring; /* keyring private to this thread */
struct key *request_key_auth; /* assumed request_key authority */
#endif
#ifdef CONFIG_SECURITY
void *security; /* subjective LSM security */
#endif
struct user_struct *user; /* real user ID subscription */
struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
struct group_info *group_info; /* supplementary groups for euid/fsgid */
struct rcu_head rcu; /* RCU deletion hook */
};

下面对uid和gid做一个简单的解释:

uid和gid

uid

  1. uid
    是最早的user id,有时被称为Real id,简写为(r)uid

    • 在资源统计和资源分配中使用(比如限制某用户拥有的进程数量时使用)
  2. euid
    euid即有效uid

    • 在内核做特权判断时使用
    • 与提升权限有关
    • 内核在做ipc(进程间通信)和key(密钥)的访问控制时也使用uid
  3. suid
    saved set user id

    • 用于存储euid的值

euid与特权有关,当euid为0时获得所有权限,因此为了让进程不要总有所有权限,引入了suid,在进程执行完euid=0的操作后,将euid恢复至其他值,将0赋给suid,直到下一次需要特权时才将suid的值传给euid

  1. fsuid
    file system user id,是linux系统独有的
    • 用于在文件系统相关的访问控制中判断操作许可

gid

gid与uid类似,除了(r)gid,egid,sgid和fgid以外,多了一个补充组id:Supplementray Group IDs,他是一个数组,也有一组group id,因为一个用户可以属于多个组

在涉及权限检查中,要判断每一个egid和补充组中的每一个gid,涉及文件还需要fsgid,只要有一个允许访问就可以访问

但也有区别

group id与特权无关,euid==0时进程具有所有权限,而egid或者别的gid为0时,进程不会因此而具备特权

系统调用

与设置uid(泛指)有关的系统调用

  • setuid(uid_t uid):用于设置euid,如果调用进程具有setuid特权,此调用会同时修改(r)uid和suid,调用后三个值相同
  • seteuid(uid_t euid):用于设置euid,但不会设置(r)uid和suid
  • setreuid(uid_t ruid,uid_t euid):可以同时修改(r)uid和euid,若”-1”为参数,则表示维持原有值不变,如果以下两个条件成立则会修改suid
    • 修改了(r)uid
    • 修改了euid且其新值不等于系统调用前的(r)uid
  • setresuid(uid_t ruid,uid_t euid,uid_t suid)同时修改ruid,euid和suid
  • setfsuid(uid_t fsuid),其修改进程的fsuid
    • 设置euid的系统调用中,其也会设置euid的同时设施fsuid,让其值相同

在上述的系统调用中,都会遵循以下几个原则

  1. 具备setuid特权的进程可以将(r)uid,euid,suid,fsuid设置为任意值
  2. 不具setuid特权的进程只能将上述值设为现有的值(除fsuid)
  3. 不具备setuid特权的进程只能将fsuid设置为现有的值之一

而组的相关set调用与uid的类似,只需要简单替换即可,除了下属的例子:

  • setgroups(size_t size,const gid_t *list)
    • 此调用用于一次性赋值进程凭证中的补充组id,该调用需要特权setgid

与get uid(泛指)值相关的函数调用

  • getuid(void):取出调用进程的(r)uid
  • geteuid(void):取出调用进程的euid
  • getresuid(uid_t ruid,uid_t euid,uid_t *suid):取出进程的(r)uid,euid和suid

proc文件接口

可以通过/proc/[pid]/status来反映进程凭证,如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@zhishi:~# cat /proc/8/status
Name: init
State: S (sleeping)
Tgid: 8
Pid: 8
PPid: 1
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 11
Groups:
VmPeak: 0 kB
VmSize: 8944 kB
VmLck: 0 kB
VmHWM: 0 kB
VmRSS: 228 kB
VmData: 0 kB
VmStk: 0 kB
VmExe: 444 kB
VmLib: 0 kB
VmPTE: 0 kB


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!