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 /lib/build_OID_registry | |
| 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 'lib/build_OID_registry')
| -rwxr-xr-x | lib/build_OID_registry | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/lib/build_OID_registry b/lib/build_OID_registry new file mode 100755 index 000000000..30493ac19 --- /dev/null +++ b/lib/build_OID_registry @@ -0,0 +1,218 @@ +#!/usr/bin/perl -w +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Build a static ASN.1 Object Identified (OID) registry +# +# Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. +# Written by David Howells (dhowells@redhat.com) +# + +use strict; +use Cwd qw(abs_path); + +my @names = (); +my @oids = (); + +if ($#ARGV != 1) { + print STDERR "Format: ", $0, " <in-h-file> <out-c-file>\n"; + exit(2); +} + +my $abs_srctree = abs_path($ENV{'srctree'}); + +# +# Open the file to read from +# +open IN_FILE, "<$ARGV[0]" || die; +while (<IN_FILE>) { + chomp; + if (m!\s+OID_([a-zA-z][a-zA-Z0-9_]+),\s+/[*]\s+([012][.0-9]*)\s+[*]/!) { + push @names, $1; + push @oids, $2; + } +} +close IN_FILE || die; + +# +# Open the files to write into +# +open C_FILE, ">$ARGV[1]" or die; +print C_FILE "/*\n"; +my $scriptname = $0; +$scriptname =~ s#^\Q$abs_srctree/\E##; +print C_FILE " * Automatically generated by ", $scriptname, ". Do not edit\n"; +print C_FILE " */\n"; + +# +# Split the data up into separate lists and also determine the lengths of the +# encoded data arrays. +# +my @indices = (); +my @lengths = (); +my $total_length = 0; + +for (my $i = 0; $i <= $#names; $i++) { + my $name = $names[$i]; + my $oid = $oids[$i]; + + my @components = split(/[.]/, $oid); + + # Determine the encoded length of this OID + my $size = $#components; + for (my $loop = 2; $loop <= $#components; $loop++) { + $ENV{'BC_LINE_LENGTH'} = "0"; + my $c = `echo "ibase=10; obase=2; $components[$loop]" | bc`; + chomp($c); + + # We will base128 encode the number + my $tmp = length($c) - 1; + $tmp = int($tmp / 7); + $size += $tmp; + } + push @lengths, $size; + push @indices, $total_length; + $total_length += $size; +} + +# +# Emit the look-up-by-OID index table +# +print C_FILE "\n"; +if ($total_length <= 255) { + print C_FILE "static const unsigned char oid_index[OID__NR + 1] = {\n"; +} else { + print C_FILE "static const unsigned short oid_index[OID__NR + 1] = {\n"; +} +for (my $i = 0; $i <= $#names; $i++) { + print C_FILE "\t[OID_", $names[$i], "] = ", $indices[$i], ",\n" +} +print C_FILE "\t[OID__NR] = ", $total_length, "\n"; +print C_FILE "};\n"; + +# +# Encode the OIDs +# +my @encoded_oids = (); + +for (my $i = 0; $i <= $#names; $i++) { + my @octets = (); + + my @components = split(/[.]/, $oids[$i]); + + push @octets, $components[0] * 40 + $components[1]; + + for (my $loop = 2; $loop <= $#components; $loop++) { + # get the base 2 representation of the component + $ENV{'BC_LINE_LENGTH'} = "0"; + my $c = `echo "ibase=10; obase=2; $components[$loop]" | bc`; + chomp($c); + + my $tmp = length($c) - 1; + $tmp = int($tmp / 7); + + # zero pad upto length multiple of 7 + $c = substr("0000000", 0, ($tmp + 1) * 7 - length($c)).$c; + + # Base128 encode the number + for (my $j = 0; $j < $tmp; $j++) { + my $b = oct("0b".substr($c, $j * 7, 7)); + + push @octets, $b | 0x80; + } + push @octets, oct("0b".substr($c, $tmp * 7, 7)); + } + + push @encoded_oids, \@octets; +} + +# +# Create a hash value for each OID +# +my @hash_values = (); +for (my $i = 0; $i <= $#names; $i++) { + my @octets = @{$encoded_oids[$i]}; + + my $hash = $#octets; + foreach (@octets) { + $hash += $_ * 33; + } + + $hash = ($hash >> 24) ^ ($hash >> 16) ^ ($hash >> 8) ^ ($hash); + + push @hash_values, $hash & 0xff; +} + +# +# Emit the OID data +# +print C_FILE "\n"; +print C_FILE "static const unsigned char oid_data[", $total_length, "] = {\n"; +for (my $i = 0; $i <= $#names; $i++) { + my @octets = @{$encoded_oids[$i]}; + print C_FILE "\t"; + print C_FILE $_, ", " foreach (@octets); + print C_FILE "\t// ", $names[$i]; + print C_FILE "\n"; +} +print C_FILE "};\n"; + +# +# Build the search index table (ordered by length then hash then content) +# +my @index_table = ( 0 .. $#names ); + +@index_table = sort { + my @octets_a = @{$encoded_oids[$a]}; + my @octets_b = @{$encoded_oids[$b]}; + + return $hash_values[$a] <=> $hash_values[$b] + if ($hash_values[$a] != $hash_values[$b]); + return $#octets_a <=> $#octets_b + if ($#octets_a != $#octets_b); + for (my $i = $#octets_a; $i >= 0; $i--) { + return $octets_a[$i] <=> $octets_b[$i] + if ($octets_a[$i] != $octets_b[$i]); + } + return 0; + +} @index_table; + +# +# Emit the search index and hash value table +# +print C_FILE "\n"; +print C_FILE "static const struct {\n"; +print C_FILE "\tunsigned char hash;\n"; +if ($#names <= 255) { + print C_FILE "\tenum OID oid : 8;\n"; +} else { + print C_FILE "\tenum OID oid : 16;\n"; +} +print C_FILE "} oid_search_table[OID__NR] = {\n"; +for (my $i = 0; $i <= $#names; $i++) { + my @octets = @{$encoded_oids[$index_table[$i]]}; + printf(C_FILE "\t[%3u] = { %3u, OID_%-35s }, // ", + $i, + $hash_values[$index_table[$i]], + $names[$index_table[$i]]); + printf C_FILE "%02x", $_ foreach (@octets); + print C_FILE "\n"; +} +print C_FILE "};\n"; + +# +# Emit the OID debugging name table +# +#print C_FILE "\n"; +#print C_FILE "const char *const oid_name_table[OID__NR + 1] = {\n"; +# +#for (my $i = 0; $i <= $#names; $i++) { +# print C_FILE "\t\"", $names[$i], "\",\n" +#} +#print C_FILE "\t\"Unknown-OID\"\n"; +#print C_FILE "};\n"; + +# +# Polish off +# +close C_FILE or die; |
