From 03b59f7842b50eda32f941744a5d94a55e47ba26 Mon Sep 17 00:00:00 2001 From: Yuri Pankov Date: Fri, 24 Apr 2015 18:31:32 +0300 Subject: [PATCH] 5868 Make checks in inet_matchaddr() more robust Reviewed by: Dan McDonald Reviewed by: Igor Kozhukhov Reviewed by: Marcel Telka Approved by: Robert Mustacchi --- usr/src/cmd/fs.d/nfs/mountd/mountd.c | 24 +++++++- usr/src/head/arpa/inet.h | 2 +- usr/src/lib/libnsl/common/llib-lnsl | 4 +- usr/src/lib/libnsl/nss/inet_matchaddr.c | 91 ++++++++++++++++++++--------- usr/src/lib/smbsrv/libsmb/common/smb_util.c | 4 +- 5 files changed, 92 insertions(+), 33 deletions(-) diff --git a/usr/src/cmd/fs.d/nfs/mountd/mountd.c b/usr/src/cmd/fs.d/nfs/mountd/mountd.c index 7204cd5f46..f0a6735a68 100644 --- a/usr/src/cmd/fs.d/nfs/mountd/mountd.c +++ b/usr/src/cmd/fs.d/nfs/mountd/mountd.c @@ -1799,6 +1799,7 @@ in_access_list(struct cln *cln, char *gr = access_list; int i; int response; + int ret; struct netbuf *pnb; struct nd_hostservlist *clnames = NULL; @@ -1854,12 +1855,31 @@ in_access_list(struct cln *cln, if (inet_ntop(AF_INET, &np->n_net, addr, INET_ADDRSTRLEN) == NULL) break; - if (inet_matchaddr(pnb->buf, addr)) + ret = inet_matchaddr(pnb->buf, addr); + if (ret == -1) { + if (errno == EINVAL) { + syslog(LOG_WARNING, + "invalid access " + "list entry: %s", + addr); + } + return (-1); + } else if (ret == 1) { return (response); + } } } else { - if (inet_matchaddr(pnb->buf, gr)) + ret = inet_matchaddr(pnb->buf, gr); + if (ret == -1) { + if (errno == EINVAL) { + syslog(LOG_WARNING, + "invalid access list " + "entry: %s", gr); + } + return (-1); + } else if (ret == 1) { return (response); + } } goto next; diff --git a/usr/src/head/arpa/inet.h b/usr/src/head/arpa/inet.h index 2d6b843946..208fdbd6af 100644 --- a/usr/src/head/arpa/inet.h +++ b/usr/src/head/arpa/inet.h @@ -58,7 +58,7 @@ extern "C" { */ #if !defined(_XPG4_2) || defined(__EXTENSIONS__) extern int inet_net_pton(int, const char *, void *, size_t); -extern boolean_t inet_matchaddr(const void *, const char *); +extern int inet_matchaddr(const void *, const char *); #endif /* !defined(_XPG4_2) || defined(__EXTENSIONS__) */ #if !defined(_XPG4_2) || defined(_XPG6) || defined(__EXTENSIONS__) diff --git a/usr/src/lib/libnsl/common/llib-lnsl b/usr/src/lib/libnsl/common/llib-lnsl index 582eecef95..46f74824eb 100644 --- a/usr/src/lib/libnsl/common/llib-lnsl +++ b/usr/src/lib/libnsl/common/llib-lnsl @@ -23,7 +23,7 @@ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Nexenta Systems, Inc. */ @@ -440,7 +440,7 @@ void endrpcent(void); struct rpcent *getrpcent_r(struct rpcent *result, char *buffer, int buflen); /* inet_matchaddr.c */ -boolean_t inet_matchaddr(const void *, const char *); +int inet_matchaddr(const void *, const char *); /* inet_ntop.c */ const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); diff --git a/usr/src/lib/libnsl/nss/inet_matchaddr.c b/usr/src/lib/libnsl/nss/inet_matchaddr.c index f60b70710d..4a510ea01b 100644 --- a/usr/src/lib/libnsl/nss/inet_matchaddr.c +++ b/usr/src/lib/libnsl/nss/inet_matchaddr.c @@ -10,7 +10,7 @@ */ /* - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Nexenta Systems, Inc. */ /* @@ -26,6 +26,14 @@ * IPv6: * [IPv6] * [IPv6]/prefix + * + * Return values: + * + * 0 mismatch + * 1 match + * -1 error occured, caller should check errno: + * EINVAL access list entry is invalid + * ENOMEM failed to allocate memory */ #include @@ -36,22 +44,24 @@ #include #include -#include #include #include #include #include - -boolean_t +int inet_matchaddr(const void *sa, const char *name) { - boolean_t ret = B_FALSE; + int ret = -1; char *lname, *mp, *p; + char *ep; + int serrno = errno; uint32_t claddr4 = 0; - if ((p = lname = strdup(name)) == NULL) - err(1, "strdup"); + if ((p = lname = strdup(name)) == NULL) { + errno = ENOMEM; + return (-1); + } if ((mp = strchr(p, '/')) != NULL) *mp++ = '\0'; @@ -59,7 +69,6 @@ inet_matchaddr(const void *sa, const char *name) switch (((struct sockaddr_in *)sa)->sin_family) { case AF_INET6: { char *pp; - int prefix6; ipaddr_t ipaddr4; struct in6_addr hcaddr6; struct in6_addr *claddr6 = @@ -67,28 +76,43 @@ inet_matchaddr(const void *sa, const char *name) if (!IN6_IS_ADDR_V4MAPPED(claddr6)) { /* IPv6 address */ - if ((p = strchr(p, '[')) == NULL) + if (*p != '[') { + errno = EINVAL; break; + } p++; - if ((pp = strchr(p, ']')) == NULL) + if ((pp = strchr(p, ']')) == NULL || + (mp != NULL && pp != mp - 2) || + (mp == NULL && *(pp + 1) != '\0')) { + errno = EINVAL; break; + } *pp = '\0'; - if (inet_pton(AF_INET6, p, &hcaddr6) != 1) + if (inet_pton(AF_INET6, p, &hcaddr6) != 1) { + errno = EINVAL; break; + } if (mp != NULL) { /* Match only first prefix bits */ - if ((prefix6 = (int)strtol(mp, - (char **)NULL, 10)) == 0) + long prefix6; + + errno = 0; + prefix6 = strtol(mp, &ep, 10); + if (errno != 0 || prefix6 < 0 || + prefix6 > 128 || *ep != '\0') { + errno = EINVAL; break; + } ret = IN6_ARE_PREFIXEDADDR_EQUAL(claddr6, - &hcaddr6, prefix6); + &hcaddr6, prefix6) ? 1 : 0; break; } else { /* No prefix, exact match */ - ret = IN6_ARE_ADDR_EQUAL(claddr6, &hcaddr6); + ret = IN6_ARE_ADDR_EQUAL(claddr6, + &hcaddr6) ? 1 : 0; break; } } else { @@ -99,7 +123,7 @@ inet_matchaddr(const void *sa, const char *name) /*FALLTHROUGH*/ } case AF_INET: { - int bits, i; + int i; uint32_t hcaddr4 = 0, mask4; if (claddr4 == 0) { @@ -108,23 +132,36 @@ inet_matchaddr(const void *sa, const char *name) } for (i = 0; i < 4; i++) { - hcaddr4 |= (int)strtol(p, (char **)NULL, 10) << - ((3 - i) * 8); - if ((p = strchr(p, '.')) == NULL) + long qaddr4; + + errno = 0; + qaddr4 = strtol(p, &ep, 10); + if (errno != 0 || qaddr4 < 0 || qaddr4 > 255 || + (*ep != '.' && *ep != '\0')) { + errno = EINVAL; break; - p++; + } + hcaddr4 |= qaddr4 << ((3 - i) * 8); + if (*ep == '\0') + break; + p = ep + 1; } - if (hcaddr4 == 0 && errno != 0) + if (errno != 0) break; if (mp != NULL) { /* Mask is specified explicitly */ - if ((bits = (int)strtol(mp, (char **)NULL, 10)) == 0 && - errno != 0) + long mb; + + errno = 0; + mb = strtol(mp, &ep, 10); + if (errno != 0 || mb < 0 || mb > 32 || *ep != '\0') { + errno = EINVAL; break; - mask4 = bits ? ~0 << ((sizeof (struct in_addr) * NBBY) - - bits) : 0; + } + mask4 = mb ? ~0 << ((sizeof (struct in_addr) * NBBY) + - mb) : 0; hcaddr4 &= mask4; } else { /* @@ -144,12 +181,14 @@ inet_matchaddr(const void *sa, const char *name) mask4 = IN_CLASSE_NET; } - ret = ((claddr4 & mask4) == hcaddr4); + ret = ((claddr4 & mask4) == hcaddr4) ? 1 : 0; break; } } free(lname); + if (ret != -1) + errno = serrno; return (ret); } diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_util.c b/usr/src/lib/smbsrv/libsmb/common/smb_util.c index 53ad11a91c..359ea0e801 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_util.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.c @@ -458,11 +458,11 @@ smb_chk_hostaccess(smb_inaddr_t *ipaddr, char *access_list) if (inet_ntop(AF_INET, &np->n_net, addr, INET_ADDRSTRLEN) == NULL) break; - if (inet_matchaddr(buf.buf, addr)) + if (inet_matchaddr(buf.buf, addr) == 1) return (response); } } else { - if (inet_matchaddr(buf.buf, gr)) + if (inet_matchaddr(buf.buf, gr) == 1) return (response); } -- 2.11.4.GIT