diff options
Diffstat (limited to '')
-rw-r--r-- | security/sandbox/linux/SandboxInfo.cpp | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/security/sandbox/linux/SandboxInfo.cpp b/security/sandbox/linux/SandboxInfo.cpp index 3d71e55921..aefd9dac2d 100644 --- a/security/sandbox/linux/SandboxInfo.cpp +++ b/security/sandbox/linux/SandboxInfo.cpp @@ -134,11 +134,21 @@ static bool CanCreateUserNamespace() { // the new capabilities (in this case, cloning another namespace) to // detect AppArmor policies that allow CLONE_NEWUSER but don't allow // doing anything useful with it. - pid_t pid = syscall(__NR_clone, SIGCHLD | CLONE_NEWUSER | CLONE_NEWPID, - nullptr, nullptr, nullptr, nullptr); + // + // Bug 1884347: There's a new AppArmor feature which can result in + // unsharing NEWUSER and NEWPID (or NEWNET etc.) in one syscall + // being allowed, but further use of capabilities will be blocked + // afterwards. That may be a bug, but we need to handle it. + pid_t pid = syscall(__NR_clone, SIGCHLD | CLONE_NEWUSER, nullptr, nullptr, + nullptr, nullptr); if (pid == 0) { - // In the child. Do as little as possible. - _exit(0); + // The exact meaning of `unshare(CLONE_NEWPID)` is slightly + // counterintuitive but in this case it doesn't matter. This just + // needs to be some operation that attempts to use capabilities, + // to check if it's blocked by an LSM. + int rv = unshare(CLONE_NEWPID); + // Exit with status 0 on success, 1 on failure. + _exit(rv == 0 ? 0 : 1); } if (pid == -1) { // Failure. @@ -149,11 +159,17 @@ static bool CanCreateUserNamespace() { return false; } // Otherwise, in the parent and successful. - bool waitpid_ok = HANDLE_EINTR(waitpid(pid, nullptr, 0)) == pid; + int wstatus; + bool waitpid_ok = HANDLE_EINTR(waitpid(pid, &wstatus, 0)) == pid; MOZ_ASSERT(waitpid_ok); if (!waitpid_ok) { return false; } + // Check for failures reported by the child process. + if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) { + setenv(kCacheEnvName, "0", 1); + return false; + } setenv(kCacheEnvName, "1", 1); return true; } |