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