162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Example wrapper around BPF macros.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
662306a36Sopenharmony_ci * Author: Will Drewry <wad@chromium.org>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * The code may be used by anyone for any purpose,
962306a36Sopenharmony_ci * and can serve as a starting point for developing
1062306a36Sopenharmony_ci * applications using prctl(PR_SET_SECCOMP, 2, ...).
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * No guarantees are provided with respect to the correctness
1362306a36Sopenharmony_ci * or functionality of this code.
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci#ifndef __BPF_HELPER_H__
1662306a36Sopenharmony_ci#define __BPF_HELPER_H__
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <asm/bitsperlong.h>	/* for __BITS_PER_LONG */
1962306a36Sopenharmony_ci#include <endian.h>
2062306a36Sopenharmony_ci#include <linux/filter.h>
2162306a36Sopenharmony_ci#include <linux/seccomp.h>	/* for seccomp_data */
2262306a36Sopenharmony_ci#include <linux/types.h>
2362306a36Sopenharmony_ci#include <linux/unistd.h>
2462306a36Sopenharmony_ci#include <stddef.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define BPF_LABELS_MAX 256
2762306a36Sopenharmony_cistruct bpf_labels {
2862306a36Sopenharmony_ci	int count;
2962306a36Sopenharmony_ci	struct __bpf_label {
3062306a36Sopenharmony_ci		const char *label;
3162306a36Sopenharmony_ci		__u32 location;
3262306a36Sopenharmony_ci	} labels[BPF_LABELS_MAX];
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciint bpf_resolve_jumps(struct bpf_labels *labels,
3662306a36Sopenharmony_ci		      struct sock_filter *filter, size_t count);
3762306a36Sopenharmony_ci__u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label);
3862306a36Sopenharmony_civoid seccomp_bpf_print(struct sock_filter *filter, size_t count);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define JUMP_JT 0xff
4162306a36Sopenharmony_ci#define JUMP_JF 0xff
4262306a36Sopenharmony_ci#define LABEL_JT 0xfe
4362306a36Sopenharmony_ci#define LABEL_JF 0xfe
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define ALLOW \
4662306a36Sopenharmony_ci	BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
4762306a36Sopenharmony_ci#define DENY \
4862306a36Sopenharmony_ci	BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
4962306a36Sopenharmony_ci#define JUMP(labels, label) \
5062306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL((labels), (label)), \
5162306a36Sopenharmony_ci		 JUMP_JT, JUMP_JF)
5262306a36Sopenharmony_ci#define LABEL(labels, label) \
5362306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL((labels), (label)), \
5462306a36Sopenharmony_ci		 LABEL_JT, LABEL_JF)
5562306a36Sopenharmony_ci#define SYSCALL(nr, jt) \
5662306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (nr), 0, 1), \
5762306a36Sopenharmony_ci	jt
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* Lame, but just an example */
6062306a36Sopenharmony_ci#define FIND_LABEL(labels, label) seccomp_bpf_label((labels), #label)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define EXPAND(...) __VA_ARGS__
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* Ensure that we load the logically correct offset. */
6562306a36Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
6662306a36Sopenharmony_ci#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
6762306a36Sopenharmony_ci#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
6862306a36Sopenharmony_ci#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
6962306a36Sopenharmony_ci#else
7062306a36Sopenharmony_ci#error "Unknown endianness"
7162306a36Sopenharmony_ci#endif
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/* Map all width-sensitive operations */
7462306a36Sopenharmony_ci#if __BITS_PER_LONG == 32
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define JEQ(x, jt) JEQ32(x, EXPAND(jt))
7762306a36Sopenharmony_ci#define JNE(x, jt) JNE32(x, EXPAND(jt))
7862306a36Sopenharmony_ci#define JGT(x, jt) JGT32(x, EXPAND(jt))
7962306a36Sopenharmony_ci#define JLT(x, jt) JLT32(x, EXPAND(jt))
8062306a36Sopenharmony_ci#define JGE(x, jt) JGE32(x, EXPAND(jt))
8162306a36Sopenharmony_ci#define JLE(x, jt) JLE32(x, EXPAND(jt))
8262306a36Sopenharmony_ci#define JA(x, jt) JA32(x, EXPAND(jt))
8362306a36Sopenharmony_ci#define ARG(i) ARG_32(i)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#elif __BITS_PER_LONG == 64
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* Ensure that we load the logically correct offset. */
8862306a36Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
8962306a36Sopenharmony_ci#define ENDIAN(_lo, _hi) _lo, _hi
9062306a36Sopenharmony_ci#define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
9162306a36Sopenharmony_ci#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
9262306a36Sopenharmony_ci#define ENDIAN(_lo, _hi) _hi, _lo
9362306a36Sopenharmony_ci#define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
9462306a36Sopenharmony_ci#endif
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ciunion arg64 {
9762306a36Sopenharmony_ci	struct {
9862306a36Sopenharmony_ci		__u32 ENDIAN(lo32, hi32);
9962306a36Sopenharmony_ci	};
10062306a36Sopenharmony_ci	__u64 u64;
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define JEQ(x, jt) \
10462306a36Sopenharmony_ci	JEQ64(((union arg64){.u64 = (x)}).lo32, \
10562306a36Sopenharmony_ci	      ((union arg64){.u64 = (x)}).hi32, \
10662306a36Sopenharmony_ci	      EXPAND(jt))
10762306a36Sopenharmony_ci#define JGT(x, jt) \
10862306a36Sopenharmony_ci	JGT64(((union arg64){.u64 = (x)}).lo32, \
10962306a36Sopenharmony_ci	      ((union arg64){.u64 = (x)}).hi32, \
11062306a36Sopenharmony_ci	      EXPAND(jt))
11162306a36Sopenharmony_ci#define JGE(x, jt) \
11262306a36Sopenharmony_ci	JGE64(((union arg64){.u64 = (x)}).lo32, \
11362306a36Sopenharmony_ci	      ((union arg64){.u64 = (x)}).hi32, \
11462306a36Sopenharmony_ci	      EXPAND(jt))
11562306a36Sopenharmony_ci#define JNE(x, jt) \
11662306a36Sopenharmony_ci	JNE64(((union arg64){.u64 = (x)}).lo32, \
11762306a36Sopenharmony_ci	      ((union arg64){.u64 = (x)}).hi32, \
11862306a36Sopenharmony_ci	      EXPAND(jt))
11962306a36Sopenharmony_ci#define JLT(x, jt) \
12062306a36Sopenharmony_ci	JLT64(((union arg64){.u64 = (x)}).lo32, \
12162306a36Sopenharmony_ci	      ((union arg64){.u64 = (x)}).hi32, \
12262306a36Sopenharmony_ci	      EXPAND(jt))
12362306a36Sopenharmony_ci#define JLE(x, jt) \
12462306a36Sopenharmony_ci	JLE64(((union arg64){.u64 = (x)}).lo32, \
12562306a36Sopenharmony_ci	      ((union arg64){.u64 = (x)}).hi32, \
12662306a36Sopenharmony_ci	      EXPAND(jt))
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define JA(x, jt) \
12962306a36Sopenharmony_ci	JA64(((union arg64){.u64 = (x)}).lo32, \
13062306a36Sopenharmony_ci	       ((union arg64){.u64 = (x)}).hi32, \
13162306a36Sopenharmony_ci	       EXPAND(jt))
13262306a36Sopenharmony_ci#define ARG(i) ARG_64(i)
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci#else
13562306a36Sopenharmony_ci#error __BITS_PER_LONG value unusable.
13662306a36Sopenharmony_ci#endif
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/* Loads the arg into A */
13962306a36Sopenharmony_ci#define ARG_32(idx) \
14062306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx))
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* Loads lo into M[0] and hi into M[1] and A */
14362306a36Sopenharmony_ci#define ARG_64(idx) \
14462306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)), \
14562306a36Sopenharmony_ci	BPF_STMT(BPF_ST, 0), /* lo -> M[0] */ \
14662306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_W+BPF_ABS, HI_ARG(idx)), \
14762306a36Sopenharmony_ci	BPF_STMT(BPF_ST, 1) /* hi -> M[1] */
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#define JEQ32(value, jt) \
15062306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 0, 1), \
15162306a36Sopenharmony_ci	jt
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#define JNE32(value, jt) \
15462306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 1, 0), \
15562306a36Sopenharmony_ci	jt
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#define JA32(value, jt) \
15862306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \
15962306a36Sopenharmony_ci	jt
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci#define JGE32(value, jt) \
16262306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \
16362306a36Sopenharmony_ci	jt
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci#define JGT32(value, jt) \
16662306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \
16762306a36Sopenharmony_ci	jt
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci#define JLE32(value, jt) \
17062306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \
17162306a36Sopenharmony_ci	jt
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#define JLT32(value, jt) \
17462306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \
17562306a36Sopenharmony_ci	jt
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/*
17862306a36Sopenharmony_ci * All the JXX64 checks assume lo is saved in M[0] and hi is saved in both
17962306a36Sopenharmony_ci * A and M[1]. This invariant is kept by restoring A if necessary.
18062306a36Sopenharmony_ci */
18162306a36Sopenharmony_ci#define JEQ64(lo, hi, jt) \
18262306a36Sopenharmony_ci	/* if (hi != arg.hi) goto NOMATCH; */ \
18362306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
18462306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
18562306a36Sopenharmony_ci	/* if (lo != arg.lo) goto NOMATCH; */ \
18662306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \
18762306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1), \
18862306a36Sopenharmony_ci	jt, \
18962306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1)
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci#define JNE64(lo, hi, jt) \
19262306a36Sopenharmony_ci	/* if (hi != arg.hi) goto MATCH; */ \
19362306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \
19462306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 0), \
19562306a36Sopenharmony_ci	/* if (lo != arg.lo) goto MATCH; */ \
19662306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \
19762306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1), \
19862306a36Sopenharmony_ci	jt, \
19962306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1)
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci#define JA64(lo, hi, jt) \
20262306a36Sopenharmony_ci	/* if (hi & arg.hi) goto MATCH; */ \
20362306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \
20462306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 0), \
20562306a36Sopenharmony_ci	/* if (lo & arg.lo) goto MATCH; */ \
20662306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \
20762306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1), \
20862306a36Sopenharmony_ci	jt, \
20962306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1)
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci#define JGE64(lo, hi, jt) \
21262306a36Sopenharmony_ci	/* if (hi > arg.hi) goto MATCH; */ \
21362306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
21462306a36Sopenharmony_ci	/* if (hi != arg.hi) goto NOMATCH; */ \
21562306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
21662306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 0), \
21762306a36Sopenharmony_ci	/* if (lo >= arg.lo) goto MATCH; */ \
21862306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \
21962306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1), \
22062306a36Sopenharmony_ci	jt, \
22162306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1)
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci#define JGT64(lo, hi, jt) \
22462306a36Sopenharmony_ci	/* if (hi > arg.hi) goto MATCH; */ \
22562306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
22662306a36Sopenharmony_ci	/* if (hi != arg.hi) goto NOMATCH; */ \
22762306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
22862306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 0), \
22962306a36Sopenharmony_ci	/* if (lo > arg.lo) goto MATCH; */ \
23062306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \
23162306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1), \
23262306a36Sopenharmony_ci	jt, \
23362306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1)
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci#define JLE64(lo, hi, jt) \
23662306a36Sopenharmony_ci	/* if (hi < arg.hi) goto MATCH; */ \
23762306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
23862306a36Sopenharmony_ci	/* if (hi != arg.hi) goto NOMATCH; */ \
23962306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
24062306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 0), \
24162306a36Sopenharmony_ci	/* if (lo <= arg.lo) goto MATCH; */ \
24262306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \
24362306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1), \
24462306a36Sopenharmony_ci	jt, \
24562306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1)
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci#define JLT64(lo, hi, jt) \
24862306a36Sopenharmony_ci	/* if (hi < arg.hi) goto MATCH; */ \
24962306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
25062306a36Sopenharmony_ci	/* if (hi != arg.hi) goto NOMATCH; */ \
25162306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
25262306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 0), \
25362306a36Sopenharmony_ci	/* if (lo < arg.lo) goto MATCH; */ \
25462306a36Sopenharmony_ci	BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 2, 0), \
25562306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1), \
25662306a36Sopenharmony_ci	jt, \
25762306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_MEM, 1)
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci#define LOAD_SYSCALL_NR \
26062306a36Sopenharmony_ci	BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
26162306a36Sopenharmony_ci		 offsetof(struct seccomp_data, nr))
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci#endif  /* __BPF_HELPER_H__ */
264