path: root/src
diff options
authorRich Felker <>2020-08-08 20:59:26 -0400
committerRich Felker <>2020-08-08 20:59:26 -0400
commitc2feda4e2ea61f4da73f2f38b2be5e327a7d1a91 (patch)
tree4cba60bff388fa9e873e93b2ee92ee641826896c /src
parent933f8e72ebbe3a456acd24eb1c910980e6c6ef91 (diff)
prefer new socket syscalls, fallback to SYS_socketcall only if needed
a number of users performing seccomp filtering have requested use of the new individual syscall numbers for socket syscalls, rather than the legacy multiplexed socketcall, since the latter has the arguments all in memory where they can't participate in filter decisions. previously, some archs used the multiplexed socketcall if it was historically all that was available, while other archs used the separate syscalls. the intent was that the latter set only include archs that have "always" had separate socket syscalls, at least going back to linux 2.6.0. however, at least powerpc, powerpc64, and sh were wrongly included in this set, and thus socket operations completely failed on old kernels for these archs. with the changes made here, the separate syscalls are always preferred, but fallback code is compiled for archs that also define SYS_socketcall. two such archs, mips (plain o32) and microblaze, define SYS_socketcall despite never having needed it, so it's now undefined by their versions of syscall_arch.h to prevent inclusion of useless fallback code. some archs, where the separate syscalls were only added after the addition of SYS_accept4, lack SYS_accept. because socket calls are always made with zeros in the unused argument positions, it suffices to just use SYS_accept4 to provide a definition of SYS_accept, and this is done to make happy the macro machinery that concatenates the socket call name onto __SC_ and SYS_.
Diffstat (limited to 'src')
1 files changed, 23 insertions, 9 deletions
diff --git a/src/internal/syscall.h b/src/internal/syscall.h
index 975a0031..d5f294d4 100644
--- a/src/internal/syscall.h
+++ b/src/internal/syscall.h
@@ -2,6 +2,7 @@
#include <features.h>
+#include <errno.h>
#include <sys/syscall.h>
#include "syscall_arch.h"
@@ -57,15 +58,22 @@ hidden long __syscall_ret(unsigned long),
#define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__)
#define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__))
-#define __socketcall(nm,a,b,c,d,e,f) __syscall(SYS_##nm, a, b, c, d, e, f)
-#define __socketcall_cp(nm,a,b,c,d,e,f) __syscall_cp(SYS_##nm, a, b, c, d, e, f)
-#define __socketcall(nm,a,b,c,d,e,f) __syscall(SYS_socketcall, __SC_##nm, \
- ((long [6]){ (long)a, (long)b, (long)c, (long)d, (long)e, (long)f }))
-#define __socketcall_cp(nm,a,b,c,d,e,f) __syscall_cp(SYS_socketcall, __SC_##nm, \
- ((long [6]){ (long)a, (long)b, (long)c, (long)d, (long)e, (long)f }))
+static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, long c, long d, long e, long f)
+ long r;
+ if (cp) r = __syscall_cp(sys, a, b, c, d, e, f);
+ else r = __syscall(sys, a, b, c, d, e, f);
+ if (r != -ENOSYS) return r;
+#ifdef SYS_socketcall
+ if (cp) r = __syscall_cp(SYS_socketcall, sock, ((long[6]){a, b, c, d, e, f}));
+ else r = __syscall(SYS_socketcall, sock, ((long[6]){a, b, c, d, e, f}));
+ return r;
+#define __socketcall(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 0, \
+ (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f))
+#define __socketcall_cp(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 1, \
+ (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f))
/* fixup legacy 16-bit junk */
@@ -338,6 +346,12 @@ hidden long __syscall_ret(unsigned long),
#define __SC_recvmmsg 19
#define __SC_sendmmsg 20
+/* This is valid only because all socket syscalls are made via
+ * socketcall, which always fills unused argument slots with zeros. */
+#ifndef SYS_accept
+#define SYS_accept SYS_accept4
#define SO_RCVTIMEO_OLD 20