diff options
Diffstat (limited to 'init/seccomp.cpp')
-rw-r--r-- | init/seccomp.cpp | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/init/seccomp.cpp b/init/seccomp.cpp new file mode 100644 index 000000000..d9f2f7929 --- /dev/null +++ b/init/seccomp.cpp | |||
@@ -0,0 +1,213 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2016 The Android Open Source Project | ||
3 | * | ||
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | * you may not use this file except in compliance with the License. | ||
6 | * You may obtain a copy of the License at | ||
7 | * | ||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | * | ||
10 | * Unless required by applicable law or agreed to in writing, software | ||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | * See the License for the specific language governing permissions and | ||
14 | * limitations under the License. | ||
15 | */ | ||
16 | |||
17 | #include "seccomp.h" | ||
18 | |||
19 | #include <vector> | ||
20 | |||
21 | #include <sys/prctl.h> | ||
22 | |||
23 | #include <linux/unistd.h> | ||
24 | #include <linux/audit.h> | ||
25 | #include <linux/filter.h> | ||
26 | #include <linux/seccomp.h> | ||
27 | |||
28 | #include "log.h" | ||
29 | #include "seccomp_policy.h" | ||
30 | |||
31 | #define syscall_nr (offsetof(struct seccomp_data, nr)) | ||
32 | #define arch_nr (offsetof(struct seccomp_data, arch)) | ||
33 | |||
34 | #if defined __arm__ | ||
35 | #define AUDIT_ARCH_NR AUDIT_ARCH_ARM | ||
36 | #elif defined __aarch64__ | ||
37 | #define AUDIT_ARCH_NR AUDIT_ARCH_AARCH64 | ||
38 | #define AUDIT_ARCH_NR32 AUDIT_ARCH_ARM | ||
39 | #elif defined __i386__ | ||
40 | #define AUDIT_ARCH_NR AUDIT_ARCH_I386 | ||
41 | #elif defined __x86_64__ | ||
42 | #define AUDIT_ARCH_NR AUDIT_ARCH_X86_64 | ||
43 | #define AUDIT_ARCH_NR32 AUDIT_ARCH_I386 | ||
44 | #elif defined __mips64__ | ||
45 | #define AUDIT_ARCH_NR AUDIT_ARCH_MIPS64 | ||
46 | #define AUDIT_ARCH_NR32 AUDIT_ARCH_MIPS | ||
47 | #elif defined __mips__ && !defined __mips64__ | ||
48 | #define AUDIT_ARCH_NR AUDIT_ARCH_MIPS | ||
49 | #else | ||
50 | #error "Could not determine AUDIT_ARCH_NR for this architecture" | ||
51 | #endif | ||
52 | |||
53 | typedef std::vector<sock_filter> filter; | ||
54 | |||
55 | // We want to keep the below inline functions for debugging and future | ||
56 | // development even though they are not used currently. | ||
57 | #pragma clang diagnostic push | ||
58 | #pragma clang diagnostic ignored "-Wunused-function" | ||
59 | |||
60 | static inline void Kill(filter& f) { | ||
61 | f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL)); | ||
62 | } | ||
63 | |||
64 | static inline void Trap(filter& f) { | ||
65 | f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP)); | ||
66 | } | ||
67 | |||
68 | static inline void Error(filter& f, __u16 retcode) { | ||
69 | f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO + retcode)); | ||
70 | } | ||
71 | |||
72 | inline static void Trace(filter& f) { | ||
73 | f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE)); | ||
74 | } | ||
75 | |||
76 | inline static void Allow(filter& f) { | ||
77 | f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW)); | ||
78 | } | ||
79 | |||
80 | inline static void AllowSyscall(filter& f, __u32 num) { | ||
81 | f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, num, 0, 1)); | ||
82 | f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW)); | ||
83 | } | ||
84 | |||
85 | inline static void ExamineSyscall(filter& f) { | ||
86 | f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr)); | ||
87 | } | ||
88 | |||
89 | #ifdef AUDIT_ARCH_NR32 | ||
90 | inline static int SetValidateArchitectureJumpTarget(size_t offset, filter& f) { | ||
91 | auto jump_length = f.size() - offset - 1; | ||
92 | auto u8_jump_length = (__u8) jump_length; | ||
93 | if (u8_jump_length != jump_length) { | ||
94 | LOG(ERROR) << "Can't set jump greater than 255 - actual jump is " << jump_length; | ||
95 | return -1; | ||
96 | } | ||
97 | f[offset] = BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR32, u8_jump_length, 0); | ||
98 | return 0; | ||
99 | } | ||
100 | #endif | ||
101 | |||
102 | inline static size_t ValidateArchitectureAndJumpIfNeeded(filter& f) { | ||
103 | f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr)); | ||
104 | |||
105 | #ifdef AUDIT_ARCH_NR32 | ||
106 | f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR, 2, 0)); | ||
107 | f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR32, 1, 0)); | ||
108 | Kill(f); | ||
109 | return f.size() - 2; | ||
110 | #else | ||
111 | f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_NR, 1, 0)); | ||
112 | Kill(f); | ||
113 | return 0; | ||
114 | #endif | ||
115 | } | ||
116 | |||
117 | #pragma clang diagnostic pop | ||
118 | |||
119 | static bool install_filter(filter const& f) { | ||
120 | struct sock_fprog prog = { | ||
121 | (unsigned short) f.size(), | ||
122 | (struct sock_filter*) &f[0], | ||
123 | }; | ||
124 | |||
125 | if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) { | ||
126 | PLOG(ERROR) << "SECCOMP: Could not set seccomp filter"; | ||
127 | return false; | ||
128 | } | ||
129 | |||
130 | LOG(INFO) << "SECCOMP: Global filter installed"; | ||
131 | return true; | ||
132 | } | ||
133 | |||
134 | bool set_seccomp_filter() { | ||
135 | filter f; | ||
136 | |||
137 | // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a | ||
138 | // jump that must be changed to point to the start of the 32-bit policy | ||
139 | // 32 bit syscalls will not hit the policy between here and the call to SetJump | ||
140 | #ifdef AUDIT_ARCH_NR32 | ||
141 | auto offset_to_32bit_filter = | ||
142 | #endif | ||
143 | ValidateArchitectureAndJumpIfNeeded(f); | ||
144 | |||
145 | // Native filter | ||
146 | ExamineSyscall(f); | ||
147 | |||
148 | #ifdef __aarch64__ | ||
149 | // Syscalls needed to boot Android | ||
150 | AllowSyscall(f, __NR_pivot_root); | ||
151 | AllowSyscall(f, __NR_ioprio_get); | ||
152 | AllowSyscall(f, __NR_ioprio_set); | ||
153 | AllowSyscall(f, __NR_gettid); | ||
154 | AllowSyscall(f, __NR_futex); | ||
155 | AllowSyscall(f, __NR_clone); | ||
156 | AllowSyscall(f, __NR_rt_sigreturn); | ||
157 | AllowSyscall(f, __NR_rt_tgsigqueueinfo); | ||
158 | AllowSyscall(f, __NR_add_key); | ||
159 | AllowSyscall(f, __NR_request_key); | ||
160 | AllowSyscall(f, __NR_keyctl); | ||
161 | AllowSyscall(f, __NR_restart_syscall); | ||
162 | AllowSyscall(f, __NR_getrandom); | ||
163 | |||
164 | // Needed for performance tools | ||
165 | AllowSyscall(f, __NR_perf_event_open); | ||
166 | |||
167 | // Needed for treble | ||
168 | AllowSyscall(f, __NR_finit_module); | ||
169 | |||
170 | // Needed for trusty | ||
171 | AllowSyscall(f, __NR_syncfs); | ||
172 | |||
173 | // arm64-only filter - autogenerated from bionic syscall usage | ||
174 | for (size_t i = 0; i < arm64_filter_size; ++i) | ||
175 | f.push_back(arm64_filter[i]); | ||
176 | #else | ||
177 | // Generic policy | ||
178 | Allow(f); | ||
179 | #endif | ||
180 | |||
181 | #ifdef AUDIT_ARCH_NR32 | ||
182 | if (SetValidateArchitectureJumpTarget(offset_to_32bit_filter, f) != 0) | ||
183 | return -1; | ||
184 | |||
185 | // 32-bit filter for 64-bit platforms | ||
186 | ExamineSyscall(f); | ||
187 | |||
188 | #ifdef __aarch64__ | ||
189 | // Syscalls needed to boot android | ||
190 | AllowSyscall(f, 120); // __NR_clone | ||
191 | AllowSyscall(f, 240); // __NR_futex | ||
192 | AllowSyscall(f, 119); // __NR_sigreturn | ||
193 | AllowSyscall(f, 173); // __NR_rt_sigreturn | ||
194 | AllowSyscall(f, 363); // __NR_rt_tgsigqueueinfo | ||
195 | AllowSyscall(f, 224); // __NR_gettid | ||
196 | |||
197 | // Syscalls needed to run Chrome | ||
198 | AllowSyscall(f, 383); // __NR_seccomp - needed to start Chrome | ||
199 | AllowSyscall(f, 384); // __NR_getrandom - needed to start Chrome | ||
200 | |||
201 | // Syscalls needed to run GFXBenchmark | ||
202 | AllowSyscall(f, 190); // __NR_vfork | ||
203 | |||
204 | // arm32-on-arm64 only filter - autogenerated from bionic syscall usage | ||
205 | for (size_t i = 0; i < arm_filter_size; ++i) | ||
206 | f.push_back(arm_filter[i]); | ||
207 | #else | ||
208 | // Generic policy | ||
209 | Allow(f); | ||
210 | #endif | ||
211 | #endif | ||
212 | return install_filter(f); | ||
213 | } | ||