Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 8 May 2001 00:43:58 -0400 (EDT)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        arch@FreeBSD.org
Subject:   securelevel -> securelevel_check()
Message-ID:  <Pine.NEB.3.96L.1010508003718.11741U-100000@fledge.watson.org>

next in thread | raw e-mail | index | archive | help

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 <sys/conf.h>
 #include <sys/errno.h>
 #include <sys/devicestat.h>
+#include <sys/proc.h>
 
 #include <cam/cam.h>
 #include <cam/cam_ccb.h>
@@ -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 <sys/kernel.h>
 #include <sys/queue.h>
 #include <sys/types.h>
+#include <sys/proc.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
@@ -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 <sys/sysctl.h>
 #include <sys/uio.h>
 #include <sys/unistd.h>
+#include <sys/proc.h>
 #include <sys/vnode.h>
 
 #include <machine/bus.h>
@@ -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 <sys/sysctl.h>
 #include <sys/syslog.h>
 #include <sys/ucred.h>
+#include <sys/proc.h>
 #include <net/if.h>
 #include <net/route.h>
 #include <netinet/in.h>
@@ -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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.NEB.3.96L.1010508003718.11741U-100000>