📄 sys.c
字号:
(current->euid != euid) && (current->suid != euid) && !capable(CAP_SETUID)) return -EPERM; } if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) return -EAGAIN; if (new_euid != old_euid) { current->mm->dumpable = suid_dumpable; smp_wmb(); } current->fsuid = current->euid = new_euid; if (ruid != (uid_t) -1 || (euid != (uid_t) -1 && euid != old_ruid)) current->suid = current->euid; current->fsuid = current->euid; key_fsuid_changed(current); proc_id_connector(current, PROC_EVENT_UID); return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);} /* * setuid() is implemented like SysV with SAVED_IDS * * Note that SAVED_ID's is deficient in that a setuid root program * like sendmail, for example, cannot set its uid to be a normal * user and then switch back, because if you're root, setuid() sets * the saved uid too. If you don't like this, blame the bright people * in the POSIX committee and/or USG. Note that the BSD-style setreuid() * will allow a root program to temporarily drop privileges and be able to * regain them by swapping the real and effective uid. */asmlinkage long sys_setuid(uid_t uid){ 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; old_ruid = current->uid; old_suid = current->suid; new_suid = old_suid; 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; if (old_euid != uid) { current->mm->dumpable = suid_dumpable; smp_wmb(); } 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);}/* * This function implements a generic ability to update ruid, euid, * and suid. This allows you to implement the 4.4 compatible seteuid(). */asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid){ int old_ruid = current->uid; int old_euid = current->euid; int old_suid = current->suid; int retval; retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); if (retval) return retval; if (!capable(CAP_SETUID)) { if ((ruid != (uid_t) -1) && (ruid != current->uid) && (ruid != current->euid) && (ruid != current->suid)) return -EPERM; if ((euid != (uid_t) -1) && (euid != current->uid) && (euid != current->euid) && (euid != current->suid)) return -EPERM; if ((suid != (uid_t) -1) && (suid != current->uid) && (suid != current->euid) && (suid != current->suid)) return -EPERM; } if (ruid != (uid_t) -1) { if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0) return -EAGAIN; } if (euid != (uid_t) -1) { if (euid != current->euid) { current->mm->dumpable = suid_dumpable; smp_wmb(); } current->euid = euid; } current->fsuid = current->euid; if (suid != (uid_t) -1) current->suid = 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_RES);}asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid){ int retval; if (!(retval = put_user(current->uid, ruid)) && !(retval = put_user(current->euid, euid))) retval = put_user(current->suid, suid); return retval;}/* * Same as above, but for rgid, egid, sgid. */asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid){ int retval; retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); if (retval) return retval; if (!capable(CAP_SETGID)) { if ((rgid != (gid_t) -1) && (rgid != current->gid) && (rgid != current->egid) && (rgid != current->sgid)) return -EPERM; if ((egid != (gid_t) -1) && (egid != current->gid) && (egid != current->egid) && (egid != current->sgid)) return -EPERM; if ((sgid != (gid_t) -1) && (sgid != current->gid) && (sgid != current->egid) && (sgid != current->sgid)) return -EPERM; } if (egid != (gid_t) -1) { if (egid != current->egid) { current->mm->dumpable = suid_dumpable; smp_wmb(); } current->egid = egid; } current->fsgid = current->egid; if (rgid != (gid_t) -1) current->gid = rgid; if (sgid != (gid_t) -1) current->sgid = sgid; key_fsgid_changed(current); proc_id_connector(current, PROC_EVENT_GID); return 0;}asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid){ int retval; if (!(retval = put_user(current->gid, rgid)) && !(retval = put_user(current->egid, egid))) retval = put_user(current->sgid, sgid); return retval;}/* * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This * is used for "access()" and for the NFS daemon (letting nfsd stay at * whatever uid it wants to). It normally shadows "euid", except when * explicitly set by setfsuid() or for access.. */asmlinkage long sys_setfsuid(uid_t uid){ int old_fsuid; old_fsuid = current->fsuid; if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS)) return old_fsuid; if (uid == current->uid || uid == current->euid || uid == current->suid || uid == current->fsuid || capable(CAP_SETUID)) { if (uid != old_fsuid) { current->mm->dumpable = suid_dumpable; smp_wmb(); } current->fsuid = uid; } key_fsuid_changed(current); proc_id_connector(current, PROC_EVENT_UID); security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); return old_fsuid;}/* * Samma på svenska.. */asmlinkage long sys_setfsgid(gid_t gid){ int old_fsgid; old_fsgid = current->fsgid; if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) return old_fsgid; if (gid == current->gid || gid == current->egid || gid == current->sgid || gid == current->fsgid || capable(CAP_SETGID)) { if (gid != old_fsgid) { current->mm->dumpable = suid_dumpable; smp_wmb(); } current->fsgid = gid; key_fsgid_changed(current); proc_id_connector(current, PROC_EVENT_GID); } return old_fsgid;}asmlinkage long sys_times(struct tms __user * tbuf){ /* * In the SMP world we might just be unlucky and have one of * the times increment as we use it. Since the value is an * atomically safe type this is just fine. Conceptually its * as if the syscall took an instant longer to occur. */ if (tbuf) { struct tms tmp; struct task_struct *tsk = current; struct task_struct *t; cputime_t utime, stime, cutime, cstime; spin_lock_irq(&tsk->sighand->siglock); utime = tsk->signal->utime; stime = tsk->signal->stime; t = tsk; do { utime = cputime_add(utime, t->utime); stime = cputime_add(stime, t->stime); t = next_thread(t); } while (t != tsk); cutime = tsk->signal->cutime; cstime = tsk->signal->cstime; spin_unlock_irq(&tsk->sighand->siglock); tmp.tms_utime = cputime_to_clock_t(utime); tmp.tms_stime = cputime_to_clock_t(stime); tmp.tms_cutime = cputime_to_clock_t(cutime); tmp.tms_cstime = cputime_to_clock_t(cstime); if (copy_to_user(tbuf, &tmp, sizeof(struct tms))) return -EFAULT; } return (long) jiffies_64_to_clock_t(get_jiffies_64());}/* * This needs some heavy checking ... * I just haven't the stomach for it. I also don't fully * understand sessions/pgrp etc. Let somebody who does explain it. * * OK, I think I have the protection semantics right.... this is really * only important on a multi-user system anyway, to make sure one user * can't send a signal to a process owned by another. -TYT, 12/12/91 * * Auch. Had to add the 'did_exec' flag to conform completely to POSIX. * LBT 04.03.94 */asmlinkage long sys_setpgid(pid_t pid, pid_t pgid){ struct task_struct *p; struct task_struct *group_leader = current->group_leader; int err = -EINVAL; if (!pid) pid = group_leader->pid; if (!pgid) pgid = pid; if (pgid < 0) return -EINVAL; /* From this point forward we keep holding onto the tasklist lock * so that our parent does not change from under us. -DaveM */ write_lock_irq(&tasklist_lock); err = -ESRCH; p = find_task_by_pid(pid); if (!p) goto out; err = -EINVAL; if (!thread_group_leader(p)) goto out; if (p->real_parent == group_leader) { err = -EPERM; if (task_session(p) != task_session(group_leader)) goto out; err = -EACCES; if (p->did_exec) goto out; } else { err = -ESRCH; if (p != group_leader) goto out; } err = -EPERM; if (p->signal->leader) goto out; if (pgid != pid) { struct task_struct *g = find_task_by_pid_type(PIDTYPE_PGID, pgid); if (!g || task_session(g) != task_session(group_leader)) goto out; } err = security_task_setpgid(p, pgid); if (err) goto out; if (process_group(p) != pgid) { detach_pid(p, PIDTYPE_PGID); p->signal->pgrp = pgid; attach_pid(p, PIDTYPE_PGID, find_pid(pgid)); } err = 0;out: /* All paths lead to here, thus we are safe. -DaveM */ write_unlock_irq(&tasklist_lock); return err;}asmlinkage long sys_getpgid(pid_t pid){ if (!pid) return process_group(current); else { int retval; struct task_struct *p; read_lock(&tasklist_lock); p = find_task_by_pid(pid); retval = -ESRCH; if (p) { retval = security_task_getpgid(p); if (!retval) retval = process_group(p); } read_unlock(&tasklist_lock); return retval; }}#ifdef __ARCH_WANT_SYS_GETPGRPasmlinkage long sys_getpgrp(void){ /* SMP - assuming writes are word atomic this is fine */ return process_group(current);}#endifasmlinkage long sys_getsid(pid_t pid){ if (!pid) return process_session(current); else { int retval; struct task_struct *p; read_lock(&tasklist_lock); p = find_task_by_pid(pid); retval = -ESRCH; if (p) { retval = security_task_getsid(p); if (!retval) retval = process_session(p); } read_unlock(&tasklist_lock); return retval; }}asmlinkage long sys_setsid(void){ struct task_struct *group_leader = current->group_leader; pid_t session; int err = -EPERM; write_lock_irq(&tasklist_lock); /* Fail if I am already a session leader */ if (group_leader->signal->leader) goto out; session = group_leader->pid; /* Fail if a process group id already exists that equals the * proposed session id. * * Don't check if session id == 1 because kernel threads use this * session id and so the check will always fail and make it so * init cannot successfully call setsid. */ if (session > 1 && find_task_by_pid_type(PIDTYPE_PGID, session)) goto out; group_leader->signal->leader = 1; __set_special_pids(session, session); spin_lock(&group_leader->sighand->siglock); group_leader->signal->tty = NULL; spin_unlock(&group_leader->sighand->siglock); err = process_group(group_leader);out: write_unlock_irq(&tasklist_lock); return err;}/* * Supplementary group IDs *//* init to 2 - one for init_task, one to ensure it is never freed */struct group_info init_groups = { .usage = ATOMIC_INIT(2) };struct group_info *groups_alloc(int gidsetsize){ struct group_info *group_info; int nblocks; int i; nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK; /* Make sure we always allocate at least one indirect block pointer */ nblocks = nblocks ? : 1; group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER); if (!group_info) return NULL; group_info->ngroups = gidsetsize; group_info->nblocks = nblocks; atomic_set(&group_info->usage, 1); if (gidsetsize <= NGROUPS_SMALL) group_info->blocks[0] = group_info->small_block; else { for (i = 0; i < nblocks; i++) { gid_t *b; b = (void *)__get_free_page(GFP_USER); if (!b) goto out_undo_partial_alloc; group_info->blocks[i] = b; } } return group_info;out_undo_partial_alloc: while (--i >= 0) { free_page((unsigned long)group_info->blocks[i]); } kfree(group_info); return NULL;}EXPORT_SYMBOL(groups_alloc);void groups_free(struct group_info *group_info){ if (group_info->blocks[0] != group_info->small_block) { int i; for (i = 0; i < group_info->nblocks; i++) free_page((unsigned long)group_info->blocks[i]); } kfree(group_info);}EXPORT_SYMBOL(groups_free);/* export the group_info to a user-space array */static int groups_to_user(gid_t __user *grouplist, struct group_info *group_info){ int i; int count = group_info->ngroups; for (i = 0; i < group_info->nblocks; i++) { int cp_count = min(NGROUPS_PER_BLOCK, count); int off = i * NGROUPS_PER_BLOCK; int len = cp_count * sizeof(*grouplist); if (copy_to_user(grouplist+off, group_info->blocks[i], len)) return -EFAULT; count -= cp_count; } return 0;}/* fill a group_info from a user-space array - it must be allocated already */static int groups_from_user(struct group_info *group_info, gid_t __user *grouplist){ int i; int count = group_info->ngroups; for (i = 0; i < group_info->nblocks; i++) { int cp_count = min(NGROUPS_PER_BLOCK, count); int off = i * NGROUPS_PER_BLOCK; int len = cp_count * sizeof(*grouplist); if (copy_from_user(group_info->blocks[i], grouplist+off, len)) return -EFAULT; count -= cp_count; } return 0;}/* a simple Shell sort */static void groups_sort(struct group_info *group_info){ int base, max, stride; int gidsetsize = group_info->ngroups; for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1) ; /* nothing */ stride /= 3; while (stride) { max = gidsetsize - stride; for (base = 0; base < max; base++) { int left = base; int right = left + stride; gid_t tmp = GROUP_AT(group_info, right); while (left >= 0 && GROUP_AT(group_info, left) > tmp) { GROUP_AT(group_info, right) = GROUP_AT(group_info, left); right = left; left -= stride;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -