最近在看linux内核文件系统的代码,发现有关权限管理的代码好多,最近索性一次性解决,一劳永逸。
我们先看一个我们在用户空间经常使用的一个setuid函数,这个函数就是变更当前进程的uid,对应的内核函数首先是sys_setuid,这个函数定义在kernel/sys.c,定义如下
我们继续看set_user改变真实uid,set_user函数定义如下
我们继续看switch_uid函数,switch_uid函数定义如下
我们先看一个我们在用户空间经常使用的一个setuid函数,这个函数就是变更当前进程的uid,对应的内核函数首先是sys_setuid,这个函数定义在kernel/sys.c,定义如下
asmlinkage long sys_setuid(uid_t uid)
{
/*保存以前的euid,就是有效用户组ID*/
int old_euid = current->euid;
int old_ruid, old_suid, new_suid;
int retval;
/*安全检查,如果没有配置内核支持安全操作就是空,暂时不用管*/
retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID);
if (retval)
return retval;
/*保存旧的uid,suid*/
old_ruid = current->uid;
old_suid = current->suid;
new_suid = old_suid;
/*之前讲解过,检验有没有setuid的权限*/
if (capable(CAP_SETUID)) {
/*如果有对应的权限,变更进程的真实用户号*/
if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
return -EAGAIN;
new_suid = uid;
} /*没有权限,并且设置的权限还和以前的不一样,(肯定不一样,一样还设置个卵子),就返回权限错误*/
else if ((uid != current->uid) && (uid != new_suid))
return -EPERM;
/*euid改变时,不允许产生dump文件*/
if (old_euid != uid) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
/*更改进程结构体的fsuid和suid和euid*/
current->fsuid = current->euid = uid;
current->suid = new_suid;
key_fsuid_changed(current);
proc_id_connector(current, PROC_EVENT_UID);
/*安全操作,暂不管*/
return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
}
我们继续看set_user改变真实uid,set_user函数定义如下
static int set_user(uid_t new_ruid, int dumpclear)
{
struct user_struct *new_user;
/*由于user_struct都是按照hash值链接的,所以根据新的uid分配user_struct结构体*/
new_user = alloc_uid(new_ruid);
if (!new_user)
return -EAGAIN;
/*如果这个用户拥有的进程数目超出了限制就返回错误*/
if (atomic_read(&new_user->processes) >=
current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
new_user != &root_user) {
free_uid(new_user);
return -EAGAIN;
}
/*变更当前进程的user_struct结构体*/
switch_uid(new_user);
/*如果euid变,就不允许产生dump文件*/
if (dumpclear) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
/*当前进程的uid变*/
current->uid = new_ruid;
return 0;
}
我们继续看switch_uid函数,switch_uid函数定义如下
void switch_uid(struct user_struct *new_user)
{
/*指针指向旧的user_struct结构体*/
struct user_struct *old_user;
/* What if a process setreuid()'s and this brings the
* new uid over his NPROC rlimit? We can check this now
* cheaply with the new uid cache, so if it matters
* we should be checking for it. -DaveM
*/
old_user = current->user;
/*新的user_struct计数加一,旧的计数减一*/
atomic_inc(&new_user->processes);
atomic_dec(&old_user->processes);
switch_uid_keyring(new_user);
/*当前进程结构体的user_struct指向新的user_struct*/
current->user = new_user;
/*
* We need to synchronize with __sigqueue_alloc()
* doing a get_uid(p->user).. If that saw the old
* user value, we need to wait until it has exited
* its critical region before we can free the old
* structure.
*/
smp_mb();
spin_unlock_wait(¤t->sighand->siglock);
/*释放旧的结构体*/
free_uid(old_user);
suid_keys(current);
}