Always allow the setsockopt & getsockopt system calls... however, in the
authorderaadt <deraadt@openbsd.org>
Tue, 20 Oct 2015 01:44:00 +0000 (01:44 +0000)
committerderaadt <deraadt@openbsd.org>
Tue, 20 Oct 2015 01:44:00 +0000 (01:44 +0000)
default case only allows SOL_SOCKET SO_RCVBUF which is very common in
network-facing daemons.  Many of them manage this on a socket after
dropping abilities which can get them _new_ sockets.. syslogd, bgpd,
relayd, etc etc.  Other sockopts still require specific pledges.
Tested by bluhm.

sys/kern/kern_pledge.c
sys/kern/uipc_syscalls.c
sys/sys/pledge.h

index 7bff183..4c8dae3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_pledge.c,v 1.57 2015/10/19 16:20:56 deraadt Exp $        */
+/*     $OpenBSD: kern_pledge.c,v 1.58 2015/10/20 01:44:00 deraadt Exp $        */
 
 /*
  * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
@@ -87,6 +87,9 @@ const u_int pledge_syscalls[SYS_MAXSYSCALL] = {
        [SYS_sysctl] = PLEDGE_SELF,     /* read-only; narrow subset */
        [SYS_adjtime] = PLEDGE_SELF,    /* read-only */
 
+       [SYS_setsockopt] = PLEDGE_SELF, /* white list */
+       [SYS_getsockopt] = PLEDGE_SELF,
+
        [SYS_fchdir] = PLEDGE_SELF,     /* careful of directory fd inside jails */
 
        /* needed by threaded programs */
@@ -242,8 +245,6 @@ const u_int pledge_syscalls[SYS_MAXSYSCALL] = {
        [SYS_accept] = PLEDGE_INET | PLEDGE_UNIX,
        [SYS_getpeername] = PLEDGE_INET | PLEDGE_UNIX,
        [SYS_getsockname] = PLEDGE_INET | PLEDGE_UNIX,
-       [SYS_setsockopt] = PLEDGE_INET | PLEDGE_UNIX,
-       [SYS_getsockopt] = PLEDGE_INET | PLEDGE_UNIX,
 
        [SYS_flock] = PLEDGE_FLOCK | PLEDGE_YP_ACTIVE,
 };
@@ -1057,12 +1058,35 @@ pledge_ioctl_check(struct proc *p, long com, void *v)
 }
 
 int
-pledge_setsockopt_check(struct proc *p, int level, int optname)
+pledge_sockopt_check(struct proc *p, int level, int optname)
 {
        if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
                return (0);
 
-       /* common case for PLEDGE_UNIX and PLEDGE_INET */
+       /* Always allow these, which are too common to reject */
+       switch (level) {
+       case SOL_SOCKET:
+               switch (optname) {
+               case SO_RCVBUF:
+                       return 0;
+               }
+               break;
+       }
+
+       if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX|PLEDGE_DNS)) == 0)
+               return (EPERM);
+       /* In use by some service libraries */
+       switch (level) {
+       case SOL_SOCKET:
+               switch (optname) {
+               case SO_TIMESTAMP:
+                       return 0;
+               }
+               break;
+       }
+
+       if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX)) == 0)
+               return (EPERM);
        switch (level) {
        case SOL_SOCKET:
                switch (optname) {
@@ -1074,7 +1098,6 @@ pledge_setsockopt_check(struct proc *p, int level, int optname)
 
        if ((p->p_p->ps_pledge & PLEDGE_INET) == 0)
                return (EPERM);
-
        switch (level) {
        case IPPROTO_TCP:
                switch (optname) {
index b80c055..c95a77a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uipc_syscalls.c,v 1.115 2015/10/18 20:15:10 deraadt Exp $     */
+/*     $OpenBSD: uipc_syscalls.c,v 1.116 2015/10/20 01:44:00 deraadt Exp $     */
 /*     $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $      */
 
 /*
@@ -930,7 +930,7 @@ sys_setsockopt(struct proc *p, void *v, register_t *retval)
                error = EINVAL;
                goto bad;
        }
-       if (pledge_setsockopt_check(p, SCARG(uap, level), SCARG(uap, name))) {
+       if (pledge_sockopt_check(p, SCARG(uap, level), SCARG(uap, name))) {
                error = pledge_fail(p, EPERM, PLEDGE_INET);
                goto bad;
        }
@@ -985,6 +985,10 @@ sys_getsockopt(struct proc *p, void *v, register_t *retval)
 
        if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
                return (error);
+       if (pledge_sockopt_check(p, SCARG(uap, level), SCARG(uap, name))) {
+               error = pledge_fail(p, EPERM, PLEDGE_INET);
+               goto out;
+       }
        if (isdnssocket((struct socket *)fp->f_data)) {
                error = EINVAL;
                goto out;
index 67af2b6..68b0ca1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pledge.h,v 1.7 2015/10/18 20:15:10 deraadt Exp $      */
+/*     $OpenBSD: pledge.h,v 1.8 2015/10/20 01:44:00 deraadt Exp $      */
 
 /*
  * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
@@ -69,7 +69,7 @@ int   pledge_adjtime_check(struct proc *p, const void *v);
 int    pledge_recvit_check(struct proc *p, const void *from);
 int    pledge_sendit_check(struct proc *p, const void *to);
 int    pledge_socket_check(struct proc *p, int domain);
-int    pledge_setsockopt_check(struct proc *p, int level, int optname);
+int    pledge_sockopt_check(struct proc *p, int level, int optname);
 int    pledge_dns_check(struct proc *p, in_port_t port);
 int    pledge_ioctl_check(struct proc *p, long com, void *);
 int    pledge_flock_check(struct proc *p);