aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libc/sys/procctl.227
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c3
-rw-r--r--sys/kern/kern_exec.c5
-rw-r--r--sys/kern/kern_fork.c2
-rw-r--r--sys/kern/kern_procctl.c32
-rw-r--r--sys/sys/proc.h1
-rw-r--r--sys/sys/procctl.h5
7 files changed, 71 insertions, 4 deletions
diff --git a/lib/libc/sys/procctl.2 b/lib/libc/sys/procctl.2
index f85825d8cc6f..432ed5919a81 100644
--- a/lib/libc/sys/procctl.2
+++ b/lib/libc/sys/procctl.2
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 13, 2020
+.Dd July 1, 2021
.Dt PROCCTL 2
.Os
.Sh NAME
@@ -564,6 +564,31 @@ Stack gaps are enabled in the process after
Stack gaps are disabled in the process after
.Xr execve 2 .
.El
+.It Dv PROC_NO_NEW_PRIVS_CTL
+Allows one to ignore the SUID and SGID bits on the program
+images activated by
+.Xr execve 2
+in the specified process and its future descendants.
+The
+.Fa data
+parameter must point to the integer variable holding the following
+value:
+.Bl -tag -width PROC_NO_NEW_PRIVS_ENABLE
+.It Dv PROC_NO_NEW_PRIVS_ENABLE
+Request SUID and SGID bits to be ignored.
+.El
+.Pp
+It is not possible to disable it once it has been enabled.
+.It Dv PROC_NO_NEW_PRIVS_STATUS
+Returns the current status of SUID/SGID enablement for the target process.
+The
+.Fa data
+parameter must point to the integer variable, where one of the
+following values is written:
+.Bl -tag -width PROC_NO_NEW_PRIVS_DISABLE
+.It Dv PROC_NO_NEW_PRIVS_ENABLE
+.It Dv PROC_NO_NEW_PRIVS_DISABLE
+.El
.El
.Sh x86 MACHINE-SPECIFIC REQUESTS
.Bl -tag -width PROC_KPTI_STATUS
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index f221397e91dc..950631352f12 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -3643,6 +3643,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
case PROC_STACKGAP_CTL:
case PROC_TRACE_CTL:
case PROC_TRAPCAP_CTL:
+ case PROC_NO_NEW_PRIVS_CTL:
error = copyin(PTRIN(uap->data), &flags, sizeof(flags));
if (error != 0)
return (error);
@@ -3676,6 +3677,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
case PROC_STACKGAP_STATUS:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_NO_NEW_PRIVS_STATUS:
data = &flags;
break;
case PROC_PDEATHSIG_CTL:
@@ -3707,6 +3709,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
case PROC_STACKGAP_STATUS:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_NO_NEW_PRIVS_STATUS:
if (error == 0)
error = copyout(&flags, uap->data, sizeof(flags));
break;
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index aff030cd432e..c3c23f44189e 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -781,8 +781,9 @@ interpret:
signotify(td);
}
- if (imgp->sysent->sv_setid_allowed != NULL &&
- !(*imgp->sysent->sv_setid_allowed)(td, imgp))
+ if ((imgp->sysent->sv_setid_allowed != NULL &&
+ !(*imgp->sysent->sv_setid_allowed)(td, imgp)) ||
+ (p->p_flag2 & P2_NO_NEW_PRIVS) != 0)
execve_nosetid(imgp);
/*
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 0d0659b432fe..7a80f7de85d8 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -492,7 +492,7 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread *
p2->p_flag2 = p1->p_flag2 & (P2_ASLR_DISABLE | P2_ASLR_ENABLE |
P2_ASLR_IGNSTART | P2_NOTRACE | P2_NOTRACE_EXEC |
P2_PROTMAX_ENABLE | P2_PROTMAX_DISABLE | P2_TRAPCAP |
- P2_STKGAP_DISABLE | P2_STKGAP_DISABLE_EXEC);
+ P2_STKGAP_DISABLE | P2_STKGAP_DISABLE_EXEC | P2_NO_NEW_PRIVS);
p2->p_swtick = ticks;
if (p1->p_flag & P_PROFIL)
startprofclock(p2);
diff --git a/sys/kern/kern_procctl.c b/sys/kern/kern_procctl.c
index b6f6f1b772b2..4eb226c6b1b3 100644
--- a/sys/kern/kern_procctl.c
+++ b/sys/kern/kern_procctl.c
@@ -420,6 +420,27 @@ trapcap_status(struct thread *td, struct proc *p, int *data)
}
static int
+no_new_privs_ctl(struct thread *td, struct proc *p, int state)
+{
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ if (state != PROC_NO_NEW_PRIVS_ENABLE)
+ return (EINVAL);
+ p->p_flag2 |= P2_NO_NEW_PRIVS;
+ return (0);
+}
+
+static int
+no_new_privs_status(struct thread *td, struct proc *p, int *data)
+{
+
+ *data = (p->p_flag2 & P2_NO_NEW_PRIVS) != 0 ?
+ PROC_NO_NEW_PRIVS_ENABLE : PROC_NO_NEW_PRIVS_DISABLE;
+ return (0);
+}
+
+static int
protmax_ctl(struct thread *td, struct proc *p, int state)
{
PROC_LOCK_ASSERT(p, MA_OWNED);
@@ -600,6 +621,7 @@ sys_procctl(struct thread *td, struct procctl_args *uap)
case PROC_STACKGAP_CTL:
case PROC_TRACE_CTL:
case PROC_TRAPCAP_CTL:
+ case PROC_NO_NEW_PRIVS_CTL:
error = copyin(uap->data, &flags, sizeof(flags));
if (error != 0)
return (error);
@@ -631,6 +653,7 @@ sys_procctl(struct thread *td, struct procctl_args *uap)
case PROC_STACKGAP_STATUS:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_NO_NEW_PRIVS_STATUS:
data = &flags;
break;
case PROC_PDEATHSIG_CTL:
@@ -661,6 +684,7 @@ sys_procctl(struct thread *td, struct procctl_args *uap)
case PROC_STACKGAP_STATUS:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_NO_NEW_PRIVS_STATUS:
if (error == 0)
error = copyout(&flags, uap->data, sizeof(flags));
break;
@@ -710,6 +734,10 @@ kern_procctl_single(struct thread *td, struct proc *p, int com, void *data)
return (trapcap_ctl(td, p, *(int *)data));
case PROC_TRAPCAP_STATUS:
return (trapcap_status(td, p, data));
+ case PROC_NO_NEW_PRIVS_CTL:
+ return (no_new_privs_ctl(td, p, *(int *)data));
+ case PROC_NO_NEW_PRIVS_STATUS:
+ return (no_new_privs_status(td, p, data));
default:
return (EINVAL);
}
@@ -740,6 +768,8 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data)
case PROC_TRAPCAP_STATUS:
case PROC_PDEATHSIG_CTL:
case PROC_PDEATHSIG_STATUS:
+ case PROC_NO_NEW_PRIVS_CTL:
+ case PROC_NO_NEW_PRIVS_STATUS:
if (idtype != P_PID)
return (EINVAL);
}
@@ -772,6 +802,7 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data)
case PROC_REAP_KILL:
case PROC_TRACE_CTL:
case PROC_TRAPCAP_CTL:
+ case PROC_NO_NEW_PRIVS_CTL:
sx_slock(&proctree_lock);
tree_locked = true;
break;
@@ -788,6 +819,7 @@ kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data)
case PROC_STACKGAP_STATUS:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_NO_NEW_PRIVS_STATUS:
tree_locked = false;
break;
default:
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 19e8d76c6f99..9813324bfa69 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -835,6 +835,7 @@ struct proc {
after exec */
#define P2_ITSTOPPED 0x00002000
#define P2_PTRACEREQ 0x00004000 /* Active ptrace req */
+#define P2_NO_NEW_PRIVS 0x00008000 /* Ignore setuid */
/* Flags protected by proctree_lock, kept in p_treeflags. */
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
diff --git a/sys/sys/procctl.h b/sys/sys/procctl.h
index 90fb149830dc..cc0279fb0d08 100644
--- a/sys/sys/procctl.h
+++ b/sys/sys/procctl.h
@@ -63,6 +63,8 @@
#define PROC_PROTMAX_STATUS 16 /* query implicit PROT_MAX status */
#define PROC_STACKGAP_CTL 17 /* en/dis stack gap on MAP_STACK */
#define PROC_STACKGAP_STATUS 18 /* query stack gap */
+#define PROC_NO_NEW_PRIVS_CTL 19 /* disable setuid/setgid */
+#define PROC_NO_NEW_PRIVS_STATUS 20 /* query suid/sgid disabled status */
/* Operations for PROC_SPROTECT (passed in integer arg). */
#define PPROT_OP(x) ((x) & 0xf)
@@ -141,6 +143,9 @@ struct procctl_reaper_kill {
#define PROC_STACKGAP_ENABLE_EXEC 0x0004
#define PROC_STACKGAP_DISABLE_EXEC 0x0008
+#define PROC_NO_NEW_PRIVS_ENABLE 1
+#define PROC_NO_NEW_PRIVS_DISABLE 2
+
#ifndef _KERNEL
__BEGIN_DECLS
int procctl(idtype_t, id_t, int, void *);