From dbb99d055289acffb72a07596e086ff114c76e2a Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 6 Dec 2024 16:09:44 +0100 Subject: [PATCH 1/4] iwinfo: limit assoclist client parsing element to IWINFO_BUFSIZE Limit assoclist element to IWINFO_BUFSIZE. This is to fix a segfault if the clients are more than 140. Once the local buffer is filled, the function stop parsing additional clients and returns info for the parsed ones. Fixes: #15 Signed-off-by: Christian Marangi --- iwinfo_madwifi.c | 4 ++++ iwinfo_nl80211.c | 7 +++++++ iwinfo_nl80211.h | 1 + 3 files changed, 12 insertions(+) diff --git a/iwinfo_madwifi.c b/iwinfo_madwifi.c index d27e6c9..a52d289 100644 --- a/iwinfo_madwifi.c +++ b/iwinfo_madwifi.c @@ -772,6 +772,10 @@ static int madwifi_get_assoclist(const char *ifname, char *buf, int *len) do { si = (struct ieee80211req_sta_info *) cp; + /* stop parsing more elements as we reached max buf */ + if (bl + sizeof(entry) > IWINFO_BUFSIZE) + break; + memset(&entry, 0, sizeof(entry)); entry.signal = (si->isi_rssi - 95); diff --git a/iwinfo_nl80211.c b/iwinfo_nl80211.c index dc4ff93..16f5d31 100644 --- a/iwinfo_nl80211.c +++ b/iwinfo_nl80211.c @@ -2254,6 +2254,10 @@ static int nl80211_get_assoclist_cb(struct nl_msg *msg, void *arg) [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, }; + /* stop parsing more elements as we reached max buf */ + if (arr->count >= arr->max) + return NL_STOP; + /* advance to end of array */ e += arr->count; memset(e, 0, sizeof(*e)); @@ -2397,6 +2401,9 @@ static int nl80211_get_assoclist(const char *ifname, char *buf, int *len) struct nl80211_array_buf arr = { .buf = buf, .count = 0 }; struct iwinfo_assoclist_entry *e; + /* Limit element to the preallocated space */ + arr.max = IWINFO_BUFSIZE / sizeof(*e); + if ((d = opendir("/sys/class/net")) != NULL) { while ((de = readdir(d)) != NULL) diff --git a/iwinfo_nl80211.h b/iwinfo_nl80211.h index 2dff08b..fbbf2f7 100644 --- a/iwinfo_nl80211.h +++ b/iwinfo_nl80211.h @@ -67,6 +67,7 @@ struct nl80211_rssi_rate { struct nl80211_array_buf { void *buf; int count; + int max; }; #endif From d6adab8a09cd575511c323186a2f6014305b5d66 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 6 Dec 2024 16:39:10 +0100 Subject: [PATCH 2/4] iwinfo: make assoclist aware of the max allocated buffer Make assoclist OP aware of the max allocated buffer. This is done by setting the third arg to the max allocated buffer. Function needs to use this info to stop parsing data if the max allocated buffer size is reached. Signed-off-by: Christian Marangi --- include/iwinfo.h | 4 ++++ iwinfo_cli.c | 3 ++- iwinfo_madwifi.c | 2 +- iwinfo_nl80211.c | 6 +++++- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/include/iwinfo.h b/include/iwinfo.h index 2a841be..369c307 100644 --- a/include/iwinfo.h +++ b/include/iwinfo.h @@ -409,6 +409,10 @@ struct iwinfo_ops { int (*hardware_name)(const char *, char *); int (*encryption)(const char *, char *); int (*phyname)(const char *, char *); + /* + * Third element is always set to the size of the buffer. + * assoclist should stop parsing elements if this is reached. + */ int (*assoclist)(const char *, char *, int *); int (*txpwrlist)(const char *, char *, int *); int (*scanlist)(const char *, char *, int *); diff --git a/iwinfo_cli.c b/iwinfo_cli.c index 6f87d98..462b2e1 100644 --- a/iwinfo_cli.c +++ b/iwinfo_cli.c @@ -784,10 +784,11 @@ static void print_freqlist(const struct iwinfo_ops *iw, const char *ifname) static void print_assoclist(const struct iwinfo_ops *iw, const char *ifname) { - int i, len; + int i, len = IWINFO_BUFSIZE; char buf[IWINFO_BUFSIZE]; struct iwinfo_assoclist_entry *e; + /* Pass to assoclist the size of buf allocated with len */ if (iw->assoclist(ifname, buf, &len)) { printf("No information available\n"); diff --git a/iwinfo_madwifi.c b/iwinfo_madwifi.c index a52d289..78b6665 100644 --- a/iwinfo_madwifi.c +++ b/iwinfo_madwifi.c @@ -773,7 +773,7 @@ static int madwifi_get_assoclist(const char *ifname, char *buf, int *len) si = (struct ieee80211req_sta_info *) cp; /* stop parsing more elements as we reached max buf */ - if (bl + sizeof(entry) > IWINFO_BUFSIZE) + if (bl + sizeof(entry) > *len) break; memset(&entry, 0, sizeof(entry)); diff --git a/iwinfo_nl80211.c b/iwinfo_nl80211.c index 16f5d31..9d4d6ed 100644 --- a/iwinfo_nl80211.c +++ b/iwinfo_nl80211.c @@ -2401,8 +2401,12 @@ static int nl80211_get_assoclist(const char *ifname, char *buf, int *len) struct nl80211_array_buf arr = { .buf = buf, .count = 0 }; struct iwinfo_assoclist_entry *e; + /* If len is not set, use IWINFO_BUFSIZE by default */ + if (!*len) + *len = IWINFO_BUFSIZE; + /* Limit element to the preallocated space */ - arr.max = IWINFO_BUFSIZE / sizeof(*e); + arr.max = *len / sizeof(*e); if ((d = opendir("/sys/class/net")) != NULL) { From 142ad0e0d6a939c85af6681bd031c0d7252e29b9 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 6 Dec 2024 17:07:39 +0100 Subject: [PATCH 3/4] iwinfo: update assoclist user to account for NULL buf Update any assoclist user to account for NULL buf. This is common practice where a NULL buf is passed if only the len element needs to be filled. This is useful to know how much space allocate for a function. Signed-off-by: Christian Marangi --- include/iwinfo.h | 3 +++ iwinfo_madwifi.c | 5 +++++ iwinfo_nl80211.c | 9 ++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/iwinfo.h b/include/iwinfo.h index 369c307..c79b939 100644 --- a/include/iwinfo.h +++ b/include/iwinfo.h @@ -410,6 +410,9 @@ struct iwinfo_ops { int (*encryption)(const char *, char *); int (*phyname)(const char *, char *); /* + * assoclist might receive a NULL buf as second element. + * In such case assoclist should only return the length + * of the expected buffer. * Third element is always set to the size of the buffer. * assoclist should stop parsing elements if this is reached. */ diff --git a/iwinfo_madwifi.c b/iwinfo_madwifi.c index 78b6665..18b50fa 100644 --- a/iwinfo_madwifi.c +++ b/iwinfo_madwifi.c @@ -772,6 +772,10 @@ static int madwifi_get_assoclist(const char *ifname, char *buf, int *len) do { si = (struct ieee80211req_sta_info *) cp; + /* If buf is NULL, we only count the station */ + if (!buf) + goto next; + /* stop parsing more elements as we reached max buf */ if (bl + sizeof(entry) > *len) break; @@ -801,6 +805,7 @@ static int madwifi_get_assoclist(const char *ifname, char *buf, int *len) memcpy(&buf[bl], &entry, sizeof(struct iwinfo_assoclist_entry)); +next: bl += sizeof(struct iwinfo_assoclist_entry); cp += si->isi_len; tl -= si->isi_len; diff --git a/iwinfo_nl80211.c b/iwinfo_nl80211.c index 9d4d6ed..09d76fb 100644 --- a/iwinfo_nl80211.c +++ b/iwinfo_nl80211.c @@ -2254,6 +2254,10 @@ static int nl80211_get_assoclist_cb(struct nl_msg *msg, void *arg) [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG }, }; + /* With NULL buf, we just count the stations */ + if (!arr->buf) + goto exit; + /* stop parsing more elements as we reached max buf */ if (arr->count >= arr->max) return NL_STOP; @@ -2373,6 +2377,8 @@ static int nl80211_get_assoclist_cb(struct nl_msg *msg, void *arg) } e->noise = 0; /* filled in by caller */ + +exit: arr->count++; return NL_SKIP; @@ -2423,7 +2429,8 @@ static int nl80211_get_assoclist(const char *ifname, char *buf, int *len) closedir(d); - if (!nl80211_get_noise(ifname, &noise)) + /* Skip setting noise if we are just counting station */ + if (arr.buf && !nl80211_get_noise(ifname, &noise)) for (i = 0, e = arr.buf; i < arr.count; i++, e++) e->noise = noise; From 54cfc77ae78ac2360741ee9863e1c86bbe2e4a7d Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Fri, 6 Dec 2024 17:09:36 +0100 Subject: [PATCH 4/4] iwinfo: dynamically allocate buffer for assoclist Change print_assoclist to dynamically allocate buffer for assoclist. Assoclist is called 2 times, one to get the size of the buffer to allocate by passint to assoclist a NULL buf. Then a second time to actually fill the data. Signed-off-by: Christian Marangi --- iwinfo_cli.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/iwinfo_cli.c b/iwinfo_cli.c index 462b2e1..622d0ba 100644 --- a/iwinfo_cli.c +++ b/iwinfo_cli.c @@ -784,20 +784,37 @@ static void print_freqlist(const struct iwinfo_ops *iw, const char *ifname) static void print_assoclist(const struct iwinfo_ops *iw, const char *ifname) { - int i, len = IWINFO_BUFSIZE; - char buf[IWINFO_BUFSIZE]; + int i, len = 0; + char *buf = NULL; struct iwinfo_assoclist_entry *e; + /* Call assoclist with NULL buf to get number of element to alloc */ + if (iw->assoclist(ifname, NULL, &len)) { + printf("No information available\n"); + return; + } + else if (len <= 0) + { + printf("No station connected\n"); + return; + } + + buf = malloc(len * sizeof(*e)); + if (!buf) { + printf("No space to allocate assoc elements buf\n"); + return; + } + /* Pass to assoclist the size of buf allocated with len */ if (iw->assoclist(ifname, buf, &len)) { printf("No information available\n"); - return; + goto exit; } else if (len <= 0) { printf("No station connected\n"); - return; + goto exit; } for (i = 0; i < len; i += sizeof(struct iwinfo_assoclist_entry)) @@ -824,6 +841,9 @@ static void print_assoclist(const struct iwinfo_ops *iw, const char *ifname) printf(" expected throughput: %s\n\n", format_rate(e->thr)); } + +exit: + free(buf); }