summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorVitaliy Makkoveev <mvs@cvs.openbsd.org>2024-08-22 10:08:26 +0000
committerVitaliy Makkoveev <mvs@cvs.openbsd.org>2024-08-22 10:08:26 +0000
commit72ee5c0bce6509f1e55ccafe76747a1fd173aca5 (patch)
tree005d8432e461ea3d9f5fe11ce4a8d206a5fe1c11 /sys/kern
parent6ffb10fc4d49fd88379e6c7ce72211ca47757276 (diff)
Introduce sysctl_securelevel() to modify `securelevel' mp-safe. Keep
KERN_SECURELVL locked until existing `securelevel' checks became moved out of kernel lock. Make sysctl_securelevel_int() mp-safe by using atomic_load_int(9) to unlocked read-only access for `securelevel'. Unlock KERN_ALLOWDT. `allowdt' is the atomically accessed integer used only once in dtopen(). ok mpi
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_sysctl.c66
1 files changed, 49 insertions, 17 deletions
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index 7df7f058385..68d6b64c813 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_sysctl.c,v 1.442 2024/08/20 13:29:25 mvs Exp $ */
+/* $OpenBSD: kern_sysctl.c,v 1.443 2024/08/22 10:08:25 mvs Exp $ */
/* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */
/*-
@@ -134,6 +134,7 @@ extern int autoconf_serial;
int allowkmem;
+int sysctl_securelevel(void *, size_t *, void *, size_t, struct proc *);
int sysctl_diskinit(int, struct proc *);
int sysctl_proc_args(int *, u_int, void *, size_t *, struct proc *);
int sysctl_proc_cwd(int *, u_int, void *, size_t *, struct proc *);
@@ -513,6 +514,11 @@ kern_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
return (sysctl_rdstring(oldp, oldlenp, newp, version));
case KERN_NUMVNODES: /* XXX numvnodes is a long */
return (sysctl_rdint(oldp, oldlenp, newp, numvnodes));
+#if NDT > 0
+ case KERN_ALLOWDT:
+ return (sysctl_securelevel_int(oldp, oldlenp, newp, newlen,
+ &allowdt));
+#endif
case KERN_HOSTID:
return (sysctl_int(oldp, oldlenp, newp, newlen, &hostid));
case KERN_CLOCKRATE:
@@ -596,26 +602,13 @@ int
kern_sysctl_locked(int *name, u_int namelen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen, struct proc *p)
{
- int error, level, stackgap;
+ int error, stackgap;
dev_t dev;
extern int pool_debug;
switch (name[0]) {
case KERN_SECURELVL:
- level = securelevel;
- if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &level)) ||
- newp == NULL)
- return (error);
- if ((securelevel > 0 || level < -1) &&
- level < securelevel && p->p_p->ps_pid != 1)
- return (EPERM);
- securelevel = level;
- return (0);
-#if NDT > 0
- case KERN_ALLOWDT:
- return (sysctl_securelevel_int(oldp, oldlenp, newp, newlen,
- &allowdt));
-#endif
+ return (sysctl_securelevel(oldp, oldlenp, newp, newlen, p));
case KERN_ALLOWKMEM:
return (sysctl_securelevel_int(oldp, oldlenp, newp, newlen,
&allowkmem));
@@ -1123,6 +1116,45 @@ sysctl_rdint(void *oldp, size_t *oldlenp, void *newp, int val)
return (error);
}
+int
+sysctl_securelevel(void *oldp, size_t *oldlenp, void *newp, size_t newlen,
+ struct proc *p)
+{
+ int oldval, newval;
+ int error;
+
+ if (oldp && *oldlenp < sizeof(int))
+ return (ENOMEM);
+ if (newp && newlen != sizeof(int))
+ return (EINVAL);
+ *oldlenp = sizeof(int);
+
+ if (newp) {
+ if ((error = copyin(newp, &newval, sizeof(int))))
+ return (error);
+ do {
+ oldval = atomic_load_int(&securelevel);
+ if ((oldval > 0 || newval < -1) && newval < oldval &&
+ p->p_p->ps_pid != 1)
+ return (EPERM);
+ } while (atomic_cas_uint(&securelevel, oldval, newval) !=
+ oldval);
+
+ if (oldp) {
+ /* new value has been set although user gets error */
+ if ((error = copyout(&oldval, oldp, sizeof(int))))
+ return (error);
+ }
+ } else if (oldp) {
+ oldval = atomic_load_int(&securelevel);
+
+ if ((error = copyout(&oldval, oldp, sizeof(int))))
+ return (error);
+ }
+
+ return (0);
+}
+
/*
* Selects between sysctl_rdint and sysctl_int according to securelevel.
*/
@@ -1130,7 +1162,7 @@ int
sysctl_securelevel_int(void *oldp, size_t *oldlenp, void *newp, size_t newlen,
int *valp)
{
- if (securelevel > 0)
+ if (atomic_load_int(&securelevel) > 0)
return (sysctl_rdint(oldp, oldlenp, newp, *valp));
return (sysctl_int(oldp, oldlenp, newp, newlen, valp));
}