diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_pledge.c | 34 | ||||
-rw-r--r-- | sys/kern/uipc_syscalls.c | 44 | ||||
-rw-r--r-- | sys/sys/pledge.h | 4 |
3 files changed, 64 insertions, 18 deletions
diff --git a/sys/kern/kern_pledge.c b/sys/kern/kern_pledge.c index 5a1b5d74c60..e74a3c1c0bc 100644 --- a/sys/kern/kern_pledge.c +++ b/sys/kern/kern_pledge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_pledge.c,v 1.114 2015/11/17 15:03:53 sthen Exp $ */ +/* $OpenBSD: kern_pledge.c,v 1.115 2015/11/18 08:24:22 semarie Exp $ */ /* * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org> @@ -1317,16 +1317,32 @@ pledge_sockopt(struct proc *p, int set, int level, int optname) } int -pledge_socket(struct proc *p, int dns) +pledge_socket(struct proc *p, int domain, int state) { - if ((p->p_p->ps_flags & PS_PLEDGE) == 0) - return (0); + if (! ISSET(p->p_p->ps_flags, PS_PLEDGE)) + return 0; - if (dns && (p->p_p->ps_pledge & PLEDGE_DNS)) - return (0); - if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX|PLEDGE_YPACTIVE))) - return (0); - return pledge_fail(p, EPERM, dns ? PLEDGE_DNS : PLEDGE_INET); + if (ISSET(state, SS_DNS)) { + if (ISSET(p->p_p->ps_pledge, PLEDGE_DNS)) + return 0; + return pledge_fail(p, EPERM, PLEDGE_DNS); + } + + switch (domain) { + case AF_INET: + case AF_INET6: + if (ISSET(p->p_p->ps_pledge, PLEDGE_INET) || + ISSET(p->p_p->ps_pledge, PLEDGE_YPACTIVE)) + return 0; + return pledge_fail(p, EPERM, PLEDGE_INET); + + case AF_UNIX: + if (ISSET(p->p_p->ps_pledge, PLEDGE_UNIX)) + return 0; + return pledge_fail(p, EPERM, PLEDGE_UNIX); + } + + return pledge_fail(p, EINVAL, PLEDGE_INET); } int diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index e2866a1a363..122d51f2a0a 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_syscalls.c,v 1.124 2015/11/08 23:23:12 tedu Exp $ */ +/* $OpenBSD: uipc_syscalls.c,v 1.125 2015/11/18 08:24:22 semarie Exp $ */ /* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */ /* @@ -80,11 +80,14 @@ sys_socket(struct proc *p, void *v, register_t *retval) struct file *fp; int type = SCARG(uap, type); int domain = SCARG(uap, domain); - int fd, error; + int fd, error, ss = 0; if ((type & SOCK_DNS) && !(domain == AF_INET || domain == AF_INET6)) return (EINVAL); - error = pledge_socket(p, type & SOCK_DNS); + + if (ISSET(type, SOCK_DNS)) + ss |= SS_DNS; + error = pledge_socket(p, domain, ss); if (error) return (error); @@ -110,8 +113,7 @@ sys_socket(struct proc *p, void *v, register_t *retval) fp->f_data = so; if (type & SOCK_NONBLOCK) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&type, p); - if (type & SOCK_DNS) - so->so_state |= SS_DNS; + so->so_state |= ss; FILE_SET_MATURE(fp, p); *retval = fd; } @@ -158,10 +160,16 @@ sys_bind(struct proc *p, void *v, register_t *retval) } */ *uap = v; struct file *fp; struct mbuf *nam; + struct socket *so; int error; if ((error = getsock(p, SCARG(uap, s), &fp)) != 0) return (error); + so = fp->f_data; + error = pledge_socket(p, so->so_proto->pr_domain->dom_family, + so->so_state); + if (error) + return (error); error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen), MT_SONAME); if (error == 0) { @@ -169,7 +177,7 @@ sys_bind(struct proc *p, void *v, register_t *retval) if (KTRPOINT(p, KTR_STRUCT)) ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen)); #endif - error = sobind(fp->f_data, nam, p); + error = sobind(so, nam, p); m_freem(nam); } FRELE(fp, p); @@ -185,11 +193,17 @@ sys_listen(struct proc *p, void *v, register_t *retval) syscallarg(int) backlog; } */ *uap = v; struct file *fp; + struct socket *so; int error; if ((error = getsock(p, SCARG(uap, s), &fp)) != 0) return (error); - error = solisten(fp->f_data, SCARG(uap, backlog)); + so = fp->f_data; + error = pledge_socket(p, so->so_proto->pr_domain->dom_family, + so->so_state); + if (error) + return (error); + error = solisten(so, SCARG(uap, backlog)); FRELE(fp, p); return (error); } @@ -245,6 +259,10 @@ doaccept(struct proc *p, int sock, struct sockaddr *name, socklen_t *anamelen, headfp = fp; head = fp->f_data; + error = pledge_socket(p, head->so_proto->pr_domain->dom_family, + head->so_state); + if (error) + goto bad; if (isdnssocket((struct socket *)fp->f_data)) { error = EINVAL; goto bad; @@ -372,6 +390,10 @@ sys_connect(struct proc *p, void *v, register_t *retval) MT_SONAME); if (error) goto bad; + error = pledge_socket(p, so->so_proto->pr_domain->dom_family, + so->so_state); + if (error) + goto bad; #ifdef KTRACE if (KTRPOINT(p, KTR_STRUCT)) ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen)); @@ -1029,6 +1051,10 @@ sys_getsockname(struct proc *p, void *v, register_t *retval) if (error) goto bad; so = fp->f_data; + error = pledge_socket(p, so->so_proto->pr_domain->dom_family, + so->so_state); + if (error) + goto bad; m = m_getclr(M_WAIT, MT_SONAME); error = (*so->so_proto->pr_usrreq)(so, PRU_SOCKADDR, 0, m, 0, p); if (error) @@ -1062,6 +1088,10 @@ sys_getpeername(struct proc *p, void *v, register_t *retval) if ((error = getsock(p, SCARG(uap, fdes), &fp)) != 0) return (error); so = fp->f_data; + error = pledge_socket(p, so->so_proto->pr_domain->dom_family, + so->so_state); + if (error) + return (error); if ((so->so_state & SS_ISCONNECTED) == 0) { FRELE(fp, p); return (ENOTCONN); diff --git a/sys/sys/pledge.h b/sys/sys/pledge.h index 94766c745a6..f0bc6e700c0 100644 --- a/sys/sys/pledge.h +++ b/sys/sys/pledge.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pledge.h,v 1.18 2015/11/04 21:24:23 tedu Exp $ */ +/* $OpenBSD: pledge.h,v 1.19 2015/11/18 08:24:22 semarie Exp $ */ /* * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org> @@ -106,7 +106,7 @@ int pledge_chown(struct proc *p, uid_t, gid_t); int pledge_adjtime(struct proc *p, const void *v); int pledge_sendit(struct proc *p, const void *to); int pledge_sockopt(struct proc *p, int set, int level, int optname); -int pledge_socket(struct proc *p, int dns); +int pledge_socket(struct proc *p, int domain, int state); int pledge_ioctl(struct proc *p, long com, struct file *); int pledge_flock(struct proc *p); int pledge_fcntl(struct proc *p, int cmd); |