diff --git a/doc/Makefile.am b/doc/Makefile.am index 5f0b8567..744394ca 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -22,6 +22,7 @@ dist_man1_MANS = \ dist_man3_MANS = \ man/man3/seccomp_arch_add.3 \ man/man3/seccomp_arch_exist.3 \ + man/man3/seccomp_arch_name.3 \ man/man3/seccomp_arch_native.3 \ man/man3/seccomp_arch_remove.3 \ man/man3/seccomp_arch_resolve_name.3 \ diff --git a/doc/man/man3/seccomp_arch_add.3 b/doc/man/man3/seccomp_arch_add.3 index ede5d92f..4efbb071 100644 --- a/doc/man/man3/seccomp_arch_add.3 +++ b/doc/man/man3/seccomp_arch_add.3 @@ -2,7 +2,7 @@ .\" ////////////////////////////////////////////////////////////////////////// .SH NAME .\" ////////////////////////////////////////////////////////////////////////// -seccomp_arch_add, seccomp_arch_remove, seccomp_arch_exist, seccomp_arch_native \- Manage seccomp filter architectures +seccomp_arch_add, seccomp_arch_remove, seccomp_arch_exist, seccomp_arch_native, seccomp_arch_resolve_name, seccomp_arch_name \- Manage seccomp filter architectures .\" ////////////////////////////////////////////////////////////////////////// .SH SYNOPSIS .\" ////////////////////////////////////////////////////////////////////////// @@ -37,6 +37,7 @@ seccomp_arch_add, seccomp_arch_remove, seccomp_arch_exist, seccomp_arch_native \ .B #define SCMP_ARCH_RISCV64 .sp .BI "uint32_t seccomp_arch_resolve_name(const char *" arch_name ");" +.BI "const char *seccomp_arch_name(uint32_t " arch_token ");" .BI "uint32_t seccomp_arch_native();" .BI "int seccomp_arch_exist(const scmp_filter_ctx " ctx ", uint32_t " arch_token ");" .BI "int seccomp_arch_add(scmp_filter_ctx " ctx ", uint32_t " arch_token ");" @@ -75,6 +76,17 @@ function also returns a constant, the returned token matches the name of the architecture passed as an argument to the function. .P +The +.BR seccomp_arch_name () +function is the inverse of +.BR seccomp_arch_resolve_name (): +it takes an architecture token and returns the canonical architecture name +string. If the token is +.BR SCMP_ARCH_NATIVE +the name of the native architecture is returned. The returned string is a +static constant; the caller must not free it. Returns NULL if the token is +not recognized. +.P When a seccomp filter is initialized with the call to .BR seccomp_init (3) the native architecture is automatically added to the filter. @@ -89,6 +101,7 @@ new architecture will be added to all of the architectures in the filter. .\" ////////////////////////////////////////////////////////////////////////// .SH RETURN VALUE .\" ////////////////////////////////////////////////////////////////////////// +.P The .BR seccomp_arch_add (), .BR seccomp_arch_remove (), @@ -112,6 +125,18 @@ Invalid input, either the context or architecture token is invalid. .TP .B -ENOMEM The library was unable to allocate enough memory. +.P +The +.BR seccomp_arch_resolve_name () +and +.BR seccomp_arch_native () +functions return an architecture token value greater than zero on success and +zero on failure. +.P +The +.BR seccomp_arch_name () +function returns a pointer to a static architecture name string on success and +NULL if the architecture token is not recognized. .\" ////////////////////////////////////////////////////////////////////////// .SH EXAMPLES .\" ////////////////////////////////////////////////////////////////////////// diff --git a/doc/man/man3/seccomp_arch_name.3 b/doc/man/man3/seccomp_arch_name.3 new file mode 100644 index 00000000..f72602be --- /dev/null +++ b/doc/man/man3/seccomp_arch_name.3 @@ -0,0 +1 @@ +.so man3/seccomp_arch_add.3 diff --git a/include/seccomp.h.in b/include/seccomp.h.in index f685480e..66c47476 100644 --- a/include/seccomp.h.in +++ b/include/seccomp.h.in @@ -541,6 +541,19 @@ int seccomp_merge(scmp_filter_ctx ctx_dst, scmp_filter_ctx ctx_src); */ uint32_t seccomp_arch_resolve_name(const char *arch_name); +/** + * Resolve the architecture token to a architecture name + * @param arch_token the architecture token, e.g. SCMP_ARCH_* + * + * This function resolves the given architecture token to the canonical + * architecture name string. If the token is SCMP_ARCH_NATIVE the name of + * the native architecture is returned. Returns a pointer to a static string + * on success; the caller must not free the returned string. Returns NULL if + * the architecture token is not recognized. + * + */ +const char *seccomp_arch_name(uint32_t arch_token); + /** * Return the native architecture token * diff --git a/src/api.c b/src/api.c index 413cc81a..913fb594 100644 --- a/src/api.c +++ b/src/api.c @@ -387,6 +387,12 @@ API uint32_t seccomp_arch_resolve_name(const char *arch_name) return arch->token; } +/* NOTE - function header comment in include/seccomp.h */ +API const char *seccomp_arch_name(uint32_t arch_token) +{ + return arch_def_name(arch_token); +} + /* NOTE - function header comment in include/seccomp.h */ API uint32_t seccomp_arch_native(void) { diff --git a/src/arch.c b/src/arch.c index a3ff7ca6..d6d1237b 100644 --- a/src/arch.c +++ b/src/arch.c @@ -188,6 +188,76 @@ const struct arch_def *arch_def_lookup(uint32_t token) return NULL; } +/** + * Return the name of the architecture + * @param token the architecture token, e.g. SCMP_ARCH_* + * + * Return the name of the architecture associated with the given token, or + * NULL if the token is not valid. If the token is SCMP_ARCH_NATIVE then the + * name of the native architecture is returned. The caller must not free the + * returned string. + * + */ +const char *arch_def_name(uint32_t token) +{ + const struct arch_def *arch; + + if (token == SCMP_ARCH_NATIVE) + token = arch_def_native->token; + arch = arch_def_lookup(token); + if (arch == NULL) + return NULL; + switch (arch->token) { + case SCMP_ARCH_X86: + return "x86"; + case SCMP_ARCH_X86_64: + return "x86_64"; + case SCMP_ARCH_X32: + return "x32"; + case SCMP_ARCH_ARM: + return "arm"; + case SCMP_ARCH_AARCH64: + return "aarch64"; + case SCMP_ARCH_LOONGARCH64: + return "loongarch64"; + case SCMP_ARCH_M68K: + return "m68k"; + case SCMP_ARCH_MIPS: + return "mips"; + case SCMP_ARCH_MIPSEL: + return "mipsel"; + case SCMP_ARCH_MIPS64: + return "mips64"; + case SCMP_ARCH_MIPSEL64: + return "mipsel64"; + case SCMP_ARCH_MIPS64N32: + return "mips64n32"; + case SCMP_ARCH_MIPSEL64N32: + return "mipsel64n32"; + case SCMP_ARCH_PARISC: + return "parisc"; + case SCMP_ARCH_PARISC64: + return "parisc64"; + case SCMP_ARCH_PPC: + return "ppc"; + case SCMP_ARCH_PPC64: + return "ppc64"; + case SCMP_ARCH_PPC64LE: + return "ppc64le"; + case SCMP_ARCH_S390: + return "s390"; + case SCMP_ARCH_S390X: + return "s390x"; + case SCMP_ARCH_RISCV64: + return "riscv64"; + case SCMP_ARCH_SHEB: + return "sheb"; + case SCMP_ARCH_SH: + return "sh"; + } + return NULL; +} + /** * Lookup the architecture definition by name * @param arch_name the architecture name diff --git a/src/arch.h b/src/arch.h index 419878e3..88196ebb 100644 --- a/src/arch.h +++ b/src/arch.h @@ -120,6 +120,7 @@ struct arch_syscall_def { int arch_valid(uint32_t arch); +const char *arch_def_name(uint32_t token); const struct arch_def *arch_def_lookup(uint32_t token); const struct arch_def *arch_def_lookup_name(const char *arch_name); diff --git a/src/gen_pfc.c b/src/gen_pfc.c index 91017166..a3eb4381 100644 --- a/src/gen_pfc.c +++ b/src/gen_pfc.c @@ -26,9 +26,6 @@ #include #include -/* NOTE: needed for the arch->token decoding in _pfc_arch() */ -#include - #include #include "arch.h" @@ -50,56 +47,8 @@ struct pfc_sys_list { */ static const char *_pfc_arch(const struct arch_def *arch) { - switch (arch->token) { - case SCMP_ARCH_X86: - return "x86"; - case SCMP_ARCH_X86_64: - return "x86_64"; - case SCMP_ARCH_X32: - return "x32"; - case SCMP_ARCH_ARM: - return "arm"; - case SCMP_ARCH_AARCH64: - return "aarch64"; - case SCMP_ARCH_LOONGARCH64: - return "loongarch64"; - case SCMP_ARCH_M68K: - return "m68k"; - case SCMP_ARCH_MIPS: - return "mips"; - case SCMP_ARCH_MIPSEL: - return "mipsel"; - case SCMP_ARCH_MIPS64: - return "mips64"; - case SCMP_ARCH_MIPSEL64: - return "mipsel64"; - case SCMP_ARCH_MIPS64N32: - return "mips64n32"; - case SCMP_ARCH_MIPSEL64N32: - return "mipsel64n32"; - case SCMP_ARCH_PARISC: - return "parisc"; - case SCMP_ARCH_PARISC64: - return "parisc64"; - case SCMP_ARCH_PPC64: - return "ppc64"; - case SCMP_ARCH_PPC64LE: - return "ppc64le"; - case SCMP_ARCH_PPC: - return "ppc"; - case SCMP_ARCH_S390X: - return "s390x"; - case SCMP_ARCH_S390: - return "s390"; - case SCMP_ARCH_RISCV64: - return "riscv64"; - case SCMP_ARCH_SHEB: - return "sheb"; - case SCMP_ARCH_SH: - return "sh"; - default: - return "UNKNOWN"; - } + const char *name = arch_def_name(arch->token); + return (name != NULL ? name : "UNKNOWN"); } /** diff --git a/tests/.gitignore b/tests/.gitignore index 55d1af1b..db6d04c2 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -72,3 +72,4 @@ util.pyc 62-sim-arch_transactions 63-live-notify_addfd 64-live-trapx +65-basic-arch_name diff --git a/tests/65-basic-arch_name.c b/tests/65-basic-arch_name.c new file mode 100644 index 00000000..7e6660b9 --- /dev/null +++ b/tests/65-basic-arch_name.c @@ -0,0 +1,99 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2025 Paul Moore + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc = 0; + uint32_t token; + const char *name; + + /* + * Verify round-trip: seccomp_arch_resolve_name() then + * seccomp_arch_name() must return the original name for every + * known architecture. + */ +#define CHECK_ARCH(str, tok) \ + do { \ + token = seccomp_arch_resolve_name(str); \ + if (token != (tok)) { \ + rc = -1; \ + goto out; \ + } \ + name = seccomp_arch_name(token); \ + if (name == NULL || strcmp(name, (str)) != 0) { \ + rc = -1; \ + goto out; \ + } \ + } while (0) + + CHECK_ARCH("x86", SCMP_ARCH_X86); + CHECK_ARCH("x86_64", SCMP_ARCH_X86_64); + CHECK_ARCH("x32", SCMP_ARCH_X32); + CHECK_ARCH("arm", SCMP_ARCH_ARM); + CHECK_ARCH("aarch64", SCMP_ARCH_AARCH64); + CHECK_ARCH("loongarch64", SCMP_ARCH_LOONGARCH64); + CHECK_ARCH("m68k", SCMP_ARCH_M68K); + CHECK_ARCH("mips", SCMP_ARCH_MIPS); + CHECK_ARCH("mipsel", SCMP_ARCH_MIPSEL); + CHECK_ARCH("mips64", SCMP_ARCH_MIPS64); + CHECK_ARCH("mipsel64", SCMP_ARCH_MIPSEL64); + CHECK_ARCH("mips64n32", SCMP_ARCH_MIPS64N32); + CHECK_ARCH("mipsel64n32", SCMP_ARCH_MIPSEL64N32); + CHECK_ARCH("parisc", SCMP_ARCH_PARISC); + CHECK_ARCH("parisc64", SCMP_ARCH_PARISC64); + CHECK_ARCH("ppc", SCMP_ARCH_PPC); + CHECK_ARCH("ppc64", SCMP_ARCH_PPC64); + CHECK_ARCH("ppc64le", SCMP_ARCH_PPC64LE); + CHECK_ARCH("s390", SCMP_ARCH_S390); + CHECK_ARCH("s390x", SCMP_ARCH_S390X); + CHECK_ARCH("riscv64", SCMP_ARCH_RISCV64); + CHECK_ARCH("sheb", SCMP_ARCH_SHEB); + CHECK_ARCH("sh", SCMP_ARCH_SH); +#undef CHECK_ARCH + + /* SCMP_ARCH_NATIVE must resolve to the native arch's name */ + name = seccomp_arch_name(SCMP_ARCH_NATIVE); + if (name == NULL) { + rc = -1; + goto out; + } + token = seccomp_arch_resolve_name(name); + if (token != seccomp_arch_native()) { + rc = -1; + goto out; + } + + /* invalid token must return NULL */ + name = seccomp_arch_name(0xdeadbeef); + if (name != NULL) { + rc = -1; + goto out; + } + +out: + return (rc < 0 ? EOPNOTSUPP : 0); +} diff --git a/tests/65-basic-arch_name.tests b/tests/65-basic-arch_name.tests new file mode 100644 index 00000000..ce28b5ec --- /dev/null +++ b/tests/65-basic-arch_name.tests @@ -0,0 +1,10 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2025 Paul Moore +# + +test type: basic + +# Test command +65-basic-arch_name diff --git a/tests/Makefile.am b/tests/Makefile.am index 280cfa83..eda0a112 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -99,7 +99,8 @@ check_PROGRAMS = \ 61-sim-transactions \ 62-sim-arch_transactions \ 63-live-notify_addfd \ - 64-live-trapx + 64-live-trapx \ + 65-basic-arch_name EXTRA_DIST_TESTPYTHON = \ util.py \ @@ -230,7 +231,8 @@ EXTRA_DIST_TESTCFGS = \ 61-sim-transactions.tests \ 62-sim-arch_transactions.tests \ 63-live-notify_addfd.tests \ - 64-live-trapx.tests + 64-live-trapx.tests \ + 65-basic-arch_name.tests EXTRA_DIST_TESTSCRIPTS = \ 38-basic-pfc_coverage.sh 38-basic-pfc_coverage.pfc \