Page MenuHomeFreeBSD

D30130.id90518.diff
No OneTemporary

D30130.id90518.diff

Index: lib/libc/sys/procctl.2
===================================================================
--- lib/libc/sys/procctl.2
+++ lib/libc/sys/procctl.2
@@ -564,6 +564,30 @@
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 created by
+.Xr execve 2
+in the specified process or its 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 SETUID/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
.Sh x86 MACHINE-SPECIFIC REQUESTS
.Bl -tag -width PROC_KPTI_STATUS
Index: sys/compat/linux/linux_misc.c
===================================================================
--- sys/compat/linux/linux_misc.c
+++ sys/compat/linux/linux_misc.c
@@ -1968,7 +1968,7 @@
int
linux_prctl(struct thread *td, struct linux_prctl_args *args)
{
- int error = 0, max_size;
+ int error = 0, max_size, arg;
struct proc *p = td->td_proc;
char comm[LINUX_MAX_COMM_LEN];
int pdeath_signal, trace_state;
@@ -2099,8 +2099,10 @@
error = EINVAL;
break;
case LINUX_PR_SET_NO_NEW_PRIVS:
- linux_msg(td, "unsupported prctl PR_SET_NO_NEW_PRIVS");
- error = EINVAL;
+ arg = args->arg2 == 1 ?
+ PROC_NO_NEW_PRIVS_ENABLE : PROC_NO_NEW_PRIVS_DISABLE;
+ error = kern_procctl(td, P_PID, p->p_pid,
+ PROC_NO_NEW_PRIVS_CTL, &arg);
break;
case LINUX_PR_SET_PTRACER:
linux_msg(td, "unsupported prctl PR_SET_PTRACER");
Index: sys/kern/kern_exec.c
===================================================================
--- sys/kern/kern_exec.c
+++ sys/kern/kern_exec.c
@@ -782,6 +782,9 @@
!(*imgp->sysent->sv_setid_allowed)(td, imgp))
execve_nosetid(imgp);
+ if (p->p_flag2 & P2_NO_NEW_PRIVS)
+ execve_nosetid(imgp);
+
/*
* Implement image setuid/setgid installation.
*/
Index: sys/kern/kern_fork.c
===================================================================
--- sys/kern/kern_fork.c
+++ sys/kern/kern_fork.c
@@ -492,7 +492,7 @@
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);
Index: sys/kern/kern_procctl.c
===================================================================
--- sys/kern/kern_procctl.c
+++ sys/kern/kern_procctl.c
@@ -419,6 +419,31 @@
return (0);
}
+static int
+no_new_privs_ctl(struct thread *td, struct proc *p, int state)
+{
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ switch (state) {
+ case PROC_NO_NEW_PRIVS_ENABLE:
+ p->p_flag2 |= P2_NO_NEW_PRIVS;
+ break;
+ default:
+ return (EINVAL);
+ }
+ 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)
{
@@ -600,6 +625,7 @@
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 +657,7 @@
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 +688,7 @@
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 +738,10 @@
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 +772,8 @@
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 +806,7 @@
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 +823,7 @@
case PROC_STACKGAP_STATUS:
case PROC_TRACE_STATUS:
case PROC_TRAPCAP_STATUS:
+ case PROC_NO_NEW_PRIVS_STATUS:
tree_locked = false;
break;
default:
Index: sys/kern/vfs_syscalls.c
===================================================================
--- sys/kern/vfs_syscalls.c
+++ sys/kern/vfs_syscalls.c
@@ -955,6 +955,10 @@
return (0);
}
+static int unprivileged_chroot = 0;
+SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_chroot, CTLFLAG_RW,
+ &unprivileged_chroot, 0,
+ "Unprivileged processes can use chroot(2)");
/*
* Change notion of root (``/'') directory.
*/
@@ -967,11 +971,20 @@
sys_chroot(struct thread *td, struct chroot_args *uap)
{
struct nameidata nd;
+ struct proc *p;
int error;
error = priv_check(td, PRIV_VFS_CHROOT);
- if (error != 0)
- return (error);
+ if (error != 0) {
+ p = td->td_proc;
+ PROC_LOCK(p);
+ if (unprivileged_chroot == 0 ||
+ (p->p_flag2 & P2_NO_NEW_PRIVS) == 0) {
+ PROC_UNLOCK(p);
+ return (error);
+ }
+ PROC_UNLOCK(p);
+ }
NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1,
UIO_USERSPACE, uap->path, td);
error = namei(&nd);
Index: sys/sys/proc.h
===================================================================
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -833,6 +833,7 @@
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 */
Index: sys/sys/procctl.h
===================================================================
--- sys/sys/procctl.h
+++ 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 @@
#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 *);
Index: usr.bin/proccontrol/proccontrol.1
===================================================================
--- usr.bin/proccontrol/proccontrol.1
+++ usr.bin/proccontrol/proccontrol.1
@@ -69,6 +69,9 @@
.It Ar protmax
Controls the implicit PROT_MAX application for
.Xr mmap 2 .
+.It Ar nonewprivs
+Controls disabling the setuid and sgid bits for
+.Xr execve 2 .
.It Ar kpti
Controls the KPTI enable, AMD64 only.
.It Ar la48
Index: usr.bin/proccontrol/proccontrol.c
===================================================================
--- usr.bin/proccontrol/proccontrol.c
+++ usr.bin/proccontrol/proccontrol.c
@@ -45,6 +45,7 @@
MODE_TRAPCAP,
MODE_PROTMAX,
MODE_STACKGAP,
+ MODE_NO_NEW_PRIVS,
#ifdef PROC_KPTI_CTL
MODE_KPTI,
#endif
@@ -84,7 +85,7 @@
{
fprintf(stderr, "Usage: proccontrol -m (aslr|protmax|trace|trapcap|"
- "stackgap"KPTI_USAGE LA_USAGE") [-q] "
+ "stackgap|nonewprivs"KPTI_USAGE LA_USAGE") [-q] "
"[-s (enable|disable)] [-p pid | command]\n");
exit(1);
}
@@ -113,6 +114,8 @@
mode = MODE_TRAPCAP;
else if (strcmp(optarg, "stackgap") == 0)
mode = MODE_STACKGAP;
+ else if (strcmp(optarg, "nonewprivs") == 0)
+ mode = MODE_NO_NEW_PRIVS;
#ifdef PROC_KPTI_CTL
else if (strcmp(optarg, "kpti") == 0)
mode = MODE_KPTI;
@@ -174,6 +177,9 @@
case MODE_STACKGAP:
error = procctl(P_PID, pid, PROC_STACKGAP_STATUS, &arg);
break;
+ case MODE_NO_NEW_PRIVS:
+ error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_STATUS, &arg);
+ break;
#ifdef PROC_KPTI_CTL
case MODE_KPTI:
error = procctl(P_PID, pid, PROC_KPTI_STATUS, &arg);
@@ -264,6 +270,16 @@
break;
}
break;
+ case MODE_NO_NEW_PRIVS:
+ switch (arg) {
+ case PROC_NO_NEW_PRIVS_ENABLE:
+ printf("enabled\n");
+ break;
+ case PROC_NO_NEW_PRIVS_DISABLE:
+ printf("disabled\n");
+ break;
+ }
+ break;
#ifdef PROC_KPTI_CTL
case MODE_KPTI:
switch (arg & ~PROC_KPTI_STATUS_ACTIVE) {
@@ -330,6 +346,11 @@
PROC_STACKGAP_DISABLE_EXEC);
error = procctl(P_PID, pid, PROC_STACKGAP_CTL, &arg);
break;
+ case MODE_NO_NEW_PRIVS:
+ arg = enable ? PROC_NO_NEW_PRIVS_ENABLE :
+ PROC_NO_NEW_PRIVS_DISABLE;
+ error = procctl(P_PID, pid, PROC_NO_NEW_PRIVS_CTL, &arg);
+ break;
#ifdef PROC_KPTI_CTL
case MODE_KPTI:
arg = enable ? PROC_KPTI_CTL_ENABLE_ON_EXEC :
Index: usr.sbin/chroot/chroot.8
===================================================================
--- usr.sbin/chroot/chroot.8
+++ usr.sbin/chroot/chroot.8
@@ -39,6 +39,7 @@
.Op Fl G Ar group Ns Op Cm \&, Ns Ar group ...
.Op Fl g Ar group
.Op Fl u Ar user
+.Op Fl n
.Ar newroot
.Op Ar command Op Ar arg ...
.Sh DESCRIPTION
@@ -61,6 +62,8 @@
.It Fl u Ar user
Run the command as the
.Ar user .
+.It Fl n
+Run in non-privileged mode.
.El
.Sh ENVIRONMENT
The following environment variable is referenced by
Index: usr.sbin/chroot/chroot.c
===================================================================
--- usr.sbin/chroot/chroot.c
+++ usr.sbin/chroot/chroot.c
@@ -44,6 +44,7 @@
__FBSDID("$FreeBSD$");
#include <sys/types.h>
+#include <sys/procctl.h>
#include <ctype.h>
#include <err.h>
@@ -51,6 +52,7 @@
#include <limits.h>
#include <paths.h>
#include <pwd.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -67,13 +69,15 @@
const char *shell;
gid_t gid, *gidlist;
uid_t uid;
- int ch, gids;
+ int arg, ch, error, gids;
long ngroups_max;
+ bool nonpriviledged;
gid = 0;
uid = 0;
user = group = grouplist = NULL;
- while ((ch = getopt(argc, argv, "G:g:u:")) != -1) {
+ nonpriviledged = false;
+ while ((ch = getopt(argc, argv, "G:g:u:n")) != -1) {
switch(ch) {
case 'u':
user = optarg;
@@ -90,6 +94,9 @@
if (*grouplist == '\0')
usage();
break;
+ case 'n':
+ nonpriviledged = true;
+ break;
case '?':
default:
usage();
@@ -153,6 +160,13 @@
}
}
+ if (nonpriviledged) {
+ arg = PROC_NO_NEW_PRIVS_ENABLE;
+ error = procctl(P_PID, getpid(), PROC_NO_NEW_PRIVS_CTL, &arg);
+ if (error != 0)
+ err(1, "procctl");
+ }
+
if (chdir(argv[0]) == -1 || chroot(".") == -1)
err(1, "%s", argv[0]);
@@ -179,6 +193,6 @@
usage(void)
{
(void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] "
- "[-u user] newroot [command]\n");
+ "[-u user] [-n ] newroot [command]\n");
exit(1);
}

File Metadata

Mime Type
text/plain
Expires
Wed, Sep 2, 9:07 PM (1 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
38013224
Default Alt Text
D30130.id90518.diff (11 KB)

Event Timeline