diff options
author | Ryan Zezeski <rpz@joyent.com> | 2019-06-19 08:19:07 -0600 |
---|---|---|
committer | Ryan Zezeski <rpz@joyent.com> | 2019-06-24 11:31:53 -0600 |
commit | 3d280bd5aa877a68b01b0b5dc7cb0f92843e8b41 (patch) | |
tree | 476f259200a1237814402b661c19dd91e5842103 | |
parent | 47478dccc69d4ee6c8753bc92430c6143d346300 (diff) | |
download | illumos-joyent-3d280bd5aa877a68b01b0b5dc7cb0f92843e8b41.tar.gz |
OS-7840 simnet requests zero-sized kmem alloc
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
-rw-r--r-- | usr/src/uts/common/io/simnet/simnet.c | 118 | ||||
-rw-r--r-- | usr/src/uts/common/io/simnet/simnet_impl.h | 4 |
2 files changed, 66 insertions, 56 deletions
diff --git a/usr/src/uts/common/io/simnet/simnet.c b/usr/src/uts/common/io/simnet/simnet.c index 8459a02d46..b169e519b1 100644 --- a/usr/src/uts/common/io/simnet/simnet.c +++ b/usr/src/uts/common/io/simnet/simnet.c @@ -73,7 +73,8 @@ static int simnet_ioc_create(void *, intptr_t, int, cred_t *, int *); static int simnet_ioc_delete(void *, intptr_t, int, cred_t *, int *); static int simnet_ioc_info(void *, intptr_t, int, cred_t *, int *); static int simnet_ioc_modify(void *, intptr_t, int, cred_t *, int *); -static uint8_t *mcastaddr_lookup(simnet_dev_t *, const uint8_t *); +static const struct ether_addr *mcastaddr_lookup(const simnet_dev_t *, + const uint8_t *); static dld_ioc_info_t simnet_ioc_list[] = { {SIMNET_IOC_CREATE, DLDCOPYINOUT, sizeof (simnet_ioc_create_t), @@ -316,7 +317,6 @@ simnet_dev_unref(simnet_dev_t *sdev) mutex_destroy(&sdev->sd_instlock); cv_destroy(&sdev->sd_threadwait); - kmem_free(sdev->sd_mcastaddrs, ETHERADDRL * sdev->sd_mcastaddr_count); kmem_free(sdev, sizeof (*sdev)); simnet_count--; } @@ -1041,77 +1041,85 @@ simnet_m_promisc(void *arg, boolean_t on) * Returns matching multicast address enabled on the simnet instance. * Assumes simnet instance mutex lock is held. */ -static uint8_t * -mcastaddr_lookup(simnet_dev_t *sdev, const uint8_t *addrp) +static const struct ether_addr * +mcastaddr_lookup(const simnet_dev_t *sdev, const uint8_t *addrp) { - int idx; - uint8_t *maddrptr; - ASSERT(MUTEX_HELD(&sdev->sd_instlock)); - maddrptr = sdev->sd_mcastaddrs; - for (idx = 0; idx < sdev->sd_mcastaddr_count; idx++) { - if (bcmp(maddrptr, addrp, ETHERADDRL) == 0) - return (maddrptr); - maddrptr += ETHERADDRL; + for (uint_t i = 0; i < sdev->sd_mcastaddr_count; i++) { + const struct ether_addr *maddrp = &sdev->sd_mcastaddrs[i]; + + if (bcmp(maddrp->ether_addr_octet, addrp, + sizeof (maddrp->ether_addr_octet)) == 0) { + return (maddrp); + } } return (NULL); } +static int +simnet_multicst_add(simnet_dev_t *sdev, const struct ether_addr *eap) +{ + ASSERT(MUTEX_HELD(&sdev->sd_instlock)); + + if ((eap->ether_addr_octet[0] & 01) == 0) { + return (EINVAL); + } + + if (sdev->sd_mcastaddr_count == SM_MAX_NUM_MCAST_ADDRS) { + return (ENOSPC); + } + + bcopy(eap, &sdev->sd_mcastaddrs[sdev->sd_mcastaddr_count], + sizeof (*eap)); + sdev->sd_mcastaddr_count++; + return (0); +} + +static int +simnet_multicst_rm(simnet_dev_t *sdev, const struct ether_addr *eap) +{ + ASSERT(MUTEX_HELD(&sdev->sd_instlock)); + + for (uint_t i = 0; i < sdev->sd_mcastaddr_count; i++) { + if (bcmp(eap, &sdev->sd_mcastaddrs[i], sizeof (*eap)) == 0) { + for (i++; i < sdev->sd_mcastaddr_count; i++) { + sdev->sd_mcastaddrs[i - 1] = + sdev->sd_mcastaddrs[i]; + } + + /* Zero-out the last entry as it is no longer valid. */ + bzero(&sdev->sd_mcastaddrs[i - 1], + sizeof (sdev->sd_mcastaddrs[0])); + + sdev->sd_mcastaddr_count--; + return (0); + } + } + + return (EINVAL); +} + /* Add or remove Multicast addresses on simnet instance */ static int simnet_m_multicst(void *arg, boolean_t add, const uint8_t *addrp) { simnet_dev_t *sdev = arg; - uint8_t *maddrptr; - uint8_t *newbuf; - size_t prevsize; - size_t newsize; - ptrdiff_t len; - ptrdiff_t len2; - -alloc_retry: - prevsize = sdev->sd_mcastaddr_count * ETHERADDRL; - newsize = prevsize + (add ? ETHERADDRL:-ETHERADDRL); - newbuf = kmem_alloc(newsize, KM_SLEEP); + struct ether_addr ea; + int ret; + bcopy(addrp, ea.ether_addr_octet, sizeof (ea.ether_addr_octet)); mutex_enter(&sdev->sd_instlock); - if (prevsize != (sdev->sd_mcastaddr_count * ETHERADDRL)) { - mutex_exit(&sdev->sd_instlock); - kmem_free(newbuf, newsize); - goto alloc_retry; - } - - maddrptr = mcastaddr_lookup(sdev, addrp); - if (!add && maddrptr != NULL) { - /* Removing a Multicast address */ - if (newbuf != NULL) { - /* LINTED: E_PTRDIFF_OVERFLOW */ - len = maddrptr - sdev->sd_mcastaddrs; - (void) memcpy(newbuf, sdev->sd_mcastaddrs, len); - len2 = prevsize - len - ETHERADDRL; - (void) memcpy(newbuf + len, - maddrptr + ETHERADDRL, len2); - } - sdev->sd_mcastaddr_count--; - } else if (add && maddrptr == NULL) { - /* Adding a new Multicast address */ - (void) memcpy(newbuf, sdev->sd_mcastaddrs, prevsize); - (void) memcpy(newbuf + prevsize, addrp, ETHERADDRL); - sdev->sd_mcastaddr_count++; + + if (add) { + ret = simnet_multicst_add(sdev, &ea); } else { - /* Error: removing a non-existing Multicast address */ - mutex_exit(&sdev->sd_instlock); - kmem_free(newbuf, newsize); - cmn_err(CE_WARN, "simnet: MAC call to remove a " - "Multicast address failed"); - return (EINVAL); + ret = simnet_multicst_rm(sdev, &ea); } - kmem_free(sdev->sd_mcastaddrs, prevsize); - sdev->sd_mcastaddrs = newbuf; + ASSERT3U(sdev->sd_mcastaddr_count, <=, SM_MAX_NUM_MCAST_ADDRS); mutex_exit(&sdev->sd_instlock); - return (0); + return (ret); } static int diff --git a/usr/src/uts/common/io/simnet/simnet_impl.h b/usr/src/uts/common/io/simnet/simnet_impl.h index 659cb10d9b..c804a416eb 100644 --- a/usr/src/uts/common/io/simnet/simnet_impl.h +++ b/usr/src/uts/common/io/simnet/simnet_impl.h @@ -42,6 +42,8 @@ extern "C" { #define MAX_ESSLIST_ARGS 10 /* Max num of ESS list arguments */ #define MAX_ESSLIST_ARGLEN 50 /* Max ESS list argument len */ +#define SM_MAX_NUM_MCAST_ADDRS 1024 + struct simnet_dev; typedef struct simnet_wifidev { @@ -81,7 +83,7 @@ typedef struct simnet_dev { /* Num of multicast addresses stored in sd_mcastaddrs */ uint_t sd_mcastaddr_count; /* Multicast address list stored in single buffer */ - uint8_t *sd_mcastaddrs; + struct ether_addr sd_mcastaddrs[SM_MAX_NUM_MCAST_ADDRS]; uint_t sd_mac_len; uchar_t sd_mac_addr[MAXMACADDRLEN]; simnet_stats_t sd_stats; |