diff options
| author | Muhammad Bilal <meatuni001@gmail.com> | 2026-07-28 17:54:55 +0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-09-01 12:15:16 +0200 |
| commit | ff917923f4fb9c83717ba135ee47d7e4c1567bb7 (patch) | |
| tree | c38fd8fcf58e1937b17fdbc6518b6f8b797fc15a /tools/perf/tests/fdarray.c | |
| download | linux-stable-ff917923f4fb9c83717ba135ee47d7e4c1567bb7.tar.gz linux-stable-ff917923f4fb9c83717ba135ee47d7e4c1567bb7.zip | |
staging: rtl8723bs: fix OOB read in rtw_action_frame_parse()grafted
rtw_action_frame_parse() takes a frame_len parameter but never
actually checks it before indexing into the frame body:
const u8 *frame_body = frame + sizeof(struct ieee80211_hdr_3addr);
...
c = frame_body[0];
...
a = frame_body[1];
frame_body already points 24 bytes (sizeof(struct
ieee80211_hdr_3addr)) into frame, so reading frame_body[0] and
frame_body[1] requires frame_len >= 26. A management action frame
shorter than that (e.g. exactly 24 bytes, the minimum a malicious
peer can send) causes a 1-2 byte out-of-bounds read.
This is reachable from rtw_cfg80211_monitor_if_xmit_entry() and
cfg80211_rtw_mgmt_tx() in ioctl_cfg80211.c, both of which pass
attacker/user-influenced frame buffers and lengths straight through.
Add the missing length check before frame_body is dereferenced.
Fixes: 554c0a3abf216 ("staging: Add rtl8723bs sdio wifi driver")
Cc: stable@vger.kernel.org
Signed-off-by: Muhammad Bilal <meatuni001@gmail.com>
Link: https://patch.msgid.link/20260728125456.32359-3-meatuni001@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'tools/perf/tests/fdarray.c')
| -rw-r--r-- | tools/perf/tests/fdarray.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c new file mode 100644 index 000000000..40983c357 --- /dev/null +++ b/tools/perf/tests/fdarray.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <api/fd/array.h> +#include <poll.h> +#include "util/debug.h" +#include "tests/tests.h" + +static void fdarray__init_revents(struct fdarray *fda, short revents) +{ + int fd; + + fda->nr = fda->nr_alloc; + + for (fd = 0; fd < fda->nr; ++fd) { + fda->entries[fd].fd = fda->nr - fd; + fda->entries[fd].events = revents; + fda->entries[fd].revents = revents; + } +} + +static int fdarray__fprintf_prefix(struct fdarray *fda, const char *prefix, FILE *fp) +{ + int printed = 0; + + if (verbose <= 0) + return 0; + + printed += fprintf(fp, "\n%s: ", prefix); + return printed + fdarray__fprintf(fda, fp); +} + +static int test__fdarray__filter(struct test_suite *test __maybe_unused, int subtest __maybe_unused) +{ + int nr_fds, err = TEST_FAIL; + struct fdarray *fda = fdarray__new(5, 5); + + if (fda == NULL) { + pr_debug("\nfdarray__new() failed!"); + goto out; + } + + fdarray__init_revents(fda, POLLIN); + nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL); + if (nr_fds != fda->nr_alloc) { + pr_debug("\nfdarray__filter()=%d != %d shouldn't have filtered anything", + nr_fds, fda->nr_alloc); + goto out_delete; + } + + fdarray__init_revents(fda, POLLHUP); + nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL); + if (nr_fds != 0) { + pr_debug("\nfdarray__filter()=%d != %d, should have filtered all fds", + nr_fds, fda->nr_alloc); + goto out_delete; + } + + fdarray__init_revents(fda, POLLHUP); + fda->entries[2].revents = POLLIN; + + pr_debug("\nfiltering all but fda->entries[2]:"); + fdarray__fprintf_prefix(fda, "before", stderr); + nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL); + fdarray__fprintf_prefix(fda, " after", stderr); + if (nr_fds != 1) { + pr_debug("\nfdarray__filter()=%d != 1, should have left just one event", nr_fds); + goto out_delete; + } + + fdarray__init_revents(fda, POLLHUP); + fda->entries[0].revents = POLLIN; + fda->entries[3].revents = POLLIN; + + pr_debug("\nfiltering all but (fda->entries[0], fda->entries[3]):"); + fdarray__fprintf_prefix(fda, "before", stderr); + nr_fds = fdarray__filter(fda, POLLHUP, NULL, NULL); + fdarray__fprintf_prefix(fda, " after", stderr); + if (nr_fds != 2) { + pr_debug("\nfdarray__filter()=%d != 2, should have left just two events", + nr_fds); + goto out_delete; + } + + pr_debug("\n"); + + err = 0; +out_delete: + fdarray__delete(fda); +out: + return err; +} + +static int test__fdarray__add(struct test_suite *test __maybe_unused, int subtest __maybe_unused) +{ + int err = TEST_FAIL; + struct fdarray *fda = fdarray__new(2, 2); + + if (fda == NULL) { + pr_debug("\nfdarray__new() failed!"); + goto out; + } + +#define FDA_CHECK(_idx, _fd, _revents) \ + if (fda->entries[_idx].fd != _fd) { \ + pr_debug("\n%d: fda->entries[%d](%d) != %d!", \ + __LINE__, _idx, fda->entries[1].fd, _fd); \ + goto out_delete; \ + } \ + if (fda->entries[_idx].events != (_revents)) { \ + pr_debug("\n%d: fda->entries[%d].revents(%d) != %d!", \ + __LINE__, _idx, fda->entries[_idx].fd, _revents); \ + goto out_delete; \ + } + +#define FDA_ADD(_idx, _fd, _revents, _nr) \ + if (fdarray__add(fda, _fd, _revents, fdarray_flag__default) < 0) { \ + pr_debug("\n%d: fdarray__add(fda, %d, %d) failed!", \ + __LINE__,_fd, _revents); \ + goto out_delete; \ + } \ + if (fda->nr != _nr) { \ + pr_debug("\n%d: fdarray__add(fda, %d, %d)=%d != %d", \ + __LINE__,_fd, _revents, fda->nr, _nr); \ + goto out_delete; \ + } \ + FDA_CHECK(_idx, _fd, _revents) + + FDA_ADD(0, 1, POLLIN, 1); + FDA_ADD(1, 2, POLLERR, 2); + + fdarray__fprintf_prefix(fda, "before growing array", stderr); + + FDA_ADD(2, 35, POLLHUP, 3); + + if (fda->entries == NULL) { + pr_debug("\nfdarray__add(fda, 35, POLLHUP) should have allocated fda->pollfd!"); + goto out_delete; + } + + fdarray__fprintf_prefix(fda, "after 3rd add", stderr); + + FDA_ADD(3, 88, POLLIN | POLLOUT, 4); + + fdarray__fprintf_prefix(fda, "after 4th add", stderr); + + FDA_CHECK(0, 1, POLLIN); + FDA_CHECK(1, 2, POLLERR); + FDA_CHECK(2, 35, POLLHUP); + FDA_CHECK(3, 88, POLLIN | POLLOUT); + +#undef FDA_ADD +#undef FDA_CHECK + + pr_debug("\n"); + + err = 0; +out_delete: + fdarray__delete(fda); +out: + return err; +} + +DEFINE_SUITE("Filter fds with revents mask in a fdarray", fdarray__filter); +DEFINE_SUITE("Add fd to a fdarray, making it autogrow", fdarray__add); |
