From owner-freebsd-arch Mon May 7 21:44:21 2001 Delivered-To: freebsd-arch@freebsd.org Received: from fledge.watson.org (fledge.watson.org [204.156.12.50]) by hub.freebsd.org (Postfix) with ESMTP id E94C437B423 for ; Mon, 7 May 2001 21:44:01 -0700 (PDT) (envelope-from robert@fledge.watson.org) Received: from fledge.watson.org (robert@fledge.pr.watson.org [192.0.2.3]) by fledge.watson.org (8.11.3/8.11.3) with SMTP id f484hwf62354 for ; Tue, 8 May 2001 00:43:58 -0400 (EDT) (envelope-from robert@fledge.watson.org) Date: Tue, 8 May 2001 00:43:58 -0400 (EDT) From: Robert Watson X-Sender: robert@fledge.watson.org To: arch@FreeBSD.org Subject: securelevel -> securelevel_check() Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-arch@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG One of the features requested for jailNG a number of times, most recently by Matt Dillon, has been to introduce support for per-jail securelevels. This would permit jail securelevels to float above the system securelevel, and allow the jail securelevel to be lowered from outside the jail. This would offer a number of benefits, largely in the form of permitting more sane use of file system flags within the jail. To do this, it is necessary to modify securelevel checks to attempt to go to a process-local (well, credential-local) securelevel. The first step in this process is to abstract out securelevel checks to a central securelevel_check(cred, maxlevel) call. The attached patch does this for most of the kernel, excluding ipfilter since that's contributed code. In some cases, converting from global securelevel to credential securelevel introduces ambiguities: should the process credential be used, or the file descriptor credential, for example. These concerns existed in a number of cases already. I may not have them all right, but would welcome comments. After this is in place, I will produce an updated jailNG patch that incorporates a new managed per-jail securelevel variable. When a securelevel check is performed, the global value is used if the process is not in jail. If in jail, the greater of local and global securelevels will be used. Securelevel modification using the normal kern.securelevel mib will now point to global securelevel outside of jail, and local securelevel within. kern.securelevel will only allow the securelevel to be raised, never lowered. The jail.instance.*.securelevel variable will allow the securelevel to be lowered from outside the jail; however, due to the check semantics, in effect per-jail securelevels will be at least the global level, preventing jails from being used to circumvent the global securelevel. As I've indicated in the past, I'm not a great fan of securelevels, but this seemed like a reasonable feature request to me, and it has substantial utility, especially where the administrator may want to make use of schg and related flags within the jail, but be able to disassemble the jail (or modify it) without rebooting to lower the global securelevel. Robert N M Watson FreeBSD Core Team, TrustedBSD Project robert@fledge.watson.org NAI Labs, Safeport Network Services ? compile/GENERIC Index: alpha/alpha/mem.c =================================================================== RCS file: /home/ncvs/src/sys/alpha/alpha/mem.c,v retrieving revision 1.34 diff -u -r1.34 mem.c --- alpha/alpha/mem.c 2001/03/26 12:39:47 1.34 +++ alpha/alpha/mem.c 2001/05/08 04:31:08 @@ -114,12 +114,16 @@ static int mmopen(dev_t dev, int flags, int fmt, struct proc *p) { + int error; switch (minor(dev)) { case 0: case 1: - if ((flags & FWRITE) && securelevel > 0) - return (EPERM); + if (flags & FWRITE) { + error = securelevel_check(p->p_ucred, 0); + if (error) + return (error); + } break; case 32: #ifdef PERFMON Index: alpha/alpha/sys_machdep.c =================================================================== RCS file: /home/ncvs/src/sys/alpha/alpha/sys_machdep.c,v retrieving revision 1.10 diff -u -r1.10 sys_machdep.c --- alpha/alpha/sys_machdep.c 2001/05/01 08:11:48 1.10 +++ alpha/alpha/sys_machdep.c 2001/05/08 04:31:08 @@ -114,8 +114,9 @@ if (error) return (error); - if (securelevel > 0) - return (EPERM); + error = securelevel_check(p->p_ucred, 0); + if (error) + return (ERROR); error = suser(p); if (error) Index: cam/scsi/scsi_pass.c =================================================================== RCS file: /home/ncvs/src/sys/cam/scsi/scsi_pass.c,v retrieving revision 1.28 diff -u -r1.28 scsi_pass.c --- cam/scsi/scsi_pass.c 2001/03/27 05:45:11 1.28 +++ cam/scsi/scsi_pass.c 2001/05/08 04:31:13 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -368,9 +369,10 @@ /* * Don't allow access when we're running at a high securelvel. */ - if (securelevel > 1) { + error = securelevel_check(p->p_ucred, 1); + if (error) { splx(s); - return(EPERM); + return (error); } /* Index: dev/pci/pci_user.c =================================================================== RCS file: /home/ncvs/src/sys/dev/pci/pci_user.c,v retrieving revision 1.2 diff -u -r1.2 pci_user.c --- dev/pci/pci_user.c 2001/03/26 12:40:30 1.2 +++ dev/pci/pci_user.c 2001/05/08 04:31:22 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -87,8 +88,12 @@ static int pci_open(dev_t dev, int oflags, int devtype, struct proc *p) { - if ((oflags & FWRITE) && securelevel > 0) { - return EPERM; + int error; + + if (oflags & FWRITE) { + error = securelevel_check(p->p_ucred, 0); + if (error) + return (error); } return 0; } Index: dev/random/randomdev.c =================================================================== RCS file: /home/ncvs/src/sys/dev/random/randomdev.c,v retrieving revision 1.28 diff -u -r1.28 randomdev.c --- dev/random/randomdev.c 2001/05/01 08:12:03 1.28 +++ dev/random/randomdev.c 2001/05/08 04:31:23 @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -140,17 +141,29 @@ static int random_open(dev_t dev, int flags, int fmt, struct proc *p) { - if ((flags & FWRITE) && (securelevel > 0 || suser(p))) - return EPERM; - else + int error; + + if (flags & FWRITE) { + error = securelevel_check(p->p_ucred, 0); + if (error) + return error; + + error = suser(p); + return error; + } else return 0; } static int random_close(dev_t dev, int flags, int fmt, struct proc *p) { - if ((flags & FWRITE) && !(securelevel > 0 || suser(p))) - random_reseed(); + int error; + + if (flags & FWRITE) { + if (!(securelevel_check(p->p_ucred, 0) || + suser(p))) + random_reseed(); + } return 0; } Index: dev/syscons/syscons.c =================================================================== RCS file: /home/ncvs/src/sys/dev/syscons/syscons.c,v retrieving revision 1.357 diff -u -r1.357 syscons.c --- dev/syscons/syscons.c 2001/05/01 08:12:05 1.357 +++ dev/syscons/syscons.c 2001/05/08 04:31:26 @@ -995,8 +995,9 @@ error = suser(p); if (error != 0) return error; - if (securelevel > 0) - return EPERM; + error = securelevel_check(p->p_ucred, 0); + if (error != 0) + return error; #ifdef __i386__ p->p_md.md_regs->tf_eflags |= PSL_IOPL; #endif Index: i386/i386/mem.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/mem.c,v retrieving revision 1.88 diff -u -r1.88 mem.c --- i386/i386/mem.c 2001/03/26 12:40:48 1.88 +++ i386/i386/mem.c 2001/05/08 04:31:27 @@ -113,15 +113,19 @@ switch (minor(dev)) { case 0: case 1: - if ((flags & FWRITE) && securelevel > 0) - return (EPERM); + if (flags & FWRITE) { + error = securelevel_check(p->p_ucred, 0); + if (error) + return (error); + } break; case 14: error = suser(p); if (error != 0) return (error); - if (securelevel > 0) - return (EPERM); + error = securelevel_check(p->p_ucred, 0); + if (error) + return (error); p->p_md.md_regs->tf_eflags |= PSL_IOPL; break; } Index: i386/i386/sys_machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/sys_machdep.c,v retrieving revision 1.55 diff -u -r1.55 sys_machdep.c --- i386/i386/sys_machdep.c 2001/05/01 08:12:47 1.55 +++ i386/i386/sys_machdep.c 2001/05/08 04:31:27 @@ -179,8 +179,9 @@ if ((error = suser(p)) != 0) return (error); - if (securelevel > 0) - return (EPERM); + error = securelevel_check(p->p_ucred, 0); + if (error) + return (error); /* * XXX * While this is restricted to root, we should probably figure out Index: i386/isa/spigot.c =================================================================== RCS file: /home/ncvs/src/sys/i386/isa/spigot.c,v retrieving revision 1.48 diff -u -r1.48 spigot.c --- i386/isa/spigot.c 2001/05/01 08:12:51 1.48 +++ i386/isa/spigot.c 2001/05/08 04:31:27 @@ -182,8 +182,9 @@ error = suser(p); if (error != 0) return error; - if (securelevel > 0) - return EPERM; + error = securelevel(p->p_ucred, 0); + if (error) + return error; #endif ss->flags |= OPEN; @@ -238,8 +239,9 @@ error = suser(p); if (error != 0) return error; - if (securelevel > 0) - return EPERM; + error = securelevel(p->p_ucred, 0); + if (error != 0) + return error; #endif p->p_md.md_regs->tf_eflags |= PSL_IOPL; break; Index: i386/linux/linux_machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/linux/linux_machdep.c,v retrieving revision 1.16 diff -u -r1.16 linux_machdep.c --- i386/linux/linux_machdep.c 2001/05/01 08:12:52 1.16 +++ i386/linux/linux_machdep.c 2001/05/08 04:31:28 @@ -472,8 +472,8 @@ return (EINVAL); if ((error = suser(p)) != 0) return (error); - if (securelevel > 0) - return (EPERM); + if ((error = securelevel_check(p->p_ucred, 0)) != 0) + return (error); p->p_md.md_regs->tf_eflags = (p->p_md.md_regs->tf_eflags & ~PSL_IOPL) | (args->level * (PSL_IOPL / 3)); return (0); Index: ia64/ia64/mem.c =================================================================== RCS file: /home/ncvs/src/sys/ia64/ia64/mem.c,v retrieving revision 1.3 diff -u -r1.3 mem.c --- ia64/ia64/mem.c 2001/03/26 12:40:56 1.3 +++ ia64/ia64/mem.c 2001/05/08 04:31:32 @@ -113,12 +113,16 @@ static int mmopen(dev_t dev, int flags, int fmt, struct proc *p) { + int error; switch (minor(dev)) { case 0: case 1: - if ((flags & FWRITE) && securelevel > 0) - return (EPERM); + if (flags & FWRITE) { + error = securelevel_check(p->p_ucred, 0); + if (error) + return (error); + } break; case 32: #ifdef PERFMON Index: kern/kern_linker.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_linker.c,v retrieving revision 1.59 diff -u -r1.59 kern_linker.c --- kern/kern_linker.c 2001/03/22 08:58:45 1.59 +++ kern/kern_linker.c 2001/05/08 04:31:33 @@ -292,8 +292,9 @@ int foundfile, error = 0; /* Refuse to load modules if securelevel raised */ - if (securelevel > 0) - return EPERM; + error = securelevel_check(curproc->p_ucred, 0); + if (error) + return error; lf = linker_find_file_by_name(filename); if (lf) { @@ -420,8 +421,9 @@ int i; /* Refuse to unload modules if securelevel raised */ - if (securelevel > 0) - return EPERM; + error = securelevel_check(curproc->p_ucred, 0); + if (error) + return error; KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); lockmgr(&lock, LK_EXCLUSIVE, 0, curproc); @@ -673,8 +675,9 @@ p->p_retval[0] = -1; - if (securelevel > 0) /* redundant, but that's OK */ - return EPERM; + error = securelevel_check(p->p_ucred, 0); /* redundant, but that's OK */ + if (error) + return error; if ((error = suser(p)) != 0) return error; @@ -716,8 +719,9 @@ linker_file_t lf; int error = 0; - if (securelevel > 0) /* redundant, but that's OK */ - return EPERM; + error = securelevel_check(p->p_ucred, 0); /* redundant, but that's OK */ + if (error) + return error; if ((error = suser(p)) != 0) return error; Index: kern/kern_prot.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_prot.c,v retrieving revision 1.89 diff -u -r1.89 kern_prot.c --- kern/kern_prot.c 2001/05/01 08:12:57 1.89 +++ kern/kern_prot.c 2001/05/08 04:31:34 @@ -984,6 +984,22 @@ return (0); } +/* + * Given a securelevel requirement, test whether securelevel state + * meets the requirement. + */ +int +securelevel_check(cred, maxlevel) + struct ucred *cred; + int maxlevel; +{ + + /* XXX: In the future, this will be protected by a mutex. */ + if (securelevel > maxlevel) + return (EPERM); + return (0); +} + static int suser_permitted = 1; SYSCTL_INT(_kern, OID_AUTO, suser_permitted, CTLFLAG_RW, &suser_permitted, 0, @@ -1189,8 +1205,11 @@ } /* can't trace init when securelevel > 0 */ - if (securelevel > 0 && p2->p_pid == 1) - return (EPERM); + if (p2->p_pid == 1) { + error = securelevel_check(p1->p_ucred, 0); + if (error) + return (error); + } return (0); } Index: kern/kern_sysctl.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_sysctl.c,v retrieving revision 1.106 diff -u -r1.106 kern_sysctl.c --- kern/kern_sysctl.c 2001/03/08 01:20:43 1.106 +++ kern/kern_sysctl.c 2001/05/08 04:31:34 @@ -1013,9 +1013,15 @@ } /* If writing isn't allowed */ - if (req->newptr && (!(oid->oid_kind & CTLFLAG_WR) || - ((oid->oid_kind & CTLFLAG_SECURE) && securelevel > 0))) - return (EPERM); + if (req->newptr) { + if (!(oid->oid_kind & CTLFLAG_WR)) + return (EPERM); + if (oid->oid_kind & CTLFLAG_SECURE) { + error = securelevel_check(req->p->p_ucred, 0); + if (error) + return (error); + } + } /* Most likely only root can write */ if (!(oid->oid_kind & CTLFLAG_ANYBODY) && Index: kern/kern_time.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_time.c,v retrieving revision 1.73 diff -u -r1.73 kern_time.c --- kern/kern_time.c 2001/05/01 08:12:57 1.73 +++ kern/kern_time.c 2001/05/08 04:31:35 @@ -103,7 +103,7 @@ * than one second, nor more than once per second. This allows * a miscreant to make the clock march double-time, but no worse. */ - if (securelevel > 1) { + if (securelevel_check(curproc->p_ucred, 1)) { if (delta.tv_sec < 0 || delta.tv_usec < 0) { /* * Update maxtime to latest time we've seen. Index: miscfs/procfs/procfs_subr.c =================================================================== RCS file: /home/ncvs/src/sys/miscfs/procfs/procfs_subr.c,v retrieving revision 1.33 diff -u -r1.33 procfs_subr.c --- miscfs/procfs/procfs_subr.c 2001/05/01 08:13:09 1.33 +++ miscfs/procfs/procfs_subr.c 2001/05/08 04:31:35 @@ -250,14 +250,17 @@ struct proc *curp = uio->uio_procp; struct pfsnode *pfs = VTOPFS(vp); struct proc *p; - int rtval; + int rtval, error; p = PFIND(pfs->pfs_pid); if (p == NULL) return (EINVAL); PROC_UNLOCK(p); - if (p->p_pid == 1 && securelevel > 0 && uio->uio_rw == UIO_WRITE) - return (EACCES); + if (p->p_pid == 1 && uio->uio_rw == UIO_WRITE) { + error = securelevel_check(curp->p_ucred, 0); + if (error) + return (EACCES); + } mp_fixme("pfs_lockowner needs a lock"); while (pfs->pfs_lockowner) { Index: miscfs/specfs/spec_vnops.c =================================================================== RCS file: /home/ncvs/src/sys/miscfs/specfs/spec_vnops.c,v retrieving revision 1.157 diff -u -r1.157 spec_vnops.c --- miscfs/specfs/spec_vnops.c 2001/04/30 14:35:35 1.157 +++ miscfs/specfs/spec_vnops.c 2001/05/08 04:31:36 @@ -176,13 +176,16 @@ * When running in secure mode, do not allow opens * for writing if the device is mounted */ - if (securelevel >= 1 && vfs_mountedon(vp)) - return (EPERM); + error = securelevel_check(ap->a_cred, 0); + if (error && vfs_mountedon(vp)) + return (error); /* * When running in very secure mode, do not allow * opens for writing of any devices. */ + error = securelevel_check(ap->a_cred, 1); + return (error); if (securelevel >= 2) return (EPERM); } Index: netinet/ip_dummynet.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_dummynet.c,v retrieving revision 1.39 diff -u -r1.39 ip_dummynet.c --- netinet/ip_dummynet.c 2001/02/10 00:10:18 1.39 +++ netinet/ip_dummynet.c 2001/05/08 04:31:53 @@ -1817,8 +1817,11 @@ struct dn_pipe *p, tmp_pipe; /* Disallow sets in really-really secure mode. */ - if (sopt->sopt_dir == SOPT_SET && securelevel >= 3) - return (EPERM); + if (sopt->sopt_dir == SOPT_SET) { + error = securelevel_check(curproc->p_ucred, 2); + if (error) + return (error); + } switch (sopt->sopt_name) { default : Index: netinet/ip_fw.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_fw.c,v retrieving revision 1.164 diff -u -r1.164 ip_fw.c --- netinet/ip_fw.c 2001/04/06 06:52:25 1.164 +++ netinet/ip_fw.c 2001/05/08 04:31:55 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -1841,9 +1842,12 @@ * Disallow modifications in really-really secure mode, but still allow * the logging counters to be reset. */ - if (securelevel >= 3 && (sopt->sopt_name == IP_FW_ADD || - (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG))) - return (EPERM); + if (sopt->sopt_name == IP_FW_ADD || (sopt->sopt_dir == SOPT_SET && + sopt->sopt_name != IP_FW_RESETLOG)) { + error = securelevel_check(curproc->p_ucred, 2); + if (error) + return (error); + } error = 0; switch (sopt->sopt_name) { Index: pc98/pc98/syscons.c =================================================================== RCS file: /home/ncvs/src/sys/pc98/pc98/syscons.c,v retrieving revision 1.159 diff -u -r1.159 syscons.c --- pc98/pc98/syscons.c 2001/05/01 08:13:15 1.159 +++ pc98/pc98/syscons.c 2001/05/08 04:31:58 @@ -997,8 +997,9 @@ error = suser(p); if (error != 0) return error; - if (securelevel > 0) - return EPERM; + error = securelevel(p->p_ucred, 0); + if (error != 0) + return error; #ifdef __i386__ p->p_md.md_regs->tf_eflags |= PSL_IOPL; #endif Index: sys/systm.h =================================================================== RCS file: /home/ncvs/src/sys/sys/systm.h,v retrieving revision 1.139 diff -u -r1.139 systm.h --- sys/systm.h 2001/04/27 19:28:25 1.139 +++ sys/systm.h 2001/05/08 04:31:59 @@ -164,6 +164,7 @@ /* flags for suser_xxx() */ #define PRISON_ROOT 1 +int securelevel_check __P((struct ucred *cred, int maxlevel)); int suser __P((struct proc *)); int suser_xxx __P((struct ucred *cred, struct proc *proc, int flag)); int u_cansee __P((struct ucred *u1, struct ucred *u2)); Index: ufs/ufs/ufs_vnops.c =================================================================== RCS file: /home/ncvs/src/sys/ufs/ufs/ufs_vnops.c,v retrieving revision 1.166 diff -u -r1.166 ufs_vnops.c --- ufs/ufs/ufs_vnops.c 2001/05/01 09:12:39 1.166 +++ ufs/ufs/ufs_vnops.c 2001/05/08 04:32:03 @@ -482,7 +482,7 @@ if (!suser_xxx(cred, NULL, 0)) { if ((ip->i_flags & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) && - securelevel > 0) + securelevel_check(p->p_ucred, 0)) return (EPERM); /* Snapshot flag cannot be set or cleared */ if (((vap->va_flags & SF_SNAPSHOT) != 0 && Index: vm/vm_mmap.c =================================================================== RCS file: /home/ncvs/src/sys/vm/vm_mmap.c,v retrieving revision 1.118 diff -u -r1.118 vm_mmap.c --- vm/vm_mmap.c 2001/05/01 08:13:21 1.118 +++ vm/vm_mmap.c 2001/05/08 04:32:03 @@ -333,7 +333,8 @@ * other securelevel. * XXX this will have to go */ - if (securelevel >= 1) + error = securelevel_check(p->p_ucred, 0); + if (error) disablexworkaround = 1; else disablexworkaround = suser(p); To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-arch" in the body of the message