diff -urN linux-2.0.31pre9/Documentation/00-INDEX linux-2.0.31pre9-privs/Documentation/00-INDEX --- linux-2.0.31pre9/Documentation/00-INDEX Thu Jun 6 04:57:43 1996 +++ linux-2.0.31pre9-privs/Documentation/00-INDEX Sun Sep 7 10:28:12 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.31pre9/Documentation/Configure.help linux-2.0.31pre9-privs/Documentation/Configure.help --- linux-2.0.31pre9/Documentation/Configure.help Sun Sep 7 16:03:46 1997 +++ linux-2.0.31pre9-privs/Documentation/Configure.help Sun Sep 7 10:28:12 1997 @@ -720,6 +720,35 @@ later load the module when you install the JDK or find an interesting Java program that you can't live without. +Non-executable user stack area (EXPERIMENTAL) +CONFIG_STACKEXEC + Most buffer overflow exploits are based on overwriting a function's + return address on the stack to point to some arbitrary code, which is + also put onto the stack. If the stack area is non-executable, buffer + overflow vulnerabilities become harder to exploit. However, a few + programs depend on the stack being executable, and might stop working + unless you also enable GCC trampolines autodetection below, or enable + the stack area execution permission for every such program separately + using chstk.c. If you don't know what all this is about, or don't care + about security that much, say N. + +Autodetect GCC trampolines +CONFIG_STACKEXEC_AUTOENABLE + GCC generates trampolines on the stack to correctly pass control to + nested functions when calling from outside. This requires the stack + being executable. When this option is enabled, programs containing + trampolines will automatically get their stack area executable when + a trampoline is found. However, in some cases this autodetection can + be fooled in a buffer overflow exploit, so it is more secure to + disable this option and use chstk.c to enable the stack area execution + permission for every such program separately. If you're too lazy, + answer Y. + +Log buffer overflow exploit attempts +CONFIG_STACKEXEC_LOG + This option enables logging of buffer overflow exploit attempts. No + more than one attempt per minute is logged, so this is safe. Say Y. + Processor type CONFIG_M386 This is the processor type of your CPU. It is used for optimizing @@ -794,6 +823,22 @@ 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. + +Default security level +DEFAULT_SECURE_LEVEL + This is a potentially dangerous number to change. The default is + zero, which affords the least security to your system. The number + is actually a union of independent flag values (see ) + that affect the way in which the system gives access to priviledged + users. Unless you know what you are doing, it is probably safest to + leave this number alone -- a bad value could make a kernel unusable. + ARP daemon support (EXPERIMENTAL) CONFIG_ARPD Normally, the kernel maintains an internal cache which maps IP @@ -2952,6 +2997,27 @@ writing none of these are available. So it's safest to say N here unless you really know that you need this feature. +Symlink security fix (EXPERIMENTAL) +CONFIG_SYMLINK_FIX + A very common class of security hole on UNIX-like systems involves + a malicious user creating a symbolic link in /tmp pointing at + another user's file. When the victim then writes to that file they + inadvertently write to the wrong file. Enabling this option fixes + this class of hole by preventing a process from following a link + which is in a +t directory unless they own the link. However, this + fix does not affect links owned by root, since these could only be + created by someone having root access already. To prevent someone + from using a hard link instead, this fix does not allow non-root + users to create hard links in a +t directory to files they don't + own. Note that this fix might break things. Only say Y if security + is more important. + +Log symlink exploit attempts +CONFIG_SYMLINK_LOG + This option enables logging of symlink (and hard link) exploit + attempts. No more than one attempt per minute is logged, so this is + safe. Say Y. + Minix fs support CONFIG_MINIX_FS Minix is a simple operating system used in many classes about @@ -3210,6 +3276,17 @@ whenever you want), say M here and read Documentation/modules.txt. If you haven't heard about all of this before, it's safe to say N. + +Kernel automounter support (experimental) +CONFIG_AUTOFS_FS + The automounter is a tool to automatically mount remote filesystems + on demand. This implementation is partially kernel-based to reduce + overhead in the already-mounted case; this is unlike the BSD + automounter (amd), which is only in user space. To use the + automounter you also need the user-space tools from + ftp.kernel.org:/pub/linux/daemons/autofs. If you are not a part of + a fairly large, distributed network, you probably do not need an + automounter, and can say N here. BSD UFS filesystem support (read only) CONFIG_UFS_FS diff -urN linux-2.0.31pre9/Documentation/POSIX.6_cap.txt linux-2.0.31pre9-privs/Documentation/POSIX.6_cap.txt --- linux-2.0.31pre9/Documentation/POSIX.6_cap.txt Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/Documentation/POSIX.6_cap.txt Sun Sep 7 10:28:12 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.31pre9/MAINTAINERS linux-2.0.31pre9-privs/MAINTAINERS --- linux-2.0.31pre9/MAINTAINERS Sun Sep 7 16:03:47 1997 +++ linux-2.0.31pre9-privs/MAINTAINERS Sun Sep 7 10:26:39 1997 @@ -406,6 +406,18 @@ M: jam@acm.org S: Maintained +KERNEL AUTOMOUNTER (AUTOFS) +P: H. Peter Anvin +M: hpa@zytor.com +L: autofs@linux.kernel.org +S: Maintained + +DEVICE NUMBER REGISTRY +P: H. Peter Anvin +M: hpa@zytor.com +L: linux-kernel@vger.rutgers.edu +S: Maintained + REST: P: Linus Torvalds S: Buried alive in email diff -urN linux-2.0.31pre9/arch/alpha/config.in linux-2.0.31pre9-privs/arch/alpha/config.in --- linux-2.0.31pre9/arch/alpha/config.in Mon Aug 5 00:13:50 1996 +++ linux-2.0.31pre9-privs/arch/alpha/config.in Sun Sep 7 10:28:12 1997 @@ -94,6 +94,12 @@ 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 +int 'Default security level - see help' DEFAULT_SECURE_LEVEL 0 + endmenu source drivers/block/Config.in diff -urN linux-2.0.31pre9/arch/alpha/defconfig linux-2.0.31pre9-privs/arch/alpha/defconfig --- linux-2.0.31pre9/arch/alpha/defconfig Sun Sep 7 16:03:47 1997 +++ linux-2.0.31pre9-privs/arch/alpha/defconfig Sun Sep 7 10:28:12 1997 @@ -42,6 +42,8 @@ CONFIG_SYSVIPC=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y +# CONFIG_POSIX6_CAP is not set +DEFAULT_SECURE_LEVEL=0 # # Floppy, IDE, and other block devices @@ -180,6 +182,8 @@ # Filesystems # # CONFIG_QUOTA is not set +# CONFIG_SYMLINK_FIX is not set +CONFIG_SYMLINK_LOG=y # CONFIG_MINIX_FS is not set # CONFIG_EXT_FS is not set CONFIG_EXT2_FS=y @@ -196,6 +200,7 @@ # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_AUTOFS_FS is not set # # Character devices diff -urN linux-2.0.31pre9/arch/alpha/kernel/entry.S linux-2.0.31pre9-privs/arch/alpha/kernel/entry.S --- linux-2.0.31pre9/arch/alpha/kernel/entry.S Thu Nov 21 03:41:46 1996 +++ linux-2.0.31pre9-privs/arch/alpha/kernel/entry.S Sun Sep 7 10:28:12 1997 @@ -10,7 +10,7 @@ #define rti .long PAL_rti #define SIGCHLD 20 -#define NR_SYSCALLS 350 +#define NR_SYSCALLS 360 #define osf_vfork sys_fork /* @@ -758,4 +758,6 @@ .quad sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler, sys_sched_yield .quad sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, do_entSys /* sys_afs_syscall */, sys_newuname .quad sys_nanosleep, sys_mremap, do_entSys, do_entSys, do_entSys - .quad sys_pciconfig_read, sys_pciconfig_write, do_entSys, do_entSys, do_entSys + .quad sys_pciconfig_read, sys_pciconfig_write, do_entSys /* sys_query_module */, sys_setproccap, sys_getproccap +/*350*/ .quad sys_setfilecap, sys_getfilecap, sys_fsetfilecap, sys_fgetfilecap, do_entSys + .quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys diff -urN linux-2.0.31pre9/arch/alpha/kernel/ptrace.c linux-2.0.31pre9-privs/arch/alpha/kernel/ptrace.c --- linux-2.0.31pre9/arch/alpha/kernel/ptrace.c Sun Sep 7 16:03:47 1997 +++ linux-2.0.31pre9-privs/arch/alpha/kernel/ptrace.c Sun Sep 7 10:28:12 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.31pre9/arch/alpha/kernel/signal.c linux-2.0.31pre9-privs/arch/alpha/kernel/signal.c --- linux-2.0.31pre9/arch/alpha/kernel/signal.c Sun Sep 7 16:03:47 1997 +++ linux-2.0.31pre9-privs/arch/alpha/kernel/signal.c Sun Sep 7 10:28:12 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.31pre9/arch/i386/config.in linux-2.0.31pre9-privs/arch/i386/config.in --- linux-2.0.31pre9/arch/i386/config.in Sun May 12 21:17:23 1996 +++ linux-2.0.31pre9-privs/arch/i386/config.in Sun Sep 7 10:28:12 1997 @@ -35,7 +35,14 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA + bool 'Non-executable user stack area (EXPERIMENTAL)' CONFIG_STACKEXEC + if [ "$CONFIG_STACKEXEC" = "y" ]; then + bool ' Autodetect GCC trampolines' CONFIG_STACKEXEC_AUTOENABLE + bool ' Log buffer overflow exploit attempts' CONFIG_STACKEXEC_LOG + fi + bool 'POSIX.6 (aka. .1e) capability system (experimental)' CONFIG_POSIX6_CAP fi +int 'Default security level - see help' DEFAULT_SECURE_LEVEL 0 bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF choice 'Processor type' \ @@ -43,6 +50,7 @@ 486 CONFIG_M486 \ Pentium CONFIG_M586 \ PPro CONFIG_M686" Pentium + endmenu source drivers/block/Config.in diff -urN linux-2.0.31pre9/arch/i386/defconfig linux-2.0.31pre9-privs/arch/i386/defconfig --- linux-2.0.31pre9/arch/i386/defconfig Sun Sep 7 16:03:48 1997 +++ linux-2.0.31pre9-privs/arch/i386/defconfig Sun Sep 7 10:28:12 1997 @@ -24,11 +24,16 @@ CONFIG_SYSVIPC=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y +# CONFIG_STACKEXEC is not set +CONFIG_STACKEXEC_AUTOENABLE=y +CONFIG_STACKEXEC_LOG=y CONFIG_KERNEL_ELF=y # CONFIG_M386 is not set # CONFIG_M486 is not set CONFIG_M586=y # CONFIG_M686 is not set +# CONFIG_POSIX6_CAP is not set +DEFAULT_SECURE_LEVEL=0 # # Floppy, IDE, and other block devices @@ -134,6 +139,8 @@ # Filesystems # # CONFIG_QUOTA is not set +# CONFIG_SYMLINK_FIX is not set +CONFIG_SYMLINK_LOG=y CONFIG_MINIX_FS=y # CONFIG_EXT_FS is not set CONFIG_EXT2_FS=y @@ -150,6 +157,7 @@ # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set +# CONFIG_AUTOFS_FS is not set # # Character devices diff -urN linux-2.0.31pre9/arch/i386/kernel/entry.S linux-2.0.31pre9-privs/arch/i386/kernel/entry.S --- linux-2.0.31pre9/arch/i386/kernel/entry.S Sun Sep 7 16:03:48 1997 +++ linux-2.0.31pre9-privs/arch/i386/kernel/entry.S Sun Sep 7 10:28:12 1997 @@ -698,6 +698,16 @@ .long SYMBOL_NAME(sys_sched_rr_get_interval) .long SYMBOL_NAME(sys_nanosleep) .long SYMBOL_NAME(sys_mremap) - .long 0,0 + .long 0 /* sys_setresuid */ + .long 0 /* sys_getresuid */ /* 165 */ .long SYMBOL_NAME(sys_vm86) - .space (NR_syscalls-166)*4 + .long 0 /* sys_query_module */ + .long 0 /* sys_poll */ + .long 0 /* sys_nfsservctl */ + .long SYMBOL_NAME(sys_setproccap) /* 170 */ + .long SYMBOL_NAME(sys_getproccap) + .long SYMBOL_NAME(sys_setfilecap) + .long SYMBOL_NAME(sys_getfilecap) + .long SYMBOL_NAME(sys_fsetfilecap) + .long SYMBOL_NAME(sys_fgetfilecap) /* 175 */ + .space (NR_syscalls-175)*4 diff -urN linux-2.0.31pre9/arch/i386/kernel/head.S linux-2.0.31pre9-privs/arch/i386/kernel/head.S --- linux-2.0.31pre9/arch/i386/kernel/head.S Mon Mar 18 03:15:00 1996 +++ linux-2.0.31pre9-privs/arch/i386/kernel/head.S Sun Sep 7 10:28:12 1997 @@ -400,10 +400,17 @@ .quad 0x0000000000000000 /* not used */ .quad 0xc0c39a000000ffff /* 0x10 kernel 1GB code at 0xC0000000 */ .quad 0xc0c392000000ffff /* 0x18 kernel 1GB data at 0xC0000000 */ +#ifdef CONFIG_STACKEXEC + .quad 0x00cafa000000ffff /* 0x23 user 2.75GB code at 0 */ + .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0 */ + .quad 0x00cbda000000ffff /* 0x32 user 3GB code at 0, DPL=2 */ + .quad 0x00cbd2000000ffff /* 0x3a user 3GB stack at 0, DPL=2 */ +#else .quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 */ .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 */ .quad 0x0000000000000000 /* not used */ .quad 0x0000000000000000 /* not used */ +#endif .fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */ #ifdef CONFIG_APM .quad 0x00c09a0000000000 /* APM CS code */ diff -urN linux-2.0.31pre9/arch/i386/kernel/ioport.c linux-2.0.31pre9-privs/arch/i386/kernel/ioport.c --- linux-2.0.31pre9/arch/i386/kernel/ioport.c Wed Jan 11 11:10:53 1995 +++ linux-2.0.31pre9-privs/arch/i386/kernel/ioport.c Sun Sep 7 10:28:12 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.31pre9/arch/i386/kernel/ptrace.c linux-2.0.31pre9-privs/arch/i386/kernel/ptrace.c --- linux-2.0.31pre9/arch/i386/kernel/ptrace.c Sun Sep 7 16:03:48 1997 +++ linux-2.0.31pre9-privs/arch/i386/kernel/ptrace.c Sun Sep 7 10:28:12 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) @@ -413,7 +415,7 @@ addr == FS || addr == GS || addr == CS || addr == SS) { data &= 0xffff; - if (data && (data & 3) != 3) + if (data && (data & 3) < 2) return -EIO; } if (addr == EFL) { /* flags. */ @@ -423,6 +425,10 @@ /* Do not allow the user to set the debug register for kernel address space */ if(addr < 17){ + if (addr == EIP && (data & 0xF0000000) == 0xB0000000) + if (put_stack_long(child, CS*sizeof(long)-MAGICNUMBER, USER_HUGE_CS) || + put_stack_long(child, SS*sizeof(long)-MAGICNUMBER, USER_HUGE_SS)) + return -EIO; if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data)) return -EIO; return 0; diff -urN linux-2.0.31pre9/arch/i386/kernel/signal.c linux-2.0.31pre9-privs/arch/i386/kernel/signal.c --- linux-2.0.31pre9/arch/i386/kernel/signal.c Sun Sep 7 16:03:48 1997 +++ linux-2.0.31pre9-privs/arch/i386/kernel/signal.c Sun Sep 7 10:28:12 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; @@ -83,18 +87,22 @@ #define COPY_SEG(x) \ if ( (context.x & 0xfffc) /* not a NULL selectors */ \ && (context.x & 0x4) != 0x4 /* not a LDT selector */ \ - && (context.x & 3) != 3 /* not a RPL3 GDT selector */ \ + && (context.x & 3) < 2 /* not a RPL3 or RPL2 GDT selector */ \ ) goto badframe; COPY(x); #define COPY_SEG_STRICT(x) \ -if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x); +if (!(context.x & 0xfffc) || (context.x & 3) < 2) 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); @@ -167,16 +175,20 @@ unsigned long * frame; frame = (unsigned long *) regs->esp; - if (regs->ss != USER_DS && sa->sa_restorer) + if (regs->ss != USER_DS && regs->ss != USER_HUGE_SS && sa->sa_restorer) frame = (unsigned long *) sa->sa_restorer; frame -= 64; if (verify_area(VERIFY_WRITE,frame,64*4)) do_exit(SIGSEGV); /* set up the "normal" stack seen by the signal handler (iBCS2) */ +#ifdef CONFIG_STACKEXEC + put_user((unsigned long)MAGIC_SIGRETURN, frame); +#else #define __CODE ((unsigned long)(frame+24)) #define CODE(x) ((unsigned long *) ((x)+__CODE)) put_user(__CODE,frame); +#endif if (current->exec_domain && current->exec_domain->signal_invmap) put_user(current->exec_domain->signal_invmap[signr], frame+1); else @@ -204,19 +216,17 @@ /* non-iBCS2 extensions.. */ put_user(oldmask, frame+22); put_user(current->tss.cr2, frame+23); +#ifndef CONFIG_STACKEXEC /* set up the return code... */ put_user(0x0000b858, CODE(0)); /* popl %eax ; movl $,%eax */ put_user(0x80cd0000, CODE(4)); /* int $0x80 */ put_user(__NR_sigreturn, CODE(2)); #undef __CODE #undef CODE +#endif /* Set up registers for signal handler */ - regs->esp = (unsigned long) frame; - regs->eip = (unsigned long) sa->sa_handler; - regs->cs = USER_CS; regs->ss = USER_DS; - regs->ds = USER_DS; regs->es = USER_DS; - regs->gs = USER_DS; regs->fs = USER_DS; + start_thread(regs, (unsigned long)sa->sa_handler, (unsigned long)frame); regs->eflags &= ~TF_MASK; } @@ -251,8 +261,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.31pre9/arch/i386/kernel/traps.c linux-2.0.31pre9-privs/arch/i386/kernel/traps.c --- linux-2.0.31pre9/arch/i386/kernel/traps.c Sun Sep 7 16:03:48 1997 +++ linux-2.0.31pre9-privs/arch/i386/kernel/traps.c Sun Sep 7 10:28:12 1997 @@ -117,7 +117,7 @@ esp = (unsigned long) ®s->esp; ss = KERNEL_DS; - if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3) + if ((regs->eflags & VM_MASK) || (3 & regs->cs) >= 2) return; if (regs->cs & 3) { esp = regs->esp; @@ -193,11 +193,82 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { +#ifdef CONFIG_STACKEXEC + unsigned long retaddr; +#endif + if (regs->eflags & VM_MASK) { handle_vm86_fault((struct vm86_regs *) regs, error_code); return; } + +#ifdef CONFIG_STACKEXEC +/* Check if it was return from a signal handler */ + if (regs->cs == USER_CS || regs->cs == USER_HUGE_CS) + if (get_seg_byte(USER_DS, (char *)regs->eip) == 0xC3) + if (!verify_area(VERIFY_READ, (void *)regs->esp, 4)) + if ((retaddr = get_seg_long(USER_DS, (char *)regs->esp)) == + MAGIC_SIGRETURN) { +/* + * Call sys_sigreturn() to restore the context. It would definitely be better + * to convert sys_sigreturn() into an inline function accepting a pointer to + * pt_regs, making this faster... + */ + regs->esp += 8; + __asm__("movl %3,%%esi;" + "subl %1,%%esp;" + "movl %2,%%ecx;" + "movl %%esp,%%edi;" + "cld; rep; movsl;" + "call sys_sigreturn;" + "leal %3,%%edi;" + "addl %1,%%edi;" + "movl %%esp,%%esi;" + "movl (%%edi),%%edi;" + "movl %2,%%ecx;" + "cld; rep; movsl;" + "movl %%esi,%%esp" + : +/* %eax is returned separately */ + "=a" (regs->eax) + : + "i" (sizeof(*regs)), + "i" (sizeof(*regs) >> 2), + "m" (regs) + : + "cx", "dx", "si", "di", "cc", "memory"); + return; + } + +#ifdef CONFIG_STACKEXEC_LOG +/* + * Check if we're returning to the stack area, which is only likely to happen + * when attempting to exploit a buffer overflow. + */ + else if (regs->cs == USER_CS && + (retaddr & 0xF0000000) == 0xB0000000) + security_alert("buffer overflow"); +#endif +#endif + die_if_kernel("general protection",regs,error_code); + +#if defined(CONFIG_STACKEXEC) && defined(CONFIG_STACKEXEC_AUTOENABLE) +/* + * Switch to the original huge code segment (and allow code execution on the + * stack for this entire process), if the faulty instruction is a call %reg, + * except for call %esp. + */ + if (regs->cs == USER_CS) + if (get_seg_byte(USER_DS, (char *)regs->eip) == 0xFF && + (get_seg_byte(USER_DS, (char *)(regs->eip + 1)) & 0xD8) == 0xD0 && + get_seg_byte(USER_DS, (char *)(regs->eip + 1)) != 0xD4) { + current->flags |= PF_STACKEXEC; + regs->cs = USER_HUGE_CS; regs->ss = USER_HUGE_SS; + return; + } +#endif + current->tss.error_code = error_code; current->tss.trap_no = 13; force_sig(SIGSEGV, current); diff -urN linux-2.0.31pre9/arch/i386/kernel/vm86.c linux-2.0.31pre9-privs/arch/i386/kernel/vm86.c --- linux-2.0.31pre9/arch/i386/kernel/vm86.c Tue Feb 25 12:22:17 1997 +++ linux-2.0.31pre9-privs/arch/i386/kernel/vm86.c Sun Sep 7 10:28:13 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.31pre9/arch/i386/mm/fault.c linux-2.0.31pre9-privs/arch/i386/mm/fault.c --- linux-2.0.31pre9/arch/i386/mm/fault.c Sun Sep 7 16:03:48 1997 +++ linux-2.0.31pre9-privs/arch/i386/mm/fault.c Sun Sep 7 10:28:13 1997 @@ -44,6 +44,7 @@ unsigned long page; int write; + if ((regs->cs & 3) >= 2) error_code |= 4; /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); down(&mm->mmap_sem); diff -urN linux-2.0.31pre9/arch/m68k/config.in linux-2.0.31pre9-privs/arch/m68k/config.in --- linux-2.0.31pre9/arch/m68k/config.in Sun May 19 21:54:26 1996 +++ linux-2.0.31pre9-privs/arch/m68k/config.in Sun Sep 7 10:28:13 1997 @@ -31,6 +31,12 @@ if [ "$CONFIG_AMIGA" = "y" ]; then bool 'Amiga AutoConfig Identification' CONFIG_ZORRO fi +int 'Default security level - see help' DEFAULT_SECURE_LEVEL 0 + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'POSIX.6 (aka. .1e) capability system (experimental)' CONFIG_POSIX6_CAP +fi + endmenu # diff -urN linux-2.0.31pre9/arch/m68k/defconfig linux-2.0.31pre9-privs/arch/m68k/defconfig --- linux-2.0.31pre9/arch/m68k/defconfig Mon May 6 02:44:30 1996 +++ linux-2.0.31pre9-privs/arch/m68k/defconfig Sun Sep 7 10:28:13 1997 @@ -23,6 +23,8 @@ CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_ZORRO is not set +# CONFIG_POSIX6_CAP is not set +DEFAULT_SECURE_LEVEL=0 # # Block device driver configuration @@ -107,6 +109,8 @@ # Filesystems # # CONFIG_QUOTA is not set +# CONFIG_SYMLINK_FIX is not set +CONFIG_SYMLINK_LOG=y CONFIG_MINIX_FS=y # CONFIG_EXT_FS is not set CONFIG_EXT2_FS=y @@ -122,6 +126,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set +# CONFIG_AUTOFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_UFS_FS is not set diff -urN linux-2.0.31pre9/arch/m68k/kernel/console.c linux-2.0.31pre9-privs/arch/m68k/kernel/console.c --- linux-2.0.31pre9/arch/m68k/kernel/console.c Mon May 6 02:26:02 1996 +++ linux-2.0.31pre9-privs/arch/m68k/kernel/console.c Sun Sep 7 10:28:13 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.31pre9/arch/m68k/kernel/entry.S linux-2.0.31pre9-privs/arch/m68k/kernel/entry.S --- linux-2.0.31pre9/arch/m68k/kernel/entry.S Wed May 15 23:05:10 1996 +++ linux-2.0.31pre9-privs/arch/m68k/kernel/entry.S Sun Sep 7 10:28:13 1997 @@ -634,4 +634,16 @@ .long SYMBOL_NAME(sys_sched_rr_get_interval) .long SYMBOL_NAME(sys_nanosleep) .long SYMBOL_NAME(sys_mremap) - .space (NR_syscalls-163)*4 + .long 0 /* sys_setresuid */ + .long 0 /* sys_getresuid */ /* 165 */ + .long 0 /* sys_vm86 */ + .long 0 /* sys_query_module */ + .long 0 /* sys_poll */ + .long 0 /* sys_nfsservctl */ + .long SYMBOL_NAME(sys_setproccap) /* 170 */ + .long SYMBOL_NAME(sys_getproccap) + .long SYMBOL_NAME(sys_setfilecap) + .long SYMBOL_NAME(sys_getfilecap) + .long SYMBOL_NAME(sys_fsetfilecap) + .long SYMBOL_NAME(sys_fgetfilecap) /* 175 */ + .space (NR_syscalls-175)*4 diff -urN linux-2.0.31pre9/arch/m68k/kernel/ptrace.c linux-2.0.31pre9-privs/arch/m68k/kernel/ptrace.c --- linux-2.0.31pre9/arch/m68k/kernel/ptrace.c Sun May 19 21:54:26 1996 +++ linux-2.0.31pre9-privs/arch/m68k/kernel/ptrace.c Sun Sep 7 10:28:13 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.31pre9/arch/m68k/kernel/signal.c linux-2.0.31pre9-privs/arch/m68k/kernel/signal.c --- linux-2.0.31pre9/arch/m68k/kernel/signal.c Sun May 19 21:54:26 1996 +++ linux-2.0.31pre9-privs/arch/m68k/kernel/signal.c Sun Sep 7 10:28:13 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.31pre9/arch/m68k/kernel/sys_m68k.c linux-2.0.31pre9-privs/arch/m68k/kernel/sys_m68k.c --- linux-2.0.31pre9/arch/m68k/kernel/sys_m68k.c Wed May 15 23:05:10 1996 +++ linux-2.0.31pre9-privs/arch/m68k/kernel/sys_m68k.c Sun Sep 7 10:28:13 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.31pre9/arch/mips/config.in linux-2.0.31pre9-privs/arch/mips/config.in --- linux-2.0.31pre9/arch/mips/config.in Sat May 4 23:05:58 1996 +++ linux-2.0.31pre9-privs/arch/mips/config.in Sun Sep 7 10:28:13 1997 @@ -50,6 +50,12 @@ # 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 +int 'Default security level - see help' DEFAULT_SECURE_LEVEL 0 + endmenu mainmenu_option next_comment diff -urN linux-2.0.31pre9/arch/mips/defconfig linux-2.0.31pre9-privs/arch/mips/defconfig --- linux-2.0.31pre9/arch/mips/defconfig Wed Feb 7 19:41:50 1996 +++ linux-2.0.31pre9-privs/arch/mips/defconfig Sun Sep 7 10:28:13 1997 @@ -26,6 +26,8 @@ CONFIG_CPU_LITTLE_ENDIAN=y # CONFIG_NET is not set # CONFIG_SYSVIPC is not set +# CONFIG_POSIX6_CAP is not set +DEFAULT_SECURE_LEVEL=0 # # Loadable module support @@ -52,6 +54,8 @@ # # Filesystems # +# CONFIG_SYMLINK_FIX is not set +CONFIG_SYMLINK_LOG=y # CONFIG_MINIX_FS is not set # CONFIG_EXT_FS is not set CONFIG_EXT2_FS=y @@ -61,6 +65,7 @@ # CONFIG_ISO9660_FS is not set # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set +# CONFIG_AUTOFS_FS is not set # CONFIG_SMB_FS is not set # diff -urN linux-2.0.31pre9/arch/mips/kernel/ptrace.c linux-2.0.31pre9-privs/arch/mips/kernel/ptrace.c --- linux-2.0.31pre9/arch/mips/kernel/ptrace.c Wed Dec 13 02:39:44 1995 +++ linux-2.0.31pre9-privs/arch/mips/kernel/ptrace.c Sun Sep 7 10:28:13 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.31pre9/arch/mips/kernel/signal.c linux-2.0.31pre9-privs/arch/mips/kernel/signal.c --- linux-2.0.31pre9/arch/mips/kernel/signal.c Sun Mar 10 23:39:33 1996 +++ linux-2.0.31pre9-privs/arch/mips/kernel/signal.c Sun Sep 7 10:28:13 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.31pre9/arch/mips/kernel/syscalls.h linux-2.0.31pre9-privs/arch/mips/kernel/syscalls.h --- linux-2.0.31pre9/arch/mips/kernel/syscalls.h Wed Dec 13 02:39:44 1995 +++ linux-2.0.31pre9-privs/arch/mips/kernel/syscalls.h Sun Sep 7 10:28:13 1997 @@ -174,3 +174,9 @@ SYS(sys_munlock, 2) /* 4155 */ SYS(sys_mlockall, 1) SYS(sys_munlockall, 0) +SYS(sys_setproccap, 4) +SYS(sys_getproccap, 4) +SYS(sys_setfilecap, 5) /* 4160 */ +SYS(sys_getfilecap, 5) +SYS(sys_fsetfilecap, 5) +SYS(sys_fgetfilecap, 5) diff -urN linux-2.0.31pre9/arch/mips/kernel/sysmips.c linux-2.0.31pre9-privs/arch/mips/kernel/sysmips.c --- linux-2.0.31pre9/arch/mips/kernel/sysmips.c Wed Dec 13 02:39:44 1995 +++ linux-2.0.31pre9-privs/arch/mips/kernel/sysmips.c Sun Sep 7 10:28:13 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.31pre9/arch/ppc/config.in linux-2.0.31pre9-privs/arch/ppc/config.in --- linux-2.0.31pre9/arch/ppc/config.in Mon May 27 02:00:57 1996 +++ linux-2.0.31pre9-privs/arch/ppc/config.in Sun Sep 7 10:28:13 1997 @@ -38,6 +38,13 @@ 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 +int 'Default security level - see help' DEFAULT_SECURE_LEVEL 0 + +endmenu + source drivers/block/Config.in if [ "$CONFIG_NET" = "y" ]; then diff -urN linux-2.0.31pre9/arch/ppc/kernel/misc.S linux-2.0.31pre9-privs/arch/ppc/kernel/misc.S --- linux-2.0.31pre9/arch/ppc/kernel/misc.S Mon Jul 8 01:27:42 1996 +++ linux-2.0.31pre9-privs/arch/ppc/kernel/misc.S Sun Sep 7 10:28:13 1997 @@ -655,5 +655,12 @@ .long sys_sched_rr_get_interval .long sys_nanosleep .long sys_mremap - .space (NR_syscalls-163)*4 - + .long 0 /* sys_setresuid */ + .long 0 /* sys_getresuid */ /* 165 */ + .long sys_setproccap + .long sys_getproccap + .long sys_setfilecap + .long sys_getfilecap + .long sys_fsetfilecap /* 170 */ + .long sys_fgetfilecap + .space (NR_syscalls-171)*4 diff -urN linux-2.0.31pre9/arch/ppc/kernel/ptrace.c linux-2.0.31pre9-privs/arch/ppc/kernel/ptrace.c --- linux-2.0.31pre9/arch/ppc/kernel/ptrace.c Mon May 27 02:00:58 1996 +++ linux-2.0.31pre9-privs/arch/ppc/kernel/ptrace.c Sun Sep 7 10:28:13 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.31pre9/arch/ppc/kernel/signal.c linux-2.0.31pre9-privs/arch/ppc/kernel/signal.c --- linux-2.0.31pre9/arch/ppc/kernel/signal.c Mon Jul 8 01:27:43 1996 +++ linux-2.0.31pre9-privs/arch/ppc/kernel/signal.c Sun Sep 7 10:28:13 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.31pre9/arch/sparc/config.in linux-2.0.31pre9-privs/arch/sparc/config.in --- linux-2.0.31pre9/arch/sparc/config.in Thu Apr 25 03:22:05 1996 +++ linux-2.0.31pre9-privs/arch/sparc/config.in Sun Sep 7 10:28:13 1997 @@ -29,6 +29,12 @@ 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 +int 'Default security level - see help' DEFAULT_SECURE_LEVEL 0 + endmenu mainmenu_option next_comment diff -urN linux-2.0.31pre9/arch/sparc/defconfig linux-2.0.31pre9-privs/arch/sparc/defconfig --- linux-2.0.31pre9/arch/sparc/defconfig Thu Apr 25 03:22:05 1996 +++ linux-2.0.31pre9-privs/arch/sparc/defconfig Sun Sep 7 10:28:13 1997 @@ -20,6 +20,8 @@ CONFIG_NET=y CONFIG_SYSVIPC=y CONFIG_BINFMT_ELF=y +# CONFIG_POSIX6_CAP is not set +DEFAULT_SECURE_LEVEL=0 # # Floppy, IDE, and other block devices @@ -96,6 +98,8 @@ # Filesystems # # CONFIG_QUOTA is not set +# CONFIG_SYMLINK_FIX is not set +CONFIG_SYMLINK_LOG=y # CONFIG_MINIX_FS is not set # CONFIG_EXT_FS is not set CONFIG_EXT2_FS=y @@ -114,6 +118,7 @@ # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set +# CONFIG_AUTOFS_FS is not set CONFIG_UFS_FS=y # diff -urN linux-2.0.31pre9/arch/sparc/kernel/ptrace.c linux-2.0.31pre9-privs/arch/sparc/kernel/ptrace.c --- linux-2.0.31pre9/arch/sparc/kernel/ptrace.c Sat May 4 09:39:23 1996 +++ linux-2.0.31pre9-privs/arch/sparc/kernel/ptrace.c Sun Sep 7 10:28:13 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.31pre9/arch/sparc/kernel/signal.c linux-2.0.31pre9-privs/arch/sparc/kernel/signal.c --- linux-2.0.31pre9/arch/sparc/kernel/signal.c Thu Apr 25 03:22:05 1996 +++ linux-2.0.31pre9-privs/arch/sparc/kernel/signal.c Sun Sep 7 10:28:13 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.31pre9/arch/sparc/kernel/sys_sparc.c linux-2.0.31pre9-privs/arch/sparc/kernel/sys_sparc.c --- linux-2.0.31pre9/arch/sparc/kernel/sys_sparc.c Thu Apr 25 03:22:05 1996 +++ linux-2.0.31pre9-privs/arch/sparc/kernel/sys_sparc.c Sun Sep 7 10:28:13 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.31pre9/drivers/block/floppy.c linux-2.0.31pre9-privs/drivers/block/floppy.c --- linux-2.0.31pre9/drivers/block/floppy.c Tue Apr 8 08:47:45 1997 +++ linux-2.0.31pre9-privs/drivers/block/floppy.c Sun Sep 7 10:28:13 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.31pre9/drivers/block/hd.c linux-2.0.31pre9-privs/drivers/block/hd.c --- linux-2.0.31pre9/drivers/block/hd.c Thu Feb 29 21:50:39 1996 +++ linux-2.0.31pre9-privs/drivers/block/hd.c Sun Sep 7 10:28:13 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.31pre9/drivers/block/ide.c linux-2.0.31pre9-privs/drivers/block/ide.c --- linux-2.0.31pre9/drivers/block/ide.c Sun Sep 7 16:03:49 1997 +++ linux-2.0.31pre9-privs/drivers/block/ide.c Sun Sep 7 10:28:14 1997 @@ -285,6 +285,7 @@ #include #include #include +#include #include #include #include @@ -2141,13 +2142,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; @@ -2158,7 +2159,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: @@ -2190,7 +2191,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; @@ -2203,7 +2204,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); @@ -2249,7 +2250,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) @@ -2270,7 +2271,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))) { @@ -2296,7 +2297,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.31pre9/drivers/block/loop.c linux-2.0.31pre9-privs/drivers/block/loop.c --- linux-2.0.31pre9/drivers/block/loop.c Sun Sep 7 16:03:49 1997 +++ linux-2.0.31pre9-privs/drivers/block/loop.c Sun Sep 7 10:28:14 1997 @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -427,7 +428,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.31pre9/drivers/block/md.c linux-2.0.31pre9-privs/drivers/block/md.c --- linux-2.0.31pre9/drivers/block/md.c Sat Jun 29 14:04:00 1996 +++ linux-2.0.31pre9-privs/drivers/block/md.c Sun Sep 7 10:28:14 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.31pre9/drivers/block/rd.c linux-2.0.31pre9-privs/drivers/block/rd.c --- linux-2.0.31pre9/drivers/block/rd.c Tue Jul 2 09:08:41 1996 +++ linux-2.0.31pre9-privs/drivers/block/rd.c Sun Sep 7 10:28:14 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.31pre9/drivers/block/xd.c linux-2.0.31pre9-privs/drivers/block/xd.c --- linux-2.0.31pre9/drivers/block/xd.c Sun Sep 8 09:50:20 1996 +++ linux-2.0.31pre9-privs/drivers/block/xd.c Sun Sep 7 10:28:14 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.31pre9/drivers/cdrom/sbpcd.c linux-2.0.31pre9-privs/drivers/cdrom/sbpcd.c --- linux-2.0.31pre9/drivers/cdrom/sbpcd.c Mon Sep 2 05:18:26 1996 +++ linux-2.0.31pre9-privs/drivers/cdrom/sbpcd.c Sun Sep 7 10:28:14 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.31pre9/drivers/char/apm_bios.c linux-2.0.31pre9-privs/drivers/char/apm_bios.c --- linux-2.0.31pre9/drivers/char/apm_bios.c Tue May 14 23:06:55 1996 +++ linux-2.0.31pre9-privs/drivers/char/apm_bios.c Sun Sep 7 10:28:14 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.31pre9/drivers/char/baycom.c linux-2.0.31pre9-privs/drivers/char/baycom.c --- linux-2.0.31pre9/drivers/char/baycom.c Mon Jul 8 00:21:45 1996 +++ linux-2.0.31pre9-privs/drivers/char/baycom.c Sun Sep 7 10:28:14 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.31pre9/drivers/char/console.c linux-2.0.31pre9-privs/drivers/char/console.c --- linux-2.0.31pre9/drivers/char/console.c Sun Sep 7 16:03:49 1997 +++ linux-2.0.31pre9-privs/drivers/char/console.c Sun Sep 7 10:28:14 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.31pre9/drivers/char/cyclades.c linux-2.0.31pre9-privs/drivers/char/cyclades.c --- linux-2.0.31pre9/drivers/char/cyclades.c Mon Oct 7 22:03:17 1996 +++ linux-2.0.31pre9-privs/drivers/char/cyclades.c Sun Sep 7 10:28:14 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.31pre9/drivers/char/istallion.c linux-2.0.31pre9-privs/drivers/char/istallion.c --- linux-2.0.31pre9/drivers/char/istallion.c Mon May 6 02:26:05 1996 +++ linux-2.0.31pre9-privs/drivers/char/istallion.c Sun Sep 7 10:28:15 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.31pre9/drivers/char/lp.c linux-2.0.31pre9-privs/drivers/char/lp.c --- linux-2.0.31pre9/drivers/char/lp.c Thu Apr 3 19:15:34 1997 +++ linux-2.0.31pre9-privs/drivers/char/lp.c Sun Sep 7 10:28:15 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.31pre9/drivers/char/random.c linux-2.0.31pre9-privs/drivers/char/random.c --- linux-2.0.31pre9/drivers/char/random.c Sun Sep 7 16:03:50 1997 +++ linux-2.0.31pre9-privs/drivers/char/random.c Sun Sep 7 10:28:15 1997 @@ -228,6 +228,7 @@ #include #include +#include #include #include #include @@ -1165,7 +1166,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) @@ -1194,7 +1195,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)); @@ -1218,7 +1219,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)); @@ -1252,13 +1253,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.31pre9/drivers/char/riscom8.c linux-2.0.31pre9-privs/drivers/char/riscom8.c --- linux-2.0.31pre9/drivers/char/riscom8.c Fri Apr 26 02:12:25 1996 +++ linux-2.0.31pre9-privs/drivers/char/riscom8.c Sun Sep 7 10:28:15 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.31pre9/drivers/char/rtc.c linux-2.0.31pre9-privs/drivers/char/rtc.c --- linux-2.0.31pre9/drivers/char/rtc.c Mon May 27 21:39:18 1996 +++ linux-2.0.31pre9-privs/drivers/char/rtc.c Sun Sep 7 10:28:15 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 @@ -2417,7 +2418,7 @@ { int found = 1; - if (!suser()) return -EPERM; + if (!capable(CAP_SYS_DEVICES)) return -EPERM; if (!arg) return -EFAULT; error = verify_area(VERIFY_READ, arg, sizeof(struct scc_hw_config)); @@ -2527,7 +2528,7 @@ if (cmd == TIOCSCCINI) { - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EPERM; if (Nchips == 0) @@ -2544,7 +2545,7 @@ { if (cmd == TIOCSCCCHANINI) { - if (!suser()) return -EPERM; + if (!capable(CAP_SYS_DEVICES)) return -EPERM; if (!arg) return -EINVAL; error = verify_area(VERIFY_READ, arg, sizeof(struct scc_modem)); if (error) return error; @@ -2596,7 +2597,7 @@ { case TIOCSCCSMEM: case TIOCCHANMEM_OLD: - if (!suser()) return -EPERM; + if (!capable(CAP_SYS_DEVICES)) return -EPERM; if (!arg) return -EINVAL; error = verify_area(VERIFY_READ, arg, sizeof(struct scc_mem_config)); if (error) return error; @@ -2639,7 +2640,7 @@ case TIOCSCCSKISS: case TIOCSKISS_OLD: - if (!suser()) return -EPERM; + if (!capable(CAP_SYS_DEVICES)) return -EPERM; if (!arg) return -EINVAL; error = verify_area(VERIFY_READ, arg, sizeof(struct scc_mem_config)); if (error) return error; diff -urN linux-2.0.31pre9/drivers/char/serial.c linux-2.0.31pre9-privs/drivers/char/serial.c --- linux-2.0.31pre9/drivers/char/serial.c Tue Apr 8 08:47:45 1997 +++ linux-2.0.31pre9-privs/drivers/char/serial.c Sun Sep 7 10:28:15 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) @@ -2960,7 +2961,7 @@ release_region(rs_table[i].port, 8); } if (tmp_buf) { - free_page(tmp_buf); + free_page((unsigned long) tmp_buf); tmp_buf = NULL; } } diff -urN linux-2.0.31pre9/drivers/char/specialix.c linux-2.0.31pre9-privs/drivers/char/specialix.c --- linux-2.0.31pre9/drivers/char/specialix.c Sun Sep 7 16:03:50 1997 +++ linux-2.0.31pre9-privs/drivers/char/specialix.c Sun Sep 7 10:28:15 1997 @@ -1839,7 +1839,7 @@ change_speed = ((port->flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); - if (!suser()) { + if (!capable(CAP_SYS_DEVICES)) { if ((tmp.close_delay != port->close_delay) || (tmp.closing_wait != port->closing_wait) || ((tmp.flags & ~ASYNC_USR_MASK) != diff -urN linux-2.0.31pre9/drivers/char/stallion.c linux-2.0.31pre9-privs/drivers/char/stallion.c --- linux-2.0.31pre9/drivers/char/stallion.c Mon May 6 02:26:06 1996 +++ linux-2.0.31pre9-privs/drivers/char/stallion.c Sun Sep 7 10:28:16 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.31pre9/drivers/char/tpqic02.c linux-2.0.31pre9-privs/drivers/char/tpqic02.c --- linux-2.0.31pre9/drivers/char/tpqic02.c Thu Feb 29 21:50:41 1996 +++ linux-2.0.31pre9-privs/drivers/char/tpqic02.c Sun Sep 7 10:28:16 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.31pre9/drivers/char/tty_io.c linux-2.0.31pre9-privs/drivers/char/tty_io.c --- linux-2.0.31pre9/drivers/char/tty_io.c Sun Sep 7 16:03:51 1997 +++ linux-2.0.31pre9-privs/drivers/char/tty_io.c Sun Sep 7 10:28:16 1997 @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -1368,7 +1369,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) { @@ -1544,7 +1546,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) @@ -1580,7 +1583,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; @@ -1627,7 +1630,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 */ @@ -1694,7 +1697,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) @@ -1742,7 +1746,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.31pre9/drivers/char/tty_ioctl.c linux-2.0.31pre9-privs/drivers/char/tty_ioctl.c --- linux-2.0.31pre9/drivers/char/tty_ioctl.c Sun Sep 7 16:03:51 1997 +++ linux-2.0.31pre9-privs/drivers/char/tty_ioctl.c Sun Sep 7 10:28:16 1997 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -505,7 +506,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.31pre9/drivers/char/vt.c linux-2.0.31pre9-privs/drivers/char/vt.c --- linux-2.0.31pre9/drivers/char/vt.c Sun May 12 21:36:19 1996 +++ linux-2.0.31pre9-privs/drivers/char/vt.c Sun Sep 7 10:28:16 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.31pre9/drivers/isdn/avmb1/capi.c linux-2.0.31pre9-privs/drivers/isdn/avmb1/capi.c --- linux-2.0.31pre9/drivers/isdn/avmb1/capi.c Sun Sep 7 16:03:52 1997 +++ linux-2.0.31pre9-privs/drivers/isdn/avmb1/capi.c Sun Sep 7 10:28:16 1997 @@ -408,7 +408,7 @@ struct capi_manufacturer_cmd mcmd; if (minor) return -EINVAL; - if (!suser()) + if (!capable(CAP_SYS_DEVICES)) return -EPERM; retval = copy_from_user((void *) &mcmd, (void *) arg, sizeof(mcmd)); diff -urN linux-2.0.31pre9/drivers/net/3c509.c linux-2.0.31pre9-privs/drivers/net/3c509.c --- linux-2.0.31pre9/drivers/net/3c509.c Sun Sep 7 16:03:59 1997 +++ linux-2.0.31pre9-privs/drivers/net/3c509.c Sun Sep 7 10:26:50 1997 @@ -35,7 +35,7 @@ other cleanups. -djb */ -static char *version = "3c509.c:1.11 4/22/97 becker@cesdis.gsfc.nasa.gov\n"; +static char *version = "3c509.c:1.12 6/4/97 becker@cesdis.gsfc.nasa.gov\n"; /* A few values that may be tweaked. */ /* Time in jiffies before concluding the transmitter is hung. */ @@ -279,10 +279,8 @@ memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); dev->base_addr = ioaddr; dev->irq = irq; - if (dev->mem_start) - dev->if_port = dev->mem_start & 3; - else - dev->if_port = if_port; + dev->if_port = (dev->mem_start & 0x1f) ? dev->mem_start & 3 : if_port; + request_region(dev->base_addr, EL3_IO_EXTENT, "3c509"); { @@ -694,9 +692,8 @@ printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len); } - outw(RxDiscard, ioaddr + EL3_CMD); lp->stats.rx_dropped++; - SLOW_DOWN_IO; + outw(RxDiscard, ioaddr + EL3_CMD); while (inw(ioaddr + EL3_STATUS) & 0x1000) printk(" Waiting for 3c509 to discard packet, status %x.\n", inw(ioaddr + EL3_STATUS) ); @@ -727,7 +724,7 @@ outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD); } else - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); + outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); } static int diff -urN linux-2.0.31pre9/drivers/net/3c59x.c linux-2.0.31pre9-privs/drivers/net/3c59x.c --- linux-2.0.31pre9/drivers/net/3c59x.c Sun Sep 7 16:03:59 1997 +++ linux-2.0.31pre9-privs/drivers/net/3c59x.c Sun Sep 7 10:26:50 1997 @@ -1,4 +1,4 @@ -/* 3c900.c: A 3Com EtherLink III XL "Boomerang" ethernet driver for linux. */ +/* EtherLink.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */ /* Written 1996-1997 by Donald Becker. @@ -15,10 +15,16 @@ */ static char *version = -"3c59x.c/3c900.c:v0.42 7/15/97 Donald Becker linux-vortex@cesdis.gsfc.nasa.gov\n"; +"3c59x.c:v0.43 9/2/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n"; /* "Knobs" that turn on special features. */ -/* Enable the automatic media selection code. */ +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1512 effectively disables this feature. */ +static const rx_copybreak = 200; +/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */ +static const mtu = 1500; + +/* Enable the automatic media selection code -- usually set. */ #define AUTOMEDIA 1 /* Allow the use of fragment bus master transfers instead of only @@ -36,12 +42,17 @@ #define RX_RING_SIZE 32 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -/* Set the copy breakpoint for the copy-only-tiny-frames scheme. - Setting to > 1512 effectively disables this feature. */ -static const rx_copybreak = 200; - -#include +#include +#ifdef MODULE +#ifdef MODVERSIONS +#include +#endif #include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif #include #include @@ -109,10 +120,6 @@ debugging. */ static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0; -/* Number of times to check to see if the Tx FIFO has space, used in some - limited cases. */ -#define WAIT_TX_AVAIL 200 - /* Operational parameter that usually are not changed. */ /* The Vortex size is twice that of the original EtherLinkIII series: the @@ -281,6 +288,7 @@ enum Window0 { Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */ Wn0EepromData = 12, /* Window 0: EEPROM results register. */ + IntrStatus=0x0E, /* Valid in all windows. */ }; enum Win0_EEPROM_bits { EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0, @@ -307,8 +315,8 @@ } u; }; -enum Window4 { - Wn4_NetDiag = 6, Wn4_Media = 10, /* Window 4: Xcvr/media bits. */ +enum Window4 { /* Window 4: Xcvr/media bits. */ + Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10, }; enum Win4_Media_bits { Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */ @@ -328,22 +336,32 @@ /* The Rx and Tx descriptor lists. Caution Alpha hackers: these types are 32 bits! Note also the 8 byte alignment contraint on tx_ring[] and rx_ring[]. */ +#define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */ struct boom_rx_desc { - u32 next; + u32 next; /* Last entry points to 0. */ s32 status; - u32 addr; - s32 length; + u32 addr; /* Up to addr/len possible.. */ + s32 length; /* set high bit to indicate last pair. */ }; /* Values for the Rx status entry. */ -#define RX_COMPLETE 0x00008000 +enum rx_desc_status { + RxDComplete=0x00008000, RxDError=0x4000, + /* See boomerang_rx() for actual error bits */ +}; struct boom_tx_desc { - u32 next; - s32 status; + u32 next; /* Last entry points to 0. */ + s32 status; /* bits 0:12 length, others see below. */ u32 addr; s32 length; }; +/* Values for the Tx status entry. */ +enum tx_desc_status { + CRCDisable=0x2000, TxDComplete=0x8000, + TxIntrUploaded=0x80000000, /* IRQ when in FIFO, but maybe not sent. */ +}; + struct vortex_private { char devname[8]; /* "ethN" string, also for kernel debug. */ const char *product_name; @@ -370,11 +388,17 @@ tx_full:1; u16 capabilities; /* Adapter capabilities word. */ u16 info1, info2; /* Software information information. */ + unsigned char phys[2]; /* MII device addresses. */ }; /* The action to take with a media selection timer tick. Note that we deviate from the 3Com order by checking 10base2 before AUI. */ +enum xcvr_types { + XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx, + XCVR_100baseFx, XCVR_MII=6, XCVR_Default=8, +}; + static struct media_table { char *name; unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ @@ -382,23 +406,24 @@ next:8; /* The media type to try next. */ short wait; /* Time before we check media status. */ } media_tbl[] = { - { "10baseT", Media_10TP,0x08, 3 /* 10baseT->10base2 */, (14*HZ)/10}, - { "10Mbs AUI", Media_SQE, 0x20, 8 /* AUI->default */, (1*HZ)/10}, - { "undefined", 0, 0x80, 0 /* Undefined */, 10000}, - { "10base2", 0, 0x10, 1 /* 10base2->AUI. */, (1*HZ)/10}, - { "100baseTX", Media_Lnk, 0x02, 5 /* 100baseTX->100baseFX */, (14*HZ)/10}, - { "100baseFX", Media_Lnk, 0x04, 6 /* 100baseFX->MII */, (14*HZ)/10}, - { "MII", 0, 0x40, 0 /* MII->10baseT */, (14*HZ)/10}, - { "undefined", 0, 0x01, 0 /* Undefined/100baseT4 */, 10000}, - { "Default", 0, 0xFF, 0 /* Use default */, 10000}, + { "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10}, + { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10}, + { "undefined", 0, 0x80, XCVR_10baseT, 10000}, + { "10base2", 0, 0x10, XCVR_AUI, (1*HZ)/10}, + { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10}, + { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14*HZ)/10}, + { "MII", 0, 0x40, XCVR_10baseT, 3*HZ }, + { "undefined", 0, 0x01, XCVR_10baseT, 10000}, + { "Default", 0, 0xFF, XCVR_10baseT, 10000}, }; static int vortex_scan(struct device *dev); static struct device *vortex_found_device(struct device *dev, int ioaddr, int irq, int product_index, - int options); + int options, int card_idx); static int vortex_probe1(struct device *dev); static int vortex_open(struct device *dev); +static int mdio_read(int ioaddr, int phy_id, int location); static void vortex_timer(unsigned long arg); static int vortex_start_xmit(struct sk_buff *skb, struct device *dev); static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev); @@ -431,13 +456,15 @@ /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Note: this is the only limit on the number of cards supported!! */ static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,}; +static int full_duplex[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; +/* A list of all installed Vortex devices, for removing the driver module. */ +static struct device *root_vortex_dev = NULL; + /* Variables to work-around the Compaq PCI BIOS32 problem. */ static int compaq_ioaddr = 0, compaq_irq = 0, compaq_prod_id = 0; #ifdef MODULE static int debug = -1; -/* A list of all installed Vortex devices, for removing the driver module. */ -static struct device *root_vortex_dev = NULL; int init_module(void) @@ -519,7 +546,8 @@ dev = vortex_found_device(dev, pci_ioaddr, pci_irq_line, board_index, dev && dev->mem_start - ? dev->mem_start : options[cards_found]); + ? dev->mem_start : options[cards_found], + cards_found); if (dev) { /* Get and check the bus-master and latency values. @@ -572,7 +600,8 @@ continue; vortex_found_device(dev, ioaddr, inw(ioaddr + 0xC88) >> 12, product_index, dev && dev->mem_start - ? dev->mem_start : options[cards_found]); + ? dev->mem_start : options[cards_found], + cards_found); dev = 0; cards_found++; } @@ -581,7 +610,8 @@ /* Special code to work-around the Compaq PCI BIOS32 problem. */ if (compaq_ioaddr) { vortex_found_device(dev, compaq_ioaddr, compaq_irq, compaq_prod_id, - dev && dev->mem_start ? dev->mem_start : options[cards_found]); + dev && dev->mem_start ? dev->mem_start + : options[cards_found], cards_found); cards_found++; dev = 0; } @@ -594,7 +624,7 @@ static struct device * vortex_found_device(struct device *dev, int ioaddr, int irq, - int product_index, int options) + int product_index, int options, int card_idx) { struct vortex_private *vp; @@ -614,13 +644,18 @@ dev->init = vortex_probe1; vp->product_name = product_names[product_index]; vp->options = options; + if (card_idx >= 0) { + if (full_duplex[card_idx] >= 0) + vp->full_duplex = full_duplex[card_idx]; + } else + vp->full_duplex = (options >= 0 && (options & 0x10) ? 1 : 0); + if (options >= 0) { - vp->media_override = ((options & 7) == 2) ? 0 : options & 7; - vp->full_duplex = (options & 8) ? 1 : 0; + vp->media_override = ((options & 7) == XCVR_10baseTOnly) ? + XCVR_10baseT : options & 7; vp->bus_master = (options & 16) ? 1 : 0; } else { vp->media_override = 7; - vp->full_duplex = 0; vp->bus_master = 0; } ether_setup(dev); @@ -637,6 +672,8 @@ dev = init_etherdev(dev, sizeof(struct vortex_private)); dev->base_addr = ioaddr; dev->irq = irq; + dev->mtu = mtu; + vp = (struct vortex_private *)dev->priv; vp->product_name = product_names[product_index]; vp->options = options; @@ -717,11 +754,29 @@ dev->if_port = vp->media_override; } + if (dev->if_port == XCVR_MII) { + int phy, phy_idx = 0; + EL3WINDOW(4); + for (phy = 0; phy < 32 && phy_idx < sizeof(vp->phys); phy++) { + int mii_status = mdio_read(ioaddr, phy, 0); + if (mii_status != 0xffff && mii_status != 0x0000) { + vp->phys[phy_idx++] = phy; + printk("%s: MII transceiver found at address %d.\n", + dev->name, phy); + } + } + if (phy_idx == 0) { + printk("%s: ***WARNING*** No MII transceivers found!\n", + dev->name); + vp->phys[0] = 0; + } + } + vp->info1 = eeprom[13]; vp->info2 = eeprom[15]; vp->capabilities = eeprom[16]; if (vp->capabilities & 0x20) { - vp->full_bus_master_tx = 0; /* TX bugs, force bus_master_tx to 0? */ + vp->full_bus_master_tx = 1; printk(" Enabling bus-master transmits and %s receives.\n", (vp->info2 & 1) ? "early" : "whole-frame" ); vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2; @@ -743,6 +798,54 @@ return 0; } + +/* Read and write the MII registers using software-generated serial + MDIO protocol. The maxium data clock rate is 2.5 Mhz. */ +#define mdio_delay(microsecs) udelay(microsecs) + +#define MDIO_SHIFT_CLK 0x01 +#define MDIO_DIR_WRITE 0x04 +#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE) +#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE) +#define MDIO_DATA_READ 0x02 +#define MDIO_ENB_IN 0x00 + +static int mdio_read(int ioaddr, int phy_id, int location) +{ + int i; + int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + unsigned short retval = 0; + int mdio_addr = ioaddr + Wn4_PhysicalMgmt; + + /* Shift the read command bits out. */ + for (i = 17; i >= 0; i--) { + int dataval = (read_cmd&(1< 0; i--) { + outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(1); + retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + outw(MDIO_ENB_IN, mdio_addr); + mdio_delay(1); + } + /* Clear out extra bits. Needed? */ + for (i = 16; i > 0; i--) { + outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(1); + outw(MDIO_ENB_IN, mdio_addr); + mdio_delay(1); + } + return retval; +} static int @@ -765,7 +868,7 @@ dev->if_port = vp->media_override; } else if (vp->autoselect) { /* Find first available media type, starting with 100baseTx. */ - dev->if_port = 4; + dev->if_port = XCVR_100baseTx; while (! (vp->available_media & media_tbl[dev->if_port].mask)) dev->if_port = media_tbl[dev->if_port].next; @@ -784,6 +887,23 @@ config.u.xcvr = dev->if_port; outl(config.i, ioaddr + Wn3_Config); + if (dev->if_port == XCVR_MII) { + int mii_reg1, mii_reg25; + /* We cheat here: we know that we are using the 83840 transceiver + which summarizes the FD status in an extended register. */ + EL3WINDOW(4); + /* Read BMSR (reg1) only to clear old status. */ + mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1); + mii_reg25 = mdio_read(ioaddr, vp->phys[0], 0x19); + if (vortex_debug > 1) + printk("%s: MII #%d status %4.4x, duplex report %4.4x," + " setting %s-duplex.\n", dev->name, vp->phys[0], + mii_reg1, mii_reg25, mii_reg25 & 0x0080 ? "full" : "half"); + if (mii_reg25 & 0x0080) + vp->full_duplex = 1; + EL3WINDOW(3); + } + /* Set the full-duplex bit. */ outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl); @@ -835,7 +955,7 @@ for (; i < 12; i+=2) outw(0, ioaddr + i); - if (dev->if_port == 3) + if (dev->if_port == XCVR_10base2) /* Start the thinnet transceiver. We should really wait 50ms...*/ outw(StartCoax, ioaddr + EL3_CMD); EL3WINDOW(4); @@ -869,7 +989,7 @@ struct sk_buff *skb; vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]); vp->rx_ring[i].status = 0; /* Clear complete bit. */ - vp->rx_ring[i].length = PKT_BUF_SZ | 0x80000000; + vp->rx_ring[i].length = PKT_BUF_SZ | LAST_FRAG; skb = dev_alloc_skb(PKT_BUF_SZ); vp->rx_skbuff[i] = skb; if (skb == NULL) @@ -937,7 +1057,7 @@ EL3WINDOW(4); media_status = inw(ioaddr + Wn4_Media); switch (dev->if_port) { - case 0: case 4: case 5: /* 10baseT, 100baseTX, 100baseFX */ + case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx: if (media_status & Media_LnkBeat) { ok = 1; if (vortex_debug > 1) @@ -948,6 +1068,16 @@ dev->name, media_tbl[dev->if_port].name, media_status); break; + case XCVR_MII: + { + int mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1); + if (vortex_debug > 1) + printk("%s: MII #%d status register is %4.4x.\n", + dev->name, vp->phys[0], mii_reg1); + if (mii_reg1 & 0x0004) + ok = 1; + break; + } default: /* Other media types handled by Tx timeouts. */ if (vortex_debug > 1) printk("%s: Media %s is has no indication, %x.\n", @@ -960,7 +1090,7 @@ do { dev->if_port = media_tbl[dev->if_port].next; } while ( ! (vp->available_media & media_tbl[dev->if_port].mask)); - if (dev->if_port == 8) { /* Go back to default. */ + if (dev->if_port == XCVR_Default) { /* Go back to default. */ dev->if_port = vp->default_media; if (vortex_debug > 1) printk("%s: Media selection failing, using default %s port.\n", @@ -980,7 +1110,8 @@ config.u.xcvr = dev->if_port; outl(config.i, ioaddr + Wn3_Config); - outw(dev->if_port == 3 ? StartCoax : StopCoax, ioaddr + EL3_CMD); + outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax, + ioaddr + EL3_CMD); } EL3WINDOW(old_window); } restore_flags(flags); @@ -1201,8 +1332,8 @@ vp->tx_skbuff[entry] = skb; vp->tx_ring[entry].next = 0; vp->tx_ring[entry].addr = virt_to_bus(skb->data); - vp->tx_ring[entry].length = skb->len | 0x80000000; - vp->tx_ring[entry].status = skb->len | 0x80000000; + vp->tx_ring[entry].length = skb->len | LAST_FRAG; + vp->tx_ring[entry].status = skb->len | TxIntrUploaded; save_flags(flags); cli(); @@ -1223,7 +1354,7 @@ if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) vp->tx_full = 1; else { /* Clear previous interrupt enable. */ - prev_entry->status &= ~0x80000000; + prev_entry->status &= ~TxIntrUploaded; dev->tbusy = 0; } dev->trans_start = jiffies; @@ -1297,7 +1428,7 @@ dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE); lp->tx_skbuff[entry] = 0; } - lp->stats.tx_packets++; + /* lp->stats.tx_packets++; Counted below. */ dirty_tx++; } outw(AckIntr | DownComplete, ioaddr + EL3_CMD); @@ -1461,8 +1592,8 @@ if (vortex_debug > 5) printk(" In boomerang_rx(), status %4.4x, rx_status %4.4x.\n", inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus)); - while ((rx_status = vp->rx_ring[entry].status) & RX_COMPLETE) { - if (rx_status & 0x4000) { /* Error, update stats. */ + while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) { + if (rx_status & RxDError) { /* Error, update stats. */ unsigned char rx_error = rx_status >> 16; if (vortex_debug > 4) printk(" Rx error: status %2.2x.\n", rx_error); @@ -1566,7 +1697,7 @@ outw(RxDisable, ioaddr + EL3_CMD); outw(TxDisable, ioaddr + EL3_CMD); - if (dev->if_port == 3) + if (dev->if_port == XCVR_10base2) /* Turn off thinnet power. Green! */ outw(StopCoax, ioaddr + EL3_CMD); @@ -1704,12 +1835,14 @@ root_vortex_dev = next_dev; } } -#endif /* MODULE */ + +#endif /* MODULE */ /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c" + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c" * c-indent-level: 4 + * c-basic-offset: 4 * tab-width: 4 * End: */ diff -urN linux-2.0.31pre9/drivers/net/de4x5.c linux-2.0.31pre9-privs/drivers/net/de4x5.c --- linux-2.0.31pre9/drivers/net/de4x5.c Sun Sep 7 16:04:00 1997 +++ linux-2.0.31pre9-privs/drivers/net/de4x5.c Sun Sep 7 10:28:16 1997 @@ -310,6 +310,7 @@ #include #include +#include #include #include #include @@ -4782,7 +4783,7 @@ if (status) break; status = -EPERM; - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) break; status = 0; copy_from_user(tmp.addr, ioc->data, ETH_ALEN); @@ -4800,7 +4801,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); @@ -4810,7 +4811,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); @@ -4830,7 +4831,7 @@ case DE4X5_CLR_MCA: /* Clear all multicast addresses */ break; case DE4X5_MCA_EN: /* Enable pass all multicast addresses*/ - if (suser()) { + if (capable(CAP_NET_IFCONFIG)) { omr = inl(DE4X5_OMR); omr |= OMR_PM; outl(omr, DE4X5_OMR); @@ -4851,7 +4852,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(); @@ -4868,7 +4869,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))) { copy_from_user(tmp.addr, ioc->data, 1); outl(tmp.addr[0], DE4X5_OMR); diff -urN linux-2.0.31pre9/drivers/net/depca.c linux-2.0.31pre9-privs/drivers/net/depca.c --- linux-2.0.31pre9/drivers/net/depca.c Tue Apr 8 08:47:45 1997 +++ linux-2.0.31pre9-privs/drivers/net/depca.c Sun Sep 7 10:28:16 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.31pre9/drivers/net/dlci.c linux-2.0.31pre9-privs/drivers/net/dlci.c --- linux-2.0.31pre9/drivers/net/dlci.c Sun Sep 15 00:34:18 1996 +++ linux-2.0.31pre9-privs/drivers/net/dlci.c Sun Sep 7 10:28:16 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.31pre9/drivers/net/eepro100.c linux-2.0.31pre9-privs/drivers/net/eepro100.c --- linux-2.0.31pre9/drivers/net/eepro100.c Sun Sep 7 16:04:00 1997 +++ linux-2.0.31pre9-privs/drivers/net/eepro100.c Sun Sep 7 10:26:51 1997 @@ -1,7 +1,7 @@ /* drivers/net/eepro100.c: An Intel i82557 ethernet driver for linux. */ /* NOTICE: this version tested with kernels 1.3.72 and later only! - Written 1996 by Donald Becker. + Written 1996-1997 by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. @@ -19,7 +19,7 @@ */ static const char *version = -"eepro100.c:v0.32 4/8/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n"; +"eepro100.c:v0.34 8/30/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n"; /* A few user-configurable values that apply to all boards. First set are undocumented and spelled per Intel recommendations. */ @@ -36,14 +36,17 @@ #define SKBUFF_RX_COPYBREAK 256 #include -#include #ifdef MODULE +#ifdef MODVERSIONS +#include +#endif #include #else #define MOD_INC_USE_COUNT #define MOD_DEC_USE_COUNT #endif +#include #include #include #include @@ -112,6 +115,10 @@ #define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2) #endif +#if (LINUX_VERSION_CODE < 0x20123) +#define test_and_set_bit(val, addr) set_bit(val, addr) +#endif + /* The total I/O port extent of the board. Nominally 0x18, but rounded up for PCI allocation. */ #define SPEEDO3_TOTAL_SIZE 0x20 @@ -142,7 +149,7 @@ need to be set on the board. The system BIOS should be set to assign the PCI INTA signal to an otherwise unused system IRQ line. While it's possible to share PCI interrupt lines, it negatively impacts performance and -only recent kernels support it. +only recent kernels support it. III. Driver operation @@ -422,14 +429,15 @@ /* PHY media interface chips. */ static const char *phys[] = { "None", "i82553-A/B", "i82553-C", "i82503", - "DP83840", "80c240", "80c24", "unknown-7", + "DP83840", "80c240", "80c24", "i82555", "unknown-8", "unknown-9", "DP83840A", "unknown-11", "unknown-12", "unknown-13", "unknown-14", "unknown-15", }; enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240, - S80C24, PhyUndefined, DP83840A=10, }; + S80C24, I82555, DP83840A=10, }; static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 }; -static void speedo_found1(struct device *dev, int ioaddr, int irq, int options); +static void speedo_found1(struct device *dev, int ioaddr, int irq, + int options, int card_idx); static int read_eeprom(int ioaddr, int location); static int mdio_read(int ioaddr, int phy_id, int location); @@ -450,16 +458,17 @@ -#ifdef MODULE /* The parameters that may be passed in... */ /* 'options' is used to pass a transceiver override or full-duplex flag e.g. "options=16" for FD, "options=32" for 100mbps-only. */ +static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +#ifdef MODULE static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int debug = -1; /* The debug level */ +#endif /* A list of all installed Speedo devices, for removing the driver module. */ static struct device *root_speedo_dev = NULL; -#endif int eepro100_init(struct device *dev) { @@ -512,11 +521,13 @@ printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency); #ifdef MODULE - speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found]); + speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found], + cards_found); #else speedo_found1(dev, pci_ioaddr, pci_irq_line, - dev ? dev->mem_start : 0); + dev ? dev->mem_start : 0, -1); #endif + dev = NULL; cards_found++; } } @@ -524,7 +535,8 @@ return cards_found; } -static void speedo_found1(struct device *dev, int ioaddr, int irq, int options) +static void speedo_found1(struct device *dev, int ioaddr, int irq, int options, + int card_idx) { static int did_version = 0; /* Already printed version info. */ struct speedo_private *sp; @@ -600,12 +612,12 @@ #if defined(notdef) /* ToDo: Read and set PHY registers through MDIO port. */ for (i = 0; i < 2; i++) - printk(" MDIO register %d is %4.4x.\n", + printk(KERN_INFO" MDIO register %d is %4.4x.\n", i, mdio_read(ioaddr, eeprom[6] & 0x1f, i)); for (i = 5; i < 7; i++) - printk(" MDIO register %d is %4.4x.\n", + printk(KERN_INFO" MDIO register %d is %4.4x.\n", i, mdio_read(ioaddr, eeprom[6] & 0x1f, i)); - printk(" MDIO register %d is %4.4x.\n", + printk(KERN_INFO" MDIO register %d is %4.4x.\n", 25, mdio_read(ioaddr, eeprom[6] & 0x1f, 25)); #endif if (((eeprom[6]>>8) & 0x3f) == DP83840 @@ -613,7 +625,7 @@ int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422; if (congenb) mdi_reg23 |= 0x0100; - printk(" DP83840 specific setup, setting register 23 to %4.4x.\n", + printk(KERN_INFO" DP83840 specific setup, setting register 23 to %4.4x.\n", mdi_reg23); mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23); } @@ -645,7 +657,7 @@ KERN_ERR " Verify that the card is a bus-master" " capable slot.\n", self_test_results[1]); - } else + } else printk(KERN_INFO " General self-test: %s.\n" KERN_INFO " Serial sub-system self-test: %s.\n" KERN_INFO " Internal registers self-test: %s.\n" @@ -673,7 +685,11 @@ root_speedo_dev = dev; #endif - sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0; + if (card_idx >= 0) { + if (full_duplex[card_idx] >= 0) + sp->full_duplex = full_duplex[card_idx]; + } else + sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0; sp->default_port = options >= 0 ? (options & 0x0f) : 0; sp->phy[0] = eeprom[6]; @@ -724,10 +740,10 @@ unsigned short retval = 0; int ee_addr = ioaddr + SCBeeprom; int read_cmd = location | EE_READ_CMD; - + outw(EE_ENB & ~EE_CS, ee_addr); outw(EE_ENB, ee_addr); - + /* Shift the read command bits out. */ for (i = 10; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; @@ -739,7 +755,7 @@ eeprom_delay(250); } outw(EE_ENB, ee_addr); - + for (i = 15; i >= 0; i--) { outw(EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay(100); @@ -845,7 +861,7 @@ outw(INT_MASK | RX_START, ioaddr + SCBCmd); /* Fill the first command with our physical address. */ - { + { unsigned short *eaddrs = (unsigned short *)dev->dev_addr; unsigned short *setup_frm = (short *)&(sp->tx_ring[0].tx_desc_addr); @@ -987,29 +1003,33 @@ "command %4.4x.\n", dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd)); #ifndef final_version - printk("%s: Tx timeout fill index %d scavenge index %d.\n", + printk(KERN_WARNING "%s: Tx timeout fill index %d scavenge index %d.\n", dev->name, sp->cur_tx, sp->dirty_tx); - printk(" Tx queue "); + printk(KERN_WARNING " Tx queue "); for (i = 0; i < TX_RING_SIZE; i++) printk(" %8.8x", (int)sp->tx_ring[i].status); - printk(".\n Rx ring "); + printk(".\n" KERN_WARNING " Rx ring "); for (i = 0; i < RX_RING_SIZE; i++) printk(" %8.8x", (int)sp->rx_ringp[i]->status); printk(".\n"); - + #else dev->if_port ^= 1; - printk(" (Media type switching not yet implemented.)\n"); + printk(KERN_WARNING " (Media type switching not yet implemented.)\n"); /* Do not do 'dev->tbusy = 0;' there -- it is incorrect. */ #endif if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) { - printk("%s: Trying to restart the transmitter...\n", dev->name); + printk(KERN_WARNING "%s: Trying to restart the transmitter...\n", + dev->name); outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]), ioaddr + SCBPointer); outw(CU_START, ioaddr + SCBCmd); } else { outw(DRVR_INT, ioaddr + SCBCmd); } + /* Reset the MII transceiver. */ + if ((sp->phy[0] & 0x8000) == 0) + mdio_write(ioaddr, sp->phy[0] & 0x1f, 0, 0x8000); sp->stats.tx_errors++; dev->trans_start = jiffies; return; @@ -1032,7 +1052,7 @@ /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. If this ever occurs the queue layer is doing something evil! */ - if (set_bit(0, (void*)&dev->tbusy) != 0) { + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < TX_TIMEOUT - 2) return 1; @@ -1150,7 +1170,7 @@ printk(KERN_WARNING"%s: The EEPro100 receiver left the ready" " state -- %4.4x! Index %d (%d).\n", dev->name, status, sp->cur_rx, sp->cur_rx % RX_RING_SIZE); - printk(" Rx ring:\n "); + printk(KERN_WARNING " Rx ring:\n "); for (i = 0; i < RX_RING_SIZE; i++) printk(" %d %8.8x %8.8x %8.8x %d %d.\n", i, sp->rx_ringp[i]->status, sp->rx_ringp[i]->link, @@ -1193,7 +1213,8 @@ #ifndef final_version if (sp->cur_tx - dirty_tx > TX_RING_SIZE) { - printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d," + " full=%d.\n", dirty_tx, sp->cur_tx, sp->tx_full); dirty_tx += TX_RING_SIZE; } @@ -1211,7 +1232,7 @@ } if (--boguscnt < 0) { - printk("%s: Too much work at interrupt, status=0x%4.4x.\n", + printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", dev->name, status); /* Clear all interrupt sources. */ outl(0xfc00, ioaddr + SCBStatus); @@ -1249,7 +1270,7 @@ struct speedo_private *sp = (struct speedo_private *)dev->priv; int entry = sp->cur_rx % RX_RING_SIZE; int status; - + if (speedo_debug > 4) printk(KERN_DEBUG " In speedo_rx().\n"); /* If we own the next entry, it's a new packet. Send it up. */ @@ -1259,12 +1280,12 @@ printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status, sp->rx_ringp[entry]->count & 0x3fff); if (status & 0x0200) { - printk("%s: Ethernet frame overran the Rx buffer, status %8.8x!\n", - dev->name, status); + printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, " + "status %8.8x!\n", dev->name, status); } else if ( ! (status & 0x2000)) { /* There was a fatal error. This *should* be impossible. */ sp->stats.rx_errors++; - printk("%s: Anomalous event in speedo_rx(), status %8.8x.\n", + printk(KERN_ERR "%s: Anomalous event in speedo_rx(), status %8.8x.\n", dev->name, status); } else { /* Malloc up new buffer, compatible with net-2e. */ @@ -1283,7 +1304,7 @@ #ifdef KERNEL_1_2 temp = skb->data; if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp) - printk("%s: Warning -- the skbuff addresses do not match" + printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match" " in speedo_rx: %p vs. %p / %p.\n", dev->name, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), temp, skb->data); @@ -1292,7 +1313,7 @@ #else temp = skb_put(skb, pkt_len); if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp) - printk("%s: Warning -- the skbuff addresses do not match" + printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match" " in speedo_rx: %8.8x vs. %p / %p.\n", dev->name, sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp); /* Get a fresh skbuff to replace the filled one. */ @@ -1329,7 +1350,7 @@ #endif if (skb == NULL) { int i; - printk("%s: Memory squeeze, deferring packet.\n", dev->name); + printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name); /* Check that at least two ring entries are free. If not, free one and mark stats->rx_dropped++. */ /* ToDo: This is not correct!!!! We should count the number @@ -1376,7 +1397,7 @@ } /* ToDo: This is better than before, but should be checked. */ - { + { struct RxFD *rxf = sp->rx_ringp[entry]; rxf->status = 0xC0000003; /* '3' for verification only */ rxf->link = 0; /* None yet. */ @@ -1444,19 +1465,20 @@ /* Print a few items for debugging. */ if (speedo_debug > 3) { - printk("%s:Printing Rx ring (next to receive into %d).\n", + int phy_num = sp->phy[0] & 0x1f; + printk(KERN_DEBUG "%s:Printing Rx ring (next to receive into %d).\n", dev->name, sp->cur_rx); for (i = 0; i < RX_RING_SIZE; i++) - printk(" Rx ring entry %d %8.8x.\n", + printk(KERN_DEBUG " Rx ring entry %d %8.8x.\n", i, (int)sp->rx_ringp[i]->status); for (i = 0; i < 5; i++) - printk(" PHY index %d register %d is %4.4x.\n", - 1, i, mdio_read(ioaddr, 1, i)); + printk(KERN_DEBUG " PHY index %d register %d is %4.4x.\n", + phy_num, i, mdio_read(ioaddr, phy_num, i)); for (i = 21; i < 26; i++) - printk(" PHY index %d register %d is %4.4x.\n", - 1, i, mdio_read(ioaddr, 1, i)); + printk(KERN_DEBUG " PHY index %d register %d is %4.4x.\n", + phy_num, i, mdio_read(ioaddr, phy_num, i)); } MOD_DEC_USE_COUNT; @@ -1527,7 +1549,7 @@ if (sp->cur_tx - sp->dirty_tx >= TX_RING_SIZE - 1) { /* The Tx ring is full -- don't add anything! Presumably the new mode - is in config_cmd_data and will be added anyway. */ + is in config_cmd_data and will be added anyway. */ sp->rx_mode = -1; return; } @@ -1563,7 +1585,7 @@ restore_flags(flags); if (speedo_debug > 5) { int i; - printk(" CmdConfig frame in entry %d.\n", entry); + printk(KERN_DEBUG " CmdConfig frame in entry %d.\n", entry); for(i = 0; i < 32; i++) printk(" %2.2x", ((unsigned char *)&sp->config_cmd)[i]); printk(".\n"); @@ -1616,20 +1638,19 @@ if (sp->mc_setup_frm) kfree(sp->mc_setup_frm); sp->mc_setup_frm_len = 10 + dev->mc_count*6 + 24; - printk("%s: Allocating a setup frame of size %d.\n", - dev->name, sp->mc_setup_frm_len); - sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, - intr_count ? GFP_ATOMIC : GFP_KERNEL); + sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC); if (sp->mc_setup_frm == NULL) { - printk("%s: Failed to allocate a setup frame.\n", dev->name); + printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", dev->name); sp->rx_mode = -1; /* We failed, try again. */ return; } } mc_setup_frm = sp->mc_setup_frm; /* Construct the new setup frame. */ - printk("%s: Constructing a setup frame at %p, %d bytes.\n", - dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len); + if (speedo_debug > 1) + printk(KERN_DEBUG "%s: Constructing a setup frame at %p, " + "%d bytes.\n", + dev->name, sp->mc_setup_frm, sp->mc_setup_frm_len); mc_setup_frm->status = 0; mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList; /* Link set below. */ @@ -1643,7 +1664,7 @@ *setup_params++ = *eaddrs++; *setup_params++ = *eaddrs++; } - + /* Disable interrupts while playing with the Tx Cmd list. */ save_flags(flags); cli(); @@ -1667,8 +1688,9 @@ outw(CU_RESUME, ioaddr + SCBCmd); sp->last_cmd = mc_setup_frm; restore_flags(flags); - printk("%s: Last command at %p is %4.4x.\n", - dev->name, sp->last_cmd, sp->last_cmd->command); + if (speedo_debug > 1) + printk(KERN_DEBUG "%s: Last command at %p is %4.4x.\n", + dev->name, sp->last_cmd, sp->last_cmd->command); } sp->rx_mode = new_rx_mode; @@ -1691,7 +1713,7 @@ root_speedo_dev = NULL; cards_found = eepro100_init(NULL); - return cards_found < 0 ? cards_found : 0; + return cards_found ? 0 : -ENODEV; } void @@ -1724,8 +1746,9 @@ /* * Local variables: - * compile-command: "gcc -DCONFIG_MODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c" + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c" * c-indent-level: 4 + * c-basic-offset: 4 * tab-width: 4 * End: */ diff -urN linux-2.0.31pre9/drivers/net/eql.c linux-2.0.31pre9-privs/drivers/net/eql.c --- linux-2.0.31pre9/drivers/net/eql.c Sun Sep 7 16:04:00 1997 +++ linux-2.0.31pre9-privs/drivers/net/eql.c Sun Sep 7 10:28:17 1997 @@ -119,6 +119,7 @@ #include #include +#include #include #include #include @@ -348,7 +349,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.31pre9/drivers/net/ewrk3.c linux-2.0.31pre9-privs/drivers/net/ewrk3.c --- linux-2.0.31pre9/drivers/net/ewrk3.c Tue Apr 8 08:47:46 1997 +++ linux-2.0.31pre9-privs/drivers/net/ewrk3.c Sun Sep 7 10:28:17 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.31pre9/drivers/net/pi2.c linux-2.0.31pre9-privs/drivers/net/pi2.c --- linux-2.0.31pre9/drivers/net/pi2.c Thu Feb 29 21:50:45 1996 +++ linux-2.0.31pre9-privs/drivers/net/pi2.c Sun Sep 7 10:28:17 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.31pre9/drivers/net/ppp.c linux-2.0.31pre9-privs/drivers/net/ppp.c --- linux-2.0.31pre9/drivers/net/ppp.c Sun Sep 7 16:04:02 1997 +++ linux-2.0.31pre9-privs/drivers/net/ppp.c Sun Sep 7 10:28:17 1997 @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include @@ -2247,7 +2248,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.31pre9/drivers/net/pt.c linux-2.0.31pre9-privs/drivers/net/pt.c --- linux-2.0.31pre9/drivers/net/pt.c Thu Apr 11 23:49:38 1996 +++ linux-2.0.31pre9-privs/drivers/net/pt.c Sun Sep 7 10:28:17 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.31pre9/drivers/net/tulip.c linux-2.0.31pre9-privs/drivers/net/tulip.c --- linux-2.0.31pre9/drivers/net/tulip.c Sun Sep 7 16:04:02 1997 +++ linux-2.0.31pre9-privs/drivers/net/tulip.c Sun Sep 7 10:26:52 1997 @@ -1,5 +1,6 @@ /* tulip.c: A DEC 21040-family ethernet driver for linux. */ /* + NOTICE: THIS IS THE ALPHA TEST VERSION! Written 1994-1997 by Donald Becker. This software may be used and distributed according to the terms @@ -16,7 +17,7 @@ http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html */ -static const char *version = "tulip.c:v0.78 7/25/97 becker@cesdis.gsfc.nasa.gov\n"; +static const char *version = "tulip.c:v0.79 9/3/97 becker@cesdis.gsfc.nasa.gov\n"; /* A few user-configurable values. */ @@ -35,7 +36,7 @@ #define RX_RING_SIZE 16 /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ -#define SKBUFF_RX_COPYBREAK 200 +static const rx_copybreak = 200; /* The following example shows how to always use the 10base2 port. */ #ifdef notdef @@ -176,12 +177,12 @@ compile time by RX/TX_RING_SIZE. This version of the driver allocates skbuffs for the Rx ring buffers at open() time and passes the skb->data field to the Tulip as receive data buffers. When an incoming frame is less than -SKBUFF_RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is +RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is copied to the new skbuff. When the incoming frame is larger, the skbuff is passed directly up the protocol stack and replaced by a newly allocated skbuff. -The SKBUFF_RX_COPYBREAK value is chosen to trade-off the memory wasted by +The RX_COPYBREAK value is chosen to trade-off the memory wasted by using a full-sized skbuff for small frames vs. the copying costs of larger frames. For small frames the copying cost is negligible (esp. considering that we are pre-loading the cache with immediately useful header @@ -279,7 +280,7 @@ "10baseT", "10base2", "AUI", "100baseTx", "10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx", "100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII", - "", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", + "10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4", }; /* A full-duplex map for above. */ static const char media_fd[] = @@ -300,6 +301,14 @@ CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 }; +/* The bits in the CSR5 status registers, mostly interrupt sources. */ +enum status_bits { + TimerInt=0x800, TPLnkFail=0x1000, TPLnkPass=0x10, + RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40, + TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, + TxIntr=0x01, +}; + /* The Tulip Rx and Tx buffer descriptors. */ struct tulip_rx_desc { s32 status; @@ -348,7 +357,11 @@ int setup_frame[48]; /* Pseudo-Tx frame to init address table. */ int chip_id; int revision; +#if LINUX_VERSION_CODE > 0x20139 + struct net_device_stats stats; +#else struct enet_statistics stats; +#endif struct timer_list timer; /* Media selection timer. */ unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ @@ -360,15 +373,16 @@ unsigned int mediasense:1; /* Media sensing in progress. */ unsigned int csr6; /* Current CSR6 control settings. */ unsigned char eeprom[128]; /* Serial EEPROM contents. */ + signed char phys[4]; /* MII device addresses. */ struct mediatable *mtable; int cur_index; /* Current media index. */ + unsigned char pci_bus, pci_device_fn; int pad0, pad1; /* Used for 8-byte alignment */ }; -#ifdef MODULE /* Used to pass the full-duplex flag, etc. */ -static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -#endif +static int full_duplex[8] = {0, }; +static int options[8] = {0, }; static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq, int chip_id, int options); @@ -448,12 +462,12 @@ if (device == tulip_tbl[chip_idx].device_id) break; if (tulip_tbl[chip_idx].chip_name == 0) { - printk("Unknown Digital PCI ethernet chip type %4.4x detected:" - " not configured.\n", device); + printk(KERN_INFO "Unknown Digital PCI ethernet chip type" + " %4.4x"" detected: not configured.\n", device); continue; } if (tulip_debug > 2) - printk("Found DEC PCI Tulip at I/O %#x, IRQ %d.\n", + printk(KERN_DEBUG "Found DEC PCI Tulip at I/O %#x, IRQ %d.\n", pci_ioaddr, pci_irq_line); if (check_region(pci_ioaddr, TULIP_TOTAL_SIZE)) @@ -461,10 +475,9 @@ #ifdef MODULE dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, - options[cards_found]); + cards_found); #else - dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, - dev ? dev->mem_start : 0); + dev = tulip_probe1(dev, pci_ioaddr, pci_irq_line, chip_idx, -1); #endif if (dev) { @@ -472,7 +485,7 @@ pcibios_read_config_word(pci_bus, pci_device_fn, PCI_COMMAND, &pci_command); if ( ! (pci_command & PCI_COMMAND_MASTER)) { - printk(" PCI Master Bit has not been set! Setting...\n"); + printk(KERN_INFO " PCI Master Bit has not been set! Setting...\n"); pci_command |= PCI_COMMAND_MASTER; pcibios_write_config_word(pci_bus, pci_device_fn, PCI_COMMAND, pci_command); @@ -480,12 +493,13 @@ pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 10) { - printk(" PCI latency timer (CFLT) is unreasonably low at %d." - " Setting to 64 clocks.\n", pci_latency); + printk(KERN_INFO " PCI latency timer (CFLT) is unreasonably" + " low at %d. Setting to 64 clocks.\n", pci_latency); pcibios_write_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, 64); } else if (tulip_debug > 1) - printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency); + printk(KERN_INFO " PCI latency timer (CFLT) is %#x.\n", + pci_latency); /* Bring the 21143 out power-down mode. */ if (device == PCI_DEVICE_ID_DEC_TULIP_21142) pcibios_write_config_dword(pci_bus, pci_device_fn, @@ -496,15 +510,11 @@ } } -#if defined (MODULE) - return cards_found; -#else - return cards_found > 0 ? 0 : -ENODEV; -#endif + return cards_found ? 0 : -ENODEV; } static struct device *tulip_probe1(struct device *dev, int ioaddr, int irq, - int chip_id, int options) + int chip_id, int board_idx) { static int did_version = 0; /* Already printed version info. */ struct tulip_private *tp; @@ -515,11 +525,11 @@ unsigned short sum; if (tulip_debug > 0 && did_version++ == 0) - printk(version); + printk(KERN_INFO "%s", version); dev = init_etherdev(dev, 0); - printk("%s: DEC %s at %#3x,", + printk(KERN_INFO "%s: DEC %s at %#3x,", dev->name, tulip_tbl[chip_id].chip_name, ioaddr); /* Stop the chip's Tx and Rx processes. */ @@ -585,7 +595,7 @@ } for (i = 0; i < 6; i++) printk(" %2.2x", last_phys_addr[i] = dev->dev_addr[i]); - printk(", IRQ %d\n", irq); + printk(", IRQ %d.\n", irq); last_irq = irq; /* We do a request_region() only to register /proc/ioports info. */ @@ -617,11 +627,36 @@ #endif /* The lower four bits are the media type. */ - if (options > 0) { - tp->full_duplex = (options & 16) ? 1 : 0; - tp->default_port = options & 15; + if (board_idx >= 0) { + tp->full_duplex = (options[board_idx]&16) || full_duplex[board_idx]>0; + tp->default_port = options[board_idx] & 15; if (tp->default_port) - tp->medialock = 1; + tp->medialock = 1; + } + + /* This is logically part of probe1(), but too complex to write inline. */ + if (chip_id != DC21040) + parse_eeprom(dev); + + if (tp->mtable && tp->mtable->has_mii) { + int phy, phy_idx; + /* Find the connected MII xcvrs. + Doing this in open() would allow detecting external xcvrs later, + but takes much time. */ + for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); + phy++) { + int mii_status = mdio_read(ioaddr, phy, 0); + if (mii_status != 0xffff && mii_status != 0x0000) { + tp->phys[phy_idx++] = phy; + printk(KERN_INFO "%s: MII transceiver found at MDIO address %d.\n", + dev->name, phy); + } + } + if (phy_idx == 0) { + printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n", + dev->name); + tp->phys[0] = 1; + } } /* The Tulip-specific entries in the device structure. */ @@ -633,10 +668,6 @@ dev->set_multicast_list = &set_multicast_list; #endif - /* This is logically part of probe1(), but too complex to write inline. */ - if (chip_id != DC21040) - parse_eeprom(dev); - /* Reset the xcvr interface and turn on heartbeat. */ switch (chip_id) { case DC21041: @@ -708,9 +739,8 @@ { static int done_did_that = 0; if (done_did_that++ == 0) - printk("\n THIS IS AN ALPHA TEST DRIVER.\n" - " The following verbose information is emitted for\n" - " bug reports on media selection.\n"); + printk(KERN_INFO" The following verbose information is emitted for\n" + KERN_INFO" bug reports on media selection.\n"); } tp->mtable = 0; for (i = 0; i < EEPROM_SIZE/2; i++) @@ -725,13 +755,13 @@ if (ee_data[0] == 0xff) { if (last_mediatable) { controller_index++; - printk("%s: Controller %d of multiport board.\n", + printk(KERN_INFO "%s: Controller %d of multiport board.\n", dev->name, controller_index); tp->mtable = last_mediatable; ee_data = last_ee_data; goto subsequent_board; } else - printk("%s: Missing EEPROM, this device may not work correctly!\n", + printk(KERN_INFO "%s: Missing EEPROM, this device may not work correctly!\n", dev->name); return; } @@ -744,22 +774,22 @@ i++; /* An Accton EN1207, not an outlaw Maxtech. */ memcpy(ee_data + 26, eeprom_fixups[i].newtable, sizeof(eeprom_fixups[i].newtable)); - printk("\n%s: Old format EEPROM on '%s' board. Using substitute" - " media control info.\n", + printk(KERN_INFO "%s: Old format EEPROM on '%s' board. Using" + " substitute media control info.\n", dev->name, eeprom_fixups[i].name); break; } } if (eeprom_fixups[i].name == NULL) { /* No fixup found. */ - printk("\n %s: Old style EEPROM -- no media selection information.\n", + printk(KERN_INFO "%s: Old style EEPROM -- no media selection information.\n", dev->name); return; } } if (tulip_debug > 1) { - printk("\nread_eeprom:"); + printk(KERN_DEBUG "\nread_eeprom:"); for (i = 0; i < 64; i++) { - printk("%c%4.4x", (i & 7) == 0 ? '\n':' ', + printk("%s%4.4x", (i & 7) == 0 ? "\n" KERN_DEBUG : " ", read_eeprom(ioaddr, i)); } printk("\n"); @@ -776,13 +806,13 @@ short media = *(u16 *)p; int count = p[2]; - printk("%s:21041 Media information at %d, default media %4.4x" - " (%s).\n", dev->name, ee_data[27], media, + printk(KERN_INFO "%s:21041 Media information at %d, default media " + "%4.4x (%s).\n", dev->name, ee_data[27], media, media & 0x0800 ? "Autosense" : medianame[media & 15]); for (i = 0; i < count; i++) { unsigned char media_code = p[3 + i*7]; unsigned short *csrvals = (unsigned short *)&p[3 + i*7 + 1]; - printk("%s: 21041 media %2.2x (%s)," + printk(KERN_INFO "%s: 21041 media %2.2x (%s)," " csr13 %4.4x csr14 %4.4x csr15 %4.4x.\n", dev->name, media_code & 15, medianame[media_code & 15], csrvals[0], csrvals[1], csrvals[2]); @@ -808,7 +838,7 @@ mtable->csr12dir = csr12dir; mtable->has_mii = 0; - printk("%s: EEPROM default media type %s.\n", dev->name, + printk(KERN_INFO "%s: EEPROM default media type %s.\n", dev->name, media & 0x0800 ? "Autosense" : medianame[media & 15]); for (i = 0; i < count; i++) { struct medialeaf *leaf = &mtable->mleaf[i]; @@ -830,20 +860,22 @@ } if (tulip_debug > 1 && leaf->media == 11) { unsigned char *bp = leaf->leafdata; - printk("%s: MII interface PHY %d, setup/reset sequences" - " %d/%d long, capabilities %2.2x %2.2x.\n", + printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " + "sequences %d/%d long, capabilities %2.2x %2.2x.\n", dev->name, bp[0], bp[1], bp[1 + bp[1]*2], bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); - if (tulip_debug > 2) { /* DEBUG only, should be > 3 */ + if (tulip_debug > 2) { int mii_reg; - printk("%s: MII xcvr control registers:", dev->name); + printk(KERN_DEBUG "%s: MII xcvr control registers:", + dev->name); for (mii_reg = 0; mii_reg < 32; mii_reg++) printk(" %4.4x", mdio_read(ioaddr,bp[0], mii_reg)); printk(".\n"); } } - printk("%s: Index #%d - Media %s (#%d) described by a %s (%d) block.\n", + printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " + "by a %s (%d) block.\n", dev->name, i, medianame[leaf->media], leaf->media, block_name[leaf->type], leaf->type); } @@ -913,35 +945,59 @@ MDIO protocol. It is just different enough from the EEPROM protocol to not share code. The maxium data clock rate is 2.5 Mhz. */ #define MDIO_SHIFT_CLK 0x10000 -#define MDIO_DATA_WRITE 0x20000 -#define MDIO_ENB 0x40000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */ +#define MDIO_ENB_IN 0x40000 #define MDIO_DATA_READ 0x80000 +#ifdef _LINUX_DELAY_H +#define mdio_delay() udelay(1) +#else +#define mdio_delay() __SLOW_DOWN_IO +#endif + static int mdio_read(int ioaddr, int phy_id, int location) { int i; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; unsigned short retval = 0; - int ee_addr = ioaddr + CSR9; + int mdio_addr = ioaddr + CSR9; + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); + mdio_delay(); + outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + } /* Shift the read command bits out. */ - for (i = 18; i >= 0; i--) { - int dataval = - (read_cmd & (1 << i)) ? MDIO_DATA_WRITE : 0; + for (i = 17; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; - outl(MDIO_ENB | dataval, ee_addr); - eeprom_delay(100); - outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, ee_addr); - eeprom_delay(250); - outl(MDIO_ENB | dataval, ee_addr); - eeprom_delay(150); - } + outl(dataval, mdio_addr); + mdio_delay(); + outl(dataval | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + outl(dataval, mdio_addr); + mdio_delay(); + } + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + outl(MDIO_ENB_IN, mdio_addr); for (i = 16; i > 0; i--) { - outl(MDIO_SHIFT_CLK, ee_addr); - eeprom_delay(250); - retval = (retval << 1) | ((inl(ee_addr) & MDIO_DATA_READ) ? 1 : 0); - outl(0, ee_addr); - eeprom_delay(250); + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 16; i > 0; i--) { + outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); + mdio_delay(); + outl(MDIO_ENB_IN, mdio_addr); + mdio_delay(); } return retval; } @@ -975,7 +1031,7 @@ C000 32 longwords 0400 4 longwords Wait the specified 50 PCI cycles after a reset by initializing Tx and Rx queues and the address filter list. */ -#if defined(__alpha) +#if defined(__alpha__) /* ToDo: Alpha setting could be better. */ outl(0x00200000 | 0xE000, ioaddr + CSR0); #else @@ -985,7 +1041,8 @@ #else outl(0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0); if (x86 <= 4) - printk("This is a 386/486 PCI system, setting cache alignment to %x.\n", + printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache " + "alignment to %x.\n", dev->name, 0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000)); #endif #endif @@ -1006,7 +1063,7 @@ #endif if (tulip_debug > 1) - printk("%s: tulip_open() irq %d.\n", dev->name, dev->irq); + printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq); MOD_INC_USE_COUNT; @@ -1052,14 +1109,14 @@ for (i = 0; i < tp->mtable->leafcount; i++) if (tp->mtable->mleaf[i].media == (dev->if_port == 12 ? 0 : dev->if_port)) { - printk("%s: Using user-specified media %s.\n", + printk(KERN_INFO "%s: Using user-specified media %s.\n", dev->name, medianame[dev->if_port]); goto media_picked; } if ((tp->mtable->defaultmedia & 0x0800) == 0) for (i = 0; i < tp->mtable->leafcount; i++) if (tp->mtable->mleaf[i].media == (tp->mtable->defaultmedia & 15)) { - printk("%s: Using EEPROM-set media %s.\n", + printk(KERN_INFO "%s: Using EEPROM-set media %s.\n", dev->name, medianame[tp->mtable->mleaf[i].media]); goto media_picked; } @@ -1087,7 +1144,7 @@ outl(0, ioaddr + CSR2); /* Rx poll demand */ if (tulip_debug > 2) { - printk("%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR13 %8.8x.\n", + printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR13 %8.8x.\n", dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5), inl(ioaddr + CSR13)); } @@ -1109,7 +1166,7 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; struct mediatable *mtable = tp->mtable; u32 new_csr6; - int i; + int check_mii =0, i; if (mtable) { struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index]; @@ -1117,7 +1174,7 @@ switch (mleaf->type) { case 0: /* 21140 non-MII xcvr. */ if (tulip_debug > 1) - printk("%s: Using a 21140 non-MII transceiver with control" + printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control" " setting %2.2x.\n", dev->name, p[1]); dev->if_port = p[0]; @@ -1131,23 +1188,24 @@ outl(mtable->csr12dir | 0x100, ioaddr + CSR12); dev->if_port = 11; if (tulip_debug > 2) - printk("%s: Doing a reset sequence of length %d.\n", + printk(KERN_DEBUG "%s: Doing a reset sequence of length %d.\n", dev->name, p[2 + p[1]]); for (i = 0; i < p[2 + p[1]]; i++) outl(p[3 + p[1] + i], ioaddr + CSR12); if (tulip_debug > 2) - printk("%s Doing a transceiver setup sequence of length %d.\n", + printk(KERN_DEBUG "%s Doing a transceiver setup sequence of length %d.\n", dev->name, p[1]); for (i = 0; i < p[1]; i++) outl(p[2 + i], ioaddr + CSR12); } + check_mii = 1; new_csr6 = 0x020C0000; break; case 2: case 4: { u16 *setup = (u16*)&p[1]; dev->if_port = p[0] & 15; if (tulip_debug > 1) - printk("%s: 21142 non-MII %s transceiver control %4.4x/%4.4x.\n", + printk(KERN_DEBUG "%s: 21142 non-MII %s transceiver control %4.4x/%4.4x.\n", dev->name, medianame[dev->if_port], setup[0], setup[1]); if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */ outl(0, ioaddr + CSR13); @@ -1175,24 +1233,25 @@ dev->if_port = 11; if (startup) { if (tulip_debug > 2) - printk("%s: Doing a 21142 reset sequence of length %d.\n", + printk(KERN_DEBUG "%s: Doing a 21142 reset sequence of length %d.\n", dev->name, reset_length); for (i = 0; i < reset_length; i++) outl(reset_sequence[i] << 16, ioaddr + CSR15); } if (tulip_debug > 2) - printk("%s: Doing a 21142 xcvr setup sequence of length %d.\n", + printk(KERN_DEBUG "%s: Doing a 21142 xcvr setup sequence of length %d.\n", dev->name, init_length); for (i = 0; i < init_length; i++) outl(init_sequence[i] << 16, ioaddr + CSR15); - new_csr6 = 0x020C0000 | (tp->full_duplex ? 0x0200 : 0); + check_mii = 1; + new_csr6 = 0x020C0000; break; } default: new_csr6 = 0x020C0000; } if (tulip_debug > 1) - printk("%s: Using media type %s, CSR12 is %2.2x.\n", + printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n", dev->name, medianame[dev->if_port], inl(ioaddr + CSR12) & 0xff); } else if (tp->chip_id == DC21140) { @@ -1200,12 +1259,12 @@ new_csr6 = 0x020C0000; dev->if_port = 11; if (tulip_debug > 1) { - printk("%s: Unknown media control, assuming MII, CSR12 %2.2x.\n", + printk(KERN_DEBUG "%s: Unknown media control, assuming MII, CSR12 %2.2x.\n", dev->name, inl(ioaddr + CSR12) & 0xff); } } else if (tp->chip_id == DC21041) { if (tulip_debug > 1) - printk("%s: 21041 using media %s, CSR12 is %4.4x.\n", + printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n", dev->name, medianame[dev->if_port & 15], inl(ioaddr + CSR12) & 0xffff); outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */ @@ -1217,7 +1276,7 @@ /* Turn on the xcvr interface. */ int csr12 = inl(ioaddr + CSR12); if (tulip_debug > 1) - printk("%s: 21040 media type is %s, CSR12 is %2.2x.\n", + printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n", dev->name, dev->if_port ? "AUI" : "10baseT", csr12); new_csr6 = (dev->if_port ? 0x01860000 : 0x00420000); /* Set the full duplux match frame. */ @@ -1239,7 +1298,7 @@ int next_tick = 0; if (tulip_debug > 3) { - printk("%s: Media selection tick, status %8.8x mode %8.8x " + printk(KERN_DEBUG "%s: Media selection tick, status %8.8x mode %8.8x " "SIA %8.8x %8.8x %8.8x %8.8x.\n", dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13), @@ -1248,7 +1307,7 @@ switch (tp->chip_id) { case DC21040: if (csr12 & 0x0002) { /* Network error */ - printk("%s: No 10baseT link beat found, switching to %s media.\n", + printk(KERN_INFO "%s: No 10baseT link beat found, switching to %s media.\n", dev->name, dev->if_port ? "10baseT" : "AUI"); dev->if_port ^= 1; outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13); @@ -1257,7 +1316,7 @@ break; case DC21041: if (tulip_debug > 2) - printk("%s: 21041 media tick CSR12 %8.8x.\n", + printk(KERN_DEBUG "%s: 21041 media tick CSR12 %8.8x.\n", dev->name, csr12); switch (dev->if_port) { case 0: case 3: case 4: @@ -1268,7 +1327,7 @@ dev->if_port = 2; else dev->if_port = 1; - printk("%s: No 21041 10baseT link beat, Media switched to %s.\n", + printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n", dev->name, medianame[dev->if_port]); outl(0, ioaddr + CSR13); /* Reset */ outl(t21041_csr14[dev->if_port], ioaddr + CSR14); @@ -1284,7 +1343,7 @@ next_tick = (30*HZ); /* 30 sec. */ tp->mediasense = 0; } else if ((csr12 & 0x0004) == 0) { - printk("%s: 21041 media switched to 10baseT.\n", dev->name); + printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n", dev->name); dev->if_port = 0; select_media(dev, 0); next_tick = (24*HZ)/10; /* 2.4 sec. */ @@ -1309,7 +1368,7 @@ /* Stop the transmit process. */ tp->csr6 = (dev->if_port ? 0x03860000 : 0x02420000); outl(tp->csr6 | 0x0002, ioaddr + CSR6); - printk("%s: link beat timed out, CSR12 is 0x%2.2x, switching to" + printk(KERN_INFO "%s: link beat timed out, CSR12 is 0x%2.2x, switching to" " %s media.\n", dev->name, csr12 & 0xff, dev->if_port ? "100baseTx" : "10baseT"); @@ -1319,7 +1378,7 @@ } else { next_tick = 10*HZ; if (tulip_debug > 2) - printk("%s: network media monitor 0x%2.2x, link" + printk(KERN_DEBUG "%s: network media monitor 0x%2.2x, link" " beat detected as %s.\n", dev->name, csr12 & 0xff, dev->if_port ? "100baseTx" : "10baseT"); @@ -1333,7 +1392,7 @@ /* Type 0 non-MII or #4 SYM transceiver. Check the link beat bit. */ s8 bitnum = p[mleaf->type == 4 ? 5 : 2]; if (tulip_debug > 2) - printk("%s: Transceiver monitor tick: CSR12=%#2.2x bit %d is" + printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x bit %d is" " %d, expecting %d.\n", dev->name, csr12, (bitnum >> 1) & 7, (csr12 & (1 << ((bitnum >> 1) & 7))) != 0, @@ -1342,7 +1401,7 @@ if ((bitnum < 0) != ((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) { if (tulip_debug > 1) - printk("%s: Link beat detected for %s.\n", dev->name, + printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name, medianame[mleaf->media]); break; } @@ -1357,7 +1416,7 @@ if (media_fd[dev->if_port]) goto select_next_media; /* Skip FD entries. */ if (tulip_debug > 1) - printk("%s: No link beat on media %s," + printk(KERN_DEBUG "%s: No link beat on media %s," " trying transceiver type %s.\n", dev->name, medianame[mleaf->media & 15], medianame[tp->mtable->mleaf[tp->cur_index].media]); @@ -1369,16 +1428,32 @@ break; } case 1: - printk(" %s: MII monitoring tick: CSR12 status %2.2x.\n", - dev->name, csr12); + { + int mii_reg5 = mdio_read(ioaddr, tp->phys[0], 5); + printk(KERN_INFO "%s: MII monitoring tick: CSR12 %2.2x, " + "Link partner report %4.4x.\n", + dev->name, csr12, mii_reg5); + if (mii_reg5 != 0xffff + && mdio_read(ioaddr, tp->phys[0], 1) & 0x0020) { + int full_duplex = mii_reg5 & 0x0100 ? 1 : 0; + if (full_duplex != tp->full_duplex) { + tp->full_duplex = full_duplex; + tp->csr6 ^= 0x0200; + outl(tp->csr6 | 0x0002, ioaddr + CSR6); + outl(tp->csr6 | 0x2002, ioaddr + CSR6); + } + if (tulip_debug > 0) /* Gurppp, should be >1 */ + printk(KERN_INFO "%s: Setting %s-duplex based on MII" + " Xcvr #%d parter capability of %4.4x.\n", + dev->name, full_duplex ? "full" : "half", + tp->phys[0], mii_reg5); + } + } + /* Hack for D-Link: Full duplex indication is on bit 3. */ if (dev->dev_addr[0] == 0 && dev->dev_addr[1] == 0x80 && dev->dev_addr[2] == 0xC8) { - /* The first message is for information only. */ - if (tp->full_duplex) { - printk("%s: D-Link card in full-duplex mode, csr6 setting" - " %8.8x.\n", dev->name, tp->csr6); - } else if (csr12 & 0x08) { + if (csr12 & 0x08) { tp->full_duplex = 0; tp->csr6 &= ~0x0200; outl(tp->csr6 | 0x0002, ioaddr + CSR6); @@ -1386,7 +1461,6 @@ } else { tp->full_duplex = 1; tp->csr6 |= 0x0200; - printk("%s: Switching D-Link card to full-duplex.\n", dev->name); outl(tp->csr6 | 0x0002, ioaddr + CSR6); outl(tp->csr6 | 0x2002, ioaddr + CSR6); } @@ -1413,15 +1487,15 @@ { struct tulip_private *tp = (struct tulip_private *)dev->priv; int ioaddr = dev->base_addr; - int i; if (tp->mtable && tp->mtable->has_mii) { /* Do nothing -- the media monitor should handle this. */ if (tulip_debug > 1) - printk("%s: Transmit timeout using MII device.\n", dev->name); + printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", + dev->name); } else if (tp->chip_id == DC21040) { if (inl(ioaddr + CSR12) & 0x0002) { - printk("%s: transmit timed out, switching to %s media.\n", + printk(KERN_INFO "%s: transmit timed out, switching to %s media.\n", dev->name, dev->if_port ? "10baseT" : "AUI"); dev->if_port ^= 1; outl(dev->if_port ? 0x0000000C : 0x00000004, ioaddr + CSR13); @@ -1432,10 +1506,11 @@ /* Stop the transmit process. */ outl(tp->csr6 | 0x0002, ioaddr + CSR6); dev->if_port ^= 1; - printk("%s: 21140 transmit timed out, status %8.8x, SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", + printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " + "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12), inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15)); - printk("%s: transmit timed out, switching to %s media.\n", + printk(KERN_WARNING "%s: transmit timed out, switching to %s media.\n", dev->name, dev->if_port ? "100baseTx" : "10baseT"); outl(tp->csr6 | 0x2002, ioaddr + CSR6); tp->stats.tx_errors++; @@ -1444,7 +1519,7 @@ } else if (tp->chip_id == DC21041) { u32 csr12 = inl(ioaddr + CSR12); - printk("%s: 21041 transmit timed out, status %8.8x, CSR12 %8.8x," + printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, CSR12 %8.8x," " CSR13 %8.8x, CSR14 %8.8x, resetting...\n", dev->name, inl(ioaddr + CSR5), csr12, inl(ioaddr + CSR13), inl(ioaddr + CSR14)); @@ -1461,10 +1536,10 @@ dev->trans_start = jiffies; return; } else - printk("%s: transmit timed out, status %8.8x, CSR12 %8.8x," + printk(KERN_WARNING "%s: transmit timed out, status %8.8x, CSR12 %8.8x," " resetting...\n", dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12)); -#ifndef __alpha__ +#ifdef way_too_many_messages printk(" Rx ring %8.8x: ", (int)tp->rx_ring); for (i = 0; i < RX_RING_SIZE; i++) printk(" %8.8x", (unsigned int)tp->rx_ring[i].status); @@ -1543,7 +1618,7 @@ #ifndef final_version if (skb == NULL || skb->len <= 0) { - printk("%s: Obsolete driver layer request made: skbuff==NULL.\n", + printk(KERN_ERR "%s: Obsolete driver layer request made: skbuff==NULL.\n", dev->name); dev_tint(dev); return 0; @@ -1607,7 +1682,7 @@ #endif struct tulip_private *lp; - int csr5, ioaddr, boguscnt = 10; + int csr5, ioaddr, boguscnt = 12; if (dev == NULL) { printk ("tulip_interrupt(): irq %d for unknown device.\n", irq); @@ -1617,7 +1692,7 @@ ioaddr = dev->base_addr; lp = (struct tulip_private *)dev->priv; if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); + printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); dev->interrupt = 1; @@ -1627,7 +1702,7 @@ outl(csr5 & 0x0001ffff, ioaddr + CSR5); if (tulip_debug > 4) - printk("%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x.\n", dev->name, csr5, inl(dev->base_addr + CSR5)); if ((csr5 & 0x00018000) == 0) @@ -1653,7 +1728,7 @@ /* There was an major error, log it. */ #ifndef final_version if (tulip_debug > 1) - printk("%s: Transmit error, Tx status %8.8x.\n", + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", dev->name, status); #endif lp->stats.tx_errors++; @@ -1681,7 +1756,7 @@ #ifndef final_version if (lp->cur_tx - dirty_tx > TX_RING_SIZE) { - printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n", dev->name, dirty_tx, lp->cur_tx, lp->tx_full); dirty_tx += TX_RING_SIZE; } @@ -1712,7 +1787,7 @@ lp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; } if (csr5 & 0x0800) { - printk("%s: Something Wicked happened! %8.8x.\n", + printk(KERN_ERR "%s: Something Wicked happened! %8.8x.\n", dev->name, csr5); /* Hmmmmm, it's not clear what to do here. */ } @@ -1720,7 +1795,7 @@ outl(0x000f7ba, ioaddr + CSR5); } if (--boguscnt < 0) { - printk("%s: Too much work at interrupt, csr5=0x%8.8x.\n", + printk(KERN_WARNING "%s: Too much work at interrupt, csr5=0x%8.8x.\n", dev->name, csr5); /* Clear all interrupt sources. */ outl(0x0001ffff, ioaddr + CSR5); @@ -1729,15 +1804,17 @@ } while (1); if (tulip_debug > 3) - printk("%s: exiting interrupt, csr5=%#4.4x.\n", + printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n", dev->name, inl(ioaddr + CSR5)); /* Code that should never be run! Perhaps remove after testing.. */ { static int stopit = 10; if (dev->start == 0 && --stopit < 0) { - printk("%s: Emergency stop, looping startup interrupt.\n", - dev->name); + printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n" + KERN_ERR "%s: Disabling interrupt handler %d to avoid " + "locking up the machine.\n", + dev->name, dev->name, dev->irq); #ifdef SA_SHIRQ free_irq(irq, dev); #else @@ -1757,18 +1834,16 @@ int entry = lp->cur_rx % RX_RING_SIZE; if (tulip_debug > 4) - printk(" In tulip_rx(), entry %d %8.8x.\n", entry, + printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry, lp->rx_ring[entry].status); /* If we own the next entry, it's a new packet. Send it up. */ while (lp->rx_ring[entry].status >= 0) { int status = lp->rx_ring[entry].status; - if (tulip_debug > 4) - printk(" tulip_rx() status was %8.8x.\n", status); if ((status & 0x0300) != 0x0300) { if ((status & 0xffff) != 0x7fff) { /* Ingore earlier buffers. */ - printk("%s: Oversized Ethernet frame spanned multiple buffers," - " status %8.8x!\n", dev->name, status); + printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " + "multiple buffers, status %8.8x!\n", dev->name, status); lp->stats.rx_length_errors++; } } else if (status & 0x8000) { @@ -1787,7 +1862,7 @@ /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ - if (pkt_len > SKBUFF_RX_COPYBREAK) { + if (pkt_len > rx_copybreak) { struct sk_buff *newskb; char *temp; @@ -1801,7 +1876,8 @@ skb = lp->rx_skbuff[entry]; temp = skb_put(skb, pkt_len); if (bus_to_virt(lp->rx_ring[entry].buffer1) != temp) - printk("%s: Warning -- the skbuff addresses do not match" + printk(KERN_ERR "%s: Internal consistency error -- the " + "skbuff addresses do not match" " in tulip_rx: %p vs. %p / %p.\n", dev->name, bus_to_virt(lp->rx_ring[entry].buffer1), skb->head, temp); @@ -1815,7 +1891,8 @@ memory_squeeze: if (skb == NULL) { int i; - printk("%s: Memory squeeze, deferring packet.\n", dev->name); + printk(KERN_WARNING "%s: Memory squeeze, deferring packet.\n", + dev->name); /* Check that at least two ring entries are free. If not, free one and mark stats->rx_dropped++. */ for (i = 0; i < RX_RING_SIZE; i++) @@ -1862,7 +1939,7 @@ dev->tbusy = 1; if (tulip_debug > 1) - printk("%s: Shutting down ethercard, status was %2.2x.\n", + printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inl(ioaddr + CSR5)); /* Disable interrupts by clearing the interrupt mask. */ @@ -1964,7 +2041,7 @@ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ outl(csr6 | 0x00C0, ioaddr + CSR6); /* Unconditionally log net taps. */ - printk("%s: Promiscuous mode enabled.\n", dev->name); + printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); tp->csr6 |= 0xC0; } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ @@ -2057,6 +2134,13 @@ } #ifdef MODULE +#if LINUX_VERSION_CODE > 0x20118 +MODULE_PARM(debug, "i"); +MODULE_PARM(reverse_probe, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +#endif /* An additional parameter that may be passed in... */ static int debug = -1; @@ -2064,15 +2148,11 @@ int init_module(void) { - int cards_found; - if (debug >= 0) tulip_debug = debug; root_tulip_dev = NULL; - cards_found = tulip_probe(0); - - return cards_found ? 0 : -ENODEV; + return tulip_probe(NULL); } void @@ -2094,7 +2174,7 @@ /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c" + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c tulip.c" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -urN linux-2.0.31pre9/drivers/net/wavelan.c linux-2.0.31pre9-privs/drivers/net/wavelan.c --- linux-2.0.31pre9/drivers/net/wavelan.c Sun Sep 7 16:04:02 1997 +++ linux-2.0.31pre9-privs/drivers/net/wavelan.c Sun Sep 7 10:28:17 1997 @@ -1950,7 +1950,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, @@ -2012,8 +2012,8 @@ break; } - /* only super-user can see encryption key */ - if(!suser()) + /* only those permitted to configure device can see encryption key */ + if(!capable(CAP_NET_IFCONFIG)) { ret = -EPERM; break; @@ -2210,7 +2210,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, @@ -2227,7 +2227,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.31pre9/drivers/sbus/char/sunserial.c linux-2.0.31pre9-privs/drivers/sbus/char/sunserial.c --- linux-2.0.31pre9/drivers/sbus/char/sunserial.c Mon May 6 02:26:09 1996 +++ linux-2.0.31pre9-privs/drivers/sbus/char/sunserial.c Sun Sep 7 10:28:17 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.31pre9/drivers/scsi/scsi_ioctl.c linux-2.0.31pre9-privs/drivers/scsi/scsi_ioctl.c --- linux-2.0.31pre9/drivers/scsi/scsi_ioctl.c Sun Sep 7 16:04:10 1997 +++ linux-2.0.31pre9-privs/drivers/scsi/scsi_ioctl.c Sun Sep 7 10:28:17 1997 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -349,13 +350,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; @@ -363,7 +364,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.31pre9/drivers/scsi/sd_ioctl.c linux-2.0.31pre9-privs/drivers/scsi/sd_ioctl.c --- linux-2.0.31pre9/drivers/scsi/sd_ioctl.c Wed May 1 21:48:54 1996 +++ linux-2.0.31pre9-privs/drivers/scsi/sd_ioctl.c Sun Sep 7 10:28:17 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.31pre9/drivers/scsi/sr.c linux-2.0.31pre9-privs/drivers/scsi/sr.c --- linux-2.0.31pre9/drivers/scsi/sr.c Sun Sep 7 16:04:10 1997 +++ linux-2.0.31pre9-privs/drivers/scsi/sr.c Sun Sep 7 10:28:17 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.31pre9/drivers/scsi/sr_ioctl.c linux-2.0.31pre9-privs/drivers/scsi/sr_ioctl.c --- linux-2.0.31pre9/drivers/scsi/sr_ioctl.c Sun Sep 7 16:04:10 1997 +++ linux-2.0.31pre9-privs/drivers/scsi/sr_ioctl.c Sun Sep 7 10:28:17 1997 @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -566,7 +567,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.31pre9/drivers/scsi/st.c linux-2.0.31pre9-privs/drivers/scsi/st.c --- linux-2.0.31pre9/drivers/scsi/st.c Sun Sep 7 16:04:10 1997 +++ linux-2.0.31pre9-privs/drivers/scsi/st.c Sun Sep 7 10:28:18 1997 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -2532,7 +2533,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.31pre9/drivers/sound/Config.in linux-2.0.31pre9-privs/drivers/sound/Config.in --- linux-2.0.31pre9/drivers/sound/Config.in Wed Jul 10 04:34:03 1996 +++ linux-2.0.31pre9-privs/drivers/sound/Config.in Sun Sep 7 10:30:19 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.31pre9/fs/Config.in linux-2.0.31pre9-privs/fs/Config.in --- linux-2.0.31pre9/fs/Config.in Sun Sep 7 16:04:11 1997 +++ linux-2.0.31pre9-privs/fs/Config.in Sun Sep 7 10:28:18 1997 @@ -5,6 +5,12 @@ comment 'Filesystems' bool 'Quota support' CONFIG_QUOTA +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Symlink security fix (EXPERIMENTAL)' CONFIG_SYMLINK_FIX + if [ "$CONFIG_SYMLINK_FIX" = "y" ]; then + bool ' Log symlink exploit attempts' CONFIG_SYMLINK_LOG + fi +fi tristate 'Minix fs support' CONFIG_MINIX_FS tristate 'Extended fs support' CONFIG_EXT_FS tristate 'Second extended fs support' CONFIG_EXT2_FS @@ -37,6 +43,9 @@ tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel automounter support (experimental)' CONFIG_AUTOFS_FS +fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS if [ "$CONFIG_AFFS_FS" != "n" ]; then diff -urN linux-2.0.31pre9/fs/Makefile linux-2.0.31pre9-privs/fs/Makefile --- linux-2.0.31pre9/fs/Makefile Sun Sep 7 16:04:11 1997 +++ linux-2.0.31pre9-privs/fs/Makefile Sun Sep 7 10:28:18 1997 @@ -13,11 +13,11 @@ 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 bad_inode.o $(BINFMTS) + dcache.o bad_inode.o file_cap.o $(BINFMTS) MOD_LIST_NAME := FS_MODULES ALL_SUB_DIRS = minix ext ext2 fat msdos vfat proc isofs nfs xiafs umsdos \ - hpfs sysv smbfs ncpfs ufs affs + hpfs sysv smbfs ncpfs ufs affs autofs ifeq ($(CONFIG_QUOTA),y) O_OBJS += dquot.o @@ -154,6 +154,14 @@ else ifeq ($(CONFIG_AFFS_FS),m) MOD_SUB_DIRS += affs + endif +endif + +ifeq ($(CONFIG_AUTOFS_FS),y) +SUB_DIRS += autofs +else + ifeq ($(CONFIG_AUTOFS_FS),m) + MOD_SUB_DIRS += autofs endif endif diff -urN linux-2.0.31pre9/fs/affs/namei.c linux-2.0.31pre9-privs/fs/affs/namei.c --- linux-2.0.31pre9/fs/affs/namei.c Sat Nov 30 02:21:19 1996 +++ linux-2.0.31pre9-privs/fs/affs/namei.c Sun Sep 7 10:28:18 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.31pre9/fs/autofs/Makefile linux-2.0.31pre9-privs/fs/autofs/Makefile --- linux-2.0.31pre9/fs/autofs/Makefile Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/fs/autofs/Makefile Sun Sep 7 10:27:02 1997 @@ -0,0 +1,35 @@ +# +# Makefile for the linux autofs-filesystem routines. +# +# We can build this either out of the kernel tree or the autofs tools tree. +# + +O_TARGET := autofs.o +O_OBJS := dir.o dirhash.o init.o inode.o root.o symlink.o waitq.o + +M_OBJS := $(O_TARGET) + +ifdef TOPDIR +# +# Part of the kernel code +# +include $(TOPDIR)/Rules.make +else +# +# Standalone (handy for development) +# +include ../Makefile.rules + +CFLAGS += -D__KERNEL__ -DMODULE $(KFLAGS) -I../include -I$(KINCLUDE) $(MODFLAGS) + +all: $(O_TARGET) + +$(O_TARGET): $(O_OBJS) + $(LD) -r -o $(O_TARGET) $(O_OBJS) + +install: $(O_TARGET) + install -c $(O_TARGET) /lib/modules/`uname -r`/fs + +clean: + rm -f *.o *.s +endif diff -urN linux-2.0.31pre9/fs/autofs/autofs_i.h linux-2.0.31pre9-privs/fs/autofs/autofs_i.h --- linux-2.0.31pre9/fs/autofs/autofs_i.h Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/fs/autofs/autofs_i.h Sun Sep 7 10:27:02 1997 @@ -0,0 +1,187 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * linux/fs/autofs/autofs_i.h + * + * Copyright 1997 Transmeta Corporation - All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* Internal header file for autofs */ + +#include + +/* This is the range of ioctl() numbers we claim as ours */ +#define AUTOFS_IOC_FIRST AUTOFS_IOC_READY +#define AUTOFS_IOC_COUNT 32 + +#include +#include +#include +#include +#include + +#define kver(a,b,c) (((a) << 16) + ((b) << 8) + (c)) + +#if LINUX_VERSION_CODE < kver(2,1,0) + +/* Segmentation stuff for pre-2.1 kernels */ +#include + +static inline int copy_to_user(void *dst, void *src, unsigned long len) +{ + int rv = verify_area(VERIFY_WRITE, dst, len); + if ( rv ) + return -1; + memcpy_tofs(dst,src,len); + return 0; +} + +static inline int copy_from_user(void *dst, void *src, unsigned long len) +{ + int rv = verify_area(VERIFY_READ, src, len); + if ( rv ) + return -1; + memcpy_fromfs(dst,src,len); + return 0; +} + +#else + +/* Segmentation stuff for post-2.1 kernels */ +#include +#define register_symtab(x) ((void)0) + +#endif + +#ifdef DEBUG +#define DPRINTK(D) printk D; +#else +#define DPRINTK(D) +#endif + +#define AUTOFS_SUPER_MAGIC 0x0187 + +/* Structures associated with the root directory hash */ + +#define AUTOFS_HASH_SIZE 67 + +typedef u32 autofs_hash_t; /* Type returned by autofs_hash() */ + +struct autofs_dir_ent { + autofs_hash_t hash; + struct autofs_dir_ent *next; + struct autofs_dir_ent **back; + char *name; + int len; + ino_t ino; + /* The following entries are for the expiry system */ + unsigned long last_usage; + struct autofs_dir_ent *exp_next; + struct autofs_dir_ent *exp_prev; +}; + +struct autofs_dirhash { + struct autofs_dir_ent *h[AUTOFS_HASH_SIZE]; + struct autofs_dir_ent expiry_head; +}; + +struct autofs_wait_queue { + unsigned long wait_queue_token; + struct wait_queue *queue; + struct autofs_wait_queue *next; + /* We use the following to see what we are waiting for */ + autofs_hash_t hash; + int len; + char *name; + /* This is for status reporting upon return */ + int status; + int wait_ctr; +}; + +struct autofs_symlink { + int len; + char *data; + time_t mtime; +}; + +#define AUTOFS_MAX_SYMLINKS 256 + +#define AUTOFS_ROOT_INO 1 +#define AUTOFS_FIRST_SYMLINK 2 +#define AUTOFS_FIRST_DIR_INO (AUTOFS_FIRST_SYMLINK+AUTOFS_MAX_SYMLINKS) + +#define AUTOFS_SYMLINK_BITMAP_LEN ((AUTOFS_MAX_SYMLINKS+31)/32) + +#ifndef END_OF_TIME +#define END_OF_TIME ((time_t)((unsigned long)((time_t)(~0UL)) >> 1)) +#endif + +#define AUTOFS_SBI_MAGIC 0x6d4a556d + +struct autofs_sb_info { + u32 magic; + struct file *pipe; + pid_t oz_pgrp; + int catatonic; + unsigned long exp_timeout; + ino_t next_dir_ino; + struct autofs_wait_queue *queues; /* Wait queue pointer */ + struct autofs_dirhash dirhash; /* Root directory hash */ + struct autofs_symlink symlink[AUTOFS_MAX_SYMLINKS]; + u32 symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN]; +}; + +/* autofs_oz_mode(): do we see the man behind the curtain? */ +static inline int autofs_oz_mode(struct autofs_sb_info *sbi) { + return sbi->catatonic || current->pgrp == sbi->oz_pgrp; +} + +/* Debug the mysteriously disappearing wait list */ + +#ifdef DEBUG_WAITLIST +#define CHECK_WAITLIST(S,O) autofs_check_waitlist_integrity(S,O) +void autofs_check_waitlist_integrity(struct autofs_sb_info *,char *); +#else +#define CHECK_WAITLIST(S,O) +#endif + +/* Hash operations */ + +autofs_hash_t autofs_hash(const char *,int); +void autofs_initialize_hash(struct autofs_dirhash *); +struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,autofs_hash_t,const char *,int); +void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *); +void autofs_hash_delete(struct autofs_dir_ent *); +struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *); +void autofs_hash_nuke(struct autofs_dirhash *); + +/* Expiration-handling functions */ + +void autofs_update_usage(struct autofs_dirhash *,struct autofs_dir_ent *); +struct autofs_dir_ent *autofs_expire(struct autofs_dirhash *,unsigned long); + +/* Operations structures */ + +extern struct inode_operations autofs_root_inode_operations; +extern struct inode_operations autofs_symlink_inode_operations; +extern struct inode_operations autofs_dir_inode_operations; + +/* Initializing function */ + +struct super_block *autofs_read_super(struct super_block *, void *,int); + +/* Queue management functions */ + +int autofs_wait(struct autofs_sb_info *,autofs_hash_t,const char *,int); +int autofs_wait_release(struct autofs_sb_info *,unsigned long,int); +void autofs_catatonic_mode(struct autofs_sb_info *); + +#ifdef DEBUG +void autofs_say(const char *name, int len); +#else +#define autofs_say(n,l) +#endif diff -urN linux-2.0.31pre9/fs/autofs/dir.c linux-2.0.31pre9-privs/fs/autofs/dir.c --- linux-2.0.31pre9/fs/autofs/dir.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/fs/autofs/dir.c Sun Sep 7 10:27:02 1997 @@ -0,0 +1,90 @@ +/* -*- linux-c -*- --------------------------------------------------------- * + * + * linux/fs/autofs/dir.c + * + * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * ------------------------------------------------------------------------- */ + +#include "autofs_i.h" + +static int autofs_dir_readdir(struct inode *inode, struct file *filp, + void *dirent, filldir_t filldir) +{ + if (!inode || !S_ISDIR(inode->i_mode)) + return -ENOTDIR; + + switch((unsigned long) filp->f_pos) + { + case 0: + if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0) + return 0; + filp->f_pos++; + /* fall through */ + case 1: + if (filldir(dirent, "..", 2, 1, AUTOFS_ROOT_INO) < 0) + return 0; + filp->f_pos++; + /* fall through */ + } + return 1; +} + +static int autofs_dir_lookup(struct inode *dir, const char *name, int len, + struct inode **result) +{ + *result = dir; + if (!len) + return 0; + if (name[0] == '.') { + if (len == 1) + return 0; + if (name[1] == '.' && len == 2) { + /* Return the root directory */ + *result = iget(dir->i_sb,AUTOFS_ROOT_INO); + iput(dir); + return 0; + } + } + *result = NULL; + iput(dir); + return -ENOENT; /* No other entries */ +} + +static struct file_operations autofs_dir_operations = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + autofs_dir_readdir, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* release */ + NULL /* fsync */ +}; + +struct inode_operations autofs_dir_inode_operations = { + &autofs_dir_operations, /* file operations */ + NULL, /* create */ + autofs_dir_lookup, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* read_page */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + diff -urN linux-2.0.31pre9/fs/autofs/dirhash.c linux-2.0.31pre9-privs/fs/autofs/dirhash.c --- linux-2.0.31pre9/fs/autofs/dirhash.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/fs/autofs/dirhash.c Sun Sep 7 10:27:02 1997 @@ -0,0 +1,172 @@ +/* -*- linux-c -*- --------------------------------------------------------- * + * + * linux/fs/autofs/dirhash.c + * + * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * ------------------------------------------------------------------------- */ + +#include "autofs_i.h" + +/* Functions for maintenance of expiry queue */ + +static void autofs_init_usage(struct autofs_dirhash *dh, + struct autofs_dir_ent *ent) +{ + ent->exp_next = &dh->expiry_head; + ent->exp_prev = dh->expiry_head.exp_prev; + dh->expiry_head.exp_prev->exp_next = ent; + dh->expiry_head.exp_prev = ent; + ent->last_usage = jiffies; +} + +static void autofs_delete_usage(struct autofs_dir_ent *ent) +{ + ent->exp_prev->exp_next = ent->exp_next; + ent->exp_next->exp_prev = ent->exp_prev; +} + +void autofs_update_usage(struct autofs_dirhash *dh, + struct autofs_dir_ent *ent) +{ + autofs_delete_usage(ent); /* Unlink from current position */ + autofs_init_usage(dh,ent); /* Relink at queue tail */ +} + +struct autofs_dir_ent *autofs_expire(struct autofs_dirhash *dh, + unsigned long timeout) +{ + struct autofs_dir_ent *ent; + + ent = dh->expiry_head.exp_next; + + if ( ent == &(dh->expiry_head) ) return NULL; + return (jiffies - ent->last_usage >= timeout) ? ent : NULL; +} + +/* Adapted from the Dragon Book, page 436 */ +/* This particular hashing algorithm requires autofs_hash_t == u32 */ +autofs_hash_t autofs_hash(const char *name, int len) +{ + autofs_hash_t h = 0; + while ( len-- ) { + h = (h << 4) + (unsigned char) (*name++); + h ^= ((h & 0xf0000000) >> 24); + } + return h; +} + +void autofs_initialize_hash(struct autofs_dirhash *dh) { + memset(&dh->h, 0, AUTOFS_HASH_SIZE*sizeof(struct autofs_dir_ent *)); + dh->expiry_head.exp_next = dh->expiry_head.exp_prev = + &dh->expiry_head; +} + +struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *dh, autofs_hash_t hash, const char *name, int len) +{ + struct autofs_dir_ent *dhn; + + DPRINTK(("autofs_hash_lookup: hash = 0x%08x, name = ", hash)); + autofs_say(name,len); + + for ( dhn = dh->h[hash % AUTOFS_HASH_SIZE] ; dhn ; dhn = dhn->next ) { + if ( hash == dhn->hash && + len == dhn->len && + !memcmp(name, dhn->name, len) ) + break; + } + + return dhn; +} + +void autofs_hash_insert(struct autofs_dirhash *dh, struct autofs_dir_ent *ent) +{ + struct autofs_dir_ent **dhnp; + + DPRINTK(("autofs_hash_insert: hash = 0x%08x, name = ", ent->hash)); + autofs_say(ent->name,ent->len); + + autofs_init_usage(dh,ent); + + dhnp = &dh->h[ent->hash % AUTOFS_HASH_SIZE]; + ent->next = *dhnp; + ent->back = dhnp; + *dhnp = ent; +} + +void autofs_hash_delete(struct autofs_dir_ent *ent) +{ + *(ent->back) = ent->next; + + autofs_delete_usage(ent); + + kfree(ent->name); + kfree(ent); +} + +/* + * Used by readdir(). We must validate "ptr", so we can't simply make it + * a pointer. Values below 0xffff are reserved; calling with any value + * <= 0x10000 will return the first entry found. + */ +struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh, off_t *ptr) +{ + int bucket, ecount, i; + struct autofs_dir_ent *ent; + + bucket = (*ptr >> 16) - 1; + ecount = *ptr & 0xffff; + + if ( bucket < 0 ) { + bucket = ecount = 0; + } + + DPRINTK(("autofs_hash_enum: bucket %d, entry %d\n", bucket, ecount)); + + ent = NULL; + + while ( bucket < AUTOFS_HASH_SIZE ) { + ent = dh->h[bucket]; + for ( i = ecount ; ent && i ; i-- ) + ent = ent->next; + + if (ent) { + ecount++; /* Point to *next* entry */ + break; + } + + bucket++; ecount = 0; + } + +#ifdef DEBUG + if ( !ent ) + printk("autofs_hash_enum: nothing found\n"); + else { + printk("autofs_hash_enum: found hash %08x, name", ent->hash); + autofs_say(ent->name,ent->len); + } +#endif + + *ptr = ((bucket+1) << 16) + ecount; + return ent; +} + +/* Delete everything. This is used on filesystem destruction, so we + make no attempt to keep the pointers valid */ +void autofs_hash_nuke(struct autofs_dirhash *dh) +{ + int i; + struct autofs_dir_ent *ent, *nent; + + for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) { + for ( ent = dh->h[i] ; ent ; ent = nent ) { + nent = ent->next; + kfree(ent->name); + kfree(ent); + } + } +} diff -urN linux-2.0.31pre9/fs/autofs/init.c linux-2.0.31pre9-privs/fs/autofs/init.c --- linux-2.0.31pre9/fs/autofs/init.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/fs/autofs/init.c Sun Sep 7 10:27:02 1997 @@ -0,0 +1,58 @@ +/* -*- linux-c -*- --------------------------------------------------------- * + * + * linux/fs/autofs/init.c + * + * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * ------------------------------------------------------------------------- */ + +#include +#include "autofs_i.h" + +#if LINUX_VERSION_CODE < kver(2,1,36) +#define __initfunc(X) X +#else +#include +#endif + +static struct file_system_type autofs_fs_type = { + autofs_read_super, "autofs", 0, NULL +}; + +#ifdef MODULE +int init_module(void) +{ + int status; + + if ((status = register_filesystem(&autofs_fs_type)) == 0) + register_symtab(0); + return status; +} + +void cleanup_module(void) +{ + unregister_filesystem(&autofs_fs_type); +} + +#else /* MODULE */ + +__initfunc(int init_autofs_fs(void)) +{ + return register_filesystem(&autofs_fs_type); +} + +#endif /* !MODULE */ + +#ifdef DEBUG +void autofs_say(const char *name, int len) +{ + printk("(%d: ", len); + while ( len-- ) + printk("%c", *name++); + printk(")\n"); +} +#endif diff -urN linux-2.0.31pre9/fs/autofs/inode.c linux-2.0.31pre9-privs/fs/autofs/inode.c --- linux-2.0.31pre9/fs/autofs/inode.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/fs/autofs/inode.c Sun Sep 7 10:27:02 1997 @@ -0,0 +1,277 @@ +/* -*- linux-c -*- --------------------------------------------------------- * + * + * linux/fs/autofs/inode.c + * + * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * ------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include "autofs_i.h" +#define __NO_VERSION__ +#include + +static void autofs_put_inode(struct inode *inode) +{ + if (inode->i_nlink) + return; + inode->i_size = 0; +} + +static void autofs_put_super(struct super_block *sb) +{ + struct autofs_sb_info *sbi = + (struct autofs_sb_info *) sb->u.generic_sbp; + unsigned int n; + + if ( !sbi->catatonic ) + autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */ + + lock_super(sb); + autofs_hash_nuke(&sbi->dirhash); + for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) { + if ( test_bit(n, sbi->symlink_bitmap) ) + kfree(sbi->symlink[n].data); + } + + sb->s_dev = 0; + kfree(sb->u.generic_sbp); + unlock_super(sb); + + DPRINTK(("autofs: shutting down\n")); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +static void autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); +static void autofs_read_inode(struct inode *inode); +static void autofs_write_inode(struct inode *inode); + +static struct super_operations autofs_sops = { + autofs_read_inode, + NULL, + autofs_write_inode, + autofs_put_inode, + autofs_put_super, + NULL, + autofs_statfs, + NULL +}; + +static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto) +{ + char *this_char, *value; + + *uid = current->uid; + *gid = current->gid; + *pgrp = current->pgrp; + + *minproto = *maxproto = AUTOFS_PROTO_VERSION; + + *pipefd = -1; + + if ( !options ) return 1; + for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { + if ((value = strchr(this_char,'=')) != NULL) + *value++ = 0; + if (!strcmp(this_char,"fd")) { + if (!value || !*value) + return 1; + *pipefd = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"uid")) { + if (!value || !*value) + return 1; + *uid = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"gid")) { + if (!value || !*value) + return 1; + *gid = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"pgrp")) { + if (!value || !*value) + return 1; + *pgrp = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"minproto")) { + if (!value || !*value) + return 1; + *minproto = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"maxproto")) { + if (!value || !*value) + return 1; + *maxproto = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else break; + } + return (*pipefd < 0); +} + +struct super_block *autofs_read_super(struct super_block *s, void *data, + int silent) +{ + int pipefd; + struct autofs_sb_info *sbi; + int minproto, maxproto; + + MOD_INC_USE_COUNT; + + lock_super(s); + sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL); + if ( !sbi ) { + s->s_dev = 0; + MOD_DEC_USE_COUNT; + return NULL; + } + DPRINTK(("autofs: starting up, sbi = %p\n",sbi)); + + s->u.generic_sbp = sbi; + sbi->magic = AUTOFS_SBI_MAGIC; + sbi->catatonic = 0; + sbi->exp_timeout = 0; + sbi->oz_pgrp = current->pgrp; + autofs_initialize_hash(&sbi->dirhash); + sbi->queues = NULL; + memset(sbi->symlink_bitmap, 0, sizeof(u32)*AUTOFS_SYMLINK_BITMAP_LEN); + sbi->next_dir_ino = AUTOFS_FIRST_DIR_INO; + s->s_blocksize = 1024; + s->s_blocksize_bits = 10; + s->s_magic = AUTOFS_SUPER_MAGIC; + s->s_op = &autofs_sops; + unlock_super(s); + if (!(s->s_mounted = iget(s, AUTOFS_ROOT_INO))) { + s->s_dev = 0; + kfree(sbi); + printk("autofs: get root inode failed\n"); + MOD_DEC_USE_COUNT; + return NULL; + } + + if ( parse_options(data,&pipefd,&s->s_mounted->i_uid,&s->s_mounted->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) { + iput(s->s_mounted); + s->s_dev = 0; + kfree(sbi); + printk("autofs: called with bogus options\n"); + MOD_DEC_USE_COUNT; + return NULL; + } + + if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) { + iput(s->s_mounted); + s->s_dev = 0; + kfree(sbi); + printk("autofs: kernel does not match daemon version\n"); + MOD_DEC_USE_COUNT; + return NULL; + } + + DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp)); + sbi->pipe = fget(pipefd); + if ( !sbi->pipe || !sbi->pipe->f_op || !sbi->pipe->f_op->write ) { + if ( sbi->pipe ) { + fput(sbi->pipe, sbi->pipe->f_inode); + printk("autofs: pipe file descriptor does not contain proper ops\n"); + } else { + printk("autofs: could not open pipe file descriptor\n"); + } + iput(s->s_mounted); + s->s_dev = 0; + kfree(sbi); + MOD_DEC_USE_COUNT; + return NULL; + } + return s; +} + +static void autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) +{ + struct statfs tmp; + + tmp.f_type = AUTOFS_SUPER_MAGIC; + tmp.f_bsize = 1024; + tmp.f_blocks = 0; + tmp.f_bfree = 0; + tmp.f_bavail = 0; + tmp.f_files = 0; + tmp.f_ffree = 0; + tmp.f_namelen = NAME_MAX; + copy_to_user(buf, &tmp, bufsiz); +} + +static void autofs_read_inode(struct inode *inode) +{ + ino_t ino = inode->i_ino; + unsigned int n; + struct autofs_sb_info *sbi = + (struct autofs_sb_info *) inode->i_sb->u.generic_sbp; + + inode->i_op = NULL; + inode->i_mode = 0; + inode->i_nlink = 2; + inode->i_size = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_blocks = 0; + inode->i_blksize = 1024; + + if ( ino == AUTOFS_ROOT_INO ) { + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; + inode->i_op = &autofs_root_inode_operations; + inode->i_uid = inode->i_gid = 0; /* Changed in read_super */ + return; + } + + inode->i_uid = inode->i_sb->s_mounted->i_uid; + inode->i_gid = inode->i_sb->s_mounted->i_gid; + + if ( ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO ) { + /* Symlink inode - should be in symlink list */ + struct autofs_symlink *sl; + + n = ino - AUTOFS_FIRST_SYMLINK; + if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) { + printk("autofs: Looking for bad symlink inode 0x%08x\n", (unsigned int) ino); + return; + } + + inode->i_op = &autofs_symlink_inode_operations; + sl = &sbi->symlink[n]; + inode->u.generic_ip = sl; + inode->i_mode = S_IFLNK | S_IRWXUGO; + inode->i_mtime = inode->i_ctime = sl->mtime; + inode->i_size = sl->len; + inode->i_nlink = 1; + } else { + /* All non-root directory inodes look the same */ + inode->i_op = &autofs_dir_inode_operations; + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + } +} + +static void autofs_write_inode(struct inode *inode) +{ + inode->i_dirt = 0; +} diff -urN linux-2.0.31pre9/fs/autofs/root.c linux-2.0.31pre9-privs/fs/autofs/root.c --- linux-2.0.31pre9/fs/autofs/root.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/fs/autofs/root.c Sun Sep 7 10:59:47 1997 @@ -0,0 +1,445 @@ +/* -*- linux-c -*- --------------------------------------------------------- * + * + * linux/fs/autofs/root.c + * + * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * ------------------------------------------------------------------------- */ + +#include +#include +#include +#include "autofs_i.h" + +static int autofs_root_readdir(struct inode *,struct file *,void *,filldir_t); +static int autofs_root_lookup(struct inode *,const char *,int,struct inode **); +static int autofs_root_symlink(struct inode *,const char *,int,const char *); +static int autofs_root_unlink(struct inode *,const char *,int); +static int autofs_root_rmdir(struct inode *,const char *,int); +static int autofs_root_mkdir(struct inode *,const char *,int,int); +static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long); + +static struct file_operations autofs_root_operations = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + autofs_root_readdir, /* readdir */ + NULL, /* select */ + autofs_root_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* release */ + NULL /* fsync */ +}; + +struct inode_operations autofs_root_inode_operations = { + &autofs_root_operations, /* file operations */ + NULL, /* create */ + autofs_root_lookup, /* lookup */ + NULL, /* link */ + autofs_root_unlink, /* unlink */ + autofs_root_symlink, /* symlink */ + autofs_root_mkdir, /* mkdir */ + autofs_root_rmdir, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int autofs_root_readdir(struct inode *inode, struct file *filp, + void *dirent, filldir_t filldir) +{ + struct autofs_dir_ent *ent; + struct autofs_dirhash *dirhash; + off_t onr, nr; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -ENOTDIR; + + dirhash = &((struct autofs_sb_info *)inode->i_sb->u.generic_sbp)->dirhash; + nr = filp->f_pos; + + switch(nr) + { + case 0: + if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0) + return 0; + filp->f_pos = ++nr; + /* fall through */ + case 1: + if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0) + return 0; + filp->f_pos = ++nr; + /* fall through */ + default: + while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr) ) { + if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0) + return 0; + filp->f_pos = nr; + } + break; + } + + return 0; +} + +static int autofs_root_lookup(struct inode *dir, const char *name, int len, + struct inode **result) +{ + struct autofs_sb_info *sbi; + struct autofs_dir_ent *ent; + struct inode *res; + autofs_hash_t hash; + int status, oz_mode; + + DPRINTK(("autofs_root_lookup: name = ")); + autofs_say(name,len); + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOTDIR; + } + + /* Handle special cases: . and ..; since this is a root directory, + they both point to the inode itself */ + *result = dir; + if (!len) + return 0; + if (name[0] == '.') { + if (len == 1) + return 0; + if (name[1] == '.' && len == 2) + return 0; + } + + *result = res = NULL; + sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp; + + hash = autofs_hash(name,len); + + oz_mode = autofs_oz_mode(sbi); + DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n", current->pid, current->pgrp, sbi->catatonic, oz_mode)); + + do { + while ( !(ent = autofs_hash_lookup(&sbi->dirhash,hash,name,len)) ) { + DPRINTK(("lookup failed, pid = %u, pgrp = %u\n", current->pid, current->pgrp)); + + if ( oz_mode ) { + iput(dir); + return -ENOENT; + } else { + status = autofs_wait(sbi,hash,name,len); + DPRINTK(("autofs_wait returned %d\n", status)); + if ( status ) { + iput(dir); + return status; + } + } + } + + DPRINTK(("lookup successful, inode = %08x\n", (unsigned int)ent->ino)); + + if (!(res = iget(dir->i_sb,ent->ino))) { + printk("autofs: iget returned null!\n"); + iput(dir); + return -EACCES; + } + + if ( !oz_mode && S_ISDIR(res->i_mode) && res->i_sb == dir->i_sb ) { + /* Not a mount point yet, call 1-800-DAEMON */ + DPRINTK(("autofs: waiting on non-mountpoint dir, inode = %lu, pid = %u, pgrp = %u\n", res->i_ino, current->pid, current->pgrp)); + iput(res); + res = NULL; + status = autofs_wait(sbi,hash,name,len); + if ( status ) { + iput(dir); + return status; + } + } + } while(!res); + autofs_update_usage(&sbi->dirhash,ent); + + *result = res; + iput(dir); + return 0; +} + +static int autofs_root_symlink(struct inode *dir, const char *name, int len, const char *symname) +{ + struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp; + struct autofs_dirhash *dh = &sbi->dirhash; + autofs_hash_t hash = autofs_hash(name,len); + struct autofs_dir_ent *ent; + unsigned int n; + int slsize; + struct autofs_symlink *sl; + + DPRINTK(("autofs_root_symlink: %s <- ", symname)); + autofs_say(name,len); + + if ( !autofs_oz_mode(sbi) ) { + iput(dir); + return -EPERM; + } + if ( autofs_hash_lookup(dh,hash,name,len) ) { + iput(dir); + return -EEXIST; + } + n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS); + if ( n >= AUTOFS_MAX_SYMLINKS ) { + iput(dir); + return -ENOSPC; + } + set_bit(n,sbi->symlink_bitmap); + sl = &sbi->symlink[n]; + sl->len = strlen(symname); + sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL); + if ( !sl->data ) { + clear_bit(n,sbi->symlink_bitmap); + iput(dir); + return -ENOSPC; + } + ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL); + if ( !ent ) { + kfree(sl->data); + clear_bit(n,sbi->symlink_bitmap); + iput(dir); + return -ENOSPC; + } + ent->name = kmalloc(len, GFP_KERNEL); + if ( !ent->name ) { + kfree(sl->data); + kfree(ent); + clear_bit(n,sbi->symlink_bitmap); + iput(dir); + return -ENOSPC; + } + memcpy(sl->data,symname,slsize); + sl->mtime = CURRENT_TIME; + + ent->ino = AUTOFS_FIRST_SYMLINK + n; + ent->hash = hash; + memcpy(ent->name,name,ent->len = len); + + autofs_hash_insert(dh,ent); + iput(dir); + + return 0; +} + +static int autofs_root_unlink(struct inode *dir, const char *name, int len) +{ + struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp; + struct autofs_dirhash *dh = &sbi->dirhash; + autofs_hash_t hash = autofs_hash(name,len); + struct autofs_dir_ent *ent; + unsigned int n; + + iput(dir); /* Nothing below can sleep */ + + if ( !autofs_oz_mode(sbi) ) + return -EPERM; + + ent = autofs_hash_lookup(dh,hash,name,len); + if ( !ent ) + return -ENOENT; + + n = ent->ino - AUTOFS_FIRST_SYMLINK; + if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap) ) + return -EINVAL; /* Not a symlink inode, can't unlink */ + + autofs_hash_delete(ent); + clear_bit(n,sbi->symlink_bitmap); + kfree(sbi->symlink[n].data); + + return 0; +} + +static int autofs_root_rmdir(struct inode *dir, const char *name, int len) +{ + struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp; + struct autofs_dirhash *dh = &sbi->dirhash; + autofs_hash_t hash = autofs_hash(name,len); + struct autofs_dir_ent *ent; + + if ( !autofs_oz_mode(sbi) ) { + iput(dir); + return -EPERM; + } + ent = autofs_hash_lookup(dh,hash,name,len); + if ( !ent ) { + iput(dir); + return -ENOENT; + } + if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO ) { + iput(dir); + return -ENOTDIR; /* Not a directory */ + } + autofs_hash_delete(ent); + dir->i_nlink--; + iput(dir); + + return 0; +} + +static int autofs_root_mkdir(struct inode *dir, const char *name, int len, int mode) +{ + struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp; + struct autofs_dirhash *dh = &sbi->dirhash; + autofs_hash_t hash = autofs_hash(name,len); + struct autofs_dir_ent *ent; + + if ( !autofs_oz_mode(sbi) ) { + iput(dir); + return -EPERM; + } + ent = autofs_hash_lookup(dh,hash,name,len); + if ( ent ) { + iput(dir); + return -EEXIST; + } + if ( sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO ) { + printk("autofs: Out of inode numbers -- what the heck did you do??\n"); + iput(dir); + return -ENOSPC; + } + ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL); + if ( !ent ) { + iput(dir); + return -ENOSPC; + } + ent->name = kmalloc(len, GFP_KERNEL); + if ( !ent->name ) { + kfree(ent); + iput(dir); + return -ENOSPC; + } + ent->hash = hash; + memcpy(ent->name, name, ent->len = len); + ent->ino = sbi->next_dir_ino++; + autofs_hash_insert(dh,ent); + dir->i_nlink++; + iput(dir); + + return 0; +} + +/* Get/set timeout ioctl() operation */ +static inline int autofs_get_set_timeout(struct autofs_sb_info *sbi, + unsigned long *p) +{ + int rv; + unsigned long ntimeout; + +#if LINUX_VERSION_CODE < kver(2,1,0) + if ( (rv = verify_area(VERIFY_WRITE, p, sizeof(unsigned long))) ) + return rv; + ntimeout = get_user(p); + put_user(sbi->exp_timeout/HZ, p); +#else + if ( (rv = get_user(ntimeout, p)) || + (rv = put_user(sbi->exp_timeout/HZ, p)) ) + return rv; +#endif + + if ( ntimeout > ULONG_MAX/HZ ) + sbi->exp_timeout = 0; + else + sbi->exp_timeout = ntimeout * HZ; + + return 0; +} + +/* Return protocol version */ +static inline int autofs_get_protover(int *p) +{ +#if LINUX_VERSION_CODE < kver(2,1,0) + int rv; + if ( (rv = verify_area(VERIFY_WRITE, p, sizeof(int))) ) + return rv; + put_user(AUTOFS_PROTO_VERSION, p); + return 0; +#else + return put_user(AUTOFS_PROTO_VERSION, p); +#endif +} + +/* Perform an expiry operation */ +static inline int autofs_expire_run(struct autofs_sb_info *sbi, + struct autofs_packet_expire *pkt_p) +{ + struct autofs_dir_ent *ent; + struct autofs_packet_expire pkt; + struct autofs_dirhash *dh = &(sbi->dirhash); + + memset(&pkt,0,sizeof pkt); + + pkt.hdr.proto_version = AUTOFS_PROTO_VERSION; + pkt.hdr.type = autofs_ptype_expire; + + if ( !sbi->exp_timeout || + !(ent = autofs_expire(dh,sbi->exp_timeout)) ) + return -EAGAIN; + + pkt.len = ent->len; + memcpy(pkt.name, ent->name, pkt.len); + pkt.name[pkt.len] = '\0'; + + if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) ) + return -EFAULT; + + autofs_update_usage(dh,ent); + + return 0; +} + +/* + * ioctl()'s on the root directory is the chief method for the daemon to + * generate kernel reactions + */ +static int autofs_root_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct autofs_sb_info *sbi = + (struct autofs_sb_info *)inode->i_sb->u.generic_sbp; + + DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,current->pgrp)); + + if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || + _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT ) + return -ENOTTY; + + if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) + return -EPERM; + + switch(cmd) { + case AUTOFS_IOC_READY: /* Wait queue: go ahead and retry */ + return autofs_wait_release(sbi,arg,0); + case AUTOFS_IOC_FAIL: /* Wait queue: fail with ENOENT */ + return autofs_wait_release(sbi,arg,-ENOENT); + case AUTOFS_IOC_CATATONIC: /* Enter catatonic mode (daemon shutdown) */ + autofs_catatonic_mode(sbi); + return 0; + case AUTOFS_IOC_PROTOVER: /* Get protocol version */ + return autofs_get_protover((int *)arg); + case AUTOFS_IOC_SETTIMEOUT: + return autofs_get_set_timeout(sbi,(unsigned long *)arg); + case AUTOFS_IOC_EXPIRE: + return autofs_expire_run(sbi,(struct autofs_packet_expire *)arg); + default: + return -ENOSYS; + } +} diff -urN linux-2.0.31pre9/fs/autofs/symlink.c linux-2.0.31pre9-privs/fs/autofs/symlink.c --- linux-2.0.31pre9/fs/autofs/symlink.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/fs/autofs/symlink.c Sun Sep 7 10:27:02 1997 @@ -0,0 +1,85 @@ +/* -*- linux-c -*- --------------------------------------------------------- * + * + * linux/fs/autofs/symlink.c + * + * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * ------------------------------------------------------------------------- */ + +#include +#include +#include "autofs_i.h" + +static int autofs_follow_link(struct inode *dir, struct inode *inode, + int flag, int mode, struct inode **res_inode) +{ + int error; + char *link; + + *res_inode = NULL; + if (!dir) { + dir = current->fs->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + return -ENOENT; + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + *res_inode = inode; + return 0; + } + if (current->link_count > 5) { + iput(dir); + iput(inode); + return -ELOOP; + } + link = ((struct autofs_symlink *)inode->u.generic_ip)->data; + current->link_count++; + error = open_namei(link,flag,mode,res_inode,dir); + current->link_count--; + iput(inode); + return error; +} + +static int autofs_readlink(struct inode *inode, char *buffer, int buflen) +{ + struct autofs_symlink *sl; + int len; + + if (!S_ISLNK(inode->i_mode)) { + iput(inode); + return -EINVAL; + } + sl = (struct autofs_symlink *)inode->u.generic_ip; + len = sl->len; + if (len > buflen) len = buflen; + copy_to_user(buffer,sl->data,len); + iput(inode); + return len; +} + +struct inode_operations autofs_symlink_inode_operations = { + NULL, /* file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + autofs_readlink, /* readlink */ + autofs_follow_link, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; diff -urN linux-2.0.31pre9/fs/autofs/waitq.c linux-2.0.31pre9-privs/fs/autofs/waitq.c --- linux-2.0.31pre9/fs/autofs/waitq.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/fs/autofs/waitq.c Sun Sep 7 10:27:02 1997 @@ -0,0 +1,171 @@ +/* -*- linux-c -*- --------------------------------------------------------- * + * + * linux/fs/autofs/waitq.c + * + * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * ------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include "autofs_i.h" + +/* We make this a static variable rather than a part of the superblock; it + is better if we don't reassign numbers easily even across filesystems */ +static int autofs_next_wait_queue = 1; + +void autofs_catatonic_mode(struct autofs_sb_info *sbi) +{ + struct autofs_wait_queue *wq, *nwq; + + DPRINTK(("autofs: entering catatonic mode\n")); + + sbi->catatonic = 1; + wq = sbi->queues; + sbi->queues = NULL; /* Erase all wait queues */ + while ( wq ) { + nwq = wq->next; + wq->status = -ENOENT; /* Magic is gone - report failure */ + kfree(wq->name); + wq->name = NULL; + wake_up(&wq->queue); + wq = nwq; + } + fput(sbi->pipe, sbi->pipe->f_inode); /* Close the pipe */ +} + +static int autofs_write(struct file *file, const void *addr, int bytes) +{ + unsigned short fs; + unsigned long old_signal; + const char *data = (const char *)addr; + int written = 0; + + /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/ + + /* Save pointer to user space and point back to kernel space */ + fs = get_fs(); + set_fs(KERNEL_DS); + + old_signal = current->signal; + + while ( bytes && (written = file->f_op->write(file->f_inode,file,data,bytes)) > 0 ) { + data += written; + bytes -= written; + } + + if ( written == -EPIPE && !(old_signal & (1 << (SIGPIPE-1))) ) { + /* Keep the currently executing process from receiving a + SIGPIPE unless it was already supposed to get one */ + current->signal &= ~(1 << (SIGPIPE-1)); + } + set_fs(fs); + + return (bytes > 0); +} + +static void autofs_notify_daemon(struct autofs_sb_info *sbi, struct autofs_wait_queue *wq) +{ + struct autofs_packet_missing pkt; + + DPRINTK(("autofs_wait: wait id = 0x%08lx, name = ", wq->wait_queue_token)); + autofs_say(wq->name,wq->len); + + memset(&pkt,0,sizeof pkt); /* For security reasons */ + + pkt.hdr.proto_version = AUTOFS_PROTO_VERSION; + pkt.hdr.type = autofs_ptype_missing; + pkt.wait_queue_token = wq->wait_queue_token; + pkt.len = wq->len; + memcpy(pkt.name, wq->name, pkt.len); + pkt.name[pkt.len] = '\0'; + + if ( autofs_write(sbi->pipe,&pkt,sizeof(struct autofs_packet_missing)) ) + autofs_catatonic_mode(sbi); +} + +int autofs_wait(struct autofs_sb_info *sbi, autofs_hash_t hash, const char *name, int len) +{ + struct autofs_wait_queue *wq; + int status; + + for ( wq = sbi->queues ; wq ; wq = wq->next ) { + if ( wq->hash == hash && + wq->len == len && + wq->name && !memcmp(wq->name,name,len) ) + break; + } + + if ( !wq ) { + /* Create a new wait queue */ + wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); + if ( !wq ) + return -ENOMEM; + + wq->name = kmalloc(len,GFP_KERNEL); + if ( !wq->name ) { + kfree(wq); + return -ENOMEM; + } + wq->wait_queue_token = autofs_next_wait_queue++; + init_waitqueue(&wq->queue); + wq->hash = hash; + wq->len = len; + wq->status = -EINTR; /* Status return if interrupted */ + memcpy(wq->name, name, len); + wq->next = sbi->queues; + sbi->queues = wq; + + /* autofs_notify_daemon() may block */ + wq->wait_ctr = 2; + autofs_notify_daemon(sbi,wq); + } else + wq->wait_ctr++; + + if ( wq->name ) { + /* wq->name is NULL if and only if the lock is released */ + interruptible_sleep_on(&wq->queue); + } else { + DPRINTK(("autofs_wait: skipped sleeping\n")); + } + + status = wq->status; + + if ( ! --wq->wait_ctr ) /* Are we the last process to need status? */ + kfree(wq); + + return status; +} + + +int autofs_wait_release(struct autofs_sb_info *sbi, unsigned long wait_queue_token, int status) +{ + struct autofs_wait_queue *wq, **wql; + + for ( wql = &sbi->queues ; (wq = *wql) ; wql = &wq->next ) { + if ( wq->wait_queue_token == wait_queue_token ) + break; + } + if ( !wq ) + return -EINVAL; + + *wql = wq->next; /* Unlink from chain */ + kfree(wq->name); + wq->name = NULL; /* Do not wait on this queue */ + + wq->status = status; + + if ( ! --wq->wait_ctr ) /* Is anyone still waiting for this guy? */ + kfree(wq); + else + wake_up(&wq->queue); + + return 0; +} + diff -urN linux-2.0.31pre9/fs/binfmt_aout.c linux-2.0.31pre9-privs/fs/binfmt_aout.c --- linux-2.0.31pre9/fs/binfmt_aout.c Sat Aug 17 11:19:28 1996 +++ linux-2.0.31pre9-privs/fs/binfmt_aout.c Sun Sep 7 10:28:18 1997 @@ -310,9 +310,9 @@ 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_FLAGS(ex) & F_STACKEXEC) current->flags |= PF_STACKEXEC; if (N_MAGIC(ex) == OMAGIC) { #ifdef __alpha__ do_mmap(NULL, N_TXTADDR(ex) & PAGE_MASK, diff -urN linux-2.0.31pre9/fs/binfmt_elf.c linux-2.0.31pre9-privs/fs/binfmt_elf.c --- linux-2.0.31pre9/fs/binfmt_elf.c Sun Sep 7 16:04:11 1997 +++ linux-2.0.31pre9-privs/fs/binfmt_elf.c Sun Sep 7 10:28:18 1997 @@ -11,6 +11,7 @@ #include +#include #include #include #include @@ -55,7 +56,10 @@ #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1)) #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1)) -static struct linux_binfmt elf_format = { +#ifndef CONFIG_STACKEXEC +static +#endif +struct linux_binfmt elf_format = { #ifndef MODULE NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump #else @@ -657,9 +661,9 @@ #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; + if (elf_ex.e_flags & EF_STACKEXEC) current->flags |= PF_STACKEXEC; bprm->p = (unsigned long) create_elf_tables((char *)bprm->p, bprm->argc, diff -urN linux-2.0.31pre9/fs/buffer.c linux-2.0.31pre9-privs/fs/buffer.c --- linux-2.0.31pre9/fs/buffer.c Sun Sep 7 16:04:12 1997 +++ linux-2.0.31pre9-privs/fs/buffer.c Sun Sep 7 10:28:18 1997 @@ -17,6 +17,7 @@ the buffer cache isn't our primary cache - Andrew Tridgell 12/96 */ #include +#include #include #include #include @@ -1565,7 +1566,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.31pre9/fs/dquot.c linux-2.0.31pre9-privs/fs/dquot.c --- linux-2.0.31pre9/fs/dquot.c Sun Sep 7 16:04:12 1997 +++ linux-2.0.31pre9-privs/fs/dquot.c Sun Sep 7 10:28:18 1997 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -378,7 +379,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", @@ -390,7 +392,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]); @@ -400,7 +403,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]); @@ -416,7 +419,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", @@ -428,7 +432,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]); @@ -438,7 +443,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]); @@ -1030,11 +1035,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.31pre9/fs/exec.c linux-2.0.31pre9-privs/fs/exec.c --- linux-2.0.31pre9/fs/exec.c Sat Nov 30 02:21:18 1996 +++ linux-2.0.31pre9-privs/fs/exec.c Sun Sep 7 10:28:18 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 == '/') @@ -449,17 +449,17 @@ } current->comm[i] = '\0'; + current->flags &= ~PF_STACKEXEC; + /* Release all of the old mmap stuff. */ exec_mmap(); 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 +509,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 +529,7 @@ || (current->fs->count > 1) || (current->sig->count > 1) || (current->files->count > 1)) { - if (!suser()) - return -EPERM; + return -EPERM; } } diff -urN linux-2.0.31pre9/fs/ext/namei.c linux-2.0.31pre9-privs/fs/ext/namei.c --- linux-2.0.31pre9/fs/ext/namei.c Sat Nov 30 02:21:19 1996 +++ linux-2.0.31pre9-privs/fs/ext/namei.c Sun Sep 7 10:28:18 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.31pre9/fs/ext2/CHANGES linux-2.0.31pre9-privs/fs/ext2/CHANGES --- linux-2.0.31pre9/fs/ext2/CHANGES Tue Jan 16 21:31:58 1996 +++ linux-2.0.31pre9-privs/fs/ext2/CHANGES Sun Sep 7 10:28:18 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.31pre9/fs/ext2/Makefile linux-2.0.31pre9-privs/fs/ext2/Makefile --- linux-2.0.31pre9/fs/ext2/Makefile Tue Aug 15 05:07:02 1995 +++ linux-2.0.31pre9-privs/fs/ext2/Makefile Sun Sep 7 10:28:18 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.31pre9/fs/ext2/acl.c linux-2.0.31pre9-privs/fs/ext2/acl.c --- linux-2.0.31pre9/fs/ext2/acl.c Tue Jul 2 09:08:42 1996 +++ linux-2.0.31pre9-privs/fs/ext2/acl.c Sun Sep 7 10:28:18 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.31pre9/fs/ext2/balloc.c linux-2.0.31pre9-privs/fs/ext2/balloc.c --- linux-2.0.31pre9/fs/ext2/balloc.c Sun Sep 7 16:04:12 1997 +++ linux-2.0.31pre9-privs/fs/ext2/balloc.c Sun Sep 7 10:28:18 1997 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -353,11 +354,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"); @@ -366,9 +367,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.31pre9/fs/ext2/file.c linux-2.0.31pre9-privs/fs/ext2/file.c --- linux-2.0.31pre9/fs/ext2/file.c Tue Feb 20 00:28:13 1996 +++ linux-2.0.31pre9-privs/fs/ext2/file.c Sun Sep 7 10:28:18 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.31pre9/fs/ext2/ialloc.c linux-2.0.31pre9-privs/fs/ext2/ialloc.c --- linux-2.0.31pre9/fs/ext2/ialloc.c Sun Sep 7 16:04:12 1997 +++ linux-2.0.31pre9-privs/fs/ext2/ialloc.c Sun Sep 7 10:28:19 1997 @@ -458,6 +458,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.31pre9/fs/ext2/inode.c linux-2.0.31pre9-privs/fs/ext2/inode.c --- linux-2.0.31pre9/fs/ext2/inode.c Sun Sep 7 16:04:12 1997 +++ linux-2.0.31pre9-privs/fs/ext2/inode.c Sun Sep 7 10:28:19 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)); @@ -474,6 +475,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; @@ -590,6 +592,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.31pre9/fs/ext2/ioctl.c linux-2.0.31pre9-privs/fs/ext2/ioctl.c --- linux-2.0.31pre9/fs/ext2/ioctl.c Sun Sep 7 16:04:12 1997 +++ linux-2.0.31pre9-privs/fs/ext2/ioctl.c Sun Sep 7 10:28:19 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; @@ -74,7 +73,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.31pre9/fs/ext2/namei.c linux-2.0.31pre9-privs/fs/ext2/namei.c --- linux-2.0.31pre9/fs/ext2/namei.c Sun Sep 7 16:04:12 1997 +++ linux-2.0.31pre9-privs/fs/ext2/namei.c Sun Sep 7 10:28:19 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; @@ -1018,7 +1020,8 @@ if (new_inode) { if ((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 (IS_APPEND(new_inode) || IS_IMMUTABLE(new_inode)) goto end_rename; diff -urN linux-2.0.31pre9/fs/ext2/res_fork.c linux-2.0.31pre9-privs/fs/ext2/res_fork.c --- linux-2.0.31pre9/fs/ext2/res_fork.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/fs/ext2/res_fork.c Sun Sep 7 10:28:19 1997 @@ -0,0 +1,638 @@ +/* + * 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; + /* XXX: BLOCK_SIZE ->? inode->i_sb->s_blocksize */ + 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, before; + 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? */ + + /* XXX: BLOCK_SIZE ->? inode->i_sb->s_blocksize */ + 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; + } + + before = 0; /* there is no block before this one */ + +#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 - a completely empty block? */ + if (res.rf_res_head->id == 0 + && (void *) (-1+res.rf_block_head) + == (void *) bh->b_data) { + + res_debug("deleting resource %u\n", block); + /* We can delete this fork. */ + brelse(bh); + bh = NULL; + ext2_free_blocks(inode, block, 1); + block = before; + + /* we link the predecessor + ('before') block to the + 'next' one */ + + if (before) { + /* XXX - load 'before' block */ + bh = bread(inode->i_dev, block, + inode->i_sb->s_blocksize); + /* XXX - point it at 'next' */ + if (bh == NULL || err) { + ext2_panic(inode->i_sb, "ext2_put_resource", + "failed to reload fork %u", + block); + if (bh) + brelse(bh); + return -EIO; + } + res.rf_data = (__u8 *) bh->b_data; + res.rf_block_head->next_fork_block + = cpu_to_le32(next); + flags |= DIRTY_BUFFER; + } else { /* first block off inode */ + inode->u.ext2_i.i_resource_fork = next; + /* mark inode changed */ + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + inode->i_dirt = 1; + } + + /* load next block */ + break; + } + + flags |= DIRTY_BUFFER; + } else { + /* Some other resource - ignore it */ + res.rf_data += le16_to_cpu(res.rf_res_head->length); + } + } + + if (bh) { + if (flags & DIRTY_BUFFER) + /* This buffer has been changed */ + mark_buffer_dirty(bh, 1); + brelse(bh); + } + + if (flags & ALL_DONE) + return 0; + + before = block; + 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.31pre9/fs/ext2/super.c linux-2.0.31pre9-privs/fs/ext2/super.c --- linux-2.0.31pre9/fs/ext2/super.c Sun Jul 7 01:06:53 1996 +++ linux-2.0.31pre9-privs/fs/ext2/super.c Sun Sep 7 10:28:19 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.31pre9/fs/fcntl.c linux-2.0.31pre9-privs/fs/fcntl.c --- linux-2.0.31pre9/fs/fcntl.c Thu Jul 4 11:23:45 1996 +++ linux-2.0.31pre9-privs/fs/fcntl.c Sun Sep 7 10:28:19 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.31pre9/fs/file_cap.c linux-2.0.31pre9-privs/fs/file_cap.c --- linux-2.0.31pre9/fs/file_cap.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/fs/file_cap.c Sun Sep 7 10:28:19 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 => unchanged.. */ + 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.31pre9/fs/filesystems.c linux-2.0.31pre9-privs/fs/filesystems.c --- linux-2.0.31pre9/fs/filesystems.c Thu Apr 25 02:32:39 1996 +++ linux-2.0.31pre9-privs/fs/filesystems.c Sun Sep 7 10:27:03 1997 @@ -24,6 +24,7 @@ #include #include #include +#include #include extern void device_setup(void); @@ -110,6 +111,9 @@ init_ufs_fs(); #endif +#ifdef CONFIG_AUTOFS_FS + init_autofs_fs(); +#endif mount_root(); return 0; } diff -urN linux-2.0.31pre9/fs/inode.c linux-2.0.31pre9-privs/fs/inode.c --- linux-2.0.31pre9/fs/inode.c Mon Apr 7 14:09:01 1997 +++ linux-2.0.31pre9-privs/fs/inode.c Sun Sep 7 10:28:19 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.31pre9/fs/minix/namei.c linux-2.0.31pre9-privs/fs/minix/namei.c --- linux-2.0.31pre9/fs/minix/namei.c Sat Nov 30 02:21:21 1996 +++ linux-2.0.31pre9-privs/fs/minix/namei.c Sun Sep 7 10:28:19 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.31pre9/fs/namei.c linux-2.0.31pre9-privs/fs/namei.c --- linux-2.0.31pre9/fs/namei.c Sun Sep 7 16:04:12 1997 +++ linux-2.0.31pre9-privs/fs/namei.c Sun Sep 7 10:28:19 1997 @@ -8,17 +8,20 @@ * Some corrections by tytso. * * Aug 97 - cevans - fix security problem with O_TRUNC and append only files + * POSIX.6 additions Darren J Moffat May 96 */ #include #include #include +#include #include #include #include #include #include +#include #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) @@ -101,20 +104,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; } @@ -207,6 +233,23 @@ *res_inode = inode; return 0; } +#ifdef CONFIG_SYMLINK_FIX +/* + * Don't follow links that we don't own in +t directories, unless the link + * is owned by root. + */ + if (S_ISLNK(inode->i_mode) && (dir->i_mode & S_ISVTX) && + inode->i_uid && + current->fsuid != inode->i_uid) { +#ifdef CONFIG_SYMLINK_LOG + security_alert("symlink"); +#endif + iput(dir); + iput(inode); + *res_inode = NULL; + return -EPERM; + } +#endif return inode->i_op->follow_link(dir,inode,flag,mode,res_inode); } @@ -507,7 +550,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: @@ -787,6 +830,22 @@ iput(dir); return -EPERM; } +#ifdef CONFIG_SYMLINK_FIX +/* + * Don't allow incapable users to create hard links to files they don't own + * in a +t directory. + */ + if ((dir->i_mode & S_ISVTX) && + current->fsuid != oldinode->i_uid && + !capable(CAP_FOWNER)) { +#ifdef CONFIG_SYMLINK_LOG + security_alert("hard link"); +#endif + iput(oldinode); + iput(dir); + return -EPERM; + } +#endif if (IS_RDONLY(dir)) { iput(oldinode); iput(dir); diff -urN linux-2.0.31pre9/fs/open.c linux-2.0.31pre9-privs/fs/open.c --- linux-2.0.31pre9/fs/open.c Sat Nov 30 02:21:19 1996 +++ linux-2.0.31pre9-privs/fs/open.c Sun Sep 7 10:28:19 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.31pre9/fs/proc/array.c linux-2.0.31pre9-privs/fs/proc/array.c --- linux-2.0.31pre9/fs/proc/array.c Sun Sep 7 16:04:12 1997 +++ linux-2.0.31pre9-privs/fs/proc/array.c Sun Sep 7 15:17: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,43 @@ 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 += sprintf(buffer, "Summary: E(%c) I(%c) P(%c)\n", + cap_isclear(tsk->cap_effective) ? '-':'+' , + cap_isclear(tsk->cap_inheritable) ? '-':'+' , + cap_isclear(tsk->cap_permitted) ? '-':'+' ); + 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 +1110,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.31pre9/fs/proc/base.c linux-2.0.31pre9-privs/fs/proc/base.c --- linux-2.0.31pre9/fs/proc/base.c Wed Feb 21 01:26:09 1996 +++ linux-2.0.31pre9-privs/fs/proc/base.c Sun Sep 7 10:28:19 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.31pre9/fs/read_write.c linux-2.0.31pre9-privs/fs/read_write.c --- linux-2.0.31pre9/fs/read_write.c Tue Aug 20 23:18:09 1996 +++ linux-2.0.31pre9-privs/fs/read_write.c Sun Sep 7 10:28:20 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.31pre9/fs/super.c linux-2.0.31pre9-privs/fs/super.c --- linux-2.0.31pre9/fs/super.c Sun Sep 7 16:04:13 1997 +++ linux-2.0.31pre9-privs/fs/super.c Sun Sep 7 10:28:20 1997 @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -640,7 +641,7 @@ int retval; struct inode dummy_inode; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; retval = namei(name, &inode); if (retval) { @@ -840,7 +841,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.31pre9/fs/sysv/namei.c linux-2.0.31pre9-privs/fs/sysv/namei.c --- linux-2.0.31pre9/fs/sysv/namei.c Sat Nov 30 02:21:22 1996 +++ linux-2.0.31pre9-privs/fs/sysv/namei.c Sun Sep 7 10:28:20 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.31pre9/fs/umsdos/namei.c linux-2.0.31pre9-privs/fs/umsdos/namei.c --- linux-2.0.31pre9/fs/umsdos/namei.c Sat Nov 30 02:21:23 1996 +++ linux-2.0.31pre9-privs/fs/umsdos/namei.c Sun Sep 7 10:28:22 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.31pre9/fs/xiafs/namei.c linux-2.0.31pre9-privs/fs/xiafs/namei.c --- linux-2.0.31pre9/fs/xiafs/namei.c Sat Nov 30 02:21:23 1996 +++ linux-2.0.31pre9-privs/fs/xiafs/namei.c Sun Sep 7 10:28:22 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.31pre9/include/asm-alpha/unistd.h linux-2.0.31pre9-privs/include/asm-alpha/unistd.h --- linux-2.0.31pre9/include/asm-alpha/unistd.h Thu Apr 3 20:00:00 1997 +++ linux-2.0.31pre9-privs/include/asm-alpha/unistd.h Sun Sep 7 10:28:22 1997 @@ -170,6 +170,13 @@ #define __NR_getresuid 344 #define __NR_pciconfig_read 345 #define __NR_pciconfig_write 346 +/* 347: query_module */ +#define __NR__setproccap 348 +#define __NR__getproccap 349 +#define __NR__setfilecap 350 +#define __NR__getfilecap 351 +#define __NR__fsetfilecap 352 +#define __NR__fgetfilecap 353 #if defined(__LIBRARY__) && defined(__GNUC__) diff -urN linux-2.0.31pre9/include/asm-i386/processor.h linux-2.0.31pre9-privs/include/asm-i386/processor.h --- linux-2.0.31pre9/include/asm-i386/processor.h Tue Mar 11 13:52:29 1997 +++ linux-2.0.31pre9-privs/include/asm-i386/processor.h Sun Sep 7 10:32:29 1997 @@ -9,6 +9,8 @@ #include #include +#include +#include /* * System setup and hardware bug flags.. @@ -41,6 +43,15 @@ */ #define TASK_SIZE (0xC0000000UL) +#if defined(CONFIG_STACKEXEC) && defined(CONFIG_BINFMT_ELF) +extern struct linux_binfmt elf_format; +#define MMAP_ADDR ( \ + current->binfmt == &elf_format && \ + !(current->flags & PF_STACKEXEC) \ + ? 0x00110000UL \ + : TASK_SIZE / 3 ) +#endif + /* * Size of io_bitmap in longwords: 32 is ports 0-0x3ff. */ @@ -134,14 +145,6 @@ #define alloc_kernel_stack() __get_free_page(GFP_KERNEL) #define free_kernel_stack(page) free_page((page)) -static inline void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp) -{ - regs->cs = USER_CS; - regs->ds = regs->es = regs->ss = regs->fs = regs->gs = USER_DS; - regs->eip = eip; - regs->esp = esp; -} - /* * Return saved PC of a blocked thread. */ @@ -151,3 +154,25 @@ } #endif /* __ASM_I386_PROCESSOR_H */ + +#if defined(current) && !defined(__START_THREAD) +#define __START_THREAD + +static inline void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp) +{ +#ifdef CONFIG_STACKEXEC + if (current->flags & PF_STACKEXEC) { + regs->cs = USER_HUGE_CS; regs->ss = USER_HUGE_SS; + } else { + regs->cs = USER_CS; regs->ss = USER_DS; + } + regs->ds = regs->es = regs->fs = regs->gs = USER_DS; +#else + regs->cs = USER_CS; + regs->ds = regs->es = regs->fs = regs->gs = regs->ss = USER_DS; +#endif + regs->eip = eip; + regs->esp = esp; +} + +#endif /* __START_THREAD */ diff -urN linux-2.0.31pre9/include/asm-i386/segment.h linux-2.0.31pre9-privs/include/asm-i386/segment.h --- linux-2.0.31pre9/include/asm-i386/segment.h Tue Apr 9 00:35:29 1996 +++ linux-2.0.31pre9-privs/include/asm-i386/segment.h Sun Sep 7 10:32:28 1997 @@ -1,11 +1,27 @@ #ifndef _ASM_SEGMENT_H #define _ASM_SEGMENT_H +#include + #define KERNEL_CS 0x10 #define KERNEL_DS 0x18 #define USER_CS 0x23 #define USER_DS 0x2B + +#ifdef CONFIG_STACKEXEC +#define USER_HUGE_CS 0x32 +#define USER_HUGE_SS 0x3A +#else +#define USER_HUGE_CS 0x23 +#define USER_HUGE_SS 0x2B +#endif + +/* + * Magic address to return to the kernel from signal handlers, any address + * beyond user code segment limit will do. + */ +#define MAGIC_SIGRETURN 0xC1428571 #ifndef __ASSEMBLY__ diff -urN linux-2.0.31pre9/include/asm-i386/unistd.h linux-2.0.31pre9-privs/include/asm-i386/unistd.h --- linux-2.0.31pre9/include/asm-i386/unistd.h Thu Mar 21 22:34:02 1996 +++ linux-2.0.31pre9-privs/include/asm-i386/unistd.h Sun Sep 7 10:28:22 1997 @@ -169,6 +169,18 @@ #define __NR_sched_rr_get_interval 161 #define __NR_nanosleep 162 #define __NR_mremap 163 +/* 164: setresuid */ +/* 165: getresuid */ +/* 166: vm86 */ +/* 167: query_module */ +/* 168: poll */ +/* 169: nfsservctl */ +#define __NR__setproccap 170 +#define __NR__getproccap 171 +#define __NR__setfilecap 172 +#define __NR__getfilecap 173 +#define __NR__fsetfilecap 174 +#define __NR__fgetfilecap 175 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ #define _syscall0(type,name) \ diff -urN linux-2.0.31pre9/include/asm-m68k/unistd.h linux-2.0.31pre9-privs/include/asm-m68k/unistd.h --- linux-2.0.31pre9/include/asm-m68k/unistd.h Wed May 15 23:05:11 1996 +++ linux-2.0.31pre9-privs/include/asm-m68k/unistd.h Sun Sep 7 10:28:22 1997 @@ -169,6 +169,18 @@ #define __NR_sched_rr_get_interval 161 #define __NR_nanosleep 162 #define __NR_mremap 163 +/* 164: setresuid */ +/* 165: getresuid */ +/* 166: vm86 */ +/* 167: query_module */ +/* 168: poll */ +/* 169: nfsservctl */ +#define __NR__setproccap 170 +#define __NR__getproccap 171 +#define __NR__setfilecap 172 +#define __NR__getfilecap 173 +#define __NR__fsetfilecap 174 +#define __NR__fgetfilecap 175 #ifdef __ELF__ diff -urN linux-2.0.31pre9/include/asm-mips/unistd.h linux-2.0.31pre9-privs/include/asm-mips/unistd.h --- linux-2.0.31pre9/include/asm-mips/unistd.h Wed Dec 13 02:39:47 1995 +++ linux-2.0.31pre9-privs/include/asm-mips/unistd.h Sun Sep 7 10:28:22 1997 @@ -1143,12 +1143,17 @@ #define __NR_munlock (__NR_Linux + 155) #define __NR_mlockall (__NR_Linux + 156) #define __NR_munlockall (__NR_Linux + 157) - - +#define __NR__setproccap (__NR_Linux + 158) +#define __NR__getproccap (__NR_Linux + 159) +#define __NR__setfilecap (__NR_Linux + 160) +#define __NR__getfilecap (__NR_Linux + 161) +#define __NR__fsetfilecap (__NR_Linux + 162) +#define __NR__fgetfilecap (__NR_Linux + 163) + /* * Offset of the last Linux flavoured syscall */ -#define __NR_Linux_syscalls 157 +#define __NR_Linux_syscalls 163 #ifndef __LANGUAGE_ASSEMBLY__ diff -urN linux-2.0.31pre9/include/asm-ppc/unistd.h linux-2.0.31pre9-privs/include/asm-ppc/unistd.h --- linux-2.0.31pre9/include/asm-ppc/unistd.h Mon Jul 8 01:27:43 1996 +++ linux-2.0.31pre9-privs/include/asm-ppc/unistd.h Sun Sep 7 10:28:22 1997 @@ -161,6 +161,13 @@ #define __NR_munlock 151 #define __NR_mlockall 152 #define __NR_munlockall 153 + +#define __NR__setproccap 166 +#define __NR__getproccap 167 +#define __NR__setfilecap 168 +#define __NR__getfilecap 169 +#define __NR__fsetfilecap 170 +#define __NR__fgetfilecap 171 #define _syscall0(type,name) \ diff -urN linux-2.0.31pre9/include/linux/a.out.h linux-2.0.31pre9-privs/include/linux/a.out.h --- linux-2.0.31pre9/include/linux/a.out.h Sat Aug 17 11:19:28 1996 +++ linux-2.0.31pre9-privs/include/linux/a.out.h Sun Sep 7 10:28:22 1997 @@ -37,6 +37,9 @@ M_MIPS2 = 152, /* MIPS R6000/R4000 binary */ }; +/* Constants for the N_FLAGS field */ +#define F_STACKEXEC 1 /* Executable stack area forced */ + #if !defined (N_MAGIC) #define N_MAGIC(exec) ((exec).a_info & 0xffff) #endif diff -urN linux-2.0.31pre9/include/linux/auto_fs.h linux-2.0.31pre9-privs/include/linux/auto_fs.h --- linux-2.0.31pre9/include/linux/auto_fs.h Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/include/linux/auto_fs.h Sun Sep 7 10:37:20 1997 @@ -0,0 +1,62 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * linux/include/linux/auto_fs.h + * + * Copyright 1997 Transmeta Corporation - All Rights Reserved + * + * This file is part of the Linux kernel and is made available under + * the terms of the GNU General Public License, version 2, or at your + * option, any later version, incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + + +#ifndef _LINUX_AUTO_FS_H +#define _LINUX_AUTO_FS_H + +#include +#include +#include +#include +#include + +#define AUTOFS_PROTO_VERSION 3 + +enum autofs_packet_type { + autofs_ptype_missing, /* Missing entry (mount request) */ + autofs_ptype_expire, /* Expire entry (umount request) */ +}; + +struct autofs_packet_hdr { + int proto_version; /* Protocol version */ + enum autofs_packet_type type; /* Type of packet */ +}; + +struct autofs_packet_missing { + struct autofs_packet_hdr hdr; + unsigned long wait_queue_token; + int len; + char name[NAME_MAX+1]; +}; + +struct autofs_packet_expire { + struct autofs_packet_hdr hdr; + int len; + char name[NAME_MAX+1]; +}; + +#define AUTOFS_IOC_READY _IO(0x93,0x60) +#define AUTOFS_IOC_FAIL _IO(0x93,0x61) +#define AUTOFS_IOC_CATATONIC _IO(0x93,0x62) +#define AUTOFS_IOC_PROTOVER _IOR(0x93,0x63,int) +#define AUTOFS_IOC_SETTIMEOUT _IOWR(0x93,0x64,unsigned long) +#define AUTOFS_IOC_EXPIRE _IOR(0x93,0x65,struct autofs_packet_expire) + +#ifdef __KERNEL__ + +/* Init function */ +int init_autofs_fs(void); + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_AUTO_FS_H */ diff -urN linux-2.0.31pre9/include/linux/binfmts.h linux-2.0.31pre9-privs/include/linux/binfmts.h --- linux-2.0.31pre9/include/linux/binfmts.h Wed May 8 08:28:01 1996 +++ linux-2.0.31pre9-privs/include/linux/binfmts.h Sun Sep 7 10:32:28 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_s 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.31pre9/include/linux/blk.h linux-2.0.31pre9-privs/include/linux/blk.h --- linux-2.0.31pre9/include/linux/blk.h Fri Mar 28 16:08:17 1997 +++ linux-2.0.31pre9-privs/include/linux/blk.h Sun Sep 7 10:32:29 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.31pre9/include/linux/capability.h linux-2.0.31pre9-privs/include/linux/capability.h --- linux-2.0.31pre9/include/linux/capability.h Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/include/linux/capability.h Sun Sep 7 10:28:22 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 *are* defined later, + ** 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.31pre9/include/linux/elf.h linux-2.0.31pre9-privs/include/linux/elf.h --- linux-2.0.31pre9/include/linux/elf.h Sat Aug 10 00:03:15 1996 +++ linux-2.0.31pre9-privs/include/linux/elf.h Sun Sep 7 10:28:22 1997 @@ -57,6 +57,9 @@ */ #define EM_ALPHA 0x9026 +/* Constants for the e_flags field */ +#define EF_STACKEXEC 1 /* Executable stack area forced */ + /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 diff -urN linux-2.0.31pre9/include/linux/ext2_fs.h linux-2.0.31pre9-privs/include/linux/ext2_fs.h --- linux-2.0.31pre9/include/linux/ext2_fs.h Sun Sep 7 16:04:15 1997 +++ linux-2.0.31pre9-privs/include/linux/ext2_fs.h Sun Sep 7 10:28:23 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 @@ -217,7 +242,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; @@ -256,7 +281,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 @@ -417,11 +442,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__ /* @@ -516,6 +542,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.31pre9/include/linux/ext2_fs_i.h linux-2.0.31pre9-privs/include/linux/ext2_fs_i.h --- linux-2.0.31pre9/include/linux/ext2_fs_i.h Sat May 4 00:06:18 1996 +++ linux-2.0.31pre9-privs/include/linux/ext2_fs_i.h Sun Sep 7 10:28:23 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.31pre9/include/linux/ext2_fs_sb.h linux-2.0.31pre9-privs/include/linux/ext2_fs_sb.h --- linux-2.0.31pre9/include/linux/ext2_fs_sb.h Sun Dec 1 09:59:18 1996 +++ linux-2.0.31pre9-privs/include/linux/ext2_fs_sb.h Sun Sep 7 10:28:23 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.31pre9/include/linux/fs.h linux-2.0.31pre9-privs/include/linux/fs.h --- linux-2.0.31pre9/include/linux/fs.h Sun Sep 7 16:04:15 1997 +++ linux-2.0.31pre9-privs/include/linux/fs.h Sun Sep 7 10:32:29 1997 @@ -503,6 +503,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 { @@ -668,6 +670,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.31pre9/include/linux/kernel.h linux-2.0.31pre9-privs/include/linux/kernel.h --- linux-2.0.31pre9/include/linux/kernel.h Sun Sep 7 16:04:15 1997 +++ linux-2.0.31pre9-privs/include/linux/kernel.h Sun Sep 7 10:28:23 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 @@ -63,12 +63,6 @@ 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) - -/* * Display an IP address in readable format. */ @@ -77,6 +71,27 @@ (((addr) >> 8) & 0xff), \ (((addr) >> 16) & 0xff), \ (((addr) >> 24) & 0xff) + +#define security_alert(msg) { \ + static unsigned long warning_time = 0, no_flood_yet = 0; \ +\ +/* Make sure at least one minute passed since the last warning logged */ \ + if (!warning_time || jiffies - warning_time > 60 * HZ) { \ + warning_time = jiffies; no_flood_yet = 1; \ + printk( \ + KERN_ALERT \ + "Possible " msg " exploit attempt:\n" \ + KERN_ALERT \ + "Process %s (pid %d, uid %d, euid %d).\n", \ + current->comm, current->pid, \ + current->uid, current->euid); \ + } else if (no_flood_yet) { \ + warning_time = jiffies; no_flood_yet = 0; \ + printk( \ + KERN_ALERT \ + "More possible " msg " exploit attempts follow.\n"); \ + } \ +} #endif /* __KERNEL__ */ diff -urN linux-2.0.31pre9/include/linux/proc_fs.h linux-2.0.31pre9-privs/include/linux/proc_fs.h --- linux-2.0.31pre9/include/linux/proc_fs.h Sun Sep 7 16:04:15 1997 +++ linux-2.0.31pre9-privs/include/linux/proc_fs.h Sun Sep 7 10:33:12 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.31pre9/include/linux/res_fork.h linux-2.0.31pre9-privs/include/linux/res_fork.h --- linux-2.0.31pre9/include/linux/res_fork.h Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/include/linux/res_fork.h Sun Sep 7 10:28:23 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.31pre9/include/linux/sched.h linux-2.0.31pre9-privs/include/linux/sched.h --- linux-2.0.31pre9/include/linux/sched.h Sun Sep 7 16:04:15 1997 +++ linux-2.0.31pre9-privs/include/linux/sched.h Sun Sep 7 10:32:29 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_s 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 */ @@ -269,6 +279,8 @@ #define PF_USEDFPU 0x00100000 /* Process used the FPU this quantum (SMP only) */ #define PF_DTRACE 0x00200000 /* delayed trace (used on m68k) */ +#define PF_STACKEXEC 0x01000000 /* Executable stack area forced */ + /* * Limit the stack by to some sane default: root can always * increase this limit if needed.. 8MB seems reasonable. @@ -277,12 +289,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 +308,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 +352,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); @@ -354,21 +372,6 @@ 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); extern void exit_thread(void); @@ -490,6 +493,9 @@ #define for_each_task(p) \ for (p = &init_task ; (p = p->next_task) != &init_task ; ) + +/* x86 start_thread() */ +#include #endif /* __KERNEL__ */ diff -urN linux-2.0.31pre9/include/linux/securelevel.h linux-2.0.31pre9-privs/include/linux/securelevel.h --- linux-2.0.31pre9/include/linux/securelevel.h Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/include/linux/securelevel.h Sun Sep 7 10:28:23 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.31pre9/include/linux/suser.h linux-2.0.31pre9-privs/include/linux/suser.h --- linux-2.0.31pre9/include/linux/suser.h Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/include/linux/suser.h Sun Sep 7 10:32:29 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.31pre9/init/patches/stack_noexec-symlink-security-fix.pinfo linux-2.0.31pre9-privs/init/patches/stack_noexec-symlink-security-fix.pinfo --- linux-2.0.31pre9/init/patches/stack_noexec-symlink-security-fix.pinfo Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/init/patches/stack_noexec-symlink-security-fix.pinfo Sun Sep 7 10:28:23 1997 @@ -0,0 +1 @@ +Non-executable stack and tmp-symlink security fix (Solar Designer ) diff -urN linux-2.0.31pre9/ipc/msg.c linux-2.0.31pre9-privs/ipc/msg.c --- linux-2.0.31pre9/ipc/msg.c Sat Aug 31 23:15:33 1996 +++ linux-2.0.31pre9-privs/ipc/msg.c Sun Sep 7 10:28:24 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.31pre9/ipc/sem.c linux-2.0.31pre9-privs/ipc/sem.c --- linux-2.0.31pre9/ipc/sem.c Sat Aug 31 23:15:34 1996 +++ linux-2.0.31pre9-privs/ipc/sem.c Sun Sep 7 10:28:24 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.31pre9/ipc/shm.c linux-2.0.31pre9-privs/ipc/shm.c --- linux-2.0.31pre9/ipc/shm.c Sun Sep 7 16:04:16 1997 +++ linux-2.0.31pre9-privs/ipc/shm.c Sun Sep 7 10:28:24 1997 @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -285,7 +286,7 @@ switch (cmd) { case SHM_UNLOCK: - if (!suser()) + if (!capable(CAP_IPC_LOCK)) return -EPERM; if (!(ipcp->mode & SHM_LOCKED)) return -EINVAL; @@ -295,7 +296,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; @@ -320,7 +321,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; @@ -331,7 +333,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.31pre9/ipc/util.c linux-2.0.31pre9-privs/ipc/util.c --- linux-2.0.31pre9/ipc/util.c Tue Jan 16 21:32:09 1996 +++ linux-2.0.31pre9-privs/ipc/util.c Sun Sep 7 10:28:24 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.31pre9/kernel/Makefile linux-2.0.31pre9-privs/kernel/Makefile --- linux-2.0.31pre9/kernel/Makefile Tue Jan 9 23:27:39 1996 +++ linux-2.0.31pre9-privs/kernel/Makefile Sun Sep 7 10:28:24 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 @@ -22,4 +22,4 @@ include $(TOPDIR)/Rules.make sched.o: sched.c - $(CC) $(CFLAGS) $(PROFILING) -fno-omit-frame-pointer -c $< + $(CC) $(CFLAGS) $(PROFILING) -DDEFAULT_SECURE_LEVEL=$(DEFAULT_SECURE_LEVEL) -fno-omit-frame-pointer -c $< diff -urN linux-2.0.31pre9/kernel/cap.c linux-2.0.31pre9-privs/kernel/cap.c --- linux-2.0.31pre9/kernel/cap.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/kernel/cap.c Sun Sep 7 10:28:24 1997 @@ -0,0 +1,155 @@ +/* + * 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, the _newly + acquired_ capabilities must be a subset of the _new + permitted_ set. */ + if (!iset) + inheritable = current->cap_inheritable; + else { + cap_set new_i = + cap_purge(inheritable, current->cap_inheritable); + + if (!cap_subset(new_i, 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.31pre9/kernel/exit.c linux-2.0.31pre9-privs/kernel/exit.c --- linux-2.0.31pre9/kernel/exit.c Sun Sep 7 16:04:16 1997 +++ linux-2.0.31pre9-privs/kernel/exit.c Sun Sep 7 10:28:24 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.31pre9/kernel/fork.c linux-2.0.31pre9-privs/kernel/fork.c --- linux-2.0.31pre9/kernel/fork.c Sun Sep 7 16:04:16 1997 +++ linux-2.0.31pre9-privs/kernel/fork.c Sun Sep 7 10:28:24 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.31pre9/kernel/ksyms.c linux-2.0.31pre9-privs/kernel/ksyms.c --- linux-2.0.31pre9/kernel/ksyms.c Tue Mar 11 14:37:16 1997 +++ linux-2.0.31pre9-privs/kernel/ksyms.c Sun Sep 7 10:28:24 1997 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ #include #include #include +#include extern unsigned char aux_device_present, kbd_read_mask; @@ -170,6 +172,7 @@ X(generic_file_read), X(generic_file_mmap), X(generic_readpage), + X(__fput), /* device registration */ X(register_chrdev), @@ -222,7 +225,8 @@ X(search_binary_handler), X(prepare_binprm), X(remove_arg_zero), - + X(compute_creds), + /* execution environment registration */ X(lookup_exec_domain), X(register_exec_domain), diff -urN linux-2.0.31pre9/kernel/module.c linux-2.0.31pre9-privs/kernel/module.c --- linux-2.0.31pre9/kernel/module.c Tue May 21 02:00:30 1996 +++ linux-2.0.31pre9-privs/kernel/module.c Sun Sep 7 10:28:24 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.31pre9/kernel/printk.c linux-2.0.31pre9-privs/kernel/printk.c --- linux-2.0.31pre9/kernel/printk.c Fri Jun 7 01:54:06 1996 +++ linux-2.0.31pre9-privs/kernel/printk.c Sun Sep 7 14:01:57 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_AUDIT_CONTROL)) /* CAP.FIXME */ return -EPERM; switch (type) { case 0: /* Close log */ diff -urN linux-2.0.31pre9/kernel/sched.c linux-2.0.31pre9-privs/kernel/sched.c --- linux-2.0.31pre9/kernel/sched.c Sun Sep 7 16:04:16 1997 +++ linux-2.0.31pre9-privs/kernel/sched.c Sun Sep 7 10:28:24 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 = DEFAULT_SECURE_LEVEL; /* system security level */ long tick = (1000000 + HZ/2) / HZ; /* timer interrupt period */ volatile struct timeval xtime; /* The current time */ @@ -1395,7 +1396,7 @@ newprio = increment; if (increment < 0) { - if (!suser()) + if (!capable(CAP_SYS_NICE)) return -EPERM; newprio = -increment; increase = 1; @@ -1475,10 +1476,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.31pre9/kernel/signal.c linux-2.0.31pre9-privs/kernel/signal.c --- linux-2.0.31pre9/kernel/signal.c Tue Jul 2 09:08:43 1996 +++ linux-2.0.31pre9-privs/kernel/signal.c Sun Sep 7 10:28:24 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.31pre9/kernel/sys.c linux-2.0.31pre9-privs/kernel/sys.c --- linux-2.0.31pre9/kernel/sys.c Sun Sep 7 16:04:16 1997 +++ linux-2.0.31pre9-privs/kernel/sys.c Sun Sep 7 11:17:05 1997 @@ -4,9 +4,11 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include #include +#include #include #include #include @@ -90,13 +92,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; @@ -183,7 +187,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; @@ -247,8 +251,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); @@ -257,7 +261,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; @@ -280,8 +284,9 @@ { int old_egid = current->egid; - if (suser()) - current->gid = current->egid = current->sgid = current->fsgid = gid; + 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; else @@ -341,7 +346,7 @@ char *tmp; int error; - if (!suser()) + if (!capable(CAP_SYS_ACCOUNT)) return -EPERM; if (name == (char *)0) { @@ -457,7 +462,7 @@ if (ruid != (uid_t) -1) { if ((old_ruid == ruid) || (current->euid==ruid) || - suser()) + (capable(CAP_SETUID))) current->uid = ruid; else return(-EPERM); @@ -466,7 +471,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; @@ -477,8 +482,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; } @@ -497,14 +506,19 @@ { int old_euid = current->euid; - if (suser()) - current->uid = current->euid = current->suid = current->fsuid = uid; + if (capable(CAP_SETUID)) + 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); } @@ -519,10 +533,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; } @@ -534,7 +553,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; @@ -692,7 +712,7 @@ { int i; - if (!suser()) + if (!capable(CAP_SETGID)) return -EPERM; if (gidsetsize > NGROUPS) return -EINVAL; @@ -789,7 +809,7 @@ { int error; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; @@ -825,7 +845,7 @@ { int error; - if (!suser()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; @@ -866,7 +886,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.31pre9/kernel/sysctl.c linux-2.0.31pre9-privs/kernel/sysctl.c --- linux-2.0.31pre9/kernel/sysctl.c Sun Sep 7 16:04:16 1997 +++ linux-2.0.31pre9-privs/kernel/sysctl.c Sun Sep 7 10:28:24 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.31pre9/kernel/time.c linux-2.0.31pre9-privs/kernel/time.c --- linux-2.0.31pre9/kernel/time.c Sun Sep 7 16:04:16 1997 +++ linux-2.0.31pre9-privs/kernel/time.c Sun Sep 7 10:28:24 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.31pre9/mm/mlock.c linux-2.0.31pre9-privs/mm/mlock.c --- linux-2.0.31pre9/mm/mlock.c Sun Sep 7 16:04:16 1997 +++ linux-2.0.31pre9-privs/mm/mlock.c Sun Sep 7 10:28:24 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.31pre9/mm/mmap.c linux-2.0.31pre9-privs/mm/mmap.c --- linux-2.0.31pre9/mm/mmap.c Fri Nov 22 06:25:17 1996 +++ linux-2.0.31pre9-privs/mm/mmap.c Sun Sep 7 10:28:24 1997 @@ -308,7 +308,11 @@ if (len > TASK_SIZE) return 0; if (!addr) +#ifdef MMAP_ADDR + addr = MMAP_ADDR; +#else addr = TASK_SIZE / 3; +#endif addr = PAGE_ALIGN(addr); for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { diff -urN linux-2.0.31pre9/mm/swapfile.c linux-2.0.31pre9-privs/mm/swapfile.c --- linux-2.0.31pre9/mm/swapfile.c Mon Mar 31 13:22:37 1997 +++ linux-2.0.31pre9-privs/mm/swapfile.c Sun Sep 7 10:28:24 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.31pre9/net/appletalk/ddp.c linux-2.0.31pre9-privs/net/appletalk/ddp.c --- linux-2.0.31pre9/net/appletalk/ddp.c Sun Sep 7 16:04:17 1997 +++ linux-2.0.31pre9-privs/net/appletalk/ddp.c Sun Sep 7 10:28:24 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; @@ -855,7 +856,7 @@ ((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node=ATADDR_BCAST; break; case SIOCATALKDIFADDR: - if(!suser()) + if(!capable(CAP_NET_IFCONFIG)) return -EPERM; if(sa->sat_family!=AF_APPLETALK) return -EINVAL; @@ -1996,7 +1997,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.31pre9/net/ax25/af_ax25.c linux-2.0.31pre9-privs/net/ax25/af_ax25.c --- linux-2.0.31pre9/net/ax25/af_ax25.c Thu Nov 14 05:20:10 1996 +++ linux-2.0.31pre9-privs/net/ax25/af_ax25.c Sun Sep 7 10:28:24 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.31pre9/net/ax25/ax25_route.c linux-2.0.31pre9-privs/net/ax25/ax25_route.c --- linux-2.0.31pre9/net/ax25/ax25_route.c Sat Aug 10 00:03:16 1996 +++ linux-2.0.31pre9-privs/net/ax25/ax25_route.c Sun Sep 7 10:28:24 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.31pre9/net/bridge/br.c linux-2.0.31pre9-privs/net/bridge/br.c --- linux-2.0.31pre9/net/bridge/br.c Sun Sep 7 16:04:17 1997 +++ linux-2.0.31pre9-privs/net/bridge/br.c Sun Sep 7 10:28:25 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.31pre9/net/core/dev.c linux-2.0.31pre9-privs/net/core/dev.c --- linux-2.0.31pre9/net/core/dev.c Sun Sep 7 16:04:17 1997 +++ linux-2.0.31pre9-privs/net/core/dev.c Sun Sep 7 10:28:25 1997 @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -1459,7 +1460,7 @@ case SIOCSIFSLAVE: case SIOCADDMULTI: case SIOCDELMULTI: - if (!suser()) + if (!capable(CAP_NET_IFCONFIG)) return -EPERM; return dev_ifsioc(arg, cmd); @@ -1479,7 +1480,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.31pre9/net/core/sock.c linux-2.0.31pre9-privs/net/core/sock.c --- linux-2.0.31pre9/net/core/sock.c Sun Sep 7 16:04:17 1997 +++ linux-2.0.31pre9-privs/net/core/sock.c Sun Sep 7 10:28:25 1997 @@ -90,6 +90,7 @@ #include #include #include +#include #include #include #include @@ -157,7 +158,7 @@ switch(optname) { case SO_DEBUG: - if(val && !suser()) + if(val && !capable(CAP_NET_DEBUG)) return(-EPERM); sk->debug=valbool; return 0; @@ -168,9 +169,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.31pre9/net/ipv4/af_inet.c linux-2.0.31pre9-privs/net/ipv4/af_inet.c --- linux-2.0.31pre9/net/ipv4/af_inet.c Sun Sep 7 16:04:17 1997 +++ linux-2.0.31pre9-privs/net/ipv4/af_inet.c Sun Sep 7 10:28:25 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; @@ -621,7 +623,7 @@ if (snum == 0) snum = sk->prot->good_socknum(); if (snum < PROT_SOCK) { - if (!suser()) + if (!capable(CAP_NET_BIND_SERVICE)) return(-EACCES); if (snum == 0) return(-EAGAIN); @@ -632,7 +634,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! */ } @@ -948,7 +950,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.31pre9/net/ipv4/arp.c linux-2.0.31pre9-privs/net/ipv4/arp.c --- linux-2.0.31pre9/net/ipv4/arp.c Sun Sep 7 16:04:17 1997 +++ linux-2.0.31pre9-privs/net/ipv4/arp.c Sun Sep 7 10:28:25 1997 @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include @@ -2227,7 +2228,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)); @@ -2237,7 +2238,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.31pre9/net/ipv4/ip_sockglue.c linux-2.0.31pre9-privs/net/ipv4/ip_sockglue.c --- linux-2.0.31pre9/net/ipv4/ip_sockglue.c Sun Sep 7 16:04:18 1997 +++ linux-2.0.31pre9-privs/net/ipv4/ip_sockglue.c Sun Sep 7 10:28:25 1997 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -182,7 +183,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) { @@ -396,7 +398,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; @@ -412,7 +414,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; @@ -430,7 +432,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.31pre9/net/ipv4/rarp.c linux-2.0.31pre9-privs/net/ipv4/rarp.c --- linux-2.0.31pre9/net/ipv4/rarp.c Sun Sep 7 16:04:18 1997 +++ linux-2.0.31pre9-privs/net/ipv4/rarp.c Sun Sep 7 10:28:25 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.31pre9/net/ipv4/raw.c linux-2.0.31pre9-privs/net/ipv4/raw.c --- linux-2.0.31pre9/net/ipv4/raw.c Tue Apr 8 08:47:47 1997 +++ linux-2.0.31pre9-privs/net/ipv4/raw.c Sun Sep 7 10:28:25 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.31pre9/net/ipv4/route.c linux-2.0.31pre9-privs/net/ipv4/route.c --- linux-2.0.31pre9/net/ipv4/route.c Sun Sep 7 16:04:18 1997 +++ linux-2.0.31pre9-privs/net/ipv4/route.c Sun Sep 7 10:28:25 1997 @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -1724,7 +1725,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.31pre9/net/ipv4/udp.c linux-2.0.31pre9-privs/net/ipv4/udp.c --- linux-2.0.31pre9/net/ipv4/udp.c Sun Sep 7 16:04:21 1997 +++ linux-2.0.31pre9-privs/net/ipv4/udp.c Sun Sep 7 10:28:25 1997 @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -604,7 +605,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.31pre9/net/ipx/af_ipx.c linux-2.0.31pre9-privs/net/ipx/af_ipx.c --- linux-2.0.31pre9/net/ipx/af_ipx.c Sun Sep 7 16:04:21 1997 +++ linux-2.0.31pre9-privs/net/ipx/af_ipx.c Sun Sep 7 10:28:25 1997 @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -1863,7 +1864,8 @@ return -EINVAL; } - if(ntohs(addr->sipx_port)sipx_port)protinfo.af_ipx.port=addr->sipx_port; @@ -2279,13 +2281,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)); @@ -2303,7 +2305,7 @@ * This socket wants to take care of the NCP connection * handed to us in arg. */ - if (!suser()) return(-EPERM); + if (!capable(CAP_NET_BIND_SERVICE)) return(-EPERM); err = verify_area(VERIFY_READ, (void *)arg, sizeof(unsigned short)); if (err) return err; diff -urN linux-2.0.31pre9/net/netrom/af_netrom.c linux-2.0.31pre9-privs/net/netrom/af_netrom.c --- linux-2.0.31pre9/net/netrom/af_netrom.c Sat Aug 10 00:03:16 1996 +++ linux-2.0.31pre9-privs/net/netrom/af_netrom.c Sun Sep 7 10:28:25 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.31pre9/scripts/captest.c linux-2.0.31pre9-privs/scripts/captest.c --- linux-2.0.31pre9/scripts/captest.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/scripts/captest.c Sun Sep 7 10:28:25 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); +}