-/* $OpenBSD: kern_pledge.c,v 1.48 2015/10/17 23:50:04 deraadt Exp $ */
+/* $OpenBSD: kern_pledge.c,v 1.49 2015/10/18 00:04:43 deraadt Exp $ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/filedesc.h>
+#include <sys/socketvar.h>
#include <sys/vnode.h>
#include <sys/mbuf.h>
#include <sys/sysctl.h>
[SYS_socketpair] = PLEDGE_RW,
[SYS_getdents] = PLEDGE_RW,
- [SYS_sendto] = PLEDGE_RW | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
+ [SYS_sendto] = PLEDGE_RW | PLEDGE_YP_ACTIVE,
[SYS_sendmsg] = PLEDGE_RW,
[SYS_recvmsg] = PLEDGE_RW,
- [SYS_recvfrom] = PLEDGE_RW | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
+ [SYS_recvfrom] = PLEDGE_RW | PLEDGE_YP_ACTIVE,
[SYS_fork] = PLEDGE_PROC,
[SYS_vfork] = PLEDGE_PROC,
[SYS_lchown] = PLEDGE_FATTR,
[SYS_fchown] = PLEDGE_FATTR,
- [SYS_socket] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
- [SYS_connect] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS_ACTIVE | PLEDGE_YP_ACTIVE,
+ /* XXX remove PLEDGE_DNS from socket/connect in 1 week */
+ [SYS_socket] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YP_ACTIVE,
+ [SYS_connect] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS | PLEDGE_YP_ACTIVE,
+
+ [SYS_dnssocket] = PLEDGE_DNS,
+ [SYS_dnsconnect] = PLEDGE_DNS,
[SYS_listen] = PLEDGE_INET | PLEDGE_UNIX,
[SYS_bind] = PLEDGE_INET | PLEDGE_UNIX,
{ "tmppath", PLEDGE_SELF | PLEDGE_RW | PLEDGE_TMPPATH },
{ "inet", PLEDGE_SELF | PLEDGE_RW | PLEDGE_INET },
{ "unix", PLEDGE_SELF | PLEDGE_RW | PLEDGE_UNIX },
- { "dns", PLEDGE_SELF | PLEDGE_MALLOC | PLEDGE_DNSPATH },
+ { "dns", PLEDGE_SELF | PLEDGE_MALLOC | PLEDGE_DNS },
{ "getpw", PLEDGE_SELF | PLEDGE_MALLOC | PLEDGE_RW | PLEDGE_GETPW },
{ "sendfd", PLEDGE_RW | PLEDGE_SENDFD },
{ "recvfd", PLEDGE_RW | PLEDGE_RECVFD },
/* DNS needs /etc/{resolv.conf,hosts,services}. */
if ((p->p_pledgenote == TMN_RPATH) &&
- (p->p_p->ps_pledge & PLEDGE_DNSPATH)) {
- if (strcmp(path, "/etc/resolv.conf") == 0) {
- p->p_pledgeafter |= TMA_DNSRESOLV;
+ (p->p_p->ps_pledge & PLEDGE_DNS)) {
+ if (strcmp(path, "/etc/resolv.conf") == 0)
return (0);
- }
if (strcmp(path, "/etc/hosts") == 0)
return (0);
if (strcmp(path, "/etc/services") == 0)
case SYS_stat:
/* DNS needs /etc/resolv.conf. */
if ((p->p_pledgenote == TMN_RPATH) &&
- (p->p_p->ps_pledge & PLEDGE_DNSPATH)) {
- if (strcmp(path, "/etc/resolv.conf") == 0) {
- p->p_pledgeafter |= TMA_DNSRESOLV;
- return (0);
- }
- }
+ (p->p_p->ps_pledge & PLEDGE_DNS) &&
+ strcmp(path, "/etc/resolv.conf") == 0)
+ return (0);
break;
}
{
if ((p->p_pledgeafter & TMA_YPLOCK) && error == 0)
atomic_setbits_int(&p->p_p->ps_pledge, PLEDGE_YP_ACTIVE | PLEDGE_INET);
- if ((p->p_pledgeafter & TMA_DNSRESOLV) && error == 0)
- atomic_setbits_int(&p->p_p->ps_pledge, PLEDGE_DNS_ACTIVE);
}
/*
{
if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
return (0);
+
if (uid != -1 && uid != p->p_ucred->cr_uid)
return (EPERM);
if (gid != -1 && !groupmember(gid, p->p_ucred))
}
int
-pledge_connect_check(struct proc *p)
+pledge_recvit_check(struct proc *p, const void *from)
{
if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
return (0);
- if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE))
- return (0); /* A port check happens inside sys_connect() */
-
if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX)))
- return (0);
- return (EPERM);
-}
-
-int
-pledge_recvfrom_check(struct proc *p, void *v)
-{
- struct sockaddr *from = v;
-
- if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
- return (0);
-
- if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) && from == NULL)
- return (0);
- if (p->p_p->ps_pledge & PLEDGE_INET)
- return (0);
- if (p->p_p->ps_pledge & PLEDGE_UNIX)
- return (0);
+ return (0); /* may use address */
if (from == NULL)
- return (0); /* behaves just like write */
+ return (0); /* behaves just like read */
return (EPERM);
}
int
-pledge_sendto_check(struct proc *p, const void *v)
+pledge_sendit_check(struct proc *p, const void *to)
{
- const struct sockaddr *to = v;
-
if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
return (0);
- if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) && to == NULL)
- return (0);
-
- if ((p->p_p->ps_pledge & PLEDGE_INET))
- return (0);
- if ((p->p_p->ps_pledge & PLEDGE_UNIX))
- return (0);
+ if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX)))
+ return (0); /* may use address */
if (to == NULL)
return (0); /* behaves just like write */
return (EPERM);
}
-int
-pledge_socket_check(struct proc *p, int domain)
-{
- if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
- return (0);
- if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX)))
- return (0);
- if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) &&
- (domain == AF_INET || domain == AF_INET6))
- return (0);
- return (EPERM);
-}
-
int
pledge_ioctl_check(struct proc *p, long com, void *v)
{
struct file *fp = v;
struct vnode *vp = NULL;
+ if (fp->f_type == DTYPE_SOCKET) {
+ struct socket *so = fp->f_data;
+
+ if (so->so_state & SS_DNS)
+ return (EINVAL);
+ }
+
if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
return (0);
if ((p->p_p->ps_pledge & PLEDGE_INET))
return (0);
- if ((p->p_p->ps_pledge & PLEDGE_DNS_ACTIVE) && port == htons(53))
+ if ((p->p_p->ps_pledge & PLEDGE_DNS) && port == htons(53))
return (0); /* Allow a DNS connect outbound */
return (EPERM);
}
{
if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
return (0);
+
if ((p->p_p->ps_pledge & PLEDGE_FLOCK))
return (0);
return (pledge_fail(p, EPERM, PLEDGE_FLOCK));
-; $OpenBSD: syscalls.master,v 1.162 2015/10/09 01:10:27 deraadt Exp $
+; $OpenBSD: syscalls.master,v 1.163 2015/10/18 00:04:43 deraadt Exp $
; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
156 OBSOL ogetdirentries
157 OBSOL statfs25
158 OBSOL fstatfs25
-159 UNIMPL
-160 UNIMPL
+159 STD { int sys_dnsconnect(int s, const struct sockaddr *name, \
+ socklen_t namelen); }
+160 STD { int sys_dnssocket(int domain, int type, int protocol); }
161 STD { int sys_getfh(const char *fname, fhandle_t *fhp); }
162 OBSOL ogetdomainname
163 OBSOL osetdomainname
-/* $OpenBSD: uipc_syscalls.c,v 1.113 2015/10/16 14:04:11 semarie Exp $ */
+/* $OpenBSD: uipc_syscalls.c,v 1.114 2015/10/18 00:04:43 deraadt Exp $ */
/* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */
/*
int copyaddrout(struct proc *, struct mbuf *, struct sockaddr *, socklen_t,
socklen_t *);
+int socketit(struct proc *p, void *v, register_t *retval, int);
+int connectit(struct proc *p, void *v, register_t *retval, int);
+
+int
+sys_dnssocket(struct proc *p, void *v, register_t *retval)
+{
+ return socketit(p, v, retval, 1);
+}
int
sys_socket(struct proc *p, void *v, register_t *retval)
+{
+ return socketit(p, v, retval, 0);
+}
+
+int
+socketit(struct proc *p, void *v, register_t *retval, int dns)
{
struct sys_socket_args /* {
syscallarg(int) domain;
struct socket *so;
struct file *fp;
int type = SCARG(uap, type);
+ int domain = SCARG(uap, domain);
int fd, error;
- if (pledge_socket_check(p, SCARG(uap, domain)))
- return (pledge_fail(p, EPERM, PLEDGE_UNIX));
+ if (dns && !(domain == AF_INET || domain == AF_INET6))
+ return (EINVAL);
fdplock(fdp);
error = falloc(p, &fp, &fd);
fp->f_data = so;
if (type & SOCK_NONBLOCK)
(*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&type, p);
+ if (dns)
+ so->so_state |= SS_DNS;
FILE_SET_MATURE(fp, p);
*retval = fd;
}
return (error);
}
+static inline int
+isdnssocket(struct socket *so)
+{
+ return (so->so_state & SS_DNS);
+}
+
+
/* ARGSUSED */
int
sys_bind(struct proc *p, void *v, register_t *retval)
if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
return (error);
+ if (isdnssocket((struct socket *)fp->f_data)) {
+ FRELE(fp, p);
+ return (EINVAL);
+ }
error = sockargs(&nam, SCARG(uap, name), SCARG(uap, namelen),
MT_SONAME);
if (error == 0) {
return (error);
if ((error = getsock(p, sock, &fp)) != 0)
return (error);
+ if (isdnssocket((struct socket *)fp->f_data)) {
+ error = EINVAL;
+ goto bad;
+ }
headfp = fp;
s = splsoftnet();
head = fp->f_data;
return (error);
}
+/* ARGSUSED */
+int
+sys_dnsconnect(struct proc *p, void *v, register_t *retval)
+{
+ return connectit(p, v, retval, 1);
+}
+
/* ARGSUSED */
int
sys_connect(struct proc *p, void *v, register_t *retval)
+{
+ return connectit(p, v, retval, 0);
+}
+
+int
+connectit(struct proc *p, void *v, register_t *retval, int dns)
{
struct sys_connect_args /* {
syscallarg(int) s;
struct mbuf *nam = NULL;
int error, s;
- if (pledge_connect_check(p))
- return (pledge_fail(p, EPERM, PLEDGE_UNIX));
-
if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
return (error);
so = fp->f_data;
+ if ((dns && !isdnssocket(so)) || (!dns && isdnssocket(so))) {
+ FRELE(fp, p);
+ return EINVAL;
+ }
+
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
FRELE(fp, p);
return (EALREADY);
struct msghdr msg;
struct iovec aiov;
- if (pledge_sendto_check(p, SCARG(uap, to)))
- return (pledge_fail(p, EPERM, PLEDGE_UNIX));
-
msg.msg_name = (caddr_t)SCARG(uap, to);
msg.msg_namelen = SCARG(uap, tolen);
msg.msg_iov = &aiov;
ktrmsghdr(p, &msg);
#endif
- if (pledge_sendto_check(p, msg.msg_name))
- return (pledge_fail(p, EPERM, PLEDGE_UNIX));
-
if (msg.msg_iovlen > IOV_MAX)
return (EMSGSIZE);
if (msg.msg_iovlen > UIO_SMALLIOV)
if ((error = getsock(p, s, &fp)) != 0)
return (error);
+ if (mp->msg_name && isdnssocket((struct socket *)fp->f_data)) {
+ error = EINVAL;
+ goto bad;
+ }
+ if (pledge_sendit_check(p, mp->msg_name)) {
+ error = pledge_fail(p, EPERM, PLEDGE_RW);
+ goto bad;
+ }
+
auio.uio_iov = mp->msg_iov;
auio.uio_iovcnt = mp->msg_iovlen;
auio.uio_segflg = UIO_USERSPACE;
struct iovec aiov;
int error;
- if (pledge_recvfrom_check(p, SCARG(uap, from)))
- return (pledge_fail(p, EPERM, PLEDGE_UNIX));
-
if (SCARG(uap, fromlenaddr)) {
error = copyin(SCARG(uap, fromlenaddr),
&msg.msg_namelen, sizeof (msg.msg_namelen));
if (error)
return (error);
- if (pledge_recvfrom_check(p, msg.msg_name))
- return (pledge_fail(p, EPERM, PLEDGE_UNIX));
-
if (msg.msg_iovlen > IOV_MAX)
return (EMSGSIZE);
if (msg.msg_iovlen > UIO_SMALLIOV)
if ((error = getsock(p, s, &fp)) != 0)
return (error);
+ if (mp->msg_name && isdnssocket((struct socket *)fp->f_data)) {
+ FRELE(fp, p);
+ return (EINVAL);
+ }
+ if (pledge_recvit_check(p, mp->msg_name)) {
+ FRELE(fp, p);
+ return (pledge_fail(p, EPERM, PLEDGE_RW));
+ }
+
auio.uio_iov = mp->msg_iov;
auio.uio_iovcnt = mp->msg_iovlen;
auio.uio_segflg = UIO_USERSPACE;
struct mbuf *m = NULL;
int error;
- if (pledge_setsockopt_check(p, SCARG(uap, level), SCARG(uap, name)))
- return (pledge_fail(p, EPERM, PLEDGE_INET));
if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
return (error);
+ if (isdnssocket((struct socket *)fp->f_data)) {
+ error = EINVAL;
+ goto bad;
+ }
+ if (pledge_setsockopt_check(p, SCARG(uap, level), SCARG(uap, name))) {
+ error = pledge_fail(p, EPERM, PLEDGE_INET);
+ goto bad;
+ }
if (SCARG(uap, valsize) > MCLBYTES) {
error = EINVAL;
goto bad;
if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
return (error);
+ if (isdnssocket((struct socket *)fp->f_data)) {
+ error = EINVAL;
+ goto out;
+ }
if (SCARG(uap, val)) {
error = copyin(SCARG(uap, avalsize),
&valsize, sizeof (valsize));
-/* $OpenBSD: in_pcb.c,v 1.181 2015/10/09 01:10:27 deraadt Exp $ */
+/* $OpenBSD: in_pcb.c,v 1.182 2015/10/18 00:04:43 deraadt Exp $ */
/* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
/*
return (EADDRNOTAVAIL);
if (pledge_dns_check(p, sin->sin_port))
- return (pledge_fail(p, EPERM, PLEDGE_DNSPATH));
+ return (pledge_fail(p, EPERM, PLEDGE_DNS));
error = in_selectsrc(&ina, sin, inp->inp_moptions, &inp->inp_route,
&inp->inp_laddr, inp->inp_rtableid);
-/* $OpenBSD: in6_pcb.c,v 1.77 2015/10/15 10:27:18 vgross Exp $ */
+/* $OpenBSD: in6_pcb.c,v 1.78 2015/10/18 00:04:43 deraadt Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
return (EADDRNOTAVAIL);
if (pledge_dns_check(p, sin6->sin6_port))
- return (pledge_fail(p, EPERM, PLEDGE_DNSPATH));
+ return (pledge_fail(p, EPERM, PLEDGE_DNS));
/* reject IPv4 mapped address, we have no support for it */
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
-/* $OpenBSD: pledge.h,v 1.5 2015/10/17 04:31:07 deraadt Exp $ */
+/* $OpenBSD: pledge.h,v 1.6 2015/10/18 00:04:43 deraadt Exp $ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
#define PLEDGE_SELF 0x00000001 /* operate on own pid */
#define PLEDGE_RW 0x00000002 /* basic io operations */
#define PLEDGE_MALLOC 0x00000004 /* enough for malloc */
-#define PLEDGE_DNSPATH 0x00000008 /* access to DNS pathnames */
+#define PLEDGE_DNS 0x00000008 /* DNS services */
#define PLEDGE_RPATH 0x00000010 /* allow open for read */
#define PLEDGE_WPATH 0x00000020 /* allow open for write */
#define PLEDGE_TMPPATH 0x00000040 /* for mk*temp() */
* Not user settable. Should be moved to a seperate variable */
#define PLEDGE_USERSET 0x0fffffff
#define PLEDGE_YP_ACTIVE 0x10000000 /* YP use detected and allowed */
-#define PLEDGE_DNS_ACTIVE 0x20000000 /* DNS use detected and allowed */
int pledge_check(struct proc *, int);
int pledge_fail(struct proc *, int, int);
int pledge_sysctl_check(struct proc *p, int namelen, int *name, void *new);
int pledge_chown_check(struct proc *p, uid_t, gid_t);
int pledge_adjtime_check(struct proc *p, const void *v);
-int pledge_recvfrom_check(struct proc *p, void *from);
-int pledge_sendto_check(struct proc *p, const void *to);
-int pledge_connect_check(struct proc *p);
+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_dns_check(struct proc *p, in_port_t port);
-/* $OpenBSD: proc.h,v 1.207 2015/10/10 14:46:15 deraadt Exp $ */
+/* $OpenBSD: proc.h,v 1.208 2015/10/18 00:04:43 deraadt Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
#define TMN_COREDUMP 0x00000020
int p_pledgeafter;
#define TMA_YPLOCK 0x00000001
-#define TMA_DNSRESOLV 0x00000002
#ifndef __HAVE_MD_TCB
void *p_tcb; /* user-space thread-control-block address */
-/* $OpenBSD: socketvar.h,v 1.58 2015/01/19 19:57:59 guenther Exp $ */
+/* $OpenBSD: socketvar.h,v 1.59 2015/10/18 00:04:43 deraadt Exp $ */
/* $NetBSD: socketvar.h,v 1.18 1996/02/09 18:25:38 christos Exp $ */
/*-
#define SS_ASYNC 0x200 /* async i/o notify */
#define SS_CONNECTOUT 0x1000 /* connect, not accept, at this end */
#define SS_ISSENDING 0x2000 /* hint for lower layer */
+#define SS_DNS 0x4000 /* created using dnssocket() */
#ifdef _KERNEL
/*