162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Seccomp BPF helper functions
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_ATTACH_SECCOMP_FILTER).
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <stdio.h>
1462306a36Sopenharmony_ci#include <stdlib.h>
1562306a36Sopenharmony_ci#include <string.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "bpf-helper.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciint bpf_resolve_jumps(struct bpf_labels *labels,
2062306a36Sopenharmony_ci		      struct sock_filter *filter, size_t count)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	size_t i;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	if (count < 1 || count > BPF_MAXINSNS)
2562306a36Sopenharmony_ci		return -1;
2662306a36Sopenharmony_ci	/*
2762306a36Sopenharmony_ci	* Walk it once, backwards, to build the label table and do fixups.
2862306a36Sopenharmony_ci	* Since backward jumps are disallowed by BPF, this is easy.
2962306a36Sopenharmony_ci	*/
3062306a36Sopenharmony_ci	for (i = 0; i < count; ++i) {
3162306a36Sopenharmony_ci		size_t offset = count - i - 1;
3262306a36Sopenharmony_ci		struct sock_filter *instr = &filter[offset];
3362306a36Sopenharmony_ci		if (instr->code != (BPF_JMP+BPF_JA))
3462306a36Sopenharmony_ci			continue;
3562306a36Sopenharmony_ci		switch ((instr->jt<<8)|instr->jf) {
3662306a36Sopenharmony_ci		case (JUMP_JT<<8)|JUMP_JF:
3762306a36Sopenharmony_ci			if (labels->labels[instr->k].location == 0xffffffff) {
3862306a36Sopenharmony_ci				fprintf(stderr, "Unresolved label: '%s'\n",
3962306a36Sopenharmony_ci					labels->labels[instr->k].label);
4062306a36Sopenharmony_ci				return 1;
4162306a36Sopenharmony_ci			}
4262306a36Sopenharmony_ci			instr->k = labels->labels[instr->k].location -
4362306a36Sopenharmony_ci				    (offset + 1);
4462306a36Sopenharmony_ci			instr->jt = 0;
4562306a36Sopenharmony_ci			instr->jf = 0;
4662306a36Sopenharmony_ci			continue;
4762306a36Sopenharmony_ci		case (LABEL_JT<<8)|LABEL_JF:
4862306a36Sopenharmony_ci			if (labels->labels[instr->k].location != 0xffffffff) {
4962306a36Sopenharmony_ci				fprintf(stderr, "Duplicate label use: '%s'\n",
5062306a36Sopenharmony_ci					labels->labels[instr->k].label);
5162306a36Sopenharmony_ci				return 1;
5262306a36Sopenharmony_ci			}
5362306a36Sopenharmony_ci			labels->labels[instr->k].location = offset;
5462306a36Sopenharmony_ci			instr->k = 0; /* fall through */
5562306a36Sopenharmony_ci			instr->jt = 0;
5662306a36Sopenharmony_ci			instr->jf = 0;
5762306a36Sopenharmony_ci			continue;
5862306a36Sopenharmony_ci		}
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci	return 0;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/* Simple lookup table for labels. */
6462306a36Sopenharmony_ci__u32 seccomp_bpf_label(struct bpf_labels *labels, const char *label)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	struct __bpf_label *begin = labels->labels, *end;
6762306a36Sopenharmony_ci	int id;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (labels->count == BPF_LABELS_MAX) {
7062306a36Sopenharmony_ci		fprintf(stderr, "Too many labels\n");
7162306a36Sopenharmony_ci		exit(1);
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci	if (labels->count == 0) {
7462306a36Sopenharmony_ci		begin->label = label;
7562306a36Sopenharmony_ci		begin->location = 0xffffffff;
7662306a36Sopenharmony_ci		labels->count++;
7762306a36Sopenharmony_ci		return 0;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci	end = begin + labels->count;
8062306a36Sopenharmony_ci	for (id = 0; begin < end; ++begin, ++id) {
8162306a36Sopenharmony_ci		if (!strcmp(label, begin->label))
8262306a36Sopenharmony_ci			return id;
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci	begin->label = label;
8562306a36Sopenharmony_ci	begin->location = 0xffffffff;
8662306a36Sopenharmony_ci	labels->count++;
8762306a36Sopenharmony_ci	return id;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_civoid seccomp_bpf_print(struct sock_filter *filter, size_t count)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct sock_filter *end = filter + count;
9362306a36Sopenharmony_ci	for ( ; filter < end; ++filter)
9462306a36Sopenharmony_ci		printf("{ code=%u,jt=%u,jf=%u,k=%u },\n",
9562306a36Sopenharmony_ci			filter->code, filter->jt, filter->jf, filter->k);
9662306a36Sopenharmony_ci}
97