summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2015-10-20 18:04:04 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2015-10-20 18:04:04 +0000
commit000a9319a0343f787afb5a159cdbed27401eb4b3 (patch)
tree977dcccd944b4ba7a68afaf86653154d1a55116a /sys
parent07d23236a7389372d09010a4ecdaaf066e1c9512 (diff)
At guenther's suggestion replace dnssocket() with a SOCK_DNS flag on
socket(). Without pledge, all other socket behaviours become permitted, except this one case: connect/send* only works to *:53. In pledge mode, a very few are further restricted. Some backwards compatibility for the dnssocket/dnsconnect calls will remain in the tree temporarily so that people can build through the transition. ok tedu guenther semarie
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_pledge.c39
-rw-r--r--sys/kern/uipc_syscalls.c117
-rw-r--r--sys/netinet/in_pcb.c6
-rw-r--r--sys/netinet6/in6_pcb.c6
-rw-r--r--sys/sys/pledge.h5
-rw-r--r--sys/sys/socket.h5
6 files changed, 84 insertions, 94 deletions
diff --git a/sys/kern/kern_pledge.c b/sys/kern/kern_pledge.c
index 1eab94e4267..a5c996e94af 100644
--- a/sys/kern/kern_pledge.c
+++ b/sys/kern/kern_pledge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_pledge.c,v 1.61 2015/10/20 17:44:48 reyk Exp $ */
+/* $OpenBSD: kern_pledge.c,v 1.62 2015/10/20 18:04:03 deraadt Exp $ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
@@ -233,19 +233,19 @@ const u_int pledge_syscalls[SYS_MAXSYSCALL] = {
[SYS_lchown] = PLEDGE_FATTR,
[SYS_fchown] = PLEDGE_FATTR,
- /* 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_bind] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS,
+ [SYS_getsockname] = PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS,
+ /* XXX remove this, and the code in uipc_syscalls.c */
[SYS_dnssocket] = PLEDGE_DNS,
[SYS_dnsconnect] = PLEDGE_DNS,
[SYS_listen] = PLEDGE_INET | PLEDGE_UNIX,
- [SYS_bind] = PLEDGE_INET | PLEDGE_UNIX,
[SYS_accept4] = PLEDGE_INET | PLEDGE_UNIX,
[SYS_accept] = PLEDGE_INET | PLEDGE_UNIX,
[SYS_getpeername] = PLEDGE_INET | PLEDGE_UNIX,
- [SYS_getsockname] = PLEDGE_INET | PLEDGE_UNIX,
[SYS_flock] = PLEDGE_FLOCK | PLEDGE_YP_ACTIVE,
};
@@ -936,25 +936,12 @@ pledge_adjtime_check(struct proc *p, const void *v)
}
int
-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_INET | PLEDGE_UNIX)))
- return (0); /* may use address */
- if (from == NULL)
- return (0); /* behaves just like read */
- return (EPERM);
-}
-
-int
pledge_sendit_check(struct proc *p, const void *to)
{
if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
return (0);
- if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX)))
+ if ((p->p_p->ps_pledge & (PLEDGE_INET | PLEDGE_UNIX | PLEDGE_DNS)))
return (0); /* may use address */
if (to == NULL)
return (0); /* behaves just like write */
@@ -1103,7 +1090,7 @@ pledge_sockopt_check(struct proc *p, int level, int optname)
}
if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX|PLEDGE_DNS)) == 0)
- return (EPERM);
+ return (EINVAL);
/* In use by some service libraries */
switch (level) {
case SOL_SOCKET:
@@ -1115,18 +1102,18 @@ pledge_sockopt_check(struct proc *p, int level, int optname)
}
if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX)) == 0)
- return (EPERM);
+ return (EINVAL);
switch (level) {
case SOL_SOCKET:
switch (optname) {
case SO_RTABLE:
- return (EPERM);
+ return (EINVAL);
}
return (0);
}
if ((p->p_p->ps_pledge & PLEDGE_INET) == 0)
- return (EPERM);
+ return (EINVAL);
switch (level) {
case IPPROTO_TCP:
switch (optname) {
@@ -1183,15 +1170,15 @@ pledge_sockopt_check(struct proc *p, int level, int optname)
}
int
-pledge_dns_check(struct proc *p, in_port_t port)
+pledge_socket_check(struct proc *p, int dns)
{
if ((p->p_p->ps_flags & PS_PLEDGE) == 0)
return (0);
- if ((p->p_p->ps_pledge & PLEDGE_INET))
+ if (dns && (p->p_p->ps_pledge & PLEDGE_DNS))
+ return (0);
+ if ((p->p_p->ps_pledge & (PLEDGE_INET|PLEDGE_UNIX|PLEDGE_YP_ACTIVE)))
return (0);
- if ((p->p_p->ps_pledge & PLEDGE_DNS) && port == htons(53))
- return (0); /* Allow a DNS connect outbound */
return (EPERM);
}
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index c95a77afea6..cbebf61d8f7 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_syscalls.c,v 1.116 2015/10/20 01:44:00 deraadt Exp $ */
+/* $OpenBSD: uipc_syscalls.c,v 1.117 2015/10/20 18:04:03 deraadt Exp $ */
/* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */
/*
@@ -55,6 +55,8 @@
#include <sys/mount.h>
#include <sys/syscallargs.h>
+#include <sys/domain.h>
+#include <netinet/in.h>
#include <net/route.h>
/*
@@ -64,23 +66,23 @@ extern struct fileops socketops;
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);
+/* XXX dnssocket() - temporary backwards compat */
int
sys_dnssocket(struct proc *p, void *v, register_t *retval)
{
- return socketit(p, v, retval, 1);
-}
+ struct sys_socket_args /* {
+ syscallarg(int) domain;
+ syscallarg(int) type;
+ syscallarg(int) protocol;
+ } */ *uap = v;
-int
-sys_socket(struct proc *p, void *v, register_t *retval)
-{
- return socketit(p, v, retval, 0);
+ SCARG(uap, type) |= SOCK_DNS;
+ return sys_socket(p, v, retval);
}
int
-socketit(struct proc *p, void *v, register_t *retval, int dns)
+sys_socket(struct proc *p, void *v, register_t *retval)
{
struct sys_socket_args /* {
syscallarg(int) domain;
@@ -94,8 +96,11 @@ socketit(struct proc *p, void *v, register_t *retval, int dns)
int domain = SCARG(uap, domain);
int fd, error;
- if (dns && !(domain == AF_INET || domain == AF_INET6))
+ if ((type & SOCK_DNS) && !(domain == AF_INET || domain == AF_INET6))
return (EINVAL);
+ error = pledge_socket_check(p, type & SOCK_DNS);
+ if (error)
+ return (pledge_fail(p, EPERM, PLEDGE_DNS));
fdplock(fdp);
error = falloc(p, &fp, &fd);
@@ -109,7 +114,7 @@ socketit(struct proc *p, void *v, register_t *retval, int dns)
fp->f_type = DTYPE_SOCKET;
fp->f_ops = &socketops;
error = socreate(SCARG(uap, domain), &so,
- type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK), SCARG(uap, protocol));
+ type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK | SOCK_DNS), SCARG(uap, protocol));
if (error) {
fdplock(fdp);
fdremove(fdp, fd);
@@ -119,7 +124,7 @@ socketit(struct proc *p, void *v, register_t *retval, int dns)
fp->f_data = so;
if (type & SOCK_NONBLOCK)
(*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&type, p);
- if (dns)
+ if (type & SOCK_DNS)
so->so_state |= SS_DNS;
FILE_SET_MATURE(fp, p);
*retval = fd;
@@ -134,6 +139,27 @@ isdnssocket(struct socket *so)
return (so->so_state & SS_DNS);
}
+/* For SS_DNS sockets, only allow port DNS (port 53) */
+static int
+dns_portcheck(struct proc *p, struct socket *so, void *nam, size_t namelen)
+{
+ switch (so->so_proto->pr_domain->dom_family) {
+ case AF_INET:
+ if (namelen < sizeof(struct sockaddr_in))
+ break;
+ if (((struct sockaddr_in *)nam)->sin_port == htons(53))
+ return (0);
+ break;
+ case AF_INET6:
+ if (namelen < sizeof(struct sockaddr_in6))
+ break;
+ if (((struct sockaddr_in6 *)nam)->sin6_port == htons(53))
+ return (0);
+ }
+ if (p->p_p->ps_flags & PS_PLEDGE)
+ return (pledge_fail(p, EPERM, PLEDGE_DNS));
+ return (EINVAL);
+}
/* ARGSUSED */
int
@@ -150,10 +176,6 @@ 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) {
@@ -337,23 +359,17 @@ bad:
return (error);
}
-/* ARGSUSED */
+/* XXX dnsconnect() - temporary backwards compat */
int
sys_dnsconnect(struct proc *p, void *v, register_t *retval)
{
- return connectit(p, v, retval, 1);
+ return sys_connect(p, v, retval);
}
/* 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;
syscallarg(const struct sockaddr *) name;
@@ -367,11 +383,6 @@ connectit(struct proc *p, void *v, register_t *retval, int dns)
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);
@@ -384,6 +395,16 @@ connectit(struct proc *p, void *v, register_t *retval, int dns)
if (KTRPOINT(p, KTR_STRUCT))
ktrsockaddr(p, mtod(nam, caddr_t), SCARG(uap, namelen));
#endif
+
+ if (isdnssocket(so)) {
+ error = dns_portcheck(p, so, mtod(nam, void *), nam->m_len);
+ if (error) {
+ FRELE(fp, p);
+ m_freem(nam);
+ return (error);
+ }
+ }
+
error = soconnect(so, nam);
if (error)
goto bad;
@@ -572,6 +593,7 @@ sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize)
struct iovec *iov;
int i;
struct mbuf *to, *control;
+ struct socket *so;
size_t len;
int error;
#ifdef KTRACE
@@ -583,9 +605,12 @@ sendit(struct proc *p, int s, struct msghdr *mp, int flags, register_t *retsize)
if ((error = getsock(p, s, &fp)) != 0)
return (error);
- if (mp->msg_name && isdnssocket((struct socket *)fp->f_data)) {
- error = EINVAL;
- goto bad;
+ so = fp->f_data;
+
+ if (mp->msg_name && mp->msg_namelen && isdnssocket(so)) {
+ error = dns_portcheck(p, so, mp->msg_name, mp->msg_namelen);
+ if (error)
+ return (error);
}
if (pledge_sendit_check(p, mp->msg_name)) {
error = pledge_fail(p, EPERM, PLEDGE_RW);
@@ -771,14 +796,6 @@ recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp,
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;
@@ -926,12 +943,9 @@ sys_setsockopt(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)) {
- error = EINVAL;
- goto bad;
- }
- if (pledge_sockopt_check(p, SCARG(uap, level), SCARG(uap, name))) {
- error = pledge_fail(p, EPERM, PLEDGE_INET);
+ error = pledge_sockopt_check(p, SCARG(uap, level), SCARG(uap, name));
+ if (error) {
+ error = pledge_fail(p, error, PLEDGE_INET);
goto bad;
}
if (SCARG(uap, valsize) > MCLBYTES) {
@@ -985,12 +999,9 @@ 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;
+ error = pledge_sockopt_check(p, SCARG(uap, level), SCARG(uap, name));
+ if (error) {
+ error = pledge_fail(p, error, PLEDGE_INET);
goto out;
}
if (SCARG(uap, val)) {
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index b7aa013330a..1d0ca68f174 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.c,v 1.184 2015/10/19 12:10:05 mpi Exp $ */
+/* $OpenBSD: in_pcb.c,v 1.185 2015/10/20 18:04:03 deraadt Exp $ */
/* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
/*
@@ -418,7 +418,6 @@ in_pcbconnect(struct inpcb *inp, struct mbuf *nam)
{
struct in_addr *ina = NULL;
struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
- struct proc *p = curproc;
int error;
#ifdef INET6
@@ -435,9 +434,6 @@ in_pcbconnect(struct inpcb *inp, struct mbuf *nam)
if (sin->sin_port == 0)
return (EADDRNOTAVAIL);
- if (pledge_dns_check(p, sin->sin_port))
- return (pledge_fail(p, EPERM, PLEDGE_DNS));
-
error = in_selectsrc(&ina, sin, inp->inp_moptions, &inp->inp_route,
&inp->inp_laddr, inp->inp_rtableid);
if (error)
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 2f6d4c0fdf4..95ae08f8a90 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in6_pcb.c,v 1.80 2015/10/19 12:11:28 mpi Exp $ */
+/* $OpenBSD: in6_pcb.c,v 1.81 2015/10/20 18:04:03 deraadt Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -370,7 +370,6 @@ in6_pcbconnect(struct inpcb *inp, struct mbuf *nam)
struct in6_addr *in6a = NULL;
struct sockaddr_in6 *sin6 = mtod(nam, struct sockaddr_in6 *);
struct ifnet *ifp = NULL; /* outgoing interface */
- struct proc *p = curproc;
int error = 0;
struct sockaddr_in6 tmp;
@@ -383,9 +382,6 @@ in6_pcbconnect(struct inpcb *inp, struct mbuf *nam)
if (sin6->sin6_port == 0)
return (EADDRNOTAVAIL);
- if (pledge_dns_check(p, sin6->sin6_port))
- 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))
return EADDRNOTAVAIL;
diff --git a/sys/sys/pledge.h b/sys/sys/pledge.h
index 68b0ca13853..a241305980a 100644
--- a/sys/sys/pledge.h
+++ b/sys/sys/pledge.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pledge.h,v 1.8 2015/10/20 01:44:00 deraadt Exp $ */
+/* $OpenBSD: pledge.h,v 1.9 2015/10/20 18:04:03 deraadt Exp $ */
/*
* Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org>
@@ -66,11 +66,10 @@ int pledge_recvfd_check(struct proc *p, struct file *);
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_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_sockopt_check(struct proc *p, int level, int optname);
-int pledge_dns_check(struct proc *p, in_port_t port);
+int pledge_socket_check(struct proc *p, int dns);
int pledge_ioctl_check(struct proc *p, long com, void *);
int pledge_flock_check(struct proc *p);
diff --git a/sys/sys/socket.h b/sys/sys/socket.h
index 8ecfaf34d8c..a0b01ba7c8a 100644
--- a/sys/sys/socket.h
+++ b/sys/sys/socket.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: socket.h,v 1.88 2015/07/17 15:23:59 guenther Exp $ */
+/* $OpenBSD: socket.h,v 1.89 2015/10/20 18:04:03 deraadt Exp $ */
/* $NetBSD: socket.h,v 1.14 1996/02/09 18:25:36 christos Exp $ */
/*
@@ -78,10 +78,11 @@ typedef __sa_family_t sa_family_t; /* sockaddr address family type */
#if __BSD_VISIBLE
#define SOCK_CLOEXEC 0x8000 /* set FD_CLOEXEC */
#define SOCK_NONBLOCK 0x4000 /* set O_NONBLOCK */
-#endif
#ifdef _KERNEL
#define SOCK_NONBLOCK_INHERIT 0x2000 /* inherit O_NONBLOCK from listener */
#endif
+#define SOCK_DNS 0x1000 /* set SS_DNS */
+#endif /* __BSD_VISIBLE */
/*
* Option flags per-socket.