summaryrefslogtreecommitdiffstats
path: root/sys/netinet6
diff options
context:
space:
mode:
authorbz <bz@FreeBSD.org>2008-01-24 08:25:59 +0000
committerbz <bz@FreeBSD.org>2008-01-24 08:25:59 +0000
commit1c376286e046dbe30549b705bd310d6218ffc824 (patch)
tree54dfe6089b6177f2bd726f05233e0c1a76433c3e /sys/netinet6
parentca561e0217663df7e35502550d299ef5f818e4e8 (diff)
downloadFreeBSD-src-1c376286e046dbe30549b705bd310d6218ffc824.zip
FreeBSD-src-1c376286e046dbe30549b705bd310d6218ffc824.tar.gz
Replace the last susers calls in netinet6/ with privilege checks.
Introduce a new privilege allowing to set certain IP header options (hop-by-hop, routing headers). Leave a few comments to be addressed later. Reviewed by: rwatson (older version, before addressing his comments)
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/in6.c20
-rw-r--r--sys/netinet6/ip6_output.c119
-rw-r--r--sys/netinet6/ip6_var.h2
-rw-r--r--sys/netinet6/raw_ip6.c11
-rw-r--r--sys/netinet6/udp6_usrreq.c7
5 files changed, 91 insertions, 68 deletions
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 450b130..bcb634f 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -401,13 +401,16 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
switch (cmd) {
case SIOCALIFADDR:
+ if (td != NULL) {
+ error = priv_check(td, PRIV_NET_ADDIFADDR);
+ if (error)
+ return (error);
+ }
+ return in6_lifaddr_ioctl(so, cmd, data, ifp, td);
+
case SIOCDLIFADDR:
- /*
- * XXXRW: Is this checked at another layer? What priv to use
- * here?
- */
if (td != NULL) {
- error = suser(td);
+ error = priv_check(td, PRIV_NET_DELIFADDR);
if (error)
return (error);
}
@@ -500,12 +503,9 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6))
return (EAFNOSUPPORT);
- /*
- * XXXRW: Is this checked at another layer? What priv to use
- * here?
- */
if (td != NULL) {
- error = suser(td);
+ error = priv_check(td, (cmd == SIOCDIFADDR_IN6) ?
+ PRIV_NET_DELIFADDR : PRIV_NET_ADDIFADDR);
if (error)
return (error);
}
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index a79363e..4b6c52e 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -114,12 +114,12 @@ struct ip6_exthdrs {
};
static int ip6_pcbopt __P((int, u_char *, int, struct ip6_pktopts **,
- int, int));
+ struct ucred *, int));
static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
struct socket *, struct sockopt *));
static int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *);
-static int ip6_setpktopt __P((int, u_char *, int, struct ip6_pktopts *, int,
- int, int, int));
+static int ip6_setpktopt __P((int, u_char *, int, struct ip6_pktopts *,
+ struct ucred *, int, int, int));
static int ip6_setmoptions(int, struct ip6_moptions **, struct mbuf *);
static int ip6_getmoptions(int, struct ip6_moptions *, struct mbuf **);
@@ -1346,7 +1346,7 @@ ip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro,
int
ip6_ctloutput(struct socket *so, struct sockopt *sopt)
{
- int privileged, optdatalen, uproto;
+ int optdatalen, uproto;
void *optdata;
struct inpcb *in6p = sotoinpcb(so);
int error, optval;
@@ -1365,7 +1365,6 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
}
error = optval = 0;
- privileged = (td == 0 || suser(td)) ? 0 : 1;
uproto = (int)so->so_proto->pr_protocol;
if (level == IPPROTO_IPV6) {
@@ -1408,9 +1407,11 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
case IPV6_RECVHOPOPTS:
case IPV6_RECVDSTOPTS:
case IPV6_RECVRTHDRDSTOPTS:
- if (!privileged) {
- error = EPERM;
- break;
+ if (td != NULL) {
+ error = priv_check(td,
+ PRIV_NETINET_SETHDROPTS);
+ if (error)
+ break;
}
/* FALLTHROUGH */
case IPV6_UNICAST_HOPS:
@@ -1482,10 +1483,9 @@ do { \
}
optp = &in6p->in6p_outputopts;
error = ip6_pcbopt(IPV6_HOPLIMIT,
- (u_char *)&optval,
- sizeof(optval),
- optp,
- privileged, uproto);
+ (u_char *)&optval, sizeof(optval),
+ optp, (td != NULL) ? td->td_ucred :
+ NULL, uproto);
break;
}
@@ -1597,10 +1597,9 @@ do { \
struct ip6_pktopts **optp;
optp = &in6p->in6p_outputopts;
error = ip6_pcbopt(optname,
- (u_char *)&optval,
- sizeof(optval),
- optp,
- privileged, uproto);
+ (u_char *)&optval, sizeof(optval),
+ optp, (td != NULL) ? td->td_ucred :
+ NULL, uproto);
break;
}
@@ -1630,13 +1629,21 @@ do { \
* Check super-user privilege.
* See comments for IPV6_RECVHOPOPTS.
*/
- if (!privileged)
- return (EPERM);
+ if (td != NULL) {
+ error = priv_check(td,
+ PRIV_NETINET_SETHDROPTS);
+ if (error)
+ return (error);
+ }
OPTSET2292(IN6P_HOPOPTS);
break;
case IPV6_2292DSTOPTS:
- if (!privileged)
- return (EPERM);
+ if (td != NULL) {
+ error = priv_check(td,
+ PRIV_NETINET_SETHDROPTS);
+ if (error)
+ return (error);
+ }
OPTSET2292(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */
break;
case IPV6_2292RTHDR:
@@ -1675,9 +1682,9 @@ do { \
optlen = sopt->sopt_valsize;
optbuf = optbuf_storage;
optp = &in6p->in6p_outputopts;
- error = ip6_pcbopt(optname,
- optbuf, optlen,
- optp, privileged, uproto);
+ error = ip6_pcbopt(optname, optbuf, optlen,
+ optp, (td != NULL) ? td->td_ucred : NULL,
+ uproto);
break;
}
#undef OPTSET
@@ -1764,6 +1771,7 @@ do { \
caddr_t req = NULL;
size_t len = 0;
struct mbuf *m;
+ int priv = 0;
if ((error = soopt_getm(sopt, &m)) != 0) /* XXX */
break;
@@ -1773,8 +1781,22 @@ do { \
req = mtod(m, caddr_t);
len = m->m_len;
}
+ if (sopt->sopt_td != NULL) {
+ /*
+ * XXXRW/XXX-BZ: Would be more desirable to do
+ * this one layer down so that we only exercise
+ * privilege if it is needed.
+ */
+ error = priv_check(sopt->sopt_td,
+ PRIV_NETINET_IPSEC);
+ if (error)
+ priv = 0;
+ else
+ priv = 1;
+ } else
+ priv = 1;
error = ipsec6_set_policy(in6p, optname, req,
- len, privileged);
+ len, priv);
m_freem(m);
}
break;
@@ -2103,7 +2125,6 @@ ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m,
struct ip6_pktopts *opt = *pktopt;
int error = 0;
struct thread *td = sopt->sopt_td;
- int priv = 0;
/* turn off any old options. */
if (opt) {
@@ -2128,10 +2149,8 @@ ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m,
}
/* set options specified by user. */
- if (td && !suser(td))
- priv = 1;
- if ((error = ip6_setpktopts(m, opt, NULL, priv,
- so->so_proto->pr_protocol)) != 0) {
+ if ((error = ip6_setpktopts(m, opt, NULL, (td != NULL) ?
+ td->td_ucred : NULL, so->so_proto->pr_protocol)) != 0) {
ip6_clearpktopts(opt, -1); /* XXX: discard all options */
free(opt, M_IP6OPT);
return (error);
@@ -2157,7 +2176,7 @@ ip6_initpktopts(struct ip6_pktopts *opt)
static int
ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt,
- int priv, int uproto)
+ struct ucred *cred, int uproto)
{
struct ip6_pktopts *opt;
@@ -2168,7 +2187,7 @@ ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt,
}
opt = *pktopt;
- return (ip6_setpktopt(optname, buf, len, opt, priv, 1, 0, uproto));
+ return (ip6_setpktopt(optname, buf, len, opt, cred, 1, 0, uproto));
}
static int
@@ -2411,7 +2430,6 @@ ip6_setmoptions(int optname, struct ip6_moptions **im6op, struct mbuf *m)
struct ip6_moptions *im6o = *im6op;
struct route_in6 ro;
struct in6_multi_mship *imm;
- struct thread *td = curthread;
if (im6o == NULL) {
/*
@@ -2507,10 +2525,10 @@ ip6_setmoptions(int optname, struct ip6_moptions **im6op, struct mbuf *m)
* all multicast addresses. Only super user is allowed
* to do this.
*/
- if (suser(td)) {
- error = EACCES;
+ /* XXX-BZ might need a better PRIV_NETINET_x for this */
+ error = priv_check(curthread, PRIV_NETINET_MROUTE);
+ if (error)
break;
- }
} else if (!IN6_IS_ADDR_MULTICAST(&mreq->ipv6mr_multiaddr)) {
error = EINVAL;
break;
@@ -2769,7 +2787,7 @@ ip6_freemoptions(struct ip6_moptions *im6o)
*/
int
ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
- struct ip6_pktopts *stickyopt, int priv, int uproto)
+ struct ip6_pktopts *stickyopt, struct ucred *cred, int uproto)
{
struct cmsghdr *cm = 0;
@@ -2814,7 +2832,7 @@ ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
continue;
error = ip6_setpktopt(cm->cmsg_type, CMSG_DATA(cm),
- cm->cmsg_len - CMSG_LEN(0), opt, priv, 0, 1, uproto);
+ cm->cmsg_len - CMSG_LEN(0), opt, cred, 0, 1, uproto);
if (error)
return (error);
}
@@ -2833,9 +2851,10 @@ ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
*/
static int
ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
- int priv, int sticky, int cmsg, int uproto)
+ struct ucred *cred, int sticky, int cmsg, int uproto)
{
int minmtupolicy, preftemp;
+ int error;
if (!sticky && !cmsg) {
#ifdef DIAGNOSTIC
@@ -2977,8 +2996,12 @@ ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
case IPV6_2292NEXTHOP:
case IPV6_NEXTHOP:
- if (!priv)
- return (EPERM);
+ if (cred != NULL) {
+ error = priv_check_cred(cred,
+ PRIV_NETINET_SETHDROPTS, 0);
+ if (error)
+ return (error);
+ }
if (len == 0) { /* just remove the option */
ip6_clearpktopts(opt, IPV6_NEXTHOP);
@@ -3032,8 +3055,12 @@ ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
* options, since per-option restriction has too much
* overhead.
*/
- if (!priv)
- return (EPERM);
+ if (cred != NULL) {
+ error = priv_check_cred(cred,
+ PRIV_NETINET_SETHDROPTS, 0);
+ if (error)
+ return (error);
+ }
if (len == 0) {
ip6_clearpktopts(opt, IPV6_HOPOPTS);
@@ -3065,8 +3092,12 @@ ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
struct ip6_dest *dest, **newdest = NULL;
int destlen;
- if (!priv) /* XXX: see the comment for IPV6_HOPOPTS */
- return (EPERM);
+ if (cred != NULL) { /* XXX: see the comment for IPV6_HOPOPTS */
+ error = priv_check_cred(cred,
+ PRIV_NETINET_SETHDROPTS, 0);
+ if (error)
+ return (error);
+ }
if (len == 0) {
ip6_clearpktopts(opt, optname);
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
index 1d34bfe..65707d6 100644
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -367,7 +367,7 @@ int ip6_ctloutput __P((struct socket *, struct sockopt *));
int ip6_raw_ctloutput __P((struct socket *, struct sockopt *));
void ip6_initpktopts __P((struct ip6_pktopts *));
int ip6_setpktopts __P((struct mbuf *, struct ip6_pktopts *,
- struct ip6_pktopts *, int, int));
+ struct ip6_pktopts *, struct ucred *, int));
void ip6_clearpktopts __P((struct ip6_pktopts *, int));
struct ip6_pktopts *ip6_copypktopts __P((struct ip6_pktopts *, int));
int ip6_optlen __P((struct inpcb *));
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index e8b5aa2..30fcbea 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -324,7 +324,6 @@ rip6_output(m, va_alist)
struct ip6_pktopts opt, *optp;
struct ifnet *oifp = NULL;
int type = 0, code = 0; /* for ICMPv6 output statistics only */
- int priv = 0;
int scope_ambiguous = 0;
struct in6_addr *in6a;
va_list ap;
@@ -338,14 +337,11 @@ rip6_output(m, va_alist)
in6p = sotoin6pcb(so);
INP_LOCK(in6p);
- priv = 0;
- if (suser_cred(so->so_cred, 0) == 0)
- priv = 1;
dst = &dstsock->sin6_addr;
if (control) {
if ((error = ip6_setpktopts(control, &opt,
- in6p->in6p_outputopts, priv, so->so_proto->pr_protocol))
- != 0) {
+ in6p->in6p_outputopts, so->so_cred,
+ so->so_proto->pr_protocol)) != 0) {
goto bad;
}
optp = &opt;
@@ -548,7 +544,8 @@ rip6_attach(struct socket *so, int proto, struct thread *td)
inp = sotoinpcb(so);
KASSERT(inp == NULL, ("rip6_attach: inp != NULL"));
- if (td && (error = suser(td)) != 0)
+ error = priv_check(td, PRIV_NETINET_RAW);
+ if (error)
return error;
error = soreserve(so, rip_sendspace, rip_recvspace);
if (error)
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index f9f3297..803e32d 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -488,17 +488,12 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
u_short fport;
int error = 0;
struct ip6_pktopts *optp, opt;
- int priv;
int af = AF_INET6, hlen = sizeof(struct ip6_hdr);
int flags;
struct sockaddr_in6 tmp;
INP_LOCK_ASSERT(inp);
- priv = 0;
- if (td && !suser(td))
- priv = 1;
-
if (addr6) {
/* addr6 has been validated in udp6_send(). */
sin6 = (struct sockaddr_in6 *)addr6;
@@ -523,7 +518,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
if (control) {
if ((error = ip6_setpktopts(control, &opt,
- inp->in6p_outputopts, priv, IPPROTO_UDP)) != 0)
+ inp->in6p_outputopts, td->td_ucred, IPPROTO_UDP)) != 0)
goto release;
optp = &opt;
} else
OpenPOWER on IntegriCloud