1*2810ac1bSKiyoung Kim /* 2*2810ac1bSKiyoung Kim * Copyright (c) 2019 Andrew G. Morgan <[email protected]> 3*2810ac1bSKiyoung Kim * 4*2810ac1bSKiyoung Kim * This header, and the -lpsx library, provide a number of things to 5*2810ac1bSKiyoung Kim * support POSIX semantics for syscalls associated with the pthread 6*2810ac1bSKiyoung Kim * library. Linking this code is tricky and is done as follows: 7*2810ac1bSKiyoung Kim * 8*2810ac1bSKiyoung Kim * ld ... -lpsx -lpthread --wrap=pthread_create 9*2810ac1bSKiyoung Kim * or, gcc ... -lpsx -lpthread -Wl,-wrap,pthread_create 10*2810ac1bSKiyoung Kim * 11*2810ac1bSKiyoung Kim * glibc provides a subset of this functionality natively through the 12*2810ac1bSKiyoung Kim * nptl:setxid mechanism and could implement psx_syscall() directly 13*2810ac1bSKiyoung Kim * using that style of functionality but, as of 2019-11-30, the setxid 14*2810ac1bSKiyoung Kim * mechanism is limited to 9 specific set*() syscalls that do not 15*2810ac1bSKiyoung Kim * support the syscall6 API (needed for prctl functions and the ambient 16*2810ac1bSKiyoung Kim * capabilities set for example). 17*2810ac1bSKiyoung Kim */ 18*2810ac1bSKiyoung Kim 19*2810ac1bSKiyoung Kim #ifndef _SYS_PSX_SYSCALL_H 20*2810ac1bSKiyoung Kim #define _SYS_PSX_SYSCALL_H 21*2810ac1bSKiyoung Kim 22*2810ac1bSKiyoung Kim #ifdef __cplusplus 23*2810ac1bSKiyoung Kim extern "C" { 24*2810ac1bSKiyoung Kim #endif 25*2810ac1bSKiyoung Kim 26*2810ac1bSKiyoung Kim #include <pthread.h> 27*2810ac1bSKiyoung Kim 28*2810ac1bSKiyoung Kim /* 29*2810ac1bSKiyoung Kim * psx_syscall performs the specified syscall on all psx registered 30*2810ac1bSKiyoung Kim * threads. The mechanism by which this occurs is much less efficient 31*2810ac1bSKiyoung Kim * than a standard system call on Linux, so it should only be used 32*2810ac1bSKiyoung Kim * when POSIX semantics are required to change process relevant 33*2810ac1bSKiyoung Kim * security state. 34*2810ac1bSKiyoung Kim * 35*2810ac1bSKiyoung Kim * Glibc has native support for POSIX semantics on setgroups() and the 36*2810ac1bSKiyoung Kim * 8 set*[gu]id() functions. So, there is no need to use psx_syscall() 37*2810ac1bSKiyoung Kim * for these calls. This call exists for all the other system calls 38*2810ac1bSKiyoung Kim * that need to maintain parity on all pthreads of a program. 39*2810ac1bSKiyoung Kim * 40*2810ac1bSKiyoung Kim * Some macrology is used to allow the caller to provide only as many 41*2810ac1bSKiyoung Kim * arguments as needed, thus psx_syscall() cannot be used as a 42*2810ac1bSKiyoung Kim * function pointer. For those situations, we define psx_syscall3() 43*2810ac1bSKiyoung Kim * and psx_syscall6(). 44*2810ac1bSKiyoung Kim */ 45*2810ac1bSKiyoung Kim #define psx_syscall(syscall_nr, ...) \ 46*2810ac1bSKiyoung Kim __psx_syscall(syscall_nr, __VA_ARGS__, (long int) 6, (long int) 5, \ 47*2810ac1bSKiyoung Kim (long int) 4, (long int) 3, (long int) 2, \ 48*2810ac1bSKiyoung Kim (long int) 1, (long int) 0) 49*2810ac1bSKiyoung Kim long int __psx_syscall(long int syscall_nr, ...); 50*2810ac1bSKiyoung Kim long int psx_syscall3(long int syscall_nr, 51*2810ac1bSKiyoung Kim long int arg1, long int arg2, long int arg3); 52*2810ac1bSKiyoung Kim long int psx_syscall6(long int syscall_nr, 53*2810ac1bSKiyoung Kim long int arg1, long int arg2, long int arg3, 54*2810ac1bSKiyoung Kim long int arg4, long int arg5, long int arg6); 55*2810ac1bSKiyoung Kim 56*2810ac1bSKiyoung Kim /* 57*2810ac1bSKiyoung Kim * This function should be used by systems to obtain pointers to the 58*2810ac1bSKiyoung Kim * two syscall functions provided by the PSX library. A linkage trick 59*2810ac1bSKiyoung Kim * is to define this function as weak in a library that can optionally 60*2810ac1bSKiyoung Kim * use libpsx and then, should the caller link -lpsx, that library can 61*2810ac1bSKiyoung Kim * implicitly use these POSIX semantics syscalls. See libcap for an 62*2810ac1bSKiyoung Kim * example of this usage. 63*2810ac1bSKiyoung Kim */ 64*2810ac1bSKiyoung Kim void psx_load_syscalls(long int (**syscall_fn)(long int, 65*2810ac1bSKiyoung Kim long int, long int, long int), 66*2810ac1bSKiyoung Kim long int (**syscall6_fn)(long int, 67*2810ac1bSKiyoung Kim long int, long int, long int, 68*2810ac1bSKiyoung Kim long int, long int, long int)); 69*2810ac1bSKiyoung Kim 70*2810ac1bSKiyoung Kim /* 71*2810ac1bSKiyoung Kim * psx_sensitivity_t holds the level of paranoia for non-POSIX syscall 72*2810ac1bSKiyoung Kim * behavior. The default is PSX_IGNORE: which is best effort - no 73*2810ac1bSKiyoung Kim * enforcement; PSX_WARNING will dump to stderr a warning when a 74*2810ac1bSKiyoung Kim * syscall's results differ; PSX_ERROR will dump info as per 75*2810ac1bSKiyoung Kim * PSX_WARNING and generate a SIGSYS. The current mode can be set with 76*2810ac1bSKiyoung Kim * psx_set_sensitivity(). 77*2810ac1bSKiyoung Kim */ 78*2810ac1bSKiyoung Kim typedef enum { 79*2810ac1bSKiyoung Kim PSX_IGNORE = 0, 80*2810ac1bSKiyoung Kim PSX_WARNING = 1, 81*2810ac1bSKiyoung Kim PSX_ERROR = 2, 82*2810ac1bSKiyoung Kim } psx_sensitivity_t; 83*2810ac1bSKiyoung Kim 84*2810ac1bSKiyoung Kim /* 85*2810ac1bSKiyoung Kim * psx_set_sensitivity sets the current sensitivity of the PSX 86*2810ac1bSKiyoung Kim * mechanism. The function returns 0 on success and -1 if the 87*2810ac1bSKiyoung Kim * requested level is invalid. 88*2810ac1bSKiyoung Kim */ 89*2810ac1bSKiyoung Kim int psx_set_sensitivity(psx_sensitivity_t level); 90*2810ac1bSKiyoung Kim 91*2810ac1bSKiyoung Kim #ifdef __cplusplus 92*2810ac1bSKiyoung Kim } 93*2810ac1bSKiyoung Kim #endif 94*2810ac1bSKiyoung Kim 95*2810ac1bSKiyoung Kim #endif /* _SYS_PSX_SYSCALL_H */ 96