3 * Author: Jan Willeke <willeke@linux.vnet.com.com>
9 #include <linux/audit.h>
12 #include "arch-s390.h"
14 /* s390 syscall numbers */
15 #define __s390_NR_socketcall 102
16 #define __s390_NR_ipc 117
18 const struct arch_def arch_def_s390
= {
19 .token
= SCMP_ARCH_S390
,
20 .token_bpf
= AUDIT_ARCH_S390
,
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
,
30 * Convert a multiplexed pseudo socket syscall into a direct syscall
31 * @param socketcall the multiplexed pseudo syscall number
33 * Return the related direct syscall number, __NR_SCMP_UNDEF is there is
34 * no related syscall, or __NR_SCMP_ERROR otherwise.
37 int _s390_sock_demux(int socketcall
)
53 /* accept - not defined */
54 return __NR_SCMP_UNDEF
;
65 /* send - not defined */
66 return __NR_SCMP_UNDEF
;
68 /* recv - not defined */
69 return __NR_SCMP_UNDEF
;
102 return __NR_SCMP_ERROR
;
106 * Convert a direct socket syscall into multiplexed pseudo socket syscall
107 * @param syscall the direct syscall
109 * Return the related multiplexed pseduo syscall number, __NR_SCMP_UNDEF is
110 * there is no related pseudo syscall, or __NR_SCMP_ERROR otherwise.
113 int _s390_sock_mux(int syscall
)
169 return __NR_SCMP_ERROR
;
173 * Rewrite a syscall value to match the architecture
174 * @param syscall the syscall number
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.
181 int s390_syscall_rewrite(int *syscall
)
185 if (sys
<= -100 && sys
>= -120)
186 *syscall
= __s390_NR_socketcall
;
187 else if (sys
<= -200 && sys
>= -224)
188 *syscall
= __s390_NR_ipc
;
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
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
207 int s390_rule_add(struct db_filter_col
*col
, struct db_filter
*db
, bool strict
,
208 struct db_api_rule_list
*rule
)
213 int sys
= rule
->syscall
;
215 struct db_api_rule_list
*rule_a
, *rule_b
;
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+ */
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
))
227 /* determine both the muxed and direct syscall numbers */
229 sys_a
= _s390_sock_mux(sys
);
230 if (sys_a
== __NR_SCMP_ERROR
)
231 return __NR_SCMP_ERROR
;
235 sys_b
= _s390_sock_demux(sys
);
236 if (sys_b
== __NR_SCMP_ERROR
)
237 return __NR_SCMP_ERROR
;
240 /* use rule_a for the multiplexed syscall and use rule_b for
241 * the direct wired syscall */
243 if (sys_a
== __NR_SCMP_UNDEF
) {
246 } else if (sys_b
== __NR_SCMP_UNDEF
) {
250 /* need two rules, dup the first and link together */
252 rule_b
= malloc(sizeof(*rule_b
));
255 args_size
= sizeof(*rule_b
->args
) * rule_a
->args_cnt
;
256 rule_b
->args
= malloc(args_size
);
257 if (rule_b
->args
== NULL
) {
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
;
267 rule_a
->next
= rule_b
;
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;
280 /* direct wired socket syscalls */
282 rule_b
->syscall
= sys_b
;
284 /* add the rules as a single transaction */
285 rc
= db_col_transaction_start(col
);
288 if (rule_a
!= NULL
) {
289 rc
= db_rule_add(db
, rule_a
);
291 goto fail_transaction
;
293 if (rule_b
!= NULL
) {
294 rc
= db_rule_add(db
, rule_b
);
296 goto fail_transaction
;
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
))
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
;
312 rc
= db_rule_add(db
, rule
);
315 } else if (sys
>= 0) {
316 /* normal syscall processing */
317 rc
= db_rule_add(db
, rule
);
326 db_col_transaction_abort(col
);