--- Begin Message ---
Package: libapache2-mpm-itk
Version: 2.4.6-01-1
Severity: important
Dear Maintainer,
The current version of mpm-itk breaks code attempting to do legitimate
setuid-type operations because of the seccomp BPF protections.
The reason stems from the fact that -1 is a permitted argument for
syscalls that change multiple ID's at once, such as setresuid, to which
(uid_t) -1 can be passed to indicate "don't change this value."
Since (uid_t) -1 == 4294967295 for everything except the old 16-bit i386
syscalls, these do-nothing values well exceed the max_uid = 65535, and
so these calls are blocked. Thus code which *should* be allowed (such
as setresuid(-1, currentid, -1) return EPERM.
In practice, this breaks anything that relies on uid changes that
*should* be permitted: in my case, a cgi script that invokes ssh fails
because ssh calls something with a -1 argument.
The attached patch updates the filters to extend the syscall argument
limits by allowing a specific value outside that min...max range, and -1
is passed for this value where needed. Thus in effect the uid/gid
syscall limits now allow anything in [min, max], and also -1.
With the patch, -1 is allowed for all the arguments of the blocked
syscalls except for __NR_setuid/__NR_setgid (and the ...32 version on
i386): -1 isn't a special value there. -1 isn't special for
__NR_setfsuid (and ...gid), either, but since man setfsuid specifically
suggests calling setfsuid a second time (with -1 as an argument) to
detect failures, I allowed it for those syscalls, too.
(I also had to reorganize the various limit_syscall_range code because
the -1 value ((__u16) -1 == 65535) for the i386, 16-bit __NR_set*uid
calls doesn't coincide with the ((uid_t) -1 == 4294967295) value of
non-i386's __NR_set*uid syscalls.)
I tested the code (on amd64) by extracting the capabilities and BPF
filter code into a test program, to make sure it was working, and indeed
it is: after the limits, all the restricted functions are indeed
restricted, while the various seteuid and related failures are now fixed.
Jason Rhinelander
--- mpm-itk-2.4.6-01.orig/seccomp.c 2013-07-10 07:22:20.000000000 -0400
+++ mpm-itk-2.4.6-01/seccomp.c 2014-02-07 17:16:55.139802820 -0500
@@ -95,7 +95,7 @@
++*pos;
}
-static int limit_syscall_range(int syscall_to_match, int nr_args, int min, int max)
+static int limit_syscall_range(int syscall_to_match, int nr_args, __u32 min, __u32 max, __u32 or_eq)
{
static struct sock_filter syscall_filter[BPF_MAXINSNS];
@@ -108,6 +108,8 @@
for (int i = 0; i < nr_args; ++i) {
add_bpf_stmt(syscall_filter, &pos, BPF_LD + BPF_W + BPF_ABS, syscall_arg(i));
+ if (or_eq < min || or_eq > max)
+ add_bpf_jump(syscall_filter, &pos, BPF_JMP + BPF_JEQ + BPF_K, or_eq, 4, 0);
add_bpf_jump(syscall_filter, &pos, BPF_JMP + BPF_JGE + BPF_K, min, 1, 0);
add_bpf_stmt(syscall_filter, &pos, BPF_RET + BPF_K, SECCOMP_RET_ERRNO | EPERM);
add_bpf_jump(syscall_filter, &pos, BPF_JMP + BPF_JGT + BPF_K, max, 0, 1);
@@ -128,6 +130,11 @@
gid_t min_gid16 = (min_gid > 65535) ? 65535 : min_gid;
gid_t max_gid16 = (max_gid > 65535) ? 65535 : max_gid;
+ uid_t minus_one = (uid_t) -1;
+#ifdef __i386__
+ __u16 minus_one16 = (__u16) -1;
+#endif // defined(__i386__)
+
/* Apply a seccomp BPF to ourselves that disallows all setuid- and
* setgid-like calls if the first argument is 0. The list of calls comes from
* the descriptions of CAP_SETUID and CAP_SETGID in capabilities(7), although
@@ -146,29 +153,43 @@
if (apply_seccomp_filter(arch_filter, sizeof(arch_filter) / sizeof(arch_filter[0])) != 0) {
return;
}
-#ifdef __i386__
- limit_syscall_range(__NR_setfsuid32, 1, min_uid, max_uid);
- limit_syscall_range(__NR_setuid32, 1, min_uid, max_uid);
- limit_syscall_range(__NR_setreuid32, 2, min_uid, max_uid);
- limit_syscall_range(__NR_setresuid32, 3, min_uid, max_uid);
-#endif // defined(__i386__)
-
- limit_syscall_range(__NR_setfsuid, 1, min_uid16, max_uid16);
- limit_syscall_range(__NR_setuid, 1, min_uid16, max_uid16);
- limit_syscall_range(__NR_setreuid, 2, min_uid16, max_uid16);
- limit_syscall_range(__NR_setresuid, 3, min_uid16, max_uid16);
#ifdef __i386__
- limit_syscall_range(__NR_setfsgid32, 1, min_gid, max_gid);
- limit_syscall_range(__NR_setgid32, 1, min_gid, max_gid);
- limit_syscall_range(__NR_setregid32, 2, min_gid, max_gid);
- limit_syscall_range(__NR_setresgid32, 3, min_gid, max_gid);
-#endif // defined(__i386__)
-
- limit_syscall_range(__NR_setfsgid, 1, min_gid16, max_gid16);
- limit_syscall_range(__NR_setgid, 1, min_gid16, max_gid16);
- limit_syscall_range(__NR_setregid, 2, min_gid16, max_gid16);
- limit_syscall_range(__NR_setresgid, 3, min_gid16, max_gid16);
+ /* Newer, 32-bit uid_t/gid_t syscalls: */
+ limit_syscall_range(__NR_setfsuid32, 1, min_uid, max_uid, minus_one);
+ limit_syscall_range(__NR_setuid32, 1, min_uid, max_uid, min_uid);
+ limit_syscall_range(__NR_setreuid32, 2, min_uid, max_uid, minus_one);
+ limit_syscall_range(__NR_setresuid32, 3, min_uid, max_uid, minus_one);
+
+ limit_syscall_range(__NR_setfsgid32, 1, min_gid, max_gid, minus_one);
+ limit_syscall_range(__NR_setgid32, 1, min_gid, max_gid, min_gid);
+ limit_syscall_range(__NR_setregid32, 2, min_gid, max_gid, minus_one);
+ limit_syscall_range(__NR_setresgid32, 3, min_gid, max_gid, minus_one);
+
+ /* Older 16-bit old_uid_t/old_gid_t syscalls: */
+ limit_syscall_range(__NR_setfsuid, 1, min_uid16, max_uid16, minus_one16);
+ limit_syscall_range(__NR_setuid, 1, min_uid16, max_uid16, min_uid16);
+ limit_syscall_range(__NR_setreuid, 2, min_uid16, max_uid16, minus_one16);
+ limit_syscall_range(__NR_setresuid, 3, min_uid16, max_uid16, minus_one16);
+
+ limit_syscall_range(__NR_setfsgid, 1, min_gid16, max_gid16, minus_one16);
+ limit_syscall_range(__NR_setgid, 1, min_gid16, max_gid16, min_gid16);
+ limit_syscall_range(__NR_setregid, 2, min_gid16, max_gid16, minus_one16);
+ limit_syscall_range(__NR_setresgid, 3, min_gid16, max_gid16, minus_one16);
+
+#else // not defined(__i386__)
+ /* Just one set of 32-bit uid_t/gid_t syscalls to worry about: */
+ limit_syscall_range(__NR_setfsuid, 1, min_uid, max_uid, minus_one);
+ limit_syscall_range(__NR_setuid, 1, min_uid, max_uid, min_uid);
+ limit_syscall_range(__NR_setreuid, 2, min_uid, max_uid, minus_one);
+ limit_syscall_range(__NR_setresuid, 3, min_uid, max_uid, minus_one);
+
+ limit_syscall_range(__NR_setfsgid, 1, min_gid, max_gid, minus_one);
+ limit_syscall_range(__NR_setgid, 1, min_gid, max_gid, min_gid);
+ limit_syscall_range(__NR_setregid, 2, min_gid, max_gid, minus_one);
+ limit_syscall_range(__NR_setresgid, 3, min_gid, max_gid, minus_one);
+#endif
+
#else
ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS, ap_server_conf,
"Your platform or architecture does not support seccomp v2; "
smime.p7s
Description: S/MIME Cryptographic Signature
--- End Message ---