net/wmnetload has a memory leak [patch]

wmnetload (6.4 release) repeatedly calls getifaddrs(3)
without freeifaddrs.

The patch here fixes and would replace
net/wmnetload/patches/patch-src_ifstat_openbsd_c
not apply over it.

Also fixes a compile warning from strcmp() w/o <string.h>

-Ed Hynan

# patch:
--- src/ifstat_openbsd.c.orig   Tue Jan 29 03:09:18 2002
+++ src/ifstat_openbsd.c        Tue Dec 18 13:38:23 2018
@@ -24,22 +24,18 @@
 #pragma ident "@(#)ifstat_netbsd.c     1.2     02/01/29 meem"
 
 #include <config.h>
+#include <string.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <net/if.h>
-#include <fcntl.h>
-#include <kvm.h>
-#include <limits.h>
-#include <nlist.h>
+#include <ifaddrs.h>
 #include <stdlib.h>
-#include <string.h>
 
 #include "ifstat.h"
 #include "utils.h"
 
 struct ifstatstate {
-       void    *ifnet_head;
-       kvm_t   *kd;
+       struct ifaddrs *ifap;
 };
 
 /*
@@ -51,8 +47,6 @@
 if_statinit(void)
 {
        ifstatstate_t   *statep;
-       struct nlist    ifnet[] = { { "_ifnet" }, { NULL }};
-       char            errbuf[_POSIX2_LINE_MAX];
 
        statep = malloc(sizeof (ifstatstate_t));
        if (statep == NULL) {
@@ -60,37 +54,7 @@
                return (NULL);
        }
 
-       /*
-        * Just for the duration of kmem_openfiles(), get privileges
-        * needed to access kmem.
-        */
-       chpriv(PRIV_GAIN);
-       statep->kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
-       chpriv(PRIV_DROP);
-       if (statep->kd == NULL) {
-               warn("cannot access raw kernel memory: %s\n", errbuf);
-               free(statep);
-               return (NULL);
-       }
-
-       if (kvm_nlist(statep->kd, ifnet) == -1) {
-               warn("cannot populate kernel namelist: %s\n",
-                   kvm_geterr(statep->kd));
-               goto fail;
-       }
-
-       if (kvm_read(statep->kd, ifnet->n_value, &statep->ifnet_head,
-           sizeof (ifnet->n_value)) != sizeof (ifnet->n_value)) {
-               warn("cannot find ifnet list head: %s\n",
-                   kvm_geterr(statep->kd));
-               goto fail;
-       }
-
        return (statep);
-fail:
-       (void) kvm_close(statep->kd);
-       free(statep);
-       return (NULL);
 }
 
 /*
@@ -100,22 +64,39 @@
 int
 if_stats(const char *ifname, ifstatstate_t *statep, ifstats_t *ifstatsp)
 {
-       void            *ifnet_addr = statep->ifnet_head;
-       struct ifnet    ifnet;
+       struct ifaddrs *ifa;
 
-       for (; ifnet_addr != NULL; ifnet_addr = TAILQ_NEXT(&ifnet, if_list)) {
+       if (statep->ifap != NULL) {
+               freeifaddrs(statep->ifap);
+       }
 
-               if (kvm_read(statep->kd, (unsigned long)ifnet_addr, &ifnet,
-                   sizeof (struct ifnet)) != sizeof (struct ifnet))
-                       return (0);
+       if (getifaddrs(&statep->ifap) != 0) {
+               warn("failed to get interface addresses");
+               statep->ifap = NULL;
+               return (0);
+       }
 
-               if (strcmp(ifnet.if_xname, ifname) == 0) {
-                       ifstatsp->rxbytes = ifnet.if_ibytes;
-                       ifstatsp->txbytes = ifnet.if_obytes;
-                       return (1);
+       for (ifa = statep->ifap; ifa != NULL; ifa = ifa->ifa_next) {
+               if (strcmp(ifname, ifa->ifa_name)) {
+                       continue;
                }
+
+               if (ifa->ifa_addr->sa_family == AF_LINK) {
+                       struct sockaddr_dl *dl = (struct sockaddr_dl 
*)ifa->ifa_addr;
+                       struct if_data *ifd = NULL;
+
+                       ifd = ifa->ifa_data;
+
+                       if (ifd != NULL) {
+                               ifstatsp->rxbytes = ifd->ifi_ibytes;
+                               ifstatsp->txbytes = ifd->ifi_obytes;
+                               return 1;
+                       }
+               }
        }
 
+       freeifaddrs(statep->ifap);
+       statep->ifap = NULL;
        return (0);
 }
 
@@ -125,6 +106,7 @@
 void
 if_statfini(ifstatstate_t *statep)
 {
-       (void) kvm_close(statep->kd);
+       if (statep->ifap != NULL)
+               freeifaddrs(statep->ifap);
        free(statep);
 }

Reply via email to