summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorderaadt <deraadt@openbsd.org>2017-12-12 01:12:34 +0000
committerderaadt <deraadt@openbsd.org>2017-12-12 01:12:34 +0000
commit4ea7ed56bd1c71560696216439fcb657286d6443 (patch)
tree93394e9dd8437592a1edb3f27aa5cee002116242 /sys
parentFix the behavior of preferring weaker-but-still-good 5Ghz APs over (diff)
downloadwireguard-openbsd-4ea7ed56bd1c71560696216439fcb657286d6443.tar.xz
wireguard-openbsd-4ea7ed56bd1c71560696216439fcb657286d6443.zip
pledge()'s 2nd argument becomes char *execpromises, which becomes the
pledge for a new execve image immediately upon start. Also introduces "error" which makes violations return -1 ENOSYS instead of killing the program ("error" may not be handed to a setuid/setgid program, which may be missing/ignoring syscall return values and would continue with inconsistant state) Discussion with many florian has used this to improve the strictness of a daemon
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_exec.c17
-rw-r--r--sys/kern/kern_fork.c4
-rw-r--r--sys/kern/kern_pledge.c129
-rw-r--r--sys/kern/syscalls.master5
-rw-r--r--sys/sys/pledge.h4
-rw-r--r--sys/sys/proc.h6
6 files changed, 108 insertions, 57 deletions
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 3c65a3a9a44..c12c5848240 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exec.c,v 1.189 2017/08/29 02:51:27 deraadt Exp $ */
+/* $OpenBSD: kern_exec.c,v 1.190 2017/12/12 01:12:34 deraadt Exp $ */
/* $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $ */
/*-
@@ -139,6 +139,13 @@ check_exec(struct proc *p, struct exec_package *epp)
goto bad1;
}
+ /* SUID programs may not be started with execpromises */
+ if ((epp->ep_vap->va_mode & (VSUID | VSGID)) &&
+ (p->p_p->ps_flags & PS_EXECPLEDGE)) {
+ error = EACCES;
+ goto bad1;
+ }
+
if ((vp->v_mount->mnt_flag & MNT_NOSUID))
epp->ep_vap->va_mode &= ~(VSUID | VSGID);
@@ -520,7 +527,13 @@ sys_execve(struct proc *p, void *v, register_t *retval)
else
atomic_clearbits_int(&pr->ps_flags, PS_SUGIDEXEC);
- atomic_clearbits_int(&pr->ps_flags, PS_PLEDGE);
+ if (pr->ps_flags & PS_EXECPLEDGE) {
+ pr->ps_pledge = pr->ps_execpledge;
+ atomic_setbits_int(&pr->ps_flags, PS_PLEDGE);
+ } else {
+ atomic_clearbits_int(&pr->ps_flags, PS_PLEDGE);
+ pr->ps_pledge = 0;
+ }
/*
* deal with set[ug]id.
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index cd5f36f6378..4a463387471 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_fork.c,v 1.200 2017/09/27 06:45:00 deraadt Exp $ */
+/* $OpenBSD: kern_fork.c,v 1.201 2017/12/12 01:12:34 deraadt Exp $ */
/* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */
/*
@@ -237,7 +237,7 @@ process_new(struct proc *p, struct process *parent, int flags)
vref(pr->ps_textvp);
pr->ps_flags = parent->ps_flags &
- (PS_SUGID | PS_SUGIDEXEC | PS_PLEDGE | PS_WXNEEDED);
+ (PS_SUGID | PS_SUGIDEXEC | PS_PLEDGE | PS_EXECPLEDGE | PS_WXNEEDED);
if (parent->ps_session->s_ttyvp != NULL)
pr->ps_flags |= parent->ps_flags & PS_CONTROLT;
diff --git a/sys/kern/kern_pledge.c b/sys/kern/kern_pledge.c
index 9daf916f0c7..232d3003095 100644
--- a/sys/kern/kern_pledge.c
+++ b/sys/kern/kern_pledge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_pledge.c,v 1.225 2017/12/09 06:50:32 deraadt Exp $ */
+/* $OpenBSD: kern_pledge.c,v 1.226 2017/12/12 01:12:34 deraadt Exp $ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
@@ -84,7 +84,9 @@
#endif
uint64_t pledgereq_flags(const char *req);
-int canonpath(const char *input, char *buf, size_t bufsize);
+int parsepledges(struct proc *p, const char *kname,
+ const char *promises, u_int64_t *fp);
+int canonpath(const char *input, char *buf, size_t bufsize);
/* #define DEBUG_PLEDGE */
#ifdef DEBUG_PLEDGE
@@ -367,6 +369,7 @@ static const struct {
{ "dns", PLEDGE_DNS },
{ "dpath", PLEDGE_DPATH },
{ "drm", PLEDGE_DRM },
+ { "error", PLEDGE_ERROR },
{ "exec", PLEDGE_EXEC },
{ "fattr", PLEDGE_FATTR | PLEDGE_CHOWN },
{ "flock", PLEDGE_FLOCK },
@@ -394,66 +397,90 @@ static const struct {
};
int
+parsepledges(struct proc *p, const char *kname, const char *promises, u_int64_t *fp)
+{
+ size_t rbuflen;
+ char *rbuf, *rp, *pn;
+ u_int64_t flags = 0, f;
+ int error;
+
+ rbuf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
+ error = copyinstr(promises, rbuf, MAXPATHLEN,
+ &rbuflen);
+ if (error) {
+ free(rbuf, M_TEMP, MAXPATHLEN);
+ return (error);
+ }
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_STRUCT))
+ ktrstruct(p, kname, rbuf, rbuflen-1);
+#endif
+
+ for (rp = rbuf; rp && *rp && error == 0; rp = pn) {
+ pn = strchr(rp, ' '); /* find terminator */
+ if (pn) {
+ while (*pn == ' ')
+ *pn++ = '\0';
+ }
+ if ((f = pledgereq_flags(rp)) == 0) {
+ free(rbuf, M_TEMP, MAXPATHLEN);
+ return (EINVAL);
+ }
+ flags |= f;
+ }
+ free(rbuf, M_TEMP, MAXPATHLEN);
+ *fp = flags;
+ return 0;
+}
+
+int
sys_pledge(struct proc *p, void *v, register_t *retval)
{
struct sys_pledge_args /* {
- syscallarg(const char *)request;
- syscallarg(const char **)paths;
+ syscallarg(const char *)promises;
+ syscallarg(const char *)execpromises;
} */ *uap = v;
struct process *pr = p->p_p;
- uint64_t flags = 0;
+ uint64_t promises, execpromises;
int error;
- if (SCARG(uap, request)) {
- size_t rbuflen;
- char *rbuf, *rp, *pn;
- uint64_t f;
-
- rbuf = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
- error = copyinstr(SCARG(uap, request), rbuf, MAXPATHLEN,
- &rbuflen);
- if (error) {
- free(rbuf, M_TEMP, MAXPATHLEN);
+ if (SCARG(uap, promises)) {
+ error = parsepledges(p, "pledgereq",
+ SCARG(uap, promises), &promises);
+ if (error)
return (error);
- }
-#ifdef KTRACE
- if (KTRPOINT(p, KTR_STRUCT))
- ktrstruct(p, "pledgereq", rbuf, rbuflen-1);
-#endif
-
- for (rp = rbuf; rp && *rp && error == 0; rp = pn) {
- pn = strchr(rp, ' '); /* find terminator */
- if (pn) {
- while (*pn == ' ')
- *pn++ = '\0';
- }
- if ((f = pledgereq_flags(rp)) == 0) {
- free(rbuf, M_TEMP, MAXPATHLEN);
- return (EINVAL);
- }
- flags |= f;
- }
- free(rbuf, M_TEMP, MAXPATHLEN);
+ /* In "error" mode, ignore promise increase requests,
+ * but accept promise decrease requests */
+ if (ISSET(pr->ps_flags, PS_PLEDGE) &&
+ (pr->ps_pledge & PLEDGE_ERROR))
+ promises &= (pr->ps_pledge & PLEDGE_USERSET);
- /*
- * if we are already pledged, allow only promises reductions.
- * flags doesn't contain flags outside _USERSET: they will be
- * relearned.
- */
+ /* Only permit reductions */
if (ISSET(pr->ps_flags, PS_PLEDGE) &&
- (((flags | pr->ps_pledge) != pr->ps_pledge)))
+ (((promises | pr->ps_pledge) != pr->ps_pledge)))
return (EPERM);
}
+ if (SCARG(uap, execpromises)) {
+ error = parsepledges(p, "pledgeexecreq",
+ SCARG(uap, execpromises), &execpromises);
+ if (error)
+ return (error);
- if (SCARG(uap, paths))
- return (EINVAL);
+ /* Only permit reductions */
+ if (ISSET(pr->ps_flags, PS_EXECPLEDGE) &&
+ (((execpromises | pr->ps_execpledge) != pr->ps_execpledge)))
+ return (EPERM);
+ }
- if (SCARG(uap, request)) {
- pr->ps_pledge = flags;
+ if (SCARG(uap, promises)) {
+ pr->ps_pledge = promises;
pr->ps_flags |= PS_PLEDGE;
}
-
+ if (SCARG(uap, execpromises)) {
+ pr->ps_execpledge = execpromises;
+ pr->ps_flags |= PS_EXECPLEDGE;
+ }
return (0);
}
@@ -489,13 +516,16 @@ pledge_fail(struct proc *p, int error, uint64_t code)
codes = pledgenames[i].name;
break;
}
- log(LOG_ERR, "%s[%d]: pledge \"%s\", syscall %d\n",
- p->p_p->ps_comm, p->p_p->ps_pid, codes, p->p_pledge_syscall);
- p->p_p->ps_acflag |= APLEDGE;
#ifdef KTRACE
if (KTRPOINT(p, KTR_PLEDGE))
ktrpledge(p, error, code, p->p_pledge_syscall);
#endif
+ if (p->p_p->ps_pledge & PLEDGE_ERROR)
+ return (ENOSYS);
+
+ log(LOG_ERR, "%s[%d]: pledge \"%s\", syscall %d\n",
+ p->p_p->ps_comm, p->p_p->ps_pid, codes, p->p_pledge_syscall);
+ p->p_p->ps_acflag |= APLEDGE;
/* Send uncatchable SIGABRT for coredump */
memset(&sa, 0, sizeof sa);
sa.sa_handler = SIG_DFL;
@@ -1394,6 +1424,9 @@ pledge_protexec(struct proc *p, int prot)
{
if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
return 0;
+ /* Before kbind(2) call, ld.so and crt may create EXEC mappings */
+ if (p->p_p->ps_kbind_addr == 0 && p->p_p->ps_kbind_cookie == 0)
+ return 0;
if (!(p->p_p->ps_pledge & PLEDGE_PROTEXEC) && (prot & PROT_EXEC))
return pledge_fail(p, EPERM, PLEDGE_PROTEXEC);
return 0;
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index eb3e0b78534..c9411db3ba1 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -1,4 +1,4 @@
-; $OpenBSD: syscalls.master,v 1.179 2017/11/28 06:03:41 guenther Exp $
+; $OpenBSD: syscalls.master,v 1.180 2017/12/12 01:12:34 deraadt Exp $
; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
@@ -227,7 +227,8 @@
106 STD { int sys_listen(int s, int backlog); }
107 STD { int sys_chflagsat(int fd, const char *path, \
u_int flags, int atflags); }
-108 STD { int sys_pledge(const char *request, const char **paths); }
+108 STD { int sys_pledge(const char *promises, \
+ const char *execpromises); }
109 STD { int sys_ppoll(struct pollfd *fds, \
u_int nfds, const struct timespec *ts, \
const sigset_t *mask); }
diff --git a/sys/sys/pledge.h b/sys/sys/pledge.h
index 4a59d112c1d..832f170e146 100644
--- a/sys/sys/pledge.h
+++ b/sys/sys/pledge.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pledge.h,v 1.32 2017/08/29 02:51:27 deraadt Exp $ */
+/* $OpenBSD: pledge.h,v 1.33 2017/12/12 01:12:34 deraadt Exp $ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
@@ -59,6 +59,7 @@
#define PLEDGE_CHOWN 0x0000000080000000ULL /* chown(2) family */
#define PLEDGE_CHOWNUID 0x0000000100000000ULL /* allow owner/group changes */
#define PLEDGE_BPF 0x0000000200000000ULL /* bpf ioctl */
+#define PLEDGE_ERROR 0x0000000400000000ULL /* ENOSYS instead of kill */
/*
* Bits outside PLEDGE_USERSET are used by the kernel itself
@@ -105,6 +106,7 @@ static struct {
{ PLEDGE_VMM, "vmm" },
{ PLEDGE_CHOWNUID, "chown" },
{ PLEDGE_BPF, "bpf" },
+ { PLEDGE_ERROR, "error" },
{ 0, NULL },
};
#endif
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index d8861f1d896..60088f49c85 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.240 2017/08/29 02:51:27 deraadt Exp $ */
+/* $OpenBSD: proc.h,v 1.241 2017/12/12 01:12:34 deraadt Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -220,6 +220,7 @@ struct process {
u_short ps_acflag; /* Accounting flags. */
uint64_t ps_pledge;
+ uint64_t ps_execpledge;
int64_t ps_kbind_cookie;
u_long ps_kbind_addr;
@@ -262,13 +263,14 @@ struct process {
#define PS_NOBROADCASTKILL 0x00080000 /* Process excluded from kill -1. */
#define PS_PLEDGE 0x00100000 /* Has called pledge(2) */
#define PS_WXNEEDED 0x00200000 /* Process may violate W^X */
+#define PS_EXECPLEDGE 0x00400000 /* Has exec pledges */
#define PS_BITS \
("\20" "\01CONTROLT" "\02EXEC" "\03INEXEC" "\04EXITING" "\05SUGID" \
"\06SUGIDEXEC" "\07PPWAIT" "\010ISPWAIT" "\011PROFIL" "\012TRACED" \
"\013WAITED" "\014COREDUMP" "\015SINGLEEXIT" "\016SINGLEUNWIND" \
"\017NOZOMBIE" "\020STOPPED" "\021SYSTEM" "\022EMBRYO" "\023ZOMBIE" \
- "\024NOBROADCASTKILL" "\025PLEDGE" "\026WXNEEDED")
+ "\024NOBROADCASTKILL" "\025PLEDGE" "\026WXNEEDED", "\027EXECPLEDGE")
struct lock_list_entry;