diff --git a/doc/man/man3/seccomp_attr_set.3 b/doc/man/man3/seccomp_attr_set.3 index a23d8750..61834931 100644 --- a/doc/man/man3/seccomp_attr_set.3 +++ b/doc/man/man3/seccomp_attr_set.3 @@ -1,4 +1,4 @@ -.TH "seccomp_attr_set" 3 "30 May 2020" "paul@paul-moore.com" "libseccomp Documentation" +.TH "seccomp_attr_set" 3 "06 June 2020" "paul@paul-moore.com" "libseccomp Documentation" .\" ////////////////////////////////////////////////////////////////////////// .SH NAME .\" ////////////////////////////////////////////////////////////////////////// @@ -100,6 +100,12 @@ A flag to disable Speculative Store Bypass mitigations for this filter. Defaults to off ( .I value == 0). +.TP +.B SCMP_FLTATR_API_SYSRAWRC +A flag to specify if libseccomp should pass system error codes back to the +caller instead of the default -ECANCELED. Defaults to off ( +.I value +== 0). .\" ////////////////////////////////////////////////////////////////////////// .SH RETURN VALUE .\" ////////////////////////////////////////////////////////////////////////// diff --git a/doc/man/man3/seccomp_export_bpf.3 b/doc/man/man3/seccomp_export_bpf.3 index 68e735fb..98b35729 100644 --- a/doc/man/man3/seccomp_export_bpf.3 +++ b/doc/man/man3/seccomp_export_bpf.3 @@ -49,7 +49,7 @@ Return zero on success or one of the following error codes on failure: .TP .B -ECANCELED -There was a kernel failure beyond the control of the library. +There was a system failure beyond the control of the library. .TP .B -EFAULT Internal libseccomp failure. @@ -59,6 +59,11 @@ Invalid input, either the context or architecture token is invalid. .TP .B -ENOMEM The library was unable to allocate enough memory. +.P +If the \fISCMP_FLTATR_API_SYSRAWRC\fP filter attribute is non-zero then +additional error codes may be returned to the caller; these additional error +codes are the negative \fIerrno\fP values returned by the system. Unfortunately +libseccomp can make no guarantees about these return values. .\" ////////////////////////////////////////////////////////////////////////// .SH EXAMPLES .\" ////////////////////////////////////////////////////////////////////////// diff --git a/doc/man/man3/seccomp_load.3 b/doc/man/man3/seccomp_load.3 index dcca7f5b..8e2e6f0a 100644 --- a/doc/man/man3/seccomp_load.3 +++ b/doc/man/man3/seccomp_load.3 @@ -39,7 +39,7 @@ is "stricter" than Returns zero on success or one of the following error codes on failure: .TP .B -ECANCELED -There was a kernel failure beyond the control of the library. +There was a system failure beyond the control of the library. .TP .B -EFAULT Internal libseccomp failure. @@ -52,6 +52,11 @@ The library was unable to allocate enough memory. .TP .B -ESRCH Unable to load the filter due to thread issues. +.P +If the \fISCMP_FLTATR_API_SYSRAWRC\fP filter attribute is non-zero then +additional error codes may be returned to the caller; these additional error +codes are the negative \fIerrno\fP values returned by the system. Unfortunately +libseccomp can make no guarantees about these return values. .\" ////////////////////////////////////////////////////////////////////////// .SH EXAMPLES .\" ////////////////////////////////////////////////////////////////////////// diff --git a/doc/man/man3/seccomp_notify_alloc.3 b/doc/man/man3/seccomp_notify_alloc.3 index 48c4599b..50c89706 100644 --- a/doc/man/man3/seccomp_notify_alloc.3 +++ b/doc/man/man3/seccomp_notify_alloc.3 @@ -47,7 +47,7 @@ this response corresponds to. .P The .BR seccomp_notify_id_valid () -function checks to see if the syscall from a particualr notification request is +function checks to see if the syscall from a particular notification request is still valid, i.e. if the task is still alive. See NOTES below for details on race conditions. .P @@ -70,11 +70,12 @@ The .BR seccomp_notify_receive (), and .BR seccomp_notify_respond () -functions return zero on success or one of the following error codes on +functions return zero on success, or one of the following error codes on failure: .TP .B -ECANCELED -There was a kernel failure beyond the control of the library. +There was a system failure beyond the control of the library, check the +\fIerrno\fP value for more information. .TP .B -EFAULT Internal libseccomp failure. diff --git a/include/seccomp.h.in b/include/seccomp.h.in index 17c90b7b..c78846b5 100644 --- a/include/seccomp.h.in +++ b/include/seccomp.h.in @@ -76,6 +76,7 @@ enum scmp_filter_attr { * 2 - binary tree sorted by syscall * number */ + SCMP_FLTATR_API_SYSRAWRC = 9, /**< return the system return codes */ _SCMP_FLTATR_MAX, }; diff --git a/src/api.c b/src/api.c index e01b196f..b4f0c642 100644 --- a/src/api.c +++ b/src/api.c @@ -93,6 +93,27 @@ static int _rc_filter(int err) } } +/** + * Filter the system error codes we send back to callers + * @param col the filter collection + * @param err the error code + * + * This is similar to _rc_filter(), but it first checks the filter attribute + * to determine if we should be filtering the return codes. + * + */ +static int _rc_filter_sys(struct db_filter_col *col, int err) +{ + /* pass through success values */ + if (err >= 0) + return err; + + /* pass the return code if the SCMP_FLTATR_API_SYSRAWRC is true */ + if (db_col_attr_read(col, SCMP_FLTATR_API_SYSRAWRC)) + return err; + return -ECANCELED; +} + /** * Validate a filter context * @param ctx the filter context @@ -355,12 +376,14 @@ API int seccomp_arch_remove(scmp_filter_ctx ctx, uint32_t arch_token) API int seccomp_load(const scmp_filter_ctx ctx) { struct db_filter_col *col; + bool rawrc; if (_ctx_valid(ctx)) return _rc_filter(-EINVAL); col = (struct db_filter_col *)ctx; - return _rc_filter(sys_filter_load(col)); + rawrc = db_col_attr_read(col, SCMP_FLTATR_API_SYSRAWRC); + return _rc_filter(sys_filter_load(col, rawrc)); } /* NOTE - function header comment in include/seccomp.h */ @@ -638,28 +661,35 @@ API int seccomp_notify_fd(const scmp_filter_ctx ctx) /* NOTE - function header comment in include/seccomp.h */ API int seccomp_export_pfc(const scmp_filter_ctx ctx, int fd) { + int rc; + struct db_filter_col *col; + if (_ctx_valid(ctx)) return _rc_filter(-EINVAL); + col = (struct db_filter_col *)ctx; - return _rc_filter(gen_pfc_generate((struct db_filter_col *)ctx, fd)); + rc = gen_pfc_generate(col, fd); + return _rc_filter_sys(col, rc); } /* NOTE - function header comment in include/seccomp.h */ API int seccomp_export_bpf(const scmp_filter_ctx ctx, int fd) { int rc; + struct db_filter_col *col; struct bpf_program *program; if (_ctx_valid(ctx)) return _rc_filter(-EINVAL); + col = (struct db_filter_col *)ctx; - rc = gen_bpf_generate((struct db_filter_col *)ctx, &program); + rc = gen_bpf_generate(col, &program); if (rc < 0) return _rc_filter(rc); rc = write(fd, program->blks, BPF_PGM_SIZE(program)); gen_bpf_release(program); if (rc < 0) - return _rc_filter(-ECANCELED); + return _rc_filter_sys(col, -errno); - return _rc_filter(0); + return 0; } diff --git a/src/db.c b/src/db.c index ebf6ad0e..f0e00063 100644 --- a/src/db.c +++ b/src/db.c @@ -1071,6 +1071,7 @@ int db_col_reset(struct db_filter_col *col, uint32_t def_action) col->attr.log_enable = 0; col->attr.spec_allow = 0; col->attr.optimize = 1; + col->attr.api_sysrawrc = 0; /* set the state */ col->state = _DB_STA_VALID; @@ -1316,6 +1317,9 @@ int db_col_attr_get(const struct db_filter_col *col, case SCMP_FLTATR_CTL_OPTIMIZE: *value = col->attr.optimize; break; + case SCMP_FLTATR_API_SYSRAWRC: + *value = col->attr.api_sysrawrc; + break; default: rc = -EINVAL; break; @@ -1324,6 +1328,25 @@ int db_col_attr_get(const struct db_filter_col *col, return rc; } +/** + * Get a filter attribute + * @param col the seccomp filter collection + * @param attr the filter attribute + * + * Returns the requested filter attribute value with zero on any error. + * Special care must be given with this function as error conditions can be + * hidden from the caller. + * + */ +uint32_t db_col_attr_read(const struct db_filter_col *col, + enum scmp_filter_attr attr) +{ + uint32_t value = 0; + + db_col_attr_get(col, attr, &value); + return value; +} + /** * Set a filter attribute * @param col the seccomp filter collection @@ -1402,6 +1425,9 @@ int db_col_attr_set(struct db_filter_col *col, break; } break; + case SCMP_FLTATR_API_SYSRAWRC: + col->attr.api_sysrawrc = (value ? 1 : 0); + break; default: rc = -EINVAL; break; diff --git a/src/db.h b/src/db.h index ae485eef..b96b1049 100644 --- a/src/db.h +++ b/src/db.h @@ -120,6 +120,8 @@ struct db_filter_attr { uint32_t spec_allow; /* SCMP_FLTATR_CTL_OPTIMIZE related attributes */ uint32_t optimize; + /* return the raw system return codes */ + uint32_t api_sysrawrc; }; struct db_filter { @@ -191,6 +193,8 @@ int db_col_arch_exist(struct db_filter_col *col, uint32_t arch_token); int db_col_attr_get(const struct db_filter_col *col, enum scmp_filter_attr attr, uint32_t *value); +uint32_t db_col_attr_read(const struct db_filter_col *col, + enum scmp_filter_attr attr); int db_col_attr_set(struct db_filter_col *col, enum scmp_filter_attr attr, uint32_t value); diff --git a/src/gen_pfc.c b/src/gen_pfc.c index 9d86e06d..405f0807 100644 --- a/src/gen_pfc.c +++ b/src/gen_pfc.c @@ -464,7 +464,7 @@ static int _gen_pfc_arch(const struct db_filter_col *col, * * This function generates a pseudo filter code representation of the given * filter collection and writes it to the given fd. Returns zero on success, - * negative values on failure. + * negative errno values on failure. * */ int gen_pfc_generate(const struct db_filter_col *col, int fd) @@ -475,11 +475,11 @@ int gen_pfc_generate(const struct db_filter_col *col, int fd) newfd = dup(fd); if (newfd < 0) - return -ECANCELED; + return -errno; fds = fdopen(newfd, "a"); if (fds == NULL) { close(newfd); - return -ECANCELED; + return -errno; } /* generate the pfc */ diff --git a/src/python/libseccomp.pxd b/src/python/libseccomp.pxd index b9703180..0629bf1e 100644 --- a/src/python/libseccomp.pxd +++ b/src/python/libseccomp.pxd @@ -62,6 +62,7 @@ cdef extern from "seccomp.h": SCMP_FLTATR_CTL_LOG SCMP_FLTATR_CTL_SSB SCMP_FLTATR_CTL_OPTIMIZE + SCMP_FLTATR_API_SYSRAWRC cdef enum scmp_compare: SCMP_CMP_NE diff --git a/src/python/seccomp.pyx b/src/python/seccomp.pyx index d7c1bb12..13aa6692 100644 --- a/src/python/seccomp.pyx +++ b/src/python/seccomp.pyx @@ -318,6 +318,11 @@ cdef class Attr: CTL_TSKIP - allow rules with a -1 syscall number CTL_LOG - log not-allowed actions CTL_SSB - disable SSB mitigations + CTL_OPTIMIZE - the filter's optimization level: + 0: currently unused + 1: rules weighted by priority and complexity (DEFAULT) + 2: binary tree sorted by syscall number + API_SYSRAWRC - return the raw syscall codes """ ACT_DEFAULT = libseccomp.SCMP_FLTATR_ACT_DEFAULT ACT_BADARCH = libseccomp.SCMP_FLTATR_ACT_BADARCH @@ -327,6 +332,7 @@ cdef class Attr: CTL_LOG = libseccomp.SCMP_FLTATR_CTL_LOG CTL_SSB = libseccomp.SCMP_FLTATR_CTL_SSB CTL_OPTIMIZE = libseccomp.SCMP_FLTATR_CTL_OPTIMIZE + API_SYSRAWRC = libseccomp.SCMP_FLTATR_API_SYSRAWRC cdef class Arg: """ Python object representing a SyscallFilter syscall argument. diff --git a/src/system.c b/src/system.c index 737558e5..741a74ec 100644 --- a/src/system.c +++ b/src/system.c @@ -291,6 +291,7 @@ void sys_set_seccomp_flag(int flag, bool enable) /** * Loads the filter into the kernel * @param col the filter collection + * @param rawrc pass the raw return code if true * * This function loads the given seccomp filter context into the kernel. If * the filter was loaded correctly, the kernel will be enforcing the filter @@ -298,7 +299,7 @@ void sys_set_seccomp_flag(int flag, bool enable) * error. * */ -int sys_filter_load(struct db_filter_col *col) +int sys_filter_load(struct db_filter_col *col, bool rawrc) { int rc; struct bpf_program *prgm = NULL; @@ -343,7 +344,7 @@ int sys_filter_load(struct db_filter_col *col) if (rc == -ESRCH) return -ESRCH; if (rc < 0) - return -ECANCELED; + return (rawrc ? -errno : -ECANCELED); return rc; } diff --git a/src/system.h b/src/system.h index d183b5e2..7517c71d 100644 --- a/src/system.h +++ b/src/system.h @@ -188,7 +188,7 @@ void sys_set_seccomp_action(uint32_t action, bool enable); int sys_chk_seccomp_flag(int flag); void sys_set_seccomp_flag(int flag, bool enable); -int sys_filter_load(struct db_filter_col *col); +int sys_filter_load(struct db_filter_col *col, bool rawrc); int sys_notify_alloc(struct seccomp_notif **req, struct seccomp_notif_resp **resp); diff --git a/tests/.gitignore b/tests/.gitignore index b51acc34..59eb15c0 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -62,3 +62,4 @@ util.pyc 54-live-binary_tree 55-basic-pfc_binary_tree 56-basic-iterate_syscalls +57-basic-rawsysrc diff --git a/tests/13-basic-attrs.c b/tests/13-basic-attrs.c index e7b14f02..e3c5881d 100644 --- a/tests/13-basic-attrs.c +++ b/tests/13-basic-attrs.c @@ -120,6 +120,28 @@ int main(int argc, char *argv[]) goto out; } + rc = seccomp_attr_set(ctx, SCMP_FLTATR_CTL_OPTIMIZE, 2); + if (rc != 0) + goto out; + rc = seccomp_attr_get(ctx, SCMP_FLTATR_CTL_OPTIMIZE, &val); + if (rc != 0) + goto out; + if (val != 2) { + rc = -1; + goto out; + } + + rc = seccomp_attr_set(ctx, SCMP_FLTATR_API_SYSRAWRC, 1); + if (rc != 0) + goto out; + rc = seccomp_attr_get(ctx, SCMP_FLTATR_API_SYSRAWRC, &val); + if (rc != 0) + goto out; + if (val != 1) { + rc = -1; + goto out; + } + rc = 0; out: seccomp_release(ctx); diff --git a/tests/13-basic-attrs.py b/tests/13-basic-attrs.py index 0435ded9..48c25a06 100755 --- a/tests/13-basic-attrs.py +++ b/tests/13-basic-attrs.py @@ -58,6 +58,9 @@ def test(): f.set_attr(Attr.CTL_OPTIMIZE, 2) if f.get_attr(Attr.CTL_OPTIMIZE) != 2: raise RuntimeError("Failed getting Attr.CTL_OPTIMIZE") + f.set_attr(Attr.API_SYSRAWRC, 1) + if f.get_attr(Attr.API_SYSRAWRC) != 1: + raise RuntimeError("Failed getting Attr.API_SYSRAWRC") test() diff --git a/tests/57-basic-rawsysrc.c b/tests/57-basic-rawsysrc.c new file mode 100644 index 00000000..4248c7aa --- /dev/null +++ b/tests/57-basic-rawsysrc.c @@ -0,0 +1,64 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2020 Cisco Systems, Inc. + * Author: 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 +#include + +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc; + int fd; + scmp_filter_ctx ctx = NULL; + + rc = seccomp_api_set(3); + if (rc != 0) + return EOPNOTSUPP; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) { + rc = ENOMEM; + goto out; + } + + rc = seccomp_attr_set(ctx, SCMP_FLTATR_API_SYSRAWRC, 1); + if (rc != 0) + goto out; + + /* we must use a closed/invalid fd for this to work */ + fd = dup(2); + close(fd); + rc = seccomp_export_pfc(ctx, fd); + if (rc == -EBADF) + rc = 0; + else + rc = -1; + +out: + seccomp_release(ctx); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/57-basic-rawsysrc.py b/tests/57-basic-rawsysrc.py new file mode 100755 index 00000000..a88461a4 --- /dev/null +++ b/tests/57-basic-rawsysrc.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2020 Cisco Systems, Inc. +# Author: 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 . +# + +import argparse +import sys +import os + +import util + +from seccomp import * + +def test(): + # this test really isn't conclusive, but considering how python does error + # handling it may be the best we can do + f = SyscallFilter(ALLOW) + dummy = open("/dev/null", "w") + os.close(dummy.fileno()) + try: + f = f.export_pfc(dummy) + except RuntimeError: + pass + +test() + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/57-basic-rawsysrc.tests b/tests/57-basic-rawsysrc.tests new file mode 100644 index 00000000..fe716323 --- /dev/null +++ b/tests/57-basic-rawsysrc.tests @@ -0,0 +1,11 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2020 Cisco Systems, Inc. +# Author: Paul Moore +# + +test type: basic + +# Test command +57-basic-rawsysrc diff --git a/tests/Makefile.am b/tests/Makefile.am index 629b910f..1765eeca 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -95,7 +95,8 @@ check_PROGRAMS = \ 53-sim-binary_tree \ 54-live-binary_tree \ 55-basic-pfc_binary_tree \ - 56-basic-iterate_syscalls + 56-basic-iterate_syscalls \ + 57-basic-rawsysrc EXTRA_DIST_TESTPYTHON = \ util.py \ @@ -210,7 +211,8 @@ EXTRA_DIST_TESTCFGS = \ 53-sim-binary_tree.tests \ 54-live-binary_tree.tests \ 55-basic-pfc_binary_tree.tests \ - 56-basic-iterate_syscalls.tests + 56-basic-iterate_syscalls.tests \ + 57-basic-rawsysrc.tests EXTRA_DIST_TESTSCRIPTS = \ 38-basic-pfc_coverage.sh 38-basic-pfc_coverage.pfc \