CTSRD-CHERI / cheribsd

FreeBSD adapted for CHERI-RISC-V and Arm Morello.
http://cheribsd.org
Other
163 stars 59 forks source link

When linking with -pthread errno is non-zero on startup #1424

Open arichardson opened 2 years ago

arichardson commented 2 years ago

I don't believe errno has to be zero at the start of main(), but this is causing some testsuites to fail (I noticed this in epoll-shim).

Using the following test program:

#include <errno.h>
#include <stdio.h>
#include <string.h>

int main() {
    printf("errno on startup=%d (%s)\n", errno, strerror(errno));
    return 0;
}
$ cc -o /tmp/errno /tmp/errno.c && /tmp/errno
errno on startup=0 (No error: 0)
$ cc -o /tmp/errno /tmp/errno.c -pthread && /tmp/errno
errno on startup=98 (Memory protection violation)

This happens because of the mprotect call here: https://github.com/CTSRD-CHERI/cheribsd/blob/6a9e74b4bd73bef8cffdb0f134fc657fed60e029/lib/libthr/thread/thr_rtld.c#L235

Should we reset errno to zero after this call or try to find some mprotect arguments that don't result in an error?

jrtc27 commented 2 years ago

The value of errno is zero at program startup, but is never set to zero by any library function.

C99 7.5p3

arichardson commented 2 years ago

The value of errno is zero at program startup, but is never set to zero by any library function.

C99 7.5p3

I guess I can drop that workaround then :)

brooksdavis commented 2 years ago

Short of allocating a page with mmap to operate on, I'm having a hard time coming up with a path at an mprotect call that doesn't error. I think just resetting errno seems fine (unless _thr_rtld_init can be called as a result of dlopen?)

brooksdavis commented 2 years ago

Short of allocating a page with mmap to operate on, I'm having a hard time coming up with a path at an mprotect call that doesn't error. I think just resetting errno seems fine (unless _thr_rtld_init can be called as a result of dlopen?)

Probably OK to save and restore around the call regardless.

arichardson commented 2 years ago

Short of allocating a page with mmap to operate on, I'm having a hard time coming up with a path at an mprotect call that doesn't error. I think just resetting errno seems fine (unless _thr_rtld_init can be called as a result of dlopen?)

My guess is that it worked because upstream treats size==0 as a no-op? But I agree saving+restoring errno seems like the simplest approach.

brooksdavis commented 2 years ago

Hmm, I wonder if instead we want to change cap_covers_pages in sys/vm/vm_mmap.h to ignore the capability if len==0.