gecko-dev/security/sandbox/linux/SandboxUtil.cpp

104 строки
3.1 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SandboxUtil.h"
#include "LinuxCapabilities.h"
#include "LinuxSched.h"
#include "SandboxLogging.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <unistd.h>
#include "mozilla/Assertions.h"
#include "mozilla/Sprintf.h"
#include "mozilla/Unused.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
namespace mozilla {
bool
IsSingleThreaded()
{
// This detects the thread count indirectly. /proc/<pid>/task has a
// subdirectory for each thread in <pid>'s thread group, and the
// link count on the "task" directory follows Unix expectations: the
// link from its parent, the "." link from itself, and the ".." link
// from each subdirectory; thus, 2+N links for N threads.
struct stat sb;
if (stat("/proc/self/task", &sb) < 0) {
MOZ_DIAGNOSTIC_ASSERT(false, "Couldn't access /proc/self/task!");
return false;
}
MOZ_DIAGNOSTIC_ASSERT(sb.st_nlink >= 3);
return sb.st_nlink == 3;
}
static bool
WriteStringToFile(const char* aPath, const char* aStr, const size_t aLen)
{
int fd = open(aPath, O_WRONLY);
if (fd < 0) {
return false;
}
ssize_t written = write(fd, aStr, aLen);
if (close(fd) != 0 || written != ssize_t(aLen)) {
return false;
}
return true;
}
bool
UnshareUserNamespace()
{
// The uid and gid need to be retrieved before the unshare; see
// below.
uid_t uid = getuid();
gid_t gid = getgid();
char buf[80];
size_t len;
if (syscall(__NR_unshare, CLONE_NEWUSER) != 0) {
return false;
}
// As mentioned in the header, this function sets up uid/gid
// mappings that preserve the process's previous ids. Mapping the
// uid/gid to something is necessary in order to nest user
// namespaces (not used yet, but we'll need this in the future for
// pid namespace support), and leaving the ids unchanged is the
// least confusing option.
//
// In recent kernels (3.19, 3.18.2, 3.17.8), for security reasons,
// establishing gid mappings will fail unless the process first
// revokes its ability to call setgroups() by using a /proc node
// added in the same set of patches.
//
// Note that /proc/self points to the thread group leader, not the
// current thread. However, CLONE_NEWUSER can be unshared only in a
// single-threaded process, so those are equivalent if we reach this
// point.
len = size_t(SprintfLiteral(buf, "%u %u 1\n", uid, uid));
MOZ_ASSERT(len < sizeof(buf));
if (!WriteStringToFile("/proc/self/uid_map", buf, len)) {
MOZ_CRASH("Failed to write /proc/self/uid_map");
}
Unused << WriteStringToFile("/proc/self/setgroups", "deny", 4);
len = size_t(SprintfLiteral(buf, "%u %u 1\n", gid, gid));
MOZ_ASSERT(len < sizeof(buf));
if (!WriteStringToFile("/proc/self/gid_map", buf, len)) {
MOZ_CRASH("Failed to write /proc/self/gid_map");
}
return true;
}
} // namespace mozilla