Bug 1742993 - Allow the `sched_*` syscalls in the RDD process sandbox for the calling thread only. r=gcp

As discussed in the previous patch, we'd like to allow these syscalls for
any thread of the calling process, but technical limitations mean that we
have to restrict them to the calling thread (or not at all).  Therefore,
they are allowed for the calling thread, and EPERM is returned otherwise.

This is a slight problem for Mesa, which in some cases changes a
thread's own scheduler attributes and in other places tries to modify
other threads, but at least if we allow this safe subset it's possible
that a future Mesa version could work within that.

The impact of denying the other-thread case of these syscalls should be
limited to slightly reduced performance via suboptimal scheduling.

Differential Revision: https://phabricator.services.mozilla.com/D133712
This commit is contained in:
Jed Davis 2021-12-16 21:23:10 +00:00
Родитель 87e3d9eabe
Коммит 398e2ccd0e
2 изменённых файлов: 38 добавлений и 13 удалений

Просмотреть файл

@ -35,6 +35,24 @@
namespace mozilla {
#ifdef XP_LINUX
static void RunTestsSched(SandboxTestingChild* child) {
struct sched_param param_pid_0 = {};
child->ErrnoTest("sched_getparam(0)"_ns, true,
[&] { return sched_getparam(0, &param_pid_0); });
struct sched_param param_pid_tid = {};
child->ErrnoTest("sched_getparam(tid)"_ns, true, [&] {
return sched_getparam((pid_t)syscall(__NR_gettid), &param_pid_tid);
});
struct sched_param param_pid_Ntid = {};
child->ErrnoValueTest("sched_getparam(Ntid)"_ns, false, EPERM, [&] {
return sched_getparam((pid_t)(syscall(__NR_gettid) - 1), &param_pid_Ntid);
});
}
#endif // XP_LINUX
void RunTestsContent(SandboxTestingChild* child) {
MOZ_ASSERT(child, "No SandboxTestingChild*?");
@ -229,6 +247,9 @@ void RunTestsRDD(SandboxTestingChild* child) {
int rv = unlinkat(AT_FDCWD, "", 0);
return rv;
});
RunTestsSched(child);
# endif // XP_LINUX
#else // XP_UNIX
child->ReportNoTests();
@ -259,19 +280,7 @@ void RunTestsGMPlugin(SandboxTestingChild* child) {
child->ErrnoTest("geteuid"_ns, true, [&] { return geteuid(); });
child->ErrnoTest("getegid"_ns, true, [&] { return getegid(); });
struct sched_param param_pid_0 = {};
child->ErrnoTest("sched_getparam(0)"_ns, true,
[&] { return sched_getparam(0, &param_pid_0); });
struct sched_param param_pid_tid = {};
child->ErrnoTest("sched_getparam(tid)"_ns, true, [&] {
return sched_getparam((pid_t)syscall(__NR_gettid), &param_pid_tid);
});
struct sched_param param_pid_Ntid = {};
child->ErrnoValueTest("sched_getparam(Ntid)"_ns, false, EPERM, [&] {
return sched_getparam((pid_t)(syscall(__NR_gettid) - 1), &param_pid_Ntid);
});
RunTestsSched(child);
std::vector<std::pair<const char*, bool>> open_tests = {
{"/etc/ld.so.cache", true},

Просмотреть файл

@ -1806,6 +1806,22 @@ class RDDSandboxPolicy final : public SandboxPolicyCommon {
case __NR_eventfd2:
return Allow();
// Allow the sched_* syscalls for the current thread only.
// Mesa attempts to use them to optimize performance; often
// this involves passing other threads' tids, which we can't
// safely allow, but maybe a future Mesa version could fix that.
case __NR_sched_getaffinity:
case __NR_sched_setaffinity:
case __NR_sched_getparam:
case __NR_sched_setparam:
case __NR_sched_getscheduler:
case __NR_sched_setscheduler:
case __NR_sched_getattr:
case __NR_sched_setattr: {
Arg<pid_t> pid(0);
return If(pid == 0, Allow()).Else(Trap(SchedTrap, nullptr));
}
// Pass through the common policy.
default:
return SandboxPolicyCommon::EvaluateSyscall(sysno);