diff options
Diffstat (limited to '')
-rw-r--r-- | security/sandbox/linux/SandboxInfo.cpp | 26 | ||||
-rw-r--r-- | security/sandbox/linux/launch/SandboxLaunch.cpp | 25 |
2 files changed, 44 insertions, 7 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; } diff --git a/security/sandbox/linux/launch/SandboxLaunch.cpp b/security/sandbox/linux/launch/SandboxLaunch.cpp index bec94f3c4c..6617ff475d 100644 --- a/security/sandbox/linux/launch/SandboxLaunch.cpp +++ b/security/sandbox/linux/launch/SandboxLaunch.cpp @@ -511,6 +511,8 @@ static pid_t ForkWithFlags(int aFlags) { return ret; } +// Returns true for success, or returns false and sets errno on +// failure. Intended only for procfs pseudo-files. static bool WriteStringToFile(const char* aPath, const char* aStr, const size_t aLen) { int fd = open(aPath, O_WRONLY); @@ -519,6 +521,11 @@ static bool WriteStringToFile(const char* aPath, const char* aStr, } ssize_t written = write(fd, aStr, aLen); if (close(fd) != 0 || written != ssize_t(aLen)) { + // procfs shouldn't ever cause a short write, but ensure that + // errno is set to something distinctive if it does + if (written >= 0) { + errno = EMSGSIZE; + } return false; } return true; @@ -537,6 +544,7 @@ static void ConfigureUserNamespace(uid_t uid, gid_t gid) { len = static_cast<size_t>(SafeSPrintf(buf, "%d %d 1", uid, uid)); MOZ_RELEASE_ASSERT(len < sizeof(buf)); if (!WriteStringToFile("/proc/self/uid_map", buf, len)) { + SANDBOX_LOG_ERRNO("writing /proc/self/uid_map"); MOZ_CRASH("Failed to write /proc/self/uid_map"); } @@ -549,6 +557,7 @@ static void ConfigureUserNamespace(uid_t uid, gid_t gid) { len = static_cast<size_t>(SafeSPrintf(buf, "%d %d 1", gid, gid)); MOZ_RELEASE_ASSERT(len < sizeof(buf)); if (!WriteStringToFile("/proc/self/gid_map", buf, len)) { + SANDBOX_LOG_ERRNO("writing /proc/self/gid_map"); MOZ_CRASH("Failed to write /proc/self/gid_map"); } } @@ -641,6 +650,9 @@ void SandboxLaunch::StartChrootServer() { char msg; ssize_t msgLen = HANDLE_EINTR(read(mChrootServer, &msg, 1)); + if (msgLen < 0) { + SANDBOX_LOG_ERRNO("chroot server couldn't read request"); + } if (msgLen == 0) { // Process exited before chrooting (or chose not to chroot?). _exit(0); @@ -653,7 +665,10 @@ void SandboxLaunch::StartChrootServer() { // exits at the end of this function, and which is always // unwriteable. int rv = chroot("/proc/self/fdinfo"); - MOZ_RELEASE_ASSERT(rv == 0); + if (rv != 0) { + SANDBOX_LOG_ERRNO("chroot"); + MOZ_CRASH("chroot failed"); + } // Drop CAP_SYS_CHROOT ASAP. This must happen before responding; // the main child won't be able to waitpid(), so it could start @@ -664,10 +679,16 @@ void SandboxLaunch::StartChrootServer() { // remove that. (Note: if the process can obtain directory fds, for // example via SandboxBroker, it must be blocked from using fchdir.) rv = chdir("/"); - MOZ_RELEASE_ASSERT(rv == 0); + if (rv != 0) { + SANDBOX_LOG_ERRNO("chdir(\"/\")"); + MOZ_CRASH("chdir(\"/\") failed"); + } msg = kSandboxChrootResponse; msgLen = HANDLE_EINTR(write(mChrootServer, &msg, 1)); + if (msgLen < 0) { + SANDBOX_LOG_ERRNO("chroot server couldn't send response"); + } MOZ_RELEASE_ASSERT(msgLen == 1); _exit(0); } |