Skip to content

libwifi_remove_tag cause corruption #24

@solsticedhiver

Description

@solsticedhiver

libwifi_remove_tag implementation is incorrect and causes various corruption or bug.

Here is a proof of concept that shows the various issues:
test_libwifi_remove_tag.c.txt

  • deleting the last tag, gives an error:

    $ ./test_libwifi_remove_tag remove_last
    removing Vendor tag; tags length: 168, expected new tag length: 142
    mremap_chunk(): invalid pointer
    Abandon (core dumped)
    
  • deleting the ssid tag, gives a corruption:

    $ ./test_libwifi_remove_tag remove_ssid
    removing ssid tag; tags length: 168, expected new tag length: 154
    new probe_resp.tags.length: 165
    
  • delting and adding back the same tag does not give a consitent tags length over all:

    $ ./test_libwifi_remove_tag
    removing HT_OPERATION tag; tags length: 168, expected new tag length: 144
    new probe_resp.tags.length: 2
    adding back the same HT_OPERATION tag; tags length: 2, expected new tag length: 26
    probe_resp.tags.length: 26
    

I think, there are 3 issues in the code of libwifi_remove_tag:

  • line 70, memcpy is copying the remaining data over the first half of the tag data, corrupting them in the process.
    The data should be copied not to tags->parameters pointer aka the start of all the data tags, but to it.tag_data - sizeof(struct libwifi_tag_header) aka the start of the current tag.
  • still using the it pointer after memcpy returns data that are not the ones expected. hence, new_len should be defined before the memcpy instruction.
  • copy_len is too big (which gives the error when removing the last tag). it should not contain sizeof(struct libwifi_tag_header)

So I think that the following patch should be used to fix that:

--- src/libwifi/core/frame/tag.c        2024-11-11 19:22:36.381371022 +0100
+++ src/libwifi/core/frame/tag.c.new    2024-11-11 19:22:19.324833442 +0100
@@ -66,9 +66,9 @@
             // how many bytes to shrink the tagged parameter list by
             size_t copy_len = tags->length -
                               (it.tag_data - tags->parameters) -
-                              (it.tag_header->tag_len + sizeof(struct libwifi_tag_header));
+                              it.tag_header->tag_len;
-            memcpy(tags->parameters, it.tag_data + it.tag_header->tag_len, copy_len);
             size_t new_len = tags->length - it.tag_header->tag_len - sizeof(struct libwifi_tag_header);
+            memcpy((unsigned char *)it.tag_data - sizeof(struct libwifi_tag_header), it.tag_data + it.tag_header->tag_len, copy_len);
             tags->parameters = realloc(tags->parameters, new_len);
             tags->length = new_len;
             break;

At least the code of concept above test_libwifi_remove_tag gives no error and the expected output when compiled against a libwifi compiled with the patch

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions