aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSeebs <seebs@seebs.net>2018-03-29 10:21:56 -0500
committerSeebs <seebs@seebs.net>2018-03-29 16:12:23 -0500
commit778abd3686fb7c419e9016fdd9e93819405d52aa (patch)
tree6492dc10505927284d75441c5c04acee83d8471a
parent32c308ee14bbe2f68cefd12cf1f40275fd216a49 (diff)
downloadpseudo-778abd3686fb7c419e9016fdd9e93819405d52aa.tar.gz
pseudo-778abd3686fb7c419e9016fdd9e93819405d52aa.tar.bz2
pseudo-778abd3686fb7c419e9016fdd9e93819405d52aa.zip
Experimental syscall(2) wrapper.
This wrapper should allow us to reject renameat2 attempts by coreutils, letting us regain functionality on FC27 and related systems. This is not safe/portable/etc even by pseudo's standards, and arguably it should be a separate and optional port. [Amended commit: Don't include the dodgy renameat2 wrapper which it turns out we'd never hit anyway.] Signed-off-by: Seebs <seebs@seebs.net>
-rw-r--r--ChangeLog.txt8
-rw-r--r--ports/linux/guts/syscall.c15
-rw-r--r--ports/linux/portdefs.h1
-rw-r--r--ports/linux/pseudo_wrappers.c40
-rw-r--r--ports/linux/wrapfuncs.in1
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 */