diff options
-rw-r--r-- | ports/linux/portdefs.h | 2 | ||||
-rw-r--r-- | ports/linux/pseudo_wrappers.c | 56 | ||||
-rw-r--r-- | ports/linux/wrapfuncs.in | 1 |
3 files changed, 59 insertions, 0 deletions
diff --git a/ports/linux/portdefs.h b/ports/linux/portdefs.h index d419365..a92e969 100644 --- a/ports/linux/portdefs.h +++ b/ports/linux/portdefs.h @@ -32,3 +32,5 @@ GLIBC_COMPAT_SYMBOL(memcpy,2.0); #include <linux/capability.h> #include <sys/syscall.h> +#include <sys/prctl.h> +#include <linux/seccomp.h> diff --git a/ports/linux/pseudo_wrappers.c b/ports/linux/pseudo_wrappers.c index cd7e173..ed34115 100644 --- a/ports/linux/pseudo_wrappers.c +++ b/ports/linux/pseudo_wrappers.c @@ -57,6 +57,7 @@ int pseudo_capset(cap_user_header_t hdrp, const cap_user_data_t datap) { long syscall(long number, ...) { long rc = -1; + va_list ap; if (!pseudo_check_wrappers() || !real_syscall) { /* rc was initialized to the "failure" value */ @@ -77,6 +78,20 @@ syscall(long number, ...) { (void) number; #endif +#ifdef SYS_seccomp + /* pseudo and seccomp are incompatible as pseudo uses different syscalls + * so pretend to enable seccomp but really do nothing */ + if (number == SYS_seccomp) { + unsigned long cmd; + va_start(ap, number); + cmd = va_arg(ap, unsigned long); + va_end(ap); + if (cmd == SECCOMP_SET_MODE_FILTER) { + return 0; + } + } +#endif + /* gcc magic to attempt to just pass these args to syscall. we have to * guess about the number of args; the docs discuss calling conventions * up to 7, so let's try that? @@ -92,3 +107,44 @@ static long wrap_syscall(long nr, va_list ap) { (void) ap; return -1; } + +int +prctl(int option, ...) { + int rc = -1; + va_list ap; + + if (!pseudo_check_wrappers() || !real_prctl) { + /* rc was initialized to the "failure" value */ + pseudo_enosys("prctl"); + return rc; + } + +#ifdef SECCOMP_SET_MODE_FILTER + /* pseudo and seccomp are incompatible as pseudo uses different syscalls + * so pretend to enable seccomp but really do nothing */ + if (option == PR_SET_SECCOMP) { + unsigned long cmd; + va_start(ap, option); + cmd = va_arg(ap, unsigned long); + va_end(ap); + if (cmd == SECCOMP_SET_MODE_FILTER) { + return 0; + } + } +#endif + + /* gcc magic to attempt to just pass these args to prctl. we have to + * guess about the number of args; the docs discuss calling conventions + * up to 5, so let's try that? + */ + void *res = __builtin_apply((void (*)()) real_prctl, __builtin_apply_args(), sizeof(long) * 5); + __builtin_return(res); +} + +/* unused. + */ +static int wrap_prctl(int option, va_list ap) { + (void) option; + (void) ap; + return -1; +} diff --git a/ports/linux/wrapfuncs.in b/ports/linux/wrapfuncs.in index c5ea7c3..aae0f0d 100644 --- a/ports/linux/wrapfuncs.in +++ b/ports/linux/wrapfuncs.in @@ -56,3 +56,4 @@ int getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbuf int capset(cap_user_header_t hdrp, const cap_user_data_t datap); /* real_func=pseudo_capset */ long syscall(long nr, ...); /* hand_wrapped=1 */ int renameat2(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, unsigned int flags); /* flags=AT_SYMLINK_NOFOLLOW */ +int prctl(int option, ...); /* hand_wrapped=1 */ |