Index: contrib/amd/include/am_defs.h =================================================================== RCS file: /home/ncvs/src/contrib/amd/include/am_defs.h,v retrieving revision 1.8 diff -u -r1.8 am_defs.h --- contrib/amd/include/am_defs.h 1999/11/05 11:58:03 1.8 +++ contrib/amd/include/am_defs.h 2000/04/12 17:04:20 @@ -445,6 +445,7 @@ * Actions to take if exists. */ #ifdef HAVE_SYS_UCRED_H +#include # include #endif /* HAVE_SYS_UCRED_H */ Index: include/rpcsvc/bootparam_prot.x =================================================================== RCS file: /home/ncvs/src/include/rpcsvc/bootparam_prot.x,v retrieving revision 1.5 diff -u -r1.5 bootparam_prot.x --- include/rpcsvc/bootparam_prot.x 1999/08/27 23:45:07 1.5 +++ include/rpcsvc/bootparam_prot.x 2000/04/12 18:00:22 @@ -43,6 +43,7 @@ %#include %#include %#include +%#include %#include #else %#ifndef lint Index: lib/libc/gen/getmntinfo.c =================================================================== RCS file: /home/ncvs/src/lib/libc/gen/getmntinfo.c,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 getmntinfo.c --- lib/libc/gen/getmntinfo.c 1994/05/27 04:56:40 1.1.1.1 +++ lib/libc/gen/getmntinfo.c 2000/01/09 07:19:44 @@ -36,6 +36,7 @@ #endif /* LIBC_SCCS and not lint */ #include +#include #include #include #include Index: lib/libkvm/kvm_getswapinfo.c =================================================================== RCS file: /home/ncvs/src/lib/libkvm/kvm_getswapinfo.c,v retrieving revision 1.12 diff -u -r1.12 kvm_getswapinfo.c --- lib/libkvm/kvm_getswapinfo.c 2000/04/16 17:36:48 1.12 +++ lib/libkvm/kvm_getswapinfo.c 2000/04/16 22:47:54 @@ -19,6 +19,7 @@ #include #include +#include #include #include #include Index: sys/coda/coda_namecache.c =================================================================== RCS file: /home/ncvs/src/sys/coda/coda_namecache.c,v retrieving revision 1.10 diff -u -r1.10 coda_namecache.c --- sys/coda/coda_namecache.c 1999/08/28 00:40:53 1.10 +++ sys/coda/coda_namecache.c 2000/04/12 04:43:28 @@ -79,6 +79,7 @@ #include #include #include +#include #include #include Index: sys/i386/conf/CAP =================================================================== RCS file: CAP diff -N CAP --- /dev/null Fri Sep 1 08:50:50 2000 +++ CAP Mon Aug 7 18:37:51 2000 @@ -0,0 +1,234 @@ +# +# GENERIC -- Generic kernel configuration file for FreeBSD/i386 +# +# For more information on this file, please read the handbook section on +# Kernel Configuration Files: +# +# http://www.FreeBSD.org/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the NOTES configuration file. If you are +# in doubt as to the purpose or necessity of a line, check first in NOTES. +# +# $FreeBSD: src/sys/i386/conf/GENERIC,v 1.269 2000/07/29 02:12:44 obrien Exp $ + +machine i386 +cpu I386_CPU +cpu I486_CPU +cpu I586_CPU +cpu I686_CPU +ident GENERIC +maxusers 32 + +hints "GENERIC.hints" #Default places to look for devices. + +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +options DDB + +options MATH_EMULATE #Support for x87 emulation +options INET #InterNETworking +options INET6 #IPv6 communications protocols +options FFS #Berkeley Fast Filesystem +options FFS_ROOT #FFS usable as root device [keep this!] +options FFS_EXTATTR #FFS extended attributes +options SOFTUPDATES #Enable FFS soft updates support +options MFS #Memory Filesystem +options MD_ROOT #MD is a potential root device +options NFS #Network Filesystem +options NFS_ROOT #NFS usable as root device, NFS required +options MSDOSFS #MSDOS Filesystem +options CD9660 #ISO 9660 Filesystem +options CD9660_ROOT #CD-ROM usable as root, CD9660 required +options PROCFS #Process filesystem +options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!] +options SCSI_DELAY=15000 #Delay (in ms) before probing SCSI +options UCONSOLE #Allow users to grab the console +options USERCONFIG #boot -c editor +options VISUAL_USERCONFIG #visual boot -c editor +options KTRACE #ktrace(1) support +options SYSVSHM #SYSV-style shared memory +options SYSVMSG #SYSV-style message queues +options SYSVSEM #SYSV-style semaphores +options P1003_1B #Posix P1003_1B real-time extensions +options _KPOSIX_PRIORITY_SCHEDULING +options KBD_INSTALL_CDEV # install a CDEV entry in /dev +options RANDOMDEV #entropy device +options CAPABILITIES + +# To make an SMP kernel, the next two are needed +#options SMP # Symmetric MultiProcessor Kernel +#options APIC_IO # Symmetric (APIC) I/O +# Optionally these may need tweaked, (defaults shown): +#options NCPU=2 # number of CPUs +#options NBUS=8 # number of busses +#options NAPIC=1 # number of IO APICs +#options NINTR=24 # number of INTs + +device isa +device eisa +device pci +options COMPAT_OLDISA # compatability shims for lnc, fe, le +options COMPAT_OLDPCI # compatability shims for lnc, vx + +# Floppy drives +device fdc + +# ATA and ATAPI devices +device ata +device atadisk # ATA disk drives +device atapicd # ATAPI CDROM drives +device atapifd # ATAPI floppy drives +device atapist # ATAPI tape drives +options ATA_STATIC_ID #Static device numbering +#options ATA_ENABLE_ATAPI_DMA #Enable DMA on ATAPI devices + +# SCSI Controllers +device ahb # EISA AHA1742 family +device ahc # AHA2940 and onboard AIC7xxx devices +device amd # AMD 53C974 (Teckram DC-390(T)) +device dpt # DPT Smartcache - See NOTES for options! +device isp # Qlogic family +#device ncr # NCR/Symbios Logic +device sym # NCR/Symbios Logic (newer chipsets + those of `ncr') + +device adv +device adw +device bt +device aha 1 +device aic + +# SCSI peripherals +device scbus # SCSI bus (required) +device da # Direct Access (disks) +device sa # Sequential Access (tape etc) +device cd # CD +device pass # Passthrough device (direct SCSI access) + +# RAID controllers +device ida # Compaq Smart RAID +device amr # AMI MegaRAID +device mlx # Mylex DAC960 family + +# atkbdc0 controls both the keyboard and the PS/2 mouse +device atkbdc 1 +device atkbd +device psm + +device vga + +# splash screen/screen saver +device splash + +# syscons is the default console driver, resembling an SCO console +device sc 1 + +# Enable this for the pcvt (VT220 compatible) console driver +#device vt +#options XSERVER # support for X server on a vt console +#options FAT_CURSOR # start with block cursor +# If you have a ThinkPAD, uncomment this along with the rest of the PCVT lines +#options PCVT_SCANSET=2 # IBM keyboards are non-std + +# Floating point support - do not disable. +device npx + +# Power management support (see NOTES for more options) +device apm + +# PCCARD (PCMCIA) support +device card +device pcic + +# Serial (COM) ports +device sio + +# Parallel port +device ppc +device ppbus # Parallel port bus (required) +device lpt # Printer +device plip # TCP/IP over parallel +device ppi # Parallel port interface device +#device vpo # Requires scbus and da + + +# PCI Ethernet NICs. +device de # DEC/Intel DC21x4x (``Tulip'') +device fxp # Intel EtherExpress PRO/100B (82557, 82558) +device tx # SMC 9432TX (83c170 ``EPIC'') +device vx # 3Com 3c590, 3c595 (``Vortex'') +device wx # Intel Gigabit Ethernet Card (``Wiseman'') + +# PCI Ethernet NICs that use the common MII bus controller code. +device miibus # MII bus support +device dc # DEC/Intel 21143 and various workalikes +device rl # RealTek 8129/8139 +device sf # Adaptec AIC-6915 (``Starfire'') +device sis # Silicon Integrated Systems SiS 900/SiS 7016 +device ste # Sundance ST201 (D-Link DFE-550TX) +device tl # Texas Instruments ThunderLAN +device vr # VIA Rhine, Rhine II +device wb # Winbond W89C840F +device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'') + +# ISA Ethernet NICs. +device ed +device ex +device ep +device cs +device sn +# WaveLAN/IEEE 802.11 wireless NICs. Note: the WaveLAN/IEEE really +# exists only as a PCMCIA device, so there is no ISA attatement needed +# and resources will always be dynamically assigned by the pccard code. +device wi +# Aironet 4500/4800 802.11 wireless NICs. Note: the declaration below will +# work for PCMCIA and PCI cards, as well as ISA cards set to ISA PnP +# mode (the factory default). If you set the switches on your ISA +# card for a manually chosen I/O address and IRQ, you must specify +# those paremeters here. +device an +# BayStack 660 and others +device awi +# Xircom pccard ethernet +device xe +# The probe order of these is presently determined by i386/isa/isa_compat.c. +device ie +device fe +device le +device lnc + +# Pseudo devices - the number indicates how many units to allocated. +device loop # Network loopback +device ether # Ethernet support +device sl # Kernel SLIP +device ppp 1 # Kernel PPP +device tun # Packet tunnel. +device pty # Pseudo-ttys (telnet etc) +device md # Memory "disks" +device gif 4 # IPv6 and IPv4 tunneling +device faith 1 # IPv6-to-IPv4 relaying (translation) + +# The `bpf' device enables the Berkeley Packet Filter. +# Be aware of the administrative consequences of enabling this! +device bpf # Berkeley packet filter + +# USB support +device uhci # UHCI PCI->USB interface +device ohci # OHCI PCI->USB interface +device usb # USB Bus (required) +#device udbp # USB Double Bulk Pipe devices +device ugen # Generic +device uhid # "Human Interface Devices" +device ukbd # Keyboard +device ulpt # Printer +device umass # Disks/Mass storage - Requires scbus and da +device ums # Mouse +device urio # Diamond Rio 500 MP3 player +# USB Ethernet, requires mii +device aue # ADMtek USB ethernet +device cue # CATC USB ethernet +device kue # Kawasaki LSI USB ethernet Index: sys/kern/init_main.c =================================================================== RCS file: /home/ncvs/src/sys/kern/init_main.c,v retrieving revision 1.139 diff -u -r1.139 init_main.c --- sys/kern/init_main.c 2000/08/20 21:34:33 1.139 +++ sys/kern/init_main.c 2000/08/24 02:19:10 @@ -72,6 +72,7 @@ #include #include #include +#include extern struct linker_set sysinit_set; /* XXX */ @@ -306,6 +307,9 @@ p->p_ucred = crget(); p->p_ucred->cr_ngroups = 1; /* group 0 */ + /* Give all kernel processes many capabilities */ + cap_init_proc0(&p->p_ucred->cr_cap); + /* Don't jail it */ p->p_prison = 0; @@ -568,6 +572,13 @@ initproc->p_flag |= P_INMEM | P_SYSTEM; cpu_set_fork_handler(initproc, start_init, NULL); remrunqueue(initproc); + + /* + * Give init necessary capabilities to shut the system down and + * avoid a panic when done. + */ + cap_init_proc1(&initproc->p_ucred->cr_cap); + splx(s); } SYSINIT(init,SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL) Index: sys/kern/kern_acct.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_acct.c,v retrieving revision 1.26 diff -u -r1.26 kern_acct.c --- sys/kern/kern_acct.c 2000/07/04 03:34:06 1.26 +++ sys/kern/kern_acct.c 2000/08/09 01:08:58 @@ -120,9 +120,10 @@ int error, flags; /* Make sure that the caller is root. */ - error = suser(p); - if (error) + if (((error = suser(p)) != 0) && + ((error = cap_check(p, CAP_SYS_PACCT)) != 0)) return (error); + suser_used(p); /* * If accounting is to be started to a file, open that file for Index: sys/kern/kern_cap.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_cap.c,v retrieving revision 1.3 diff -u -r1.3 kern_cap.c --- sys/kern/kern_cap.c 2000/07/25 03:37:36 1.3 +++ sys/kern/kern_cap.c 2000/08/28 12:34:53 @@ -26,13 +26,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/kern/kern_cap.c,v 1.3 2000/07/25 03:37:36 rwatson Exp $ + * $FreeBSD: src/sys/kern/kern_cap.c,v 1.3 2000/07/25 03:37:36 rwatson Exp $ */ /* * Developed by the TrustedBSD Project. * Support for POSIX.1e process capabilities. - * - * XXX Currently just syscall stubs */ #include @@ -43,15 +41,298 @@ #include #include #include +#include +#include + +#include "opt_cap.h" + +static void cap_zero(struct cap *cap_p); +static int cap_valid(struct cap *cap_p); +static int cap_subset(struct cap *cap1, struct cap *cap2); +static int cap_get_vp(struct vnode *vp, int ioflg, struct cap *cap_p, + struct proc *p); +static int cap_set_vp(struct vnode *vp, int ioflg, struct cap *cap_p, + struct proc *p); + +/* + * Return a capability set to a state where it has no flags enabled. + */ +static void +cap_zero(struct cap *cap_p) +{ + + bzero(cap_p, sizeof(*cap_p)); +} + +/* + * Check the validity of a capability set -- 0 on success, EINVAL otherwise + */ +static int +cap_valid(struct cap *cap_p) +{ + + /* + * effective and inheritable cannot contain anything not in + * permitted + */ + if ((cap_p->c_permitted[0] | cap_p->c_effective[0] | + cap_p->c_inheritable[0]) != cap_p->c_permitted[0]) + return (EINVAL); + + if ((cap_p->c_permitted[1] | cap_p->c_effective[1] | + cap_p->c_inheritable[1]) != cap_p->c_permitted[1]) + return (EINVAL); + + /* + * None of the masks should contain mask indexing information + */ + if (cap_p->c_permitted[0] & CAP_TYPE_MASK) + return (EINVAL); + if (cap_p->c_permitted[1] & CAP_TYPE_MASK) + return (EINVAL); + + return (0); +} + +/* + * Check whether cap2 is a strict subset of cap1 + * This only checks that cap2's permitted mask is a subset of cap1's permitted + * mask. cap_valid() can be used to check that the inheritable and effective + * masks are valid for the new capability set. + */ +static int +cap_subset(struct cap *cap1, struct cap *cap2) +{ + + if ((cap1->c_permitted[0] | cap2->c_permitted[0]) != + cap1->c_permitted[0]) + return (EPERM); + + if ((cap1->c_permitted[1] | cap2->c_permitted[1]) != + cap1->c_permitted[1]) + return (EPERM); + return (0); +} + /* + * cap_proc0: initialize capabilities for kernel processes + * + * XXX for now, give them all capabilities, as kernel processes may + * need to do all kinds of things. + */ +void +cap_init_proc0(struct cap *cap_p) +{ + int i; + + /* all effective rights */ + for (i = 0; i < __CAP_MASK_LEN; i++) + cap_p->c_effective[i] = 0xffffffff; + for (i = 0; i < __CAP_MASK_LEN; i++) + cap_p->c_permitted[i] = 0xffffffff; + for (i = 0; i < __CAP_MASK_LEN; i++) + cap_p->c_inheritable[i] = 0xffffffff; +} + +/* + * cap_init: initialize capabilities for init + * + * XXX init requires CAP_KILL in order to shut the system + * down successfully, as well as CAP_SYS_BOOT. + */ +void +cap_init_proc1(struct cap *cap_p) +{ + + bzero(cap_p, sizeof(struct cap)); + + /* + * Give init the ability to kill processes later to shut + * down. Set as not-inheritable so those processes don't + * get extra rights. + * + * XXX we may need to setsugid() init, so would require + * a proc pointer, not just the cap pointer here. + */ + SET_CAPABILITY(cap_p->c_permitted, CAP_KILL); + SET_CAPABILITY(cap_p->c_effective, CAP_KILL); + SET_CAPABILITY(cap_p->c_permitted, CAP_SYS_BOOT); + SET_CAPABILITY(cap_p->c_effective, CAP_SYS_BOOT); +} + +/* + * Perform capability inheritence on p, with optional vnode for a file + * from which to gain/mask new capabilities. To not use a vnode, set + * vp to NULL. + * + * POSIX.1e defines the following inheritence: + * pI` = pI + * pP` = (fP` & X) | (fI & pI) + * pE` = fE & pP + */ +void +cap_inherit(struct vnode *vp, struct proc *p) +{ + struct cap cap_file; + struct cap *cap_p_proc; + int len, error; + +#ifndef CAPABILITIES + return; +#else /* CAPABILITIES */ + + /* + * XXX have to do this, since we don't know if capabilities will + * change. This should be fixed to not crcopy if the capabilities + * have not changed. + */ + p->p_ucred = crcopy(p->p_ucred); + cap_p_proc = &p->p_ucred->cr_cap; + + len = sizeof(cap_file); + error = cap_get_vp(vp, 0, &cap_file, p); + if (error) { + printf("cap_inherit: error retrieving capability\n"); + printf("error: %d\n", error); + } + + /* no change to cap_p_proc->c_inheritable[0,1] */ + /* changes to permitted */ + if (error == 0) { + cap_p_proc->c_permitted[0] = cap_file.c_permitted[0] | + (cap_file.c_inheritable[0] & + cap_p_proc->c_inheritable[0]); + cap_p_proc->c_permitted[1] = cap_file.c_permitted[1] | + (cap_file.c_inheritable[1] & + cap_p_proc->c_inheritable[1]); + } else { + cap_p_proc->c_permitted[0] = 0; + cap_p_proc->c_permitted[1] = 0; + } + /* changes to effective: */ + if (error == 0) { + cap_p_proc->c_effective[0] = cap_file.c_effective[0] & + cap_p_proc->c_permitted[0]; + cap_p_proc->c_effective[1] = cap_file.c_effective[1] & + cap_p_proc->c_permitted[1]; + } else { + cap_p_proc->c_effective[0] = 0; + cap_p_proc->c_effective[1] = 0; + } + + /* + * Currently, we protect a process only if some of its capability + * bits end up being turned on. Is this correct? + */ + if ((cap_p_proc->c_permitted[0] || cap_p_proc->c_permitted[1]) || + (cap_p_proc->c_effective[0] || cap_p_proc->c_effective[1]) || + (cap_p_proc->c_inheritable[0] || cap_p_proc->c_inheritable[1])) + setsugid(p); +#endif /* CAPABILITIES */ +} + +/* + * cap_check_xxx, cap_check: perform an authorization check to see if + * the given process has the specified capability, optionally with flags + * in the style of suser_xxx/suser. + */ +int +cap_check_xxx(struct ucred *cred, struct proc *proc, cap_value_t cap, int flags) +{ + +#ifndef CAPABILITIES + return (EPERM); +#else /* CAPABILITIES */ + + if (!cred && !proc) { + printf("cap_check_xxx(): THINK!\n"); + return (EPERM); + } + if (!cred) + cred = proc->p_ucred; + if (!(cred->cr_cap.c_effective[CAP_TYPE_MASK & cap] & + (cap & ~CAP_TYPE_MASK))) + return (EPERM); + if (proc && proc->p_prison && !(flags & PRISON_ROOT)) + return (EPERM); + if (proc) + proc->p_acflag |= ASU; + return (0); + +#endif /* CAPABILITIES */ +} + +int +cap_check(struct proc *p, cap_value_t cap) +{ + + return (cap_check_xxx(NULL, p, cap, 0)); +} + +/* + * Internal function to retrieve the capability block from a + * vnode. Will always fill in the cap set, possibly by zero'ing it + * if the file doesn't have a capability, or if it is invalid. + */ +static int +cap_get_vp(struct vnode *vp, int ioflg, struct cap *cap_p, struct proc *p) +{ + int len, error; + + len = sizeof(*cap_p); + error = vn_extattr_get(vp, ioflg, POSIX1E_CAPABILITY_EXTATTR_NAME, + &len, (char *) cap_p, p); + /* + * XXX should check for ENOATTR and convert to null capability it + * received, not ENOENT + */ + if (error == ENOENT || error == EOPNOTSUPP) { + /* + * Coerce no capability attribute to a null capability set + */ + error = 0; + cap_zero(cap_p); + } else if (error == 0 && len != sizeof(*cap_p)) { + printf("__cap_get_file: invalid capability on file\n"); + cap_zero(cap_p); + } + return (error); +} + +/* + * Internal function to set the capability set for a vnode. + * Partial writes of extended attributes may be a problem if the + * underlying implementation doesn't properly return failure + * information. A partial write *should* result in an invalid + * capability, which cap_get_vp will convert into a NULL capability + * set. + */ +static int cap_set_vp(struct vnode *vp, int ioflg, struct cap *cap_p, + struct proc *p) +{ + int len, error; + + if ((error = cap_check_xxx(NULL, p, CAP_SETFCAP, PRISON_ROOT)) && + (error = suser_xxx(NULL, p, PRISON_ROOT))) + return (error); + /* audit privilege here */ + + len = sizeof(*cap_p); + error = vn_extattr_set(vp, ioflg, POSIX1E_CAPABILITY_EXTATTR_NAME, + len, (char *) cap_p, p); + return (error); +} + +/* * Syscall to allow a process to get it's currently capability set */ int __cap_get_proc(struct proc *p, struct __cap_get_proc_args *uap) { - return (ENOSYS); + return (copyout(&p->p_ucred->cr_cap, (caddr_t)uap->cap_p, + sizeof (struct cap))); } /* @@ -61,10 +342,42 @@ int __cap_set_proc(struct proc *p, struct __cap_set_proc_args *uap) { + struct cap capability; + int error, ok = 0, requires_privilege; - return (ENOSYS); + error = copyin(SCARG(uap, cap_p), &capability, sizeof(struct cap)); + if (error) + return (error); + + if ((error = cap_valid(&capability))) + return (error); + + requires_privilege = 1; + + if (suser_xxx(NULL, p, PRISON_ROOT) == 0) + ok = 1; + + if (cap_check_xxx(NULL, p, CAP_SETPCAP, PRISON_ROOT) == 0) + ok = 1; + + if (cap_subset(&p->p_ucred->cr_cap, &capability) == 0) { + ok = 1; + requires_privilege = 0; + } + + if (!ok) + return (EPERM); + + if (requires_privilege) + suser_used(p); + + p->p_ucred = crcopy(p->p_ucred); + p->p_ucred->cr_cap = capability; + + return (0); } + /* * Syscalls to allow a process to retrieve capabilities associated with * files, if permitted. @@ -72,6 +385,8 @@ int __cap_get_fd(struct proc *p, struct __cap_get_fd_args *uap) { + struct cap cap; + int error; return (ENOSYS); } @@ -79,8 +394,21 @@ int __cap_get_file(struct proc *p, struct __cap_get_file_args *uap) { + struct nameidata nd; + struct cap cap; + int error; + + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path_p), p); + if ((error = namei(&nd)) != 0) + return (error); + + error = cap_get_vp(nd.ni_vp, IO_NODELOCKED, &cap, p); + if (error == 0) + error = copyout(&cap, SCARG(uap, cap_p), sizeof(cap)); - return (ENOSYS); + NDFREE(&nd, 0); + return (error); } /* @@ -90,6 +418,8 @@ int __cap_set_fd(struct proc *p, struct __cap_set_fd_args *uap) { + struct cap cap; + int error; return (ENOSYS); } @@ -97,6 +427,21 @@ int __cap_set_file(struct proc *p, struct __cap_set_file_args *uap) { + struct nameidata nd; + struct cap cap; + int error; + + error = copyin(SCARG(uap, cap_p), &cap, sizeof(cap)); + if (error) + return (error); + + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, + SCARG(uap, path_p), p); + if ((error = namei(&nd)) != 0) + return (error); - return (ENOSYS); + error = cap_set_vp(nd.ni_vp, IO_NODELOCKED, &cap, p); + + NDFREE(&nd, 0); + return (error); } Index: sys/kern/kern_exec.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_exec.c,v retrieving revision 1.112 diff -u -r1.112 kern_exec.c --- sys/kern/kern_exec.c 2000/07/05 07:46:40 1.112 +++ sys/kern/kern_exec.c 2000/08/09 00:57:53 @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -275,6 +276,8 @@ * * Don't honor setuid/setgid if the filesystem prohibits it or if * the process is being traced. + * + * Do CAP execution stuff here, in style of setuid/setgid */ if ((((attr.va_mode & VSUID) && p->p_ucred->cr_uid != attr.va_uid) || ((attr.va_mode & VSGID) && p->p_ucred->cr_gid != attr.va_gid)) && @@ -284,11 +287,13 @@ * Turn off syscall tracing for set-id programs, except for * root. */ - if (p->p_tracep && suser(p)) { + if (p->p_tracep && suser(p) && cap_check(p, CAP_SYS_PTRACE)) { p->p_traceflag = 0; vrele(p->p_tracep); p->p_tracep = NULL; } + if (p->p_tracep) + suser_used(p); /* * Set the new credentials. */ @@ -310,6 +315,14 @@ */ p->p_cred->p_svuid = p->p_ucred->cr_uid; p->p_cred->p_svgid = p->p_ucred->cr_gid; + + /* + * CAP inheritence, et al. + * XXX should this be above the file CAP stuff? + * XXX is this the right vp? could be the vp from the interpreter. + * XXX vp is now unlocked? + */ + cap_inherit(ndp->ni_vp, p); /* * Store the vp for use in procfs Index: sys/kern/kern_jail.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_jail.c,v retrieving revision 1.7 diff -u -r1.7 kern_jail.c --- sys/kern/kern_jail.c 2000/06/04 04:28:31 1.7 +++ sys/kern/kern_jail.c 2000/08/09 01:09:40 @@ -51,9 +51,11 @@ struct jail j; struct chroot_args ca; - error = suser(p); - if (error) + if (((error = suser(p)) != 0) && + ((error = cap_check(p, CAP_SYS_CHROOT)) != 0)) return (error); + suser_used(p); + error = copyin(uap->jail, &j, sizeof j); if (error) return (error); Index: sys/kern/kern_linker.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_linker.c,v retrieving revision 1.50 diff -u -r1.50 kern_linker.c --- sys/kern/kern_linker.c 2000/08/02 21:08:53 1.50 +++ sys/kern/kern_linker.c 2000/08/09 01:10:25 @@ -689,8 +689,10 @@ if (securelevel > 0) /* redundant, but that's OK */ return EPERM; - if ((error = suser(p)) != 0) + if (((error = suser(p)) != 0) && + ((error = cap_check(p, CAP_SYS_MODULE)) != 0)) return error; + suser_used(p); realpath = NULL; pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); @@ -732,8 +734,10 @@ if (securelevel > 0) /* redundant, but that's OK */ return EPERM; - if ((error = suser(p)) != 0) + if (((error = suser(p)) != 0) && + ((error = cap_check(p, CAP_SYS_MODULE)) != 0)) return error; + suser_used(p); lf = linker_find_file_by_id(SCARG(uap, fileid)); if (lf) { Index: sys/kern/kern_ntptime.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_ntptime.c,v retrieving revision 1.35 diff -u -r1.35 kern_ntptime.c --- sys/kern/kern_ntptime.c 2000/07/04 11:25:22 1.35 +++ sys/kern/kern_ntptime.c 2000/08/09 01:13:28 @@ -285,10 +285,12 @@ * the assumption the superuser should know what it is doing. */ modes = ntv.modes; - if (modes) - error = suser(p); - if (error) - return (error); + if (modes) { + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_TIME))); + return (error); + suser_used(p); + } s = splclock(); if (modes & MOD_FREQUENCY) { freq = (ntv.freq * 1000LL) >> 16; Index: sys/kern/kern_prot.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_prot.c,v retrieving revision 1.62 diff -u -r1.62 kern_prot.c --- sys/kern/kern_prot.c 2000/08/31 15:55:17 1.62 +++ sys/kern/kern_prot.c 2000/09/01 04:18:06 @@ -411,6 +411,7 @@ #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ uid != pc->pc_ucred->cr_uid && /* allow setuid(geteuid()) */ #endif + (error = cap_check_xxx(0, p, CAP_SETUID, PRISON_ROOT)) && (error = suser_xxx(0, p, PRISON_ROOT))) return (error); @@ -423,7 +424,8 @@ #ifdef POSIX_APPENDIX_B_4_2_2 /* Use the clause from B.4.2.2 */ uid == pc->pc_ucred->cr_uid || #endif - suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ + suser_xxx(0, p, PRISON_ROOT) == 0 || /* we are using privs */ + cap_check_xxx(0, p, CAP_SETUID, PRISON_ROOT) == 0) #endif { /* @@ -483,7 +485,8 @@ euid = uap->euid; if (euid != pc->p_ruid && /* allow seteuid(getuid()) */ euid != pc->p_svuid && /* allow seteuid(saved uid) */ - (error = suser_xxx(0, p, PRISON_ROOT))) + (error = suser_xxx(0, p, PRISON_ROOT)) && + (error = cap_check_xxx(0, p, CAP_SETUID, PRISON_ROOT))) return (error); /* * Everything's okay, do it. Copy credentials so other references do @@ -531,7 +534,8 @@ #ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */ gid != pc->pc_ucred->cr_groups[0] && /* allow setgid(getegid()) */ #endif - (error = suser_xxx(0, p, PRISON_ROOT))) + (error = suser_xxx(0, p, PRISON_ROOT)) && + (error = cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT))) return (error); #ifdef _POSIX_SAVED_IDS @@ -543,7 +547,8 @@ #ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */ gid == pc->pc_ucred->cr_groups[0] || #endif - suser_xxx(0, p, PRISON_ROOT) == 0) /* we are using privs */ + suser_xxx(0, p, PRISON_ROOT) == 0 || /* we are using privs */ + cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT) == 0) #endif { /* @@ -595,7 +600,8 @@ egid = uap->egid; if (egid != pc->p_rgid && /* allow setegid(getgid()) */ egid != pc->p_svgid && /* allow setegid(saved gid) */ - (error = suser_xxx(0, p, PRISON_ROOT))) + (error = suser_xxx(0, p, PRISON_ROOT)) && + (error = cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT))) return (error); if (pc->pc_ucred->cr_groups[0] != egid) { pc->pc_ucred = crcopy(pc->pc_ucred); @@ -621,7 +627,8 @@ register u_int ngrp; int error; - if ((error = suser_xxx(0, p, PRISON_ROOT))) + if ((error = suser_xxx(0, p, PRISON_ROOT)) && + (error = cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT))) return (error); ngrp = uap->gidsetsize; if (ngrp > NGROUPS) @@ -670,7 +677,8 @@ if (((ruid != (uid_t)-1 && ruid != pc->p_ruid && ruid != pc->p_svuid) || (euid != (uid_t)-1 && euid != pc->pc_ucred->cr_uid && euid != pc->p_ruid && euid != pc->p_svuid)) && - (error = suser_xxx(0, p, PRISON_ROOT)) != 0) + (error = suser_xxx(0, p, PRISON_ROOT)) != 0 && + (error = cap_check_xxx(0, p, CAP_SETUID, PRISON_ROOT)) != 0) return (error); if (euid != (uid_t)-1 && pc->pc_ucred->cr_uid != euid) { @@ -713,7 +721,8 @@ if (((rgid != (gid_t)-1 && rgid != pc->p_rgid && rgid != pc->p_svgid) || (egid != (gid_t)-1 && egid != pc->pc_ucred->cr_groups[0] && egid != pc->p_rgid && egid != pc->p_svgid)) && - (error = suser_xxx(0, p, PRISON_ROOT)) != 0) + (error = suser_xxx(0, p, PRISON_ROOT)) != 0 && + (error = cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT)) != 0) return (error); if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { @@ -815,7 +824,8 @@ egid != pc->pc_ucred->cr_groups[0]) || (sgid != (gid_t)-1 && sgid != pc->p_rgid && sgid != pc->p_svgid && sgid != pc->pc_ucred->cr_groups[0])) && - (error = suser_xxx(0, p, PRISON_ROOT)) != 0) + (error = suser_xxx(0, p, PRISON_ROOT)) != 0 && + (error = cap_check_xxx(0, p, CAP_SETGID, PRISON_ROOT))) return (error); if (egid != (gid_t)-1 && pc->pc_ucred->cr_groups[0] != egid) { @@ -932,6 +942,23 @@ return (0); } +/* + * For accounting purposes, flag a process as having used super-user + * privileges. Right now this is not called much, as most code still + * assumes that suser() will do the dirty work. But this is incorrect + * behavior. Use of suser_used() is difficult in current code due to + * abuse of short-circuit boolean evaluation to call or not call + * suser(), rather than isolating use of privilege. + */ +void +suser_used(proc) + struct proc *proc; +{ + + if (proc) + proc->p_acflag |= ASU; +} + static int suser_permitted = 1; SYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0, @@ -939,8 +966,9 @@ /* * Test whether the specified credentials imply "super-user" - * privilege; if so, and we have accounting info, set the flag - * indicating use of super-powers. + * privilege. This used to also set the appropriate accounting flag, + * but now ``suser_used(p)'' must be called explicitely, as not all + * invocations of suser() result in the privilege being excercised. * Returns 0 or error. */ int @@ -1134,7 +1162,6 @@ } } - /* * Allocate a zeroed cred structure. */ @@ -1233,7 +1260,8 @@ int error; char logintmp[MAXLOGNAME]; - if ((error = suser_xxx(0, p, PRISON_ROOT))) + if ((error = suser_xxx(0, p, PRISON_ROOT)) && + (error = cap_check_xxx(0, p, CAP_SETUID, PRISON_ROOT))) return (error); error = copyinstr((caddr_t) uap->namebuf, (caddr_t) logintmp, sizeof(logintmp), (size_t *)0); Index: sys/kern/kern_resource.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_resource.c,v retrieving revision 1.60 diff -u -r1.60 kern_resource.c --- sys/kern/kern_resource.c 2000/08/30 04:49:07 1.60 +++ sys/kern/kern_resource.c 2000/09/01 15:29:32 @@ -78,6 +78,8 @@ { register struct proc *p; register int low = PRIO_MAX + 1; + int privused = 0, cumulative_privused = 0; + int error; switch (uap->which) { @@ -101,8 +103,11 @@ else if ((pg = pgfind(uap->who)) == NULL) break; LIST_FOREACH(p, &pg->pg_members, p_pglist) { - if (!p_can(curp, p, P_CAN_SEE, NULL) && p->p_nice < low) + if (!p_can(curp, p, P_CAN_SEE, &privused) && + p->p_nice < low) low = p->p_nice; + if (privused) + cumulative_privused = 1; } break; } @@ -111,10 +116,13 @@ if (uap->who == 0) uap->who = curp->p_ucred->cr_uid; LIST_FOREACH(p, &allproc, p_list) - if (!p_can(curp, p, P_CAN_SEE, NULL) && + if (!p_can(curp, p, P_CAN_SEE, NULL) && p->p_ucred->cr_uid == uap->who && - p->p_nice < low) + p->p_nice < low) { low = p->p_nice; + if (privused) + cumulative_privused = 1; + } break; default: @@ -122,6 +130,10 @@ } if (low == PRIO_MAX + 1) return (ESRCH); + + if (cumulative_privused) + suser_used(curp); + curp->p_retval[0] = low; return (0); } @@ -205,8 +217,11 @@ n = PRIO_MAX; if (n < PRIO_MIN) n = PRIO_MIN; - if (n < chgp->p_nice && suser(curp)) - return (EACCES); + if (n < chgp->p_nice) { + if (suser(curp) && cap_check(curp, CAP_SYS_NICE)) + return (EACCES); + suser_used(curp); + } chgp->p_nice = n; (void)resetpriority(chgp); return (0); @@ -254,7 +269,7 @@ if ((error = p_can(curp, p, P_CAN_SCHED, NULL))) return (error); /* disallow setting rtprio in most cases if not superuser */ - if (suser(curp) != 0) { + if (suser(NULL) && cap_check(curp, CAP_SYS_NICE)) { /* can't set someone else's */ if (uap->pid) return (EPERM); @@ -272,6 +287,7 @@ if (rtp.type != RTP_PRIO_NORMAL) return (EPERM); } + suser_used(curp); switch (rtp.type) { #ifdef RTP_PRIO_FIFO case RTP_PRIO_FIFO: @@ -386,9 +402,12 @@ limp->rlim_max = RLIM_INFINITY; if (limp->rlim_cur > alimp->rlim_max || - limp->rlim_max > alimp->rlim_max) - if ((error = suser_xxx(0, p, PRISON_ROOT))) + limp->rlim_max > alimp->rlim_max) { + if ((error = suser_xxx(0, p, PRISON_ROOT)) && + (error = cap_check_xxx(0, p, CAP_SYS_NICE, PRISON_ROOT))) return (error); + suser_used(p); + } if (limp->rlim_cur > limp->rlim_max) limp->rlim_cur = limp->rlim_max; if (p->p_limit->p_refcnt > 1 && Index: sys/kern/kern_shutdown.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_shutdown.c,v retrieving revision 1.77 diff -u -r1.77 kern_shutdown.c --- sys/kern/kern_shutdown.c 2000/08/31 00:08:49 1.77 +++ sys/kern/kern_shutdown.c 2000/08/31 04:09:32 @@ -140,8 +140,9 @@ { int error; - if ((error = suser(p))) + if ((error = suser(p)) && (error = cap_check(p, CAP_SYS_BOOT))) return (error); + suser_used(p); boot(uap->opt); return (0); Index: sys/kern/kern_sig.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_sig.c,v retrieving revision 1.84 diff -u -r1.84 kern_sig.c --- sys/kern/kern_sig.c 2000/08/30 04:49:07 1.84 +++ sys/kern/kern_sig.c 2000/08/31 04:26:12 @@ -62,6 +62,7 @@ #include #include #include +#include #include @@ -95,6 +96,11 @@ /* * Can process p, with pcred pc, send the signal sig to process q? + * XXX should p be able to signal q outside the same prison if CAP_KILL + * is present? + * + * XXX This should propagate the privused flag up the stack but + * doesn't. */ #define CANSIGNAL(p, q, sig) \ (!p_can(p, q, P_CAN_KILL, NULL) || \ Index: sys/kern/kern_sysctl.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_sysctl.c,v retrieving revision 1.100 diff -u -r1.100 kern_sysctl.c --- sys/kern/kern_sysctl.c 2000/07/28 22:40:04 1.100 +++ sys/kern/kern_sysctl.c 2000/08/09 04:54:08 @@ -1016,11 +1016,26 @@ return (EPERM); /* Most likely only root can write */ + /* + * XXX What about capabilities? Ought to map into many different + * capabilities, which doesn't fit will in this scheme. + * CAP_SYS_ADMIN is closest, but wrong. + */ if (!(oid->oid_kind & CTLFLAG_ANYBODY) && - req->newptr && req->p && - (error = suser_xxx(0, req->p, - (oid->oid_kind & CTLFLAG_PRISON) ? PRISON_ROOT : 0))) - return (error); + req->newptr && req->p) { + int error_suser, error_cap, flag_prison; + + flag_prison = ((oid->oid_kind & CTLFLAG_PRISON) ? + PRISON_ROOT : 0); + + error_suser = suser_xxx(0, req->p, flag_prison); + error_cap = cap_check_xxx(0, req->p, CAP_SYS_ADMIN, + flag_prison); + if (error_suser && error_cap) + return (error_suser); + + suser_used(req->p); + } if (!oid->oid_handler) return EINVAL; Index: sys/kern/kern_time.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_time.c,v retrieving revision 1.70 diff -u -r1.70 kern_time.c --- sys/kern/kern_time.c 2000/04/18 15:15:20 1.70 +++ sys/kern/kern_time.c 2000/08/09 01:16:22 @@ -174,8 +174,9 @@ struct timespec ats; int error; - if ((error = suser(p)) != 0) + if (((error = suser(p)) != 0) && (error = cap_check(p, CAP_SYS_TIME))) return (error); + suser_used(p); if (SCARG(uap, clock_id) != CLOCK_REALTIME) return (EINVAL); if ((error = copyin(SCARG(uap, tp), &ats, sizeof(ats))) != 0) @@ -331,8 +332,9 @@ struct timezone atz; int error; - if ((error = suser(p))) + if (((error = suser(p))) && (error = cap_check(p, CAP_SYS_TIME))) return (error); + suser_used(p); /* Verify all parameters before changing time. */ if (uap->tv) { if ((error = copyin((caddr_t)uap->tv, (caddr_t)&atv, @@ -371,8 +373,11 @@ register long ndelta, ntickdelta, odelta; int s, error; - if ((error = suser(p))) + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_TIME))) return (error); + suser_used(p); + if ((error = copyin((caddr_t)uap->delta, (caddr_t)&atv, sizeof(struct timeval)))) return (error); Index: sys/kern/kern_xxx.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_xxx.c,v retrieving revision 1.31 diff -u -r1.31 kern_xxx.c --- sys/kern/kern_xxx.c 1999/08/28 00:46:15 1.31 +++ sys/kern/kern_xxx.c 2000/08/09 01:50:45 @@ -85,8 +85,11 @@ name[0] = CTL_KERN; name[1] = KERN_HOSTNAME; - if ((error = suser_xxx(0, p, PRISON_ROOT))) + if ((error = suser_xxx(0, p, PRISON_ROOT)) && + (error = cap_check_xxx(0, p, CAP_SYS_ADMIN, PRISON_ROOT))) return (error); + suser_used(p); + return (userland_sysctl(p, name, 2, 0, 0, 0, uap->hostname, uap->len, 0)); } @@ -122,8 +125,11 @@ { int error; - if ((error = suser(p))) + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_ADMIN))) return (error); + suser_used(p); + hostid = uap->hostid; return (0); } @@ -244,8 +250,11 @@ { int error, domainnamelen; - if ((error = suser(p))) + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_ADMIN))) return (error); + suser_used(p); + if ((u_int)uap->len > sizeof (domainname) - 1) return EINVAL; domainnamelen = uap->len; Index: sys/kern/makesyscalls.sh =================================================================== RCS file: /home/ncvs/src/sys/kern/makesyscalls.sh,v retrieving revision 1.42 diff -u -r1.42 makesyscalls.sh --- sys/kern/makesyscalls.sh 2000/07/29 00:16:26 1.42 +++ sys/kern/makesyscalls.sh 2000/08/07 00:51:53 @@ -111,8 +111,9 @@ printf " * created from%s\n */\n\n", $0 > sysarg printf "#ifndef %s\n", sysproto_h > sysarg printf "#define\t%s\n\n", sysproto_h > sysarg - printf "#include \n\n" > sysarg - printf "#include \n\n" > sysarg + printf "#include \n" > sysarg + printf "#include \n" > sysarg + printf "#include \n\n" > sysarg printf "struct proc;\n\n" > sysarg printf "#define\tPAD_(t)\t(sizeof(register_t) <= sizeof(t) ? \\\n" > sysarg printf "\t\t0 : sizeof(register_t) - sizeof(t))\n\n" > sysarg Index: sys/kern/sys_process.c =================================================================== RCS file: /home/ncvs/src/sys/kern/sys_process.c,v retrieving revision 1.52 diff -u -r1.52 sys_process.c --- sys/kern/sys_process.c 2000/08/30 04:49:07 1.52 +++ sys/kern/sys_process.c 2000/08/31 04:27:19 @@ -206,6 +206,7 @@ struct proc *p; struct iovec iov; struct uio uio; + int privused = 0; int error = 0; int write; int s; @@ -237,8 +238,10 @@ if (p->p_flag & P_TRACED) return EBUSY; - if ((error = p_can(curp, p, P_CAN_DEBUG, NULL))) + if ((error = p_can(curp, p, P_CAN_DEBUG, &privused))) return error; + if (privused) + suser_used(curp); /* OK */ break; Index: sys/kern/sys_socket.c =================================================================== RCS file: /home/ncvs/src/sys/kern/sys_socket.c,v retrieving revision 1.32 diff -u -r1.32 sys_socket.c --- sys/kern/sys_socket.c 2000/07/03 00:05:40 1.32 +++ sys/kern/sys_socket.c 2000/08/07 18:44:28 @@ -45,6 +45,7 @@ #include #include #include +#include #include #include Index: sys/kern/sysv_ipc.c =================================================================== RCS file: /home/ncvs/src/sys/kern/sysv_ipc.c,v retrieving revision 1.15 diff -u -r1.15 sysv_ipc.c --- sys/kern/sysv_ipc.c 2000/05/01 11:13:40 1.15 +++ sys/kern/sysv_ipc.c 2000/08/09 04:54:38 @@ -54,8 +54,14 @@ /* Check for user match. */ if (cred->cr_uid != perm->cuid && cred->cr_uid != perm->uid) { - if (mode & IPC_M) - return (suser(p) == 0 ? 0 : EPERM); + if (mode & IPC_M) { + if (suser(p) && cap_check(p, CAP_SYS_ADMIN)) + return (EPERM); + else { + suser_used(p); + return (0); + } + } /* Check for group match. */ mode >>= 3; if (!groupmember(perm->gid, cred) && @@ -66,7 +72,14 @@ if (mode & IPC_M) return (0); - return ((mode & perm->mode) == mode || suser(p) == 0 ? 0 : EACCES); + + if ((mode & perm->mode) == mode) + return (0); + if (suser(p) == 0 || cap_check(p, CAP_IPC_OWNER) == 0) { + suser_used(p); + return (0); + } + return (EACCES); } #endif /* defined(SYSVSEM) || defined(SYSVSHM) || defined(SYSVMSG) */ Index: sys/kern/sysv_msg.c =================================================================== RCS file: /home/ncvs/src/sys/kern/sysv_msg.c,v retrieving revision 1.24 diff -u -r1.24 sysv_msg.c --- sys/kern/sysv_msg.c 2000/05/01 13:33:53 1.24 +++ sys/kern/sysv_msg.c 2000/08/09 02:32:30 @@ -329,8 +329,11 @@ return(eval); if (msqbuf.msg_qbytes > msqptr->msg_qbytes) { eval = suser(p); + if (eval != 0) + eval = cap_check(p, CAP_SYS_RESOURCE); if (eval) return(eval); + suser_used(p); } if (msqbuf.msg_qbytes > msginfo.msgmnb) { #ifdef MSG_DEBUG_OK Index: sys/kern/tty.c =================================================================== RCS file: /home/ncvs/src/sys/kern/tty.c,v retrieving revision 1.138 diff -u -r1.138 tty.c --- sys/kern/tty.c 2000/07/04 11:25:23 1.138 +++ sys/kern/tty.c 2000/08/09 04:55:05 @@ -816,8 +816,10 @@ ISSET(constty->t_state, TS_CONNECTED)) return (EBUSY); #ifndef UCONSOLE - if ((error = suser(p)) != 0) + if (((error = suser(p)) != 0) && + (error = cap_check(p, CAP_SYS_TTY_CONFIG)) != 0) return (error); + suser_used(p); #endif constty = tp; } else if (tp == constty) @@ -988,10 +990,18 @@ splx(s); break; case TIOCSTI: /* simulate terminal input */ - if ((flag & FREAD) == 0 && suser(p)) - return (EPERM); - if (!isctty(p, tp) && suser(p)) - return (EACCES); + if ((flag & FREAD) == 0) { + if (suser(p) && cap_check(p, CAP_SYS_TTY_CONFIG)) + return (EPERM); + else + suser_used(p); + } + if (!isctty(p, tp)) { + if (suser(p) && cap_check(p, CAP_SYS_TTY_CONFIG)) + return (EACCES); + else + suser_used(p); + } s = spltty(); (*linesw[tp->t_line].l_rint)(*(u_char *)data, tp); splx(s); @@ -1038,9 +1048,11 @@ } break; case TIOCSDRAINWAIT: - error = suser(p); - if (error) + if (((error = suser(p)) != 0) && + ((error = cap_check(p, CAP_SYS_TTY_CONFIG)) != 0)) return (error); + suser_used(p); + tp->t_timeout = *(int *)data * hz; wakeup(TSA_OCOMPLETE(tp)); wakeup(TSA_OLOWAT(tp)); Index: sys/kern/tty_cons.c =================================================================== RCS file: /home/ncvs/src/sys/kern/tty_cons.c,v retrieving revision 1.83 diff -u -r1.83 tty_cons.c --- sys/kern/tty_cons.c 2000/07/04 11:25:23 1.83 +++ sys/kern/tty_cons.c 2000/08/09 02:45:21 @@ -373,9 +373,11 @@ * output from the "virtual" console. */ if (cmd == TIOCCONS && constty) { - error = suser(p); - if (error) + if (((error = suser(p)) != 0) && + ((error = cap_check(p, CAP_SYS_TTY_CONFIG)) != 0)) return (error); + suser_used(p); + constty = NULL; return (0); } Index: sys/kern/tty_pty.c =================================================================== RCS file: /home/ncvs/src/sys/kern/tty_pty.c,v retrieving revision 1.78 diff -u -r1.78 tty_pty.c --- sys/kern/tty_pty.c 2000/08/20 21:34:34 1.78 +++ sys/kern/tty_pty.c 2000/08/24 01:46:58 @@ -205,7 +205,11 @@ tp->t_lflag = TTYDEF_LFLAG; tp->t_cflag = TTYDEF_CFLAG; tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; - } else if (tp->t_state & TS_XCLUDE && suser(p)) { + } else if (tp->t_state & TS_XCLUDE) { + /* + * XXX used to be && suser(p) with, why could suser override + * TS_XCLUDE? + */ return (EBUSY); } else if (pti->pt_prison != p->p_prison) { return (EBUSY); Index: sys/kern/tty_snoop.c =================================================================== RCS file: /home/ncvs/src/sys/kern/tty_snoop.c,v retrieving revision 1.47 diff -u -r1.47 tty_snoop.c --- sys/kern/tty_snoop.c 2000/04/02 07:02:41 1.47 +++ sys/kern/tty_snoop.c 2000/08/09 02:52:57 @@ -286,7 +286,8 @@ struct snoop *snp; int error; - if ((error = suser(p)) != 0) + if (((error = suser(p)) != 0) && + ((error = cap_check(p, CAP_SYS_ADMIN))) return (error); if (dev->si_drv1 == NULL) { Index: sys/kern/vfs_syscalls.c =================================================================== RCS file: /home/ncvs/src/sys/kern/vfs_syscalls.c,v retrieving revision 1.163 diff -u -r1.163 vfs_syscalls.c --- sys/kern/vfs_syscalls.c 2000/08/09 01:57:11 1.163 +++ sys/kern/vfs_syscalls.c 2000/08/10 18:51:31 @@ -123,21 +123,31 @@ struct nameidata nd; char fstypename[MFSNAMELEN]; - if (usermount == 0 && (error = suser(p))) - return (error); + if (usermount == 0) { + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_ADMIN))) + return (error); + suser_used(p); + } /* * Do not allow NFS export by non-root users. */ if (SCARG(uap, flags) & MNT_EXPORTED) { - error = suser(p); - if (error) + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_ADMIN))) return (error); + suser_used(p); } /* * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users */ - if (suser_xxx(p->p_ucred, 0, 0)) + if (suser_xxx(p->p_ucred, 0, 0) && + cap_check_xxx(p->p_ucred, NULL, CAP_SYS_ADMIN, 0)) SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV; + else if ((SCARG(uap, flags) & (MNT_NOSUID | MNT_NODEV)) != + (MNT_NOSUID | MNT_NODEV)) + suser_used(p); + /* * Get vnode to be covered */ @@ -168,10 +178,14 @@ * Only root, or the user that did the original mount is * permitted to update it. */ - if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid && - (error = suser(p))) { - vput(vp); - return (error); + if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid) { + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_ADMIN))) + suser_used(p); + else { + vput(vp); + return (error); + } } if (vfs_busy(mp, LK_NOWAIT, 0, p)) { vput(vp); @@ -197,10 +211,14 @@ * onto which we are attempting to mount. */ if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) || - (va.va_uid != p->p_ucred->cr_uid && - (error = suser(p)))) { - vput(vp); - return (error); + (va.va_uid != p->p_ucred->cr_uid)) { + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_ADMIN))) + suser_used(p); + else { + vput(vp); + return (error); + } } if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) { vput(vp); @@ -239,10 +257,12 @@ linker_file_t lf; /* Only load modules for root (very important!) */ - if ((error = suser(p)) != 0) { + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_MODULE))) { vput(vp); return error; } + suser_used(p); error = linker_load_file(fstypename, &lf); if (error || lf == NULL) { vput(vp); @@ -444,10 +464,13 @@ * Only root, or the user that did the original mount is * permitted to unmount this filesystem. */ - if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) && - (error = suser(p))) { - vput(vp); - return (error); + if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid)) { + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_ADMIN))) { + vput(vp); + return (error); + } + suser_used(p); } /* @@ -669,11 +692,13 @@ if (error) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - if (suser_xxx(p->p_ucred, 0, 0)) { + if (suser_xxx(p->p_ucred, 0, 0) && + cap_check_xxx(p->p_ucred, NULL, CAP_SYS_ADMIN, 0)) { bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; sp = &sb; - } + } else + suser_used(p); return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); } @@ -709,11 +734,13 @@ if (error) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - if (suser_xxx(p->p_ucred, 0, 0)) { + if (suser_xxx(p->p_ucred, 0, 0) && + cap_check_xxx(p->p_ucred, NULL, CAP_SYS_ADMIN, 0)) { bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; sp = &sb; - } + } else + suser_used(p); return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp))); } @@ -925,9 +952,11 @@ int error; struct nameidata nd; - error = suser_xxx(0, p, PRISON_ROOT); - if (error) + if ((error = suser_xxx(NULL, p, PRISON_ROOT)) && + (error = cap_check_xxx(NULL, p, CAP_SYS_CHROOT, PRISON_ROOT))) return (error); + suser_used(p); + if (chroot_allow_open_directories == 0 || (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) error = chroot_refuse_vdir_fds(fdp); @@ -1141,9 +1170,13 @@ case S_IFCHR: case S_IFBLK: error = suser(p); + if (error != 0) + error = cap_check(p, CAP_MKNOD); break; default: error = suser_xxx(0, p, PRISON_ROOT); + if (error != 0) + error = cap_check_xxx(NULL, p, CAP_MKNOD, PRISON_ROOT); break; } if (error) @@ -2002,9 +2035,13 @@ * if they are allowed to set flags and programs assume that * chown can't fail when done as root. */ - if ((vp->v_type == VCHR || vp->v_type == VBLK) && - ((error = suser_xxx(p->p_ucred, p, PRISON_ROOT)) != 0)) - return (error); + if (vp->v_type == VCHR || vp->v_type == VBLK) { + if ((error = suser_xxx(p->p_ucred, p, PRISON_ROOT)) && + (error = cap_check_xxx(p->p_ucred, p, CAP_SYS_SETFFLAG, + PRISON_ROOT))) + return (error); + suser_used(p); + } if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) return (error); @@ -3181,8 +3218,13 @@ } if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0) goto out; - if (p->p_ucred->cr_uid != vattr.va_uid && - (error = suser_xxx(0, p, PRISON_ROOT))) + if (p->p_ucred->cr_uid != vattr.va_uid) { + if ((error = suser_xxx(NULL, p, PRISON_ROOT)) && + (error = cap_check_xxx(NULL, p, CAP_SYS_ADMIN, + PRISON_ROOT))) + goto out; + suser_used(p); + } goto out; if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) goto out; @@ -3235,9 +3277,11 @@ /* * Must be super user */ - error = suser(p); - if (error) + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_ADMIN))) return (error); + suser_used(p); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p); error = namei(&nd); if (error) @@ -3290,9 +3334,10 @@ /* * Must be super user */ - error = suser(p); - if (error) + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_ADMIN))) return (error); + suser_used(p); fmode = FFLAGS(SCARG(uap, flags)); /* why not allow a non-read/write open for our lockd? */ @@ -3440,9 +3485,10 @@ /* * Must be super user */ - error = suser(p); - if (error) + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_ADMIN))) return (error); + suser_used(p); error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t)); if (error) @@ -3484,8 +3530,10 @@ /* * Must be super user */ - if ((error = suser(p))) + if ((error = suser(p)) && + (error = cap_check(p, CAP_SYS_ADMIN))) return (error); + suser_used(p); if ((error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t))) != 0) return (error); @@ -3500,11 +3548,14 @@ if ((error = VFS_STATFS(mp, sp, p)) != 0) return (error); sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - if (suser_xxx(p->p_ucred, 0, 0)) { + if (suser_xxx(p->p_ucred, 0, 0) && + cap_check_xxx(p->p_ucred, NULL, CAP_SYS_ADMIN, 0)) { bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb)); sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; sp = &sb; - } + } else + suser_used(p); + return (copyout(sp, SCARG(uap, buf), sizeof(*sp))); } Index: sys/kern/vfs_vnops.c =================================================================== RCS file: /home/ncvs/src/sys/kern/vfs_vnops.c,v retrieving revision 1.100 diff -u -r1.100 vfs_vnops.c --- sys/kern/vfs_vnops.c 2000/08/08 17:15:32 1.100 +++ sys/kern/vfs_vnops.c 2000/08/09 03:45:28 @@ -530,7 +530,8 @@ } sb->st_flags = vap->va_flags; - if (suser_xxx(p->p_ucred, 0, 0)) + if (suser_xxx(p->p_ucred, 0, 0) && + cap_check_xxx(p->p_ucred, NULL, CAP_SYS_ADMIN, 0)) sb->st_gen = 0; else sb->st_gen = vap->va_gen; Index: sys/net/if.c =================================================================== RCS file: /home/ncvs/src/sys/net/if.c,v retrieving revision 1.92 diff -u -r1.92 if.c --- sys/net/if.c 2000/08/15 00:48:38 1.92 +++ sys/net/if.c 2000/08/24 01:47:52 @@ -764,7 +764,7 @@ register struct ifnet *ifp; register struct ifreq *ifr; struct ifstat *ifs; - int error; + int error, privilege_used = 0; short oif_flags; switch (cmd) { @@ -796,9 +796,10 @@ break; case SIOCSIFFLAGS: - error = suser(p); - if (error) + if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN))) return (error); + suser_used(p); + ifr->ifr_prevflags = ifp->if_flags; if (ifp->if_flags & IFF_SMART) { /* Smart drivers twiddle their own routes */ @@ -821,31 +822,37 @@ break; case SIOCSIFMETRIC: - error = suser(p); - if (error) + if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN))) return (error); + suser_used(p); + ifp->if_metric = ifr->ifr_metric; getmicrotime(&ifp->if_lastchange); break; case SIOCSIFPHYS: - error = suser(p); - if (error) + if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN))) return error; + privilege_used = 1; + if (!ifp->if_ioctl) return EOPNOTSUPP; error = (*ifp->if_ioctl)(ifp, cmd, data); if (error == 0) getmicrotime(&ifp->if_lastchange); + + if (error == 0 && privilege_used) + suser_used(p); return(error); case SIOCSIFMTU: { u_long oldmtu = ifp->if_mtu; - error = suser(p); - if (error) + if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN))) return (error); + privilege_used = 1; + if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) @@ -863,14 +870,16 @@ nd6_setmtu(ifp); #endif } + if (error == 0 && privilege_used) + suser_used(p); return (error); } case SIOCADDMULTI: case SIOCDELMULTI: - error = suser(p); - if (error) + if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN))) return (error); + privilege_used = 1; /* Don't allow group membership on non-multicast interfaces. */ if ((ifp->if_flags & IFF_MULTICAST) == 0) @@ -888,18 +897,23 @@ } if (error == 0) getmicrotime(&ifp->if_lastchange); + if (error == 0 && privilege_used) + suser_used(p); return error; case SIOCSIFMEDIA: case SIOCSIFGENERIC: - error = suser(p); - if (error) + if ((error = suser(p)) && (error = cap_check(p, CAP_NET_ADMIN))) return (error); + privilege_used = 1; + if (ifp->if_ioctl == 0) return (EOPNOTSUPP); error = (*ifp->if_ioctl)(ifp, cmd, data); if (error == 0) getmicrotime(&ifp->if_lastchange); + if (error == 0 && privilege_used) + suser_used(p); return error; case SIOCGIFSTATUS: Index: sys/netinet/in_pcb.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/in_pcb.c,v retrieving revision 1.67 diff -u -r1.67 in_pcb.c --- sys/netinet/in_pcb.c 2000/07/21 23:26:37 1.67 +++ sys/netinet/in_pcb.c 2000/08/07 00:55:25 @@ -49,6 +49,7 @@ #include #include #include +#include #include @@ -219,7 +220,9 @@ /* GROSS */ if (ntohs(lport) < IPPORT_RESERVED && p && - suser_xxx(0, p, PRISON_ROOT)) + suser_xxx(0, p, PRISON_ROOT) && + cap_check_xxx(0, p, CAP_NET_BIND_SERVICE, + PRISON_ROOT)) return (EACCES); if (p && p->p_prison) prison = 1; @@ -279,7 +282,9 @@ last = ipport_hilastauto; lastport = &pcbinfo->lasthi; } else if (inp->inp_flags & INP_LOWPORT) { - if (p && (error = suser_xxx(0, p, PRISON_ROOT))) + if (p && (error = suser_xxx(0, p, PRISON_ROOT)) && + (error = cap_check_xxx(0, p, CAP_NET_BIND_SERVICE, + PRISON_ROOT))) return error; first = ipport_lowfirstauto; /* 1023 */ last = ipport_lowlastauto; /* 600 */ Index: sys/netinet/raw_ip.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/raw_ip.c,v retrieving revision 1.68 diff -u -r1.68 raw_ip.c --- sys/netinet/raw_ip.c 2000/09/01 12:33:03 1.68 +++ sys/netinet/raw_ip.c 2000/09/01 13:47:49 @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -444,7 +445,8 @@ inp = sotoinpcb(so); if (inp) panic("rip_attach"); - if (p && (error = suser(p)) != 0) + if (p && (error = suser(p)) != 0 && + (error = cap_check(p, CAP_NET_RAW)) != 0) return error; error = soreserve(so, rip_sendspace, rip_recvspace); Index: sys/netinet6/in6_pcb.c =================================================================== RCS file: /home/ncvs/src/sys/netinet6/in6_pcb.c,v retrieving revision 1.13 diff -u -r1.13 in6_pcb.c --- sys/netinet6/in6_pcb.c 2000/07/04 16:35:09 1.13 +++ sys/netinet6/in6_pcb.c 2000/08/10 02:06:52 @@ -178,7 +178,9 @@ /* GROSS */ if (ntohs(lport) < IPV6PORT_RESERVED && p && - suser_xxx(0, p, PRISON_ROOT)) + suser_xxx(0, p, PRISON_ROOT) && + cap_check_xxx(NULL, p, CAP_NET_BIND_SERVICE, + PRISON_ROOT)) return(EACCES); if (so->so_cred->cr_uid != 0 && !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { Index: sys/netinet6/in6_src.c =================================================================== RCS file: /home/ncvs/src/sys/netinet6/in6_src.c,v retrieving revision 1.1 diff -u -r1.1 in6_src.c --- sys/netinet6/in6_src.c 2000/07/04 16:35:09 1.1 +++ sys/netinet6/in6_src.c 2000/08/10 04:18:04 @@ -346,7 +346,8 @@ last = ipport_hilastauto; lastport = &pcbinfo->lasthi; } else if (inp->inp_flags & INP_LOWPORT) { - if (p && (error = suser(p))) + if (p && (error = suser(p)) && + (error = cap_check(p, CAP_NET_BIND_SERVICE))) return error; first = ipport_lowfirstauto; /* 1023 */ last = ipport_lowlastauto; /* 600 */ Index: sys/sys/capability.h =================================================================== RCS file: /home/ncvs/src/sys/sys/capability.h,v retrieving revision 1.3 diff -u -r1.3 capability.h --- sys/sys/capability.h 2000/08/08 18:47:59 1.3 +++ sys/sys/capability.h 2000/08/09 05:03:03 @@ -129,7 +129,7 @@ * in the BSD file environment * #define CAP_LINUX_IMMUTABLE (0x00000200 | SYSTEM_CAPABILITY) */ -#define CAP_BSD_SETFFLAG (0x00000200 | SYSTEM_CAPABILITY) +#define CAP_SYS_SETFFLAG (0x00000200 | SYSTEM_CAPABILITY) #define CAP_NET_BIND_SERVICE (0x00000400 | SYSTEM_CAPABILITY) #define CAP_NET_BROADCAST (0x00000800 | SYSTEM_CAPABILITY) #define CAP_NET_ADMIN (0x00001000 | SYSTEM_CAPABILITY) @@ -140,18 +140,22 @@ * The following capabilities, borrowed from Linux, are unsafe in a * secure environment. * - * #define CAP_SYS_MODULE (0x00010000 | SYSTEM_CAPABILITY) - * #define CAP_SYS_RAWIO (0x00020000 | SYSTEM_CAPABILITY) - * #define CAP_SYS_CHROOT (0x00040000 | SYSTEM_CAPABILITY) - * #define CAP_SYS_PTRACE (0x00080000 | SYSTEM_CAPABILITY) */ +#define CAP_SYS_MODULE (0x00010000 | SYSTEM_CAPABILITY) +#define CAP_SYS_RAWIO (0x00020000 | SYSTEM_CAPABILITY) +#define CAP_SYS_CHROOT (0x00040000 | SYSTEM_CAPABILITY) +#define CAP_SYS_PTRACE (0x00080000 | SYSTEM_CAPABILITY) #define CAP_SYS_PACCT (0x00100000 | SYSTEM_CAPABILITY) #define CAP_SYS_ADMIN (0x00200000 | SYSTEM_CAPABILITY) +/* + * Back to the safe ones, again + */ #define CAP_SYS_BOOT (0x00400000 | SYSTEM_CAPABILITY) #define CAP_SYS_NICE (0x00800000 | SYSTEM_CAPABILITY) #define CAP_SYS_RESOURCE (0x01000000 | SYSTEM_CAPABILITY) #define CAP_SYS_TIME (0x02000000 | SYSTEM_CAPABILITY) #define CAP_SYS_TTY_CONFIG (0x04000000 | SYSTEM_CAPABILITY) +#define CAP_MKNOD (0x08000000 | SYSTEM_CAPABILITY) #ifdef _KERNEL Index: sys/sys/mount.h =================================================================== RCS file: /home/ncvs/src/sys/sys/mount.h,v retrieving revision 1.95 diff -u -r1.95 mount.h --- sys/sys/mount.h 2000/07/11 19:28:20 1.95 +++ sys/sys/mount.h 2000/07/12 18:29:21 @@ -37,6 +37,7 @@ #ifndef _SYS_MOUNT_H_ #define _SYS_MOUNT_H_ +#include #include #ifndef _KERNEL Index: sys/sys/proc.h =================================================================== RCS file: /home/ncvs/src/sys/sys/proc.h,v retrieving revision 1.109 diff -u -r1.109 proc.h --- sys/sys/proc.h 2000/08/30 04:49:09 1.109 +++ sys/sys/proc.h 2000/08/31 04:29:28 @@ -51,6 +51,7 @@ #ifndef _KERNEL #include /* For structs itimerval, timeval. */ #endif +#include #include #include /* For struct klist */ @@ -311,6 +312,7 @@ uid_t p_svuid; /* Saved effective user id. */ gid_t p_rgid; /* Real group id. */ gid_t p_svgid; /* Saved effective group id. */ + struct cap p_cap; /* Capabilities */ int p_refcnt; /* Number of references. */ }; Index: sys/sys/sysctl.h =================================================================== RCS file: /home/ncvs/src/sys/sys/sysctl.h,v retrieving revision 1.87 diff -u -r1.87 sysctl.h --- sys/sys/sysctl.h 2000/07/15 10:26:04 1.87 +++ sys/sys/sysctl.h 2000/08/07 00:55:43 @@ -328,7 +328,8 @@ #define KERN_PS_STRINGS 32 /* int: address of PS_STRINGS */ #define KERN_USRSTACK 33 /* int: address of USRSTACK */ #define KERN_LOGSIGEXIT 34 /* int: do we log sigexit procs? */ -#define KERN_MAXID 35 /* number of valid kern ids */ +#define KERN_SUSER_PERMITTED 35 /* int: suser_xxx() may succeed */ +#define KERN_MAXID 36 /* number of valid kern ids */ #define CTL_KERN_NAMES { \ { 0, 0 }, \ @@ -366,6 +367,7 @@ { "ps_strings", CTLTYPE_INT }, \ { "usrstack", CTLTYPE_INT }, \ { "logsigexit", CTLTYPE_INT }, \ + { "suser_permitted", CTLTYPE_INT }, \ } /* Index: sys/sys/systm.h =================================================================== RCS file: /home/ncvs/src/sys/sys/systm.h,v retrieving revision 1.117 diff -u -r1.117 systm.h --- sys/sys/systm.h 2000/08/31 00:08:50 1.117 +++ sys/sys/systm.h 2000/08/31 04:12:34 @@ -47,6 +47,7 @@ #include extern int securelevel; /* system security level (see init(8)) */ +extern int suser_permitted; /* suser_xxx() is permitted to return 0 */ extern int cold; /* nonzero if we are doing a cold boot */ extern const char *panicstr; /* panic message */ Index: sys/sys/ucred.h =================================================================== RCS file: /home/ncvs/src/sys/sys/ucred.h,v retrieving revision 1.14 diff -u -r1.14 ucred.h --- sys/sys/ucred.h 1999/12/29 04:24:49 1.14 +++ sys/sys/ucred.h 2000/04/12 14:54:30 @@ -48,6 +48,7 @@ uid_t cr_uid; /* effective user id */ short cr_ngroups; /* number of groups */ gid_t cr_groups[NGROUPS]; /* groups */ + struct cap cr_cap; /* capabilities */ }; #define cr_gid cr_groups[0] #define NOCRED ((struct ucred *)0) /* no credential available */ Index: sys/sys/user.h =================================================================== RCS file: /home/ncvs/src/sys/sys/user.h,v retrieving revision 1.24 diff -u -r1.24 user.h --- sys/sys/user.h 1999/12/29 04:24:49 1.24 +++ sys/sys/user.h 2000/04/12 02:04:02 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include Index: sys/sys/vnode.h =================================================================== RCS file: /home/ncvs/src/sys/sys/vnode.h,v retrieving revision 1.124 diff -u -r1.124 vnode.h --- sys/sys/vnode.h 2000/08/29 14:45:45 1.124 +++ sys/sys/vnode.h 2000/08/29 16:37:03 @@ -528,6 +528,7 @@ struct proc; struct stat; struct nstat; +struct cap; struct ucred; struct uio; struct vattr; Index: sys/ufs/ufs/ufs_extattr.c =================================================================== RCS file: /home/ncvs/src/sys/ufs/ufs/ufs_extattr.c,v retrieving revision 1.8 diff -u -r1.8 ufs_extattr.c --- sys/ufs/ufs/ufs_extattr.c 2000/08/26 22:00:58 1.8 +++ sys/ufs/ufs/ufs_extattr.c 2000/08/27 03:48:35 @@ -309,18 +309,25 @@ char *filename; int error, len, flags; - if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0))) + if ((error = suser_xxx(p->p_cred->pc_ucred, p, 0)) && + (error = cap_check_xxx(p->p_cred->pc_ucred, p, CAP_SYS_ADMIN, 0))) return (error); switch(cmd) { case UFS_EXTATTR_CMD_START: error = ufs_extattr_start(mp, p); + if (error == 0) + suser_used(p); return (error); case UFS_EXTATTR_CMD_STOP: - return (ufs_extattr_stop(mp, p)); + error = ufs_extattr_stop(mp, p); + if (error == 0) + suser_used(p); + return (error); + case UFS_EXTATTR_CMD_ENABLE: error = copyinstr(attrname, local_attrname, UFS_EXTATTR_MAXEXTATTRNAME, &len); @@ -341,6 +348,8 @@ error = ufs_extattr_enable(ump, local_attrname, vp, p); ufs_extattr_uepm_unlock(ump, p); + if (error == 0) + suser_used(p); return (error); case UFS_EXTATTR_CMD_DISABLE: @@ -351,6 +360,8 @@ error = ufs_extattr_disable(ump, local_attrname, p); ufs_extattr_uepm_unlock(ump, p); + if (error == 0) + suser_used(p); return (error); default: @@ -364,7 +375,8 @@ */ static int ufs_extattr_credcheck(struct ufs_extattr_list_entry *uele, u_int32_t fowner, - struct ucred *cred, struct proc *p, int access) + struct ucred *cred, struct proc *p, int access, + int *privilege_used) { u_int uef_perm; @@ -386,8 +398,12 @@ /* XXX there might eventually be a capability check here */ /* If it's set to root-only, check for suser(p) */ - if (uef_perm == UFS_EXTATTR_PERM_ROOT && !suser(p)) + if (uef_perm == UFS_EXTATTR_PERM_ROOT && !suser(p) && + cap_check(p, CAP_SYS_ADMIN)) { + if (privilege_used) + *privilege_used = 1; return (0); + } /* Allow the owner if appropriate */ if (uef_perm == UFS_EXTATTR_PERM_OWNER && cred->cr_uid == fowner) @@ -446,7 +462,7 @@ struct inode *ip = VTOI(vp); off_t base_offset; size_t size, old_size; - int error = 0; + int error = 0, privilege_used = 0; if (!(ump->um_extattr.uepm_flags & UFS_EXTATTR_UEPM_STARTED)) return (EOPNOTSUPP); @@ -456,7 +472,7 @@ return (ENOENT); if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, p, - IREAD))) + IREAD, &privilege_used))) return (error); /* @@ -555,6 +571,8 @@ vopunlock_exit: VOP_UNLOCK(attribute->uele_backing_vnode, 0, p); + if (error == 0 && privilege_used) + suser_used(p); return (error); } @@ -609,7 +627,7 @@ struct inode *ip = VTOI(vp); off_t base_offset; - int error = 0; + int error = 0, privilege_used = 0; if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); @@ -622,7 +640,7 @@ return (ENOENT); if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, - p, IWRITE))) + p, IWRITE, &privilege_used))) return (error); /* @@ -695,6 +713,8 @@ if (attribute->uele_backing_vnode != vp) VOP_UNLOCK(attribute->uele_backing_vnode, 0, p); + if (error == 0 && privilege_used) + suser_used(p); return (error); } @@ -714,7 +734,7 @@ struct ufsmount *ump = VFSTOUFS(mp); struct inode *ip = VTOI(vp); off_t base_offset; - int error = 0; + int error = 0, privilege_used = 0; if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); @@ -727,7 +747,7 @@ return (ENOENT); if ((error = ufs_extattr_credcheck(attribute, ip->i_uid, cred, p, - IWRITE))) + IWRITE, &privilege_used))) return (error); /* @@ -788,6 +808,8 @@ vopunlock_exit: VOP_UNLOCK(attribute->uele_backing_vnode, 0, p); + if (error == 0 && privilege_used) + suser_used(p); return (error); } Index: sys/ufs/ufs/ufs_vfsops.c =================================================================== RCS file: /home/ncvs/src/sys/ufs/ufs/ufs_vfsops.c,v retrieving revision 1.18 diff -u -r1.18 ufs_vfsops.c --- sys/ufs/ufs/ufs_vfsops.c 2000/04/15 03:34:26 1.18 +++ sys/ufs/ufs/ufs_vfsops.c 2000/08/09 18:41:17 @@ -102,7 +102,7 @@ #ifndef QUOTA return (EOPNOTSUPP); #else - int cmd, type, error; + int cmd, type, error, privilege_used = 0; if (uid == -1) uid = p->p_cred->p_ruid; @@ -116,8 +116,11 @@ break; /* fall through */ default: - if ((error = suser_xxx(0, p, PRISON_ROOT)) != 0) + if ((error = suser_xxx(0, p, PRISON_ROOT)) && + (error = cap_check_xxx(NULL, p, CAP_SYS_ADMIN, + PRISON_ROOT))) return (error); + privilege_used = 1; } type = cmds & SUBCMDMASK; @@ -157,6 +160,8 @@ break; } vfs_unbusy(mp, p); + if (error == 0 && privilege_used) + suser_used(p); return (error); #endif } Index: sys/ufs/ufs/ufs_vnops.c =================================================================== RCS file: /home/ncvs/src/sys/ufs/ufs/ufs_vnops.c,v retrieving revision 1.143 diff -u -r1.143 ufs_vnops.c --- sys/ufs/ufs/ufs_vnops.c 2000/08/29 14:45:49 1.143 +++ sys/ufs/ufs/ufs_vnops.c 2000/08/29 17:01:00 @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -300,10 +301,10 @@ { struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); - mode_t mode = ap->a_mode; -#ifdef QUOTA - int error; -#endif + struct ucred *cred = ap->a_cred; + struct proc *p = ap->a_p; + register gid_t *gp; + int i, error, privused; /* * Disallow write attempts on read-only file systems; @@ -331,8 +332,15 @@ if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT))) return (EPERM); - return (vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid, - ap->a_mode, ap->a_cred, NULL)); + privused = 0; + error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid, + ap->a_mode, ap->a_cred, &privused); + if (error) + return (error); + if (privused) + suser_used(ap->a_p); + + return (0); } /* ARGSUSED */ @@ -394,7 +402,7 @@ struct inode *ip = VTOI(vp); struct ucred *cred = ap->a_cred; struct proc *p = ap->a_p; - int error; + int error, privilege_used = 0; /* * Check for unsettable attributes. @@ -409,9 +417,12 @@ if (vp->v_mount->mnt_flag & MNT_RDONLY) return (EROFS); if (cred->cr_uid != ip->i_uid && - (error = suser_xxx(cred, p, PRISON_ROOT))) + (error = suser_xxx(cred, p, PRISON_ROOT)) && + (error = cap_check_xxx(cred, p, CAP_SYS_SETFFLAG, 0))) return (error); - if ((cred->cr_uid == 0) && (p->p_prison == NULL)) { + if (!suser_xxx(cred, p, 0) || + !cap_check_xxx(cred, p, CAP_SYS_SETFFLAG, 0)) { + privilege_used = 1; if ((ip->i_flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) && securelevel > 0) @@ -432,8 +443,11 @@ ip->i_flags |= (vap->va_flags & UF_SETTABLE); } ip->i_flag |= IN_CHANGE; - if (vap->va_flags & (IMMUTABLE | APPEND)) + if (vap->va_flags & (IMMUTABLE | APPEND)) { + if (privilege_used) + suser_used(p); return (0); + } } if (ip->i_flags & (IMMUTABLE | APPEND)) return (EPERM); @@ -474,10 +488,14 @@ if ((ip->i_flags & SF_SNAPSHOT) != 0) return (EPERM); if (cred->cr_uid != ip->i_uid && - (error = suser_xxx(cred, p, PRISON_ROOT)) && ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || - (error = VOP_ACCESS(vp, VWRITE, cred, p)))) - return (error); + (error = VOP_ACCESS(vp, VWRITE, cred, p)))) { + if ((error = suser_xxx(cred, p, PRISON_ROOT)) && + (error = cap_check_xxx(cred, p, CAP_FOWNER, + PRISON_ROOT))) + return (error); + privilege_used = 1; + } if (vap->va_atime.tv_sec != VNOVAL) ip->i_flag |= IN_ACCESS; if (vap->va_mtime.tv_sec != VNOVAL) @@ -505,6 +523,8 @@ error = ufs_chmod(vp, (int)vap->va_mode, cred, p); } VN_KNOTE(vp, NOTE_ATTRIB); + if (error == 0 && privilege_used) + suser_used(p); return (error); } @@ -520,22 +540,29 @@ struct proc *p; { register struct inode *ip = VTOI(vp); - int error; + int error, privilege_used = 0; if (cred->cr_uid != ip->i_uid) { - error = suser_xxx(cred, p, PRISON_ROOT); - if (error) - return (error); + if ((error = suser_xxx(cred, p, PRISON_ROOT)) && + (error = cap_check_xxx(cred, p, CAP_FOWNER, PRISON_ROOT))) + return (error); + privilege_used = 1; } - if (cred->cr_uid) { + if (suser_xxx(cred, NULL, PRISON_ROOT)) { if (vp->v_type != VDIR && (mode & S_ISTXT)) return (EFTYPE); if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) return (EPERM); + } else { + if ((vp->v_type != VDIR && (mode & S_ISTXT)) || + (!groupmember(ip->i_gid, cred) && (mode & ISGID))) + privilege_used = 1; } ip->i_mode &= ~ALLPERMS; ip->i_mode |= (mode & ALLPERMS); ip->i_flag |= IN_CHANGE; + if (privilege_used) + suser_used(p); return (0); } @@ -554,7 +581,7 @@ register struct inode *ip = VTOI(vp); uid_t ouid; gid_t ogid; - int error = 0; + int error = 0, privilege_used = 0; #ifdef QUOTA register int i; long change; @@ -570,9 +597,12 @@ * the caller must be superuser or the call fails. */ if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid || - (gid != ip->i_gid && !groupmember((gid_t)gid, cred))) && - (error = suser_xxx(cred, p, PRISON_ROOT))) - return (error); + (gid != ip->i_gid && !groupmember((gid_t)gid, cred)))) { + if ((error = suser_xxx(cred, p, PRISON_ROOT)) && + (error = cap_check_xxx(cred, p, CAP_CHOWN, PRISON_ROOT))) + return (error); + privilege_used = 1; + } ogid = ip->i_gid; ouid = ip->i_uid; #ifdef QUOTA @@ -638,8 +668,15 @@ panic("ufs_chown: lost quota"); #endif /* QUOTA */ ip->i_flag |= IN_CHANGE; - if (cred->cr_uid != 0 && (ouid != uid || ogid != gid)) - ip->i_mode &= ~(ISUID | ISGID); + if (ouid != uid || ogid != gid) { + if (suser_xxx(cred, p, PRISON_ROOT) && + cap_check_xxx(cred, p, CAP_FSETID, PRISON_ROOT)) + ip->i_mode &= ~(ISUID | ISGID); + else + privilege_used = 1; + } + if (privilege_used) + suser_used(p); return (0); } @@ -854,7 +891,7 @@ struct inode *ip, *xp, *dp; struct direct newdir; int doingdirectory = 0, oldparent = 0, newparent = 0; - int error = 0, ioflag; + int error = 0, ioflag, privilege_used = 0; #ifdef DIAGNOSTIC if ((tcnp->cn_flags & HASBUF) == 0 || @@ -1092,12 +1129,19 @@ * own the parent directory, or the destination of the rename, * otherwise the destination may not be changed (except by * root). This implements append-only directories. + * + * XXX should some sort of capability check be happening here? */ - if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 && + if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != dp->i_uid && xp->i_uid != tcnp->cn_cred->cr_uid) { - error = EPERM; - goto bad; + if (suser_xxx(tcnp->cn_cred, NULL, 0) && + cap_check_xxx(tcnp->cn_cred, NULL, CAP_DAC_WRITE, + 0)) { + error = EPERM; + goto bad; + } + privilege_used = 1; } /* * Target must be empty if a directory and have no links @@ -1185,6 +1229,8 @@ if (doingdirectory) panic("ufs_rename: lost dir entry"); vrele(ap->a_fvp); + if (privilege_used) + suser_used(p); return (0); } /* @@ -1220,6 +1266,8 @@ if (xp) vput(fvp); vrele(ap->a_fvp); + if (error == 0 && privilege_used) + suser_used(p); return (error); bad: @@ -1239,6 +1287,8 @@ vput(fvp); } else vrele(fvp); + if (error == 0 && privilege_used) + suser_used(p); return (error); } @@ -2043,7 +2093,7 @@ register struct inode *ip, *pdir; struct direct newdir; struct vnode *tvp; - int error; + int error, privilege_used = 0; pdir = VTOI(dvp); #ifdef DIAGNOSTIC @@ -2121,9 +2171,13 @@ ip->i_nlink = 1; if (DOINGSOFTDEP(tvp)) softdep_change_linkcnt(ip); - if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) && - suser_xxx(cnp->cn_cred, 0, 0)) - ip->i_mode &= ~ISGID; + if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred)) { + if (suser_xxx(cnp->cn_cred, 0, 0) && + cap_check_xxx(cnp->cn_cred, NULL, CAP_FSETID, 0)) + ip->i_mode &= ~ISGID; + else + privilege_used = 1; + } if (cnp->cn_flags & ISWHITEOUT) ip->i_flags |= UF_OPAQUE; @@ -2139,6 +2193,13 @@ if (error) goto bad; *vpp = tvp; +/* + XXX struct proc is not passed in, so we can't mark as having used + privilege + + if (privilege_used) + suser_used(p); +*/ return (0); bad: Index: usr.bin/find/function.c =================================================================== RCS file: /home/ncvs/src/usr.bin/find/function.c,v retrieving revision 1.27 diff -u -r1.27 function.c --- usr.bin/find/function.c 2000/07/28 20:02:42 1.27 +++ usr.bin/find/function.c 2000/08/07 00:56:16 @@ -44,6 +44,7 @@ #endif /* not lint */ #include +#include #include #include #include Index: usr.bin/kdump/Makefile =================================================================== RCS file: /home/ncvs/src/usr.bin/kdump/Makefile,v retrieving revision 1.5 diff -u -r1.5 Makefile --- usr.bin/kdump/Makefile 2000/08/01 10:21:12 1.5 +++ usr.bin/kdump/Makefile 2000/08/07 00:56:25 @@ -2,7 +2,7 @@ # $FreeBSD: src/usr.bin/kdump/Makefile,v 1.5 2000/08/01 10:21:12 ru Exp $ PROG= kdump -CFLAGS+=-I${.CURDIR}/../ktrace -I${.CURDIR}/../.. +CFLAGS+=-I${.CURDIR}/../ktrace -I${.CURDIR}/../.. -I${.CURDIR}/../../sys SRCS= kdump.c ioctl.c subr.c .PATH: ${.CURDIR}/../ktrace CLEANFILES+=ioctl.c Index: usr.sbin/inetd/builtins.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/inetd/builtins.c,v retrieving revision 1.24 diff -u -r1.24 builtins.c --- usr.sbin/inetd/builtins.c 2000/07/12 20:49:06 1.24 +++ usr.sbin/inetd/builtins.c 2000/07/14 05:48:31 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include Index: usr.sbin/pstat/pstat.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/pstat/pstat.c,v retrieving revision 1.49 diff -u -r1.49 pstat.c --- usr.sbin/pstat/pstat.c 2000/01/29 16:45:28 1.49 +++ usr.sbin/pstat/pstat.c 2000/04/12 19:57:58 @@ -48,6 +48,7 @@ #include #include #include +#include #include #define _KERNEL #include Index: usr.sbin/rpc.umntall/rpc.umntall.c =================================================================== RCS file: /home/ncvs/src/usr.sbin/rpc.umntall/rpc.umntall.c,v retrieving revision 1.3 diff -u -r1.3 rpc.umntall.c --- usr.sbin/rpc.umntall/rpc.umntall.c 2000/01/15 14:28:14 1.3 +++ usr.sbin/rpc.umntall/rpc.umntall.c 2000/04/12 20:10:46 @@ -31,6 +31,7 @@ #endif /* not lint */ #include +#include #include #include