OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 // http://code.google.com/p/chromium/wiki/LinuxSUIDSandbox |
| 6 |
5 #include <asm/unistd.h> | 7 #include <asm/unistd.h> |
6 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <fcntl.h> |
7 #include <sched.h> | 10 #include <sched.h> |
8 #include <signal.h> | 11 #include <signal.h> |
9 #include <stdarg.h> | 12 #include <stdarg.h> |
10 #include <stdio.h> | 13 #include <stdio.h> |
11 #include <stdlib.h> | 14 #include <stdlib.h> |
12 #include <string.h> | 15 #include <string.h> |
13 #include <sys/prctl.h> | 16 #include <sys/prctl.h> |
14 #include <sys/resource.h> | 17 #include <sys/resource.h> |
15 #include <sys/socket.h> | 18 #include <sys/socket.h> |
16 #include <sys/stat.h> | 19 #include <sys/stat.h> |
17 #include <sys/time.h> | 20 #include <sys/time.h> |
18 #include <sys/types.h> | 21 #include <sys/types.h> |
19 #include <unistd.h> | 22 #include <unistd.h> |
20 | 23 |
21 #if !defined(CLONE_NEWPID) | 24 #if !defined(CLONE_NEWPID) |
22 #define CLONE_NEWPID 0x20000000 | 25 #define CLONE_NEWPID 0x20000000 |
23 #endif | 26 #endif |
24 | 27 |
25 static const char kSandboxPath[] = "/var/run/chrome-sandbox"; | |
26 static const char kChromeBinary[] = "/opt/google/chrome/chrome"; | 28 static const char kChromeBinary[] = "/opt/google/chrome/chrome"; |
27 static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D"; | 29 static const char kSandboxDescriptorEnvironmentVarName[] = "SBX_D"; |
28 | 30 |
29 // These are the magic byte values which the sandboxed process uses to request | 31 // These are the magic byte values which the sandboxed process uses to request |
30 // that it be chrooted. | 32 // that it be chrooted. |
31 static const char kMsgChrootMe = 'C'; | 33 static const char kMsgChrootMe = 'C'; |
32 static const char kMsgChrootSuccessful = 'O'; | 34 static const char kMsgChrootSuccessful = 'O'; |
33 | 35 |
34 static void FatalError(const char *msg, ...) | 36 static void FatalError(const char *msg, ...) |
35 __attribute__((noreturn, format(printf,1,2))); | 37 __attribute__((noreturn, format(printf,1,2))); |
(...skipping 19 matching lines...) Expand all Loading... |
55 __NR_clone, CLONE_FS | SIGCHLD, 0, 0, 0); | 57 __NR_clone, CLONE_FS | SIGCHLD, 0, 0, 0); |
56 | 58 |
57 if (pid == -1) { | 59 if (pid == -1) { |
58 perror("clone"); | 60 perror("clone"); |
59 close(sv[0]); | 61 close(sv[0]); |
60 close(sv[1]); | 62 close(sv[1]); |
61 return -1; | 63 return -1; |
62 } | 64 } |
63 | 65 |
64 if (pid == 0) { | 66 if (pid == 0) { |
| 67 // We create a temp directory for our chroot. Nobody should ever write into |
| 68 // it, so it's root:root 0555. |
| 69 char kTempDirectoryTemplate[] = "/tmp/chrome-sandbox-chroot-XXXXXX"; |
| 70 const char* temp_dir = mkdtemp(kTempDirectoryTemplate); |
| 71 if (!temp_dir) |
| 72 FatalError("Failed to create temp directory for chroot"); |
| 73 |
| 74 const int chroot_dir_fd = open(temp_dir, O_DIRECTORY | O_RDONLY); |
| 75 if (chroot_dir_fd < 0) { |
| 76 rmdir(temp_dir); |
| 77 FatalError("Failed to open chroot temp directory"); |
| 78 } |
| 79 |
| 80 rmdir(temp_dir); |
| 81 fchown(chroot_dir_fd, 0, 0); |
| 82 fchmod(chroot_dir_fd, 0555); |
| 83 |
65 // We share our files structure with an untrusted process. As a security in | 84 // We share our files structure with an untrusted process. As a security in |
66 // depth measure, we make sure that we can't open anything by mistake. | 85 // depth measure, we make sure that we can't open anything by mistake. |
67 // TODO: drop CAP_SYS_RESOURCE | 86 // TODO: drop CAP_SYS_RESOURCE |
68 | 87 |
69 const struct rlimit nofile = {0, 0}; | 88 const struct rlimit nofile = {0, 0}; |
70 if (setrlimit(RLIMIT_NOFILE, &nofile)) | 89 if (setrlimit(RLIMIT_NOFILE, &nofile)) |
71 FatalError("Setting RLIMIT_NOFILE"); | 90 FatalError("Setting RLIMIT_NOFILE"); |
72 | 91 |
73 if (close(sv[1])) | 92 if (close(sv[1])) |
74 FatalError("close"); | 93 FatalError("close"); |
75 | 94 |
76 char msg; | 95 char msg; |
77 ssize_t bytes; | 96 ssize_t bytes; |
78 do { | 97 do { |
79 bytes = read(sv[0], &msg, 1); | 98 bytes = read(sv[0], &msg, 1); |
80 } while (bytes == -1 && errno == EINTR); | 99 } while (bytes == -1 && errno == EINTR); |
81 | 100 |
82 if (bytes == 0) | 101 if (bytes == 0) |
83 _exit(0); | 102 _exit(0); |
84 if (bytes != 1) | 103 if (bytes != 1) |
85 FatalError("read"); | 104 FatalError("read"); |
86 | 105 |
87 if (msg != kMsgChrootMe) | 106 if (msg != kMsgChrootMe) |
88 FatalError("Unknown message from sandboxed process"); | 107 FatalError("Unknown message from sandboxed process"); |
89 | 108 |
90 if (chdir(kSandboxPath)) | 109 if (fchdir(chroot_dir_fd)) |
91 FatalError("Cannot chdir into %s", kSandboxPath); | 110 FatalError("Cannot chdir into chroot temp directory"); |
92 | 111 |
93 struct stat st; | 112 struct stat st; |
94 if (stat(".", &st)) | 113 if (stat(".", &st)) |
95 FatalError("stat"); | 114 FatalError("stat"); |
96 | 115 |
97 if (st.st_uid || st.st_gid || st.st_mode & S_IWOTH) | 116 if (st.st_uid || st.st_gid || st.st_mode & S_IWOTH) |
98 FatalError("Bad permissions on chroot directory (%s)", kSandboxPath); | 117 FatalError("Bad permissions on chroot temp directory"); |
99 | 118 |
100 if (chroot(".")) | 119 if (chroot(".")) |
101 FatalError("Cannot chroot into %s", kSandboxPath); | 120 FatalError("Cannot chroot into temp directory"); |
102 | 121 |
103 if (chdir("/")) | 122 if (chdir("/")) |
104 FatalError("Cannot chdir to / after chroot"); | 123 FatalError("Cannot chdir to / after chroot"); |
105 | 124 |
106 const char reply = kMsgChrootSuccessful; | 125 const char reply = kMsgChrootSuccessful; |
107 do { | 126 do { |
108 bytes = write(sv[0], &reply, 1); | 127 struct msghdr msg = {0}; |
| 128 struct iovec iov = {(char *) &reply, 1}; |
| 129 |
| 130 msg.msg_iov = &iov; |
| 131 msg.msg_iovlen = 1; |
| 132 |
| 133 char control_buffer[CMSG_SPACE(sizeof(int))]; |
| 134 msg.msg_control = control_buffer; |
| 135 msg.msg_controllen = sizeof(control_buffer); |
| 136 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); |
| 137 cmsg->cmsg_level = SOL_SOCKET; |
| 138 cmsg->cmsg_type = SCM_RIGHTS; |
| 139 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
| 140 memcpy(CMSG_DATA(cmsg), &chroot_dir_fd, sizeof(int)); |
| 141 msg.msg_controllen = cmsg->cmsg_len; |
| 142 |
| 143 bytes = sendmsg(sv[0], &msg, 0); |
109 } while (bytes == -1 && errno == EINTR); | 144 } while (bytes == -1 && errno == EINTR); |
110 | 145 |
111 if (bytes != 1) | 146 if (bytes != 1) |
112 FatalError("Writing reply"); | 147 FatalError("Writing reply"); |
113 | 148 |
114 _exit(0); | 149 _exit(0); |
115 } | 150 } |
116 | 151 |
117 if (close(sv[0])) { | 152 if (close(sv[0])) { |
118 close(sv[1]); | 153 close(sv[1]); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 if (!SpawnChrootHelper()) | 250 if (!SpawnChrootHelper()) |
216 return 1; | 251 return 1; |
217 if (!DropRoot()) | 252 if (!DropRoot()) |
218 return 1; | 253 return 1; |
219 | 254 |
220 execv(argv[1], &argv[1]); | 255 execv(argv[1], &argv[1]); |
221 FatalError("execv failed"); | 256 FatalError("execv failed"); |
222 | 257 |
223 return 1; | 258 return 1; |
224 } | 259 } |
OLD | NEW |