https://sourceware.org/bugzilla/show_bug.cgi?id=34901

            Bug ID: 34901
           Summary: bfd: archive member name "/x1" is accepted as
                    extended-name index 0; in a thin archive it resolves
                    to a different member's file
           Product: binutils
           Version: 2.48 (HEAD)
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: binutils
          Assignee: unassigned at sourceware dot org
          Reporter: martin.mirchev at u dot nus.edu
  Target Milestone: ---

get_extended_arelt_filename() (bfd/archive.c) parses the index after '/' with
strtol() and checks only errno and the upper bound:

    485   table_index = strtol (name + 1, (char **) &endp, 10);
    486   if (errno != 0 || table_index >= bfd_ardata
(arch)->extended_names_size)

For a name such as "/x1", strtol consumes nothing, returns 0 and leaves errno
at 0, so the member takes extended_names[0], the first member's name. In a thin
archive that name is the path that gets opened (open_nested_file,
archive.c:760), so tools silently use a different file than the header
describes. Out-of-range indices ("/92", "/-2") are already rejected as
"malformed archive".

Tested on master 1ec1cee48577c7b1960ddce5a6054b3f9fab6ef5. Release: Ubuntu
22.04 gcc 11 -g -O2. ASan: -O1 -g -fsanitize=address,undefined.

Reproducer (attached mk-thin.sh): builds sub/one.o (defines one), two.o
(defines two) and main.o (calls two), runs "ar rcsT lib.a sub/one.o two.o",
then copies lib.a to lib-bad.a with the second member's name "/11" changed to
"/x1" (one byte).

  $ ar t lib.a              ->  sub/one.o  two.o
  $ ar t lib-bad.a          ->  sub/one.o  sub/one.o
  $ nm lib-bad.a            ->  member 2 is listed as sub/one.o with symbol
"one"
  $ ld -o p main.o lib.a    (exit 0)
  $ ld -o p main.o lib-bad.a
  main.c:(.text+0x9): undefined reference to `two'     (exit 1)
  $ ld -o q main.o --whole-archive lib-bad.a
  one.c:(.text+0x0): multiple definition of `one'; sub/one.o:one.c:(.text+0x0):
first defined here
  (exit 1)

ld follows the armap entry for "two" to member 2 and loads sub/one.o instead
of two.o. If the substituted file also defines the requested symbols, the link
succeeds with no diagnostic. ASan and valgrind are clean: this is a parsing
bug, not a memory error.

The name should be rejected as a malformed archive unless at least one digit
follows the '/' (i.e. check that strtol consumed something).

This issue was found by an LLM-Enhanced Static Analysis Engine and verified
manually.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Reply via email to