Bundle libseccomp 2.3.1
[linux-seccomp.git] / libseccomp / src / arch-x86.c
CommitLineData
8befd5cc
MG
1/**
2 * Enhanced Seccomp x86 Specific Code
3 *
4 * Copyright (c) 2012,2016 Red Hat <pmoore@redhat.com>
5 * Author: Paul Moore <paul@paul-moore.com>
6 */
7
8/*
9 * This library is free software; you can redistribute it and/or modify it
10 * under the terms of version 2.1 of the GNU Lesser General Public License as
11 * published by the Free Software Foundation.
12 *
13 * This library is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, see <http://www.gnu.org/licenses>.
20 */
21
22#include <stdlib.h>
23#include <errno.h>
24#include <string.h>
25#include <linux/audit.h>
26
27#include "arch.h"
28#include "arch-x86.h"
29
30/* x86 syscall numbers */
31#define __x86_NR_socketcall 102
32#define __x86_NR_ipc 117
33
34const struct arch_def arch_def_x86 = {
35 .token = SCMP_ARCH_X86,
36 .token_bpf = AUDIT_ARCH_I386,
37 .size = ARCH_SIZE_32,
38 .endian = ARCH_ENDIAN_LITTLE,
39 .syscall_resolve_name = x86_syscall_resolve_name,
40 .syscall_resolve_num = x86_syscall_resolve_num,
41 .syscall_rewrite = x86_syscall_rewrite,
42 .rule_add = x86_rule_add,
43};
44
45/**
46 * Convert a multiplexed pseudo socket syscall into a direct syscall
47 * @param socketcall the multiplexed pseudo syscall number
48 *
49 * Return the related direct syscall number, __NR_SCMP_UNDEF is there is
50 * no related syscall, or __NR_SCMP_ERROR otherwise.
51 *
52 */
53int _x86_sock_demux(int socketcall)
54{
55 switch (socketcall) {
56 case -101:
57 /* socket */
58 return 359;
59 case -102:
60 /* bind */
61 return 361;
62 case -103:
63 /* connect */
64 return 362;
65 case -104:
66 /* listen */
67 return 363;
68 case -105:
69 /* accept - not defined */
70 return __NR_SCMP_UNDEF;
71 case -106:
72 /* getsockname */
73 return 367;
74 case -107:
75 /* getpeername */
76 return 368;
77 case -108:
78 /* socketpair */
79 return 360;
80 case -109:
81 /* send - not defined */
82 return __NR_SCMP_UNDEF;
83 case -110:
84 /* recv - not defined */
85 return __NR_SCMP_UNDEF;
86 case -111:
87 /* sendto */
88 return 369;
89 case -112:
90 /* recvfrom */
91 return 371;
92 case -113:
93 /* shutdown */
94 return 373;
95 case -114:
96 /* setsockopt */
97 return 366;
98 case -115:
99 /* getsockopt */
100 return 365;
101 case -116:
102 /* sendmsg */
103 return 370;
104 case -117:
105 /* recvmsg */
106 return 372;
107 case -118:
108 /* accept4 */
109 return 364;
110 case -119:
111 /* recvmmsg */
112 return 337;
113 case -120:
114 /* sendmmsg */
115 return 345;
116 }
117
118 return __NR_SCMP_ERROR;
119}
120
121/**
122 * Convert a direct socket syscall into multiplexed pseudo socket syscall
123 * @param syscall the direct syscall
124 *
125 * Return the related multiplexed pseduo syscall number, __NR_SCMP_UNDEF is
126 * there is no related pseudo syscall, or __NR_SCMP_ERROR otherwise.
127 *
128 */
129int _x86_sock_mux(int syscall)
130{
131 switch (syscall) {
132 case 337:
133 /* recvmmsg */
134 return -119;
135 case 345:
136 /* sendmmsg */
137 return -120;
138 case 359:
139 /* socket */
140 return -101;
141 case 360:
142 /* socketpair */
143 return -108;
144 case 361:
145 /* bind */
146 return -102;
147 case 362:
148 /* connect */
149 return -103;
150 case 363:
151 /* listen */
152 return -104;
153 case 364:
154 /* accept4 */
155 return -118;
156 case 365:
157 /* getsockopt */
158 return -115;
159 case 366:
160 /* setsockopt */
161 return -114;
162 case 367:
163 /* getsockname */
164 return -106;
165 case 368:
166 /* getpeername */
167 return -107;
168 case 369:
169 /* sendto */
170 return -111;
171 case 370:
172 /* sendmsg */
173 return -116;
174 case 371:
175 /* recvfrom */
176 return -112;
177 case 372:
178 /* recvmsg */
179 return -117;
180 case 373:
181 /* shutdown */
182 return -113;
183 }
184
185 return __NR_SCMP_ERROR;
186}
187
188/**
189 * Rewrite a syscall value to match the architecture
190 * @param syscall the syscall number
191 *
192 * Syscalls can vary across different architectures so this function rewrites
193 * the syscall into the correct value for the specified architecture. Returns
194 * zero on success, negative values on failure.
195 *
196 */
197int x86_syscall_rewrite(int *syscall)
198{
199 int sys = *syscall;
200
201 if (sys <= -100 && sys >= -120)
202 *syscall = __x86_NR_socketcall;
203 else if (sys <= -200 && sys >= -224)
204 *syscall = __x86_NR_ipc;
205 else if (sys < 0)
206 return -EDOM;
207
208 return 0;
209}
210
211/**
212 * add a new rule to the x86 seccomp filter
213 * @param col the filter collection
214 * @param db the seccomp filter db
215 * @param strict the strict flag
216 * @param rule the filter rule
217 *
218 * This function adds a new syscall filter to the seccomp filter db, making any
219 * necessary adjustments for the x86 ABI. Returns zero on success, negative
220 * values on failure.
221 *
222 */
223int x86_rule_add(struct db_filter_col *col, struct db_filter *db, bool strict,
224 struct db_api_rule_list *rule)
225{
226 int rc;
227 unsigned int iter;
228 size_t args_size;
229 int sys = rule->syscall;
230 int sys_a, sys_b;
231 struct db_api_rule_list *rule_a, *rule_b;
232
233 if ((sys <= -100 && sys >= -120) || (sys >= 359 && sys <= 373)) {
234 /* (-100 to -120) : multiplexed socket syscalls
235 (359 to 373) : direct socket syscalls, Linux 4.3+ */
236
237 /* strict check for the multiplexed socket syscalls */
238 for (iter = 0; iter < rule->args_cnt; iter++) {
239 if ((rule->args[iter].valid != 0) && (strict))
240 return -EINVAL;
241 }
242
243 /* determine both the muxed and direct syscall numbers */
244 if (sys > 0) {
245 sys_a = _x86_sock_mux(sys);
246 if (sys_a == __NR_SCMP_ERROR)
247 return __NR_SCMP_ERROR;
248 sys_b = sys;
249 } else {
250 sys_a = sys;
251 sys_b = _x86_sock_demux(sys);
252 if (sys_b == __NR_SCMP_ERROR)
253 return __NR_SCMP_ERROR;
254 }
255
256 /* use rule_a for the multiplexed syscall and use rule_b for
257 * the direct wired syscall */
258
259 if (sys_a == __NR_SCMP_UNDEF) {
260 rule_a = NULL;
261 rule_b = rule;
262 } else if (sys_b == __NR_SCMP_UNDEF) {
263 rule_a = rule;
264 rule_b = NULL;
265 } else {
266 /* need two rules, dup the first and link together */
267 rule_a = rule;
268 rule_b = malloc(sizeof(*rule_b));
269 if (rule_b == NULL)
270 return -ENOMEM;
271 args_size = sizeof(*rule_b->args) * rule_a->args_cnt;
272 rule_b->args = malloc(args_size);
273 if (rule_b->args == NULL) {
274 free(rule_b);
275 return -ENOMEM;
276 }
277 rule_b->action = rule_a->action;
278 rule_b->syscall = rule_a->syscall;
279 rule_b->args_cnt = rule_a->args_cnt;
280 memcpy(rule_b->args, rule_a->args, args_size);
281 rule_b->prev = rule_a;
282 rule_b->next = NULL;
283 rule_a->next = rule_b;
284 }
285
286 /* multiplexed socket syscalls */
287 if (rule_a != NULL) {
288 rule_a->syscall = __x86_NR_socketcall;
289 rule_a->args[0].arg = 0;
290 rule_a->args[0].op = SCMP_CMP_EQ;
291 rule_a->args[0].mask = DATUM_MAX;
292 rule_a->args[0].datum = (-sys_a) % 100;
293 rule_a->args[0].valid = 1;
294 }
295
296 /* direct wired socket syscalls */
297 if (rule_b != NULL)
298 rule_b->syscall = sys_b;
299
300 /* add the rules as a single transaction */
301 rc = db_col_transaction_start(col);
302 if (rc < 0)
303 return rc;
304 if (rule_a != NULL) {
305 rc = db_rule_add(db, rule_a);
306 if (rc < 0)
307 goto fail_transaction;
308 }
309 if (rule_b != NULL) {
310 rc = db_rule_add(db, rule_b);
311 if (rc < 0)
312 goto fail_transaction;
313 }
314 db_col_transaction_commit(col);
315 } else if (sys <= -200 && sys >= -224) {
316 /* multiplexed ipc syscalls */
317 for (iter = 0; iter < ARG_COUNT_MAX; iter++) {
318 if ((rule->args[iter].valid != 0) && (strict))
319 return -EINVAL;
320 }
321 rule->args[0].arg = 0;
322 rule->args[0].op = SCMP_CMP_EQ;
323 rule->args[0].mask = DATUM_MAX;
324 rule->args[0].datum = abs(sys) % 200;
325 rule->args[0].valid = 1;
326 rule->syscall = __x86_NR_ipc;
327
328 rc = db_rule_add(db, rule);
329 if (rc < 0)
330 return rc;
331 } else if (sys >= 0) {
332 /* normal syscall processing */
333 rc = db_rule_add(db, rule);
334 if (rc < 0)
335 return rc;
336 } else if (strict)
337 return -EDOM;
338
339 return 0;
340
341fail_transaction:
342 db_col_transaction_abort(col);
343 return rc;
344}
This page took 0.027246 seconds and 4 git commands to generate.