| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" | 5 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <fcntl.h> | 9 #include <fcntl.h> |
| 10 #include <linux/net.h> | 10 #include <linux/net.h> |
| 11 #include <sched.h> | 11 #include <sched.h> |
| 12 #include <signal.h> | 12 #include <signal.h> |
| 13 #include <sys/ioctl.h> | 13 #include <sys/ioctl.h> |
| 14 #include <sys/mman.h> | 14 #include <sys/mman.h> |
| 15 #include <sys/prctl.h> | 15 #include <sys/prctl.h> |
| 16 #include <sys/stat.h> | 16 #include <sys/stat.h> |
| 17 #include <sys/types.h> | 17 #include <sys/types.h> |
| 18 #include <unistd.h> | 18 #include <unistd.h> |
| 19 | 19 |
| 20 #include "base/basictypes.h" | 20 #include "base/basictypes.h" |
| 21 #include "base/logging.h" | 21 #include "base/logging.h" |
| 22 #include "build/build_config.h" | 22 #include "build/build_config.h" |
| 23 #include "sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h" |
| 23 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" | 24 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" |
| 24 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" | 25 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" |
| 25 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 26 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| 26 | 27 |
| 27 #if defined(OS_ANDROID) | 28 #if defined(OS_ANDROID) |
| 28 #if !defined(F_DUPFD_CLOEXEC) | 29 #if !defined(F_DUPFD_CLOEXEC) |
| 29 #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) | 30 #define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) |
| 30 #endif | 31 #endif |
| 31 #endif | 32 #endif |
| 32 | 33 |
| 33 #if defined(__arm__) && !defined(MAP_STACK) | 34 #if defined(__arm__) && !defined(MAP_STACK) |
| 34 #define MAP_STACK 0x20000 // Daisy build environment has old headers. | 35 #define MAP_STACK 0x20000 // Daisy build environment has old headers. |
| 35 #endif | 36 #endif |
| 36 | 37 |
| 38 using namespace sandbox::bpf_dsl; |
| 39 |
| 37 namespace { | 40 namespace { |
| 38 | 41 |
| 39 inline bool IsArchitectureX86_64() { | 42 inline bool IsArchitectureX86_64() { |
| 40 #if defined(__x86_64__) | 43 #if defined(__x86_64__) |
| 41 return true; | 44 return true; |
| 42 #else | 45 #else |
| 43 return false; | 46 return false; |
| 44 #endif | 47 #endif |
| 45 } | 48 } |
| 46 | 49 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 60 #endif | 63 #endif |
| 61 } | 64 } |
| 62 | 65 |
| 63 } // namespace. | 66 } // namespace. |
| 64 | 67 |
| 65 namespace sandbox { | 68 namespace sandbox { |
| 66 | 69 |
| 67 // Allow Glibc's and Android pthread creation flags, crash on any other | 70 // Allow Glibc's and Android pthread creation flags, crash on any other |
| 68 // thread creation attempts and EPERM attempts to use neither | 71 // thread creation attempts and EPERM attempts to use neither |
| 69 // CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations. | 72 // CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations. |
| 70 ErrorCode RestrictCloneToThreadsAndEPERMFork(SandboxBPF* sandbox) { | 73 ResultExpr RestrictCloneToThreadsAndEPERMFork() { |
| 74 const Arg<int> flags_arg(0); |
| 71 if (!IsAndroid()) { | 75 if (!IsAndroid()) { |
| 72 const uint64_t kGlibcPthreadFlags = | 76 const uint64_t kGlibcPthreadFlags = |
| 73 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | | 77 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | |
| 74 CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | | 78 CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | |
| 75 CLONE_CHILD_CLEARTID; | 79 CLONE_CHILD_CLEARTID; |
| 76 | 80 |
| 77 return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 81 return If(flags_arg == kGlibcPthreadFlags).Then( |
| 78 kGlibcPthreadFlags, | 82 Allow() |
| 79 ErrorCode(ErrorCode::ERR_ALLOWED), | 83 ).ElseIf((flags_arg & (CLONE_VM | CLONE_THREAD)) == 0).Then( |
| 80 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, | 84 Error(EPERM) |
| 81 CLONE_VM | CLONE_THREAD, | 85 ).Else( |
| 82 sandbox->Trap(SIGSYSCloneFailure, NULL), | 86 bpf_dsl::Trap(SIGSYSCloneFailure, NULL) |
| 83 ErrorCode(EPERM))); | 87 ); |
| 84 } else { | 88 } else { |
| 85 const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES | | 89 const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES | |
| 86 CLONE_SIGHAND | CLONE_THREAD | | 90 CLONE_SIGHAND | CLONE_THREAD | |
| 87 CLONE_SYSVSEM; | 91 CLONE_SYSVSEM; |
| 88 const uint64_t kObsoleteAndroidCloneMask = | 92 const uint64_t kObsoleteAndroidCloneMask = |
| 89 kAndroidCloneMask | CLONE_DETACHED; | 93 kAndroidCloneMask | CLONE_DETACHED; |
| 90 | 94 |
| 91 return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 95 return If(flags_arg == kAndroidCloneMask || |
| 92 kAndroidCloneMask, | 96 flags_arg == kObsoleteAndroidCloneMask).Then( |
| 93 ErrorCode(ErrorCode::ERR_ALLOWED), | 97 Allow() |
| 94 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 98 ).ElseIf((flags_arg & (CLONE_VM | CLONE_THREAD)) == 0).Then( |
| 95 kObsoleteAndroidCloneMask, | 99 Error(EPERM) |
| 96 ErrorCode(ErrorCode::ERR_ALLOWED), | 100 ).Else( |
| 97 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, | 101 bpf_dsl::Trap(SIGSYSCloneFailure, NULL) |
| 98 CLONE_VM | CLONE_THREAD, | 102 ); |
| 99 sandbox->Trap(SIGSYSCloneFailure, NULL), | |
| 100 ErrorCode(EPERM)))); | |
| 101 } | 103 } |
| 102 } | 104 } |
| 103 | 105 |
| 104 ErrorCode RestrictPrctl(SandboxBPF* sandbox) { | 106 ResultExpr RestrictPrctl() { |
| 105 // Will need to add seccomp compositing in the future. PR_SET_PTRACER is | 107 // Will need to add seccomp compositing in the future. PR_SET_PTRACER is |
| 106 // used by breakpad but not needed anymore. | 108 // used by breakpad but not needed anymore. |
| 107 return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 109 const Arg<int> option_arg(0); |
| 108 PR_SET_NAME, ErrorCode(ErrorCode::ERR_ALLOWED), | 110 return If(option_arg == PR_SET_NAME || |
| 109 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 111 option_arg == PR_SET_DUMPABLE || |
| 110 PR_SET_DUMPABLE, ErrorCode(ErrorCode::ERR_ALLOWED), | 112 option_arg == PR_GET_DUMPABLE).Then( |
| 111 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 113 Allow() |
| 112 PR_GET_DUMPABLE, ErrorCode(ErrorCode::ERR_ALLOWED), | 114 ).Else( |
| 113 sandbox->Trap(SIGSYSPrctlFailure, NULL)))); | 115 bpf_dsl::Trap(SIGSYSPrctlFailure, NULL) |
| 116 ); |
| 114 } | 117 } |
| 115 | 118 |
| 116 ErrorCode RestrictIoctl(SandboxBPF* sandbox) { | 119 ResultExpr RestrictIoctl() { |
| 117 return sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, TCGETS, | 120 const Arg<int> request_arg(1); |
| 118 ErrorCode(ErrorCode::ERR_ALLOWED), | 121 return If(request_arg == TCGETS || request_arg == FIONREAD).Then( |
| 119 sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, FIONREAD, | 122 Allow() |
| 120 ErrorCode(ErrorCode::ERR_ALLOWED), | 123 ).Else( |
| 121 sandbox->Trap(SIGSYSIoctlFailure, NULL))); | 124 bpf_dsl::Trap(SIGSYSIoctlFailure, NULL) |
| 125 ); |
| 122 } | 126 } |
| 123 | 127 |
| 124 ErrorCode RestrictMmapFlags(SandboxBPF* sandbox) { | 128 ResultExpr RestrictMmapFlags() { |
| 125 // The flags you see are actually the allowed ones, and the variable is a | 129 // The flags you see are actually the allowed ones, and the variable is a |
| 126 // "denied" mask because of the negation operator. | 130 // "denied" mask because of the negation operator. |
| 127 // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as | 131 // Significantly, we don't permit MAP_HUGETLB, or the newer flags such as |
| 128 // MAP_POPULATE. | 132 // MAP_POPULATE. |
| 129 // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries. | 133 // TODO(davidung), remove MAP_DENYWRITE with updated Tegra libraries. |
| 130 uint32_t denied_mask = ~(MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | | 134 uint32_t denied_mask = ~(MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS | |
| 131 MAP_STACK | MAP_NORESERVE | MAP_FIXED | | 135 MAP_STACK | MAP_NORESERVE | MAP_FIXED | |
| 132 MAP_DENYWRITE); | 136 MAP_DENYWRITE); |
| 133 return sandbox->Cond(3, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, | 137 const Arg<int> flags_arg(3); |
| 134 denied_mask, | 138 return If((flags_arg & denied_mask) == 0).Then( |
| 135 sandbox->Trap(CrashSIGSYS_Handler, NULL), | 139 Allow() |
| 136 ErrorCode(ErrorCode::ERR_ALLOWED)); | 140 ).Else( |
| 141 bpf_dsl::Trap(CrashSIGSYS_Handler, NULL) |
| 142 ); |
| 137 } | 143 } |
| 138 | 144 |
| 139 ErrorCode RestrictMprotectFlags(SandboxBPF* sandbox) { | 145 ResultExpr RestrictMprotectFlags() { |
| 140 // The flags you see are actually the allowed ones, and the variable is a | 146 // The flags you see are actually the allowed ones, and the variable is a |
| 141 // "denied" mask because of the negation operator. | 147 // "denied" mask because of the negation operator. |
| 142 // Significantly, we don't permit weird undocumented flags such as | 148 // Significantly, we don't permit weird undocumented flags such as |
| 143 // PROT_GROWSDOWN. | 149 // PROT_GROWSDOWN. |
| 144 uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC); | 150 uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC); |
| 145 return sandbox->Cond(2, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, | 151 const Arg<int> prot_arg(2); |
| 146 denied_mask, | 152 return If((prot_arg & denied_mask) == 0).Then( |
| 147 sandbox->Trap(CrashSIGSYS_Handler, NULL), | 153 Allow() |
| 148 ErrorCode(ErrorCode::ERR_ALLOWED)); | 154 ).Else( |
| 155 bpf_dsl::Trap(CrashSIGSYS_Handler, NULL) |
| 156 ); |
| 149 } | 157 } |
| 150 | 158 |
| 151 ErrorCode RestrictFcntlCommands(SandboxBPF* sandbox) { | 159 ResultExpr RestrictFcntlCommands() { |
| 152 // We also restrict the flags in F_SETFL. We don't want to permit flags with | 160 // We also restrict the flags in F_SETFL. We don't want to permit flags with |
| 153 // a history of trouble such as O_DIRECT. The flags you see are actually the | 161 // a history of trouble such as O_DIRECT. The flags you see are actually the |
| 154 // allowed ones, and the variable is a "denied" mask because of the negation | 162 // allowed ones, and the variable is a "denied" mask because of the negation |
| 155 // operator. | 163 // operator. |
| 156 // Glibc overrides the kernel's O_LARGEFILE value. Account for this. | 164 // Glibc overrides the kernel's O_LARGEFILE value. Account for this. |
| 157 int kOLargeFileFlag = O_LARGEFILE; | 165 int kOLargeFileFlag = O_LARGEFILE; |
| 158 if (IsArchitectureX86_64() || IsArchitectureI386()) | 166 if (IsArchitectureX86_64() || IsArchitectureI386()) |
| 159 kOLargeFileFlag = 0100000; | 167 kOLargeFileFlag = 0100000; |
| 160 | 168 |
| 161 // TODO(jln): add TP_LONG/TP_SIZET types. | |
| 162 ErrorCode::ArgType mask_long_type; | |
| 163 if (sizeof(long) == 8) | |
| 164 mask_long_type = ErrorCode::TP_64BIT; | |
| 165 else if (sizeof(long) == 4) | |
| 166 mask_long_type = ErrorCode::TP_32BIT; | |
| 167 else | |
| 168 NOTREACHED(); | |
| 169 | |
| 170 unsigned long denied_mask = ~(O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC | | 169 unsigned long denied_mask = ~(O_ACCMODE | O_APPEND | O_NONBLOCK | O_SYNC | |
| 171 kOLargeFileFlag | O_CLOEXEC | O_NOATIME); | 170 kOLargeFileFlag | O_CLOEXEC | O_NOATIME); |
| 172 return sandbox->Cond(1, ErrorCode::TP_32BIT, | 171 const Arg<int> cmd_arg(1); |
| 173 ErrorCode::OP_EQUAL, F_GETFL, | 172 const Arg<unsigned long> flags_arg(2); |
| 174 ErrorCode(ErrorCode::ERR_ALLOWED), | 173 |
| 175 sandbox->Cond(1, ErrorCode::TP_32BIT, | 174 return If(cmd_arg == F_GETFL || |
| 176 ErrorCode::OP_EQUAL, F_SETFL, | 175 (cmd_arg == F_SETFL && (flags_arg & denied_mask) == 0) || |
| 177 sandbox->Cond(2, mask_long_type, | 176 cmd_arg == F_GETFD || |
| 178 ErrorCode::OP_HAS_ANY_BITS, denied_mask, | 177 cmd_arg == F_SETFD || |
| 179 sandbox->Trap(CrashSIGSYS_Handler, NULL), | 178 cmd_arg == F_DUPFD || |
| 180 ErrorCode(ErrorCode::ERR_ALLOWED)), | 179 cmd_arg == F_SETLK || |
| 181 sandbox->Cond(1, ErrorCode::TP_32BIT, | 180 cmd_arg == F_SETLKW || |
| 182 ErrorCode::OP_EQUAL, F_GETFD, | 181 cmd_arg == F_GETLK || |
| 183 ErrorCode(ErrorCode::ERR_ALLOWED), | 182 cmd_arg == F_DUPFD_CLOEXEC).Then( |
| 184 sandbox->Cond(1, ErrorCode::TP_32BIT, | 183 Allow() |
| 185 ErrorCode::OP_EQUAL, F_SETFD, | 184 ).Else( |
| 186 ErrorCode(ErrorCode::ERR_ALLOWED), | 185 bpf_dsl::Trap(CrashSIGSYS_Handler, NULL) |
| 187 sandbox->Cond(1, ErrorCode::TP_32BIT, | 186 ); |
| 188 ErrorCode::OP_EQUAL, F_DUPFD, | |
| 189 ErrorCode(ErrorCode::ERR_ALLOWED), | |
| 190 sandbox->Cond(1, ErrorCode::TP_32BIT, | |
| 191 ErrorCode::OP_EQUAL, F_SETLK, | |
| 192 ErrorCode(ErrorCode::ERR_ALLOWED), | |
| 193 sandbox->Cond(1, ErrorCode::TP_32BIT, | |
| 194 ErrorCode::OP_EQUAL, F_SETLKW, | |
| 195 ErrorCode(ErrorCode::ERR_ALLOWED), | |
| 196 sandbox->Cond(1, ErrorCode::TP_32BIT, | |
| 197 ErrorCode::OP_EQUAL, F_GETLK, | |
| 198 ErrorCode(ErrorCode::ERR_ALLOWED), | |
| 199 sandbox->Cond(1, ErrorCode::TP_32BIT, | |
| 200 ErrorCode::OP_EQUAL, F_DUPFD_CLOEXEC, | |
| 201 ErrorCode(ErrorCode::ERR_ALLOWED), | |
| 202 sandbox->Trap(CrashSIGSYS_Handler, NULL)))))))))); | |
| 203 } | 187 } |
| 204 | 188 |
| 205 #if defined(__i386__) | 189 #if defined(__i386__) |
| 206 ErrorCode RestrictSocketcallCommand(SandboxBPF* sandbox) { | 190 ResultExpr RestrictSocketcallCommand() { |
| 207 // Unfortunately, we are unable to restrict the first parameter to | 191 // Unfortunately, we are unable to restrict the first parameter to |
| 208 // socketpair(2). Whilst initially sounding bad, it's noteworthy that very | 192 // socketpair(2). Whilst initially sounding bad, it's noteworthy that very |
| 209 // few protocols actually support socketpair(2). The scary call that we're | 193 // few protocols actually support socketpair(2). The scary call that we're |
| 210 // worried about, socket(2), remains blocked. | 194 // worried about, socket(2), remains blocked. |
| 211 return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 195 const Arg<int> call_arg(0); |
| 212 SYS_SOCKETPAIR, ErrorCode(ErrorCode::ERR_ALLOWED), | 196 return If(call_arg == SYS_SOCKETPAIR || |
| 213 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 197 call_arg == SYS_SEND || |
| 214 SYS_SEND, ErrorCode(ErrorCode::ERR_ALLOWED), | 198 call_arg == SYS_RECV || |
| 215 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 199 call_arg == SYS_SENDTO || |
| 216 SYS_RECV, ErrorCode(ErrorCode::ERR_ALLOWED), | 200 call_arg == SYS_RECVFROM || |
| 217 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 201 call_arg == SYS_SHUTDOWN || |
| 218 SYS_SENDTO, ErrorCode(ErrorCode::ERR_ALLOWED), | 202 call_arg == SYS_SENDMSG || |
| 219 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 203 call_arg == SYS_RECVMSG).Then( |
| 220 SYS_RECVFROM, ErrorCode(ErrorCode::ERR_ALLOWED), | 204 Allow() |
| 221 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 205 ).Else( |
| 222 SYS_SHUTDOWN, ErrorCode(ErrorCode::ERR_ALLOWED), | 206 Error(EPERM) |
| 223 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 207 ); |
| 224 SYS_SENDMSG, ErrorCode(ErrorCode::ERR_ALLOWED), | |
| 225 sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | |
| 226 SYS_RECVMSG, ErrorCode(ErrorCode::ERR_ALLOWED), | |
| 227 ErrorCode(EPERM))))))))); | |
| 228 } | 208 } |
| 229 #endif | 209 #endif |
| 230 | 210 |
| 231 ErrorCode RestrictKillTarget(pid_t target_pid, SandboxBPF* sandbox, int sysno) { | 211 ResultExpr RestrictKillTarget(pid_t target_pid, int sysno) { |
| 232 switch (sysno) { | 212 switch (sysno) { |
| 233 case __NR_kill: | 213 case __NR_kill: |
| 234 case __NR_tgkill: | 214 case __NR_tgkill: { |
| 235 return sandbox->Cond(0, | 215 const Arg<pid_t> target_arg(0); |
| 236 ErrorCode::TP_32BIT, | 216 return If(target_arg == target_pid).Then( |
| 237 ErrorCode::OP_EQUAL, | 217 Allow() |
| 238 target_pid, | 218 ).Else( |
| 239 ErrorCode(ErrorCode::ERR_ALLOWED), | 219 bpf_dsl::Trap(SIGSYSKillFailure, NULL) |
| 240 sandbox->Trap(SIGSYSKillFailure, NULL)); | 220 ); |
| 221 } |
| 241 case __NR_tkill: | 222 case __NR_tkill: |
| 242 return sandbox->Trap(SIGSYSKillFailure, NULL); | 223 return bpf_dsl::Trap(SIGSYSKillFailure, NULL); |
| 243 default: | 224 default: |
| 244 NOTREACHED(); | 225 NOTREACHED(); |
| 245 return sandbox->Trap(CrashSIGSYS_Handler, NULL); | 226 return bpf_dsl::Trap(CrashSIGSYS_Handler, NULL); |
| 246 } | 227 } |
| 247 } | 228 } |
| 248 | 229 |
| 249 } // namespace sandbox. | 230 } // namespace sandbox. |
| OLD | NEW |