diff options
-rw-r--r-- | ChangeLog.txt | 8 | ||||
-rw-r--r-- | ports/linux/guts/syscall.c | 15 | ||||
-rw-r--r-- | ports/linux/portdefs.h | 1 | ||||
-rw-r--r-- | ports/linux/pseudo_wrappers.c | 40 | ||||
-rw-r--r-- | ports/linux/wrapfuncs.in | 1 |
5 files changed, 65 insertions, 0 deletions
diff --git a/ChangeLog.txt b/ChangeLog.txt index 8a8b71b..b4a76ac 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,11 @@ +2018-03-29: + * (seebs) wrap syscall, and if SYS_renameat2 exists, try to + reject it with ENOSYS, because coreutils started using a + new syscall. An actual renameat2 wrapper will be a major + effort ("changing the pseudo_ipc data structure") and is + pointless when glibc hasn't got a wrapper so we have no + viable test cases. + 2018-03-06: * (seebs) Update path handling a bit to correctly fail if a path tries to have a slash after a plain file name, even in cases diff --git a/ports/linux/guts/syscall.c b/ports/linux/guts/syscall.c new file mode 100644 index 0000000..d1226c5 --- /dev/null +++ b/ports/linux/guts/syscall.c @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2018 Wind River Systems; see + * guts/COPYRIGHT for information. + * + * long syscall(long nr) + * long rc = -1; + */ + + /* we should never get here, syscall is hand-wrapped */ + rc = -1; + errno = ENOTSUPP; + +/* return rc; + * } + */ diff --git a/ports/linux/portdefs.h b/ports/linux/portdefs.h index 942356d..86aa4f9 100644 --- a/ports/linux/portdefs.h +++ b/ports/linux/portdefs.h @@ -27,3 +27,4 @@ GLIBC_COMPAT_SYMBOL(memcpy,2.0); #endif #include <linux/capability.h> +#include <sys/syscall.h> diff --git a/ports/linux/pseudo_wrappers.c b/ports/linux/pseudo_wrappers.c index e7f79f8..229b1d9 100644 --- a/ports/linux/pseudo_wrappers.c +++ b/ports/linux/pseudo_wrappers.c @@ -49,3 +49,43 @@ int pseudo_capset(cap_user_header_t hdrp, const cap_user_data_t datap) { return 0; } + +long +syscall(long number, ...) { + /* In a fit of optimism, I imagine that if we didn't get at least 7 + * arguments, reading past the ones we did get will read into this + * space and maybe not clash with or overlap with any later-declared + * values. This isn't really a guarantee, and is probably just + * superstition. + */ + unsigned long long padding[7]; + (void) padding; + +#ifdef SYS_renameat2 + /* concerns exist about trying to parse arguments because syscall(2) + * specifies strange ABI behaviors. If we can get better clarity on + * that, it could make sense to redirect to wrap_renameat2(). + */ + if (number == SYS_renameat2) { + errno = ENOSYS; + return -1; + } +#else + (void) number; +#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? + */ + void *res = __builtin_apply((void (*)()) real_syscall, __builtin_apply_args(), sizeof(long long) * 7); + __builtin_return(res); +} + +/* unused. + */ +static long wrap_syscall(long nr, va_list ap) { + (void) nr; + (void) ap; + return -1; +} diff --git a/ports/linux/wrapfuncs.in b/ports/linux/wrapfuncs.in index fca5b50..9be6505 100644 --- a/ports/linux/wrapfuncs.in +++ b/ports/linux/wrapfuncs.in @@ -54,3 +54,4 @@ int getpw(uid_t uid, char *buf); int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp); int getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp); int capset(cap_user_header_t hdrp, const cap_user_data_t datap); /* real_func=pseudo_capset */ +long syscall(long nr, ...); /* hand_wrapped=1 */ |