162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * System call table mapper
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * (C) 2016 Arnaldo Carvalho de Melo <acme@redhat.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "syscalltbl.h"
962306a36Sopenharmony_ci#include <stdlib.h>
1062306a36Sopenharmony_ci#include <linux/compiler.h>
1162306a36Sopenharmony_ci#include <linux/zalloc.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#ifdef HAVE_SYSCALL_TABLE_SUPPORT
1462306a36Sopenharmony_ci#include <string.h>
1562306a36Sopenharmony_ci#include "string2.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#if defined(__x86_64__)
1862306a36Sopenharmony_ci#include <asm/syscalls_64.c>
1962306a36Sopenharmony_ciconst int syscalltbl_native_max_id = SYSCALLTBL_x86_64_MAX_ID;
2062306a36Sopenharmony_cistatic const char *const *syscalltbl_native = syscalltbl_x86_64;
2162306a36Sopenharmony_ci#elif defined(__s390x__)
2262306a36Sopenharmony_ci#include <asm/syscalls_64.c>
2362306a36Sopenharmony_ciconst int syscalltbl_native_max_id = SYSCALLTBL_S390_64_MAX_ID;
2462306a36Sopenharmony_cistatic const char *const *syscalltbl_native = syscalltbl_s390_64;
2562306a36Sopenharmony_ci#elif defined(__powerpc64__)
2662306a36Sopenharmony_ci#include <asm/syscalls_64.c>
2762306a36Sopenharmony_ciconst int syscalltbl_native_max_id = SYSCALLTBL_POWERPC_64_MAX_ID;
2862306a36Sopenharmony_cistatic const char *const *syscalltbl_native = syscalltbl_powerpc_64;
2962306a36Sopenharmony_ci#elif defined(__powerpc__)
3062306a36Sopenharmony_ci#include <asm/syscalls_32.c>
3162306a36Sopenharmony_ciconst int syscalltbl_native_max_id = SYSCALLTBL_POWERPC_32_MAX_ID;
3262306a36Sopenharmony_cistatic const char *const *syscalltbl_native = syscalltbl_powerpc_32;
3362306a36Sopenharmony_ci#elif defined(__aarch64__)
3462306a36Sopenharmony_ci#include <asm/syscalls.c>
3562306a36Sopenharmony_ciconst int syscalltbl_native_max_id = SYSCALLTBL_ARM64_MAX_ID;
3662306a36Sopenharmony_cistatic const char *const *syscalltbl_native = syscalltbl_arm64;
3762306a36Sopenharmony_ci#elif defined(__mips__)
3862306a36Sopenharmony_ci#include <asm/syscalls_n64.c>
3962306a36Sopenharmony_ciconst int syscalltbl_native_max_id = SYSCALLTBL_MIPS_N64_MAX_ID;
4062306a36Sopenharmony_cistatic const char *const *syscalltbl_native = syscalltbl_mips_n64;
4162306a36Sopenharmony_ci#elif defined(__loongarch__)
4262306a36Sopenharmony_ci#include <asm/syscalls.c>
4362306a36Sopenharmony_ciconst int syscalltbl_native_max_id = SYSCALLTBL_LOONGARCH_MAX_ID;
4462306a36Sopenharmony_cistatic const char *const *syscalltbl_native = syscalltbl_loongarch;
4562306a36Sopenharmony_ci#endif
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistruct syscall {
4862306a36Sopenharmony_ci	int id;
4962306a36Sopenharmony_ci	const char *name;
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic int syscallcmpname(const void *vkey, const void *ventry)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	const char *key = vkey;
5562306a36Sopenharmony_ci	const struct syscall *entry = ventry;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	return strcmp(key, entry->name);
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int syscallcmp(const void *va, const void *vb)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	const struct syscall *a = va, *b = vb;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return strcmp(a->name, b->name);
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int syscalltbl__init_native(struct syscalltbl *tbl)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	int nr_entries = 0, i, j;
7062306a36Sopenharmony_ci	struct syscall *entries;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	for (i = 0; i <= syscalltbl_native_max_id; ++i)
7362306a36Sopenharmony_ci		if (syscalltbl_native[i])
7462306a36Sopenharmony_ci			++nr_entries;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	entries = tbl->syscalls.entries = malloc(sizeof(struct syscall) * nr_entries);
7762306a36Sopenharmony_ci	if (tbl->syscalls.entries == NULL)
7862306a36Sopenharmony_ci		return -1;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	for (i = 0, j = 0; i <= syscalltbl_native_max_id; ++i) {
8162306a36Sopenharmony_ci		if (syscalltbl_native[i]) {
8262306a36Sopenharmony_ci			entries[j].name = syscalltbl_native[i];
8362306a36Sopenharmony_ci			entries[j].id = i;
8462306a36Sopenharmony_ci			++j;
8562306a36Sopenharmony_ci		}
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	qsort(tbl->syscalls.entries, nr_entries, sizeof(struct syscall), syscallcmp);
8962306a36Sopenharmony_ci	tbl->syscalls.nr_entries = nr_entries;
9062306a36Sopenharmony_ci	tbl->syscalls.max_id	 = syscalltbl_native_max_id;
9162306a36Sopenharmony_ci	return 0;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistruct syscalltbl *syscalltbl__new(void)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	struct syscalltbl *tbl = malloc(sizeof(*tbl));
9762306a36Sopenharmony_ci	if (tbl) {
9862306a36Sopenharmony_ci		if (syscalltbl__init_native(tbl)) {
9962306a36Sopenharmony_ci			free(tbl);
10062306a36Sopenharmony_ci			return NULL;
10162306a36Sopenharmony_ci		}
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci	return tbl;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_civoid syscalltbl__delete(struct syscalltbl *tbl)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	zfree(&tbl->syscalls.entries);
10962306a36Sopenharmony_ci	free(tbl);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ciconst char *syscalltbl__name(const struct syscalltbl *tbl __maybe_unused, int id)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	return id <= syscalltbl_native_max_id ? syscalltbl_native[id]: NULL;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ciint syscalltbl__id(struct syscalltbl *tbl, const char *name)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	struct syscall *sc = bsearch(name, tbl->syscalls.entries,
12062306a36Sopenharmony_ci				     tbl->syscalls.nr_entries, sizeof(*sc),
12162306a36Sopenharmony_ci				     syscallcmpname);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return sc ? sc->id : -1;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciint syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	int i;
12962306a36Sopenharmony_ci	struct syscall *syscalls = tbl->syscalls.entries;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	for (i = *idx + 1; i < tbl->syscalls.nr_entries; ++i) {
13262306a36Sopenharmony_ci		if (strglobmatch(syscalls[i].name, syscall_glob)) {
13362306a36Sopenharmony_ci			*idx = i;
13462306a36Sopenharmony_ci			return syscalls[i].id;
13562306a36Sopenharmony_ci		}
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return -1;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ciint syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	*idx = -1;
14462306a36Sopenharmony_ci	return syscalltbl__strglobmatch_next(tbl, syscall_glob, idx);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci#else /* HAVE_SYSCALL_TABLE_SUPPORT */
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#include <libaudit.h>
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistruct syscalltbl *syscalltbl__new(void)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct syscalltbl *tbl = zalloc(sizeof(*tbl));
15462306a36Sopenharmony_ci	if (tbl)
15562306a36Sopenharmony_ci		tbl->audit_machine = audit_detect_machine();
15662306a36Sopenharmony_ci	return tbl;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_civoid syscalltbl__delete(struct syscalltbl *tbl)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	free(tbl);
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ciconst char *syscalltbl__name(const struct syscalltbl *tbl, int id)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	return audit_syscall_to_name(id, tbl->audit_machine);
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ciint syscalltbl__id(struct syscalltbl *tbl, const char *name)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	return audit_name_to_syscall(name, tbl->audit_machine);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ciint syscalltbl__strglobmatch_next(struct syscalltbl *tbl __maybe_unused,
17562306a36Sopenharmony_ci				  const char *syscall_glob __maybe_unused, int *idx __maybe_unused)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	return -1;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ciint syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	return syscalltbl__strglobmatch_next(tbl, syscall_glob, idx);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci#endif /* HAVE_SYSCALL_TABLE_SUPPORT */
185