158 / 163 · C11 · 约 8 分钟
身份认证
先记住这句话
操作系统必须可靠识别每个进程背后的主体才能正确执行安全策略。本章讨论身份如何通过进程继承以及登录时的初始绑定附加到进程上。
主体、代理与安全决策
操作系统提供的每项服务都由某个进程发起,该进程充当某个主体的代理。主体可以是人类用户、用户组或特定程序。操作系统查看进程控制块中记录的身份,据此判断是否允许该代理访问某个对象。没有准确的身份信息,最小权限等安全原则就无法落实。
身份的继承机制
新进程几乎总是由已有进程通过 fork 一类的调用创建。操作系统只需把父进程控制块里的身份字段复制到子进程控制块即可。同一登录会话里的所有进程因此共享同一认证结果,除非以后显式改变。
登录时的初始身份绑定
用户第一次接触系统时,操作系统必须核对其声称的身份。核对成功后,操作系统亲自创建第一个进程(通常是 shell 或窗口管理器)并把正确的用户标识写入该进程的控制块。此后该用户的全部活动都建立在这次一次性的认证之上。
凭证记住先前的判定
身份一旦绑定,操作系统就可以生成凭证,把“允许访问某对象”的判定保存下来,避免每次都重新检查。这些凭证存放在页表、打开文件表等进程私有数据结构中。
常见误区
- 把甲用户的身份错误地写进乙用户的进程会导致权限错乱。
- 认证完成后系统通常在整个进程生命期内不再复查,因此最初的错误很难被发现和纠正。
运行一个例子
最低标准 C11 · 完整程序 · 下载 .c
#include <stdio.h>
#include <stdint.h>
typedef struct {
uint32_t uid;
const char *username;
} Identity;
void attach_identity(Identity *id, uint32_t uid, const char *name) {
id->uid = uid;
id->username = name;
}
int main(void) {
Identity login_id;
printf("=== OS Authentication Simulation ===\n");
printf("User attempts login...\n");
/* Simulated successful authentication */
attach_identity(&login_id, 1000, "alice");
printf("Authenticated: UID=%u, User=%s\n", login_id.uid, login_id.username);
printf("Creating initial process (shell) with attached identity.\n");
printf("Forking child process for command execution.\n");
printf("Child inherits UID=%u from parent.\n", login_id.uid);
printf("Security policy can now be applied based on this identity.\n");
return 0;
}
在本地编译
gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-54-authentication.c -o example && ./example预期结果
=== OS Authentication Simulation ===
User attempts login...
Authenticated: UID=1000, User=alice
Creating initial process (shell) with attached identity.
Forking child process for command execution.
Child inherits UID=1000 from parent.
Security policy can now be applied based on this identity.
CHECK YOUR UNDERSTANDING
合上答案,试着解释。
新进程通常如何获得自己的安全身份?登录进程又有何不同?
查看参考答案
普通进程从创建它的父进程继承身份,操作系统在构造子进程控制块时直接复制该字段。登录进程则由操作系统在验证用户凭据之后亲自写入身份,因为它没有可继承的父进程。
继续查证
标准草案与官方章节会更新;版本标记只说明示例最低要求。