📄 sys.c
字号:
* Unprivileged users may change the real gid to the effective gid * or vice versa. (BSD-style) * * If you set the real gid at all, or set the effective gid to a value not * equal to the real gid, then the saved gid is set to the new effective gid. * * This makes it possible for a setgid program to completely drop its * privileges, which is often a useful assertion to make when you are doing * a security audit over a program. * * The general idea is that a program which uses just setregid() will be * 100% compatible with BSD. A program which uses just setgid() will be * 100% compatible with POSIX with saved IDs. * * SMP: There are not races, the GIDs are checked only by filesystem * operations (as far as semantic preservation is concerned). */asmlinkage long sys_setregid(gid_t rgid, gid_t egid){ int old_rgid = current->gid; int old_egid = current->egid; int new_rgid = old_rgid; int new_egid = old_egid; if (rgid != (gid_t) - 1) { if ((old_rgid == rgid) || (current->egid == rgid) || capable(CAP_SETGID)) new_rgid = rgid; else return -EPERM; } if (egid != (gid_t) - 1) { if ((old_rgid == egid) || (current->egid == egid) || (current->sgid == egid) || capable(CAP_SETGID)) new_egid = egid; else { return -EPERM; } } if (new_egid != old_egid) { current->mm->dumpable = 0; wmb(); } if (rgid != (gid_t) - 1 || (egid != (gid_t) - 1 && egid != old_rgid)) current->sgid = new_egid; current->fsgid = new_egid; current->egid = new_egid; current->gid = new_rgid; return 0;}/* * setgid() is implemented like SysV w/ SAVED_IDS * * SMP: Same implicit races as above. */asmlinkage long sys_setgid(gid_t gid){ int old_egid = current->egid; if (capable(CAP_SETGID)) { if (old_egid != gid) { current->mm->dumpable = 0; wmb(); } current->gid = current->egid = current->sgid = current->fsgid = gid; } else if ((gid == current->gid) || (gid == current->sgid)) { if (old_egid != gid) { current->mm->dumpable = 0; wmb(); } current->egid = current->fsgid = gid; } else return -EPERM; return 0;}/* * cap_emulate_setxuid() fixes the effective / permitted capabilities of * a process after a call to setuid, setreuid, or setresuid. * * 1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of * {r,e,s}uid != 0, the permitted and effective capabilities are * cleared. * * 2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective * capabilities of the process are cleared. * * 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective * capabilities are set to the permitted capabilities. * * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should * never happen. * * -astor * * cevans - New behaviour, Oct '99 * A process may, via prctl(), elect to keep its capabilities when it * calls setuid() and switches away from uid==0. Both permitted and * effective sets will be retained. * Without this change, it was impossible for a daemon to drop only some * of its privilege. The call to setuid(!=0) would drop all privileges! * Keeping uid 0 is not an option because uid 0 owns too many vital * files.. * Thanks to Olaf Kirch and Peter Benie for spotting this. */extern inline void cap_emulate_setxuid(int old_ruid, int old_euid, int old_suid){ if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && (current->uid != 0 && current->euid != 0 && current->suid != 0) && !current->keep_capabilities) { cap_clear(current->cap_permitted); cap_clear(current->cap_effective); } if (old_euid == 0 && current->euid != 0) { cap_clear(current->cap_effective); } if (old_euid != 0 && current->euid == 0) { current->cap_effective = current->cap_permitted; }}static int set_user(uid_t new_ruid, int dumpclear){ struct user_struct *new_user, *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 */ new_user = alloc_uid(new_ruid); if (!new_user) return -EAGAIN; old_user = current->user; atomic_dec(&old_user->processes); atomic_inc(&new_user->processes); if (dumpclear) { current->mm->dumpable = 0; wmb(); } current->uid = new_ruid; current->user = new_user; free_uid(old_user); return 0;}/* * Unprivileged users may change the real uid to the effective uid * or vice versa. (BSD-style) * * If you set the real uid at all, or set the effective uid to a value not * equal to the real uid, then the saved uid is set to the new effective uid. * * This makes it possible for a setuid program to completely drop its * privileges, which is often a useful assertion to make when you are doing * a security audit over a program. * * The general idea is that a program which uses just setreuid() will be * 100% compatible with BSD. A program which uses just setuid() will be * 100% compatible with POSIX with saved IDs. */asmlinkage long sys_setreuid(uid_t ruid, uid_t euid){ int old_ruid, old_euid, old_suid, new_ruid, new_euid; new_ruid = old_ruid = current->uid; new_euid = old_euid = current->euid; old_suid = current->suid; if (ruid != (uid_t) - 1) { new_ruid = ruid; if ((old_ruid != ruid) && (current->euid != ruid) && !capable(CAP_SETUID)) return -EPERM; } if (euid != (uid_t) - 1) { new_euid = euid; if ((old_ruid != euid) && (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 = 0; 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; if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); } return 0;}/* * 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_ruid, new_suid; old_ruid = new_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 = 0; wmb(); } current->fsuid = current->euid = uid; current->suid = new_suid; if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); } return 0;}/* * 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; 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 = 0; wmb(); } current->euid = euid; current->fsuid = euid; } if (suid != (uid_t) - 1) current->suid = suid; if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); } return 0;}asmlinkage long sys_getresuid(uid_t * ruid, uid_t * euid, uid_t * 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){ 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 = 0; wmb(); } current->egid = egid; current->fsgid = egid; } if (rgid != (gid_t) - 1) current->gid = rgid; if (sgid != (gid_t) - 1) current->sgid = sgid; return 0;}asmlinkage long sys_getresgid(gid_t * rgid, gid_t * egid, gid_t * 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 (uid == current->uid || uid == current->euid || uid == current->suid || uid == current->fsuid || capable(CAP_SETUID)) { if (uid != old_fsuid) { current->mm->dumpable = 0; wmb(); } current->fsuid = uid; } /* We emulate fsuid by essentially doing a scaled-down version * of what we did in setresuid and friends. However, we only * operate on the fs-specific bits of the process' effective * capabilities * * FIXME - is fsuser used for all CAP_FS_MASK capabilities? * if not, we might be a bit too harsh here. */ if (!issecure(SECURE_NO_SETUID_FIXUP)) { if (old_fsuid == 0 && current->fsuid != 0) { cap_t(current->cap_effective) &= ~CAP_FS_MASK; } if (old_fsuid != 0 && current->fsuid == 0) { cap_t(current->cap_effective) |= (cap_t(current->cap_permitted) & CAP_FS_MASK); } } return old_fsuid;}/* * Samma p
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -