blob: d93ae1e2991c2f0886c76f9c66919030ded73bb2 [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>
21#include <linux/filter.h>
22#include <linux/seccomp.h>
23#include <sys/prctl.h>
24
25#include <vector>
26
27#include <android-base/logging.h>
28
Paul Lawrence89fa81f2017-02-17 10:22:03 -080029#include "seccomp_bpfs.h"
30
31
Paul Lawrencedfe84342017-02-16 09:24:39 -080032#if defined __arm__ || defined __aarch64__
33
Paul Lawrence89fa81f2017-02-17 10:22:03 -080034#define DUAL_ARCH
35#define PRIMARY_ARCH AUDIT_ARCH_AARCH64
36static const struct sock_filter* primary_filter = arm64_filter;
37static const size_t primary_filter_size = arm64_filter_size;
38#define SECONDARY_ARCH AUDIT_ARCH_ARM
39static const struct sock_filter* secondary_filter = arm_filter;
40static const size_t secondary_filter_size = arm_filter_size;
41
42#elif defined __i386__ || defined __x86_64__
43
44#define DUAL_ARCH
45#define PRIMARY_ARCH AUDIT_ARCH_X86_64
46static const struct sock_filter* primary_filter = x86_64_filter;
47static const size_t primary_filter_size = x86_64_filter_size;
48#define SECONDARY_ARCH AUDIT_ARCH_I386
49static const struct sock_filter* secondary_filter = x86_filter;
50static const size_t secondary_filter_size = x86_filter_size;
51
52#elif defined __mips__ || defined __mips64__
53
54#define DUAL_ARCH
55#define PRIMARY_ARCH AUDIT_ARCH_MIPS64
56static const struct sock_filter* primary_filter = mips64_filter;
57static const size_t primary_filter_size = mips64_filter_size;
58#define SECONDARY_ARCH AUDIT_ARCH_MIPS
59static const struct sock_filter* secondary_filter = mips_filter;
60static const size_t secondary_filter_size = mips_filter_size;
61
62#else
63#error No architecture was defined!
64#endif
65
Paul Lawrencedfe84342017-02-16 09:24:39 -080066
67#define syscall_nr (offsetof(struct seccomp_data, nr))
68#define arch_nr (offsetof(struct seccomp_data, arch))
69
70typedef std::vector<sock_filter> filter;
71
Paul Lawrence89fa81f2017-02-17 10:22:03 -080072inline void Disallow(filter& f) {
Paul Lawrencedfe84342017-02-16 09:24:39 -080073 f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP));
74}
75
Paul Lawrence89fa81f2017-02-17 10:22:03 -080076static void ExamineSyscall(filter& f) {
Paul Lawrencedfe84342017-02-16 09:24:39 -080077 f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr));
78}
79
Paul Lawrence89fa81f2017-02-17 10:22:03 -080080#ifdef DUAL_ARCH
81static bool SetValidateArchitectureJumpTarget(size_t offset, filter& f) {
Paul Lawrencedfe84342017-02-16 09:24:39 -080082 size_t jump_length = f.size() - offset - 1;
83 auto u8_jump_length = (__u8) jump_length;
84 if (u8_jump_length != jump_length) {
85 LOG(FATAL)
86 << "Can't set jump greater than 255 - actual jump is " << jump_length;
Paul Lawrence89fa81f2017-02-17 10:22:03 -080087 return false;
Paul Lawrencedfe84342017-02-16 09:24:39 -080088 }
Paul Lawrence89fa81f2017-02-17 10:22:03 -080089 f[offset] = BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SECONDARY_ARCH, u8_jump_length, 0);
90 return true;
Paul Lawrencedfe84342017-02-16 09:24:39 -080091}
92
Paul Lawrence89fa81f2017-02-17 10:22:03 -080093static size_t ValidateArchitectureAndJumpIfNeeded(filter& f) {
Paul Lawrencedfe84342017-02-16 09:24:39 -080094 f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
Paul Lawrence89fa81f2017-02-17 10:22:03 -080095 f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, PRIMARY_ARCH, 2, 0));
96 f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SECONDARY_ARCH, 1, 0));
97 Disallow(f);
Paul Lawrencedfe84342017-02-16 09:24:39 -080098 return f.size() - 2;
99}
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800100#else
101static void ValidateArchitecture(filter& f) {
102 f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
103 f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, PRIMARY_ARCH, 1, 0));
104 Disallow(f);
105}
106#endif
Paul Lawrencedfe84342017-02-16 09:24:39 -0800107
108static bool install_filter(filter const& f) {
109 struct sock_fprog prog = {
110 static_cast<unsigned short>(f.size()),
111 const_cast<struct sock_filter*>(&f[0]),
112 };
113
114 if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
115 PLOG(FATAL) << "Could not set seccomp filter of size " << f.size();
116 return false;
117 }
118
119 LOG(INFO) << "Global filter of size " << f.size() << " installed";
120 return true;
121}
122
123bool set_seccomp_filter() {
124 filter f;
125
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800126#ifdef DUAL_ARCH
Paul Lawrencedfe84342017-02-16 09:24:39 -0800127 // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
128 // jump that must be changed to point to the start of the 32-bit policy
129 // 32 bit syscalls will not hit the policy between here and the call to SetJump
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800130 auto offset_to_secondary_filter = ValidateArchitectureAndJumpIfNeeded(f);
131#else
132 ValidateArchitecture(f);
133#endif
Paul Lawrencedfe84342017-02-16 09:24:39 -0800134
Paul Lawrencedfe84342017-02-16 09:24:39 -0800135 ExamineSyscall(f);
136
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800137 for (size_t i = 0; i < primary_filter_size; ++i) {
138 f.push_back(primary_filter[i]);
Paul Lawrencedfe84342017-02-16 09:24:39 -0800139 }
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800140 Disallow(f);
Paul Lawrencedfe84342017-02-16 09:24:39 -0800141
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800142#ifdef DUAL_ARCH
143 if (!SetValidateArchitectureJumpTarget(offset_to_secondary_filter, f)) {
144 return false;
Paul Lawrencedfe84342017-02-16 09:24:39 -0800145 }
146
Paul Lawrencedfe84342017-02-16 09:24:39 -0800147 ExamineSyscall(f);
148
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800149 for (size_t i = 0; i < secondary_filter_size; ++i) {
150 f.push_back(secondary_filter[i]);
Paul Lawrencedfe84342017-02-16 09:24:39 -0800151 }
Paul Lawrence89fa81f2017-02-17 10:22:03 -0800152 Disallow(f);
153#endif
Paul Lawrencedfe84342017-02-16 09:24:39 -0800154
155 return install_filter(f);
156}