1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-05 19:35:52 +03:00

Check multiple NT_GNU_PROPERTY_TYPE_0 notes [BZ #23509]

Linkers group input note sections with the same name into one output
note section with the same name.  One output note section is placed in
one PT_NOTE segment.  Since new linkers merge input .note.gnu.property
sections into one output .note.gnu.property section, there is only
one NT_GNU_PROPERTY_TYPE_0 note in one PT_NOTE segment with new linkers.
Since older linkers treat input .note.gnu.property section as a generic
note section and just concatenate all input .note.gnu.property sections
into one output .note.gnu.property section without merging them, we may
see multiple NT_GNU_PROPERTY_TYPE_0 notes in one PT_NOTE segment with
older linkers.

When an older linker is used to created the program on CET-enabled OS,
the linker output has a single .note.gnu.property section with multiple
NT_GNU_PROPERTY_TYPE_0 notes, some of which have IBT and SHSTK enable
bits set even if the program isn't CET enabled.  Such programs will
crash on CET-enabled machines.  This patch updates the note parser:

1. Skip note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed.
2. Check multiple NT_GNU_PROPERTY_TYPE_0 notes.

	[BZ #23509]
	* sysdeps/x86/dl-prop.h (_dl_process_cet_property_note): Skip
	note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed.
	Update the l_cet field when processing NT_GNU_PROPERTY_TYPE_0 note.
	Check multiple NT_GNU_PROPERTY_TYPE_0 notes.
	* sysdeps/x86/link_map.h (l_cet): Expand to 3 bits,  Add
	lc_unknown.
This commit is contained in:
H.J. Lu
2018-11-08 10:06:58 -08:00
parent ac8060265b
commit d524fa6c35
3 changed files with 56 additions and 14 deletions

View File

@@ -1,3 +1,13 @@
2018-11-08 H.J. Lu <hongjiu.lu@intel.com>
[BZ #23509]
* sysdeps/x86/dl-prop.h (_dl_process_cet_property_note): Skip
note parsing if a NT_GNU_PROPERTY_TYPE_0 note has been processed.
Update the l_cet field when processing NT_GNU_PROPERTY_TYPE_0 note.
Check multiple NT_GNU_PROPERTY_TYPE_0 notes.
* sysdeps/x86/link_map.h (l_cet): Expand to 3 bits, Add
lc_unknown.
2018-11-08 Alexandra Hájková <ahajkova@redhat.com> 2018-11-08 Alexandra Hájková <ahajkova@redhat.com>
[BZ #17630] [BZ #17630]

View File

@@ -49,6 +49,10 @@ _dl_process_cet_property_note (struct link_map *l,
const ElfW(Addr) align) const ElfW(Addr) align)
{ {
#if CET_ENABLED #if CET_ENABLED
/* Skip if we have seen a NT_GNU_PROPERTY_TYPE_0 note before. */
if (l->l_cet != lc_unknown)
return;
/* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in /* The NT_GNU_PROPERTY_TYPE_0 note must be aliged to 4 bytes in
32-bit objects and to 8 bytes in 64-bit objects. Skip notes 32-bit objects and to 8 bytes in 64-bit objects. Skip notes
with incorrect alignment. */ with incorrect alignment. */
@@ -57,6 +61,9 @@ _dl_process_cet_property_note (struct link_map *l,
const ElfW(Addr) start = (ElfW(Addr)) note; const ElfW(Addr) start = (ElfW(Addr)) note;
unsigned int feature_1 = 0;
unsigned int last_type = 0;
while ((ElfW(Addr)) (note + 1) - start < size) while ((ElfW(Addr)) (note + 1) - start < size)
{ {
/* Find the NT_GNU_PROPERTY_TYPE_0 note. */ /* Find the NT_GNU_PROPERTY_TYPE_0 note. */
@@ -64,10 +71,18 @@ _dl_process_cet_property_note (struct link_map *l,
&& note->n_type == NT_GNU_PROPERTY_TYPE_0 && note->n_type == NT_GNU_PROPERTY_TYPE_0
&& memcmp (note + 1, "GNU", 4) == 0) && memcmp (note + 1, "GNU", 4) == 0)
{ {
/* Stop if we see more than one GNU property note which may
be generated by the older linker. */
if (l->l_cet != lc_unknown)
return;
/* Check CET status now. */
l->l_cet = lc_none;
/* Check for invalid property. */ /* Check for invalid property. */
if (note->n_descsz < 8 if (note->n_descsz < 8
|| (note->n_descsz % sizeof (ElfW(Addr))) != 0) || (note->n_descsz % sizeof (ElfW(Addr))) != 0)
break; return;
/* Start and end of property array. */ /* Start and end of property array. */
unsigned char *ptr = (unsigned char *) (note + 1) + 4; unsigned char *ptr = (unsigned char *) (note + 1) + 4;
@@ -78,9 +93,15 @@ _dl_process_cet_property_note (struct link_map *l,
unsigned int type = *(unsigned int *) ptr; unsigned int type = *(unsigned int *) ptr;
unsigned int datasz = *(unsigned int *) (ptr + 4); unsigned int datasz = *(unsigned int *) (ptr + 4);
/* Property type must be in ascending order. */
if (type < last_type)
return;
ptr += 8; ptr += 8;
if ((ptr + datasz) > ptr_end) if ((ptr + datasz) > ptr_end)
break; return;
last_type = type;
if (type == GNU_PROPERTY_X86_FEATURE_1_AND) if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
{ {
@@ -89,14 +110,18 @@ _dl_process_cet_property_note (struct link_map *l,
we stop the search regardless if its size is correct we stop the search regardless if its size is correct
or not. There is no point to continue if this note or not. There is no point to continue if this note
is ill-formed. */ is ill-formed. */
if (datasz == 4) if (datasz != 4)
{ return;
unsigned int feature_1 = *(unsigned int *) ptr;
if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT)) feature_1 = *(unsigned int *) ptr;
l->l_cet |= lc_ibt;
if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK)) /* Keep searching for the next GNU property note
l->l_cet |= lc_shstk; generated by the older linker. */
} break;
}
else if (type > GNU_PROPERTY_X86_FEATURE_1_AND)
{
/* Stop since property type is in ascending order. */
return; return;
} }
@@ -112,6 +137,12 @@ _dl_process_cet_property_note (struct link_map *l,
+ ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz, + ELF_NOTE_NEXT_OFFSET (note->n_namesz, note->n_descsz,
align)); align));
} }
/* We get here only if there is one or no GNU property note. */
if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_IBT))
l->l_cet |= lc_ibt;
if ((feature_1 & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
l->l_cet |= lc_shstk;
#endif #endif
} }

View File

@@ -19,8 +19,9 @@
/* If this object is enabled with CET. */ /* If this object is enabled with CET. */
enum enum
{ {
lc_none = 0, /* Not enabled with CET. */ lc_unknown = 0, /* Unknown CET status. */
lc_ibt = 1 << 0, /* Enabled with IBT. */ lc_none = 1 << 0, /* Not enabled with CET. */
lc_shstk = 1 << 1, /* Enabled with STSHK. */ lc_ibt = 1 << 1, /* Enabled with IBT. */
lc_shstk = 1 << 2, /* Enabled with STSHK. */
lc_ibt_and_shstk = lc_ibt | lc_shstk /* Enabled with both. */ lc_ibt_and_shstk = lc_ibt | lc_shstk /* Enabled with both. */
} l_cet:2; } l_cet:3;