suser() -> capable() for linux/*

Alexander Kjeldaas (astor@guardian.no)
Thu, 23 Apr 1998 18:51:19 +0200


--CMA9jn6tkzFBcd8L
Content-Type: text/plain; charset=us-ascii

This patch changes all suser() to capable() not in the directories
handled by the other patches. The patch also includes the following
things.

* Init is started without CAP_SETPCAP in inheritable and effective
capability set. This means that we don't _by default_ make root any
more powerful than it already is under compatibility mode.

* set*uid() compatibility is handled.

It does not include the system calls to set/get capabilities and
emulate securelevel.

astor

-- 
 Alexander Kjeldaas, Guardian Networks AS, Trondheim, Norway
 http://www.guardian.no/

--CMA9jn6tkzFBcd8L Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=cap_97_3_misc

diff -urN /tmp/l97/arch/alpha/kernel/bios32.c lp97/arch/alpha/kernel/bios32.c --- /tmp/l97/arch/alpha/kernel/bios32.c Fri Apr 10 22:44:09 1998 +++ lp97/arch/alpha/kernel/bios32.c Thu Apr 23 01:25:45 1998 @@ -2041,7 +2041,7 @@ unsigned int uint; long err = 0; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); @@ -2082,7 +2082,7 @@ unsigned int uint; long err = 0; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); diff -urN /tmp/l97/arch/alpha/kernel/ptrace.c lp97/arch/alpha/kernel/ptrace.c --- /tmp/l97/arch/alpha/kernel/ptrace.c Sun Nov 30 19:59:02 1997 +++ lp97/arch/alpha/kernel/ptrace.c Thu Apr 23 01:35:16 1998 @@ -506,7 +506,7 @@ (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff -urN /tmp/l97/arch/arm/kernel/ioport.c lp97/arch/arm/kernel/ioport.c --- /tmp/l97/arch/arm/kernel/ioport.c Wed Jan 21 01:39:41 1998 +++ lp97/arch/arm/kernel/ioport.c Thu Apr 23 01:38:08 1998 @@ -58,7 +58,7 @@ if (from + num > IO_BITMAP_SIZE*32) return -EINVAL; #endif - if (!suser()) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; #ifdef IODEBUG @@ -91,7 +91,7 @@ if (level > 3) return -EINVAL; - if (!suser()) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; *(&eflags) = (eflags & 0xffffcfff) | (level << 12); return 0; diff -urN /tmp/l97/arch/arm/kernel/ptrace.c lp97/arch/arm/kernel/ptrace.c --- /tmp/l97/arch/arm/kernel/ptrace.c Sun Apr 12 20:42:15 1998 +++ lp97/arch/arm/kernel/ptrace.c Thu Apr 23 01:38:18 1998 @@ -581,7 +581,7 @@ (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff -urN /tmp/l97/arch/i386/kernel/ioport.c lp97/arch/i386/kernel/ioport.c --- /tmp/l97/arch/i386/kernel/ioport.c Thu Apr 2 00:51:41 1998 +++ lp97/arch/i386/kernel/ioport.c Thu Apr 23 03:16:10 1998 @@ -58,7 +58,7 @@ if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32)) return -EINVAL; - if (!suser()) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; /* * If it's the first ioperm() call in this thread's lifetime, set the @@ -94,7 +94,7 @@ if (level > 3) return -EINVAL; - if (!suser()) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12); return 0; diff -urN /tmp/l97/arch/i386/kernel/ptrace.c lp97/arch/i386/kernel/ptrace.c --- /tmp/l97/arch/i386/kernel/ptrace.c Thu Mar 12 01:07:20 1998 +++ lp97/arch/i386/kernel/ptrace.c Thu Apr 23 01:24:03 1998 @@ -386,7 +386,7 @@ (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff -urN /tmp/l97/arch/i386/kernel/vm86.c lp97/arch/i386/kernel/vm86.c --- /tmp/l97/arch/i386/kernel/vm86.c Sun Mar 29 21:31:16 1998 +++ lp97/arch/i386/kernel/vm86.c Thu Apr 23 01:03:45 1998 @@ -660,7 +660,7 @@ int sig = irqnumber >> 8; int irq = irqnumber & 255; handle_irq_zombies(); - if (!suser()) return -EPERM; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!((1 << sig) & ALLOWED_SIGS)) return -EPERM; if ( (irq<3) || (irq>15) ) return -EPERM; if (vm86_irqs[irq].tsk) return -EPERM; diff -urN /tmp/l97/arch/m68k/kernel/ptrace.c lp97/arch/m68k/kernel/ptrace.c --- /tmp/l97/arch/m68k/kernel/ptrace.c Sat Mar 21 20:04:04 1998 +++ lp97/arch/m68k/kernel/ptrace.c Thu Apr 23 01:31:41 1998 @@ -340,7 +340,7 @@ (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff -urN /tmp/l97/arch/m68k/kernel/sys_m68k.c lp97/arch/m68k/kernel/sys_m68k.c --- /tmp/l97/arch/m68k/kernel/sys_m68k.c Fri Feb 13 01:30:12 1998 +++ lp97/arch/m68k/kernel/sys_m68k.c Thu Apr 23 01:32:26 1998 @@ -548,7 +548,7 @@ if (scope == FLUSH_SCOPE_ALL) { /* Only the superuser may flush the whole cache. */ ret = -EPERM; - if (!suser ()) + if (!capable(CAP_SYS_ADMIN)) goto out; } else { /* Verify that the specified address region actually belongs to diff -urN /tmp/l97/arch/mips/kernel/ptrace.c lp97/arch/mips/kernel/ptrace.c --- /tmp/l97/arch/mips/kernel/ptrace.c Wed Dec 10 19:31:09 1997 +++ lp97/arch/mips/kernel/ptrace.c Thu Apr 23 01:27:57 1998 @@ -289,7 +289,8 @@ (current->uid != child->uid) || (current->gid != child->egid) || (current->gid != child->sgid) || - (current->gid != child->gid)) && !suser()) { + (current->gid != child->gid)) && + !capable(CAP_SYS_PTRACE)) { res = -EPERM; goto out; } diff -urN /tmp/l97/arch/mips/kernel/sysirix.c lp97/arch/mips/kernel/sysirix.c --- /tmp/l97/arch/mips/kernel/sysirix.c Wed Dec 10 19:31:10 1997 +++ lp97/arch/mips/kernel/sysirix.c Thu Apr 23 01:30:27 1998 @@ -113,7 +113,7 @@ current->comm, current->pid, (unsigned long) value); if(value > RLIM_INFINITY) value = RLIM_INFINITY; - if(suser()) { + if(capable(CAP_SYS_ADMIN)) { current->rlim[RLIMIT_STACK].rlim_max = current->rlim[RLIMIT_STACK].rlim_cur = value; error = value; @@ -545,7 +545,7 @@ int ret; lock_kernel(); - if(!suser()) { + if(!capable(CAP_SYS_TIME)) { ret = -EPERM; goto out; } diff -urN /tmp/l97/arch/mips/kernel/sysmips.c lp97/arch/mips/kernel/sysmips.c --- /tmp/l97/arch/mips/kernel/sysmips.c Wed Dec 10 19:31:10 1997 +++ lp97/arch/mips/kernel/sysmips.c Thu Apr 23 01:29:03 1998 @@ -58,7 +58,7 @@ { case SETNAME: retval = -EPERM; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) goto out; name = (char *) arg1; diff -urN /tmp/l97/arch/ppc/kernel/ptrace.c lp97/arch/ppc/kernel/ptrace.c --- /tmp/l97/arch/ppc/kernel/ptrace.c Thu Apr 23 00:59:18 1998 +++ lp97/arch/ppc/kernel/ptrace.c Thu Apr 23 01:31:17 1998 @@ -331,7 +331,7 @@ (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || - (current->gid != child->gid)) && !suser()) + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff -urN /tmp/l97/arch/sparc/kernel/ptrace.c lp97/arch/sparc/kernel/ptrace.c --- /tmp/l97/arch/sparc/kernel/ptrace.c Thu Mar 12 00:44:14 1998 +++ lp97/arch/sparc/kernel/ptrace.c Thu Apr 23 01:27:20 1998 @@ -539,7 +539,8 @@ (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || - (current->gid != child->gid)) && !suser()) { + (current->gid != child->gid)) && + !capable(CAP_SYS_PTRACE)) { pt_error_return(regs, EPERM); goto out; } diff -urN /tmp/l97/arch/sparc64/kernel/psycho.c lp97/arch/sparc64/kernel/psycho.c --- /tmp/l97/arch/sparc64/kernel/psycho.c Thu Apr 23 00:59:20 1998 +++ lp97/arch/sparc64/kernel/psycho.c Thu Apr 23 01:36:22 1998 @@ -2323,7 +2323,7 @@ unsigned int uint; int err = 0; - if(!suser()) + if(!capable(CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); @@ -2361,7 +2361,7 @@ unsigned int uint; int err = 0; - if(!suser()) + if(!capable(CAP_SYS_ADMIN)) return -EPERM; lock_kernel(); diff -urN /tmp/l97/arch/sparc64/kernel/ptrace.c lp97/arch/sparc64/kernel/ptrace.c --- /tmp/l97/arch/sparc64/kernel/ptrace.c Tue Jan 13 00:15:44 1998 +++ lp97/arch/sparc64/kernel/ptrace.c Thu Apr 23 01:36:00 1998 @@ -557,7 +557,8 @@ (current->uid != child->euid) || (current->uid != child->uid) || (current->gid != child->egid) || - (current->gid != child->gid)) && !suser()) { + (current->gid != child->gid)) && + !capable(CAP_SYS_PTRACE)) { pt_error_return(regs, EPERM); goto out; } diff -urN /tmp/l97/arch/sparc64/kernel/sys_sparc32.c lp97/arch/sparc64/kernel/sys_sparc32.c --- /tmp/l97/arch/sparc64/kernel/sys_sparc32.c Thu Apr 23 00:59:21 1998 +++ lp97/arch/sparc64/kernel/sys_sparc32.c Thu Apr 23 01:33:19 1998 @@ -1366,7 +1366,7 @@ unsigned long type_page; int err, is_smb, is_ncp; - if(!suser()) + if(!capable(CAP_SYS_ADMIN)) return -EPERM; is_smb = is_ncp = 0; err = copy_mount_stuff_to_kernel((const void *)A(type), &type_page); diff -urN /tmp/l97/arch/sparc64/kernel/traps.c lp97/arch/sparc64/kernel/traps.c --- /tmp/l97/arch/sparc64/kernel/traps.c Thu Apr 23 00:59:21 1998 +++ lp97/arch/sparc64/kernel/traps.c Thu Apr 23 01:35:20 1998 @@ -583,7 +583,7 @@ regs->tpc = regs->tnpc; regs->tnpc = regs->tnpc + 4; - if (!suser()) return; + if (!capable(CAP_SYS_ADMIN)) return; size >>= PAGE_SHIFT; addr = PAGE_OFFSET - PAGE_SIZE; page = mem_map - 1; diff -urN /tmp/l97/arch/sparc64/solaris/fs.c lp97/arch/sparc64/solaris/fs.c --- /tmp/l97/arch/sparc64/solaris/fs.c Thu Apr 23 00:59:21 1998 +++ lp97/arch/sparc64/solaris/fs.c Thu Apr 23 01:37:32 1998 @@ -464,7 +464,7 @@ val <<= 9; lock_kernel(); if (val > current->rlim[RLIMIT_FSIZE].rlim_max) { - if (!suser()) { + if (!capable(CAP_SYS_RESOURCE)) { unlock_kernel(); return -EPERM; } diff -urN /tmp/l97/include/linux/blk.h lp97/include/linux/blk.h --- /tmp/l97/include/linux/blk.h Tue Apr 14 22:00:26 1998 +++ lp97/include/linux/blk.h Thu Apr 23 17:37:58 1998 @@ -95,7 +95,7 @@ #endif #define RO_IOCTLS(dev,where) \ - case BLKROSET: { int __val; if (!suser()) return -EACCES; \ + case BLKROSET: { int __val; if (!capable(CAP_SYS_ADMIN)) return -EACCES; \ if (get_user(__val, (int *)(where))) return -EFAULT; \ set_device_ro((dev),__val); return 0; } \ case BLKROGET: { int __val = (is_read_only(dev) != 0) ; \ diff -urN /tmp/l97/include/linux/capability.h lp97/include/linux/capability.h --- /tmp/l97/include/linux/capability.h Tue Apr 14 22:00:11 1998 +++ lp97/include/linux/capability.h Thu Apr 23 17:30:24 1998 @@ -19,16 +19,14 @@ #define _LINUX_CAPABILITY_VERSION 0x19980330 -typedef struct _user_cap_struct { - __u32 version; - __u32 size; - __u8 cap[1]; +typedef struct __user_cap_struct { + __u32 cap[1]; } *cap_t; #ifdef __KERNEL__ typedef struct kernel_cap_struct { - int cap; + __u32 cap; } kernel_cap_t; #endif @@ -46,13 +44,13 @@ /* Override all DAC access, including ACL execute access if [_POSIX_ACL] is defined. Excluding DAC access covered by - CAP_LINUX_IMMUTABLE */ + CAP_LINUX_IMMUTABLE. */ #define CAP_DAC_OVERRIDE 1 /* Overrides all DAC restrictions regarding read and search on files and directories, including ACL restrictions if [_POSIX_ACL] is - defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE */ + defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. */ #define CAP_DAC_READ_SEARCH 2 @@ -82,10 +80,13 @@ #define CAP_KILL 5 /* Allows setgid(2) manipulation */ +/* Allows setgroups(2) */ +/* Allows forged gids on socket credentials passing. */ #define CAP_SETGID 6 -/* Allows setuid(2) manipulation */ +/* Allows set*uid(2) manipulation (including fsuid). */ +/* Allows forged pids on socket credentials passing. */ #define CAP_SETUID 7 @@ -112,9 +113,17 @@ #define CAP_NET_BROADCAST 11 /* Allow interface configuration */ -/* Allow configuring of firewall stuff */ +/* Allow administration of IP firewall, masquerading and accounting */ /* Allow setting debug option on sockets */ /* Allow modification of routing tables */ +/* Allow setting arbitrary process / process group ownership on + sockets */ +/* Allow binding to any address for transparent proxying */ +/* Allow setting TOS (type of service) */ +/* Allow setting promiscuous mode */ +/* Allow clearing driver statistics */ +/* Allow multicasting */ +/* Allow read/write of device-specific registers */ #define CAP_NET_ADMIN 12 @@ -123,7 +132,9 @@ #define CAP_NET_RAW 13 -/* Allow locking of segments in memory */ +/* Allow locking of shared memory segments */ +/* Allow mlock and mlockall (which doesn't really have anything to do + with IPC) */ #define CAP_IPC_LOCK 14 @@ -153,9 +164,42 @@ /* Allow configuration of the secure attention key */ /* Allow administration of the random device */ -/* Allow device administration */ +/* Allow device administration (mknod)*/ /* Allow examination and configuration of disk quotas */ -/* System Admin functions: mount et al */ +/* Allow configuring the kernel's syslog (printk behaviour) */ +/* Allow sending a signal to any process */ +/* Allow setting the domainname */ +/* Allow setting the hostname */ +/* Allow calling bdflush() */ +/* Allow mount() and umount(), setting up new smb connection */ +/* Allow some autofs root ioctls */ +/* Allow nfsservctl */ +/* Allow VM86_REQUEST_IRQ */ +/* Allow to read/write pci config on alpha */ +/* Allow irix_prctl on mips (setstacksize) */ +/* Allow flushing all cache on m68k (sys_cacheflush) */ +/* Allow removing semaphores */ +/* Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores + and shared memory */ +/* Allow locking/unlocking of shared memory segment */ +/* Allow turning swap on/off */ +/* Allow forged pids on socket credentials passing */ +/* Allow setting readahead and flushing buffers on block devices */ +/* Allow setting geometry in floppy driver */ +/* Allow turning DMA on/off in xd driver */ +/* Allow administration of md devices (mostly the above, but some + extra ioctls) */ +/* Allow tuning the ide driver */ +/* Allow access to the nvram device */ +/* Allow administration of apm_bios, serial and bttv (TV) device */ +/* Allow manufacturer commands in isdn CAPI support driver */ +/* Allow reading non-standardized portions of pci configuration space */ +/* Allow DDI debug ioctl on sbpcd driver */ +/* Allow setting up serial ports */ +/* Allow sending raw qic-117 commands */ +/* Allow enabling/disabling tagged queuing on SCSI controllers and sending + arbitrary SCSI commands */ +/* Allow setting encryption key on loopback filesystem */ #define CAP_SYS_ADMIN 21 @@ -163,19 +207,34 @@ #define CAP_SYS_BOOT 22 -/* Allow use of renice() on others, and raising of priority */ +/* Allow raising priority and setting priority on other (different + UID) processes */ +/* Allow use of FIFO and round-robin (realtime) scheduling on own + processes and setting the scheduling algorithm used by another + process. */ #define CAP_SYS_NICE 23 -/* Override resource limits */ +/* Override resource limits. Set resource limits. */ +/* Override quota limits. */ +/* Override reserved space on ext2 filesystem */ +/* NOTE: ext2 honors fsuid when checking for resource overrides, so + you can override using fsuid too */ +/* Override size restrictions on IPC message queues */ +/* Allow more than 64hz interrupts from the real-time clock */ +/* Override max number of consoles on console allocation */ +/* Override max number of keymaps */ #define CAP_SYS_RESOURCE 24 /* Allow manipulation of system clock */ +/* Allow irix_stime on mips */ +/* Allow setting the real-time clock */ #define CAP_SYS_TIME 25 /* Allow configuration of tty devices */ +/* Allow vhangup() of tty */ #define CAP_SYS_TTY_CONFIG 26 @@ -187,6 +246,8 @@ #define CAP_EMPTY_SET { 0 } #define CAP_FULL_SET { ~0 } +#define CAP_INIT_EFF_SET { ~0 & ~CAP_TO_MASK(CAP_SETPCAP) } +#define CAP_INIT_INH_SET { ~0 & ~CAP_TO_MASK(CAP_SETPCAP) } #define CAP_TO_MASK(x) (1 << (x)) #define cap_raise(c, flag) (c.cap |= CAP_TO_MASK(flag)) @@ -196,8 +257,9 @@ #define cap_isclear(c) (!c.cap) #define cap_copy(dest,src) do { (dest).cap = (src).cap; } while(0) -#define cap_clear(c) do { c.cap = 0; } while(0) -#define cap_set_full(c) do { c.cap = ~0; } while(0) +#define cap_clear(c) do { (c).cap = 0; } while(0) +#define cap_set_full(c) do { (c).cap = ~0; } while(0) +#define cap_mask(c,mask) do { (c).cap &= (mask).cap; } while(0) #define cap_is_fs_cap(c) ((c) & CAP_FS_MASK) diff -urN /tmp/l97/include/linux/sched.h lp97/include/linux/sched.h --- /tmp/l97/include/linux/sched.h Tue Apr 14 22:00:12 1998 +++ lp97/include/linux/sched.h Thu Apr 23 17:37:34 1998 @@ -354,7 +354,7 @@ /* process credentials */ \ /* uid etc */ 0,0,0,0,0,0,0,0, \ /* suppl grps*/ 0, {0,}, \ -/* caps */ CAP_FULL_SET, CAP_FULL_SET, CAP_FULL_SET, \ +/* caps */ CAP_INIT_EFF_SET,CAP_INIT_INH_SET,CAP_FULL_SET, \ /* rlimits */ INIT_RLIMITS, \ /* math */ 0, \ /* comm */ "swapper", \ diff -urN /tmp/l97/ipc/msg.c lp97/ipc/msg.c --- /tmp/l97/ipc/msg.c Sun Mar 15 19:25:43 1998 +++ lp97/ipc/msg.c Thu Apr 23 01:51:32 1998 @@ -477,9 +477,10 @@ case IPC_SET: err = -EPERM; if (current->euid != ipcp->cuid && - current->euid != ipcp->uid && !suser()) + current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) + /* We _could_ check for CAP_CHOWN above, but we don't */ goto out; - if (tbuf.msg_qbytes > MSGMNB && !suser()) + if (tbuf.msg_qbytes > MSGMNB && !capable(CAP_SYS_RESOURCE)) goto out; msq->msg_qbytes = tbuf.msg_qbytes; ipcp->uid = tbuf.msg_perm.uid; @@ -492,7 +493,7 @@ case IPC_RMID: err = -EPERM; if (current->euid != ipcp->cuid && - current->euid != ipcp->uid && !suser()) + current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) goto out; freeque (id); diff -urN /tmp/l97/ipc/sem.c lp97/ipc/sem.c --- /tmp/l97/ipc/sem.c Mon Dec 22 02:11:08 1997 +++ lp97/ipc/sem.c Thu Apr 23 01:51:13 1998 @@ -482,7 +482,8 @@ goto out; break; case IPC_RMID: - if (current->euid == ipcp->cuid || current->euid == ipcp->uid || suser()) { + if (current->euid == ipcp->cuid || + current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) { freeary (id); err = 0; goto out; @@ -540,7 +541,8 @@ update_queue(sma); break; case IPC_SET: - if (current->euid == ipcp->cuid || current->euid == ipcp->uid || suser()) { + if (current->euid == ipcp->cuid || + current->euid == ipcp->uid || capable(CAP_SYS_ADMIN)) { ipcp->uid = tbuf.sem_perm.uid; ipcp->gid = tbuf.sem_perm.gid; ipcp->mode = (ipcp->mode & ~S_IRWXUGO) diff -urN /tmp/l97/ipc/shm.c lp97/ipc/shm.c --- /tmp/l97/ipc/shm.c Mon Mar 30 10:21:41 1998 +++ lp97/ipc/shm.c Thu Apr 23 02:10:49 1998 @@ -306,7 +306,7 @@ switch (cmd) { case SHM_UNLOCK: err = -EPERM; - if (!suser()) + if (!capable(CAP_IPC_LOCK)) goto out; err = -EINVAL; if (!(ipcp->mode & SHM_LOCKED)) @@ -318,7 +318,7 @@ /* Should the pages be faulted in here or leave it to user? */ /* need to determine interaction with current->swappable */ err = -EPERM; - if (!suser()) + if (!capable(CAP_IPC_LOCK)) goto out; err = -EINVAL; if (ipcp->mode & SHM_LOCKED) @@ -347,7 +347,8 @@ break; case IPC_SET: if (current->euid == shp->shm_perm.uid || - current->euid == shp->shm_perm.cuid || suser()) { + current->euid == shp->shm_perm.cuid || + capable(CAP_SYS_ADMIN)) { ipcp->uid = tbuf.shm_perm.uid; ipcp->gid = tbuf.shm_perm.gid; ipcp->mode = (ipcp->mode & ~S_IRWXUGO) @@ -359,7 +360,8 @@ goto out; case IPC_RMID: if (current->euid == shp->shm_perm.uid || - current->euid == shp->shm_perm.cuid || suser()) { + current->euid == shp->shm_perm.cuid || + capable(CAP_SYS_ADMIN)) { shp->shm_perm.mode |= SHM_DEST; if (shp->shm_nattch <= 0) killseg (id); diff -urN /tmp/l97/ipc/util.c lp97/ipc/util.c --- /tmp/l97/ipc/util.c Tue Mar 10 23:43:13 1998 +++ lp97/ipc/util.c Thu Apr 23 02:12:12 1998 @@ -47,8 +47,10 @@ else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid)) granted_mode >>= 3; /* is there some bit set in requested_mode but not in granted_mode? */ - if ((requested_mode & ~granted_mode & 0007) && !suser()) + if ((requested_mode & ~granted_mode & 0007) && + !capable(CAP_IPC_OWNER)) return -1; + return 0; } diff -urN /tmp/l97/kernel/acct.c lp97/kernel/acct.c --- /tmp/l97/kernel/acct.c Sat Feb 28 22:33:49 1998 +++ lp97/kernel/acct.c Mon Apr 20 23:56:14 1998 @@ -119,7 +119,7 @@ int error = -EPERM; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_PACCT)) goto out; if (name == (char *)NULL) { diff -urN /tmp/l97/kernel/module.c lp97/kernel/module.c --- /tmp/l97/kernel/module.c Tue Mar 10 23:43:13 1998 +++ lp97/kernel/module.c Mon Apr 20 23:56:14 1998 @@ -120,7 +120,7 @@ struct module *mod; lock_kernel(); - if (!suser()) { + if (!capable(CAP_SYS_MODULE)) { error = -EPERM; goto err0; } @@ -175,7 +175,7 @@ struct module_ref *dep; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_MODULE)) goto err0; if ((namelen = get_mod_name(name_user, &name)) < 0) { error = namelen; @@ -366,7 +366,7 @@ int something_changed; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_MODULE)) goto out; if (name_user) { diff -urN /tmp/l97/kernel/printk.c lp97/kernel/printk.c --- /tmp/l97/kernel/printk.c Mon Apr 13 23:41:53 1998 +++ lp97/kernel/printk.c Mon Apr 20 23:56:14 1998 @@ -130,7 +130,7 @@ int error = -EPERM; lock_kernel(); - if ((type != 3) && !suser()) + if ((type != 3) && !capable(CAP_SYS_ADMIN)) goto out; error = 0; switch (type) { diff -urN /tmp/l97/kernel/sched.c lp97/kernel/sched.c --- /tmp/l97/kernel/sched.c Thu Apr 2 02:26:35 1998 +++ lp97/kernel/sched.c Mon Apr 20 23:56:14 1998 @@ -1227,7 +1227,7 @@ newprio = increment; if (increment < 0) { - if (!suser()) + if (!capable(CAP_SYS_NICE)) return -EPERM; newprio = -increment; increase = 1; @@ -1322,10 +1322,11 @@ goto out_unlock; retval = -EPERM; - if ((policy == SCHED_FIFO || policy == SCHED_RR) && !suser()) + if ((policy == SCHED_FIFO || policy == SCHED_RR) && + !capable(CAP_SYS_NICE)) goto out_unlock; if ((current->euid != p->euid) && (current->euid != p->uid) && - !suser()) + !capable(CAP_SYS_NICE)) goto out_unlock; retval = 0; diff -urN /tmp/l97/kernel/signal.c lp97/kernel/signal.c --- /tmp/l97/kernel/signal.c Tue Apr 14 01:47:48 1998 +++ lp97/kernel/signal.c Mon Apr 20 23:56:14 1998 @@ -235,7 +235,7 @@ && ((sig != SIGCONT) || (current->session != t->session)) && (current->euid ^ t->suid) && (current->euid ^ t->uid) && (current->uid ^ t->suid) && (current->uid ^ t->uid) - && !suser()) + && !capable(CAP_SYS_ADMIN)) goto out_nolock; /* The null signal is a permissions and process existance probe. diff -urN /tmp/l97/kernel/sys.c lp97/kernel/sys.c --- /tmp/l97/kernel/sys.c Thu Apr 23 00:59:29 1998 +++ lp97/kernel/sys.c Wed Apr 22 00:10:34 1998 @@ -114,13 +114,13 @@ if (!proc_sel(p, which, who)) continue; if (p->uid != current->euid && - p->uid != current->uid && !suser()) { + p->uid != current->uid && !capable(CAP_SYS_NICE)) { error = EPERM; continue; } if (error == ESRCH) error = 0; - if (priority > p->priority && !suser()) + if (priority > p->priority && !capable(CAP_SYS_NICE)) error = EACCES; else p->priority = priority; @@ -172,7 +172,7 @@ char buffer[256]; /* We only trust the superuser with rebooting the system. */ - if (!suser()) + if (!capable(CAP_SYS_BOOT)) return -EPERM; /* For safety, we require "magic" arguments. */ @@ -273,7 +273,7 @@ if (rgid != (gid_t) -1) { if ((old_rgid == rgid) || (current->egid==rgid) || - suser()) + capable(CAP_SETGID)) current->gid = rgid; else return -EPERM; @@ -282,7 +282,7 @@ if ((old_rgid == egid) || (current->egid == egid) || (current->sgid == egid) || - suser()) + capable(CAP_SETGID)) current->fsgid = current->egid = egid; else { current->gid = old_rgid; @@ -307,7 +307,7 @@ { int old_egid = current->egid; - if (suser()) + if (capable(CAP_SETGID)) current->gid = current->egid = current->sgid = current->fsgid = gid; else if ((gid == current->gid) || (gid == current->sgid)) current->egid = current->fsgid = gid; @@ -319,6 +319,41 @@ 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 + */ +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)) { + 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) { + cap_copy(current->cap_effective, current->cap_permitted); + } +} + /* * Unprivileged users may change the real uid to the effective uid * or vice versa. (BSD-style) @@ -336,14 +371,15 @@ */ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) { - int old_ruid, old_euid, new_ruid; + int old_ruid, old_euid, old_suid, new_ruid; new_ruid = old_ruid = current->uid; old_euid = current->euid; + old_suid = current->suid; if (ruid != (uid_t) -1) { if ((old_ruid == ruid) || (current->euid==ruid) || - suser()) + capable(CAP_SETUID)) new_ruid = ruid; else return -EPERM; @@ -352,7 +388,7 @@ if ((old_ruid == euid) || (current->euid == euid) || (current->suid == euid) || - suser()) + capable(CAP_SETUID)) current->fsuid = current->euid = euid; else return -EPERM; @@ -375,9 +411,16 @@ if(new_ruid) charge_uid(current, 1); } + + if (!issecure(SECURE_NO_SETUID_FIXUP)) { + cap_emulate_setxuid(old_ruid, old_euid, old_suid); + } + return 0; } + + /* * setuid() is implemented like SysV w/ SAVED_IDS * @@ -392,10 +435,11 @@ asmlinkage int sys_setuid(uid_t uid) { int old_euid = current->euid; - int old_ruid, new_ruid; + int old_ruid, old_suid, new_ruid; old_ruid = new_ruid = current->uid; - if (suser()) + old_suid = current->suid; + if (capable(CAP_SETUID)) new_ruid = current->euid = current->suid = current->fsuid = uid; else if ((uid == current->uid) || (uid == current->suid)) current->fsuid = current->euid = uid; @@ -412,6 +456,11 @@ if(new_ruid) charge_uid(current, 1); } + + if (!issecure(SECURE_NO_SETUID_FIXUP)) { + cap_emulate_setxuid(old_ruid, old_euid, old_suid); + } + return 0; } @@ -422,6 +471,9 @@ */ asmlinkage int 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 (current->uid != 0 && current->euid != 0 && current->suid != 0) { if ((ruid != (uid_t) -1) && (ruid != current->uid) && (ruid != current->euid) && (ruid != current->suid)) @@ -448,6 +500,11 @@ } 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; } @@ -515,11 +572,31 @@ old_fsuid = current->fsuid; if (uid == current->uid || uid == current->euid || - uid == current->suid || uid == current->fsuid || suser()) + uid == current->suid || uid == current->fsuid || + capable(CAP_SETUID)) current->fsuid = uid; if (current->fsuid != old_fsuid) current->dumpable = 0; + /* 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) { + current->cap_effective.cap &= ~CAP_FS_MASK; + } + if (old_fsuid != 0 && current->fsuid == 0) { + current->cap_effective.cap |= + (current->cap_permitted.cap & CAP_FS_MASK); + } + } + return old_fsuid; } @@ -532,7 +609,8 @@ old_fsgid = current->fsgid; if (gid == current->gid || gid == current->egid || - gid == current->sgid || gid == current->fsgid || suser()) + gid == current->sgid || gid == current->fsgid || + capable(CAP_SETGID)) current->fsgid = gid; if (current->fsgid != old_fsgid) current->dumpable = 0; @@ -716,7 +794,7 @@ asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist) { - if (!suser()) + if (!capable(CAP_SETGID)) return -EPERM; if ((unsigned) gidsetsize > NGROUPS) return -EINVAL; @@ -756,7 +834,7 @@ asmlinkage int sys_sethostname(char *name, int len) { - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; @@ -787,7 +865,7 @@ */ asmlinkage int sys_setdomainname(char *name, int len) { - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; @@ -820,7 +898,7 @@ old_rlim = current->rlim + resource; if (((new_rlim.rlim_cur > old_rlim->rlim_max) || (new_rlim.rlim_max > old_rlim->rlim_max)) && - !suser()) + !capable(CAP_SYS_RESOURCE)) return -EPERM; if (resource == RLIMIT_NOFILE) { if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN) diff -urN /tmp/l97/kernel/time.c lp97/kernel/time.c --- /tmp/l97/kernel/time.c Fri Feb 13 01:44:15 1998 +++ lp97/kernel/time.c Mon Apr 20 23:56:14 1998 @@ -87,7 +87,7 @@ { int value; - if (!suser()) + if (!capable(CAP_SYS_TIME)) return -EPERM; if (get_user(value, tptr)) return -EFAULT; @@ -156,7 +156,7 @@ { static int firsttime = 1; - if (!suser()) + if (!capable(CAP_SYS_TIME)) return -EPERM; if (tz) { @@ -221,7 +221,7 @@ long ltemp, mtemp, save_adjust; /* In order to modify anything, you gotta be super-user! */ - if (txc->modes && !suser()) + if (txc->modes && !capable(CAP_SYS_TIME)) return -EPERM; /* Now we validate the data before disabling interrupts */ diff -urN /tmp/l97/mm/mlock.c lp97/mm/mlock.c --- /tmp/l97/mm/mlock.c Fri Feb 27 19:53:07 1998 +++ lp97/mm/mlock.c Thu Apr 23 02:02:27 1998 @@ -144,7 +144,7 @@ struct vm_area_struct * vma, * next; int error; - if (!suser()) + if (!capable(CAP_IPC_LOCK)) return -EPERM; len = (len + ~PAGE_MASK) & PAGE_MASK; end = start + len; @@ -235,7 +235,7 @@ unsigned int def_flags; struct vm_area_struct * vma; - if (!suser()) + if (!capable(CAP_IPC_LOCK)) return -EPERM; def_flags = 0; diff -urN /tmp/l97/mm/swapfile.c lp97/mm/swapfile.c --- /tmp/l97/mm/swapfile.c Tue Apr 7 02:48:34 1998 +++ lp97/mm/swapfile.c Thu Apr 23 02:02:52 1998 @@ -356,7 +356,7 @@ int err = -EPERM; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) goto out; dentry = namei(specialfile); @@ -491,7 +491,7 @@ static int least_priority = 0; lock_kernel(); - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) goto out; memset(&filp, 0, sizeof(filp)); p = swap_info;

--CMA9jn6tkzFBcd8L--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu