/* * 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; int retval; retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); if (retval) return retval; if (capable(CAP_SETGID)) { if (old_egid != gid) { set_dumpable(current->mm, suid_dumpable); smp_wmb(); } current->gid = current->egid = current->sgid = current->fsgid = gid; } else if ((gid == current->gid) || (gid == current->sgid)) { if (old_egid != gid) { set_dumpable(current->mm, suid_dumpable); smp_wmb(); } current->egid = current->fsgid = gid; } else return -EPERM; key_fsgid_changed(current); proc_id_connector(current, PROC_EVENT_GID); 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; int retval; retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); if (retval) return retval; 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; key_fsgid_changed(current); return 0; }
/* * 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; int retval; retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); if (retval) return retval; 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 = suid_dumpable; smp_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; key_fsgid_changed(current); proc_id_connector(current, PROC_EVENT_GID); return 0; }
/* * 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) { set_dumpable(current->mm, suid_dumpable); smp_wmb(); } current->fsgid = gid; key_fsgid_changed(current); proc_id_connector(current, PROC_EVENT_GID); } return old_fsgid; }
/* * 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 = 0; wmb(); } current->fsgid = gid; key_fsgid_changed(current); } return old_fsgid; }
/* * 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; }