Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(666)

Side by Side Diff: sandbox/linux/suid/sandbox.cc

Issue 149230: Linux: SUID sandbox support (Closed)
Patch Set: ... Created 11 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/common/chrome_switches.cc ('k') | sandbox/sandbox.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <asm/unistd.h>
6 #include <errno.h>
7 #include <sched.h>
8 #include <signal.h>
9 #include <stdarg.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/prctl.h>
14 #include <sys/resource.h>
15 #include <sys/socket.h>
16 #include <sys/stat.h>
17 #include <sys/time.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20
21 #if !defined(CLONE_NEWPID)
22 #define CLONE_NEWPID 20000000
23 #endif
24
25 static const char kSandboxPath[] = "/var/run/chrome-sandbox";
26 static const char kChromeBinary[] = "/opt/google/chrome/chrome";
27
28 // These are the magic byte values which the sandboxed process uses to request
29 // that it be chrooted.
30 static const char kMsgChrootMe = 'C';
31 static const char kMsgChrootSuccessful = 'O';
32
33 static void FatalError(const char *msg, ...) {
34 va_list ap;
35 va_start(ap, msg);
36
37 vfprintf(stderr, msg, ap);
38 fprintf(stderr, ": %s\n", strerror(errno));
39 fflush(stderr);
40 _exit(1);
41 }
42
43 static int CloneChrootHelperProcess() {
44 int sv[2];
45 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
46 perror("socketpair");
47 return -1;
48 }
49
50 const pid_t pid = syscall(
51 __NR_clone, CLONE_FS | SIGCHLD, 0, 0, 0);
52
53 if (pid == -1) {
54 perror("clone");
55 close(sv[0]);
56 close(sv[1]);
57 return -1;
58 }
59
60 if (pid == 0) {
61 // We share our files structure with an untrusted process. As a security in
62 // depth measure, we make sure that we can't open anything by mistake.
63 // TODO: drop CAP_SYS_RESOURCE
64
65 const struct rlimit nofile = {0, 0};
66 if (setrlimit(RLIMIT_NOFILE, &nofile))
67 FatalError("Setting RLIMIT_NOFILE");
68
69 if (close(sv[1]))
70 FatalError("close");
71
72 char msg;
73 ssize_t bytes;
74 do {
75 bytes = read(sv[0], &msg, 1);
76 } while (bytes == -1 && errno == EINTR);
77
78 if (bytes == 0)
79 exit(0);
80 if (bytes != 1)
81 FatalError("read");
82
83 if (msg != kMsgChrootMe)
84 FatalError("Unknown message from sandboxed process");
85
86 if (chdir(kSandboxPath))
87 FatalError("Cannot chdir into %s", kSandboxPath);
88
89 struct stat st;
90 if (stat("/", &st))
91 FatalError("stat");
92
93 if (st.st_uid || st.st_gid || st.st_mode & S_IWOTH)
94 FatalError("Bad permissions on chroot directory (%s)", kSandboxPath);
95
96 if (chroot(kSandboxPath))
97 FatalError("Cannot chroot into %s", kSandboxPath);
98
99 if (chdir("/"))
100 FatalError("Cannot chdir to / after chroot");
101
102 const char reply = kMsgChrootSuccessful;
103 do {
104 bytes = write(sv[0], &reply, 1);
105 } while (bytes == -1 && errno == EINTR);
106
107 if (bytes != 1)
108 FatalError("Writing reply");
109
110 exit(0);
111 }
112
113 if (close(sv[0])) {
114 close(sv[1]);
115 perror("close");
116 return false;
117 }
118
119 return sv[1];
120 }
121
122 static bool SpawnChrootHelper() {
123 const int chroot_signal_fd = CloneChrootHelperProcess();
124
125 if (chroot_signal_fd == -1)
126 return false;
127
128 // In the parent process, we install an environment variable containing the
129 // number of the file descriptor.
130 char desc_str[64];
131 snprintf(desc_str, sizeof(desc_str), "%d", chroot_signal_fd);
132
133 if (setenv("SBX_D", desc_str, 1)) {
134 perror("setenv");
135 close(chroot_signal_fd);
136 return false;
137 }
138
139 return true;
140 }
141
142 static bool MoveToNewPIDNamespace() {
143 const pid_t pid = syscall(
144 __NR_clone, CLONE_NEWPID | SIGCHLD, 0, 0, 0);
145
146 if (pid == -1)
147 return false;
148
149 if (pid)
150 syscall(__NR_exit, 0);
151
152 return true;
153 }
154
155 static bool DropRoot() {
156 if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0)) {
157 perror("prctl(PR_SET_DUMPABLE)");
158 return false;
159 }
160
161 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0)) {
162 perror("Still dumpable after prctl(PR_SET_DUMPABLE)");
163 return false;
164 }
165
166 gid_t rgid, egid, sgid;
167 if (getresgid(&rgid, &egid, &sgid)) {
168 perror("getresgid");
169 return false;
170 }
171
172 if (setresgid(rgid, rgid, rgid)) {
173 perror("setresgid");
174 return false;
175 }
176
177 uid_t ruid, euid, suid;
178 if (getresuid(&ruid, &euid, &suid)) {
179 perror("getresuid");
180 return false;
181 }
182
183 if (setresuid(ruid, ruid, ruid)) {
184 perror("setresuid");
185 return false;
186 }
187
188 return true;
189 }
190
191 int main(int argc, char **argv) {
192 if (argc == 1) {
193 fprintf(stderr, "Usage: %s <renderer process> <args...>\n", argv[0]);
194 return 1;
195 }
196
197 if (strcmp(argv[1], kChromeBinary)) {
198 fprintf(stderr, "This wrapper can only run %s!\n", kChromeBinary);
199 return 1;
200 }
201
202 if (!MoveToNewPIDNamespace())
203 return 1;
204 if (!SpawnChrootHelper())
205 return 1;
206 if (!DropRoot())
207 return 1;
208
209 execv(argv[1], &argv[1]);
210 FatalError("execv failed");
211
212 return 1;
213 }
OLDNEW
« no previous file with comments | « chrome/common/chrome_switches.cc ('k') | sandbox/sandbox.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698