diff -urN linux-2.0.30/Documentation/00-INDEX linux-privs/Documentation/00-INDEX --- linux-2.0.30/Documentation/00-INDEX Thu Jun 6 04:57:43 1996 +++ linux-privs/Documentation/00-INDEX Mon Apr 14 20:29:45 1997 @@ -14,6 +14,8 @@ - how the boss likes the C code in the kernel to look. Configure.help - text file that is used for help when you run "make config" +POSIX.6_cap.txt + - the experimental POSIX.6 capability system SMP.txt - notes, and "To Fix" list for multi-processor Linux. (see smp.tex) cdrom/ diff -urN linux-2.0.30/Documentation/Configure.help linux-privs/Documentation/Configure.help --- linux-2.0.30/Documentation/Configure.help Tue Apr 8 08:47:45 1997 +++ linux-privs/Documentation/Configure.help Mon Apr 14 20:29:45 1997 @@ -764,6 +764,13 @@ available via ftp (user: anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If unsure, say Y. +POSIX.6 capability system +CONFIG_POSIX6_CAP + Please see the file in the Documentation directory. If you enable + this, superuser privileges will be controlled individually, rather + than all being tied to UID zero. This completely changes the way a + Unix system works; say N unless you really know what you are doing. + ARP daemon support (EXPERIMENTAL) CONFIG_ARPD Normally, the kernel maintains an internal cache which maps IP diff -urN linux-2.0.30/Documentation/POSIX.6_cap.txt linux-privs/Documentation/POSIX.6_cap.txt --- linux-2.0.30/Documentation/POSIX.6_cap.txt Wed Dec 31 16:00:00 1969 +++ linux-privs/Documentation/POSIX.6_cap.txt Mon Apr 14 20:29:45 1997 @@ -0,0 +1,187 @@ +POSIX.1e (a.k.a. 6) Capability System +===================================== + + +================================ WARNING =================================== + THIS IS CODE IN DEVELOPMENT AND IS VERY UNSTABLE AND NOT WELL TESTED. + +If you intend using this code or want to help out or just want to say +something about it then please join . + +Please don't send messages to Linux-Kernel. + +Announcements to Linux-Kernel when the maintainers of linux-privs deem +it appropriate, please keep all other discussion off that list. +============================================================================ + + +Rationale +========= + +The basic idea behind POSIX.1e capabilities is that the root user +concept on normal UNIX systems is too coarse grained, i.e. you either +have all access to the system or no privileged access as an ordinary +user. + +The privilege normally given to the user with uid=0 is split into a +number of capabilities designed to give access to do only a single job, +eg reconfigure a TTY, or Net device, or to override read access on file +you wouldn't normally be allowed to access. + + +The System +========== + +Capabilities are stored as bitsets. Currently these are 128 bits each, +but the kernel code has the capability to truncate and zero-fill as +required to talk to other code that wants a different size. + +Each process has three sets of capabilities: + +Inheritable: These capabilities may be inherited through exec(). + In other words, if running process has capabilities "raised" + in this set and then exec()s another file, these capabilities + can be inherited by the new executable. However, this + alone is not enough to actually grant capabilities to the + new executable: it must have the capabilities in *its* + Inheritable set too. + +Permitted: The capabilities that the process may raise in the Effective + and Inheritable sets. + +Effective: Subset of Permitted; used to determine what the process can + actually do. + +Each file has three sets of capabilities, when the file is exec()'d +these three capabilities combine with those of the exec()'ing process +to establish the newly exec()'d process' capabilities: + +Inheritable: This is a mask against which the Inheritable capabilities + of the exec()'ing process are filtered. Only capabilities + in this set may be inherited by the exec()'d process. + +Effective: This set must have either all capabilities raised or all + capabilities lowered. It is used to indicate whether + the program knows about capabilities. If this set has + capabilities raised, the program will start with all of its + Permitted capabilities in its Effective set. If this set is + empty, the program will start with an empty Effective set, + and will have to raise the capabilities it needs itself. + +Permitted: This set is the set of capabilities required by the + executable in order to do its job. These will appear in the + Permitted set of the process after exec()ing this executable. + +On exec, the process' capability sets are modified thus: + + pI' = pI + pP' = fP | (fI & pI) + pE' = pP' & fE [NB. fE is 0 or ~0] + +I=Inheritable, P=Permitted, E=Effective // p=process, f=file +' indicates post-exec(). + +The capabilities are *not* modified on fork. The Effective set is +cleared whenever the EUID is changed. + + +Filesystem modifications (during development) +============================================= + +Along with the patch for the kernel, there is a patch for e2fsprogs-1.06. +You must also build these modified tools. + +Choose a filesystem to experiment with -- *NOT* your root filesystem, or +anything at all important. It must be an ext2 filesystem. If nothing +is handy, create a new filesystem on an empty partition, or a floppy, +or even in a loopback device (if you have that configured). If using +an existing filesystem, issue the command + + tune2fs -O res_fork + +or, if creating a new filesystem, + + mke2fs -O res_fork + +(Note that only the modified e2fsprogs understand the -O option.) +This sets a flag on the filesystem to indicate that extra information +-- such as capability sets -- can be stored on each inode. Old Linux +systems will be unable to mount the filesystem at all, and any kernel +without the POSIX.6 patch will be unable to mount it read/write. + +DO NOT USE THE UNPATCHED E2FSCK ON THIS FILESYSTEM! If you are lucky, +it will notice that it is inadequate and bail out. But it might go +steaming straight ahead and mangle the filesystem. + + +Using capabilities (during development) +======================================= + +Enable Experimental options, enable CONFIG_POSIX6_CAP, build the kernel, and +reboot. + +The POSIX.6 capabilities will be in operation immediately, but nothing +will have any capabilites. For this reason, UID 0 (root) will *also* be +all-powerful. root privileges can be disabled by setting securelevel to 2 +("echo 2 > /proc/sys/kernel/securelevel"), but once this is done there is +no way back other than a reboot, unless you have a modified init. + +You can set capabilities on a file on an appropriate filesystem using +the captest program in the scripts directory. For example, + +captest -fs i=8.9,p=8.9,e=1 + +will set the CAP_SETGID (8) and CAP_SETUID (9) capabilities in the +Inheritable and Permitted sets on the . The number used with the +`e=' part is not very important: if a number is present, capabilities +will be raised automatically when the file is executed, and if it is +absent they will not. + +Note, you need to be superuser (or have the CAP_SETFCAP capability) to +do this, you also need to own the file (or have CAP_FOWNER raised). +(See /usr/include/linux/capability.h for the numbers.) If su is given +these particular capabilities, it won't need to be setuid root any +more. The odd rules for capability inheritance mean that an +unmodified su won't leak privileges. + +You can check file capabilities by doing + +captest -fg ipe + +The capabilities of a running process can be checked by looking at +/proc//capabilities. The bitsets are listed in hexadecimal. +The blocks are listed in little-endian order (i.e., the first block of +digits represents privileges 0 to 31). + + +Status +====== + +Processes have capability sets. These can be listed through the /proc fs. +System calls _setproccap() and _getproccap() are implemented and tested. + +Resource forks are implemented in the ext2 filesystem. (That code works +but needs some review.) A readonly-compatible feature flag has been +assigned to indicate the presence of resource forks. The e2fsprogs have +been modified to handle resource forks correctly. + +File capabilities can now be stored. File capabilities can be set and +read via the internal interface read_inode_caps() and write_inode_caps(). +System calls _{,f}{s,g}etfilecap() are implemented and tested. + +Capabilities are computed appropriately on exec, and the dumpable flag +handled. Capabilities are also cleared when a file is written to, and +when the EUID is changed by syscall. These things are not fully tested +yet, but the code is sufficiently simple to leave little room for doubt. + +The capable() function, for testing capabilities, is implemented. +(The securelevel mechanism has been improved as required.) All (as of +kernel version 2.0.30) existing {,f}suser() checks have been converted to +use it. Additional actions have been permitted based on the CAP_SIGMASK +and CAP_LINK_DIR capabilities; uid=0 does *not* confer these capabilities. + +TODO: implement the proper user-space interface to the syscalls. +(Header and a library.) + +TODO: implement user-space utilities for listing and setting file +capabilities. diff -urN linux-2.0.30/arch/alpha/config.in linux-privs/arch/alpha/config.in --- linux-2.0.30/arch/alpha/config.in Mon Aug 5 00:13:50 1996 +++ linux-privs/arch/alpha/config.in Mon Apr 14 20:29:45 1997 @@ -94,6 +94,11 @@ bool 'System V IPC' CONFIG_SYSVIPC tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'POSIX.6 (aka. .1e) capability system (experimental)' CONFIG_POSIX6_CAP +fi + endmenu source drivers/block/Config.in diff -urN linux-2.0.30/arch/alpha/defconfig linux-privs/arch/alpha/defconfig --- linux-2.0.30/arch/alpha/defconfig Tue Oct 29 17:42:40 1996 +++ linux-privs/arch/alpha/defconfig Mon Apr 14 20:29:45 1997 @@ -42,6 +42,7 @@ CONFIG_SYSVIPC=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y +# CONFIG_POSIX6_CAP is not set # # Floppy, IDE, and other block devices diff -urN linux-2.0.30/arch/alpha/kernel/ptrace.c linux-privs/arch/alpha/kernel/ptrace.c --- linux-2.0.30/arch/alpha/kernel/ptrace.c Wed Sep 11 07:57:13 1996 +++ linux-privs/arch/alpha/kernel/ptrace.c Mon Apr 14 20:29:45 1997 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -514,7 +515,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)) return -EPERM; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff -urN linux-2.0.30/arch/alpha/kernel/signal.c linux-privs/arch/alpha/kernel/signal.c --- linux-2.0.30/arch/alpha/kernel/signal.c Tue Aug 20 23:18:07 1996 +++ linux-privs/arch/alpha/kernel/signal.c Mon Apr 14 20:29:45 1997 @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -17,7 +18,8 @@ #include #define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _NBLOCKABLE (_S(SIGKILL) | _S(SIGSTOP)) +#define _BLOCKABLE (~_NBLOCKABLE) asmlinkage int sys_wait4(int, int *, int, struct rusage *); asmlinkage void ret_from_sys_call(void); @@ -54,7 +56,8 @@ unsigned long block, unblock; oldmask = tsk->blocked; - newmask &= _BLOCKABLE; + if((newmask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + newmask &= _BLOCKABLE; sign = how-2; unblock = oldmask & ~newmask; block = oldmask | newmask; @@ -74,7 +77,9 @@ asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct switch_stack * sw) { unsigned long oldmask = current->blocked; - current->blocked = mask & _BLOCKABLE; + if((mask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + mask &= _BLOCKABLE; + current->blocked = mask; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); @@ -98,7 +103,7 @@ if (get_fs_quad(&sc->sc_ps) != 8) do_exit(SIGSEGV); mask = get_fs_quad(&sc->sc_mask); - if (mask & ~_BLOCKABLE) + if ((mask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) do_exit(SIGSEGV); /* ok, looks fine, start restoring */ @@ -235,8 +240,12 @@ if (sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - if (!(sa->sa_flags & SA_NOMASK)) - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + if (!(sa->sa_flags & SA_NOMASK)) { + unsigned long mask = sa->sa_mask; + if((mask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + mask &= _BLOCKABLE; + current->blocked |= mask | _S(signr); + } } static inline void syscall_restart(unsigned long r0, unsigned long r19, diff -urN linux-2.0.30/arch/i386/config.in linux-privs/arch/i386/config.in --- linux-2.0.30/arch/i386/config.in Sun May 12 21:17:23 1996 +++ linux-privs/arch/i386/config.in Mon Apr 14 20:29:45 1997 @@ -43,6 +43,11 @@ 486 CONFIG_M486 \ Pentium CONFIG_M586 \ PPro CONFIG_M686" Pentium + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'POSIX.6 (aka. .1e) capability system (experimental)' CONFIG_POSIX6_CAP +fi + endmenu source drivers/block/Config.in diff -urN linux-2.0.30/arch/i386/defconfig linux-privs/arch/i386/defconfig --- linux-2.0.30/arch/i386/defconfig Tue Oct 29 17:42:40 1996 +++ linux-privs/arch/i386/defconfig Mon Apr 14 20:29:45 1997 @@ -29,6 +29,7 @@ # CONFIG_M486 is not set CONFIG_M586=y # CONFIG_M686 is not set +# CONFIG_POSIX6_CAP is not set # # Floppy, IDE, and other block devices diff -urN linux-2.0.30/arch/i386/kernel/entry.S linux-privs/arch/i386/kernel/entry.S --- linux-2.0.30/arch/i386/kernel/entry.S Wed Dec 11 06:41:01 1996 +++ linux-privs/arch/i386/kernel/entry.S Mon Apr 14 20:29:45 1997 @@ -674,6 +674,13 @@ .long SYMBOL_NAME(sys_sched_rr_get_interval) .long SYMBOL_NAME(sys_nanosleep) .long SYMBOL_NAME(sys_mremap) - .long 0,0 + .long 0,0 /* 165 */ .long SYMBOL_NAME(sys_vm86) - .space (NR_syscalls-166)*4 + .long 0,0 + .long SYMBOL_NAME(sys_setproccap) + .long SYMBOL_NAME(sys_getproccap) /* 170 */ + .long SYMBOL_NAME(sys_setfilecap) + .long SYMBOL_NAME(sys_getfilecap) + .long SYMBOL_NAME(sys_fsetfilecap) + .long SYMBOL_NAME(sys_fgetfilecap) + .space (NR_syscalls-174)*4 diff -urN linux-2.0.30/arch/i386/kernel/ioport.c linux-privs/arch/i386/kernel/ioport.c --- linux-2.0.30/arch/i386/kernel/ioport.c Wed Jan 11 11:10:53 1995 +++ linux-privs/arch/i386/kernel/ioport.c Mon Apr 14 20:29:45 1997 @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -54,7 +55,7 @@ return -EINVAL; if (from + num > IO_BITMAP_SIZE*32) return -EINVAL; - if (!suser()) + if (!capable(CAP_LINUX_RAWIO)) return -EPERM; set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on); @@ -82,7 +83,7 @@ if (level > 3) return -EINVAL; - if (!suser()) + if (!capable(CAP_LINUX_RAWIO)) return -EPERM; *(&eflags) = (eflags & 0xffffcfff) | (level << 12); return 0; diff -urN linux-2.0.30/arch/i386/kernel/ptrace.c linux-privs/arch/i386/kernel/ptrace.c --- linux-2.0.30/arch/i386/kernel/ptrace.c Wed Sep 11 07:57:13 1996 +++ linux-privs/arch/i386/kernel/ptrace.c Mon Apr 14 20:29:45 1997 @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -324,7 +325,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)) return -EPERM; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff -urN linux-2.0.30/arch/i386/kernel/signal.c linux-privs/arch/i386/kernel/signal.c --- linux-2.0.30/arch/i386/kernel/signal.c Wed Dec 11 06:41:01 1996 +++ linux-privs/arch/i386/kernel/signal.c Mon Apr 14 20:29:45 1997 @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -19,7 +20,8 @@ #define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _NBLOCKABLE (_S(SIGKILL) | _S(SIGSTOP)) +#define _BLOCKABLE (~_NBLOCKABLE) asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs); @@ -33,7 +35,9 @@ struct pt_regs * regs = (struct pt_regs *) &restart; mask = current->blocked; - current->blocked = set & _BLOCKABLE; + if((set & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + set &= _BLOCKABLE; + current->blocked = set; regs->eax = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; @@ -89,12 +93,16 @@ if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x); struct sigcontext_struct context; struct pt_regs * regs; + unsigned long mask; regs = (struct pt_regs *) &__unused; if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context))) goto badframe; memcpy_fromfs(&context,(void *) regs->esp, sizeof(context)); - current->blocked = context.oldmask & _BLOCKABLE; + mask = context.oldmask; + if((mask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + mask &= _BLOCKABLE; + current->blocked = mask; COPY_SEG(ds); COPY_SEG(es); COPY_SEG(fs); @@ -251,8 +259,12 @@ if (sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - if (!(sa->sa_flags & SA_NOMASK)) - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + if (!(sa->sa_flags & SA_NOMASK)) { + unsigned long mask = sa->sa_mask; + if((mask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + mask &= _BLOCKABLE; + current->blocked |= mask | _S(signr); + } } /* diff -urN linux-2.0.30/arch/i386/kernel/vm86.c linux-privs/arch/i386/kernel/vm86.c --- linux-2.0.30/arch/i386/kernel/vm86.c Tue Feb 25 12:22:17 1997 +++ linux-privs/arch/i386/kernel/vm86.c Mon Apr 14 20:29:45 1997 @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -611,7 +612,7 @@ int sig = irqnumber >> 8; int irq = irqnumber & 255; handle_irq_zombies(); - if (!suser()) return -EPERM; + if (!capable(CAP_LINUX_RAWIO)) 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 linux-2.0.30/arch/m68k/config.in linux-privs/arch/m68k/config.in --- linux-2.0.30/arch/m68k/config.in Sun May 19 21:54:26 1996 +++ linux-privs/arch/m68k/config.in Mon Apr 14 20:29:45 1997 @@ -31,6 +31,11 @@ if [ "$CONFIG_AMIGA" = "y" ]; then bool 'Amiga AutoConfig Identification' CONFIG_ZORRO fi + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'POSIX.6 (aka. .1e) capability system (experimental)' CONFIG_POSIX6_CAP +fi + endmenu # diff -urN linux-2.0.30/arch/m68k/defconfig linux-privs/arch/m68k/defconfig --- linux-2.0.30/arch/m68k/defconfig Mon May 6 02:44:30 1996 +++ linux-privs/arch/m68k/defconfig Mon Apr 14 20:29:45 1997 @@ -23,6 +23,7 @@ CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_ZORRO is not set +# CONFIG_POSIX6_CAP is not set # # Block device driver configuration diff -urN linux-2.0.30/arch/m68k/kernel/console.c linux-privs/arch/m68k/kernel/console.c --- linux-2.0.30/arch/m68k/kernel/console.c Mon May 6 02:26:02 1996 +++ linux-privs/arch/m68k/kernel/console.c Mon Apr 14 20:29:46 1997 @@ -104,6 +104,7 @@ */ #include +#include #include #include #include @@ -272,7 +273,8 @@ long p, q; /* prevent users from taking too much memory */ - if (currcons >= MAX_NR_USER_CONSOLES && !suser()) + if (currcons >= MAX_NR_USER_CONSOLES && + !capable(CAP_SYS_RESOURCE)) return -EPERM; /* due to the granularity of kmalloc, we waste some memory here */ diff -urN linux-2.0.30/arch/m68k/kernel/ptrace.c linux-privs/arch/m68k/kernel/ptrace.c --- linux-2.0.30/arch/m68k/kernel/ptrace.c Sun May 19 21:54:26 1996 +++ linux-privs/arch/m68k/kernel/ptrace.c Mon Apr 14 20:29:46 1997 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -346,7 +347,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)) return -EPERM; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff -urN linux-2.0.30/arch/m68k/kernel/signal.c linux-privs/arch/m68k/kernel/signal.c --- linux-2.0.30/arch/m68k/kernel/signal.c Sun May 19 21:54:26 1996 +++ linux-privs/arch/m68k/kernel/signal.c Mon Apr 14 20:29:46 1997 @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -30,7 +31,8 @@ #define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _NBLOCKABLE (_S(SIGKILL) | _S(SIGSTOP)) +#define _BLOCKABLE (~_NBLOCKABLE) asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs); @@ -62,7 +64,9 @@ unsigned long oldmask = current->blocked; unsigned long newmask = regs->d3; - current->blocked = newmask & _BLOCKABLE; + if((newmask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + newmask &= _BLOCKABLE; + current->blocked = newmask; regs->d0 = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; @@ -86,6 +90,7 @@ int formatvec = 0; unsigned long fp; unsigned long usp = rdusp(); + unsigned long mask; #if 0 printk("sys_sigreturn, usp=%08x\n", (unsigned) usp); @@ -104,7 +109,10 @@ fp = usp + sizeof (context); /* restore signal mask */ - current->blocked = context.sc_mask & _BLOCKABLE; + mask = context.sc_mask; + if((mask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + mask &= _BLOCKABLE; + current->blocked = mask; /* restore passed registers */ regs->ptregs.d0 = context.sc_d0; diff -urN linux-2.0.30/arch/m68k/kernel/sys_m68k.c linux-privs/arch/m68k/kernel/sys_m68k.c --- linux-2.0.30/arch/m68k/kernel/sys_m68k.c Wed May 15 23:05:10 1996 +++ linux-privs/arch/m68k/kernel/sys_m68k.c Mon Apr 14 20:29:46 1997 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -470,7 +471,7 @@ if (scope == FLUSH_SCOPE_ALL) { /* Only the superuser may flush the whole cache. */ - if (!suser ()) + if (!capable(CAP_LINUX_RAWIO)) return -EPERM; } else diff -urN linux-2.0.30/arch/mips/config.in linux-privs/arch/mips/config.in --- linux-2.0.30/arch/mips/config.in Sat May 4 23:05:58 1996 +++ linux-privs/arch/mips/config.in Mon Apr 14 20:29:46 1997 @@ -50,6 +50,11 @@ # fi #fi bool 'System V IPC' CONFIG_SYSVIPC + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'POSIX.6 (aka. .1e) capability system (experimental)' CONFIG_POSIX6_CAP +fi + endmenu mainmenu_option next_comment diff -urN linux-2.0.30/arch/mips/defconfig linux-privs/arch/mips/defconfig --- linux-2.0.30/arch/mips/defconfig Wed Feb 7 19:41:50 1996 +++ linux-privs/arch/mips/defconfig Mon Apr 14 20:29:46 1997 @@ -26,6 +26,7 @@ CONFIG_CPU_LITTLE_ENDIAN=y # CONFIG_NET is not set # CONFIG_SYSVIPC is not set +# CONFIG_POSIX6_CAP is not set # # Loadable module support diff -urN linux-2.0.30/arch/mips/kernel/ptrace.c linux-privs/arch/mips/kernel/ptrace.c --- linux-2.0.30/arch/mips/kernel/ptrace.c Wed Dec 13 02:39:44 1995 +++ linux-privs/arch/mips/kernel/ptrace.c Mon Apr 14 20:29:46 1997 @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -304,7 +305,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)) return -EPERM; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff -urN linux-2.0.30/arch/mips/kernel/signal.c linux-privs/arch/mips/kernel/signal.c --- linux-2.0.30/arch/mips/kernel/signal.c Sun Mar 10 23:39:33 1996 +++ linux-privs/arch/mips/kernel/signal.c Mon Apr 14 20:29:46 1997 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ #include +#include #include #include #include @@ -18,7 +19,8 @@ #define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _NBLOCKABLE (_S(SIGKILL) | _S(SIGSTOP)) +#define _BLOCKABLE (~_NBLOCKABLE) asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs); @@ -32,7 +34,9 @@ struct pt_regs * regs = (struct pt_regs *) &restart; mask = current->blocked; - current->blocked = set & _BLOCKABLE; + if((set & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + set &= _BLOCKABLE; + current->blocked = set; regs->reg2 = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; @@ -48,6 +52,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) { struct sigcontext_struct *context; + unsigned long mask; /* * We don't support fixing ADEL/ADES exceptions for signal stack frames. @@ -59,7 +64,10 @@ (regs->reg29 & 3)) goto badframe; - current->blocked = context->sc_oldmask & _BLOCKABLE; + mask = context->sc_oldmask; + if((mask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + mask &= _BLOCKABLE; + current->blocked = mask; regs->reg1 = context->sc_at; regs->reg2 = context->sc_v0; regs->reg3 = context->sc_v1; diff -urN linux-2.0.30/arch/mips/kernel/sysmips.c linux-privs/arch/mips/kernel/sysmips.c --- linux-2.0.30/arch/mips/kernel/sysmips.c Wed Dec 13 02:39:44 1995 +++ linux-privs/arch/mips/kernel/sysmips.c Mon Apr 14 20:29:46 1997 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -57,7 +58,7 @@ switch(cmd) { case SETNAME: - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; name = (char *) arg1; len = get_max_hostname((unsigned long)name); diff -urN linux-2.0.30/arch/ppc/config.in linux-privs/arch/ppc/config.in --- linux-2.0.30/arch/ppc/config.in Mon May 27 02:00:57 1996 +++ linux-privs/arch/ppc/config.in Mon Apr 14 20:29:46 1997 @@ -38,6 +38,12 @@ bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'POSIX.6 (aka. .1e) capability system (experimental)' CONFIG_POSIX6_CAP +fi + +endmenu + source drivers/block/Config.in if [ "$CONFIG_NET" = "y" ]; then diff -urN linux-2.0.30/arch/ppc/kernel/ptrace.c linux-privs/arch/ppc/kernel/ptrace.c --- linux-2.0.30/arch/ppc/kernel/ptrace.c Mon May 27 02:00:58 1996 +++ linux-privs/arch/ppc/kernel/ptrace.c Mon Apr 14 20:29:46 1997 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -398,7 +399,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)) return -EPERM; /* the same process cannot be attached many times */ if (child->flags & PF_PTRACED) diff -urN linux-2.0.30/arch/ppc/kernel/signal.c linux-privs/arch/ppc/kernel/signal.c --- linux-2.0.30/arch/ppc/kernel/signal.c Mon Jul 8 01:27:43 1996 +++ linux-privs/arch/ppc/kernel/signal.c Mon Apr 14 20:29:46 1997 @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -16,7 +17,8 @@ #define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _NBLOCKABLE (_S(SIGKILL) | _S(SIGSTOP)) +#define _BLOCKABLE (~_NBLOCKABLE) asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); @@ -28,7 +30,9 @@ unsigned long mask; mask = current->blocked; - current->blocked = set & _BLOCKABLE; + if((set & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + set &= _BLOCKABLE; + current->blocked = set; regs->gpr[3] = -EINTR; #if 0 printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, regs->nip, set); @@ -49,8 +53,12 @@ struct sigcontext_struct *sc; struct pt_regs *int_regs; int signo; + unsigned long mask; sc = (struct sigcontext_struct *)regs->gpr[1]; - current->blocked = sc->oldmask & _BLOCKABLE; + mask = sc->oldmask; + if((mask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + mask &= _BLOCKABLE; + current->blocked = mask; int_regs = sc->regs; signo = sc->signal; sc++; /* Pop signal 'context' */ diff -urN linux-2.0.30/arch/sparc/config.in linux-privs/arch/sparc/config.in --- linux-2.0.30/arch/sparc/config.in Thu Apr 25 03:22:05 1996 +++ linux-privs/arch/sparc/config.in Mon Apr 14 20:29:46 1997 @@ -29,6 +29,11 @@ bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'POSIX.6 (aka. .1e) capability system (experimental)' CONFIG_POSIX6_CAP +fi + endmenu mainmenu_option next_comment diff -urN linux-2.0.30/arch/sparc/defconfig linux-privs/arch/sparc/defconfig --- linux-2.0.30/arch/sparc/defconfig Thu Apr 25 03:22:05 1996 +++ linux-privs/arch/sparc/defconfig Mon Apr 14 20:29:46 1997 @@ -20,6 +20,7 @@ CONFIG_NET=y CONFIG_SYSVIPC=y CONFIG_BINFMT_ELF=y +# CONFIG_POSIX6_CAP is not set # # Floppy, IDE, and other block devices diff -urN linux-2.0.30/arch/sparc/kernel/ptrace.c linux-privs/arch/sparc/kernel/ptrace.c --- linux-2.0.30/arch/sparc/kernel/ptrace.c Sat May 4 09:39:23 1996 +++ linux-privs/arch/sparc/kernel/ptrace.c Mon Apr 14 20:29:46 1997 @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -478,7 +479,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); return; } diff -urN linux-2.0.30/arch/sparc/kernel/signal.c linux-privs/arch/sparc/kernel/signal.c --- linux-2.0.30/arch/sparc/kernel/signal.c Thu Apr 25 03:22:05 1996 +++ linux-privs/arch/sparc/kernel/signal.c Mon Apr 14 20:29:46 1997 @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -19,7 +20,8 @@ #define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _NBLOCKABLE (_S(SIGKILL) | _S(SIGSTOP)) +#define _BLOCKABLE (~_NBLOCKABLE) asmlinkage int sys_waitpid(pid_t pid, unsigned long *stat_addr, int options); asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs); @@ -33,7 +35,9 @@ unsigned long mask; mask = current->blocked; - current->blocked = set & _BLOCKABLE; + if((set & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + set &= _BLOCKABLE; + current->blocked = set; /* Advance over the syscall instruction for when * we return. We want setup_frame to save the proper @@ -63,9 +67,11 @@ unsigned long mask; unsigned long set; - set = regs->u_regs [UREG_I0]; mask = current->blocked; - current->blocked = set & _BLOCKABLE; + set = regs->u_regs [UREG_I0]; + if((set & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + set &= _BLOCKABLE; + current->blocked = set; regs->pc = regs->npc; regs->npc += 4; while (1) { @@ -83,6 +89,7 @@ { struct sigcontext_struct *scptr = (struct sigcontext_struct *) regs->u_regs[UREG_I0]; + unsigned long mask; synchronize_user_stack(); @@ -97,7 +104,10 @@ if((scptr->sigc_pc | scptr->sigc_npc) & 3) return; /* Nice try. */ - current->blocked = scptr->sigc_mask & _BLOCKABLE; + mask = scptr->sigc_mask; + if((mask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + mask &= _BLOCKABLE; + current->blocked = mask; current->tss.sstk_info.cur_status = (scptr->sigc_onstack & 1); regs->pc = scptr->sigc_pc; regs->npc = scptr->sigc_npc; diff -urN linux-2.0.30/arch/sparc/kernel/sys_sparc.c linux-privs/arch/sparc/kernel/sys_sparc.c --- linux-2.0.30/arch/sparc/kernel/sys_sparc.c Thu Apr 25 03:22:05 1996 +++ linux-privs/arch/sparc/kernel/sys_sparc.c Mon Apr 14 20:29:46 1997 @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -57,15 +58,8 @@ * If data has been written to the file, remove the setuid and * the setgid bits. We do it anyway otherwise there is an * extremely exploitable race - does your OS get it right |-> - * - * Set ATTR_FORCE so it will always be changed. */ - if (!suser() && (inode->i_mode & (S_ISUID | S_ISGID))) { - struct iattr newattrs; - newattrs.ia_mode = inode->i_mode & ~(S_ISUID | S_ISGID); - newattrs.ia_valid = ATTR_CTIME | ATTR_MODE | ATTR_FORCE; - notify_change(inode, &newattrs); - } + clear_file_privs(inode); down(&inode->i_sem); error = file->f_op->write(inode,file,buf,count); diff -urN linux-2.0.30/drivers/block/floppy.c linux-privs/drivers/block/floppy.c --- linux-2.0.30/drivers/block/floppy.c Tue Apr 8 08:47:45 1997 +++ linux-privs/drivers/block/floppy.c Mon Apr 14 20:29:46 1997 @@ -121,6 +121,7 @@ #include +#include #include #include #include @@ -3133,7 +3134,7 @@ (g->stretch&~(FD_STRETCH|FD_SWAPSIDES)) != 0) return -EINVAL; if (type){ - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EPERM; LOCK_FDC(drive,1); for (cnt = 0; cnt < N_DRIVE; cnt++){ @@ -3306,7 +3307,7 @@ return -EINVAL; /* permission checks */ - if (((cmd & 0x80) && !suser()) || + if (((cmd & 0x80) && !capable(CAP_SYS_DEVICES)) || ((cmd & 0x40) && !IOCTL_ALLOWED)) return -EPERM; diff -urN linux-2.0.30/drivers/block/hd.c linux-privs/drivers/block/hd.c --- linux-2.0.30/drivers/block/hd.c Thu Feb 29 21:50:39 1996 +++ linux-privs/drivers/block/hd.c Mon Apr 14 20:29:46 1997 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -803,7 +804,7 @@ (long *) &loc->start); return 0; case BLKRASET: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_DEVICES)) return -EACCES; if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; return 0; @@ -822,7 +823,7 @@ put_user(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg); return 0; case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_DEVICES)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; @@ -831,7 +832,7 @@ return revalidate_hddisk(inode->i_rdev, 1); case HDIO_SET_UNMASKINTR: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_DEVICES)) return -EACCES; if ((arg > 1) || (MINOR(inode->i_rdev) & 0x3F)) return -EINVAL; unmask_intr[dev] = arg; @@ -854,7 +855,7 @@ return 0; case HDIO_SET_MULTCOUNT: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_DEVICES)) return -EACCES; if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL; save_flags(flags); cli(); /* a prior request might still be in progress */ diff -urN linux-2.0.30/drivers/block/ide.c linux-privs/drivers/block/ide.c --- linux-2.0.30/drivers/block/ide.c Tue Nov 19 06:21:06 1996 +++ linux-privs/drivers/block/ide.c Mon Apr 14 20:29:46 1997 @@ -274,6 +274,7 @@ #include #include #include +#include #include #include #include @@ -2040,13 +2041,13 @@ return 0; } case BLKFLSBUF: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_DEVICES)) return -EACCES; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); return 0; case BLKRASET: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_DEVICES)) return -EACCES; if(arg > 0xff) return -EINVAL; read_ahead[MAJOR(inode->i_rdev)] = arg; return 0; @@ -2057,7 +2058,7 @@ case BLKGETSIZE: /* Return device size */ return write_fs_long(arg, drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects); case BLKRRPART: /* Re-read partition tables */ - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_DEVICES)) return -EACCES; return revalidate_disk(inode->i_rdev); case HDIO_GET_KEEPSETTINGS: @@ -2089,7 +2090,7 @@ return write_fs_long(arg, drive->bad_wstat == BAD_R_STAT); case HDIO_SET_DMA: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_DEVICES)) return -EACCES; #ifdef CONFIG_BLK_DEV_IDECD if (drive->media == ide_cdrom) return -EPERM; @@ -2102,7 +2103,7 @@ if (arg > 1) return -EINVAL; case HDIO_SET_32BIT: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_DEVICES)) return -EACCES; if ((MINOR(inode->i_rdev) & PARTN_MASK)) return -EINVAL; save_flags(flags); @@ -2148,7 +2149,7 @@ return 0; case HDIO_SET_MULTCOUNT: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_DEVICES)) return -EACCES; if (MINOR(inode->i_rdev) & PARTN_MASK) return -EINVAL; if (drive->id && arg > drive->id->max_multsect) @@ -2169,7 +2170,7 @@ { byte args[4], *argbuf = args; int argsize = 4; - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_DEVICES)) return -EACCES; if (NULL == (void *) arg) { err = ide_do_drive_cmd(drive, &rq, ide_wait); } else if (!(err = verify_area(VERIFY_READ,(void *)arg, 4))) { @@ -2195,7 +2196,7 @@ return err; } case HDIO_SET_PIO_MODE: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_DEVICES)) return -EACCES; if (MINOR(inode->i_rdev) & PARTN_MASK) return -EINVAL; if (!HWIF(drive)->tuneproc) diff -urN linux-2.0.30/drivers/block/loop.c linux-privs/drivers/block/loop.c --- linux-2.0.30/drivers/block/loop.c Mon Jul 15 03:47:39 1996 +++ linux-privs/drivers/block/loop.c Mon Apr 14 20:29:46 1997 @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -418,7 +419,7 @@ info.lo_flags = lo->lo_flags; strncpy(info.lo_name, lo->lo_name, LO_NAME_SIZE); info.lo_encrypt_type = lo->lo_encrypt_type; - if (lo->lo_encrypt_key_size && suser()) { + if (lo->lo_encrypt_key_size && capable(CAP_SYS_DEVICES)) { info.lo_encrypt_key_size = lo->lo_encrypt_key_size; memcpy(info.lo_encrypt_key, lo->lo_encrypt_key, lo->lo_encrypt_key_size); diff -urN linux-2.0.30/drivers/block/md.c linux-privs/drivers/block/md.c --- linux-2.0.30/drivers/block/md.c Sat Jun 29 14:04:00 1996 +++ linux-privs/drivers/block/md.c Mon Apr 14 20:29:46 1997 @@ -19,6 +19,7 @@ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -271,7 +272,7 @@ int minor, err; struct hd_geometry *loc = (struct hd_geometry *) arg; - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EACCES; if (((minor=MINOR(inode->i_rdev)) & 0x80) && diff -urN linux-2.0.30/drivers/block/rd.c linux-privs/drivers/block/rd.c --- linux-2.0.30/drivers/block/rd.c Tue Jul 2 09:08:41 1996 +++ linux-privs/drivers/block/rd.c Mon Apr 14 20:29:46 1997 @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -157,7 +158,7 @@ switch (cmd) { case BLKFLSBUF: - if (!suser()) return -EACCES; + if (!capable(CAP_SYS_DEVICES)) return -EACCES; invalidate_buffers(inode->i_rdev); break; case BLKGETSIZE: /* Return device size */ diff -urN linux-2.0.30/drivers/block/xd.c linux-privs/drivers/block/xd.c --- linux-2.0.30/drivers/block/xd.c Sun Sep 8 09:50:20 1996 +++ linux-privs/drivers/block/xd.c Mon Apr 14 20:29:47 1997 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -265,7 +266,7 @@ } break; case BLKRASET: - if(!suser()) + if(!capable(CAP_SYS_DEVICES)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; @@ -283,7 +284,8 @@ } break; case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_DEVICES)) + return -EACCES; if(!(inode->i_rdev)) return -EINVAL; fsync_dev(inode->i_rdev); diff -urN linux-2.0.30/drivers/cdrom/sbpcd.c linux-privs/drivers/cdrom/sbpcd.c --- linux-2.0.30/drivers/cdrom/sbpcd.c Mon Sep 2 05:18:26 1996 +++ linux-privs/drivers/cdrom/sbpcd.c Mon Apr 14 20:29:47 1997 @@ -319,6 +319,7 @@ #include #include +#include #include #include #include @@ -3968,7 +3969,7 @@ switch (cmd) /* Sun-compatible */ { case DDIOCSDBG: /* DDI Debug */ - if (!suser()) RETURN_UP(-EPERM); + if (!capable(CAP_SYS_DEVICES)) RETURN_UP(-EPERM); i=sbpcd_dbg_ioctl(arg,1); RETURN_UP(i); @@ -4510,7 +4511,7 @@ RETURN_UP(0); case BLKRASET: - if(!suser()) RETURN_UP(-EACCES); + if(!capable(CAP_SYS_DEVICES)) RETURN_UP(-EACCES); if(!(inode->i_rdev)) RETURN_UP(-EINVAL); if(arg > 0xff) RETURN_UP(-EINVAL); read_ahead[MAJOR(inode->i_rdev)] = arg; diff -urN linux-2.0.30/drivers/char/apm_bios.c linux-privs/drivers/char/apm_bios.c --- linux-2.0.30/drivers/char/apm_bios.c Tue May 14 23:06:55 1996 +++ linux-privs/drivers/char/apm_bios.c Mon Apr 14 20:29:47 1997 @@ -60,6 +60,7 @@ #include #include +#include #include #include #include @@ -972,7 +973,7 @@ as->event_tail = as->event_head = 0; as->suspends_pending = as->standbys_pending = 0; as->suspends_read = as->standbys_read = 0; - as->suser = suser(); + as->suser = capable(CAP_SYS_ADMIN); as->next = user_list; user_list = as; filp->private_data = as; diff -urN linux-2.0.30/drivers/char/baycom.c linux-privs/drivers/char/baycom.c --- linux-2.0.30/drivers/char/baycom.c Mon Jul 8 00:21:45 1996 +++ linux-privs/drivers/char/baycom.c Mon Apr 14 20:29:47 1997 @@ -86,6 +86,7 @@ #include #include #include +#include #include #include #include @@ -1851,7 +1852,7 @@ return 0; case BAYCOMCTL_SETPARAMS: - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EPERM; i = verify_area(VERIFY_READ, (void *) arg, sizeof(par)); diff -urN linux-2.0.30/drivers/char/console.c linux-privs/drivers/char/console.c --- linux-2.0.30/drivers/char/console.c Thu Nov 7 01:25:21 1996 +++ linux-privs/drivers/char/console.c Mon Apr 14 20:29:47 1997 @@ -86,6 +86,7 @@ */ #include +#include #include #include #include @@ -311,7 +312,7 @@ long p, q; /* prevent users from taking too much memory */ - if (i >= MAX_NR_USER_CONSOLES && !suser()) + if (i >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE)) return -EPERM; /* due to the granularity of kmalloc, we waste some memory here */ diff -urN linux-2.0.30/drivers/char/cyclades.c linux-privs/drivers/char/cyclades.c --- linux-2.0.30/drivers/char/cyclades.c Mon Oct 7 22:03:17 1996 +++ linux-privs/drivers/char/cyclades.c Mon Apr 14 20:29:47 1997 @@ -266,6 +266,7 @@ #include #include #include +#include #include #include #include @@ -1870,7 +1871,7 @@ memcpy_fromfs(&new_serial,new_info,sizeof(new_serial)); old_info = *info; - if (!suser()) { + if (!capable(CAP_SYS_TTY_CONFIG)) { if ((new_serial.close_delay != info->close_delay) || ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))) diff -urN linux-2.0.30/drivers/char/istallion.c linux-privs/drivers/char/istallion.c --- linux-2.0.30/drivers/char/istallion.c Mon May 6 02:26:05 1996 +++ linux-privs/drivers/char/istallion.c Mon Apr 14 20:29:47 1997 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1727,7 +1728,7 @@ #endif memcpy_fromfs(&sio, sp, sizeof(struct serial_struct)); - if (!suser()) { + if (!capable(CAP_SYS_TTY_CONFIG)) { if ((sio.baud_base != portp->baud_base) || (sio.close_delay != portp->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != (portp->flags & ~ASYNC_USR_MASK))) diff -urN linux-2.0.30/drivers/char/lp.c linux-privs/drivers/char/lp.c --- linux-2.0.30/drivers/char/lp.c Thu Apr 3 19:15:34 1997 +++ linux-privs/drivers/char/lp.c Mon Apr 14 20:29:47 1997 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -437,7 +438,7 @@ int newirq = arg; struct lp_struct *lp = &lp_table[minor]; - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EPERM; oldirq = LP_IRQ(minor); @@ -502,7 +503,7 @@ return retval; else { memcpy_tofs((int *) arg, &LP_STAT(minor), sizeof(struct lp_stats)); - if (suser()) + if (capable(CAP_SYS_DEVICES)) memset(&LP_STAT(minor), 0, sizeof(struct lp_stats)); } break; diff -urN linux-2.0.30/drivers/char/random.c linux-privs/drivers/char/random.c --- linux-2.0.30/drivers/char/random.c Tue Apr 8 08:47:45 1997 +++ linux-privs/drivers/char/random.c Mon Apr 14 20:29:47 1997 @@ -228,6 +228,7 @@ #include #include +#include #include #include #include @@ -1167,7 +1168,7 @@ put_user(ent_count, (int *) arg); return 0; case RNDADDTOENTCNT: - if (!suser()) + if (!capable(CAP_LINUX_RANDOM)) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg, sizeof(int)); if (retval) @@ -1196,7 +1197,7 @@ wake_up_interruptible(&random_wait); return 0; case RNDGETPOOL: - if (!suser()) + if (!capable(CAP_LINUX_RANDOM)) return -EPERM; p = (int *) arg; retval = verify_area(VERIFY_WRITE, (void *) p, sizeof(int)); @@ -1220,7 +1221,7 @@ memcpy_tofs(p, random_state.pool, size*sizeof(__u32)); return 0; case RNDADDENTROPY: - if (!suser()) + if (!capable(CAP_LINUX_RANDOM)) return -EPERM; p = (int *) arg; retval = verify_area(VERIFY_READ, (void *) p, 2*sizeof(int)); @@ -1254,13 +1255,13 @@ wake_up_interruptible(&random_wait); return 0; case RNDZAPENTCNT: - if (!suser()) + if (!capable(CAP_LINUX_RANDOM)) return -EPERM; random_state.entropy_count = 0; return 0; case RNDCLEARPOOL: /* Clear the entropy pool and associated counters. */ - if (!suser()) + if (!capable(CAP_LINUX_RANDOM)) return -EPERM; rand_clear_pool(); return 0; diff -urN linux-2.0.30/drivers/char/riscom8.c linux-privs/drivers/char/riscom8.c --- linux-2.0.30/drivers/char/riscom8.c Fri Apr 26 02:12:25 1996 +++ linux-privs/drivers/char/riscom8.c Mon Apr 14 20:29:47 1997 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1446,7 +1447,7 @@ change_speed = ((port->flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); - if (!suser()) { + if (!capable(CAP_SYS_TTY_CONFIG)) { if ((tmp.close_delay != port->close_delay) || (tmp.closing_wait != port->closing_wait) || ((tmp.flags & ~ASYNC_USR_MASK) != diff -urN linux-2.0.30/drivers/char/rtc.c linux-privs/drivers/char/rtc.c --- linux-2.0.30/drivers/char/rtc.c Mon May 27 21:39:18 1996 +++ linux-privs/drivers/char/rtc.c Mon Apr 14 20:29:48 1997 @@ -43,6 +43,7 @@ * this driver.) */ +#include #include #include #include @@ -217,7 +218,8 @@ * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. */ - if ((rtc_freq > 64) && (!suser())) + if ((rtc_freq > 64) && + (!capable(CAP_SYS_RESOURCE))) return -EACCES; if (!(rtc_status & RTC_TIMER_ON)) { @@ -326,7 +328,7 @@ unsigned int yrs; unsigned long flags; - if (!suser()) + if (!capable(CAP_SYS_TIME)) return -EACCES; retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time)); @@ -417,7 +419,7 @@ * We don't really want Joe User generating more * than 64Hz of interrupts on a multi-user machine. */ - if ((arg > 64) && (!suser())) + if ((arg > 64) && (!capable(CAP_SYS_RESOURCE))) return -EACCES; while (arg > (1< #include #include +#include #include #include #include @@ -2116,7 +2117,7 @@ { int found = 1; - if (!suser()) return -EPERM; + if (!capable(CAP_SYS_DEVICES)) return -EPERM; if (!arg) return -EFAULT; if (Nchips >= MAXSCC) @@ -2202,7 +2203,7 @@ if (cmd == TIOCSCCINI) { - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EPERM; if (Nchips == 0) @@ -2225,7 +2226,7 @@ if (!arg) return -EFAULT; - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EPERM; memcpy_fromfs(&scc->modem, (void *) arg, sizeof(struct scc_modem)); diff -urN linux-2.0.30/drivers/char/serial.c linux-privs/drivers/char/serial.c --- linux-2.0.30/drivers/char/serial.c Tue Apr 8 08:47:45 1997 +++ linux-privs/drivers/char/serial.c Mon Apr 14 20:29:48 1997 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -963,7 +964,7 @@ */ if (serial_inp(info, UART_LSR) == 0xff) { restore_flags(flags); - if (suser()) { + if (capable(CAP_SYS_TTY_CONFIG)) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); return 0; @@ -989,7 +990,7 @@ "serial", NULL); if (retval) { restore_flags(flags); - if (suser()) { + if (capable(CAP_SYS_TTY_CONFIG)) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -1538,7 +1539,7 @@ change_irq = new_serial.irq != info->irq; change_port = (new_serial.port != info->port) || (new_serial.hub6 != info->hub6); - if (!suser()) { + if (!capable(CAP_SYS_TTY_CONFIG)) { if (change_irq || change_port || (new_serial.baud_base != info->baud_base) || (new_serial.type != info->type) || @@ -1710,7 +1711,7 @@ { int retval; - if (!suser()) + if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; if (info->count > 1) @@ -1831,7 +1832,7 @@ int retval; void (*handler)(int, void *, struct pt_regs *); - if (!suser()) + if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; if (!in_multi) return -EFAULT; @@ -1996,7 +1997,7 @@ return get_lsr_info(info, (unsigned int *) arg); case TIOCSERSWILD: - if (!suser()) + if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; error = verify_area(VERIFY_READ, (void *) arg,sizeof(long)); if (error) diff -urN linux-2.0.30/drivers/char/stallion.c linux-privs/drivers/char/stallion.c --- linux-2.0.30/drivers/char/stallion.c Mon May 6 02:26:06 1996 +++ linux-privs/drivers/char/stallion.c Mon Apr 14 20:29:48 1997 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1101,7 +1102,7 @@ #endif memcpy_fromfs(&sio, sp, sizeof(struct serial_struct)); - if (!suser()) { + if (!capable(CAP_SYS_TTY_CONFIG)) { if ((sio.baud_base != portp->baud_base) || (sio.close_delay != portp->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != (portp->flags & ~ASYNC_USR_MASK))) diff -urN linux-2.0.30/drivers/char/tpqic02.c linux-privs/drivers/char/tpqic02.c --- linux-2.0.30/drivers/char/tpqic02.c Thu Feb 29 21:50:41 1996 +++ linux-privs/drivers/char/tpqic02.c Mon Apr 14 20:29:48 1997 @@ -201,6 +201,7 @@ #define REALLY_SLOW_IO /* it sure is ... */ #include +#include #include #include #include @@ -2257,7 +2258,7 @@ } if (MINOR(dev)==255) /* special case for resetting */ - if (suser()) + if (capable(CAP_SYS_DEVICES)) return (tape_reset(1)==TE_OK) ? -EAGAIN : -ENXIO; else return -EPERM; @@ -2583,7 +2584,7 @@ #ifdef DDIOCSDBG /* Check for DDI Debug Control, contributed by FvK, edited by HHB. */ if (c == DDIOCSDBG) { - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EPERM; error = verify_area(VERIFY_READ, (int *) ioarg, sizeof(int)); if (error) return error; @@ -2634,7 +2635,7 @@ tpqputs(TPQD_ALWAYS, "sizeof(struct mtconfiginfo) does not match!"); return -EFAULT; } - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EPERM; if ((doing_read!=NO) || (doing_write!=NO)) return -EBUSY; diff -urN linux-2.0.30/drivers/char/tty_io.c linux-privs/drivers/char/tty_io.c --- linux-2.0.30/drivers/char/tty_io.c Thu Oct 31 04:34:58 1996 +++ linux-privs/drivers/char/tty_io.c Mon Apr 14 20:29:48 1997 @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -1242,7 +1243,8 @@ else retval = -ENODEV; - if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser()) + if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && + !capable(CAP_SYS_TTY_CONFIG)) retval = -EBUSY; if (retval) { @@ -1423,7 +1425,8 @@ switch (cmd) { case TIOCSTI: - if ((current->tty != tty) && !suser()) + if ((current->tty != tty) && + !capable(CAP_SYS_TTY_CONFIG)) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg, 1); if (retval) @@ -1459,7 +1462,7 @@ return 0; case TIOCCONS: if (tty->driver.type == TTY_DRIVER_TYPE_CONSOLE) { - if (!suser()) + if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; redirect = NULL; return 0; @@ -1506,7 +1509,7 @@ * This tty is already the controlling * tty for another session group! */ - if ((arg == 1) && suser()) { + if ((arg == 1) && capable(CAP_SYS_TTY_CONFIG)) { /* * Steal it away */ @@ -1573,7 +1576,8 @@ case TIOCLINUX: if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) return -EINVAL; - if (current->tty != tty && !suser()) + if (current->tty != tty && + !capable(CAP_SYS_TTY_CONFIG)) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg, 1); if (retval) @@ -1621,7 +1625,7 @@ set_vesa_blanking(arg); return 0; case 11: /* set kmsg redirect */ - if (!suser()) + if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg+1, 1); diff -urN linux-2.0.30/drivers/char/tty_ioctl.c linux-privs/drivers/char/tty_ioctl.c --- linux-2.0.30/drivers/char/tty_ioctl.c Sun Sep 17 22:54:08 1995 +++ linux-privs/drivers/char/tty_ioctl.c Mon Apr 14 20:29:48 1997 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -506,7 +507,7 @@ sizeof (struct termios)); return 0; case TIOCSLCKTRMIOS: - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EPERM; retval = verify_area(VERIFY_READ, (void *) arg, sizeof (struct termios)); diff -urN linux-2.0.30/drivers/char/vt.c linux-privs/drivers/char/vt.c --- linux-2.0.30/drivers/char/vt.c Sun May 12 21:36:19 1996 +++ linux-privs/drivers/char/vt.c Mon Apr 14 20:29:48 1997 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -212,7 +213,7 @@ * to be the owner of the tty, or super-user. */ perm = 0; - if (current->tty == tty || suser()) + if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG)) perm = 1; kbd = kbd_table + console; @@ -479,7 +480,8 @@ if (!(key_map = key_maps[s])) { int j; - if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && !suser()) + if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && + !capable(CAP_SYS_RESOURCE)) return -EPERM; key_map = (ushort *) kmalloc(sizeof(plain_map), @@ -499,7 +501,8 @@ * Only the Superuser can set or unset the Secure * Attention Key. */ - if (((ov == K_SAK) || (v == K_SAK)) && !suser()) + if (((ov == K_SAK) || (v == K_SAK)) && + !capable(CAP_LINUX_ATTENTION)) return -EPERM; key_map[i] = U(v); if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) @@ -1123,12 +1126,12 @@ return con_get_unimap(ct, &(ud->entry_ct), list); } case VT_LOCKSWITCH: - if (!suser()) + if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; vt_dont_switch = 1; return 0; case VT_UNLOCKSWITCH: - if (!suser()) + if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; vt_dont_switch = 0; return 0; diff -urN linux-2.0.30/drivers/net/de4x5.c linux-privs/drivers/net/de4x5.c --- linux-2.0.30/drivers/net/de4x5.c Sat Nov 9 09:31:38 1996 +++ linux-privs/drivers/net/de4x5.c Mon Apr 14 20:29:48 1997 @@ -223,6 +223,7 @@ #include #include +#include #include #include #include @@ -3876,7 +3877,7 @@ if (status) break; status = -EPERM; - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) break; status = 0; memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN); @@ -3894,7 +3895,7 @@ break; case DE4X5_SET_PROM: /* Set Promiscuous Mode */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { omr = inl(DE4X5_OMR); omr |= OMR_PR; outl(omr, DE4X5_OMR); @@ -3904,7 +3905,7 @@ break; case DE4X5_CLR_PROM: /* Clear Promiscuous Mode */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { omr = inl(DE4X5_OMR); omr &= ~OMR_PR; outb(omr, DE4X5_OMR); @@ -3926,7 +3927,7 @@ break; case DE4X5_SET_MCA: /* Set a multicast address */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { /******* FIX ME! ********/ if (ioc->len != HASH_TABLE_LEN) { /* MCA changes */ if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN * ioc->len))) { @@ -3942,7 +3943,7 @@ break; case DE4X5_CLR_MCA: /* Clear all multicast addresses */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { /******* FIX ME! ********/ set_multicast_list(dev); } else { @@ -3951,7 +3952,7 @@ break; case DE4X5_MCA_EN: /* Enable pass all multicast addressing */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { omr = inl(DE4X5_OMR); omr |= OMR_PM; outl(omr, DE4X5_OMR); @@ -3972,7 +3973,7 @@ break; case DE4X5_CLR_STATS: /* Zero out the driver statistics */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { cli(); memset(&lp->pktStats, 0, sizeof(lp->pktStats)); sti(); @@ -3989,7 +3990,7 @@ break; case DE4X5_SET_OMR: /* Set the OMR Register contents */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, 1))) { memcpy_fromfs(tmp.addr, ioc->data, 1); outl(tmp.addr[0], DE4X5_OMR); diff -urN linux-2.0.30/drivers/net/depca.c linux-privs/drivers/net/depca.c --- linux-2.0.30/drivers/net/depca.c Tue Apr 8 08:47:45 1997 +++ linux-privs/drivers/net/depca.c Mon Apr 14 20:29:49 1997 @@ -212,6 +212,7 @@ #include #include +#include #include #include #include @@ -1709,7 +1710,7 @@ break; case DEPCA_SET_HWADDR: /* Set the hardware address */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN))) { memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN); for (i=0; itbusy); /* Stop ring access */ set_bit(0, (void*)&dev->tbusy); while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ @@ -1749,7 +1750,7 @@ break; case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { while(dev->tbusy); /* Stop ring access */ set_bit(0, (void*)&dev->tbusy); while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */ @@ -1778,7 +1779,7 @@ break; case DEPCA_SET_MCA: /* Set a multicast address */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { if (!(status=verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len))) { memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len); set_multicast_list(dev); @@ -1789,7 +1790,7 @@ break; case DEPCA_CLR_MCA: /* Clear all multicast addresses */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { set_multicast_list(dev); } else { status = -EPERM; @@ -1797,7 +1798,7 @@ break; case DEPCA_MCA_EN: /* Enable pass all multicast addressing */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { set_multicast_list(dev); } else { status = -EPERM; @@ -1814,7 +1815,7 @@ break; case DEPCA_CLR_STATS: /* Zero out the driver statistics */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { cli(); memset(&lp->pktStats, 0, sizeof(lp->pktStats)); sti(); diff -urN linux-2.0.30/drivers/net/dlci.c linux-privs/drivers/net/dlci.c --- linux-2.0.30/drivers/net/dlci.c Sun Sep 15 00:34:18 1996 +++ linux-privs/drivers/net/dlci.c Mon Apr 14 20:29:49 1997 @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -324,7 +325,7 @@ struct dlci_local *dlp; int err, len; - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return(-EPERM); dlp = dev->priv; @@ -549,7 +550,7 @@ int err; struct dlci_add add; - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return(-EPERM); err=verify_area(VERIFY_READ, arg, sizeof(struct dlci_add)); diff -urN linux-2.0.30/drivers/net/eql.c linux-privs/drivers/net/eql.c --- linux-2.0.30/drivers/net/eql.c Sun Sep 22 11:17:08 1996 +++ linux-privs/drivers/net/eql.c Mon Apr 14 20:29:49 1997 @@ -116,6 +116,7 @@ #include #include +#include #include #include #include @@ -344,7 +345,8 @@ static int eql_ioctl(struct device *dev, struct ifreq *ifr, int cmd) { - if(!suser() && cmd!=EQL_GETMASTRCFG && cmd!=EQL_GETSLAVECFG) + if(!capable(CAP_NET_IFCONFIG) && + cmd!=EQL_GETMASTRCFG && cmd!=EQL_GETSLAVECFG) return -EPERM; switch (cmd) { diff -urN linux-2.0.30/drivers/net/ewrk3.c linux-privs/drivers/net/ewrk3.c --- linux-2.0.30/drivers/net/ewrk3.c Tue Apr 8 08:47:46 1997 +++ linux-privs/drivers/net/ewrk3.c Mon Apr 14 20:29:49 1997 @@ -142,6 +142,7 @@ #include #include +#include #include #include #include @@ -1679,7 +1680,7 @@ break; case EWRK3_SET_HWADDR: /* Set the hardware address */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN))) { csr = inb(EWRK3_CSR); csr |= (CSR_TXD|CSR_RXD); @@ -1700,7 +1701,7 @@ break; case EWRK3_SET_PROM: /* Set Promiscuous Mode */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { csr = inb(EWRK3_CSR); csr |= CSR_PME; csr &= ~CSR_MCE; @@ -1711,7 +1712,7 @@ break; case EWRK3_CLR_PROM: /* Clear Promiscuous Mode */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { csr = inb(EWRK3_CSR); csr &= ~CSR_PME; outb(csr, EWRK3_CSR); @@ -1744,7 +1745,7 @@ break; case EWRK3_SET_MCA: /* Set a multicast address */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { if (!(status=verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len))) { memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len); set_multicast_list(dev); @@ -1755,7 +1756,7 @@ break; case EWRK3_CLR_MCA: /* Clear all multicast addresses */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { set_multicast_list(dev); } else { status = -EPERM; @@ -1763,7 +1764,7 @@ break; case EWRK3_MCA_EN: /* Enable multicast addressing */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { csr = inb(EWRK3_CSR); csr |= CSR_MCE; csr &= ~CSR_PME; @@ -1783,7 +1784,7 @@ break; case EWRK3_CLR_STATS: /* Zero out the driver statistics */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { cli(); memset(&lp->pktStats, 0, sizeof(lp->pktStats)); sti(); @@ -1801,7 +1802,7 @@ break; case EWRK3_SET_CSR: /* Set the CSR Register contents */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { if (!(status=verify_area(VERIFY_READ, ioc->data, 1))) { memcpy_fromfs(tmp.addr, ioc->data, 1); outb(tmp.addr[0], EWRK3_CSR); @@ -1812,7 +1813,7 @@ break; case EWRK3_GET_EEPROM: /* Get the EEPROM contents */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { for (i=0; i<(EEPROM_MAX>>1); i++) { tmp.val[i] = (short)Read_EEPROM(iobase, i); } @@ -1831,7 +1832,7 @@ break; case EWRK3_SET_EEPROM: /* Set the EEPROM contents */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { if (!(status=verify_area(VERIFY_READ, ioc->data, EEPROM_MAX))) { memcpy_fromfs(tmp.addr, ioc->data, EEPROM_MAX); for (i=0; i<(EEPROM_MAX>>1); i++) { @@ -1852,7 +1853,7 @@ break; case EWRK3_SET_TX_CUT_THRU: /* Set TX cut through mode */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { lp->txc = 1; } else { status = -EPERM; @@ -1860,7 +1861,7 @@ break; case EWRK3_CLR_TX_CUT_THRU: /* Clear TX cut through mode */ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { lp->txc = 0; } else { status = -EPERM; diff -urN linux-2.0.30/drivers/net/pi2.c linux-privs/drivers/net/pi2.c --- linux-2.0.30/drivers/net/pi2.c Thu Feb 29 21:50:45 1996 +++ linux-privs/drivers/net/pi2.c Mon Apr 14 20:29:49 1997 @@ -96,6 +96,7 @@ #include #include +#include #include #include #include @@ -1610,7 +1611,7 @@ switch (rq.cmd) { case SIOCSPIPARAM: - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; save_flags(flags); cli(); @@ -1627,7 +1628,7 @@ case SIOCSPIDMA: - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; ret = 0; if (dev->base_addr & 2) { /* if A channel */ diff -urN linux-2.0.30/drivers/net/ppp.c linux-privs/drivers/net/ppp.c --- linux-2.0.30/drivers/net/ppp.c Tue Oct 8 11:21:03 1996 +++ linux-privs/drivers/net/ppp.c Mon Apr 14 20:29:49 1997 @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -2240,7 +2241,7 @@ /* * The user must have an euid of root to do these requests. */ - if (!suser ()) + if (!capable (CAP_NET_IFCONFIG)) return -EPERM; /* * Set the MRU value diff -urN linux-2.0.30/drivers/net/pt.c linux-privs/drivers/net/pt.c --- linux-2.0.30/drivers/net/pt.c Thu Apr 11 23:49:38 1996 +++ linux-privs/drivers/net/pt.c Mon Apr 14 20:29:49 1997 @@ -66,6 +66,7 @@ #include #include +#include #include #include #include @@ -1044,7 +1045,7 @@ switch (rq.cmd) { case SIOCSPIPARAM: - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; save_flags(flags); cli(); @@ -1061,7 +1062,7 @@ case SIOCSPIDMA: - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; ret = 0; if (dev->base_addr & CHANA) { /* if A channel */ diff -urN linux-2.0.30/drivers/net/wavelan.c linux-privs/drivers/net/wavelan.c --- linux-2.0.30/drivers/net/wavelan.c Thu Mar 6 10:03:51 1997 +++ linux-privs/drivers/net/wavelan.c Mon Apr 14 20:29:49 1997 @@ -1935,7 +1935,7 @@ case SIOCSIWSENS: /* Set the level threshold */ - if(!suser()) + if(!capable(CAP_NET_IFCONFIG)) return -EPERM; psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, @@ -2119,7 +2119,7 @@ /* ------------------ PRIVATE IOCTL ------------------ */ case SIOCSIPQTHR: - if(!suser()) + if(!capable(CAP_NET_IFCONFIG)) return -EPERM; psa.psa_quality_thr = *(wrq->u.name) & 0x0F; psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa, @@ -2136,7 +2136,7 @@ #ifdef HISTOGRAM case SIOCSIPHISTO: /* Verif if the user is root */ - if(!suser()) + if(!capable(CAP_NET_IFCONFIG)) return -EPERM; /* Check the number of intervals */ diff -urN linux-2.0.30/drivers/sbus/char/sunserial.c linux-privs/drivers/sbus/char/sunserial.c --- linux-2.0.30/drivers/sbus/char/sunserial.c Mon May 6 02:26:09 1996 +++ linux-privs/drivers/sbus/char/sunserial.c Mon Apr 14 20:29:49 1997 @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -1261,7 +1262,7 @@ memcpy_fromfs(&new_serial,new_info,sizeof(new_serial)); old_info = *info; - if (!suser()) { + if (!capable(CAP_SYS_TTY_CONFIG)) { if ((new_serial.baud_base != info->baud_base) || (new_serial.type != info->type) || (new_serial.close_delay != info->close_delay) || diff -urN linux-2.0.30/drivers/scsi/scsi_ioctl.c linux-privs/drivers/scsi/scsi_ioctl.c --- linux-2.0.30/drivers/scsi/scsi_ioctl.c Fri Feb 28 15:14:18 1997 +++ linux-privs/drivers/scsi/scsi_ioctl.c Mon Apr 14 20:29:49 1997 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -344,13 +345,13 @@ put_user( dev->host->unique_id, (unsigned long *) arg+1); return 0; case SCSI_IOCTL_TAGGED_ENABLE: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_DEVICES)) return -EACCES; if(!dev->tagged_supported) return -EINVAL; dev->tagged_queue = 1; dev->current_tag = 1; return 0; case SCSI_IOCTL_TAGGED_DISABLE: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_DEVICES)) return -EACCES; if(!dev->tagged_supported) return -EINVAL; dev->tagged_queue = 0; dev->current_tag = 0; @@ -358,7 +359,7 @@ case SCSI_IOCTL_PROBE_HOST: return ioctl_probe(dev->host, arg); case SCSI_IOCTL_SEND_COMMAND: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_DEVICES)) return -EACCES; return ioctl_command((Scsi_Device *) dev, arg); case SCSI_IOCTL_DOORLOCK: if (!dev->removable || !dev->lockable) return 0; diff -urN linux-2.0.30/drivers/scsi/sd_ioctl.c linux-privs/drivers/scsi/sd_ioctl.c --- linux-2.0.30/drivers/scsi/sd_ioctl.c Wed May 1 21:48:54 1996 +++ linux-privs/drivers/scsi/sd_ioctl.c Mon Apr 14 20:29:49 1997 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -66,7 +67,7 @@ return 0; case BLKRASET: - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; if(arg > 0xff) return -EINVAL; @@ -83,7 +84,7 @@ return 0; case BLKFLSBUF: - if(!suser()) return -EACCES; + if(!capable(CAP_SYS_DEVICES)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; fsync_dev(inode->i_rdev); invalidate_buffers(inode->i_rdev); diff -urN linux-2.0.30/drivers/scsi/sr.c linux-privs/drivers/scsi/sr.c --- linux-2.0.30/drivers/scsi/sr.c Tue Apr 8 08:47:46 1997 +++ linux-privs/drivers/scsi/sr.c Mon Apr 14 20:29:49 1997 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -402,7 +403,7 @@ return; } - if (!suser()) { + if (!capable(CAP_SYS_DEVICES)) { /* I'm not the superuser, so SCSI_IOCTL_SEND_COMMAND isn't allowed * for me. That's why mpcd_sector will be initialized with zero, * because I'm not able to get the right value. Necessary only if diff -urN linux-2.0.30/drivers/scsi/sr_ioctl.c linux-privs/drivers/scsi/sr_ioctl.c --- linux-2.0.30/drivers/scsi/sr_ioctl.c Sat May 18 12:19:19 1996 +++ linux-privs/drivers/scsi/sr_ioctl.c Mon Apr 14 20:29:50 1997 @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -564,7 +565,7 @@ return 0; case BLKRASET: - if(!suser()) + if(!capable(CAP_SYS_DEVICES)) return -EACCES; if(!(inode->i_rdev)) return -EINVAL; diff -urN linux-2.0.30/drivers/scsi/st.c linux-privs/drivers/scsi/st.c --- linux-2.0.30/drivers/scsi/st.c Fri Feb 28 15:14:18 1997 +++ linux-privs/drivers/scsi/st.c Mon Apr 14 20:29:50 1997 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -2531,7 +2532,7 @@ memcpy_fromfs((char *) &mtc, (char *)arg, sizeof(struct mtop)); - if (mtc.mt_op == MTSETDRVBUFFER && !suser()) { + if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_DEVICES)) { printk(KERN_WARNING "st%d: MTSETDRVBUFFER only allowed for root.\n", dev); return (-EPERM); } diff -urN linux-2.0.30/drivers/sound/Config.in linux-privs/drivers/sound/Config.in --- linux-2.0.30/drivers/sound/Config.in Wed Jul 10 04:34:03 1996 +++ linux-privs/drivers/sound/Config.in Wed Apr 16 19:06:34 1997 @@ -1,15 +1,251 @@ -# -# Sound driver configuration -# -#-------- -# There is another confic script which is compatible with rest of -# the kernel. It can be activated by running 'make mkscript' in this -# directory. Please note that this is an _experimental_ feature which -# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui). -#-------- -# -$MAKE -C drivers/sound config || exit 1 +bool 'ProAudioSpectrum 16 support' CONFIG_PAS +bool 'Sound Blaster (SB, SBPro, SB16, clones) support' CONFIG_SB +bool 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB +bool 'Gravis Ultrasound support' CONFIG_GUS +bool 'MPU-401 support (NOT for SB16)' CONFIG_MPU401 +bool '6850 UART Midi support' CONFIG_UART6850 +bool 'PSS (ECHO-ADI2111) support' CONFIG_PSS +bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 +bool 'GUS MAX support' CONFIG_GUSMAX +bool 'Microsoft Sound System support' CONFIG_MSS +bool 'Ensoniq SoundScape support' CONFIG_SSCAPE +bool 'MediaTrix AudioTrix Pro support' CONFIG_TRIX +bool 'Support for MAD16 and/or Mozart based cards' CONFIG_MAD16 +bool 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232 +bool 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI +bool '/dev/dsp and /dev/audio support' CONFIG_AUDIO +bool 'MIDI interface support' CONFIG_MIDI +bool 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 + +if [ "$CONFIG_SB" = "y" ]; then +hex 'I/O base for SB Check from manual of the card' SBC_BASE 220 +fi + +if [ "$CONFIG_SB" = "y" ]; then +int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7 +fi + +if [ "$CONFIG_SB" = "y" ]; then +int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1 +fi + +if [ "$CONFIG_SB" = "y" ]; then +int 'Sound Blaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5 +fi + +if [ "$CONFIG_SB" = "y" ]; then +hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 0 +fi + +if [ "$CONFIG_SB" = "y" ]; then +int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Use -1 with SB16' SB_MPU_IRQ -1 +fi + +if [ "$CONFIG_PAS" = "y" ]; then +int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10 +fi + +if [ "$CONFIG_PAS" = "y" ]; then +int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3 +fi + +if [ "$CONFIG_GUS" = "y" ]; then +hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220 +fi + +if [ "$CONFIG_GUS" = "y" ]; then +int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15 +fi + +if [ "$CONFIG_GUS" = "y" ]; then +int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6 +fi + +if [ "$CONFIG_GUS" = "y" ]; then +int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1 +fi + +if [ "$CONFIG_GUS16" = "y" ]; then +hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530 +fi + +if [ "$CONFIG_GUS16" = "y" ]; then +int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7 +fi + +if [ "$CONFIG_GUS16" = "y" ]; then +int 'GUS DMA 0, 1 or 3' GUS16_DMA 3 +fi + +if [ "$CONFIG_MPU401" = "y" ]; then +hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330 +fi + +if [ "$CONFIG_MPU401" = "y" ]; then +int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9 +fi + +if [ "$CONFIG_MAUI" = "y" ]; then +hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330 +fi + +if [ "$CONFIG_MAUI" = "y" ]; then +int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9 +fi + +if [ "$CONFIG_UART6850" = "y" ]; then +hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0 +fi + +if [ "$CONFIG_UART6850" = "y" ]; then +int 'UART6850 IRQ (Unknown)' U6850_IRQ -1 +fi + +if [ "$CONFIG_PSS" = "y" ]; then +hex 'PSS I/O base 220 or 240' PSS_BASE 220 +fi + +if [ "$CONFIG_PSS" = "y" ]; then +hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530 +fi + +if [ "$CONFIG_PSS" = "y" ]; then +int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11 +fi + +if [ "$CONFIG_PSS" = "y" ]; then +int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3 +fi + +if [ "$CONFIG_PSS" = "y" ]; then +hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330 +fi + +if [ "$CONFIG_PSS" = "y" ]; then +int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9 +fi +if [ "$CONFIG_MSS" = "y" ]; then +hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530 +fi + +if [ "$CONFIG_MSS" = "y" ]; then +int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11 +fi + +if [ "$CONFIG_MSS" = "y" ]; then +int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3 +fi + +if [ "$CONFIG_SSCAPE" = "y" ]; then +hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330 +fi + +if [ "$CONFIG_SSCAPE" = "y" ]; then +int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9 +fi + +if [ "$CONFIG_SSCAPE" = "y" ]; then +int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3 +fi + +if [ "$CONFIG_SSCAPE" = "y" ]; then +hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534 +fi + +if [ "$CONFIG_SSCAPE" = "y" ]; then +int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +hex 'AudioTrix audio I/O base 530, 604, E80 or F40' TRIX_BASE 530 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix audio DMA 0, 1 or 3' TRIX_DMA 0 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +hex 'AudioTrix MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +hex 'AudioTrix SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix SB DMA 1 or 3' TRIX_SB_DMA 1 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9 +fi + +if [ "$CONFIG_AUDIO" = "y" ]; then +int 'Audio DMA buffer size 4096, 16384, 32768 or 65536' DSP_BUFFSIZE 65536 +fi +# +$MAKE -C drivers/sound kernelconfig || exit 1 bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then diff -urN linux-2.0.30/fs/Makefile linux-privs/fs/Makefile --- linux-2.0.30/fs/Makefile Wed May 8 08:28:01 1996 +++ linux-privs/fs/Makefile Mon Apr 14 20:29:50 1997 @@ -13,7 +13,7 @@ O_OBJS = open.o read_write.o inode.o devices.o file_table.o buffer.o \ super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \ - dcache.o $(BINFMTS) + dcache.o file_cap.o $(BINFMTS) MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = minix ext ext2 fat msdos vfat proc isofs nfs xiafs umsdos \ diff -urN linux-2.0.30/fs/affs/namei.c linux-privs/fs/affs/namei.c --- linux-2.0.30/fs/affs/namei.c Sat Nov 30 02:21:19 1996 +++ linux-privs/fs/affs/namei.c Mon Apr 14 20:29:50 1997 @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -328,8 +329,8 @@ goto rmdir_done; } retval = -EPERM; - if (!fsuser() && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + if (current->fsuid != inode->i_uid && + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto rmdir_done; if (inode->i_dev != dir->i_dev) goto rmdir_done; diff -urN linux-2.0.30/fs/binfmt_aout.c linux-privs/fs/binfmt_aout.c --- linux-2.0.30/fs/binfmt_aout.c Sat Aug 17 11:19:28 1996 +++ linux-privs/fs/binfmt_aout.c Mon Apr 14 20:29:50 1997 @@ -310,8 +310,7 @@ current->mm->rss = 0; current->mm->mmap = NULL; - current->suid = current->euid = current->fsuid = bprm->e_uid; - current->sgid = current->egid = current->fsgid = bprm->e_gid; + compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; if (N_MAGIC(ex) == OMAGIC) { #ifdef __alpha__ diff -urN linux-2.0.30/fs/binfmt_elf.c linux-privs/fs/binfmt_elf.c --- linux-2.0.30/fs/binfmt_elf.c Thu Jan 2 10:29:30 1997 +++ linux-privs/fs/binfmt_elf.c Mon Apr 14 20:29:50 1997 @@ -11,6 +11,7 @@ #include +#include #include #include #include @@ -657,8 +658,7 @@ #ifdef LOW_ELF_STACK current->start_stack = bprm->p = elf_stack - 4; #endif - current->suid = current->euid = current->fsuid = bprm->e_uid; - current->sgid = current->egid = current->fsgid = bprm->e_gid; + compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; bprm->p = (unsigned long) create_elf_tables((char *)bprm->p, diff -urN linux-2.0.30/fs/buffer.c linux-privs/fs/buffer.c --- linux-2.0.30/fs/buffer.c Tue Apr 8 08:47:46 1997 +++ linux-privs/fs/buffer.c Mon Apr 14 20:29:50 1997 @@ -17,6 +17,7 @@ the buffer cache isn't our primary cache - Andrew Tridgell 12/96 */ #include +#include #include #include #include @@ -1545,7 +1546,7 @@ asmlinkage int sys_bdflush(int func, long data) { - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (func == 1) diff -urN linux-2.0.30/fs/dquot.c linux-privs/fs/dquot.c --- linux-2.0.30/fs/dquot.c Sun May 12 21:36:19 1996 +++ linux-privs/fs/dquot.c Mon Apr 14 20:29:50 1997 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -376,7 +377,8 @@ if (inodes <= 0 || dquot->dq_flags & DQ_FAKE) return(QUOTA_OK); if (dquot->dq_ihardlimit && - (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && !fsuser()) { + (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && + !capable(CAP_SYS_RESOURCE)) { if ((dquot->dq_flags & DQ_INODES) == 0 && need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: write failed, %s file limit reached\r\n", @@ -388,7 +390,8 @@ } if (dquot->dq_isoftlimit && (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && - dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && !fsuser()) { + dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && + !capable(CAP_SYS_RESOURCE)) { if (need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: warning, %s file quota exceeded too long.\r\n", dquot->dq_mnt->mnt_dirname, quotatypes[type]); @@ -398,7 +401,7 @@ } if (dquot->dq_isoftlimit && (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && - dquot->dq_itime == 0 && !fsuser()) { + dquot->dq_itime == 0 && !capable(CAP_SYS_RESOURCE)) { if (need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: warning, %s file quota exceeded\r\n", dquot->dq_mnt->mnt_dirname, quotatypes[type]); @@ -414,7 +417,8 @@ if (blocks <= 0 || dquot->dq_flags & DQ_FAKE) return(QUOTA_OK); if (dquot->dq_bhardlimit && - (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && !fsuser()) { + (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && + !capable(CAP_SYS_RESOURCE)) { if ((dquot->dq_flags & DQ_BLKS) == 0 && need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: write failed, %s disk limit reached.\r\n", @@ -426,7 +430,8 @@ } if (dquot->dq_bsoftlimit && (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && - dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && !fsuser()) { + dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && + !capable(CAP_SYS_RESOURCE)) { if (need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: write failed, %s disk quota exceeded too long.\r\n", dquot->dq_mnt->mnt_dirname, quotatypes[type]); @@ -436,7 +441,7 @@ } if (dquot->dq_bsoftlimit && (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit && - dquot->dq_btime == 0 && !fsuser()) { + dquot->dq_btime == 0 && !capable(CAP_SYS_RESOURCE)) { if (need_print_warning(type, dquot)) { sprintf(quotamessage, "%s: warning, %s disk quota exceeded\r\n", dquot->dq_mnt->mnt_dirname, quotatypes[type]); @@ -1026,11 +1031,12 @@ break; case Q_GETQUOTA: if (((type == USRQUOTA && current->uid != id) || - (type == GRPQUOTA && current->gid != id)) && !fsuser()) + (type == GRPQUOTA && current->gid != id)) && + !capable(CAP_SYS_QUOTA)) return(-EPERM); break; default: - if (!fsuser()) + if (!capable(CAP_SYS_QUOTA)) return(-EPERM); } diff -urN linux-2.0.30/fs/exec.c linux-privs/fs/exec.c --- linux-2.0.30/fs/exec.c Sat Nov 30 02:21:18 1996 +++ linux-privs/fs/exec.c Mon Apr 14 20:29:50 1997 @@ -22,8 +22,10 @@ * formats. */ +#include #include #include +#include #include #include #include @@ -437,8 +439,6 @@ int ch; char * name; - if (current->euid == current->uid && current->egid == current->gid) - current->dumpable = 1; name = bprm->filename; for (i=0; (ch = *(name++)) != '\0';) { if (ch == '/') @@ -454,12 +454,10 @@ flush_thread(); - if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || - permission(bprm->inode,MAY_READ)) - current->dumpable = 0; - flush_old_signals(current->sig); flush_old_files(current->files); + + current->dumpable = !permission(bprm->inode,MAY_READ); } /* @@ -509,6 +507,17 @@ id_change = 1; } +#ifdef CONFIG_POSIX6_CAP + read_inode_caps(bprm->inode, + &bprm->cap_inheritable, + &bprm->cap_permitted, + &bprm->cap_effective); + if( !cap_isclear(bprm->cap_permitted) + && !cap_isclear(bprm->cap_effective) ) { + id_change = 1; + } +#endif + if (id_change) { /* We can't suid-execute if we're sharing parts of the executable */ /* or if we're being traced (or if suid execs are not allowed) */ @@ -518,8 +527,7 @@ || (current->fs->count > 1) || (current->sig->count > 1) || (current->files->count > 1)) { - if (!suser()) - return -EPERM; + return -EPERM; } } diff -urN linux-2.0.30/fs/ext/namei.c linux-privs/fs/ext/namei.c --- linux-2.0.30/fs/ext/namei.c Sat Nov 30 02:21:19 1996 +++ linux-privs/fs/ext/namei.c Mon Apr 14 20:29:50 1997 @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -544,9 +545,9 @@ retval = -EPERM; if (!(inode = iget(dir->i_sb, de->inode))) goto end_rmdir; - if ((dir->i_mode & S_ISVTX) && !fsuser() && + if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_rmdir; if (inode->i_dev != dir->i_dev) goto end_rmdir; @@ -598,11 +599,11 @@ if (!(inode = iget(dir->i_sb, de->inode))) goto end_unlink; retval = -EPERM; - if ((dir->i_mode & S_ISVTX) && !fsuser() && + if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_unlink; - if (S_ISDIR(inode->i_mode)) + if (S_ISDIR(inode->i_mode) && !capable(CAP_LINK_DIR)) goto end_unlink; if (!inode->i_nlink) { printk("Deleting nonexistent file (%s:%ld), %d\n", @@ -687,7 +688,7 @@ struct ext_dir_entry * de; struct buffer_head * bh; - if (S_ISDIR(oldinode->i_mode)) { + if (S_ISDIR(oldinode->i_mode) && !capable(CAP_LINK_DIR)) { iput(oldinode); iput(dir); return -EPERM; @@ -793,7 +794,7 @@ retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && - current->fsuid != old_dir->i_uid && !fsuser()) + current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL); if (new_bh) { @@ -814,7 +815,7 @@ retval = -EPERM; if (new_inode && (new_dir->i_mode & S_ISVTX) && current->fsuid != new_inode->i_uid && - current->fsuid != new_dir->i_uid && !fsuser()) + current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; if (S_ISDIR(old_inode->i_mode)) { retval = -EEXIST; diff -urN linux-2.0.30/fs/ext2/CHANGES linux-privs/fs/ext2/CHANGES --- linux-2.0.30/fs/ext2/CHANGES Tue Jan 16 21:31:58 1996 +++ linux-privs/fs/ext2/CHANGES Mon Apr 14 20:29:50 1997 @@ -1,3 +1,11 @@ +Changes for Linux-privs +======================= + - securelevel is now a bitfield. + - Superuser checking now uses capable() instead of suser(). + - Added res_fork.c file. This provides a means for general + resources to be associated with any ext2 inode. + - Added a ro_compat flag for resource forks. + Changes from version 0.5a to version 0.5b ========================================= - Now that we have sysctl(), the immutable flag cannot be changed when diff -urN linux-2.0.30/fs/ext2/Makefile linux-privs/fs/ext2/Makefile --- linux-2.0.30/fs/ext2/Makefile Tue Aug 15 05:07:02 1995 +++ linux-privs/fs/ext2/Makefile Mon Apr 14 20:29:50 1997 @@ -9,7 +9,7 @@ O_TARGET := ext2.o O_OBJS := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o truncate.o + ioctl.o namei.o super.o symlink.o truncate.o res_fork.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff -urN linux-2.0.30/fs/ext2/acl.c linux-privs/fs/ext2/acl.c --- linux-2.0.30/fs/ext2/acl.c Tue Jul 2 09:08:42 1996 +++ linux-privs/fs/ext2/acl.c Mon Apr 14 20:29:50 1997 @@ -16,6 +16,7 @@ #include #include #include +#include #include /* @@ -25,34 +26,39 @@ */ int ext2_permission (struct inode * inode, int mask) { - unsigned short mode = inode->i_mode; + int mode = inode->i_mode; + int dmask, rmask; - /* - * Nobody gets write access to a file on a readonly-fs - */ - if ((mask & S_IWOTH) && - (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) && - IS_RDONLY(inode)) + /* Nobody gets write access to a read-only fs */ + if ((mask & S_IWOTH) && IS_RDONLY(inode) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) return -EROFS; - /* - * Nobody gets write access to an immutable file - */ + + /* Nobody gets write access to an immutable file */ if ((mask & S_IWOTH) && IS_IMMUTABLE(inode)) return -EACCES; - /* - * Special case, access is always granted for root - */ - if (fsuser()) + + /* Get DAC permissions */ + if (current->fsuid == inode->i_uid) + dmask = (mode >> 6) & 7; + else if (in_group_p(inode->i_gid)) + dmask = (mode >> 3) & 7; + else + dmask = mode & 7; + + /* Set mask to the set of permission bits that we want * + * but don't get through DAC. */ + mask &= ~dmask; + + /* We have access if DAC allows it, or if we completely override DAC. */ + if(!mask || capable(CAP_DAC_OVERRIDE)) return 0; - /* - * If no ACL, checks using the file mode - */ - else if (current->fsuid == inode->i_uid) - mode >>= 6; - else if (in_group_p (inode->i_gid)) - mode >>= 3; - if (((mode & mask & S_IRWXO) == mask)) + + /* CAP_DAC_READ_SEARCH allows read and search access. rmask is * + * the set of permission bits that it affects. */ + rmask = S_IROTH | (S_ISDIR(inode->i_mode) ? S_IXOTH : 0); + if(!(mask & ~rmask) && capable(CAP_DAC_READ_SEARCH)) return 0; - else - return -EACCES; + + return -EACCES; } diff -urN linux-2.0.30/fs/ext2/balloc.c linux-privs/fs/ext2/balloc.c --- linux-2.0.30/fs/ext2/balloc.c Thu Jan 4 04:14:20 1996 +++ linux-privs/fs/ext2/balloc.c Mon Apr 14 20:29:50 1997 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -264,11 +265,11 @@ struct super_block * sb; struct ext2_group_desc * gdp; struct ext2_super_block * es; - - *err = -ENOSPC; #ifdef EXT2FS_DEBUG static int goal_hits = 0, goal_attempts = 0; #endif + + *err = -ENOSPC; sb = inode->i_sb; if (!sb) { printk ("ext2_new_block: nonexistent device"); @@ -277,9 +278,10 @@ lock_super (sb); es = sb->u.ext2_sb.s_es; if (es->s_free_blocks_count <= es->s_r_blocks_count && - (!fsuser() && (sb->u.ext2_sb.s_resuid != current->fsuid) && - (sb->u.ext2_sb.s_resgid == 0 || - !in_group_p (sb->u.ext2_sb.s_resgid)))) { + !capable(CAP_SYS_RESOURCE) && + (sb->u.ext2_sb.s_resuid != current->fsuid) && + (sb->u.ext2_sb.s_resgid == 0 || + !in_group_p (sb->u.ext2_sb.s_resgid))) { unlock_super (sb); return 0; } diff -urN linux-2.0.30/fs/ext2/file.c linux-privs/fs/ext2/file.c --- linux-2.0.30/fs/ext2/file.c Tue Feb 20 00:28:13 1996 +++ linux-privs/fs/ext2/file.c Mon Apr 14 20:29:50 1997 @@ -77,7 +77,9 @@ ext2_bmap, /* bmap */ ext2_truncate, /* truncate */ ext2_permission, /* permission */ - NULL /* smap */ + NULL, /* smap */ + ext2_get_resource, /* get_resource */ + ext2_put_resource, /* put_resource */ }; static int ext2_file_write (struct inode * inode, struct file * filp, diff -urN linux-2.0.30/fs/ext2/ialloc.c linux-privs/fs/ext2/ialloc.c --- linux-2.0.30/fs/ext2/ialloc.c Sat Nov 30 02:21:20 1996 +++ linux-privs/fs/ext2/ialloc.c Mon Apr 14 20:29:50 1997 @@ -419,6 +419,7 @@ inode->u.ext2_i.i_faddr = 0; inode->u.ext2_i.i_frag_no = 0; inode->u.ext2_i.i_frag_size = 0; + inode->u.ext2_i.i_resource_fork = 0; inode->u.ext2_i.i_file_acl = 0; inode->u.ext2_i.i_dir_acl = 0; inode->u.ext2_i.i_dtime = 0; diff -urN linux-2.0.30/fs/ext2/inode.c linux-privs/fs/ext2/inode.c --- linux-2.0.30/fs/ext2/inode.c Tue Mar 11 13:46:41 1997 +++ linux-privs/fs/ext2/inode.c Mon Apr 14 20:29:50 1997 @@ -35,6 +35,7 @@ if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO || inode->i_ino == EXT2_ACL_DATA_INO) return; + ext2_unlink_resource_fork(inode); inode->u.ext2_i.i_dtime = CURRENT_TIME; inode->i_dirt = 1; ext2_update_inode(inode, IS_SYNC(inode)); @@ -468,6 +469,7 @@ inode->u.ext2_i.i_frag_no = raw_inode->i_frag; inode->u.ext2_i.i_frag_size = raw_inode->i_fsize; inode->u.ext2_i.i_osync = 0; + inode->u.ext2_i.i_resource_fork = raw_inode->osd1.linux1.l_i_res_fork; inode->u.ext2_i.i_file_acl = raw_inode->i_file_acl; inode->u.ext2_i.i_dir_acl = raw_inode->i_dir_acl; inode->u.ext2_i.i_version = raw_inode->i_version; @@ -564,6 +566,7 @@ raw_inode->i_faddr = inode->u.ext2_i.i_faddr; raw_inode->i_frag = inode->u.ext2_i.i_frag_no; raw_inode->i_fsize = inode->u.ext2_i.i_frag_size; + raw_inode->osd1.linux1.l_i_res_fork = inode->u.ext2_i.i_resource_fork; raw_inode->i_file_acl = inode->u.ext2_i.i_file_acl; raw_inode->i_dir_acl = inode->u.ext2_i.i_dir_acl; raw_inode->i_version = inode->u.ext2_i.i_version; diff -urN linux-2.0.30/fs/ext2/ioctl.c linux-privs/fs/ext2/ioctl.c --- linux-2.0.30/fs/ext2/ioctl.c Tue Jul 2 09:08:42 1996 +++ linux-privs/fs/ext2/ioctl.c Mon Apr 14 20:29:50 1997 @@ -14,6 +14,7 @@ #include #include #include +#include #include int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, @@ -38,17 +39,15 @@ flags = get_user((int *) arg); /* * The IMMUTABLE and APPEND_ONLY flags can only be changed by - * the super user when the security level is zero. + * the super user when the SECURE_IMMUTABLE flag is off. */ - if ((flags & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) ^ - (inode->u.ext2_i.i_flags & - (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) { - /* This test looks nicer. Thanks to Pauline Middelink */ - if (!fsuser() || securelevel > 0) - return -EPERM; - } else - if ((current->fsuid != inode->i_uid) && !fsuser()) - return -EPERM; + if (((flags ^ inode->u.ext2_i.i_flags) & + (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) && + (issecure(SECURE_IMMUTABLE) || + !capable(CAP_LINUX_IMMUTABLE))) + return -EPERM; + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + return -EPERM; if (IS_RDONLY(inode)) return -EROFS; inode->u.ext2_i.i_flags = flags; @@ -70,7 +69,7 @@ put_user(inode->u.ext2_i.i_version, (int *) arg); return 0; case EXT2_IOC_SETVERSION: - if ((current->fsuid != inode->i_uid) && !fsuser()) + if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; if (IS_RDONLY(inode)) return -EROFS; diff -urN linux-2.0.30/fs/ext2/namei.c linux-privs/fs/ext2/namei.c --- linux-2.0.30/fs/ext2/namei.c Sat Nov 30 02:21:20 1996 +++ linux-privs/fs/ext2/namei.c Mon Apr 14 20:29:50 1997 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -641,9 +642,9 @@ schedule(); goto repeat; } - if ((dir->i_mode & S_ISVTX) && !fsuser() && + if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_rmdir; if (inode == dir) /* we may not delete ".", but "../dir" is ok */ goto end_rmdir; @@ -719,7 +720,7 @@ if (inode->i_sb->dq_op) inode->i_sb->dq_op->initialize (inode, -1); retval = -EPERM; - if (S_ISDIR(inode->i_mode)) + if (S_ISDIR(inode->i_mode) && !capable(CAP_LINK_DIR)) goto end_unlink; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) goto end_unlink; @@ -730,9 +731,9 @@ schedule(); goto repeat; } - if ((dir->i_mode & S_ISVTX) && !fsuser() && + if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_unlink; if (!inode->i_nlink) { ext2_warning (inode->i_sb, "ext2_unlink", @@ -850,7 +851,7 @@ struct buffer_head * bh; int err; - if (S_ISDIR(oldinode->i_mode)) { + if (S_ISDIR(oldinode->i_mode) && !capable(CAP_LINK_DIR)) { iput (oldinode); iput (dir); return -EPERM; @@ -981,7 +982,8 @@ retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && - current->fsuid != old_dir->i_uid && !fsuser()) + current->fsuid != old_dir->i_uid && + !capable(CAP_FOWNER)) goto end_rename; if (IS_APPEND(old_inode) || IS_IMMUTABLE(old_inode)) goto end_rename; @@ -1017,7 +1019,8 @@ retval = -EPERM; if (new_inode && (new_dir->i_mode & S_ISVTX) && current->fsuid != new_inode->i_uid && - current->fsuid != new_dir->i_uid && !fsuser()) + current->fsuid != new_dir->i_uid && + !capable(CAP_FOWNER)) goto end_rename; if (S_ISDIR(old_inode->i_mode)) { retval = -ENOTDIR; diff -urN linux-2.0.30/fs/ext2/res_fork.c linux-privs/fs/ext2/res_fork.c --- linux-2.0.30/fs/ext2/res_fork.c Wed Dec 31 16:00:00 1969 +++ linux-privs/fs/ext2/res_fork.c Mon Apr 14 20:29:51 1997 @@ -0,0 +1,592 @@ +/* + * Copyright (c) Andrew G. Morgan 1997 + * + * This file implements the reading and writing of an inode resource + * fork. + * + * It is intended to be used for POSIX.1e capabilities (formerly POSIX + * 6 privileges) and such. This implementation is based on notes + * prepared by Ted Ts'o. + */ + +/* + * These functions are NOT intended to be available outside the + * Kernel's filesystem layer and are certainly NOT to be available + * directly from user space. The functions implicitly assume that the + * current task it permitted to perform the actions they provide, ie., + * it is assumed that the parent functions will provide any necessary + * checks. + */ + +/* Define to add debugging code */ +#undef DEBUG + +#ifdef DEBUG +# define res_debug(f, a...) ({ \ + printk (KERN_DEBUG "ResFork DEBUG (%s, %d): %s: ", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (f, ## a); \ + }) +#else +# define res_debug(f, a...) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if 1 /* XXX -- temporary code for 2.0 (delete when porting to 2.1) */ +/* XXX -- in 2.0 the filesystem is native-endian */ +# define le16_to_cpu(x) (x) +# define le32_to_cpu(x) (x) +# define cpu_to_le16(x) (x) +# define cpu_to_le32(x) (x) +#endif + +/* + * Format of a resource fork block + + [rf-head][r-head][data][?][r-head][data][?][r-head][unused] + ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^ + + * The ^^^ indicate the "resources" stored in the resource fork block + * The ? indicates a possible extra byte that is used to align each + * header on a two byte boundary. + */ + +/* Here are some example ext2_resource_head_struct's: + + { 0, ??, ??, ?? } - no more resources in this block + + { 1, 27, 0x0153, 44 } - resource type '1' is 27 bytes long + has 0x0153-flags set and it is 28 bytes + following this header to the next header + { 1, 1005, 0, 1014 } - resource type '1' is 1005 bytes long. + it padded this means that this resource + (including header) is 1014 bytes. This + can only fit into its own device block + and cannot be followed with a "free-space" + header. In this case it is implicit that + there is no following block. + */ + +/* + * A union for convenient parsing/construction of the resource fork. + */ + +union ext2_rfork_reader { + struct ext2_resource_fork_head_struct *rf_block_head; + struct ext2_resource_head_struct *rf_res_head; + __u8 *rf_data; +}; + +/* + * Locate the first resource fork for this inode + */ + +static __u32 ext2_locate_resource_fork(const struct inode * const inode, + int *err) +{ + __u32 block; + + /* Is the inode valid? (XXX - Is it an ext2 inode?) */ + if ((inode->i_ino != EXT2_ROOT_INO && + inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) || + inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) { + + ext2_error(inode->i_sb, "ext2_locate_resource_fork" + , "bad inode number: %lu", inode->i_ino); + *err = -EINVAL; + block = 0; + + } else { + /* identify block this inode uses for its resource fork */ + + block = inode->u.ext2_i.i_resource_fork; + if (!block) { + res_debug("no resource fork on inode %ld\n", + inode->i_ino); + *err = -ENODATA; + } else { + *err = 0; + } + } + + return block; +} + +/* + * Read a requested resource from the resource fork associated with the + * argument inode. + * + * The resource requested is identified by the members of the argument + * resource_struct, the size field of this header indicates how + * much space is available for the corresponding information. The + * information (if available) is returned as the contents of the + * argument resource_struct.buf. + * + * 0 = SUCCESS, all other returns indicate an error. Only when the + * return is 0 will the argument resource be filled. Note, the size + * member of the resource will be _changed_ to indicate the size of + * the returned resource->buf. NB. If it is important, the calling + * function should independently keep track of the real size of this + * buffer. + */ + +int ext2_get_resource(struct inode *inode, + struct resource_struct *resource) +{ + __u16 id; + __u32 block; + int err; + + if(!(inode->i_sb->u.ext2_sb.s_feature_ro_compat & + EXT2_FEATURE_RO_COMPAT_RES_FORK)) { + resource->size = resource->flags = 0; + return 0; + } + + res_debug("getting resource for inode %ld\n", inode->i_ino); + block = ext2_locate_resource_fork(inode, &err); + if (err) { + res_debug("failed; error %d\n", -err); + if(err == -ENODATA) { + resource->size = resource->flags = 0; + err = 0; + } + return err; + } + + /* read the chain of resource forks */ + do { + struct buffer_head *bh; + union ext2_rfork_reader res; + __u32 old_block, magic; + + /* obtain the resource fork block */ + bh = bread(inode->i_dev, (old_block=block), + inode->i_sb->s_blocksize); + if (bh == NULL) { + ext2_error(inode->i_sb, "ext2_get_resource" + , "bad (%d) resource fork block (%u)" + , err, old_block); + return -EINVAL; /* XXX - this needs attention */ + } + res.rf_data = (__u8 *) bh->b_data; + + /* have a block. Is it a resource-fork? */ + magic = 0; + if (!res.rf_data) + goto badmagic; + magic = le32_to_cpu(res.rf_block_head->magic); + if(magic != EXT2_RESOURCE_FORK_MAGIC) { + badmagic: + ext2_error(inode->i_sb, "ext2_get_resource", + "bad magic (%.8x) for resource fork (%u)", + magic, old_block); + brelse(bh); + return -EINVAL; /* XXX - this needs attention */ + } + + /* identify next block */ + block = le32_to_cpu(res.rf_block_head->next_fork_block); + ++res.rf_block_head; + + /* loop through the resources in this block */ + while ((id = le16_to_cpu(res.rf_res_head->id))) { + __u16 sz = le16_to_cpu(res.rf_res_head->size); + __u16 len = le16_to_cpu(res.rf_res_head->length); + if (id == resource->id) { + /* Success! Is there enough space * + * to store this resource? */ + if (resource->size < sz) { + ext2_warning(inode->i_sb, + "ext2_get_resource", + "insufficient space " + "to copy resource"); + err = -EFBIG; /* XXX - this needs attention */ + } else { + /* copy the resource from block */ + resource->size = sz; + resource->flags = + le16_to_cpu(res.rf_res_head->flags); + memcpy(resource->buf, 1+res.rf_res_head, + sz); + res_debug("found resource, size = %u\n", + sz); + err = 0; + } + brelse(bh); /* tidy up */ + return err; + } + + /* check if there is another resource */ + if (!len) { + res_debug("block has no room for " + "next resource\n"); + break; /* try next block */ + } + + /* jump to the next header in this block */ + res.rf_data += len; + if (res.rf_data > BLOCK_SIZE + (__u8 *) bh->b_data) { + ext2_error(inode->i_sb, "ext2_get_resource", + "corrupted resource fork (%u)", + old_block); + brelse(bh); + return -EINVAL; /* XXX - this needs attention */ + } + + } + + brelse(bh); + + } while (block); /* zero = end of block list */ + + res_debug("specific resource not found\n"); + resource->size = 0; + return 0; +} + +/* + * Copy the resource to the data block + */ + +static void ext2_copy_resource(const struct resource_struct *resource, + const union ext2_rfork_reader res) +{ + /* insert the resource info and copy data */ + res.rf_res_head->id = cpu_to_le16(resource->id); + res.rf_res_head->flags = cpu_to_le16(resource->flags); + res.rf_res_head->size = cpu_to_le16(resource->size); + res.rf_res_head->length = cpu_to_le16( + sizeof(struct ext2_resource_head_struct) + + resource->size + + (resource->size&1) /* __u16 aligned */ + ); + memcpy(1+res.rf_res_head, resource->buf, resource->size); +} + +/* + * This function writes a resource to the resource fork of this inode. + * The function will create a resource fork if the inode does not + * currently possess one. It will replace an existing resource if the + * old one exists (resizing if necessary). If there is insufficient + * space for the new resource in the current chain of resource forks, + * the chain is extended with a new fork. + * + * This function may also be used to remove resources from a resource + * fork. This is achieved by specifying a size of zero for the + * resource. + */ + +int ext2_put_resource(struct inode *inode, + const struct resource_struct * const resource) +{ + __u32 block, first, goal; + union ext2_rfork_reader res; + int err, flags; + struct buffer_head *bh; + + if(!(inode->i_sb->u.ext2_sb.s_feature_ro_compat & + EXT2_FEATURE_RO_COMPAT_RES_FORK)) { + if(!resource->size && !resource->flags) + return 0; + return -EINVAL; + } + + res_debug("putting resource for inode %ld\n", inode->i_ino); + /* Determine where to store the resource */ + first = block = ext2_locate_resource_fork(inode, &err); + if (err) { + if (err != -ENODATA) { + res_debug("inode corruption\n"); + return err; + } + res_debug("will create new resource\n"); + } + + /* Need to know inode is OK (above) before checking resource length? */ + + if (resource->size > BLOCK_SIZE - + ( sizeof(struct ext2_resource_fork_head_struct) + + sizeof(struct ext2_resource_head_struct) )) { + ext2_error(inode->i_sb, "ext2_put_resource" + , "resource (%d) too long for ext2 fork (#%u)" + , resource->size, block); + return -EINVAL; + } + +#define JUST_DELETE 01 +#define ALL_DONE 02 +#define DIRTY_BUFFER 04 + + /* is this a replacement or removal request? */ + flags = (!resource->size && !resource->flags) ? JUST_DELETE:0 ; + + while (block) { + __u32 next, magic; + + bh = bread(inode->i_dev, block, inode->i_sb->s_blocksize); + if (bh == NULL || err) { + ext2_error(inode->i_sb, "ext2_put_resource" + , "(%d) no resource fork block (%u)" + , err, block); + if (bh) + brelse(bh); + return -EINVAL; /* XXX - this needs attention */ + } + res.rf_data = (__u8 *) bh->b_data; + magic = le32_to_cpu(res.rf_block_head->magic); + if (magic != EXT2_RESOURCE_FORK_MAGIC) { + ext2_error(inode->i_sb, "ext2_put_resource", + "bad magic (%.8x) in block %u", + magic, block); + brelse(bh); + return -EINVAL; /* XXX - this needs attention */ + } + next = le32_to_cpu((res.rf_block_head++)->next_fork_block); + + flags &= ~DIRTY_BUFFER; /* Set if we change the buffer */ + + /* Loop through the resource headers in this block */ + while (!(flags & ALL_DONE)) { + __u16 id; + /* find how much of the fork is left to parse */ + int remains_in_fork = BLOCK_SIZE + - (res.rf_data - (__u8 *) bh->b_data); + + /* Enough space for another resource? */ + if (remains_in_fork < + sizeof(struct ext2_resource_head_struct)) { + res_debug("reached the end of this block\n"); + break; + } + + id = le16_to_cpu(res.rf_res_head->id); + /* Is this resource header unused? */ + if (!id) { + + /* Have located a resource header * + * -- remove from count */ + remains_in_fork -= + sizeof(struct ext2_resource_head_struct); + + /* Found a space large enough for this resource? */ + if (remains_in_fork > resource->size) { + __u16 len; + /* Will change buffer */ + mark_buffer_dirty(bh, 1); + + /* write the resource */ + ext2_copy_resource(resource, res); + + /* if possible, mark with * + * "terminating header" */ + len = le16_to_cpu(res.rf_res_head->length); + if (remains_in_fork >= len) { + res.rf_data += len; + res.rf_res_head->id = 0; + } + + /* For the rest of the search, * + * set "just-delete" flag */ + flags |= JUST_DELETE|DIRTY_BUFFER; + + } else { + /* empty resources are only allowed * + * at end of block so we are done * + * searching this one */ + res_debug("empty space (%d) not " + "sufficient for resource (%d)\n", + remains_in_fork, resource->size); + } + + break; /* We're done with this fork block */ + + } else if (id == resource->id) { + /* Will change buffer */ + mark_buffer_dirty(bh, 1); + + /* Found an old version of this resource */ + if (!(flags & JUST_DELETE) && + le16_to_cpu(res.rf_res_head->size) == + resource->size) { + + /* Overwrite old with new */ + ext2_copy_resource(resource, res); + + /* step on with the search */ + res.rf_data += + le16_to_cpu(res.rf_res_head->length); + + flags |= ALL_DONE; + } else { + __u16 len = + le16_to_cpu(res.rf_res_head->length); + int length = remains_in_fork - len; + union ext2_rfork_reader fix = res; + + /* Just delete this resource */ + memmove(res.rf_data, + len + res.rf_data, length); + + /* "Just in case" append terminator */ + fix.rf_data += length; + fix.rf_res_head->id = 0; + + if (flags & JUST_DELETE) { + flags |= ALL_DONE; + } + /* Else, search from same place */ + } + + /* XXX - if we make an empty block, it * + * might be wise to remove it from chain? */ + + flags |= DIRTY_BUFFER; + } else { + /* Some other resource - ignore it */ + res.rf_data += + le16_to_cpu(res.rf_res_head->length); + } + } + + if (flags & DIRTY_BUFFER) + /* This buffer has been changed */ + mark_buffer_dirty(bh, 1); + + brelse(bh); + + if (flags & ALL_DONE) + return 0; + + block = next; + } + + /* + * If we get here and the "just delete" flag is not set, we need + * to add a new block to the resource_fork chain: this will + * contain the new resource. + */ + + if (flags & JUST_DELETE) + return 0; + + /* + * I have opted to add this resource at the "top" of the chain + * (directly to the inode) primarily because it is easier to + * program. + * + * This also means that we will dirty the inode. We need to make + * sure that the inode is marked for writing to disk. + */ + + goal = inode->u.ext2_i.i_resource_fork; + if (!goal) { + /* this was ripped from inode.c */ + goal = (inode->u.ext2_i.i_block_group * + EXT2_BLOCKS_PER_GROUP(inode->i_sb)) + + inode->i_sb->u.ext2_sb.s_es->s_first_data_block; + } + + /* Get a new block - XXX could we have prealloc_ info? */ + block = ext2_new_block(inode, goal, 0, 0, &err); + if (!block) { + ext2_warning(inode->i_sb, "ext2_put_resource" + , "no space for resource"); + return -ENOSPC; + } + + bh = bread(inode->i_dev, block, inode->i_sb->s_blocksize); + if (!bh) { + ext2_error(inode->i_sb, "ext2_put_resource" + , "unable to read block (%u)", block); + return -EINVAL; /* XXX -- This should probably be fixed */ + } + res.rf_data = (__u8 *) bh->b_data; + + /* Make new block a resource fork; link current first block as "next" */ + res.rf_block_head->magic = cpu_to_le16(EXT2_RESOURCE_FORK_MAGIC); + res.rf_block_head++->next_fork_block = cpu_to_le32(first); + + /* Add the requested resource */ + ext2_copy_resource(resource, res); + res.rf_data += le16_to_cpu(res.rf_res_head->length); + + /* Append a terminator */ + res.rf_res_head->id = 0; + + /* Mark the block as "to be written" */ + mark_buffer_dirty(bh, 1); + + /* Alter the inode resource fork pointer to this block */ + inode->u.ext2_i.i_resource_fork = block; + + /* Mark inode as "to be written" */ + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + inode->i_dirt = 1; + + /* All done! */ + return 0; +} + +/* + * This function is used to delete the resource fork (chain) + * associated with an inode. It must be called when the inode is to be + * deleted. + */ + +int ext2_unlink_resource_fork(struct inode *inode) +{ + __u32 block; + int err; + + res_debug("unlinking resource fork for inode %ld\n", inode->i_ino); + /* Obtain resource fork block number */ + block = ext2_locate_resource_fork(inode, &err); + if (err) { + res_debug("no resource fork (error %d)\n", -err); + return err; + } + + /* Purge inode of its link to it */ + inode->u.ext2_i.i_resource_fork = 0; + inode->i_dirt = 1; + + while (block) { + __u32 old_block; + struct buffer_head *bh; + union ext2_rfork_reader res; + + /* + * From here on, a failure may result in block leakage, but + * this is likely to be the least of our worries, as the + * filesystem is likely corrupted. + */ + + /* find block */ + bh = bread(inode->i_dev, (old_block=block), + inode->i_sb->s_blocksize); + if (bh == NULL) { + ext2_error(inode->i_sb, "ext2_unlink_resource_fork" + , "bad (%d) resource fork block (%u)" + , err, old_block); + return -EINVAL; /* XXX - this needs attention */ + } + res.rf_data = (__u8 *) bh->b_data; + + /* step on to next block in chain */ + block = le32_to_cpu(res.rf_block_head->next_fork_block); + + /* purge block */ + brelse(bh); + ext2_free_blocks(inode, old_block, 1); + } + + return 0; +} diff -urN linux-2.0.30/fs/ext2/super.c linux-privs/fs/ext2/super.c --- linux-2.0.30/fs/ext2/super.c Sun Jul 7 01:06:53 1996 +++ linux-privs/fs/ext2/super.c Mon Apr 14 20:29:51 1997 @@ -454,6 +454,9 @@ if (es->s_rev_level == EXT2_GOOD_OLD_REV) { sb->u.ext2_sb.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; sb->u.ext2_sb.s_first_ino = EXT2_GOOD_OLD_FIRST_INO; + sb->u.ext2_sb.s_feature_compat = 0; + sb->u.ext2_sb.s_feature_incompat = 0; + sb->u.ext2_sb.s_feature_ro_compat = 0; } else { sb->u.ext2_sb.s_inode_size = es->s_inode_size; sb->u.ext2_sb.s_first_ino = es->s_first_ino; @@ -462,6 +465,9 @@ sb->u.ext2_sb.s_inode_size); goto failed_mount; } + sb->u.ext2_sb.s_feature_compat = es->s_feature_compat; + sb->u.ext2_sb.s_feature_incompat = es->s_feature_incompat; + sb->u.ext2_sb.s_feature_ro_compat = es->s_feature_ro_compat; } sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE << es->s_log_frag_size; diff -urN linux-2.0.30/fs/fcntl.c linux-privs/fs/fcntl.c --- linux-2.0.30/fs/fcntl.c Thu Jul 4 11:23:45 1996 +++ linux-privs/fs/fcntl.c Mon Apr 14 20:29:51 1997 @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -142,12 +143,12 @@ if ((p->session != current->session) && (p->uid != current->uid) && (p->euid != current->euid) && - !suser()) + !capable(CAP_CHOWN)) return -EPERM; break; } } - if ((task_found == 0) && !suser()) + if ((task_found == 0) && !capable(CAP_CHOWN)) return -EINVAL; fasync_ok: filp->f_owner = arg; diff -urN linux-2.0.30/fs/file_cap.c linux-privs/fs/file_cap.c --- linux-2.0.30/fs/file_cap.c Wed Dec 31 16:00:00 1969 +++ linux-privs/fs/file_cap.c Wed Apr 16 21:59:50 1997 @@ -0,0 +1,410 @@ +/* + * Copyright (C) 1997 Andrew G. Morgan + * Copyright (C) 1997 Andrew Main + * + * Read a file's capabilities. + */ + +/* Define to add debugging code */ +#undef DEBUG + +#ifdef DEBUG +# define cap_debug(f, a...) ({ \ + printk (KERN_DEBUG "POSIX.6_cap DEBUG (%s, %d): %s: ", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (f, ## a); \ +}) +# define cap_debugcap(str, cap) \ + cap_debug(str "%08x %08x %08x %08x\n", \ + (cap)._blk[0], (cap)._blk[1], (cap)._blk[2], (cap)._blk[3] ) +#else +# define cap_debug(f, a...) +# define cap_debugcap(str, cap) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 1 /* XXX -- temporary code for 2.0 (delete when porting to 2.1) */ +static inline __u16 le16_to_cpu(__u16 n) +{ + __u8 *p = (__u8 *) &n; + return p[0] | (p[1] << 8); +} +static inline __u32 le32_to_cpu(__u32 n) +{ + __u8 *p = (__u8 *) &n; + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} +# define cpu_to_le16 le16_to_cpu +# define cpu_to_le32 le32_to_cpu +#endif + +#ifdef CONFIG_POSIX6_CAP + +/* + * On disk, capability sets in resources are stored in a purely + * little-endian representation. If the buffers are appropriately + * aligned, they can therefore be accessed as arrays of words of + * any size, and each of these words will itself be little-endian. + */ + +/* + * This function probes the inode's optional resource fork for any + * file capabilities. If there are none or the capabilities are in + * some way corrupted, the default (empty) capabilities are returned. + */ + +int read_inode_caps(struct inode *inode, + cap_set *inheritable, /* aka Allowed */ + cap_set *permitted, /* aka Forced */ + cap_set *effective) +{ + int error, i; + size_t size; + struct resource_struct res; + cap_blk buffer[__CAP_BLKS * 2], eff; + + cap_clear(inheritable); + cap_clear(permitted); + cap_clear(effective); + + cap_debug("reading caps for inode %lu\n", inode->i_ino); + + /* If resources can't be stored on this fs, there aren't any caps */ + if (!inode->i_op || !inode->i_op->get_resource) { + cap_debug("fs doesn't support resources\n"); + return 0; + } + + res.id = RF_RES_ID_FILE_CAPS; + res.size = 2*sizeof(cap_set); + res.flags = 0; + res.buf = (__u8 *) buffer; + + if ((error = inode->i_op->get_resource(inode, &res))) { + cap_debug("error %d getting resource\n", -error); + return error; + } + + /* + * NB. It is possible that the stored capabilities are smaller + * than the kernel's internal representation for them + * (backward compatability built in from the start). This + * piece of code copies as much as is available to the + * beginning of the kernel's representation of capability sets. + */ + + size = res.size >> 3; /* resource is divided into 2 sets */ + eff = (res.flags & RF_RES_FLAG_CAPS_SET_EFFECTIVE) ? ~0:0; + + /* architecture independent copy from device memory */ + for (i=0; i_blk[i] = le32_to_cpu(buffer[i]); + permitted->_blk[i] = le32_to_cpu(buffer[size+i]); + effective->_blk[i] = eff; + } + + /* Check that was correct */ + cap_debug("got resource (res.size = %u)\n", res.size); + cap_debugcap("inheritable = ", *inheritable); + cap_debugcap("permitted = ", *permitted); + cap_debugcap("effective = ", *effective); + + return 0; +} + +/* + * This function is used to set the capabilities of the inode. + */ + +int write_inode_caps(struct inode *inode, + cap_set const *inheritable, /* aka Allowed */ + cap_set const *permitted, /* aka Forced */ + cap_set const *effective) +{ + struct resource_struct res; + cap_blk buffer[__CAP_BLKS * 2]; + + if (cap_isclear(*inheritable) && cap_isclear(*permitted) && + cap_isclear(*effective)) { + /* Special case: if clearing all sets, going back to * + * the default state, remove the resource. */ + if(!inode->i_op || !inode->i_op->put_resource) { + return 0; + } + res.size = res.flags = 0; + } else { + int i; + + if (!inode->i_op || !inode->i_op->put_resource) { + return -EINVAL; + } + + res.size = 2*sizeof(cap_set); + res.buf = (__u8 *) buffer; + + /* architecture independent copy to device memory */ + for (i=0; i<__CAP_BLKS; ++i) { + buffer[i] = cpu_to_le32(inheritable->_blk[i]); + buffer[i+__CAP_BLKS] = cpu_to_le32(permitted->_blk[i]); + } + } + res.id = RF_RES_ID_FILE_CAPS; + res.flags = cap_isclear(*effective) ? 0:RF_RES_FLAG_CAPS_SET_EFFECTIVE; + + cap_debug("(pid=%d) writing caps for inode %lu:\n", + current->pid, inode->i_ino); + cap_debugcap("inheritable = ", *inheritable); + cap_debugcap("permitted = ", *permitted); + cap_debug("on exec DO%s set effective to permitted\n", + (res.flags & RF_RES_FLAG_CAPS_SET_EFFECTIVE) ? "":" NOT" ); + + return inode->i_op->put_resource(inode, &res); +} + +/* + * For sys_{,f}{s,g}etfilecap(), any of the four capability set pointers + * may be NULL, indicating that that set is uninteresting and not to be + * changed. + */ + +static int getfilecaps(struct inode *inode, size_t usize, + void *iset, void *pset, void *eset) +{ + cap_set inheritable, permitted, effective; + int error; + + if ((error = + read_inode_caps(inode, &inheritable, &permitted, &effective))) + return error; + + if (iset && (error = cap_touser(iset, &inheritable, usize))) + return error; + + if (pset && (error = cap_touser(pset, &permitted, usize))) + return error; + + if (eset && (error = cap_touser(eset, &effective, usize))) + return error; + + return 0; +} + +asmlinkage int sys_getfilecap(char const *filename, size_t usize, + void *iset, void *pset, void *eset) +{ + struct inode *inode; + int error; + + if ((error = namei(filename, &inode))) + return error; + + error = getfilecaps(inode, usize, iset, pset, eset); + iput(inode); + return error; +} + +asmlinkage int sys_fgetfilecap(unsigned fd, size_t usize, + void *iset, void *pset, void *eset) +{ + struct file *f; + struct inode *inode; + + if (fd >= NR_OPEN || !(f=current->files->fd[fd]) + || !(inode=f->f_inode)) + return -EBADF; + + return getfilecaps(inode, usize, iset, pset, eset); +} + +/* + * The restrictions on setting a file's capabilities are: + * process must have CAP_SETFCAP capability to set any capabilities + * AND inode should be writable to + * AND (process must own file OR have CAP_FOWNER raised). + */ + +static int setfilecaps(struct inode *inode, size_t usize, + void const *iset, + void const *pset, + void const *eset) +{ + int error; + cap_set inheritable, permitted, effective, junk; + + /* inode is writable? And do we have permission to write to it? */ + if (IS_RDONLY(inode)) + return -EROFS; + else if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || + (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))) + return -EPERM; + + /* copy caps from user space */ + if (iset && (error = cap_fromuser(&inheritable, iset, usize))) + return error; + + if (pset && (error = cap_fromuser(&permitted, pset, usize))) + return error; + + if (eset && (error = cap_fromuser(&effective, eset, usize))) + return error; + + /* Now read current inode */ + if ( (!iset || !pset || !eset) && + (error = read_inode_caps(inode, + iset ? &junk : &inheritable, + pset ? &junk : &permitted, + eset ? &junk : &effective)) ) + return error; + + return write_inode_caps(inode, &inheritable, &permitted, &effective); +} + +asmlinkage int sys_setfilecap(char const *filename, size_t usize, + void const *iset, + void const *pset, + void const *eset) +{ + struct inode *inode; + int error; + + /* permitted to set capabilities? */ + if (!capable(CAP_SETFCAP)) + return -EPERM; + + /* inode exists? */ + if ((error = namei(filename, &inode))) + return error; + + error = setfilecaps(inode, usize, iset, pset, eset); + iput(inode); + return error; +} + +asmlinkage int sys_fsetfilecap(unsigned fd, size_t usize, + void const *iset, + void const *pset, + void const *eset) +{ + struct file *f; + struct inode *inode; + + /* permitted to set capabilities? */ + if (!capable(CAP_SETFCAP)) + return -EPERM; + + if (fd >= NR_OPEN || !(f=current->files->fd[fd]) + || !(inode=f->f_inode)) + return -EBADF; + + return setfilecaps(inode, usize, iset, pset, eset); +} + +#else /* !CONFIG_POSIX6_CAP */ + +asmlinkage int sys_setfilecap(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_getfilecap(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_fsetfilecap(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_fgetfilecap(void) +{ + return -ENOSYS; +} + +#endif /* !CONFIG_POSIX6_CAP */ + +/* + * This function is used to produce the new IDs and capabilities + * from the old ones and the file's capabilities. + * + * The formula used for evolving capabilities is: + * + * pI' = pI + * pP' = fP | (fI & pI) + * pE' = pP' & fE [NB. fE is 0 or ~0] + * + * I=Inheritable, P=Permitted, E=Effective // p=process, f=file + * ' indicates post-exec(). + */ + +void compute_creds(struct linux_binprm *bprm) +{ +#define task current +#ifdef CONFIG_POSIX6_CAP + + /* + * logic for combining capabilities + */ + /* task->cap_inheritable = task->cap_inheritable */ + task->cap_permitted = cap_union(bprm->cap_permitted, + cap_inter(bprm->cap_inheritable, + task->cap_inheritable)); + task->cap_effective = cap_inter(task->cap_permitted, + bprm->cap_effective); + + cap_debug("computed caps for %s (pid %d):\n", task->comm, task->pid); + cap_debugcap("inheritable = ", task->cap_inheritable); + cap_debugcap("permitted = ", task->cap_permitted); + cap_debugcap("effective = ", task->cap_effective); + + /* capability privileged processes should not dump core */ + if (!cap_isclear(task->cap_permitted)) + task->dumpable = 0; + + /* XXX - Audit candidate */ + if (!cap_isclear(task->cap_effective)) { + printk(KERN_NOTICE + "raising capabilities on `%s'(pid=%d) [%04x]:%lu\n", + task->comm, task->pid, + kdev_t_to_nr(bprm->inode->i_dev), bprm->inode->i_ino); + } + +#endif /* CONFIG_POSIX6_CAP */ + + task->suid = task->euid = task->fsuid = bprm->e_uid; + task->sgid = task->egid = task->fsgid = bprm->e_gid; + if (task->euid != task->uid || task->egid != task->gid) + task->dumpable = 0; +} + +/* + * Clear privileges on an executable (to be called when it is written to). + */ + +void clear_file_privs(struct inode *inode) +{ + int idmode; +#ifdef CONFIG_POSIX6_CAP + static cap_set const empty = _CAP_EMPTY_SET; + write_inode_caps(inode, &empty, &empty, &empty); +#endif + /* Don't turn off setgid if no group execute. This special * + * case marks candidates for mandatory locking. */ + idmode = S_ISUID | ((inode->i_mode & S_IXGRP) ? S_ISGID : 0); + if ((inode->i_mode & idmode) && !capable(CAP_FSETID)) { + struct iattr newattrs; + newattrs.ia_mode = inode->i_mode & ~idmode; + newattrs.ia_valid = ATTR_CTIME | ATTR_MODE | ATTR_FORCE; + notify_change(inode, &newattrs); + } +} diff -urN linux-2.0.30/fs/inode.c linux-privs/fs/inode.c --- linux-2.0.30/fs/inode.c Mon Apr 7 14:09:01 1997 +++ linux-privs/fs/inode.c Mon Apr 14 20:29:51 1997 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -278,31 +279,35 @@ /* Make sure a caller can chown */ if ((attr->ia_valid & ATTR_UID) && (current->fsuid != inode->i_uid || - attr->ia_uid != inode->i_uid) && !fsuser()) + attr->ia_uid != inode->i_uid) && + !capable (CAP_CHOWN)) return -EPERM; /* Make sure caller can chgrp */ if ((attr->ia_valid & ATTR_GID) && (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) && - !fsuser()) + !capable (CAP_CHOWN)) return -EPERM; /* Make sure a caller can chmod */ if (attr->ia_valid & ATTR_MODE) { - if ((current->fsuid != inode->i_uid) && !fsuser()) + if ((current->fsuid != inode->i_uid) && + !capable(CAP_FOWNER)) return -EPERM; /* Also check the setgid bit! */ - if (!fsuser() && !in_group_p((attr->ia_valid & ATTR_GID) ? attr->ia_gid : - inode->i_gid)) + if (!in_group_p((attr->ia_valid & ATTR_GID) ? attr->ia_gid : + inode->i_gid) && !capable(CAP_FSETID)) attr->ia_mode &= ~S_ISGID; } /* Check for setting the inode time */ if ((attr->ia_valid & ATTR_ATIME_SET) && - ((current->fsuid != inode->i_uid) && !fsuser())) + ((current->fsuid != inode->i_uid) && + !capable(CAP_FOWNER))) return -EPERM; if ((attr->ia_valid & ATTR_MTIME_SET) && - ((current->fsuid != inode->i_uid) && !fsuser())) + ((current->fsuid != inode->i_uid) && + !capable(CAP_FOWNER))) return -EPERM; return 0; } @@ -327,7 +332,7 @@ inode->i_ctime = attr->ia_ctime; if (attr->ia_valid & ATTR_MODE) { inode->i_mode = attr->ia_mode; - if (!fsuser() && !in_group_p(inode->i_gid)) + if (!capable(CAP_FSETID) && !in_group_p(inode->i_gid)) inode->i_mode &= ~S_ISGID; } inode->i_dirt = 1; diff -urN linux-2.0.30/fs/minix/namei.c linux-privs/fs/minix/namei.c --- linux-2.0.30/fs/minix/namei.c Sat Nov 30 02:21:21 1996 +++ linux-privs/fs/minix/namei.c Mon Apr 14 20:29:51 1997 @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -442,9 +443,9 @@ retval = -EPERM; if (!(inode = iget(dir->i_sb, de->inode))) goto end_rmdir; - if ((dir->i_mode & S_ISVTX) && !fsuser() && + if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_rmdir; if (inode->i_dev != dir->i_dev) goto end_rmdir; @@ -500,7 +501,7 @@ if (!(inode = iget(dir->i_sb, de->inode))) goto end_unlink; retval = -EPERM; - if (S_ISDIR(inode->i_mode)) + if (S_ISDIR(inode->i_mode) && !capable(CAP_LINK_DIR)) goto end_unlink; if (de->inode != inode->i_ino) { iput(inode); @@ -509,9 +510,9 @@ schedule(); goto repeat; } - if ((dir->i_mode & S_ISVTX) && !fsuser() && + if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_unlink; if (de->inode != inode->i_ino) { retval = -ENOENT; @@ -600,7 +601,7 @@ struct minix_dir_entry * de; struct buffer_head * bh; - if (S_ISDIR(oldinode->i_mode)) { + if (S_ISDIR(oldinode->i_mode) && !capable(CAP_LINK_DIR)) { iput(oldinode); iput(dir); return -EPERM; @@ -705,7 +706,7 @@ retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && - current->fsuid != old_dir->i_uid && !fsuser()) + current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de); if (new_bh) { @@ -736,7 +737,7 @@ retval = -EPERM; if (new_inode && (new_dir->i_mode & S_ISVTX) && current->fsuid != new_inode->i_uid && - current->fsuid != new_dir->i_uid && !fsuser()) + current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; if (S_ISDIR(old_inode->i_mode)) { retval = -ENOTDIR; diff -urN linux-2.0.30/fs/namei.c linux-privs/fs/namei.c --- linux-2.0.30/fs/namei.c Mon Mar 17 17:28:54 1997 +++ linux-privs/fs/namei.c Mon Apr 14 20:29:51 1997 @@ -6,12 +6,15 @@ /* * Some corrections by tytso. + * + * POSIX.6 additions Darren J Moffat May 96 */ #include #include #include +#include #include #include #include @@ -99,20 +102,43 @@ int permission(struct inode * inode,int mask) { int mode = inode->i_mode; + int dmask, rmask; + /* Some filesystems have their own ideas of how to do this */ if (inode->i_op && inode->i_op->permission) return inode->i_op->permission(inode, mask); - else if ((mask & S_IWOTH) && IS_RDONLY(inode) && + + /* Nobody gets write access to a read-only fs */ + if ((mask & S_IWOTH) && IS_RDONLY(inode) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) - return -EROFS; /* Nobody gets write access to a read-only fs */ - else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode)) - return -EACCES; /* Nobody gets write access to an immutable file */ - else if (current->fsuid == inode->i_uid) - mode >>= 6; + return -EROFS; + + /* Nobody gets write access to an immutable file */ + if ((mask & S_IWOTH) && IS_IMMUTABLE(inode)) + return -EACCES; + + /* Get DAC permissions */ + if (current->fsuid == inode->i_uid) + dmask = (mode >> 6) & 7; else if (in_group_p(inode->i_gid)) - mode >>= 3; - if (((mode & mask & 0007) == mask) || fsuser()) + dmask = (mode >> 3) & 7; + else + dmask = mode & 7; + + /* Set mask to the set of permission bits that we want * + * but don't get through DAC. */ + mask &= ~dmask; + + /* We have access if DAC allows it, or if we completely override DAC. */ + if(!mask || capable(CAP_DAC_OVERRIDE)) + return 0; + + /* CAP_DAC_READ_SEARCH allows read and search access. rmask is * + * the set of permission bits that it affects. */ + rmask = S_IROTH | (S_ISDIR(inode->i_mode) ? S_IXOTH : 0); + if(!(mask & ~rmask) && capable(CAP_DAC_READ_SEARCH)) return 0; + return -EACCES; } @@ -500,7 +526,7 @@ int error; char * tmp; - if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !fsuser())) + if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !capable(CAP_SYS_ADMIN))) return -EPERM; switch (mode & S_IFMT) { case 0: diff -urN linux-2.0.30/fs/open.c linux-privs/fs/open.c --- linux-2.0.30/fs/open.c Sat Nov 30 02:21:19 1996 +++ linux-privs/fs/open.c Mon Apr 14 20:29:51 1997 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -318,7 +319,7 @@ iput(inode); return -ENOTDIR; } - if (!fsuser()) { + if (!capable(CAP_SYS_CHROOT)) { iput(inode); return -EPERM; } @@ -402,7 +403,8 @@ /* * If the owner has been changed, remove the setuid bit */ - if (inode->i_mode & S_ISUID) { + if (user != inode->i_uid && + (inode->i_mode & S_ISUID) && !capable(CAP_FSETID)) { newattrs.ia_mode &= ~S_ISUID; newattrs.ia_valid |= ATTR_MODE; } @@ -412,7 +414,9 @@ * Don't remove the setgid bit if no group execute bit. * This is a file marked for mandatory locking. */ - if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { + if (group != inode->i_gid && + (inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) && + !capable(CAP_FSETID)) { newattrs.ia_mode &= ~S_ISGID; newattrs.ia_valid |= ATTR_MODE; } @@ -457,7 +461,8 @@ /* * If the owner has been changed, remove the setuid bit */ - if (inode->i_mode & S_ISUID) { + if (user != inode->i_uid && + (inode->i_mode & S_ISUID) && !capable(CAP_FSETID)) { newattrs.ia_mode &= ~S_ISUID; newattrs.ia_valid |= ATTR_MODE; } @@ -467,12 +472,14 @@ * Don't remove the setgid bit if no group execute bit. * This is a file marked for mandatory locking. */ - if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { + if (group != inode->i_gid && + (inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) && + !capable(CAP_FSETID)) { newattrs.ia_mode &= ~S_ISGID; newattrs.ia_valid |= ATTR_MODE; } inode->i_dirt = 1; - if (inode->i_sb->dq_op) { + if (inode->i_sb && inode->i_sb->dq_op) { inode->i_sb->dq_op->initialize(inode, -1); if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0)) return -EDQUOT; @@ -651,7 +658,7 @@ */ asmlinkage int sys_vhangup(void) { - if (!suser()) + if (!capable(CAP_SYS_TTY_CONFIG)) return -EPERM; /* If there is a controlling tty, hang it up */ if (current->tty) diff -urN linux-2.0.30/fs/proc/array.c linux-privs/fs/proc/array.c --- linux-2.0.30/fs/proc/array.c Tue Oct 29 17:42:41 1996 +++ linux-privs/fs/proc/array.c Mon Apr 14 20:29:51 1997 @@ -5,6 +5,9 @@ * based on ideas by Darren Senn * * Fixes: + * Andrew G. Morgan: added capability file to processes + * + * * Michael. K. Johnson: stat,statm extensions. * * @@ -30,6 +33,7 @@ * */ +#include #include #include #include @@ -634,6 +638,39 @@ return buffer - orig; } +#ifdef CONFIG_POSIX6_CAP + +static char *list_caps(const char *prefix, cap_set *c, char *buffer) +{ +/* XXX - this depends on __CAP_BLKS */ +#if __CAP_BLKS != 4 +# error I thought there were 4 cap blocks +#endif + + return buffer + + sprintf(buffer, "%s\t" + "%08x %08x %08x %08x" + "\n", prefix, + c->_blk[0], c->_blk[1], c->_blk[2], c->_blk[3]); +} + +static int get_caps(int pid, char *buffer) +{ + char * orig = buffer; + struct task_struct ** p = get_task(pid), *tsk; + + if (!p || (tsk = *p) == NULL) + return 0; + + buffer = list_caps("Effective:", &tsk->cap_effective, buffer); + buffer = list_caps("Inheritable:", &tsk->cap_inheritable, buffer); + buffer = list_caps("Permitted:", &tsk->cap_permitted, buffer); + + return buffer - orig; +} + +#endif /* CONFIG_POSIX6_CAP */ + static int get_stat(int pid, char * buffer) { struct task_struct ** p = get_task(pid), *tsk; @@ -1069,6 +1106,10 @@ return get_stat(pid, page); case PROC_PID_STATM: return get_statm(pid, page); +#ifdef CONFIG_POSIX6_CAP + case PROC_PID_CAPS: + return get_caps(pid, page); +#endif } return -EBADF; } diff -urN linux-2.0.30/fs/proc/base.c linux-privs/fs/proc/base.c --- linux-2.0.30/fs/proc/base.c Wed Feb 21 01:26:09 1996 +++ linux-privs/fs/proc/base.c Mon Apr 14 20:29:51 1997 @@ -124,6 +124,14 @@ 0, &proc_array_inode_operations, NULL, proc_pid_fill_inode, }); +#ifdef CONFIG_POSIX6_CAP + proc_register(&proc_pid, &(struct proc_dir_entry) { + PROC_PID_CAPS, 12, "capabilities", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations, + NULL, proc_pid_fill_inode, + }); +#endif proc_register(&proc_pid, &(struct proc_dir_entry) { PROC_PID_CMDLINE, 7, "cmdline", S_IFREG | S_IRUGO, 1, 0, 0, diff -urN linux-2.0.30/fs/read_write.c linux-privs/fs/read_write.c --- linux-2.0.30/fs/read_write.c Tue Aug 20 23:18:09 1996 +++ linux-privs/fs/read_write.c Mon Apr 14 20:29:51 1997 @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -167,20 +168,8 @@ * If data has been written to the file, remove the setuid and * the setgid bits. We do it anyway otherwise there is an * extremely exploitable race - does your OS get it right |-> - * - * Set ATTR_FORCE so it will always be changed. */ - if (!suser() && (inode->i_mode & (S_ISUID | S_ISGID))) { - struct iattr newattrs; - /* - * Don't turn off setgid if no group execute. This special - * case marks candidates for mandatory locking. - */ - newattrs.ia_mode = inode->i_mode & - ~(S_ISUID | ((inode->i_mode & S_IXGRP) ? S_ISGID : 0)); - newattrs.ia_valid = ATTR_CTIME | ATTR_MODE | ATTR_FORCE; - notify_change(inode, &newattrs); - } + clear_file_privs(inode); down(&inode->i_sem); error = file->f_op->write(inode,file,buf,count); diff -urN linux-2.0.30/fs/super.c linux-privs/fs/super.c --- linux-2.0.30/fs/super.c Tue Apr 8 08:47:46 1997 +++ linux-privs/fs/super.c Mon Apr 14 20:29:51 1997 @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -638,7 +639,7 @@ int retval; struct inode dummy_inode; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; retval = namei(name, &inode); if (retval) { @@ -839,7 +840,7 @@ unsigned long flags = 0; unsigned long page = 0; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if ((new_flags & (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { diff -urN linux-2.0.30/fs/sysv/namei.c linux-privs/fs/sysv/namei.c --- linux-2.0.30/fs/sysv/namei.c Sat Nov 30 02:21:22 1996 +++ linux-privs/fs/sysv/namei.c Mon Apr 14 20:29:51 1997 @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -434,9 +435,9 @@ retval = -EPERM; if (!(inode = iget(dir->i_sb, de->inode))) goto end_rmdir; - if ((dir->i_mode & S_ISVTX) && !fsuser() && + if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_rmdir; if (inode->i_dev != dir->i_dev) goto end_rmdir; @@ -491,7 +492,7 @@ if (!(inode = iget(dir->i_sb, de->inode))) goto end_unlink; retval = -EPERM; - if (S_ISDIR(inode->i_mode)) + if (S_ISDIR(inode->i_mode) && !capable(CAP_LINK_DIR)) goto end_unlink; if (de->inode != inode->i_ino) { iput(inode); @@ -500,9 +501,9 @@ schedule(); goto repeat; } - if ((dir->i_mode & S_ISVTX) && !fsuser() && + if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_unlink; if (de->inode != inode->i_ino) { retval = -ENOENT; @@ -595,7 +596,7 @@ struct sysv_dir_entry * de; struct buffer_head * bh; - if (S_ISDIR(oldinode->i_mode)) { + if (S_ISDIR(oldinode->i_mode) && !capable(CAP_LINK_DIR)) { iput(oldinode); iput(dir); return -EPERM; @@ -699,7 +700,7 @@ retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && - current->fsuid != old_dir->i_uid && !fsuser()) + current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; new_bh = sysv_find_entry(new_dir,new_name,new_len,&new_de); if (new_bh) { @@ -730,7 +731,7 @@ retval = -EPERM; if (new_inode && (new_dir->i_mode & S_ISVTX) && current->fsuid != new_inode->i_uid && - current->fsuid != new_dir->i_uid && !fsuser()) + current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; if (S_ISDIR(old_inode->i_mode)) { retval = -ENOTDIR; diff -urN linux-2.0.30/fs/umsdos/namei.c linux-privs/fs/umsdos/namei.c --- linux-2.0.30/fs/umsdos/namei.c Sat Nov 30 02:21:23 1996 +++ linux-privs/fs/umsdos/namei.c Mon Apr 14 20:29:51 1997 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -331,16 +332,18 @@ PRINTK (("ret %d ",ret)); if (ret == 0){ /* check sticky bit on old_dir */ - if ( !(old_dir->i_mode & S_ISVTX) || fsuser() || + if ( !(old_dir->i_mode & S_ISVTX) || current->fsuid == old_info.entry.uid || - current->fsuid == old_dir->i_uid ) { + current->fsuid == old_dir->i_uid || + capable(CAP_FOWNER) ) { /* Does new_name already exist? */ PRINTK(("new findentry ")); ret = umsdos_findentry(new_dir,&new_info,0); if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */ - !(new_dir->i_mode & S_ISVTX) || fsuser() || + !(new_dir->i_mode & S_ISVTX) || current->fsuid == new_info.entry.uid || - current->fsuid == new_dir->i_uid ) { + current->fsuid == new_dir->i_uid || + capable(CAP_FOWNER)) { PRINTK (("new newentry ")); umsdos_ren_init(&new_info,&old_info,flags); ret = umsdos_newentry (new_dir,&new_info); @@ -877,9 +880,10 @@ }else if ((empty = umsdos_isempty (sdir)) != 0){ PRINTK (("isempty %d i_count %d ",empty,sdir->i_count)); /* check sticky bit */ - if ( !(dir->i_mode & S_ISVTX) || fsuser() || + if ( !(dir->i_mode & S_ISVTX) || current->fsuid == sdir->i_uid || - current->fsuid == dir->i_uid ) { + current->fsuid == dir->i_uid || + capable(CAP_FOWNER) ) { if (empty == 1){ /* We have to removed the EMD file */ ret = msdos_unlink(sdir,UMSDOS_EMD_FILE @@ -940,9 +944,10 @@ if (ret == 0){ PRINTK (("UMSDOS_unlink %s ",info.fake.fname)); /* check sticky bit */ - if ( !(dir->i_mode & S_ISVTX) || fsuser() || + if ( !(dir->i_mode & S_ISVTX) || current->fsuid == info.entry.uid || - current->fsuid == dir->i_uid ) { + current->fsuid == dir->i_uid || + capable(CAP_FOWNER) ) { if (info.entry.flags & UMSDOS_HLINK){ /* #Specification: hard link / deleting a link When we deletes a file, and this file is a link diff -urN linux-2.0.30/fs/xiafs/namei.c linux-privs/fs/xiafs/namei.c --- linux-2.0.30/fs/xiafs/namei.c Sat Nov 30 02:21:23 1996 +++ linux-privs/fs/xiafs/namei.c Mon Apr 14 20:29:51 1997 @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -498,9 +499,9 @@ retval = -EPERM; if (!(inode = iget(dir->i_sb, de->d_ino))) goto end_rmdir; - if ((dir->i_mode & S_ISVTX) && !fsuser() && + if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_rmdir; if (inode->i_dev != dir->i_dev) goto end_rmdir; @@ -551,7 +552,7 @@ if (!(inode = iget(dir->i_sb, de->d_ino))) goto end_unlink; retval = -EPERM; - if (S_ISDIR(inode->i_mode)) + if (S_ISDIR(inode->i_mode) && !capable(CAP_LINK_DIR)) goto end_unlink; if (de->d_ino != inode->i_ino) { iput(inode); @@ -560,9 +561,9 @@ schedule(); goto repeat; } - if ((dir->i_mode & S_ISVTX) && !fsuser() && + if ((dir->i_mode & S_ISVTX) && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + current->fsuid != dir->i_uid && !capable(CAP_FOWNER)) goto end_unlink; if (!inode->i_nlink) { printk("XIA-FS: Deleting nonexistent file (%s %d)\n", WHERE_ERR); @@ -640,7 +641,7 @@ struct xiafs_direct * de; struct buffer_head * bh; - if (S_ISDIR(oldinode->i_mode)) { + if (S_ISDIR(oldinode->i_mode) && !capable(CAP_LINK_DIR)) { iput(oldinode); iput(dir); return -EPERM; @@ -736,7 +737,7 @@ retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && - current->fsuid != old_dir->i_uid && !fsuser()) + current->fsuid != old_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; new_bh = xiafs_find_entry(new_dir, new_name, new_len, &new_de, NULL); if (new_bh) { @@ -757,7 +758,7 @@ retval = -EPERM; if (new_inode && (new_dir->i_mode & S_ISVTX) && current->fsuid != new_inode->i_uid && - current->fsuid != new_dir->i_uid && !fsuser()) + current->fsuid != new_dir->i_uid && !capable(CAP_FOWNER)) goto end_rename; if (S_ISDIR(old_inode->i_mode)) { retval = -EEXIST; diff -urN linux-2.0.30/include/asm-i386/unistd.h linux-privs/include/asm-i386/unistd.h --- linux-2.0.30/include/asm-i386/unistd.h Thu Mar 21 22:34:02 1996 +++ linux-privs/include/asm-i386/unistd.h Mon Apr 14 20:29:51 1997 @@ -169,6 +169,13 @@ #define __NR_sched_rr_get_interval 161 #define __NR_nanosleep 162 #define __NR_mremap 163 +/* 164 to 168 already reserved as of 2.1.26 */ +#define __NR__setproccap 169 +#define __NR__getproccap 170 +#define __NR__setfilecap 171 +#define __NR__getfilecap 172 +#define __NR__fsetfilecap 173 +#define __NR__fgetfilecap 174 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ #define _syscall0(type,name) \ diff -urN linux-2.0.30/include/linux/binfmts.h linux-privs/include/linux/binfmts.h --- linux-2.0.30/include/linux/binfmts.h Wed May 8 08:28:01 1996 +++ linux-privs/include/linux/binfmts.h Wed Apr 16 19:08:07 1997 @@ -1,6 +1,8 @@ #ifndef _LINUX_BINFMTS_H #define _LINUX_BINFMTS_H +#include +#include #include /* @@ -11,7 +13,8 @@ #define MAX_ARG_PAGES 32 /* - * This structure is used to hold the arguments that are used when loading binaries. + * This structure is used to hold the arguments that are used when + * loading binaries. */ struct linux_binprm{ char buf[128]; @@ -20,6 +23,9 @@ int sh_bang; struct inode * inode; int e_uid, e_gid; +#ifdef CONFIG_POSIX6_CAP + cap_set cap_inheritable, cap_permitted, cap_effective; +#endif int argc, envc; char * filename; /* Name of binary */ unsigned long loader, exec; @@ -27,8 +33,8 @@ }; /* - * This structure defines the functions that are used to load the binary formats that - * linux accepts. + * This structure defines the functions that are used to load the + * binary formats that linux accepts. */ struct linux_binfmt { struct linux_binfmt * next; @@ -58,6 +64,8 @@ extern unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm); extern unsigned long copy_strings(int argc,char ** argv,unsigned long *page, unsigned long p, int from_kmem); + +extern void compute_creds(struct linux_binprm *bprm); /* this eventually goes away */ #define change_ldt(a,b) setup_arg_pages(a,b) diff -urN linux-2.0.30/include/linux/blk.h linux-privs/include/linux/blk.h --- linux-2.0.30/include/linux/blk.h Fri Mar 28 16:08:17 1997 +++ linux-privs/include/linux/blk.h Wed Apr 16 19:08:07 1997 @@ -4,6 +4,7 @@ #include #include #include +#include /* * NR_REQUEST is the number of entries in the request-queue. @@ -107,7 +108,7 @@ #endif #define RO_IOCTLS(dev,where) \ - case BLKROSET: { int __err; if (!suser()) return -EACCES; \ + case BLKROSET: { int __err; if (!capable(CAP_SYS_DEVICES)) return -EACCES; \ __err = verify_area(VERIFY_READ, (void *) (where), sizeof(long)); \ if (!__err) set_device_ro((dev),get_fs_long((long *) (where))); return __err; } \ case BLKROGET: { int __err = verify_area(VERIFY_WRITE, (void *) (where), sizeof(long)); \ diff -urN linux-2.0.30/include/linux/capability.h linux-privs/include/linux/capability.h --- linux-2.0.30/include/linux/capability.h Wed Dec 31 16:00:00 1969 +++ linux-privs/include/linux/capability.h Sun Apr 20 13:40:15 1997 @@ -0,0 +1,433 @@ +/* + * This is + * + * Andrew G. Morgan + * with help from Aleph1, Roland Buresund and Andrew Main. + */ + +#ifndef _LINUX_CAPABILITY_H +#define _LINUX_CAPABILITY_H + +#include + +/* + * Since the number of capabilities will change in time, we define a + * version for this file. Great care should be taken when compiling + * an old library against a new version of this file. + */ +#define _LINUX_CAPABILITY_VERSION 0x19970420 + +/* + * The kernel bitmap holding a capability set + * + * The current implementation is __CAP_BLKS*32 bits. POSIX (at time of + * writing) has ~20 capabilities defined. + */ +#define __CAP_BLKS 4 /* 128 capabilities */ + +#define __CAP_BITS (__CAP_BLKS * 32) /* remember cpp can't grok sizeof() */ + +/* + * The internal representation of a capability set + */ +typedef __u32 __cap_b; +typedef struct __cap_s { + __cap_b _blk[__CAP_BLKS]; +} __cap_s; + +/* Addressing the capabilities */ + +#define _cap_blk(cap_val) ( (cap_val) >> 5 ) +#define _cap_bit(cap_val) ( 0x1 << ((cap_val) & 0x1F) ) + +/* + * Some capability bit manipulations: + * + * Example usage: some_cap_set._cap_raise(CAP_CHOWN); + */ + +#define _cap_raise(cap_val) _blk[ _cap_blk(cap_val) ] |= _cap_bit(cap_val) +#define _cap_lower(cap_val) _blk[ _cap_blk(cap_val) ] &= ~_cap_bit(cap_val) +#define _cap_raised(cap_val) _blk[ _cap_blk(cap_val) ] & _cap_bit(cap_val) + +/** + ** POSIX-defined capabilities + **/ + +/* In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this + overrides the restriction of changing file ownership and group + ownership. */ + +#define CAP_CHOWN 0 + +/* Overrides all DAC restrictions, including ACL restrictions if + [_POSIX_ACL] is defined. */ + +#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. */ + +#define CAP_DAC_READ_SEARCH 2 + +/* Overrides all restrictions about allowed operations on files, where + file owner ID must be equal to the user ID, except where CAP_FSETID + is applicable. It doesn't override MAC and DAC restrictions. */ + +#define CAP_FOWNER 3 + +/* Overrides the following restrictions that the effective user ID + shall match the file owner ID when setting the S_ISUID and S_ISGID + bits on that file; that the effective group ID (or one of the + supplementary group IDs shall match the file owner ID when setting + the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are + cleared on successful return from chown(2). */ + +#define CAP_FSETID 4 + +/* Used to decide between falling back on the old suser() or fsuser(). */ + +#define __LAST_FS_CAP CAP_FSETID + +/* Overrides the restriction that the real or effective user ID of a + process sending a signal must match the real or effective user ID + of the process receiving the signal. */ + +#define CAP_KILL 5 + +/* Overrides the restriction that a process cannot create or delete a + hard link to a directory. This shall not override MAC and DAC + policies. */ + +#define CAP_LINK_DIR 6 + +/* Allows a process to set the file capability of a file. */ + +#define CAP_SETFCAP 7 + +/* Allows setgid(2) manipulation */ + +#define CAP_SETGID 8 + +/* Allows setuid(2) manipulation */ + +#define CAP_SETUID 9 + +/* Overrides the restriction that no process may block SIGKILL and + SIGSTOP */ + +#define CAP_SIGMASK 10 + +/* + * For the following capabilities to be available we need the following + */ +#define _POSIX_MAC + +/* Allows a process to downgrade an object's label */ + +#define CAP_MAC_DOWNGRADE 11 + +/* Overrides MAC read restrictions on objects */ + +#define CAP_MAC_READ 12 + +/* Allows a process to modify its own label */ + +#define CAP_MAC_RELABEL_SUBJ 13 + +/* Allows a process to upgrade an object's label */ + +#define CAP_MAC_UPGRADE 14 + +/* Overrides MAC write restrictions on objects */ + +#define CAP_MAC_WRITE 15 + +/* + * For the following to be available we need the following + */ +#define _POSIX_INF + +/* Prevents the process's Information Label to float during writes */ + +#define CAP_INF_NOFLOAT_OBJ 16 + +/* Prevents the process' Information Label from floating during reads + or executes */ + +#define CAP_INF_NOFLOAT_SUBJ 17 + +/* Allows a process to change an objects information label */ + +#define CAP_INF_RELABEL_OBJ 18 + +/* Allows a process to modify its own information label in violation + of the policy */ + +#define CAP_INF_RELABEL_SUBJ 19 + +/* + * For the following to be available we need the following + */ +#define _POSIX_AUD + +/* Allows a process to modify audit control parameters */ + +#define CAP_AUDIT_CONTROL 20 + +/* Allows a process to write data to the audit trail */ + +#define CAP_AUDIT_WRITE 21 + +/** + ** Capability numbers 22 to 31 are reserved + ** for future POSIX-defined capabilties + **/ + +/** + ** Linux-specific capabilities + **/ + +/* Allow modification of S_IMMUTABLE and S_APPEND file attributes */ + +#define CAP_LINUX_IMMUTABLE 32 + +/* Permission to act as kerneld */ + +#define CAP_LINUX_KERNELD 33 + +/* Allow installation of kernel modules */ + +#define CAP_LINUX_INSMOD 34 + +/* Allow removal of kernel modules */ + +#define CAP_LINUX_RMMOD 35 + +/* Allow ioperm/iopl access */ + +#define CAP_LINUX_RAWIO 36 + +/* Allow configuration of the secure attention key */ + +#define CAP_LINUX_ATTENTION 37 + +/* Allow administration of the random device */ + +#define CAP_LINUX_RANDOM 38 + +/** + ** The rest of the capabilities are not covered by anything above, but are + ** apparently not defined by POSIX. If some of them later *are* defined, + ** the names might have to change. + ** + ** There are three groups of these: CAP_NET, CAP_IPC and CAP_SYS + **/ + +/* Allows binding to TCP/UDP sockets below 1024 */ + +#define CAP_NET_BIND_SERVICE 39 + +/* Allow broadcasting */ + +#define CAP_NET_BROADCAST 40 + +/* Allow setting debug option on sockets */ + +#define CAP_NET_DEBUG 41 + +/* Allow configuring of firewall stuff */ + +#define CAP_NET_FIREWALL 42 + +/* Allow interface configuration */ + +#define CAP_NET_IFCONFIG 43 + +/* Allow use of PACKET sockets */ + +#define CAP_NET_PACKET 44 + +/* Allow use of RAW sockets */ + +#define CAP_NET_RAW 45 + +/* Allow modification of routing tables */ + +#define CAP_NET_ROUTE 46 + +/* CAP.FIXME: what is this about? */ + +#define CAP_NET_SETID 47 + +/* Allow locking of segments in memory */ + +#define CAP_IPC_LOCK 48 + +/* Override IPC ownership checks */ + +#define CAP_IPC_OWNER 49 + +/* Allow use of chroot() */ + +#define CAP_SYS_CHROOT 50 + +/* Allow ptrace() of any process */ + +#define CAP_SYS_PTRACE 51 + +/* Allow configuration of process accounting */ + +#define CAP_SYS_ACCOUNT 52 + +/* System Admin functions: mount et al */ + +#define CAP_SYS_ADMIN 53 + +/* Allow use of reboot() */ + +#define CAP_SYS_BOOT 54 + +/* Allow device administration */ + +#define CAP_SYS_DEVICES 55 + +/* Allow use of renice() on others, and raising of priority */ + +#define CAP_SYS_NICE 56 + +/* Override resource limits */ + +#define CAP_SYS_RESOURCE 57 + +/* Allow manipulation of system clock */ + +#define CAP_SYS_TIME 58 + +/* Allow configuration of tty devices */ + +#define CAP_SYS_TTY_CONFIG 59 + +/* Allow examination and configuration of disk quotas */ + +#define CAP_SYS_QUOTA 60 + +#define __NR_CAP 61 /* XXX - remember to increase */ + +#ifdef __KERNEL__ + +/* + * Internal kernel functions only + */ + +typedef __cap_b cap_blk; +typedef __cap_s cap_set; + +#define _CAP_EMPTY_SET {{0,0,0,0}} + +/* + * logic for combining capabilities + * + * rewritten to allow for the fact that the number of + * capabilities may change and we don't want things to break for + * random reasons.. The compiler should optimize these. + */ + +static inline int cap_isclear(cap_set c) +{ + register i; + for (i=0; i<__CAP_BLKS; ++i) { + if (c._blk[i]) + return 0; + } + return 1; +} + +static inline int cap_disjoint(cap_set a, cap_set b) +{ + register i; + for (i=0; i<__CAP_BLKS; ++i) { + if (a._blk[i] & b._blk[i]) + return 0; + } + return 1; +} + +static inline int cap_subset(cap_set a, cap_set b) +{ + register i; + for (i=0; i<__CAP_BLKS; ++i) { + if (a._blk[i] & ~b._blk[i]) + return 0; + } + return 1; +} + +static inline cap_set cap_inter(cap_set a, cap_set b) +{ + cap_set result; + register i; + for (i=0; i<__CAP_BLKS; ++i) { + result._blk[i] = a._blk[i] & b._blk[i]; + } + return result; +} + +static inline cap_set cap_purge(cap_set a, cap_set b) +{ + cap_set result; + register i; + for (i=0; i<__CAP_BLKS; ++i) { + result._blk[i] = a._blk[i] & ~b._blk[i]; + } + return result; +} + +static inline cap_set cap_union(cap_set a, cap_set b) +{ + cap_set result; + register i; + for (i=0; i<__CAP_BLKS; ++i) { + result._blk[i] = a._blk[i] | b._blk[i]; + } + return result; +} + +static inline void cap_clear(register cap_set *a) +{ + register cap_blk *tmp = a->_blk + __CAP_BLKS; + while (tmp-- > a->_blk) { + *tmp = 0; + } +} + +/* + * These macros determine the fallback behaviour of capable(). If + * cap_is_noroot_cap(), the capability is unvailable; otherwise, + * if cap_is_fs_cap(), the capability is conferred by fsuid == 0; + * otherwise the capability is conferred by euid == 0. + */ + +#define cap_is_noroot_cap(cap) ((cap) == CAP_LINK_DIR || (cap) == CAP_SIGMASK) +#define cap_is_fs_cap(cap) ((cap) <= __LAST_FS_CAP) + +struct inode; /* fully defined in */ + +/* kernel/cap.c */ +int cap_fromuser(cap_set *k, void const *u, size_t usize); +int cap_touser(void *u, cap_set const *k, size_t usize); + +/* fs/file_cap.c */ +int read_inode_caps(struct inode *inode, + cap_set *inheritable, + cap_set *permitted, + cap_set *effective); +int write_inode_caps(struct inode *inode, + cap_set const *inheritable, + cap_set const *permitted, + cap_set const *effective); + +#endif /* __KERNEL__ */ + +#endif /* !_LINUX_CAPABILITY_H */ diff -urN linux-2.0.30/include/linux/ext2_fs.h linux-privs/include/linux/ext2_fs.h --- linux-2.0.30/include/linux/ext2_fs.h Tue Apr 8 08:47:46 1997 +++ linux-privs/include/linux/ext2_fs.h Mon Apr 14 20:29:52 1997 @@ -17,6 +17,7 @@ #define _LINUX_EXT2_FS_H #include +#include /* * The second extended filesystem constants/structures @@ -142,6 +143,30 @@ }; /* + * This is the header for a resource fork block + */ + +#define EXT2_RESOURCE_FORK_MAGIC 0xEC59E5FC + +struct ext2_resource_fork_head_struct { + __u32 magic; /* something to identify resource forks to ext2 */ + __u32 next_fork_block; /* pointer to next fork block for this inode */ +}; + +/* + * This is the resource header as stored in a resource fork block + */ + +struct ext2_resource_head_struct { + __u16 id; /* magic/id of this resource (0 = end) */ + __u16 size; /* size in bytes of resource data (no header) */ + __u16 flags; /* reserved flags for resource modification */ + __u16 length; /* number of __u8's to jump to next + header (INCLUDING this header: ie., 8+...) + ALSO is __u16 aligned. */ +}; + +/* * Structure of a blocks group descriptor */ struct ext2_group_desc @@ -216,7 +241,7 @@ __u32 i_flags; /* File flags */ union { struct { - __u32 l_i_reserved1; + __u32 l_i_res_fork; /* resource fork block */ } linux1; struct { __u32 h_i_translator; @@ -255,7 +280,7 @@ }; #if defined(__KERNEL__) || defined(__linux__) -#define i_reserved1 osd1.linux1.l_i_reserved1 +#define i_res_fork osd1.linux1.l_i_res_fork #define i_frag osd2.linux2.l_i_frag #define i_fsize osd2.linux2.l_i_fsize #define i_reserved2 osd2.linux2.l_i_reserved2 @@ -416,11 +441,12 @@ ~EXT2_DIR_ROUND) /* - * Feature set definitions --- none are defined as of now + * Feature set definitions */ #define EXT2_FEATURE_COMPAT_SUPP 0 #define EXT2_FEATURE_INCOMPAT_SUPP 0 -#define EXT2_FEATURE_RO_COMPAT_SUPP 0 +#define EXT2_FEATURE_RO_COMPAT_RES_FORK 0x00000001 +#define EXT2_FEATURE_RO_COMPAT_SUPP EXT2_FEATURE_RO_COMPAT_RES_FORK #ifdef __KERNEL__ /* @@ -515,6 +541,11 @@ /* truncate.c */ extern void ext2_truncate (struct inode *); + +/* res_fork.c */ +extern int ext2_get_resource(struct inode *, struct resource_struct *); +extern int ext2_put_resource(struct inode *, const struct resource_struct *); +extern int ext2_unlink_resource_fork(struct inode *); /* * Inodes and files operations diff -urN linux-2.0.30/include/linux/ext2_fs_i.h linux-privs/include/linux/ext2_fs_i.h --- linux-2.0.30/include/linux/ext2_fs_i.h Sat May 4 00:06:18 1996 +++ linux-privs/include/linux/ext2_fs_i.h Mon Apr 14 20:29:52 1997 @@ -26,6 +26,7 @@ __u8 i_frag_no; __u8 i_frag_size; __u16 i_osync; + __u32 i_resource_fork; __u32 i_file_acl; __u32 i_dir_acl; __u32 i_dtime; diff -urN linux-2.0.30/include/linux/ext2_fs_sb.h linux-privs/include/linux/ext2_fs_sb.h --- linux-2.0.30/include/linux/ext2_fs_sb.h Sun Dec 1 09:59:18 1996 +++ linux-privs/include/linux/ext2_fs_sb.h Mon Apr 14 20:29:52 1997 @@ -60,6 +60,9 @@ int s_desc_per_block_bits; int s_inode_size; int s_first_ino; + __u32 s_feature_compat; + __u32 s_feature_incompat; + __u32 s_feature_ro_compat; }; #endif /* _LINUX_EXT2_FS_SB */ diff -urN linux-2.0.30/include/linux/fs.h linux-privs/include/linux/fs.h --- linux-2.0.30/include/linux/fs.h Fri Mar 28 16:08:17 1997 +++ linux-privs/include/linux/fs.h Wed Apr 16 19:08:07 1997 @@ -488,6 +488,8 @@ void (*truncate) (struct inode *); int (*permission) (struct inode *, int); int (*smap) (struct inode *,int); + int (*get_resource) (struct inode *, struct resource_struct *); + int (*put_resource) (struct inode *, const struct resource_struct * const); }; struct super_operations { @@ -652,6 +654,8 @@ extern int generic_file_read(struct inode *, struct file *, char *, int); extern int generic_file_mmap(struct inode *, struct file *, struct vm_area_struct *); extern int brw_page(int, struct page *, kdev_t, int [], int, int); + +extern void clear_file_privs(struct inode *inode); extern void put_super(kdev_t dev); unsigned long generate_cluster(kdev_t dev, int b[], int size); diff -urN linux-2.0.30/include/linux/kernel.h linux-privs/include/linux/kernel.h --- linux-2.0.30/include/linux/kernel.h Mon May 20 10:33:57 1996 +++ linux-privs/include/linux/kernel.h Mon Apr 14 20:29:52 1997 @@ -51,7 +51,7 @@ asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); -#if DEBUG +#ifdef DEBUG #define pr_debug(fmt,arg...) \ printk(KERN_DEBUG fmt,##arg) #else @@ -61,12 +61,6 @@ #define pr_info(fmt,arg...) \ printk(KERN_INFO fmt,##arg) - -/* - * "suser()" checks against the effective user id, while "fsuser()" - * is used for file permission checking and checks against the fsuid.. - */ -#define fsuser() (current->fsuid == 0) #endif /* __KERNEL__ */ diff -urN linux-2.0.30/include/linux/proc_fs.h linux-privs/include/linux/proc_fs.h --- linux-2.0.30/include/linux/proc_fs.h Tue Apr 8 08:47:46 1997 +++ linux-privs/include/linux/proc_fs.h Wed Apr 16 19:08:55 1997 @@ -58,6 +58,7 @@ PROC_PID_CMDLINE, PROC_PID_STAT, PROC_PID_STATM, + PROC_PID_CAPS, PROC_PID_MAPS }; diff -urN linux-2.0.30/include/linux/res_fork.h linux-privs/include/linux/res_fork.h --- linux-2.0.30/include/linux/res_fork.h Wed Dec 31 16:00:00 1969 +++ linux-privs/include/linux/res_fork.h Mon Apr 14 20:29:52 1997 @@ -0,0 +1,43 @@ +#ifndef _LINUX_RES_FORK_H +#define _LINUX_RES_FORK_H + +/* + * This file contains generic definitions for inode resources as + * implemented in some filesystems. (Ext2 so far) + */ + +#ifdef __KERNEL__ + +struct resource_struct { + __u16 id; /* MAGIC to indicate which resource (0=empty) */ + __u16 size; /* number of '__u8's that it is safe to + use in buf[..] */ + __u16 flags; /* reserved for later use */ + __u8 *buf; /* pointer for storage of data */ +}; + +/* + * Reserved flag - for ID independent use later. + * (The thought being that the resource is currently indexed + * by its ID. Later we may want to have extended resources + * that span more than a singe resource fork. This bit + * will likely be used to indicate that there is another + * resource of this ID and that it should be concatinated) + */ + +#define RF_RES_FLAG_RESERVED 0x8000 + +/* + * List known resource id's and comment on their expected length + * also list flags used by each resource. + */ + +#define RF_RES_ID_TERMINATOR 0 + +#define RF_RES_ID_FILE_CAPS 1 /* 2*sizeof(cap_set) */ +# define RF_RES_FLAG_CAPS_SET_EFFECTIVE 0x0001 + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_RES_FORK_H */ + diff -urN linux-2.0.30/include/linux/sched.h linux-privs/include/linux/sched.h --- linux-2.0.30/include/linux/sched.h Fri Mar 28 16:08:17 1997 +++ linux-privs/include/linux/sched.h Wed Apr 16 19:08:07 1997 @@ -26,6 +26,12 @@ #include #include +#include + +#ifdef CONFIG_POSIX6_CAP +# include +#endif + /* * cloning flags: */ @@ -183,14 +189,14 @@ long debugreg[8]; /* Hardware debugging registers */ struct exec_domain *exec_domain; /* various fields */ + /* Kernel process handling code */ struct linux_binfmt *binfmt; struct task_struct *next_task, *prev_task; struct task_struct *next_run, *prev_run; unsigned long saved_kernel_stack; unsigned long kernel_stack_page; int exit_code, exit_signal; - /* ??? */ - unsigned long personality; + unsigned long personality; /* ??? */ int dumpable:1; int did_exec:1; /* shouldn't this be pid_t? */ @@ -200,16 +206,13 @@ int session; /* boolean value for session group leader */ int leader; - int groups[NGROUPS]; /* - * pointers to (original) parent process, youngest child, younger sibling, - * older sibling, respectively. (p->father can be replaced with - * p->p_pptr->pid) + * pointers to (original) parent process, youngest child, + * younger sibling, older sibling, respectively. (p->father + * can be replaced with p->p_pptr->pid) */ struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; struct wait_queue *wait_chldexit; /* for wait4() */ - unsigned short uid,euid,suid,fsuid; - unsigned short gid,egid,sgid,fsgid; unsigned long timeout, policy, rt_priority; unsigned long it_real_value, it_prof_value, it_virt_value; unsigned long it_real_incr, it_prof_incr, it_virt_incr; @@ -222,10 +225,17 @@ unsigned long old_maj_flt; /* old value of maj_flt */ unsigned long dec_flt; /* page fault count of the last time */ unsigned long swap_cnt; /* number of pages to swap on next pass */ +/* process credentials */ + unsigned short uid,euid,suid,fsuid; + unsigned short gid,egid,sgid,fsgid; + int groups[NGROUPS]; +#ifdef CONFIG_POSIX6_CAP + cap_set cap_effective, cap_inheritable, cap_permitted; +#endif + char comm[16]; /* limits */ struct rlimit rlim[RLIM_NLIMITS]; unsigned short used_math; - char comm[16]; /* file system info */ int link_count; struct tty_struct *tty; /* NULL if no tty */ @@ -277,12 +287,18 @@ #define DEF_PRIORITY (20*HZ/100) /* 200 ms time slices */ +#ifdef CONFIG_POSIX6_CAP +# define INIT_CAPS _CAP_EMPTY_SET, _CAP_EMPTY_SET, _CAP_EMPTY_SET, +#else +# define INIT_CAPS +#endif + /* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) */ -#define INIT_TASK \ -/* state etc */ { 0,DEF_PRIORITY,DEF_PRIORITY,0,0,0,0, \ +#define INIT_TASK { \ +/* state etc */ 0,DEF_PRIORITY,DEF_PRIORITY,0,0,0,0, \ /* debugregs */ { 0, }, \ /* exec domain */&default_exec_domain, \ /* binfmt */ NULL, \ @@ -290,17 +306,19 @@ /* stack */ 0,(unsigned long) &init_kernel_stack, \ /* ec,brk... */ 0,0,0,0,0, \ /* pid etc.. */ 0,0,0,0,0, \ -/* suppl grps*/ {NOGROUP,}, \ /* proc links*/ &init_task,&init_task,NULL,NULL,NULL,NULL, \ -/* uid etc */ 0,0,0,0,0,0,0,0, \ /* timeout */ 0,SCHED_OTHER,0,0,0,0,0,0,0, \ /* timer */ { NULL, NULL, 0, 0, it_real_fn }, \ /* utime */ 0,0,0,0,0, \ /* flt */ 0,0,0,0,0,0, \ /* swp */ 0,0,0,0,0, \ + /* user credentials */ \ +/* uid etc */ 0,0,0,0,0,0,0,0, \ +/* suppl grps*/ {NOGROUP,}, \ +/* cap's */ INIT_CAPS \ +/* comm */ "swapper", \ /* rlimits */ INIT_RLIMITS, \ /* math */ 0, \ -/* comm */ "swapper", \ /* fs info */ 0,NULL, \ /* ipc */ NULL, NULL, \ /* ldt */ NULL, \ @@ -332,8 +350,6 @@ extern unsigned long prof_len; extern unsigned long prof_shift; -extern int securelevel; /* system security level */ - #define CURRENT_TIME (xtime.tv_sec) extern void sleep_on(struct wait_queue ** p); @@ -353,21 +369,6 @@ const char *device, void *dev_id); extern void free_irq(unsigned int irq, void *dev_id); - -/* - * This has now become a routine instead of a macro, it sets a flag if - * it returns true (to do BSD-style accounting where the process is flagged - * if it uses root privs). The implication of this is that you should do - * normal permissions checks first, and check suser() last. - */ -extern inline int suser(void) -{ - if (current->euid == 0) { - current->flags |= PF_SUPERPRIV; - return 1; - } - return 0; -} extern void copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *); extern void flush_thread(void); diff -urN linux-2.0.30/include/linux/securelevel.h linux-privs/include/linux/securelevel.h --- linux-2.0.30/include/linux/securelevel.h Wed Dec 31 16:00:00 1969 +++ linux-privs/include/linux/securelevel.h Mon Apr 14 20:29:52 1997 @@ -0,0 +1,12 @@ +#ifndef _LINUX_SECURELEVEL_H +#define _LINUX_SECURELEVEL_H 1 + +extern unsigned securelevel; + +#define SECURE_IMMUTABLE 0 /* cannot change S_IMMUTABLE or S_APPEND flags */ +#define SECURE_NOROOT 1 /* UID 0 has no privileges */ +#define SECURE_FIXED 2 /* securelevel can't be changed any more */ + +#define issecure(X) (securelevel & (1 << (X))) + +#endif /* !_LINUX_SECURELEVEL_H */ diff -urN linux-2.0.30/include/linux/suser.h linux-privs/include/linux/suser.h --- linux-2.0.30/include/linux/suser.h Wed Dec 31 16:00:00 1969 +++ linux-privs/include/linux/suser.h Wed Apr 16 19:08:07 1997 @@ -0,0 +1,72 @@ +#ifndef _LINUX_SUSER_H +#define _LINUX_SUSER_H 1 + +#include +#include +#include +#include + +/* + * These have now become functions instead of macros. They set a flag if + * returning true (to do BSD-style accounting where the process is flagged + * if it uses root privs). The implication of this is that you should do + * normal permissions checks first, and check superuserness last. + */ + +/* + * _suser() checks against the effective user id, while _fsuser() + * is used for file permission checking and checks against the fsuid. + * On a system using POSIX.6 privileges, the SECURE_NOROOT flag may be + * set, in which case uids do not grant privilege. + */ + +static inline int _suser(void) +{ + if (!issecure(SECURE_NOROOT) && current->euid == 0) { + current->flags |= PF_SUPERPRIV; + return 1; + } + return 0; +} + +static inline int _fsuser(void) +{ + if (!issecure(SECURE_NOROOT) && current->fsuid == 0) { + current->flags |= PF_SUPERPRIV; + return 1; + } + return 0; +} + +/* + * capable() checks for a particular capability. It falls back on + * _suser()/_fsuser(), which might have been disabled by setting securelevel. + * New privilege checks should use this interface, rather than suser() or + * fsuser(). + */ + +static inline int capable(int cap) +{ +#ifdef CONFIG_POSIX6_CAP + if (current->cap_effective._cap_raised(cap)) { + current->flags |= PF_SUPERPRIV; + return 1; + } +#endif /* CONFIG_POSIX6_CAP */ + if (cap_is_noroot_cap(cap)) + return 0; + return cap_is_fs_cap(cap) ? _fsuser() : _suser(); +} + +/* + * The old interface. These should not be used in new code; use capable() + * instead, which will if appropriate fall back on the behaviour of these. + * When all the existing code has been converted, these can be removed. + */ + +#if 0 /* Wahey -- everything actually has been converted */ +# define suser() _suser() +# define fsuser() _fsuser() +#endif + +#endif /* !_LINUX_SUSER_H */ diff -urN linux-2.0.30/ipc/msg.c linux-privs/ipc/msg.c --- linux-2.0.30/ipc/msg.c Sat Aug 31 23:15:33 1996 +++ linux-privs/ipc/msg.c Mon Apr 14 20:29:52 1997 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -471,7 +472,7 @@ */ if ((msgflg & IPC_KERNELD)) { int i; - if (!suser()) + if (!capable(CAP_LINUX_KERNELD)) return -EPERM; #ifdef NEW_KERNELD_PROTOCOL if ((msgflg & IPC_KERNELD) == OLDIPC_KERNELD) { @@ -635,10 +636,12 @@ memcpy_tofs (buf, &tbuf, sizeof (*buf)); return 0; case IPC_SET: - if (!suser() && current->euid != ipcp->cuid && + if (!capable(CAP_IPC_OWNER) && + current->euid != ipcp->cuid && current->euid != ipcp->uid) return -EPERM; - if (tbuf.msg_qbytes > MSGMNB && !suser()) + if (tbuf.msg_qbytes > MSGMNB && + !capable(CAP_SYS_RESOURCE)) /* CAP.FIXME: Check Priv */ return -EPERM; msq->msg_qbytes = tbuf.msg_qbytes; ipcp->uid = tbuf.msg_perm.uid; @@ -648,7 +651,8 @@ msq->msg_ctime = CURRENT_TIME; return 0; case IPC_RMID: - if (!suser() && current->euid != ipcp->cuid && + if (!capable(CAP_IPC_OWNER) && + current->euid != ipcp->cuid && current->euid != ipcp->uid) return -EPERM; /* diff -urN linux-2.0.30/ipc/sem.c linux-privs/ipc/sem.c --- linux-2.0.30/ipc/sem.c Sat Aug 31 23:15:34 1996 +++ linux-privs/ipc/sem.c Mon Apr 14 20:29:52 1997 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -465,7 +466,9 @@ return -ERANGE; break; case IPC_RMID: - if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) { + if (capable(CAP_IPC_OWNER) || + current->euid == ipcp->cuid || + current->euid == ipcp->uid) { freeary (id); return 0; } @@ -516,7 +519,9 @@ update_queue(sma); break; case IPC_SET: - if (suser() || current->euid == ipcp->cuid || current->euid == ipcp->uid) { + if (capable(CAP_IPC_OWNER) || + current->euid == ipcp->cuid || + current->euid == ipcp->uid) { ipcp->uid = tbuf.sem_perm.uid; ipcp->gid = tbuf.sem_perm.gid; ipcp->mode = (ipcp->mode & ~S_IRWXUGO) diff -urN linux-2.0.30/ipc/shm.c linux-privs/ipc/shm.c --- linux-2.0.30/ipc/shm.c Fri Nov 22 06:25:18 1996 +++ linux-privs/ipc/shm.c Mon Apr 14 20:29:52 1997 @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -284,7 +285,7 @@ switch (cmd) { case SHM_UNLOCK: - if (!suser()) + if (!capable(CAP_IPC_LOCK)) return -EPERM; if (!(ipcp->mode & SHM_LOCKED)) return -EINVAL; @@ -294,7 +295,7 @@ /* Allow superuser to lock segment in memory */ /* Should the pages be faulted in here or leave it to user? */ /* need to determine interaction with current->swappable */ - if (!suser()) + if (!capable(CAP_IPC_LOCK)) return -EPERM; if (ipcp->mode & SHM_LOCKED) return -EINVAL; @@ -319,7 +320,8 @@ memcpy_tofs (buf, &tbuf, sizeof(*buf)); break; case IPC_SET: - if (suser() || current->euid == shp->shm_perm.uid || + if (capable(CAP_IPC_OWNER) || + current->euid == shp->shm_perm.uid || current->euid == shp->shm_perm.cuid) { ipcp->uid = tbuf.shm_perm.uid; ipcp->gid = tbuf.shm_perm.gid; @@ -330,7 +332,8 @@ } return -EPERM; case IPC_RMID: - if (suser() || current->euid == shp->shm_perm.uid || + if (capable(CAP_IPC_OWNER) || + current->euid == shp->shm_perm.uid || current->euid == shp->shm_perm.cuid) { shp->shm_perm.mode |= SHM_DEST; if (shp->shm_nattch <= 0) diff -urN linux-2.0.30/ipc/util.c linux-privs/ipc/util.c --- linux-2.0.30/ipc/util.c Tue Jan 16 21:32:09 1996 +++ linux-privs/ipc/util.c Mon Apr 14 20:29:52 1997 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,7 @@ { /* flag will most probably be 0 or S_...UGO from */ int requested_mode, granted_mode; - if (suser()) + if (capable(CAP_IPC_OWNER)) return 0; requested_mode = (flag >> 6) | (flag >> 3) | flag; granted_mode = ipcp->mode; diff -urN linux-2.0.30/kernel/Makefile linux-privs/kernel/Makefile --- linux-2.0.30/kernel/Makefile Tue Jan 9 23:27:39 1996 +++ linux-privs/kernel/Makefile Mon Apr 14 20:29:52 1997 @@ -13,7 +13,7 @@ O_TARGET := kernel.o O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \ module.o exit.o signal.o itimer.o info.o time.o softirq.o \ - resource.o sysctl.o + resource.o sysctl.o cap.o ifeq ($(CONFIG_MODULES),y) OX_OBJS = ksyms.o diff -urN linux-2.0.30/kernel/cap.c linux-privs/kernel/cap.c --- linux-2.0.30/kernel/cap.c Wed Dec 31 16:00:00 1969 +++ linux-privs/kernel/cap.c Mon Apr 14 20:29:52 1997 @@ -0,0 +1,152 @@ +/* + * linux/kernel/cap.c + * + * Copyright (C) 1997 Andrew Main + */ + +#include +#include +#include + +#ifdef CONFIG_POSIX6_CAP + +#include +#include +#include +#include + +/* + * User programs might have been compiled with a different idea of the number + * of capabilities. These functions provide a standard mechanism for + * translating between kernelspace and userspace capability structures. + * Bitsets are truncated if too big, and zero-filled if too small. + */ + +int cap_fromuser(cap_set *k, void const *u, size_t usize) +{ + int error; + + if (usize > sizeof(cap_set)) + usize = sizeof(cap_set); + if ((error = verify_area(VERIFY_READ, u, usize))) + return error; + memcpy_fromfs(k, u, usize); + if (usize < sizeof(cap_set)) + memset(k + usize, 0, sizeof(cap_set) - usize); + return 0; +} + +int cap_touser(void *u, cap_set const *k, size_t usize) +{ + int error; + size_t csize = usize; + char *p; + + if ((error = verify_area(VERIFY_WRITE, u, usize))) + return error; + if (csize > sizeof(cap_set)) + csize = sizeof(cap_set); + memcpy_tofs(u, k, csize); + for (p = u + csize; csize < usize; csize++, p++) { + put_user(0, p); + if (need_resched) + schedule(); + } + return 0; +} + +/* + * For sys_setproccap() and sys_getproccap(), any of the four capability set + * pointers may be NULL, indicating that that set is uninteresting and not to + * be changed. + */ + +asmlinkage int sys_getproccap(size_t usize, void *iset, void *pset, void *eset) +{ + int error; + + if (pset && (error = cap_touser(pset, ¤t->cap_permitted, usize))) + return error; + + if (iset + && (error = cap_touser(iset, ¤t->cap_inheritable, usize))) + return error; + + if (eset && (error = cap_touser(eset, ¤t->cap_effective, usize))) + return error; + + return 0; +} + +/* + * The restrictions on setting capabilities are: + * + * P: permitted capabilities can only be removed and never added. + * E: must be set to a subset of (new) Permitted + * I: _IF CHANGED_ must be a subset of the (new) Permitted + * + * CAP.FIXME: this policy needs to be checked for POSIX compliance + */ + +asmlinkage int sys_setproccap(size_t usize, void const *iset, + void const *pset, void const *eset) +{ + cap_set inheritable, permitted, effective; + int error; + + /* copy from userspace */ + if (iset && (error = cap_fromuser(&inheritable, iset, usize))) + return error; + + if (pset && (error = cap_fromuser(&permitted, pset, usize))) + return error; + + if (eset && (error = cap_fromuser(&effective, eset, usize))) + return error; + + /* verify new permitted is a subset of old permitted set */ + if (!pset) + permitted = current->cap_permitted; + else if (!cap_subset(permitted, current->cap_permitted)) + return -EPERM; + + /* _IF_ we are changing the inheritable set, it can only + contain capabilities that this process is permitted to raise */ + + if (!iset) + inheritable = current->cap_inheritable; + else if (memcmp(&inheritable, ¤t->cap_inheritable, + sizeof(cap_set)) && + !cap_subset(inheritable, permitted)) + return -EPERM; + + /* verify the (new) effective is a subset of the (new) permitted */ + if (!eset) + effective = cap_inter(current->cap_effective, permitted); + else if (!cap_subset(effective, permitted)) + return -EPERM; + + /* We have verified that the proposed changes are permitted, + so set these capabilities */ + + current->cap_inheritable = inheritable; + current->cap_permitted = permitted; + current->cap_effective = effective; + + /* Success */ + return 0; +} + +#else /* !CONFIG_POSIX6_CAP */ + +asmlinkage int sys_setproccap(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_getproccap(void) +{ + return -ENOSYS; +} + +#endif /* !CONFIG_POSIX6_CAP */ diff -urN linux-2.0.30/kernel/exit.c linux-privs/kernel/exit.c --- linux-2.0.30/kernel/exit.c Tue Oct 29 17:42:42 1996 +++ linux-privs/kernel/exit.c Mon Apr 14 20:29:52 1997 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -77,7 +78,7 @@ if (!priv && ((sig != SIGCONT) || (current->session != p->session)) && (current->euid ^ p->suid) && (current->euid ^ p->uid) && (current->uid ^ p->suid) && (current->uid ^ p->uid) && - !suser()) + !capable(CAP_KILL)) return -EPERM; if (!sig) return 0; diff -urN linux-2.0.30/kernel/fork.c linux-privs/kernel/fork.c --- linux-2.0.30/kernel/fork.c Thu Apr 3 20:02:28 1997 +++ linux-privs/kernel/fork.c Mon Apr 14 20:29:52 1997 @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -36,10 +37,10 @@ int i; if (nr_tasks >= NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT) { - if (current->uid) + if (!capable(CAP_SYS_RESOURCE)) return -EAGAIN; } - if (current->uid) { + if (!capable(CAP_SYS_RESOURCE)) { long max_tasks = current->rlim[RLIMIT_NPROC].rlim_cur; max_tasks--; /* count the new process.. */ diff -urN linux-2.0.30/kernel/ksyms.c linux-privs/kernel/ksyms.c --- linux-2.0.30/kernel/ksyms.c Tue Mar 11 14:37:16 1997 +++ linux-privs/kernel/ksyms.c Mon Apr 14 20:29:52 1997 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff -urN linux-2.0.30/kernel/module.c linux-privs/kernel/module.c --- linux-2.0.30/kernel/module.c Tue May 21 02:00:30 1996 +++ linux-privs/kernel/module.c Mon Apr 14 20:29:52 1997 @@ -5,6 +5,7 @@ #include #include #include +#include #include #include /* @@ -42,6 +43,10 @@ * * - Use dummy syscall functions for users who disable all * module support. Similar to kernel/sys.c (Paul Gortmaker) + * + * May 1996: + * - Checking "security" things when using POSIX.6 + * */ #ifdef CONFIG_MODULES /* a *big* #ifdef block... */ @@ -86,7 +91,7 @@ int sspace = sizeof(struct module) + MOD_MAX_NAME; char name[MOD_MAX_NAME]; - if (!suser()) + if (!capable (CAP_LINUX_INSMOD)) return -EPERM; if (module_name == NULL || size == 0) return -EINVAL; @@ -138,7 +143,7 @@ int error; struct mod_routines rt; - if (!suser()) + if (!capable (CAP_LINUX_INSMOD)) return -EPERM; #ifdef __i386__ @@ -264,7 +269,7 @@ char name[MOD_MAX_NAME]; int error; - if (!suser()) + if (!capable (CAP_LINUX_RMMOD)) return -EPERM; /* else */ if (module_name != NULL) { diff -urN linux-2.0.30/kernel/printk.c linux-privs/kernel/printk.c --- linux-2.0.30/kernel/printk.c Fri Jun 7 01:54:06 1996 +++ linux-privs/kernel/printk.c Mon Apr 14 20:29:52 1997 @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -65,7 +66,7 @@ char c; int error; - if ((type != 3) && !suser()) + if ((type != 3) && !capable (CAP_SYS_ADMIN)) /* CAP.FIXME: check priv */ return -EPERM; switch (type) { case 0: /* Close log */ diff -urN linux-2.0.30/kernel/sched.c linux-privs/kernel/sched.c --- linux-2.0.30/kernel/sched.c Tue Apr 8 08:47:47 1997 +++ linux-privs/kernel/sched.c Mon Apr 14 20:29:52 1997 @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -44,7 +45,7 @@ * kernel variables */ -int securelevel = 0; /* system security level */ +unsigned securelevel = 0; /* system security level */ long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */ volatile struct timeval xtime; /* The current time */ @@ -1312,7 +1313,7 @@ newprio = increment; if (increment < 0) { - if (!suser()) + if (!capable(CAP_SYS_NICE)) return -EPERM; newprio = -increment; increase = 1; @@ -1392,10 +1393,11 @@ if ((policy == SCHED_OTHER) != (lp.sched_priority == 0)) return -EINVAL; - if ((policy == SCHED_FIFO || policy == SCHED_RR) && !suser()) + if ((policy == SCHED_FIFO || policy == SCHED_RR) && + !capable (CAP_SYS_RESOURCE)) return -EPERM; if ((current->euid != p->euid) && (current->euid != p->uid) && - !suser()) + !capable (CAP_SYS_RESOURCE)) return -EPERM; p->policy = policy; diff -urN linux-2.0.30/kernel/signal.c linux-privs/kernel/signal.c --- linux-2.0.30/kernel/signal.c Tue Jul 2 09:08:43 1996 +++ linux-privs/kernel/signal.c Mon Apr 14 20:29:52 1997 @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -17,7 +18,8 @@ #define _S(nr) (1<<((nr)-1)) -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _NBLOCKABLE (_S(SIGKILL) | _S(SIGSTOP)) +#define _BLOCKABLE (~_NBLOCKABLE) #ifndef __alpha__ @@ -35,7 +37,9 @@ error = verify_area(VERIFY_READ, set, sizeof(sigset_t)); if (error) return error; - new_set = get_user(set) & _BLOCKABLE; + new_set = get_user(set); + if((new_set & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + new_set &= _BLOCKABLE; switch (how) { case SIG_BLOCK: current->blocked |= new_set; @@ -71,7 +75,9 @@ { int old=current->blocked; - current->blocked = newmask & _BLOCKABLE; + if((newmask & _NBLOCKABLE) && !capable(CAP_SIGMASK)) + newmask &= _BLOCKABLE; + current->blocked = newmask; return old; } @@ -130,7 +136,7 @@ if (signum<1 || signum>32) return -EINVAL; - if (signum==SIGKILL || signum==SIGSTOP) + if ((signum==SIGKILL || signum==SIGSTOP) && !capable(CAP_SIGMASK)) return -EINVAL; if (handler != SIG_DFL && handler != SIG_IGN) { err = verify_area(VERIFY_READ, handler, 1); @@ -159,7 +165,8 @@ int err = verify_area(VERIFY_READ, action, sizeof(*action)); if (err) return err; - if (signum==SIGKILL || signum==SIGSTOP) + if ((signum==SIGKILL || signum==SIGSTOP) && + !capable(CAP_SIGMASK)) return -EINVAL; memcpy_fromfs(&new_sa, action, sizeof(struct sigaction)); if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { diff -urN linux-2.0.30/kernel/sys.c linux-privs/kernel/sys.c --- linux-2.0.30/kernel/sys.c Tue Apr 8 08:47:47 1997 +++ linux-privs/kernel/sys.c Mon Apr 14 20:29:52 1997 @@ -4,9 +4,11 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include #include +#include #include #include #include @@ -89,13 +91,15 @@ 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; @@ -182,7 +186,7 @@ */ asmlinkage int sys_reboot(int magic, int magic_too, int flag) { - if (!suser()) + if (!capable(CAP_SYS_BOOT)) return -EPERM; if (magic != 0xfee1dead || magic_too != 672274793) return -EINVAL; @@ -240,8 +244,8 @@ if (rgid != (gid_t) -1) { if ((old_rgid == rgid) || - (current->egid==rgid) || - suser()) + (current->egid == rgid) || + (capable(CAP_SETGID))) current->gid = rgid; else return(-EPERM); @@ -250,7 +254,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; @@ -273,7 +277,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; @@ -334,7 +338,7 @@ char *tmp; int error; - if (!suser()) + if (!capable(CAP_SYS_ACCOUNT)) return -EPERM; if (name == (char *)0) { @@ -450,7 +454,7 @@ if (ruid != (uid_t) -1) { if ((old_ruid == ruid) || (current->euid==ruid) || - suser()) + (capable(CAP_SETUID))) current->uid = ruid; else return(-EPERM); @@ -459,7 +463,7 @@ if ((old_ruid == euid) || (current->euid == euid) || (current->suid == euid) || - suser()) + (capable(CAP_SETUID))) current->fsuid = current->euid = euid; else { current->uid = old_ruid; @@ -470,8 +474,12 @@ (euid != (uid_t) -1 && euid != old_ruid)) current->suid = current->euid; current->fsuid = current->euid; - if (current->euid != old_euid) + if (current->euid != old_euid) { +#ifdef CONFIG_POSIX6_CAP + cap_clear(¤t->cap_effective); +#endif current->dumpable = 0; + } return 0; } @@ -490,14 +498,18 @@ { int old_euid = current->euid; - if (suser()) + if (capable(CAP_SETGID)) current->uid = current->euid = current->suid = current->fsuid = uid; else if ((uid == current->uid) || (uid == current->suid)) current->fsuid = current->euid = uid; else return -EPERM; - if (current->euid != old_euid) + if (current->euid != old_euid) { +#ifdef CONFIG_POSIX6_CAP + cap_clear(¤t->cap_effective); +#endif current->dumpable = 0; + } return(0); } @@ -512,10 +524,15 @@ int 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) + if (current->fsuid != old_fsuid) { +#ifdef CONFIG_POSIX6_CAP + cap_clear(¤t->cap_effective); +#endif current->dumpable = 0; + } return old_fsuid; } @@ -527,7 +544,8 @@ int 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; @@ -685,7 +703,7 @@ { int i; - if (!suser()) + if (!capable(CAP_SETGID)) return -EPERM; if (gidsetsize > NGROUPS) return -EINVAL; @@ -782,7 +800,7 @@ { int error; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; @@ -818,7 +836,7 @@ { int error; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; @@ -859,7 +877,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 linux-2.0.30/kernel/sysctl.c linux-privs/kernel/sysctl.c --- linux-2.0.30/kernel/sysctl.c Mon Mar 31 13:22:37 1997 +++ linux-privs/kernel/sysctl.c Mon Apr 14 20:29:52 1997 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -128,8 +129,8 @@ 0444, NULL, &proc_dointvec}, {KERN_MAXFILE, "file-max", &max_files, sizeof(int), 0644, NULL, &proc_dointvec}, - {KERN_SECURELVL, "securelevel", &securelevel, sizeof(int), - 0444, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy}, + {KERN_SECURELVL, "securelevel", &securelevel, sizeof(unsigned), + 0644, NULL, &proc_dointvec, (ctl_handler *)&do_securelevel_strategy}, {KERN_PANIC, "panic", &panic_timeout, sizeof(int), 0644, NULL, &proc_dointvec}, #ifdef CONFIG_BLK_DEV_INITRD @@ -348,13 +349,14 @@ void *oldval, size_t *oldlenp, void *newval, size_t newlen, void **context) { - int level; + unsigned level; if (newval && newlen) { - if (newlen != sizeof (int)) + if (newlen != sizeof (unsigned)) return -EINVAL; memcpy_fromfs (&level, newval, newlen); - if (level < securelevel && current->pid != 1) + if (issecure(SECURE_FIXED) || + ((~level & securelevel) && current->pid != 1)) return -EPERM; } return 0; diff -urN linux-2.0.30/kernel/time.c linux-privs/kernel/time.c --- linux-2.0.30/kernel/time.c Wed Apr 24 23:59:33 1996 +++ linux-privs/kernel/time.c Mon Apr 14 20:29:52 1997 @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -66,7 +67,7 @@ { int error, value; - if (!suser()) + if (!capable (CAP_SYS_TIME)) return -EPERM; error = verify_area(VERIFY_READ, tptr, sizeof(*tptr)); if (error) @@ -144,7 +145,7 @@ struct timeval new_tv; struct timezone new_tz; - if (!suser()) + if (!capable (CAP_SYS_TIME)) return -EPERM; if (tv) { int error = verify_area(VERIFY_READ, tv, sizeof(*tv)); @@ -211,7 +212,7 @@ memcpy_fromfs(&txc, txc_p, sizeof(struct timex)); /* 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 linux-2.0.30/mm/mlock.c linux-privs/mm/mlock.c --- linux-2.0.30/mm/mlock.c Wed Sep 11 07:57:19 1996 +++ linux-privs/mm/mlock.c Mon Apr 14 20:29:52 1997 @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include @@ -140,7 +141,7 @@ struct vm_area_struct * vma, * next; int error; - if (!suser()) + if (!capable(CAP_SYS_RESOURCE)) return -EPERM; len = (len + ~PAGE_MASK) & PAGE_MASK; end = start + len; @@ -221,7 +222,7 @@ unsigned int def_flags; struct vm_area_struct * vma; - if (!suser()) + if (!capable(CAP_SYS_RESOURCE)) return -EPERM; def_flags = 0; diff -urN linux-2.0.30/mm/swapfile.c linux-privs/mm/swapfile.c --- linux-2.0.30/mm/swapfile.c Mon Mar 31 13:22:37 1997 +++ linux-privs/mm/swapfile.c Mon Apr 14 20:29:53 1997 @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -323,7 +324,7 @@ int i, type, prev; int err; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = namei(specialfile,&inode); if (err) @@ -413,7 +414,7 @@ static int least_priority = 0; memset(&filp, 0, sizeof(filp)); - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; p = swap_info; for (type = 0 ; type < nr_swapfiles ; type++,p++) diff -urN linux-2.0.30/net/appletalk/ddp.c linux-privs/net/appletalk/ddp.c --- linux-2.0.30/net/appletalk/ddp.c Thu Nov 14 05:20:10 1996 +++ linux-privs/net/appletalk/ddp.c Mon Apr 14 20:29:53 1997 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -755,7 +756,7 @@ switch(cmd) { case SIOCSIFADDR: - if(!suser()) + if(!capable(CAP_NET_IFCONFIG)) return -EPERM; if(sa->sat_family!=AF_APPLETALK) return -EINVAL; @@ -1913,7 +1914,7 @@ */ case SIOCADDRT: case SIOCDELRT: - if(!suser()) + if(!capable(CAP_NET_ROUTE)) return -EPERM; return(atrtr_ioctl(cmd,(void *)arg)); /* diff -urN linux-2.0.30/net/ax25/af_ax25.c linux-privs/net/ax25/af_ax25.c --- linux-2.0.30/net/ax25/af_ax25.c Thu Nov 14 05:20:10 1996 +++ linux-privs/net/ax25/af_ax25.c Mon Apr 14 20:29:53 1997 @@ -97,6 +97,7 @@ #include #include #include +#include #include #include #include @@ -493,7 +494,7 @@ return -ENOENT; case SIOCAX25ADDUID: - if(!suser()) + if(!capable(CAP_NET_SETID)) return -EPERM; if (ax25_findbyuid(sax->sax25_uid)) return -EEXIST; @@ -509,7 +510,7 @@ case SIOCAX25DELUID: { ax25_uid_assoc **l; - if(!suser()) + if(!capable(CAP_NET_SETID)) return -EPERM; l = &ax25_uid_list; while ((*l) != NULL) { @@ -1320,7 +1321,8 @@ return -EINVAL; call = ax25_findbyuid(current->euid); - if (call == NULL && ax25_uid_policy && !suser()) + if (call == NULL && ax25_uid_policy && + !capable(CAP_NET_IFCONFIG)) return -EPERM; if (call == NULL) @@ -2193,7 +2195,7 @@ case SIOCAX25NOUID: /* Set the default policy (default/bar) */ if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(unsigned long))) != 0) return err; - if(!suser()) + if(!capable(CAP_NET_SETID)) return -EPERM; amount = get_fs_long((void *)arg); if (amount > AX25_NOUID_BLOCK) @@ -2203,7 +2205,7 @@ #ifdef CONFIG_BPQETHER case SIOCAX25BPQADDR: - if (!suser()) + if (!capable(CAP_NET_ROUTE) return -EPERM; return ax25_bpq_ioctl(cmd, (void *)arg); #endif @@ -2215,12 +2217,12 @@ case SIOCADDRT: case SIOCDELRT: case SIOCAX25OPTRT: - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; return ax25_rt_ioctl(cmd, (void *)arg); case SIOCAX25CTLCON: - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; return ax25_ctl_ioctl(cmd, (void *)arg); diff -urN linux-2.0.30/net/ax25/ax25_route.c linux-privs/net/ax25/ax25_route.c --- linux-2.0.30/net/ax25/ax25_route.c Sat Aug 10 00:03:16 1996 +++ linux-privs/net/ax25/ax25_route.c Mon Apr 14 20:29:53 1997 @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -413,7 +414,7 @@ ax25->device = ax25_rt->dev; if ((call = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !suser()) + if (ax25_uid_policy && !capable(CAP_NET_IFCONFIG)) return -EPERM; call = (ax25_address *)ax25->device->dev_addr; } @@ -604,7 +605,7 @@ switch (cmd) { case SIOCAX25SETPARMS: - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; if ((err = verify_area(VERIFY_READ, arg, sizeof(ax25_parms))) != 0) return err; diff -urN linux-2.0.30/net/bridge/br.c linux-privs/net/bridge/br.c --- linux-2.0.30/net/bridge/br.c Thu Nov 7 22:44:27 1996 +++ linux-privs/net/bridge/br.c Mon Apr 14 20:29:53 1997 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1451,7 +1452,7 @@ memcpy_tofs(arg, &br_stats, sizeof(struct br_stat)); return(0); case SIOCSIFBR: - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; err = verify_area(VERIFY_READ, arg, sizeof(struct br_cf)); diff -urN linux-2.0.30/net/core/dev.c linux-privs/net/core/dev.c --- linux-2.0.30/net/core/dev.c Tue Apr 8 08:47:47 1997 +++ linux-privs/net/core/dev.c Mon Apr 14 20:29:53 1997 @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -1448,7 +1449,7 @@ case SIOCSIFSLAVE: case SIOCADDMULTI: case SIOCDELMULTI: - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; return dev_ifsioc(arg, cmd); @@ -1468,7 +1469,7 @@ if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { - if((IW_IS_SET(cmd)) && (!suser())) + if(IW_IS_SET(cmd) && !capable(CAP_NET_IFCONFIG)) return -EPERM; return dev_ifsioc(arg, cmd); } diff -urN linux-2.0.30/net/core/sock.c linux-privs/net/core/sock.c --- linux-2.0.30/net/core/sock.c Tue Oct 29 17:42:42 1996 +++ linux-privs/net/core/sock.c Mon Apr 14 20:29:53 1997 @@ -89,6 +89,7 @@ #include #include #include +#include #include #include #include @@ -155,7 +156,7 @@ switch(optname) { case SO_DEBUG: - if(val && !suser()) + if(val && !capable(CAP_NET_DEBUG)) return(-EPERM); sk->debug=valbool; return 0; @@ -166,9 +167,13 @@ case SO_ERROR: return(-ENOPROTOOPT); case SO_DONTROUTE: + if (!capable(CAP_NET_ROUTE)) + return(-EPERM); sk->localroute=valbool; return 0; case SO_BROADCAST: + if (!capable(CAP_NET_BROADCAST)) + return(-EPERM); sk->broadcast=valbool; return 0; case SO_SNDBUF: diff -urN linux-2.0.30/net/ipv4/af_inet.c linux-privs/net/ipv4/af_inet.c --- linux-2.0.30/net/ipv4/af_inet.c Tue Apr 8 08:47:47 1997 +++ linux-privs/net/ipv4/af_inet.c Mon Apr 14 20:29:53 1997 @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -279,7 +280,8 @@ * way to make sure that you can't send a sigurg to * another process. */ - if (!suser() && current->pgrp != -arg && + if (!capable(CAP_KILL) && + current->pgrp != -arg && current->pid != arg) return(-EPERM); sk->proc = arg; return(0); @@ -435,7 +437,7 @@ sk->no_check = UDP_NO_CHECK; prot=&udp_prot; } else if(sock->type == SOCK_RAW || sock->type == SOCK_PACKET) { - if (!suser()) + if (!capable(CAP_NET_RAW)) goto free_and_badperm; if (!protocol) goto free_and_noproto; @@ -620,7 +622,7 @@ #endif if (snum == 0) snum = sk->prot->good_socknum(); - if (snum < PROT_SOCK && !suser()) + if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return(-EACCES); chk_addr_ret = ip_chk_addr(addr->sin_addr.s_addr); @@ -628,7 +630,7 @@ chk_addr_ret != IS_MULTICAST && chk_addr_ret != IS_BROADCAST) { #ifdef CONFIG_IP_TRANSPARENT_PROXY /* Superuser may bind to any address to allow transparent proxying. */ - if(!suser()) + if(!capable(CAP_NET_FIREWALL)) #endif return(-EADDRNOTAVAIL); /* Source address MUST be ours! */ } @@ -944,7 +946,9 @@ return err; pid = get_user((int *) arg); /* see inet_fcntl */ - if (current->pid != pid && current->pgrp != -pid && !suser()) + if (current->pid != pid && + current->pgrp != -pid && + !capable(CAP_KILL)) return -EPERM; sk->proc = pid; return(0); diff -urN linux-2.0.30/net/ipv4/arp.c linux-privs/net/ipv4/arp.c --- linux-2.0.30/net/ipv4/arp.c Tue Apr 8 08:47:47 1997 +++ linux-privs/net/ipv4/arp.c Mon Apr 14 20:29:53 1997 @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include @@ -2229,7 +2230,7 @@ { case SIOCDARP: case SIOCSARP: - if (!suser()) + if (!capable(CAP_NET_ROUTE)) return -EPERM; case SIOCGARP: err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); @@ -2239,7 +2240,7 @@ break; case OLD_SIOCDARP: case OLD_SIOCSARP: - if (!suser()) + if (!capable(CAP_NET_ROUTE)) return -EPERM; case OLD_SIOCGARP: err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq_old)); diff -urN linux-2.0.30/net/ipv4/ip_sockglue.c linux-privs/net/ipv4/ip_sockglue.c --- linux-2.0.30/net/ipv4/ip_sockglue.c Tue Apr 8 08:47:47 1997 +++ linux-privs/net/ipv4/ip_sockglue.c Mon Apr 14 20:29:53 1997 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -181,7 +182,8 @@ case IP_TOS: /* This sets both TOS and Precedence */ if (val & ~0xfe) /* Reject setting of unused bits */ return -EINVAL; - if ((val>>5) > 4 && !suser()) /* Only root can set Prec>4 */ + if ((val>>5) > 4 && !capable(CAP_NET_IFCONFIG)) + /* Only root can set Prec>4 */ return -EPERM; sk->ip_tos=val; switch (val & 0x1E) { @@ -395,7 +397,7 @@ case IP_FW_POLICY_OUT: case IP_FW_POLICY_FWD: case IP_FW_MASQ_TIMEOUTS: - if(!suser()) + if(!capable(CAP_NET_FIREWALL)) return -EPERM; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; @@ -411,7 +413,7 @@ case IP_AUTOFW_ADD: case IP_AUTOFW_DEL: case IP_AUTOFW_FLUSH: - if(!suser()) + if(!capable(CAP_NET_FIREWALL)) return -EPERM; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; @@ -429,7 +431,7 @@ case IP_ACCT_DELETE: case IP_ACCT_FLUSH: case IP_ACCT_ZERO: - if(!suser()) + if(!capable(CAP_SYS_ACCOUNT)) return -EPERM; if(optlen>sizeof(tmp_fw) || optlen<1) return -EINVAL; diff -urN linux-2.0.30/net/ipv4/rarp.c linux-privs/net/ipv4/rarp.c --- linux-2.0.30/net/ipv4/rarp.c Tue Oct 29 17:42:42 1996 +++ linux-privs/net/ipv4/rarp.c Mon Apr 14 20:29:53 1997 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -475,7 +476,7 @@ switch(cmd) { case SIOCDRARP: - if (!suser()) + if (!capable(CAP_NET_ROUTE)) return -EPERM; err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); if(err) @@ -493,7 +494,7 @@ return err; return rarp_req_get((struct arpreq *)arg); case SIOCSRARP: - if (!suser()) + if (!capable(CAP_NET_ROUTE)) return -EPERM; err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq)); if(err) diff -urN linux-2.0.30/net/ipv4/raw.c linux-privs/net/ipv4/raw.c --- linux-2.0.30/net/ipv4/raw.c Tue Apr 8 08:47:47 1997 +++ linux-privs/net/ipv4/raw.c Mon Apr 14 20:29:53 1997 @@ -228,7 +228,7 @@ chk_addr_ret != IS_MULTICAST && chk_addr_ret != IS_BROADCAST) { #ifdef CONFIG_IP_TRANSPARENT_PROXY /* Superuser may bind to any address to allow transparent proxying. */ - if(!suser()) + if(!capable(CAP_NET_FIREWALL)) #endif return -EADDRNOTAVAIL; } diff -urN linux-2.0.30/net/ipv4/route.c linux-privs/net/ipv4/route.c --- linux-2.0.30/net/ipv4/route.c Tue Apr 8 08:47:47 1997 +++ linux-privs/net/ipv4/route.c Mon Apr 14 20:29:53 1997 @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -1697,7 +1698,7 @@ { case SIOCADDRT: /* Add a route */ case SIOCDELRT: /* Delete a route */ - if (!suser()) + if (!capable(CAP_NET_ROUTE)) return -EPERM; err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry)); if (err) diff -urN linux-2.0.30/net/ipv4/udp.c linux-privs/net/ipv4/udp.c --- linux-2.0.30/net/ipv4/udp.c Tue Apr 8 08:47:47 1997 +++ linux-privs/net/ipv4/udp.c Mon Apr 14 20:29:54 1997 @@ -90,6 +90,7 @@ #include #include #include +#include #include #include #include @@ -573,7 +574,7 @@ struct sockaddr_in *sinfrom = (struct sockaddr_in *) sin->sin_zero; - if (!suser()) + if (!capable(CAP_NET_FIREWALL)) return(-EPERM); if (sinfrom->sin_family && sinfrom->sin_family != AF_INET) return(-EINVAL); diff -urN linux-2.0.30/net/ipx/af_ipx.c linux-privs/net/ipx/af_ipx.c --- linux-2.0.30/net/ipx/af_ipx.c Tue Nov 26 23:44:21 1996 +++ linux-privs/net/ipx/af_ipx.c Mon Apr 14 20:29:54 1997 @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -1809,7 +1810,8 @@ return -EINVAL; } - if(ntohs(addr->sipx_port)sipx_port)protinfo.af_ipx.port=addr->sipx_port; @@ -2225,13 +2227,13 @@ } case SIOCADDRT: case SIOCDELRT: - if(!suser()) + if(!capable(CAP_NET_ROUTE)) return -EPERM; return(ipxrtr_ioctl(cmd,(void *)arg)); case SIOCSIFADDR: case SIOCAIPXITFCRT: case SIOCAIPXPRISLT: - if(!suser()) + if(!capable(CAP_NET_IFCONFIG)) return -EPERM; case SIOCGIFADDR: return(ipxitf_ioctl(cmd,(void *)arg)); diff -urN linux-2.0.30/net/netrom/af_netrom.c linux-privs/net/netrom/af_netrom.c --- linux-2.0.30/net/netrom/af_netrom.c Sat Aug 10 00:03:16 1996 +++ linux-privs/net/netrom/af_netrom.c Mon Apr 14 20:29:54 1997 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -740,7 +741,7 @@ * Only the super user can set an arbitrary user callsign. */ if (addr->fsa_ax25.sax25_ndigis == 1) { - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; sk->nr->user_addr = addr->fsa_digipeater[0]; sk->nr->source_addr = addr->fsa_ax25.sax25_call; @@ -748,7 +749,8 @@ source = &addr->fsa_ax25.sax25_call; if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !suser()) + if (ax25_uid_policy && + !capable(CAP_NET_SETID)) return -EPERM; user = source; } @@ -804,7 +806,8 @@ source = (ax25_address *)dev->dev_addr; if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !suser()) + if (ax25_uid_policy && + !capable(CAP_NET_SETID)) return -EPERM; user = source; } @@ -1280,7 +1283,7 @@ case SIOCDELRT: case SIOCNRDECOBS: case SIOCNRRTCTL: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_ROUTE)) return -EPERM; return nr_rt_ioctl(cmd, (void *)arg); case SIOCNRGETPARMS: { @@ -1295,7 +1298,7 @@ case SIOCNRSETPARMS: { struct nr_parms_struct nr_parms; - if (!suser()) return -EPERM; + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(struct nr_parms_struct))) != 0) return err; memcpy_fromfs(&nr_parms, (void *)arg, sizeof(struct nr_parms_struct)); @@ -1304,7 +1307,7 @@ } case SIOCNRCTLCON: - if (!suser()) return -EPERM; + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; return nr_ctl_ioctl(cmd, (void *)arg); default: diff -urN linux-2.0.30/scripts/captest.c linux-privs/scripts/captest.c --- linux-2.0.30/scripts/captest.c Wed Dec 31 16:00:00 1969 +++ linux-privs/scripts/captest.c Wed Apr 16 22:27:31 1997 @@ -0,0 +1,280 @@ +/* + * scripts/captest.c -- test program for POSIX.6 capabilities + * + * Copyright (C) 1997 Andrew Main + * Redistributable under the GPL + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +typedef struct __cap_s cap_set; + +/* The new system calls. Obviously this is not the POSIX interface, * + * but it's the only one we've got at the moment. (And I don't * + * believe some of the POSIX prototypes we've seen.) */ + +/* Firstly, we have process capability setting: processes may only + read/set their own capabilities */ + +_syscall4(int, _setproccap, + size_t, usize, + cap_set const *, iset, + cap_set const *, pset, + cap_set const *, eset) + +_syscall4(int, _getproccap, + size_t, usize, + cap_set *, iset, + cap_set *, pset, + cap_set *, eset) + +/* Secondly, we have the file capabilitiy setting */ + +_syscall5(int, _setfilecap, + char const *, filename, + size_t, usize, + cap_set const *, iset, + cap_set const *, pset, + cap_set const *, eset) + +_syscall5(int, _getfilecap, + char const *, filename, + size_t, usize, + cap_set *, iset, + cap_set *, pset, + cap_set *, eset) + +_syscall5(int, _fsetfilecap, + int, fd, + size_t, usize, + cap_set const *, iset, + cap_set const *, pset, + cap_set const *, eset) + +_syscall5(int, _fgetfilecap, + int, fd, + size_t, usize, + cap_set *, iset, + cap_set *, pset, + cap_set *, eset) + +void Usage(void) +{ + fprintf(stderr, + "Usage:\n" + "\n" + "captest [ command ... ]\n" + "\n" + "Commands that can be given are:\n" + "\n" + "-S size for non-default range of caps\n" + "-ps [ipe]=cap... _setproccap()\n" + "-pg [ipe] _getproccap()\n" + "-fs filename [ipe]=caps.. _setfilecap()\n" + "-fg filename [ipe] _getfilecap()\n" + "-Fs fd [ipe]=caps.. _fsetfilecap()\n" + "-Fg fd [ipe] _fgetfilecap()\n" + "\n" + "capability sets look like: i=1.2.3,p=4.7,e=\n"); + exit(2); +} + +/* + * prototypes for this file.. + */ + +void getcaps(char *str, char *abbrevs, + cap_set **I, + cap_set **P, + cap_set **E) +{ + int n; + static cap_set i,p,e; + + *I = *P = *E = NULL; + memset(&i, 0, sizeof(i)); + memset(&p, 0, sizeof(p)); + memset(&e, 0, sizeof(e)); + + while(*str) { + char *c = strchr(abbrevs, *str++); + cap_set *x = NULL; + + if (!c) + Usage(); + switch (c - abbrevs) { + case 0: x = *I = &i; break; + case 1: x = *P = &p; break; + case 2: x = *E = &e; break; + } + if (*str == '=') + do { + if (!isdigit(*++str)) + break; + n = strtol(str, &str, 0); + if (n >= 0 && n < __CAP_BITS) + (*x)._cap_raise(n); + } while (*str == '.'); + if (*str == ',') + str++; + } +} + +void getcapsets(char *str, char *abbrevs, + cap_set **I, + cap_set **P, + cap_set **E) +{ + static cap_set i,p,e; + + memset(&i, 0xaa, sizeof(i)); + memset(&p, 0xaa, sizeof(p)); + memset(&e, 0xaa, sizeof(e)); + *I = *P = *E = NULL; + + while (*str) { + char *c = strchr(abbrevs, *str++); + if (!c) + return; + switch (c - abbrevs) { + case 0: *I = &i; break; + case 1: *P = &p; break; + case 2: *E = &e; break; + } + } +} + +void showcap(char abbrev, cap_set *c) +{ + int n; + printf(" %c:", abbrev); + if (!c) { + printf(" NULL\n"); + return; + } + for (n = 0; n < __CAP_BLKS; n++) + printf(" %08x", c->_blk[n]); + putchar('\n'); +} + +void showcaps(char *str, char *abbrevs, + cap_set *i, + cap_set *p, + cap_set *h) +{ + printf("%s syscall:\n", str); + if (*abbrevs) + showcap(*abbrevs++, i); + if (*abbrevs) + showcap(*abbrevs++, p); + if (*abbrevs) + showcap(*abbrevs++, h); +} + +void sysc(char const *name, int ret) +{ + int e = errno; + printf("syscall %s returned %d", name, ret); + if(ret == -1) + printf(" (errno = %d, %s)", e, strerror(e)); + putchar('\n'); +} + +int main(int argc, char **argv) +{ + size_t usize = sizeof(cap_set); + for (argv++; *argv; argv++) { + cap_set *e, *i, *p; + + putchar('\n'); + errno = 0; + + if (!strcmp(*argv, "-S")) { + + if (!argv[1]) goto bad; + usize = strtoul(*++argv, NULL, 0); + printf("Setting usize to %u (0x%x)\n", usize, usize); + + } else if (!strcmp(*argv, "-ps")) { + + if (!argv[1]) goto bad; + printf("Setting process capabilities\n"); + getcaps(*++argv, "ipe", &i, &p, &e); + showcaps("before", "ipe", i, p, e); + sysc("_setproccap", _setproccap(usize, i, p, e)); + showcaps("after", "ipe", i, p, e); + + } else if (!strcmp(*argv, "-pg")) { + + if (!argv[1]) goto bad; + printf("Getting process capabilities\n"); + getcapsets(*++argv, "ipe", &i, &p, &e); + showcaps("before", "ipe", i, p, e); + sysc("_getproccap", _getproccap(usize, i, p, e)); + showcaps("after", "ipe", i, p, e); + + } else if (!strcmp(*argv, "-fs")) { + char *filename; + if (!argv[1] || !argv[2]) goto bad; + filename = *++argv; + printf("Setting file capabilities on %s\n", filename); + + getcaps(*++argv, "ipe", &i, &p, &e); + showcaps("before", "ipe", i, p, e); + sysc("_setfilecap", + _setfilecap(filename, usize, i, p, e)); + showcaps("after", "ipe", i,p,e); + + } else if (!strcmp(*argv, "-fg")) { + char *filename; + if (!argv[1] || !argv[2]) goto bad; + filename = *++argv; + printf("Getting file capabilities on %s\n", filename); + + getcapsets(*++argv, "ipe", &i, &p, &e); + showcaps("before", "ipe", i, p, e); + sysc("_getfilecap", + _getfilecap(filename, usize, i, p, e)); + showcaps("after", "ipe", i, p, e); + + } else if (!strcmp(*argv, "-Fs")) { + int fd; + if (!argv[1] || !argv[2]) goto bad; + fd = strtol(*++argv, NULL, 0); + printf("Setting file capabilities on fd %d\n", fd); + + getcaps(*++argv, "ipe", &i, &p, &e); + showcaps("before", "ipe", i, p, e); + sysc("_fsetfilecap", + _fsetfilecap(fd, usize, i, p, e)); + showcaps("after", "ipe", i, p, e); + + } else if (!strcmp(*argv, "-Fg")) { + int fd; + if (!argv[1] || !argv[2]) goto bad; + fd = strtol(*++argv, NULL, 0); + printf("Getting file capabilities on fd %d\n", fd); + + getcapsets(*++argv, "ipe", &i, &p, &e); + showcaps("before", "ipe", i, p, e); + sysc("_fgetfilecap", + _fgetfilecap(fd, usize, i, p, e)); + showcaps("after", "ipe", i, p, e); + + } else { + bad: + printf("unrecognised argument: %s\n", *argv); + Usage(); + } + fflush(stdout); + } + exit(0); +}