Bug 22370 - Incorrect note padding check
Summary: Incorrect note padding check
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: dynamic-link (show other bugs)
Version: 2.27
: P2 normal
Target Milestone: 2.27
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-10-31 00:19 UTC by H.J. Lu
Modified: 2018-04-07 13:38 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2017-10-31 00:19:59 UTC
open_verify has

     /* Check .note.ABI-tag if present.  */
      for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph)
        if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4)
          {
            ElfW(Addr) size = ph->p_filesz;

            if (ph->p_offset + size <= (size_t) fbp->len)
              abi_note = (void *) (fbp->buf + ph->p_offset);
            else
              {
                abi_note = alloca (size);
                __lseek (fd, ph->p_offset, SEEK_SET);
                if (__libc_read (fd, (void *) abi_note, size) != size)
                  goto read_error;
              } 

            while (memcmp (abi_note, &expected_note, sizeof (expected_note)))
              {
#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This works only when sizeof (ElfW(Word)) == ph->p_align.  Instead,
it should be replaced by ALIGN_UP (len, ph->align)

                ElfW(Addr) note_size = 3 * sizeof (ElfW(Word))
                                       + ROUND (abi_note[0])
                                       + ROUND (abi_note[1]);
            
                if (size - 32 < note_size)
                  {
                    size = 0;
                    break;
                  }
                size -= note_size;
                abi_note = (void *) abi_note + note_size;
              }
Comment 1 Sourceware Commits 2017-10-31 12:12:56 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, hjl/pr22370/master has been created
        at  69803aeeec234c8f754f805313402255c5342467 (commit)

- Log -----------------------------------------------------------------
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=69803aeeec234c8f754f805313402255c5342467

commit 69803aeeec234c8f754f805313402255c5342467
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Tue Oct 31 04:51:41 2017 -0700

    Replace ROUND with ALIGN_UP by p_align [BZ #22370]
    
    Alignment of notes in PT_NOTE segment is specified by the p_align field
    in the PT_NOTE segment header.  This patch replaces ROUND with ALIGN_UP
    by p_align to scan notes in PT_NOTE segment.
    
    	[BZ #22370]
    	* dl-hwcaps.c (ROUND): Removed.
    	(_dl_important_hwcaps): Replace ROUND with ALIGN_UP by p_align.
    	* elf/dl-load.c (ROUND): Removed.
    	(open_verify): Replace ROUND with ALIGN_UP by p_align.
    	* elf/readelflib.c (ROUND): Removed.
    	(process_elf_file): Replace ROUND with ALIGN_UP by p_align.

-----------------------------------------------------------------------
Comment 2 H.J. Lu 2017-11-16 11:55:16 UTC
According to gABI:

namesz and name
The first namesz bytes in name contain a null-terminated character representation of the entry's owner or originator. There is no formal mechanism for avoiding name conflicts. By convention, vendors use their own name, such as XYZ Computer Company, as the identifier. If no name is present, namesz contains 0. Padding is present, if necessary, to ensure 8 or 4-byte alignment for the descriptor (depending on whether the file is a 64-bit or 32-bit object). Such padding is not included in namesz.

descsz and desc
The first descsz bytes in desc hold the note descriptor. The ABI places no constraints on a descriptor's contents. If no descriptor is present, descsz contains 0. Padding is present, if necessary, to ensure 8 or 4-byte alignment for the next note entry (depending on whether the file is a 64-bit or 32-bit object). Such padding is not included in descsz.

Here the name field, not namesz, is padded for the note descriptor.  And
the desc field, not descsz, is padded for the next note entry.

But on Linux, .note.ABI-tag and .note.gnu.build-id notes are always aligned
to 4 bytes.  In this case, we should check segment alignment, instead of using
alignment based on 32-bit or 64-bit objects.
Comment 3 Sourceware Commits 2017-11-16 13:22:31 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, hjl/pr22370/master has been deleted
       was  69803aeeec234c8f754f805313402255c5342467

- Log -----------------------------------------------------------------
69803aeeec234c8f754f805313402255c5342467 Replace ROUND with ALIGN_UP by p_align [BZ #22370]
-----------------------------------------------------------------------
Comment 4 Sourceware Commits 2017-11-16 13:22:36 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, hjl/pr22370/master has been created
        at  0dfdda09f7b0faef5ff166f3e4e099b20571b76c (commit)

- Log -----------------------------------------------------------------
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=0dfdda09f7b0faef5ff166f3e4e099b20571b76c

commit 0dfdda09f7b0faef5ff166f3e4e099b20571b76c
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Tue Oct 31 04:51:41 2017 -0700

    Properly compute offsets of note descriptor and next note [BZ #22370]
    
    A note header has 3 4-bytes fields, followed by note name and note
    descriptor.  According to gABI, in a note entry, the note name field,
    not note name size, is padded for the note descriptor.  And the note
    descriptor field, not note descriptor size, is padded for the next
    note entry.  Notes are aligned to 4 bytes in 32-bit objects and 8 bytes
    in 64-bit objects.
    
    For all GNU notes, the name is "GNU" which is 4 bytes.  They have the
    same format in the first 16 bytes in both 32-bit and 64-bit objects.
    They differ by note descriptor size and note type.  So far, .note.ABI-tag
    and .note.gnu.build-id notes are always aligned to 4 bytes.  The exsting
    codes compute the note size by aligning the note name size and note
    descriptor size to 4 bytes.  It happens to produce the same value as
    the actual note size by luck since the name size is 4 and offset of the
    note descriptor is 16.  But it will produce the wrong size when note
    alignment is 8 bytes in 64-bit objects.
    
    This patch defines ELF_NOTE_DESC_OFFSET and ELF_NOTE_NEXT_OFFSET to
    properly compute offsets of note descriptor and next note.  It uses
    alignment of PT_NOTE segment to support both 4-byte and 8-byte note
    alignments in 64-bit objects.
    
    	[BZ #22370]
    	* dl-hwcaps.c (ROUND): Removed.
    	(_dl_important_hwcaps): Replace ROUND with ELF_NOTE_DESC_OFFSET
    	and ELF_NOTE_NEXT_OFFSET.
    	* elf/dl-load.c (ROUND): Removed.
    	(open_verify): Replace ROUND with ELF_NOTE_NEXT_OFFSET.
    	* elf/readelflib.c (ROUND): Removed.
    	(process_elf_file): Replace ROUND with ELF_NOTE_NEXT_OFFSET.
    	* include/elf.h [!_ISOMAC]: Include <libc-pointer-arith.h>.
    	[!_ISOMAC] (ELF_NOTE_DESC_OFFSET): New.
    	[!_ISOMAC] (ELF_NOTE_NEXT_OFFSET): Likewise.

-----------------------------------------------------------------------
Comment 5 Sourceware Commits 2017-11-25 14:34:10 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, hjl/pr22370/master has been deleted
       was  0dfdda09f7b0faef5ff166f3e4e099b20571b76c

- Log -----------------------------------------------------------------
0dfdda09f7b0faef5ff166f3e4e099b20571b76c Properly compute offsets of note descriptor and next note [BZ #22370]
-----------------------------------------------------------------------
Comment 6 Sourceware Commits 2017-11-25 14:34:16 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, hjl/pr22370/master has been created
        at  b7cfacca88269901546529445f0bb757107984b4 (commit)

- Log -----------------------------------------------------------------
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=b7cfacca88269901546529445f0bb757107984b4

commit b7cfacca88269901546529445f0bb757107984b4
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Tue Oct 31 04:51:41 2017 -0700

    Properly compute offsets of note descriptor and next note [BZ #22370]
    
    A note header has 3 4-bytes fields, followed by note name and note
    descriptor.  According to gABI, in a note entry, the note name field,
    not note name size, is padded for the note descriptor.  And the note
    descriptor field, not note descriptor size, is padded for the next
    note entry.  Notes are aligned to 4 bytes in 32-bit objects and 8 bytes
    in 64-bit objects.
    
    For all GNU notes, the name is "GNU" which is 4 bytes.  They have the
    same format in the first 16 bytes in both 32-bit and 64-bit objects.
    They differ by note descriptor size and note type.  So far, .note.ABI-tag
    and .note.gnu.build-id notes are always aligned to 4 bytes.  The exsting
    codes compute the note size by aligning the note name size and note
    descriptor size to 4 bytes.  It happens to produce the same value as
    the actual note size by luck since the name size is 4 and offset of the
    note descriptor is 16.  But it will produce the wrong size when note
    alignment is 8 bytes in 64-bit objects.
    
    This patch defines ELF_NOTE_DESC_OFFSET and ELF_NOTE_NEXT_OFFSET to
    properly compute offsets of note descriptor and next note.  It uses
    alignment of PT_NOTE segment to support both 4-byte and 8-byte note
    alignments in 64-bit objects.  To handle PT_NOTE segments with
    incorrect alignment, which may lead to an infinite loop, if segment
    alignment is less than 4, we treate alignment as 4 bytes.
    
    	[BZ #22370]
    	* elf/dl-hwcaps.c (ROUND): Removed.
    	(_dl_important_hwcaps): Replace ROUND with ELF_NOTE_DESC_OFFSET
    	and ELF_NOTE_NEXT_OFFSET.
    	* elf/dl-load.c (ROUND): Removed.
    	(open_verify): Replace ROUND with ELF_NOTE_NEXT_OFFSET.
    	* elf/readelflib.c (ROUND): Removed.
    	(process_elf_file): Replace ROUND with ELF_NOTE_NEXT_OFFSET.
    	* include/elf.h [!_ISOMAC]: Include <libc-pointer-arith.h>.
    	[!_ISOMAC] (ELF_NOTE_DESC_OFFSET): New.
    	[!_ISOMAC] (ELF_NOTE_NEXT_OFFSET): Likewise.

-----------------------------------------------------------------------
Comment 7 Sourceware Commits 2017-11-28 17:57:46 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  8d81ce0c6d6ca923571e8b2bac132929f9a02973 (commit)
      from  313ba4630f5f891af22bea9bdf9d9f3c88e49aee (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=8d81ce0c6d6ca923571e8b2bac132929f9a02973

commit 8d81ce0c6d6ca923571e8b2bac132929f9a02973
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Tue Nov 28 09:56:47 2017 -0800

    Properly compute offsets of note descriptor and next note [BZ #22370]
    
    A note header has 3 4-bytes fields, followed by note name and note
    descriptor.  According to gABI, in a note entry, the note name field,
    not note name size, is padded for the note descriptor.  And the note
    descriptor field, not note descriptor size, is padded for the next
    note entry.  Notes are aligned to 4 bytes in 32-bit objects and 8 bytes
    in 64-bit objects.
    
    For all GNU notes, the name is "GNU" which is 4 bytes.  They have the
    same format in the first 16 bytes in both 32-bit and 64-bit objects.
    They differ by note descriptor size and note type.  So far, .note.ABI-tag
    and .note.gnu.build-id notes are always aligned to 4 bytes.  The exsting
    codes compute the note size by aligning the note name size and note
    descriptor size to 4 bytes.  It happens to produce the same value as
    the actual note size by luck since the name size is 4 and offset of the
    note descriptor is 16.  But it will produce the wrong size when note
    alignment is 8 bytes in 64-bit objects.
    
    This patch defines ELF_NOTE_DESC_OFFSET and ELF_NOTE_NEXT_OFFSET to
    properly compute offsets of note descriptor and next note.  It uses
    alignment of PT_NOTE segment to support both 4-byte and 8-byte note
    alignments in 64-bit objects.  To handle PT_NOTE segments with
    incorrect alignment, which may lead to an infinite loop, if segment
    alignment is less than 4, we treate alignment as 4 bytes since some
    note segments have 0 or 1 byte alignment.
    
    	[BZ #22370]
    	* elf/dl-hwcaps.c (ROUND): Removed.
    	(_dl_important_hwcaps): Replace ROUND with ELF_NOTE_DESC_OFFSET
    	and ELF_NOTE_NEXT_OFFSET.
    	* elf/dl-load.c (ROUND): Removed.
    	(open_verify): Replace ROUND with ELF_NOTE_NEXT_OFFSET.
    	* elf/readelflib.c (ROUND): Removed.
    	(process_elf_file): Replace ROUND with ELF_NOTE_NEXT_OFFSET.
    	* include/elf.h [!_ISOMAC]: Include <libc-pointer-arith.h>.
    	[!_ISOMAC] (ELF_NOTE_DESC_OFFSET): New.
    	[!_ISOMAC] (ELF_NOTE_NEXT_OFFSET): Likewise.

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog        |   14 ++++++++++++++
 elf/dl-hwcaps.c  |   24 ++++++++++++++++++------
 elf/dl-load.c    |   19 +++++++++++++++----
 elf/readelflib.c |   19 +++++++++++++++----
 include/elf.h    |   16 ++++++++++++++--
 5 files changed, 76 insertions(+), 16 deletions(-)
Comment 8 H.J. Lu 2017-11-28 18:08:39 UTC
Fixed for 2.27.
Comment 9 Sourceware Commits 2018-04-07 13:38:57 UTC
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, hjl/pr22370/master has been deleted
       was  b7cfacca88269901546529445f0bb757107984b4

- Log -----------------------------------------------------------------
b7cfacca88269901546529445f0bb757107984b4 Properly compute offsets of note descriptor and next note [BZ #22370]
-----------------------------------------------------------------------