1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
/* -*- 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];
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.
int len = SprintfLiteral(buf, "%u %u 1\n", uid, uid);
if (len >= int(sizeof(buf)) || len < 0) {
return false;
}
if (!WriteStringToFile("/proc/self/uid_map", buf, size_t(len))) {
MOZ_CRASH("Failed to write /proc/self/uid_map");
}
Unused << WriteStringToFile("/proc/self/setgroups", "deny", 4);
len = SprintfLiteral(buf, "%u %u 1\n", gid, gid);
if (len >= int(sizeof(buf)) || len < 0) {
return false;
}
if (!WriteStringToFile("/proc/self/gid_map", buf, size_t(len))) {
MOZ_CRASH("Failed to write /proc/self/gid_map");
}
return true;
}
} // namespace mozilla
|