blob: fe83af03c3c186430f6efef6872f42220aadad09 [file] [log] [blame]
Paul Lawrencedfe84342017-02-16 09:24:39 -08001/*
2 * Copyright (C) 2017 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_policy.h"
18
Paul Lawrence89fa81f2017-02-17 10:22:03 -080019#include <assert.h>
Paul Lawrencedfe84342017-02-16 09:24:39 -080020#include <linux/audit.h>
Paul Lawrencedfe84342017-02-16 09:24:39 -080021#include <linux/seccomp.h>
22#include <sys/prctl.h>
23
24#include <vector>
25
26#include <android-base/logging.h>
27
Paul Lawrence89fa81f2017-02-17 10:22:03 -080028#include "seccomp_bpfs.h"
29
30
Paul Lawrencedfe84342017-02-16 09:24:39 -080031#if defined __arm__ || defined __aarch64__
32
Paul Lawrence89fa81f2017-02-17 10:22:03 -080033#define DUAL_ARCH
34#define PRIMARY_ARCH AUDIT_ARCH_AARCH64
35static const struct sock_filter* primary_filter = arm64_filter;
36static const size_t primary_filter_size = arm64_filter_size;
37#define SECONDARY_ARCH AUDIT_ARCH_ARM
38static const struct sock_filter* secondary_filter = arm_filter;
39static const size_t secondary_filter_size = arm_filter_size;
40
41#elif defined __i386__ || defined __x86_64__
42
43#define DUAL_ARCH
44#define PRIMARY_ARCH AUDIT_ARCH_X86_64
45static const struct sock_filter* primary_filter = x86_64_filter;
46static const size_t primary_filter_size = x86_64_filter_size;
47#define SECONDARY_ARCH AUDIT_ARCH_I386
48static const struct sock_filter* secondary_filter = x86_filter;
49static const size_t secondary_filter_size = x86_filter_size;
50
51#elif defined __mips__ || defined __mips64__
52
53#define DUAL_ARCH
Lazar Trsic22b43512017-05-05 14:29:34 +020054#define PRIMARY_ARCH AUDIT_ARCH_MIPSEL64
Paul Lawrence89fa81f2017-02-17 10:22:03 -080055static const struct sock_filter* primary_filter = mips64_filter;
56static const size_t primary_filter_size = mips64_filter_size;
Lazar Trsic22b43512017-05-05 14:29:34 +020057#define SECONDARY_ARCH AUDIT_ARCH_MIPSEL
Paul Lawrence89fa81f2017-02-17 10:22:03 -080058static const struct sock_filter* secondary_filter = mips_filter;
59static const size_t secondary_filter_size = mips_filter_size;
60
61#else
62#error No architecture was defined!
63#endif
64
Paul Lawrencedfe84342017-02-16 09:24:39 -080065
66#define syscall_nr (offsetof(struct seccomp_data, nr))
67#define arch_nr (offsetof(struct seccomp_data, arch))
68
69typedef std::vector<sock_filter> filter;
70
Paul Lawrence89fa81f2017-02-17 10:22:03 -080071inline void Disallow(filter& f) {
Paul Lawrencedfe84342017-02-16 09:24:39 -080072 f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP));
73}
74
Paul Lawrence89fa81f2017-02-17 10:22:03 -080075static void ExamineSyscall(filter& f) {
Paul Lawrencedfe84342017-02-16 09:24:39 -080076 f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr));
77}
78
Paul Lawrence89fa81f2017-02-17 10:22:03 -080079#ifdef DUAL_ARCH
80static bool SetValidateArchitectureJumpTarget(size_t offset, filter& f) {
Paul Lawrencedfe84342017-02-16 09:24:39 -080081 size_t jump_length = f.size() - offset - 1;
82 auto u8_jump_length = (__u8) jump_length;
83 if (u8_jump_length != jump_length) {
84 LOG(FATAL)
85 << "Can't set jump greater than 255 - actual jump is " << jump_length;
Paul Lawrence89fa81f2017-02-17 10:22:03 -080086 return false;
Paul Lawrencedfe84342017-02-16 09:24:39 -080087 }
Paul Lawrence89fa81f2017-02-17 10:22:03 -080088 f[offset] = BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SECONDARY_ARCH, u8_jump_length, 0);
89 return true;
Paul Lawrencedfe84342017-02-16 09:24:39 -080090}
91
Paul Lawrence89fa81f2017-02-17 10:22:03 -080092static size_t ValidateArchitectureAndJumpIfNeeded(filter& f) {
Paul Lawrencedfe84342017-02-16 09:24:39 -080093 f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
Paul Lawrence89fa81f2017-02-17 10:22:03 -080094 f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, PRIMARY_ARCH, 2, 0));
95 f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SECONDARY_ARCH, 1, 0));
96 Disallow(f);
Paul Lawrencedfe84342017-02-16 09:24:39 -080097 return f.size() - 2;
98}
Paul Lawrence89fa81f2017-02-17 10:22:03 -080099#else
100static void ValidateArchitecture(filter& f) {
101 f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
102 f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, PRIMARY_ARCH, 1, 0));
103 Disallow(f);
104}
105#endif
Paul Lawrencedfe84342017-02-16 09:24:39 -0800106
107static bool install_filter(filter const& f) {
108 struct sock_fprog prog = {
109 static_cast<unsigned short>(f.size()),
110 const_cast<struct sock_filter*>(&f[0]),
111 };
112
113 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
114 PLOG(FATAL) << "Could not set seccomp filter of size " << f.size();
115 return false;
116 }
117
118 LOG(INFO) << "Global filter of size " << f.size() << " installed";
119 return true;
120}
121
122bool set_seccomp_filter() {
123 filter f;
124
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800125#ifdef DUAL_ARCH
Paul Lawrencedfe84342017-02-16 09:24:39 -0800126 // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
127 // jump that must be changed to point to the start of the 32-bit policy
128 // 32 bit syscalls will not hit the policy between here and the call to SetJump
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800129 auto offset_to_secondary_filter = ValidateArchitectureAndJumpIfNeeded(f);
130#else
131 ValidateArchitecture(f);
132#endif
Paul Lawrencedfe84342017-02-16 09:24:39 -0800133
Paul Lawrencedfe84342017-02-16 09:24:39 -0800134 ExamineSyscall(f);
135
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800136 for (size_t i = 0; i < primary_filter_size; ++i) {
137 f.push_back(primary_filter[i]);
Paul Lawrencedfe84342017-02-16 09:24:39 -0800138 }
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800139 Disallow(f);
Paul Lawrencedfe84342017-02-16 09:24:39 -0800140
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800141#ifdef DUAL_ARCH
142 if (!SetValidateArchitectureJumpTarget(offset_to_secondary_filter, f)) {
143 return false;
Paul Lawrencedfe84342017-02-16 09:24:39 -0800144 }
145
Paul Lawrencedfe84342017-02-16 09:24:39 -0800146 ExamineSyscall(f);
147
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800148 for (size_t i = 0; i < secondary_filter_size; ++i) {
149 f.push_back(secondary_filter[i]);
Paul Lawrencedfe84342017-02-16 09:24:39 -0800150 }
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800151 Disallow(f);
152#endif
Paul Lawrencedfe84342017-02-16 09:24:39 -0800153
154 return install_filter(f);
155}
Paul Lawrence26f57b62017-03-27 15:38:37 -0700156
157void get_seccomp_filter(const sock_filter*& filter, size_t& filter_size) {
158#if defined __aarch64__ || defined __x86_64__ || defined __mips64__
159 filter = primary_filter;
160 filter_size = primary_filter_size;
161#else
162 filter = secondary_filter;
163 filter_size = secondary_filter_size;
164#endif
165}