Message ID | 20241110112252.616754-1-aurelien@aurel32.net |
---|---|
State | New |
Headers | show |
Series | elf: handle addition overflow in _dl_find_object_update_1 [BZ #32345] | expand |
* Aurelien Jarno: > Theoretically, current_used + count can wrap around to zero without > undefined behaviour. Sorry, I don't see how. These are counts of link maps (among other things). Link maps have byte sizes larger than 1, so two counts of allocated link maps always fit into a size_t value without wrapping around. > This is caught by GCC 14+ on hppa, which determines > from there that target_seg could be be NULL when remaining_to_add is > zero, which in turns causes a -Wstringop-overflow warning: > > In file included from ../include/atomic.h:49, > from dl-find_object.c:20: > In function '_dlfo_update_init_seg', > inlined from '_dl_find_object_update_1' at dl-find_object.c:689:30, > inlined from '_dl_find_object_update' at dl-find_object.c:805:13: > ../sysdeps/unix/sysv/linux/hppa/atomic-machine.h:44:4: error: '__atomic_store_4' writing 4 bytes into a region of size 0 overflows the destination [-Werror=stringop-overflow=] > 44 | __atomic_store_n ((mem), (val), __ATOMIC_RELAXED); \ > | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > dl-find_object.c:644:3: note: in expansion of macro 'atomic_store_relaxed' > 644 | atomic_store_relaxed (&seg->size, new_seg_size); > | ^~~~~~~~~~~~~~~~~~~~ > In function '_dl_find_object_update': > cc1: note: destination object is likely at address zero What is HPPA doing that triggers this warning? Clone some path? Maybe we can tell the compiler that the path is unreachable (with a suitable comment)? if (__builtin_add_overflow(current_used, count, &remaining_to_add)) __builtin_unreachable ();
Patch fixes build on hppa. But I agree with Florian that the overflow is impossible. I think Florian's suggestion will work. Dave On 2024-11-10 6:22 a.m., Aurelien Jarno wrote: > Theoretically, current_used + count can wrap around to zero without > undefined behaviour. This is caught by GCC 14+ on hppa, which determines > from there that target_seg could be be NULL when remaining_to_add is > zero, which in turns causes a -Wstringop-overflow warning: > > In file included from ../include/atomic.h:49, > from dl-find_object.c:20: > In function '_dlfo_update_init_seg', > inlined from '_dl_find_object_update_1' at dl-find_object.c:689:30, > inlined from '_dl_find_object_update' at dl-find_object.c:805:13: > ../sysdeps/unix/sysv/linux/hppa/atomic-machine.h:44:4: error: '__atomic_store_4' writing 4 bytes into a region of size 0 overflows the destination [-Werror=stringop-overflow=] > 44 | __atomic_store_n ((mem), (val), __ATOMIC_RELAXED); \ > | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > dl-find_object.c:644:3: note: in expansion of macro 'atomic_store_relaxed' > 644 | atomic_store_relaxed (&seg->size, new_seg_size); > | ^~~~~~~~~~~~~~~~~~~~ > In function '_dl_find_object_update': > cc1: note: destination object is likely at address zero > > Fix that by doing the addition using __builtin_add_overflow and > returning false in the unlikely case an overflow happens. > > Thanks to Andreas Schwab for the investigation. > > Closes: BZ #32345 > Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> > --- > elf/dl-find_object.c | 6 +++++- > 1 file changed, 5 insertions(+), 1 deletion(-) > > diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c > index 449302eda3..c51a9711c9 100644 > --- a/elf/dl-find_object.c > +++ b/elf/dl-find_object.c > @@ -660,7 +660,11 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count) > > struct dlfo_mappings_segment *target_seg > = _dlfo_loaded_mappings[!active_idx]; > - size_t remaining_to_add = current_used + count; > + size_t remaining_to_add; > + > + if (__glibc_unlikely (__builtin_add_overflow(current_used, count, &remaining_to_add))) > + /* Out of memory if remaining_to_add does not fit in a size_t type */ > + return false; > > /* Ensure that the new segment chain has enough space. */ > {
On Nov 10 2024, Aurelien Jarno wrote: > diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c > index 449302eda3..c51a9711c9 100644 > --- a/elf/dl-find_object.c > +++ b/elf/dl-find_object.c > @@ -660,7 +660,11 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count) > > struct dlfo_mappings_segment *target_seg > = _dlfo_loaded_mappings[!active_idx]; > - size_t remaining_to_add = current_used + count; > + size_t remaining_to_add; > + > + if (__glibc_unlikely (__builtin_add_overflow(current_used, count, &remaining_to_add))) > + /* Out of memory if remaining_to_add does not fit in a size_t type */ > + return false; Does it work to assert that remaining_to_add != 0?
On 2024-11-10 22:23, Florian Weimer wrote: > * Aurelien Jarno: > > > Theoretically, current_used + count can wrap around to zero without > > undefined behaviour. > > Sorry, I don't see how. These are counts of link maps (among other > things). Link maps have byte sizes larger than 1, so two counts of > allocated link maps always fit into a size_t value without wrapping > around. Theoretically means from the C code point of view, but I agree with you that it can't happen when looking at the whole picture (that GCC can't see). > > This is caught by GCC 14+ on hppa, which determines > > from there that target_seg could be be NULL when remaining_to_add is > > zero, which in turns causes a -Wstringop-overflow warning: > > > > In file included from ../include/atomic.h:49, > > from dl-find_object.c:20: > > In function '_dlfo_update_init_seg', > > inlined from '_dl_find_object_update_1' at dl-find_object.c:689:30, > > inlined from '_dl_find_object_update' at dl-find_object.c:805:13: > > ../sysdeps/unix/sysv/linux/hppa/atomic-machine.h:44:4: error: '__atomic_store_4' writing 4 bytes into a region of size 0 overflows the destination [-Werror=stringop-overflow=] > > 44 | __atomic_store_n ((mem), (val), __ATOMIC_RELAXED); \ > > | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > > dl-find_object.c:644:3: note: in expansion of macro 'atomic_store_relaxed' > > 644 | atomic_store_relaxed (&seg->size, new_seg_size); > > | ^~~~~~~~~~~~~~~~~~~~ > > In function '_dl_find_object_update': > > cc1: note: destination object is likely at address zero > > What is HPPA doing that triggers this warning? Clone some path? Not clear to me why this is limited to HPPA. I only know this issue is new in GCC 14. > Maybe we can tell the compiler that the path is unreachable (with a > suitable comment)? > > if (__builtin_add_overflow(current_used, count, &remaining_to_add)) > __builtin_unreachable (); Unfortunately this does not work. On the other hand this one works: if (remaining_to_add == 0) __builtin_unreachable ();
On 2024-11-11 10:04, Andreas Schwab wrote: > On Nov 10 2024, Aurelien Jarno wrote: > > > diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c > > index 449302eda3..c51a9711c9 100644 > > --- a/elf/dl-find_object.c > > +++ b/elf/dl-find_object.c > > @@ -660,7 +660,11 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count) > > > > struct dlfo_mappings_segment *target_seg > > = _dlfo_loaded_mappings[!active_idx]; > > - size_t remaining_to_add = current_used + count; > > + size_t remaining_to_add; > > + > > + if (__glibc_unlikely (__builtin_add_overflow(current_used, count, &remaining_to_add))) > > + /* Out of memory if remaining_to_add does not fit in a size_t type */ > > + return false; > > Does it work to assert that remaining_to_add != 0? Yep, that works. However Joseph commented in the bug report that we want glibc to build even with -DNDEBUG, so an assert is not enough. As answered to Florian, this one works: if (remaining_to_add == 0) __builtin_unreachable ();
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c index 449302eda3..c51a9711c9 100644 --- a/elf/dl-find_object.c +++ b/elf/dl-find_object.c @@ -660,7 +660,11 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count) struct dlfo_mappings_segment *target_seg = _dlfo_loaded_mappings[!active_idx]; - size_t remaining_to_add = current_used + count; + size_t remaining_to_add; + + if (__glibc_unlikely (__builtin_add_overflow(current_used, count, &remaining_to_add))) + /* Out of memory if remaining_to_add does not fit in a size_t type */ + return false; /* Ensure that the new segment chain has enough space. */ {
Theoretically, current_used + count can wrap around to zero without undefined behaviour. This is caught by GCC 14+ on hppa, which determines from there that target_seg could be be NULL when remaining_to_add is zero, which in turns causes a -Wstringop-overflow warning: In file included from ../include/atomic.h:49, from dl-find_object.c:20: In function '_dlfo_update_init_seg', inlined from '_dl_find_object_update_1' at dl-find_object.c:689:30, inlined from '_dl_find_object_update' at dl-find_object.c:805:13: ../sysdeps/unix/sysv/linux/hppa/atomic-machine.h:44:4: error: '__atomic_store_4' writing 4 bytes into a region of size 0 overflows the destination [-Werror=stringop-overflow=] 44 | __atomic_store_n ((mem), (val), __ATOMIC_RELAXED); \ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ dl-find_object.c:644:3: note: in expansion of macro 'atomic_store_relaxed' 644 | atomic_store_relaxed (&seg->size, new_seg_size); | ^~~~~~~~~~~~~~~~~~~~ In function '_dl_find_object_update': cc1: note: destination object is likely at address zero Fix that by doing the addition using __builtin_add_overflow and returning false in the unlikely case an overflow happens. Thanks to Andreas Schwab for the investigation. Closes: BZ #32345 Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> --- elf/dl-find_object.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)