运行统计信息
在进程运行的过程中,会有一些统计量,具体见下面的表,这里面有进程在用户态和内核态消耗的时间,上下文切换的次数等等。
u64 utime;//用户态消耗的CPU时间
u64 stime;//内核态消耗的CPU时间
unsigned long nvcsw;//自愿(voluntary)上下文切换计数
unsigned long nivcsw;//非自愿(involuntary)上下文切换计数
u64 start_time;//进程启动时间,不包含睡眠时间
u64 real_start_time;//进程启动时间,包含睡眠时间
进程亲缘关系
struct task_struct __rcu *real_parent; /* real parent process */
struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
struct list_head children; /* list of my children */
struct list_head sibling; /* linkage in my parent's children list */
parent 指向其父进程。当它终止时,必须向它的父进程发送信号。children 表示链表的头部。链表中的所有元素都是它的子进程。sibling 用于把当前进程插入到兄弟链表中。如果在 bash 上使用 GDB 来 debug 一个进程,这个时候 GDB 是 parent(SIGCHLD的回收者),bash 是这个进程的 real_parent(真正的父进程)。
进程权限
在Linux中对于进程权限的定义如下:
/* Objective and real subjective task credentials (COW): */
const struct cred __rcu *real_cred;
/* Effective (overridable) subjective task credentials (COW): */
const struct cred __rcu *cred;
其中,real_cred 就是说明谁能操作我这个进程,而 cred 就是说明我这个进程能够操作谁。
cred的定义如下:
struct cred {
......
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 */
......
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 */
kernel_cap_t cap_ambient; /* Ambient capability set */
......
} __randomize_layout;
一看这个名字,就知道这个是起“作用”的。当这个进程要操作消息队列、共享内存、信号量等对象的时候,其实就是在比较这个用户和组是否有权限。谁启动的进程就该审核启动的用户有没有这个权限。我们可以通过 chmod u+s program 命令,给这个游戏程序设置 set-user-ID 的标识位。创建的进程 uid 当然还是用户 A,但是 euid 和 fsuid 就不是用户 A 了,因为看到了 set-user-id 标识,就改为文件的所有者的 ID,也就是说,euid 和 fsuid 都改成用户 B 了。一个进程可以随时通过setuid设置用户ID。
linux中的最高权限是root,一般用户都是普通权限,可以引入capabileties,用位图表示权限
在 capability.h 可以找到定义的权限。我这里列举几个。
#define CAP_CHOWN 0
#define CAP_KILL 5
#define CAP_NET_BIND_SERVICE 10
#define CAP_NET_RAW 13
#define CAP_SYS_MODULE 16
#define CAP_SYS_RAWIO 17
#define CAP_SYS_BOOT 22
#define CAP_SYS_TIME 25
#define CAP_AUDIT_READ 37
#define CAP_LAST_CAP CAP_AUDIT_READ
- cap_permitted 表示进程能够使用的权限。
- cap_inheritable,root下可以继承调用者的集合;非root用户的话通常不会保留
- cap_bset,也就是 capability bounding set,是系统中所有进程允许保留的权限。
- cap_ambient非 root 用户进程使用 exec 执行一个程序的时候,如何保留权限的问题。当执行 exec 的时候,cap_ambient 会被添加到 cap_permitted 中,同时设置到 cap_effective 中。
内存管理
每个进程都有自己独立的虚拟内存管理空间,这里需要一个数据结构来表示
struct mm_struct *mm;
struct mm_struct *active_mm;
文件与文件系统
每个进程有一个文件系统的数据结构,还有一个打开文件的数据结构。这个我们放到文件系统那一节详细讲述。
/* Filesystem information: */
struct fs_struct *fs;
/* Open file information: */
struct files_struct *files;
setuid是一个权限的特殊标志位,带有这个标志位可以对文件执行等同root的权限!比如,Linux下修改密码的指令passwd,我们ls去查看时发现其权限就有s标志,这个就是之所以能修改密码的原因。如果去掉这个权限,再以普通用户身份去修改密码则会提示没有权限!这个例子和老师的玩游戏可以说是异曲同工,但它更具有普遍性,大家也更熟悉!