18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Example wrapper around BPF macros. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org> 68c2ecf20Sopenharmony_ci * Author: Will Drewry <wad@chromium.org> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * The code may be used by anyone for any purpose, 98c2ecf20Sopenharmony_ci * and can serve as a starting point for developing 108c2ecf20Sopenharmony_ci * applications using prctl(PR_SET_SECCOMP, 2, ...). 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * No guarantees are provided with respect to the correctness 138c2ecf20Sopenharmony_ci * or functionality of this code. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci#ifndef __BPF_HELPER_H__ 168c2ecf20Sopenharmony_ci#define __BPF_HELPER_H__ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <asm/bitsperlong.h> /* for __BITS_PER_LONG */ 198c2ecf20Sopenharmony_ci#include <endian.h> 208c2ecf20Sopenharmony_ci#include <linux/filter.h> 218c2ecf20Sopenharmony_ci#include <linux/seccomp.h> /* for seccomp_data */ 228c2ecf20Sopenharmony_ci#include <linux/types.h> 238c2ecf20Sopenharmony_ci#include <linux/unistd.h> 248c2ecf20Sopenharmony_ci#include <stddef.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define BPF_LABELS_MAX 256 278c2ecf20Sopenharmony_cistruct bpf_labels { 288c2ecf20Sopenharmony_ci int count; 298c2ecf20Sopenharmony_ci struct __bpf_label { 308c2ecf20Sopenharmony_ci const char *label; 318c2ecf20Sopenharmony_ci __u32 location; 328c2ecf20Sopenharmony_ci } labels[BPF_LABELS_MAX]; 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ciint bpf_resolve_jumps(struct bpf_labels *labels, 368c2ecf20Sopenharmony_ci struct sock_filter *filter, size_t count); 378c2ecf20Sopenharmony_ci__u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label); 388c2ecf20Sopenharmony_civoid seccomp_bpf_print(struct sock_filter *filter, size_t count); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define JUMP_JT 0xff 418c2ecf20Sopenharmony_ci#define JUMP_JF 0xff 428c2ecf20Sopenharmony_ci#define LABEL_JT 0xfe 438c2ecf20Sopenharmony_ci#define LABEL_JF 0xfe 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define ALLOW \ 468c2ecf20Sopenharmony_ci BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) 478c2ecf20Sopenharmony_ci#define DENY \ 488c2ecf20Sopenharmony_ci BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) 498c2ecf20Sopenharmony_ci#define JUMP(labels, label) \ 508c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL((labels), (label)), \ 518c2ecf20Sopenharmony_ci JUMP_JT, JUMP_JF) 528c2ecf20Sopenharmony_ci#define LABEL(labels, label) \ 538c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JA, FIND_LABEL((labels), (label)), \ 548c2ecf20Sopenharmony_ci LABEL_JT, LABEL_JF) 558c2ecf20Sopenharmony_ci#define SYSCALL(nr, jt) \ 568c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (nr), 0, 1), \ 578c2ecf20Sopenharmony_ci jt 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* Lame, but just an example */ 608c2ecf20Sopenharmony_ci#define FIND_LABEL(labels, label) seccomp_bpf_label((labels), #label) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define EXPAND(...) __VA_ARGS__ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Ensure that we load the logically correct offset. */ 658c2ecf20Sopenharmony_ci#if __BYTE_ORDER == __LITTLE_ENDIAN 668c2ecf20Sopenharmony_ci#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) 678c2ecf20Sopenharmony_ci#elif __BYTE_ORDER == __BIG_ENDIAN 688c2ecf20Sopenharmony_ci#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) 698c2ecf20Sopenharmony_ci#else 708c2ecf20Sopenharmony_ci#error "Unknown endianness" 718c2ecf20Sopenharmony_ci#endif 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* Map all width-sensitive operations */ 748c2ecf20Sopenharmony_ci#if __BITS_PER_LONG == 32 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define JEQ(x, jt) JEQ32(x, EXPAND(jt)) 778c2ecf20Sopenharmony_ci#define JNE(x, jt) JNE32(x, EXPAND(jt)) 788c2ecf20Sopenharmony_ci#define JGT(x, jt) JGT32(x, EXPAND(jt)) 798c2ecf20Sopenharmony_ci#define JLT(x, jt) JLT32(x, EXPAND(jt)) 808c2ecf20Sopenharmony_ci#define JGE(x, jt) JGE32(x, EXPAND(jt)) 818c2ecf20Sopenharmony_ci#define JLE(x, jt) JLE32(x, EXPAND(jt)) 828c2ecf20Sopenharmony_ci#define JA(x, jt) JA32(x, EXPAND(jt)) 838c2ecf20Sopenharmony_ci#define ARG(i) ARG_32(i) 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#elif __BITS_PER_LONG == 64 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* Ensure that we load the logically correct offset. */ 888c2ecf20Sopenharmony_ci#if __BYTE_ORDER == __LITTLE_ENDIAN 898c2ecf20Sopenharmony_ci#define ENDIAN(_lo, _hi) _lo, _hi 908c2ecf20Sopenharmony_ci#define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32) 918c2ecf20Sopenharmony_ci#elif __BYTE_ORDER == __BIG_ENDIAN 928c2ecf20Sopenharmony_ci#define ENDIAN(_lo, _hi) _hi, _lo 938c2ecf20Sopenharmony_ci#define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) 948c2ecf20Sopenharmony_ci#endif 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciunion arg64 { 978c2ecf20Sopenharmony_ci struct { 988c2ecf20Sopenharmony_ci __u32 ENDIAN(lo32, hi32); 998c2ecf20Sopenharmony_ci }; 1008c2ecf20Sopenharmony_ci __u64 u64; 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define JEQ(x, jt) \ 1048c2ecf20Sopenharmony_ci JEQ64(((union arg64){.u64 = (x)}).lo32, \ 1058c2ecf20Sopenharmony_ci ((union arg64){.u64 = (x)}).hi32, \ 1068c2ecf20Sopenharmony_ci EXPAND(jt)) 1078c2ecf20Sopenharmony_ci#define JGT(x, jt) \ 1088c2ecf20Sopenharmony_ci JGT64(((union arg64){.u64 = (x)}).lo32, \ 1098c2ecf20Sopenharmony_ci ((union arg64){.u64 = (x)}).hi32, \ 1108c2ecf20Sopenharmony_ci EXPAND(jt)) 1118c2ecf20Sopenharmony_ci#define JGE(x, jt) \ 1128c2ecf20Sopenharmony_ci JGE64(((union arg64){.u64 = (x)}).lo32, \ 1138c2ecf20Sopenharmony_ci ((union arg64){.u64 = (x)}).hi32, \ 1148c2ecf20Sopenharmony_ci EXPAND(jt)) 1158c2ecf20Sopenharmony_ci#define JNE(x, jt) \ 1168c2ecf20Sopenharmony_ci JNE64(((union arg64){.u64 = (x)}).lo32, \ 1178c2ecf20Sopenharmony_ci ((union arg64){.u64 = (x)}).hi32, \ 1188c2ecf20Sopenharmony_ci EXPAND(jt)) 1198c2ecf20Sopenharmony_ci#define JLT(x, jt) \ 1208c2ecf20Sopenharmony_ci JLT64(((union arg64){.u64 = (x)}).lo32, \ 1218c2ecf20Sopenharmony_ci ((union arg64){.u64 = (x)}).hi32, \ 1228c2ecf20Sopenharmony_ci EXPAND(jt)) 1238c2ecf20Sopenharmony_ci#define JLE(x, jt) \ 1248c2ecf20Sopenharmony_ci JLE64(((union arg64){.u64 = (x)}).lo32, \ 1258c2ecf20Sopenharmony_ci ((union arg64){.u64 = (x)}).hi32, \ 1268c2ecf20Sopenharmony_ci EXPAND(jt)) 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci#define JA(x, jt) \ 1298c2ecf20Sopenharmony_ci JA64(((union arg64){.u64 = (x)}).lo32, \ 1308c2ecf20Sopenharmony_ci ((union arg64){.u64 = (x)}).hi32, \ 1318c2ecf20Sopenharmony_ci EXPAND(jt)) 1328c2ecf20Sopenharmony_ci#define ARG(i) ARG_64(i) 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#else 1358c2ecf20Sopenharmony_ci#error __BITS_PER_LONG value unusable. 1368c2ecf20Sopenharmony_ci#endif 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* Loads the arg into A */ 1398c2ecf20Sopenharmony_ci#define ARG_32(idx) \ 1408c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)) 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* Loads lo into M[0] and hi into M[1] and A */ 1438c2ecf20Sopenharmony_ci#define ARG_64(idx) \ 1448c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)), \ 1458c2ecf20Sopenharmony_ci BPF_STMT(BPF_ST, 0), /* lo -> M[0] */ \ 1468c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_W+BPF_ABS, HI_ARG(idx)), \ 1478c2ecf20Sopenharmony_ci BPF_STMT(BPF_ST, 1) /* hi -> M[1] */ 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#define JEQ32(value, jt) \ 1508c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 0, 1), \ 1518c2ecf20Sopenharmony_ci jt 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci#define JNE32(value, jt) \ 1548c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 1, 0), \ 1558c2ecf20Sopenharmony_ci jt 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#define JA32(value, jt) \ 1588c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \ 1598c2ecf20Sopenharmony_ci jt 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci#define JGE32(value, jt) \ 1628c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \ 1638c2ecf20Sopenharmony_ci jt 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci#define JGT32(value, jt) \ 1668c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \ 1678c2ecf20Sopenharmony_ci jt 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci#define JLE32(value, jt) \ 1708c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \ 1718c2ecf20Sopenharmony_ci jt 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci#define JLT32(value, jt) \ 1748c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \ 1758c2ecf20Sopenharmony_ci jt 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* 1788c2ecf20Sopenharmony_ci * All the JXX64 checks assume lo is saved in M[0] and hi is saved in both 1798c2ecf20Sopenharmony_ci * A and M[1]. This invariant is kept by restoring A if necessary. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci#define JEQ64(lo, hi, jt) \ 1828c2ecf20Sopenharmony_ci /* if (hi != arg.hi) goto NOMATCH; */ \ 1838c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ 1848c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \ 1858c2ecf20Sopenharmony_ci /* if (lo != arg.lo) goto NOMATCH; */ \ 1868c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \ 1878c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1), \ 1888c2ecf20Sopenharmony_ci jt, \ 1898c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1) 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci#define JNE64(lo, hi, jt) \ 1928c2ecf20Sopenharmony_ci /* if (hi != arg.hi) goto MATCH; */ \ 1938c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \ 1948c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 0), \ 1958c2ecf20Sopenharmony_ci /* if (lo != arg.lo) goto MATCH; */ \ 1968c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \ 1978c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1), \ 1988c2ecf20Sopenharmony_ci jt, \ 1998c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1) 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci#define JA64(lo, hi, jt) \ 2028c2ecf20Sopenharmony_ci /* if (hi & arg.hi) goto MATCH; */ \ 2038c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \ 2048c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 0), \ 2058c2ecf20Sopenharmony_ci /* if (lo & arg.lo) goto MATCH; */ \ 2068c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \ 2078c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1), \ 2088c2ecf20Sopenharmony_ci jt, \ 2098c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1) 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci#define JGE64(lo, hi, jt) \ 2128c2ecf20Sopenharmony_ci /* if (hi > arg.hi) goto MATCH; */ \ 2138c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ 2148c2ecf20Sopenharmony_ci /* if (hi != arg.hi) goto NOMATCH; */ \ 2158c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ 2168c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 0), \ 2178c2ecf20Sopenharmony_ci /* if (lo >= arg.lo) goto MATCH; */ \ 2188c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \ 2198c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1), \ 2208c2ecf20Sopenharmony_ci jt, \ 2218c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1) 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci#define JGT64(lo, hi, jt) \ 2248c2ecf20Sopenharmony_ci /* if (hi > arg.hi) goto MATCH; */ \ 2258c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \ 2268c2ecf20Sopenharmony_ci /* if (hi != arg.hi) goto NOMATCH; */ \ 2278c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ 2288c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 0), \ 2298c2ecf20Sopenharmony_ci /* if (lo > arg.lo) goto MATCH; */ \ 2308c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \ 2318c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1), \ 2328c2ecf20Sopenharmony_ci jt, \ 2338c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1) 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci#define JLE64(lo, hi, jt) \ 2368c2ecf20Sopenharmony_ci /* if (hi < arg.hi) goto MATCH; */ \ 2378c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \ 2388c2ecf20Sopenharmony_ci /* if (hi != arg.hi) goto NOMATCH; */ \ 2398c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ 2408c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 0), \ 2418c2ecf20Sopenharmony_ci /* if (lo <= arg.lo) goto MATCH; */ \ 2428c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \ 2438c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1), \ 2448c2ecf20Sopenharmony_ci jt, \ 2458c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1) 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci#define JLT64(lo, hi, jt) \ 2488c2ecf20Sopenharmony_ci /* if (hi < arg.hi) goto MATCH; */ \ 2498c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \ 2508c2ecf20Sopenharmony_ci /* if (hi != arg.hi) goto NOMATCH; */ \ 2518c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \ 2528c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 0), \ 2538c2ecf20Sopenharmony_ci /* if (lo < arg.lo) goto MATCH; */ \ 2548c2ecf20Sopenharmony_ci BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 2, 0), \ 2558c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1), \ 2568c2ecf20Sopenharmony_ci jt, \ 2578c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_MEM, 1) 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci#define LOAD_SYSCALL_NR \ 2608c2ecf20Sopenharmony_ci BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ 2618c2ecf20Sopenharmony_ci offsetof(struct seccomp_data, nr)) 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci#endif /* __BPF_HELPER_H__ */ 264