On 2023/06/07 23:57, Yann Sionneau wrote:
> Hello uClibc-ng hackers, Damien, Rich,
>
> I am sending this email to discuss the possibility to revert
> https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/commit/?id=08d46f1ce21e4e…
>
> I think this change is wrong, I have been tracking an issue for a few
> days and I am pretty sure the issue comes from this commit.
>
> Basically what happens is that with this commit, tst-cancel18 test is
> failing.
>
> The test is available over there:
> https://github.com/wbx-github/uclibc-ng-test/blob/master/test/nptl/tst-canc…
>
> The reason for this fail is that clock_nanosleep code from libc is badly
> compiled:
> https://elixir.bootlin.com/uclibc-ng/latest/source/librt/clock_nanosleep.c#…
>
> Because SINGLE_THREAD_P is actually defined, in case your libc build
> supports NPTL threads (which is, I think, the majority of configs,
> except very old systems using LINUXTHREADS or NOMMU maybe).
>
> In my case (kvx arch):
>
> #define SINGLE_THREAD_P __builtin_expect (THREAD_GETMEM (THREAD_SELF,
> header.multiple_threads) == 0, 1)
>
> See:
> https://elixir.bootlin.com/uclibc-ng/latest/source/libpthread/nptl/sysdeps/…
>
> This results to clock_nanosleep code being compiled to a very simple
> version that directly calls the syscall and does not change at all the
> thread cancellability to asynchronous before calling the syscall.
>
> Therefore, when the test main thread calls pthread_cancel(), no signal
> is sent (see
> https://elixir.bootlin.com/uclibc-ng/latest/source/libpthread/nptl/pthread_…)
> and therefore the nanosleep syscall is never interrupted and the test fails.
>
> clock_nanosleep is defined to be a mandatory cancellation point by
> POSIX, it must be interruptible in all cases by pthread_cancel, whether
> in synchronous or asynchronous mode.
>
> I think the fix for the NOMMU case should be different, maybe checking
> for if LIBC_CANCEL_ASYNC is defined ?
>
> Damien do you have time to work on a new fix for the NOMMU case? Are you
> OK with the revert?
Not OK with a revert as that will bring back the compilation errors for RISC-V
NOMMU case.
Instead, please work on a fix for your case on top of the current code. If I
recall correctly, the code around this is rather messy with lots of ifdefs,
which may be why this regression was introduced. Cleaning up the code first to
avoid that may help avoiding further issues in the future.
Note that to test patches/regressions for risc-v NOMMU builds, you can simply
use buildroot and run:
make sipeed_maix_bit_defconfig
make
To check that it builds.
>
> Can someone confirm my analysis here?
>
> Thanks!
>
> Best regards,
>
--
Damien Le Moal
Western Digital Research
Recently I tried compiling QEMU user emulation with uClibc on Aarch64,
and found the 'futimesat' symbol was missing (but still defined in
headers).
This emulation is similar to the 'lutimesat' emulation.
Regards,
Elliot.
Hi,
I have a problem linking uClibc-ng for riscv64 with binutils 2.40.
I get following error:
/home/wbx/openadk/toolchain_qemu-riscv64_uclibc-ng/usr/bin/riscv64-openadk-linux-uclibc-gcc
-Wl,-EL -shared -Wl,--warn-common -Wl,--warn-once -Wl,-z,combreloc
-Wl,-z,relro -Wl,-O2 -Wl,-z,defs
-L/home/wbx/openadk/target_qemu-riscv64_uclibc-ng/lib
-L/home/wbx/openadk/target_qemu-riscv64_uclibc-ng/usr/lib -Wl,-O1
-Wl,-rpath -Wl,/usr/lib -Wl,-rpath-link
-Wl,/home/wbx/openadk/target_qemu-riscv64_uclibc-ng/usr/lib
-Wl,-init,__uClibc_init -Wl,-soname=libc.so.1 -nostdlib
-nostartfiles -o lib/libuClibc-1.0.42.so -Wl,--whole-archive
libc/libc_so.a -Wl,--no-whole-archive ./lib/interp.os
./lib/ld-uClibc.so.1 ./lib/uclibc_nonshared.a
./lib/libpthread_nonshared.a
/home/wbx/openadk/toolchain_qemu-riscv64_uclibc-ng/usr/lib/gcc/riscv64-openadk-linux-uclibc/11.3.0/libgcc.a
/home/wbx/openadk/toolchain_qemu-riscv64_uclibc-ng/usr/lib/gcc/riscv64-openadk-linux-uclibc/11.3.0/../../../../riscv64-openadk-linux-uclibc/bin/ld:
relocation R_RISCV_RVC_JUMP against `__sigsetjmp' which may bind
externally can not be used when making a shared object; recompile
with -fPIC
collect2: error: ld returned 1 exit status
gmake[6]: *** [libc/Makefile.in:77: lib/libc.so] Error 1
I found this commit in glibc:
https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=68389203832ab39dd0db…
But it does not work here. Anyone an idea how to fix it?
best regards
Waldemar
Hello,
Attached is a patch addressing CVE-2022-29503. After extensive testing, I
wasn't able to trigger the bug as described in the reference articles. In
my testing, the only way to trigger this bug is to modify
PTHREAD_THREADS_MAX to allow enough threads to exhaust the address space.
It is however possible that some custom configurations have small enough
memory spaces which allow this to become an issue.
Since this is a problem of mmap'ing overtop of existing mapped pages, I
have elected to take advantage of the new MAP_FIXED_NOREPLACE flag and its
associated guidance for backporting. I define it to 0 at the top of
manager.c if it isn't defined to support older kernels.
From 2b11aa00bd3b637c5c96db39538952dd12514085 Mon Sep 17 00:00:00 2001
From: linted <linted(a)users.noreply.github.com>
Date: Sat, 21 Jan 2023 15:22:48 -0500
Subject: [PATCH 1/2] Fix for CVE-2022-29503. Changed linux thread's stack
allocation mmap to use new MAP_FIXED_NOREPLACE flag on kernels >4.17. For
older kernels, a check is added to see if requested address matches the
address received. If the addresses don't match, an error is returned and
thread creation is aborted.
Signed-off-by: linted <linted(a)users.noreply.github.com>
---
libpthread/linuxthreads/manager.c | 35 ++++++++++++++++++++++++++-----
1 file changed, 30 insertions(+), 5 deletions(-)
diff --git a/libpthread/linuxthreads/manager.c
b/libpthread/linuxthreads/manager.c
index 2a1ee62af..122997b10 100644
--- a/libpthread/linuxthreads/manager.c
+++ b/libpthread/linuxthreads/manager.c
@@ -47,6 +47,15 @@
# define USE_SELECT
#endif
+/* MAP_FIXED_NOREPLACE is not supported in kernel <= 4.17
+ * If it's not already defined, define it to 0.
+ * We check the results of mmap to ensure the correct
+ * results, and error out otherwise.
+ */
+#ifndef MAP_FIXED_NOREPLACE
+#define MAP_FIXED_NOREPLACE 0
+#endif
+
/* Array of active threads. Entry 0 is reserved for the initial thread. */
struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] =
{ { __LOCK_INITIALIZER, &__pthread_initial_thread, 0},
@@ -371,12 +380,19 @@ static int pthread_allocate_stack(const
pthread_attr_t *attr,
/* Allocate space for stack and thread descriptor at default address
*/
new_thread = default_new_thread;
new_thread_bottom = (char *) (new_thread + 1) - stacksize;
- if (mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE),
+ void * new_stack_addr = NULL;
+ new_stack_addr = mmap((caddr_t)((char *)(new_thread + 1) -
INITIAL_STACK_SIZE),
INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN,
- -1, 0) == MAP_FAILED)
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE |
MAP_GROWSDOWN,
+ -1, 0);
+ if (new_stack_addr == MAP_FAILED){
/* Bad luck, this segment is already mapped. */
return -1;
+ } else if ( new_stack_addr != (caddr_t)((char *)(new_thread + 1) -
INITIAL_STACK_SIZE)) {
+ /* Worse luck, we almost overwrote an existing page */
+ munmap(new_stack_addr, INITIAL_STACK_SIZE);
+ return -2;
+ }
/* We manage to get a stack. Now see whether we need a guard
and allocate it if necessary. Notice that the default
attributes (stack_size = STACK_SIZE - pagesize) do not need
@@ -496,9 +512,10 @@ static int pthread_handle_create(pthread_t *thread,
const pthread_attr_t *attr,
return EAGAIN;
if (__pthread_handles[sseg].h_descr != NULL)
continue;
- if (pthread_allocate_stack(attr, thread_segment(sseg), pagesize,
+ int res = pthread_allocate_stack(attr, thread_segment(sseg),
pagesize,
&new_thread, &new_thread_bottom,
- &guardaddr, &guardsize) == 0)
+ &guardaddr, &guardsize);
+ if ( res == 0)
break;
#ifndef __ARCH_USE_MMU__
else
@@ -507,6 +524,14 @@ static int pthread_handle_create(pthread_t *thread,
const pthread_attr_t *attr,
* use the next one. However, when there is no MMU, malloc () is
used.
* It's waste of CPU cycles to continue to try if it fails. */
return EAGAIN;
+#else
+ else if (res == -2)
+ /* When there is an MMU, if pthread_allocate_stack failed with -2,
+ * it indicates that we are attempting to mmap in address space
which
+ * is already allocated. Any additional attempts will result in
failure
+ * since we have exhausted our stack area.
+ */
+ return EAGAIN;
#endif
}
__pthread_handles_num++;
--
2.34.1