aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build-test-ci.yml51
-rw-r--r--.gitignore5
-rw-r--r--INSTALL6
-rw-r--r--Makefile.am42
-rw-r--r--README28
-rw-r--r--README.md78
-rw-r--r--TODO25
-rwxr-xr-xautogen.sh15
-rw-r--r--configure.ac117
-rw-r--r--data/sandbox.bashrc15
-rw-r--r--etc/sandbox.conf15
-rw-r--r--headers.h6
-rw-r--r--libsandbox/Makefile4
-rw-r--r--libsandbox/Makefile.am93
-rw-r--r--libsandbox/canonicalize.c38
-rw-r--r--libsandbox/headers.h1
-rw-r--r--libsandbox/libsandbox.c236
-rw-r--r--libsandbox/libsandbox.h14
-rw-r--r--libsandbox/local.mk105
-rw-r--r--libsandbox/pre_check_at.c (renamed from libsandbox/wrapper-funcs/__pre_at_check.c)5
-rw-r--r--libsandbox/pre_check_mkdirat.c (renamed from libsandbox/wrapper-funcs/mkdirat_pre_check.c)11
-rw-r--r--libsandbox/pre_check_openat.c30
-rw-r--r--libsandbox/pre_check_openat64.c (renamed from libsandbox/wrapper-funcs/openat64_pre_check.c)9
-rw-r--r--libsandbox/pre_check_unlinkat.c (renamed from libsandbox/wrapper-funcs/unlinkat_pre_check.c)5
-rw-r--r--libsandbox/symbols.h.in17
-rw-r--r--libsandbox/trace.c370
-rw-r--r--libsandbox/trace/common.c2
-rw-r--r--libsandbox/trace/linux/aarch64.c50
-rw-r--r--libsandbox/trace/linux/arch.c4
-rw-r--r--libsandbox/trace/linux/i386.c2
-rw-r--r--libsandbox/trace/linux/powerpc.c10
-rw-r--r--libsandbox/trace/linux/s390.c6
-rw-r--r--libsandbox/trace/linux/sparc.c88
-rw-r--r--libsandbox/trace/linux/syscall_info.c24
-rw-r--r--libsandbox/trace/linux/x86_64.c8
-rw-r--r--libsandbox/wrapper-funcs/__64_post.h4
-rw-r--r--libsandbox/wrapper-funcs/__64_pre.h4
-rw-r--r--libsandbox/wrapper-funcs/__futimesat64.c13
l---------libsandbox/wrapper-funcs/__futimesat_time64.c1
-rw-r--r--libsandbox/wrapper-funcs/__lutimes64.c13
l---------libsandbox/wrapper-funcs/__lutimes_time64.c1
-rw-r--r--libsandbox/wrapper-funcs/__open64_2.c4
-rw-r--r--libsandbox/wrapper-funcs/__openat64_2.c4
-rw-r--r--libsandbox/wrapper-funcs/__openat_2.c6
-rw-r--r--libsandbox/wrapper-funcs/__pre_check.c24
-rw-r--r--libsandbox/wrapper-funcs/__utime64.c13
-rw-r--r--libsandbox/wrapper-funcs/__utimensat64.c13
l---------libsandbox/wrapper-funcs/__utimensat_time64.c1
-rw-r--r--libsandbox/wrapper-funcs/__utimes64.c13
l---------libsandbox/wrapper-funcs/__utimes_time64.c1
-rw-r--r--libsandbox/wrapper-funcs/__wrapper_exec.c124
-rw-r--r--libsandbox/wrapper-funcs/fchmod.c11
-rw-r--r--libsandbox/wrapper-funcs/fchown.c11
-rw-r--r--libsandbox/wrapper-funcs/fopen.c7
-rw-r--r--libsandbox/wrapper-funcs/fopen64.c4
-rw-r--r--libsandbox/wrapper-funcs/fopen64_pre_check.c2
-rw-r--r--libsandbox/wrapper-funcs/fopen_pre_check.c3
-rw-r--r--libsandbox/wrapper-funcs/futimesat.c6
-rw-r--r--libsandbox/wrapper-funcs/lremovexattr.c11
-rw-r--r--libsandbox/wrapper-funcs/lsetxattr.c11
-rw-r--r--libsandbox/wrapper-funcs/lutimes.c6
-rw-r--r--libsandbox/wrapper-funcs/open64.c4
-rw-r--r--libsandbox/wrapper-funcs/openat.c6
-rw-r--r--libsandbox/wrapper-funcs/openat64.c4
-rw-r--r--libsandbox/wrapper-funcs/openat_pre_check.c34
-rw-r--r--libsandbox/wrapper-funcs/removexattr.c11
-rw-r--r--libsandbox/wrapper-funcs/renameat2.c11
-rw-r--r--libsandbox/wrapper-funcs/setxattr.c11
-rw-r--r--libsandbox/wrapper-funcs/truncate.c4
-rw-r--r--libsandbox/wrapper-funcs/truncate64.c3
-rw-r--r--libsandbox/wrapper-funcs/utime.c4
-rw-r--r--libsandbox/wrapper-funcs/utimensat.c6
-rw-r--r--libsandbox/wrapper-funcs/utimes.c6
-rw-r--r--libsandbox/wrapper-funcs/vfork.c28
-rw-r--r--libsandbox/wrappers.h2
-rw-r--r--libsbutil/Makefile4
-rw-r--r--libsbutil/Makefile.am70
-rw-r--r--libsbutil/get_sandbox_conf.c1
-rw-r--r--libsbutil/headers.h1
-rw-r--r--libsbutil/include/rcscripts/util/file.h2
-rw-r--r--libsbutil/local.mk64
-rw-r--r--libsbutil/sb_close.c4
-rw-r--r--libsbutil/sb_exists.c24
-rw-r--r--libsbutil/sb_method.c34
-rw-r--r--libsbutil/sbutil.h33
-rw-r--r--libsbutil/src/debug.c2
-rw-r--r--libsbutil/src/file.c38
-rw-r--r--localdecls.h13
-rw-r--r--m4/ax_append_compile_flags.m467
-rw-r--r--m4/ax_append_flag.m471
-rw-r--r--m4/ax_append_link_flags.m465
-rw-r--r--m4/ax_cflags_force_c89.m493
-rw-r--r--m4/ax_cflags_no_writable_strings.m4121
-rw-r--r--m4/ax_cflags_strict_prototypes.m4118
-rw-r--r--m4/ax_cflags_warn_all.m4180
-rw-r--r--m4/ax_check_compile_flag.m431
-rw-r--r--m4/ax_check_link_flag.m431
-rw-r--r--m4/ax_compiler_flags.m4158
-rw-r--r--m4/ax_compiler_flags_cflags.m4140
-rw-r--r--m4/ax_compiler_flags_cxxflags.m4136
-rw-r--r--m4/ax_compiler_flags_gir.m460
-rw-r--r--m4/ax_compiler_flags_ldflags.m492
-rw-r--r--m4/ax_compiler_vendor.m4119
-rw-r--r--m4/ax_prepend_flag.m451
-rw-r--r--scripts/gen_symbol_header.awk145
-rw-r--r--scripts/gen_symbol_version_map.awk137
-rw-r--r--scripts/gen_trace_header.awk49
-rw-r--r--src/Makefile4
-rw-r--r--src/Makefile.am17
-rw-r--r--src/environ.c15
-rw-r--r--src/local.mk14
-rw-r--r--src/namespaces.c19
-rw-r--r--src/options.c81
-rw-r--r--src/sandbox.c102
-rw-r--r--src/sandbox.h14
-rw-r--r--tests/Makefile4
-rw-r--r--tests/Makefile.am123
-rw-r--r--tests/atlocal.in28
-rw-r--r--tests/fchmod-0.c35
-rwxr-xr-xtests/fchmod-1.sh18
-rwxr-xr-xtests/fchmod-2.sh11
-rw-r--r--tests/fchmod.at2
-rw-r--r--tests/fchown-0.c34
-rwxr-xr-xtests/fchown-1.sh18
-rwxr-xr-xtests/fchown-2.sh11
-rw-r--r--tests/fchown.at2
-rw-r--r--tests/fork-follow_static_tst.c1
-rw-r--r--tests/fork-follow_tst.c34
-rw-r--r--tests/get-group.c4
-rw-r--r--tests/get-user.c4
-rwxr-xr-xtests/git-bisector.sh15
-rw-r--r--tests/libsigsegv_tst.c2
-rw-r--r--tests/local.at2
-rw-r--r--tests/local.mk150
-rw-r--r--tests/lremovexattr-0.c15
-rw-r--r--tests/lsetxattr-0.c24
-rwxr-xr-xtests/lutimes-1.sh9
-rw-r--r--tests/lutimes.at1
-rw-r--r--tests/malloc_hooked_tst.c2
-rw-r--r--tests/removexattr-0.c15
-rwxr-xr-xtests/removexattr-1.sh13
-rw-r--r--tests/removexattr.at1
-rw-r--r--tests/renameat2-0.c22
-rwxr-xr-xtests/renameat2-1.sh8
-rwxr-xr-xtests/renameat2-2.sh12
-rwxr-xr-xtests/renameat2-3.sh11
-rw-r--r--tests/renameat2.at3
-rwxr-xr-xtests/script-1.sh7
-rwxr-xr-x[-rw-r--r--]tests/script-14.sh0
-rwxr-xr-x[-rw-r--r--]tests/script-15.sh0
-rwxr-xr-xtests/script-16.sh12
-rwxr-xr-xtests/script-17.sh23
-rwxr-xr-xtests/script-2.sh2
-rwxr-xr-xtests/script-3.sh2
-rwxr-xr-xtests/script-8.sh3
-rw-r--r--tests/script.at2
-rw-r--r--tests/setxattr-0.c24
-rwxr-xr-xtests/setxattr-1.sh13
-rw-r--r--tests/setxattr.at1
-rw-r--r--tests/test-skel-0.c6
-rw-r--r--tests/tests.h1
-rwxr-xr-xtests/trace-02
-rw-r--r--tests/trace-memory_static_tst.c4
-rwxr-xr-xtests/utimensat-3.sh11
-rw-r--r--tests/utimensat64-0.c3
-rwxr-xr-xtests/utimensat64-1.sh9
-rw-r--r--tests/utimensat64.at1
-rw-r--r--tests/utimensat64_static-0.c1
-rwxr-xr-xtests/utimensat64_static-1.sh10
-rw-r--r--tests/utimensat64_static.at1
-rwxr-xr-xtests/xattr-07
171 files changed, 2865 insertions, 2314 deletions
diff --git a/.github/workflows/build-test-ci.yml b/.github/workflows/build-test-ci.yml
new file mode 100644
index 0000000..5c95baa
--- /dev/null
+++ b/.github/workflows/build-test-ci.yml
@@ -0,0 +1,51 @@
+# GitHub actions workflow.
+# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions
+
+name: Build+Test CI
+
+on: [pull_request, push]
+
+jobs:
+ glibc:
+ strategy:
+ matrix:
+ cc: [gcc, clang]
+ fail-fast: false
+ runs-on: ubuntu-latest
+ env:
+ CC: ${{ matrix.cc }}
+ steps:
+ - name: Install dependencies
+ run: |
+ sudo apt-get update -qq
+ sudo apt-get install build-essential gcc clang automake autoconf autoconf-archive libtool pax-utils -qy
+
+ - uses: actions/checkout@v3
+ name: Checkout
+
+ - name: Build
+ run: |
+ ./autogen.sh
+ ./configure || { cat config.log; false; }
+ make V=1
+ make V=1 check || { cat tests/testsuite.log; false; }
+ make V=1 distcheck
+
+ musl:
+ runs-on: ubuntu-latest
+ container:
+ image: alpine:latest
+ options: --cap-add=SYS_PTRACE
+ steps:
+ - name: Install dependencies
+ run: apk add bash coreutils build-base automake autoconf autoconf-archive libtool pax-utils gawk sed
+
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Build
+ run: |
+ ./autogen.sh
+ ./configure || { cat config.log; false; }
+ make V=1
+ make V=1 check || { cat tests/testsuite.log; false; }
diff --git a/.gitignore b/.gitignore
index 76d3d1a..7704390 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,8 +7,8 @@ a.out
.deps
.libs
.dirstamp
-Makefile
-Makefile.in
+/Makefile
+/Makefile.in
f
f2
@@ -42,7 +42,6 @@ core
/ltmain.sh
/missing
/stamp-h1
-/test.sh
/m4/libtool.m4
/m4/ltoptions.m4
diff --git a/INSTALL b/INSTALL
index 8865734..e82fd21 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,8 +1,8 @@
Installation Instructions
*************************
- Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software
-Foundation, Inc.
+ Copyright (C) 1994-1996, 1999-2002, 2004-2017, 2020-2021 Free
+Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
@@ -225,7 +225,7 @@ order to use an ANSI C compiler:
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
- HP-UX 'make' updates targets which have the same time stamps as their
+ HP-UX 'make' updates targets which have the same timestamps as their
prerequisites, which makes it generally unusable when shipped generated
files such as 'configure' are involved. Use GNU 'make' instead.
diff --git a/Makefile.am b/Makefile.am
index 309a41e..07b1c6d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,40 +1,36 @@
ACLOCAL_AMFLAGS = -I m4
MAKEFLAGS = --no-print-directory
-AM_CPPFLAGS = $(SANDBOX_DEFINES)
-
-SUBDIRS = \
- libsbutil \
- libsandbox \
- src \
- tests
+AM_CPPFLAGS = \
+ $(SANDBOX_DEFINES) \
+ -I$(top_srcdir)
confdir = $(sysconfdir)
confddir = $(sysconfdir)/sandbox.d
-pixmapdir = $(datadir)/pixmaps
-desktopdir = $(datadir)/applications
+bin_PROGRAMS =
+check_PROGRAMS =
+check_SCRIPTS =
+dist_check_SCRIPTS =
dist_conf_DATA = etc/sandbox.conf
confd_DATA = etc/sandbox.d/00default
dist_pkgdata_DATA = data/sandbox.bashrc
-dist_pixmap_DATA = data/sandbox.svg
-dist_desktop_DATA = data/sandbox.desktop
+lib_LTLIBRARIES =
noinst_LTLIBRARIES =
-libsandbox: libsbutil
-src: libsbutil
-tests: src
+CLEANFILES =
+DISTCLEANFILES =
EXTRA_DIST = \
headers.h \
localdecls.h \
ChangeLog.0 \
+ data/sandbox.desktop \
+ data/sandbox.svg \
etc/sandbox.d/00default.in \
scripts/gen_symbol_version_map.awk \
scripts/gen_symbol_header.awk \
scripts/gen_trace_header.awk
-DISTCLEANFILES = $(CLEANFILES)
-
ChangeLog:
touch ChangeLog
@@ -50,11 +46,9 @@ dist-hook:
fi ; \
fi
-install-exec-hook:
- set -e ; \
- for f in $(bindir)/sandbox $(libdir)/libsandbox.so ; do \
- sed -i.tmp \
- 's:__SANDBOX_TESTING:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:' \
- $(DESTDIR)$$f ; \
- rm -f $(DESTDIR)$$f.tmp ; \
- done
+include libsandbox/local.mk
+include libsbutil/local.mk
+include src/local.mk
+include tests/local.mk
+
+DISTCLEANFILES += $(CLEANFILES)
diff --git a/README b/README
deleted file mode 100644
index 1bbc6e6..0000000
--- a/README
+++ /dev/null
@@ -1,28 +0,0 @@
----------
- about
----------
-
-Sandbox is a library (and helper utility) to run programs in a "sandboxed"
-environment. This is used as a QA measure to try and prevent applications from
-modifying files they should not.
-
-For example, in the Gentoo world we use it so we can build applications as root
-and make sure that the build system does not do crazy things outside of its
-build directory. Such as install files to the live root file system or modify
-config files on the fly.
-
-For people who are familiar with the Debian "fakeroot" project or the RPM based
-"InstallWatch", sandbox is in the same vein of projects.
-
-----------
- method
-----------
-
-The way sandbox works is that you prime a few environment variables (in order
-to control the sandbox's behavior) and then stick it into the LD_PRELOAD
-variable. Then when the ELF loader runs, it will first load the sandbox
-library. Whenever an applications makes a library call that we have wrapped,
-we'll check the arguments against the environment settings. Based on that, any
-access that is not permitted is logged and we return an error to the
-application. Any access that is permitted is of course forwarded along to the
-real C library.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..750c0fe
--- /dev/null
+++ b/README.md
@@ -0,0 +1,78 @@
+# Sandbox
+
+Sandbox is a library (and helper utility) to run programs in a "sandboxed"
+environment. This is used as a QA measure to try and prevent applications from
+modifying files they should not.
+
+For example, in the Gentoo world we use it so we can build applications as root
+and make sure that the build system does not do crazy things outside of its
+build directory. Such as install files to the live root file system or modify
+config files on the fly.
+
+For people who are familiar with the Debian "fakeroot" project or the RPM based
+"InstallWatch", sandbox is in the same vein of projects.
+
+## Method
+
+The way sandbox works is that you prime a few environment variables (in order
+to control the sandbox's behavior) and then stick it into the LD_PRELOAD
+variable. Then when the ELF loader runs, it will first load the sandbox
+library. Whenever an applications makes a library call that we have wrapped,
+we'll check the arguments against the environment settings. Based on that, any
+access that is not permitted is logged and we return an error to the
+application. Any access that is permitted is of course forwarded along to the
+real C library.
+
+Static ELFs and setuid/setgid programs are executed with
+[ptrace()](https://man7.org/linux/man-pages/man2/ptrace.2.html) instead.
+
+## Availability
+
+Sandbox supports multiple monitoring methods, but not all are available in all
+system configurations.
+
+### preload
+
+The in-process LD_PRELOAD method should be available on any reasonable ELF-based
+system as long as it uses dynamic linking. Statically linked programs will run,
+but will not be monitored, nor will set*id programs (because the C library will
+clear LD_PRELOAD first).
+
+Multiple ABIs are supported (e.g. x86 32-bit & 64-bit).
+
+It has been tested & known to work with:
+* Architecture
+ * They all should work!
+* Operating system
+ * [Linux](https://kernel.org/) 2.4+
+* C library
+ * [GNU C library (glibc)](https://www.gnu.org/software/libc/) 2.2+
+ * [uClibc](https://uclibc.org/) 0.9.26+
+ * [musl](https://musl.libc.org/) 0.9.9+
+
+### ptrace
+
+The out-of-process ptrace method is available on Linux systems, works with
+dynamic & static linking, and supports set*id programs (by forcing them to run
+without any elevated privileges).
+
+Multiple personalities are supported (e.g. PowerPC 32-bit & 64-bit).
+
+NB: Does not work in userland emulators (e.g. QEMU) which do not provide ptrace
+emulation.
+
+It requires:
+* Architecture
+ * Alpha
+ * ARM (32-bit EABI)
+ * Blackfin
+ * HPPA/PA-RISC (32-bit)
+ * Itanium
+ * PowerPC (32-bit & 64-bit)
+ * s390 (32-bit & 64-bit)
+ * SPARC (32-bit & 64-bit)
+ * x86 (32-bit & 64-bit & x32)
+* Operating system
+ * [Linux](https://kernel.org/) 3.8+
+* C library
+ * They all should work!
diff --git a/TODO b/TODO
index c8d1109..2210d84 100644
--- a/TODO
+++ b/TODO
@@ -9,6 +9,26 @@ review erealpath vs realpath usage
wrappers for execl{,l,p} ... unfortunately, we'll probably have to basically
reimplement the functions (building up argv[] and then call the execv* ver)
+wrappers for open funcs:
+ - freopen
+ - freopen64
+ - name_to_handle_at
+ - open_by_handle_at
+ - __open
+ - __open64
+
+wrappers for 64-bit time funcs
+https://bugs.gentoo.org/751241
+
+wrappers for syscalls that modify non-filesystem resources ?
+how would we `addpredict` these ?
+is it worth checking for these in the first place ? unittests sometimes do
+terrible things to systems.
+ - clock_settime
+ - create_module
+ - setdomainname
+ - settimeofday
+
erealpath() might deref symlinks when working with unreadable paths as non-root
even when working on funcs that do not deref funcs themselves ... this isnt a
real big issue though
@@ -26,8 +46,6 @@ handle multiple processing writing to log simultaneously
doesnt seem to work quite right:
echo $(./vfork-0 ./mkdir_static-0 2>&1)
-handle env var modification inside of traced apps
-
messaging still needs a little work. consider:
- user is running as root
- user does `emerge foo`
@@ -40,3 +58,6 @@ really only way around this would be to have sandbox set up
a named pipe in $T and set the message path to that. then
it would poll that for data and take care of writing it to
its open stderr.
+
+sparc32 tracing under sparc64 doesn't work quite right. we need to reload the
+syscall table after the exec call finishes. not sure any other port needs this.
diff --git a/autogen.sh b/autogen.sh
index e583300..2223e51 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -7,14 +7,21 @@ touch ChangeLog
# whatever updated version is on the host
rm -f m4/*.m4
-# not everyone has sys-devel/autoconf-archive installed
+# not everyone has dev-build/autoconf-archive installed
has() { [[ " ${*:2} " == *" $1 "* ]] ; }
import_ax() {
- local macro content m4 lm4s=()
+ local macro content m4 found lm4s=()
content=$(sed -e '/^[[:space:]]*#/d' -e 's:\<dnl\>.*::' "$@")
for macro in $(echo "${content}" | grep -o '\<AX[A-Z_]*\>' | sort -u) ; do
- for m4 in $(grep -rl "\[${macro}\]" /usr/share/aclocal/) ; do
- has ${m4} "${m4s[@]}" || lm4s+=( ${m4} )
+ if ! found=$(grep -rl "AC_DEFUN(\[${macro}\]" /usr/share/aclocal/) ; then
+ echo "error: ${macro}: unable to locate m4 definition"
+ exit 1
+ fi
+ for m4 in ${found} ; do
+ if ! has ${m4} "${m4s[@]}" "${lm4s[@]}" ; then
+ echo "$*: ${macro}: ${m4}"
+ lm4s+=( ${m4} )
+ fi
done
done
if [[ ${#lm4s[@]} -gt 0 ]] ; then
diff --git a/configure.ac b/configure.ac
index 8c1866c..7d6fce4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.69])
-AC_INIT([sandbox], [2.15], [sandbox@gentoo.org])
-AM_INIT_AUTOMAKE([1.14 dist-xz no-dist-gzip silent-rules subdir-objects -Wall])
+AC_INIT([sandbox], [3.2], [sandbox@gentoo.org])
+AM_INIT_AUTOMAKE([1.15 dist-xz foreign no-dist-gzip silent-rules subdir-objects -Wall])
AM_SILENT_RULES([yes]) # AM_INIT_AUTOMAKE([silent-rules]) is broken atm
AC_CONFIG_HEADER([config.h])
AC_CONFIG_MACRO_DIR([m4])
@@ -20,10 +20,18 @@ env 1>&AS_MESSAGE_LOG_FD
AC_MSG_RESULT([ok])
dnl Check for compiler and features first.
-AC_PROG_CC
+AC_PROG_CC_C99
+AS_IF([test "$ac_cv_prog_cc_c99" = "no"], [AC_MSG_ERROR([A C99+ compiler is required])])
AM_PROG_CC_C_O
AC_ISC_POSIX
AC_USE_SYSTEM_EXTENSIONS
+dnl http://www.gnu.org/s/libc/manual/html_node/Feature-Test-Macros.html
+dnl _LARGEFILE_SOURCE: enable support for new LFS funcs (ftello/etc...)
+dnl _LARGEFILE64_SOURCE: enable support for 64-bit variants (off64_t/fseeko64/etc...)
+dnl NB: We do not want -D_FILE_OFFSET_BITS=64 because we need to interpose both 32-bit
+dnl and 64-bit FS interfaces, and having the C library rewrite them makes that difficult.
+dnl Along those lines, we do not use AC_SYS_LARGEFILE.
+AS_VAR_APPEND([CPPFLAGS], [" -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE"])
dnl Checks for programs.
AM_PROG_AR
@@ -31,7 +39,7 @@ AC_PROG_INSTALL
AC_PROG_MAKE_SET
AC_PROG_AWK
AC_PROG_EGREP
-AC_CHECK_PROGS([READELF], [readelf eu-readelf], [false])
+AC_CHECK_TOOLS([READELF], [readelf eu-readelf], [false])
AM_MISSING_PROG([AUTOM4TE], [autom4te])
LT_INIT([disable-static])
@@ -40,12 +48,12 @@ AC_PREFIX_DEFAULT([/usr])
dnl multiple personality support (x86 & x86_64: multilib)
AC_MSG_CHECKING([for multiple personalities])
-AC_ARG_ENABLE([schizo],
- [AS_HELP_STRING([--enable-schizo],[Support multiple personalities])],
- [],[enable_schizo="auto"])
-AC_MSG_RESULT([$enable_schizo])
-SB_SCHIZO_SETTINGS=
-AC_DEFUN([SB_CHECK_SCHIZO],[dnl
+AC_ARG_ENABLE([personalities],
+ [AS_HELP_STRING([--enable-personalities],[Support multiple Linux personalities using ptrace])],
+ [],[enable_personalities="auto"])
+AC_MSG_RESULT([$enable_personalities])
+SB_PERSONALITIES_SETTINGS=
+AC_DEFUN([SB_CHECK_PERSONALITIES],[dnl
AC_MSG_CHECKING([checking for $1/$2 compiler support])
ac_save_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS $2"
@@ -54,43 +62,46 @@ AC_DEFUN([SB_CHECK_SCHIZO],[dnl
], [
return 0
], [
- enable_schizo=yes
- AS_VAR_APPEND([SB_SCHIZO_SETTINGS], " $1:$2")
- AS_VAR_APPEND([SB_SCHIZO_HEADERS], " trace_syscalls_$1.h")
+ enable_personalities=yes
+ AS_VAR_APPEND([SB_PERSONALITIES_SETTINGS], " $1:$2")
+ AS_VAR_APPEND([SB_PERSONALITIES_HEADERS], " libsandbox/trace_syscalls_$1.h")
AC_MSG_RESULT([yes])
- AC_DEFINE_UNQUOTED([SB_SCHIZO_$1], 1, [Support for $1/$2 is available])
+ AC_DEFINE_UNQUOTED([SB_PERSONALITIES_$1], 1, [Support for $1/$2 is available])
], [
AC_MSG_RESULT([no])
])
CFLAGS=$ac_save_CFLAGS
])
-if test "x$enable_schizo" != "xno" ; then
- enable_schizo=no
+if test "x$enable_personalities" != "xno" ; then
+ enable_personalities=no
case $host in
i686*linux*|\
x86_64*linux*)
- SB_CHECK_SCHIZO([x86_64], [-m64])
- SB_CHECK_SCHIZO([x86], [-m32])
- SB_CHECK_SCHIZO([x32], [-mx32])
+ SB_CHECK_PERSONALITIES([x86_64], [-m64])
+ SB_CHECK_PERSONALITIES([x86], [-m32])
+ SB_CHECK_PERSONALITIES([x32], [-mx32])
;;
s390*linux*)
- SB_CHECK_SCHIZO([s390x], [-m64])
- SB_CHECK_SCHIZO([s390], [-m31])
+ SB_CHECK_PERSONALITIES([s390x], [-m64])
+ SB_CHECK_PERSONALITIES([s390], [-m31])
+ ;;
+ sparc*linux*)
+ SB_CHECK_PERSONALITIES([sparc64], [-m64])
+ SB_CHECK_PERSONALITIES([sparc], [-m32])
;;
esac
- SB_SCHIZO_SETTINGS=${SB_SCHIZO_SETTINGS# }
- if test "x$enable_schizo" != "xno" ; then
- AC_DEFINE_UNQUOTED([SB_SCHIZO], ["$SB_SCHIZO_SETTINGS"], [Enable multiple personalities support])
+ SB_PERSONALITIES_SETTINGS=${SB_PERSONALITIES_SETTINGS# }
+ if test "x$enable_personalities" != "xno" ; then
+ AC_DEFINE_UNQUOTED([SB_PERSONALITIES], ["$SB_PERSONALITIES_SETTINGS"], [Enable multiple personalities support])
fi
fi
-AC_SUBST(SB_SCHIZO_SETTINGS)
-AC_SUBST(SB_SCHIZO_HEADERS)
-AM_CONDITIONAL([SB_SCHIZO], [test "x$enable_schizo" != "xno"])
+AC_SUBST(SB_PERSONALITIES_SETTINGS)
+AC_SUBST(SB_PERSONALITIES_HEADERS)
+AM_CONDITIONAL([SB_PERSONALITIES], [test "x$enable_personalities" != "xno"])
dnl this test fills up the stack and then triggers a segfault ...
dnl but it's hard to wrap things without a stack, so let's ignore
dnl this test for now ...
-ac_cv_header_sigsegv_h=no
ac_cv_lib_sigsegv_stackoverflow_install_handler=false
dnl Checks for libraries.
@@ -134,6 +145,7 @@ AC_CHECK_HEADERS_ONCE(m4_flatten([
sys/mman.h
sys/mount.h
sys/param.h
+ sys/prctl.h
sys/ptrace.h
sys/reg.h
sys/socket.h
@@ -144,6 +156,7 @@ AC_CHECK_HEADERS_ONCE(m4_flatten([
sys/uio.h
sys/user.h
sys/wait.h
+ sys/xattr.h
asm/ptrace.h
linux/ptrace.h
]))
@@ -160,6 +173,7 @@ AC_CHECK_TYPES([sighandler_t, sig_t, __sighandler_t],,,[#include <signal.h>])
save_CPPFLAGS=$CPPFLAGS
CPPFLAGS="-I$srcdir $CPPFLAGS"
+AC_CHECK_TYPES([struct ptrace_syscall_info],,,[#include "headers.h"])
AC_CHECK_TYPES([struct user_regs_struct, struct pt_regs],,,[#include "headers.h"])
AC_CHECK_SIZEOF([struct user_regs_struct],,[#include "headers.h"])
AC_CHECK_SIZEOF([struct pt_regs],,[#include "headers.h"])
@@ -186,6 +200,8 @@ AC_CHECK_FUNCS_ONCE(m4_flatten([
getcwd
lchown
linkat
+ lremovexattr
+ lsetxattr
lutimes
memmove
memcpy
@@ -207,13 +223,17 @@ AC_CHECK_FUNCS_ONCE(m4_flatten([
openat
openat64
pathconf
+ prctl
process_vm_readv
ptrace
realpath
remove
+ removexattr
renameat
+ renameat2
rmdir
setenv
+ setxattr
strcasecmp
strchr
strdup
@@ -274,18 +294,18 @@ if test x"$va_copy" != xva_copy ; then
)
fi
-dnl Verify people aren't doing stupid shit
+dnl Avoid footguns.
if test x"$enable_static" != xno ; then
- AC_MSG_ERROR([dont be a Kumba, building a libsandbox.a is stupid])
+ AC_MSG_ERROR([Building a static libsandbox.a is not supported])
fi
if test x"$enable_shared" != xyes ; then
- AC_MSG_ERROR([dont be a Kumba, omitting a libsandbox.so is stupid])
+ AC_MSG_ERROR([Omitting a libsandbox.so is not supported])
fi
if echo " $CFLAGS " | $EGREP ' -static ' >/dev/null 2>&1; then
- AC_MSG_ERROR([dont be a Kumba, using -static in CFLAGS is stupid])
+ AC_MSG_ERROR([Using -static in CFLAGS is not supported])
fi
if echo " $LDFLAGS " | $EGREP ' -static ' >/dev/null 2>&1; then
- AC_MSG_ERROR([dont be a Kumba, using -static in LDFLAGS is stupid])
+ AC_MSG_ERROR([Using -static in LDFLAGS is not supported])
fi
dnl Some libc's like those on bsd have dlopen() in libc, and not libdl
@@ -295,18 +315,6 @@ dnl uClibc doesn't currently provide dlvsym() so lets
dnl verify the toolchain supports it
AC_CHECK_FUNCS([dlvsym])
-dnl when using libc5, (f)trucate's offset argument type is size_t with
-dnl libc5, but it's off_t with libc6 (glibc2).
-AC_MSG_CHECKING([truncate argument type])
-AC_EGREP_HEADER([truncate.*size_t], [unistd.h],
- [dnl
- AC_MSG_RESULT([size_t])
- AC_DEFINE([TRUNCATE_T], [size_t], [truncate arg type])
- ],[dnl
- AC_MSG_RESULT([off_t])
- AC_DEFINE([TRUNCATE_T], [off_t], [truncate arg type])
-])
-
dnl Check if libc provides RTLD_NEXT
AC_MSG_CHECKING([for RTLD_NEXT])
AC_TRY_COMPILE([
@@ -324,7 +332,7 @@ if test x"$have_rtld_next" = xyes ; then
AC_DEFINE([HAVE_RTLD_NEXT], [1], [Have RTLD_NEXT enabled libc])
fi
-dnl we need to handle symbols differently based upon their version,
+dnl we need to handle symbols differently based upon their version,
dnl but we have to know which symbols the libc supports first
AC_MSG_CHECKING([libc path])
echo "int main(void) { return 0; }" > libctest.c
@@ -344,9 +352,12 @@ try_link() {
) 1>&AS_MESSAGE_LOG_FD
}
LIBC_PATH=$(AS_IF(
- dnl GNU linker (bfd & gold)
- [try_link -Wl,--verbose],
- [$AWK '/ttempt to open/ { if (($(NF-1) ~ /\/libc\.so/) && ($NF == "succeeded")) LIBC = $(NF-1); }; END {print LIBC}' libctest.log],
+ dnl GNU linkers (bfd, gold), LLVM lld, mold - searching for latest entry of:
+ dnl "/usr/lib/gcc/x86_64-pc-linux-gnu/8.3.0/../../../../lib64/libc.so"
+ dnl "/lib64/libc.so.6"
+ dnl Note that mold prefixes output with "trace: " whereas others do not.
+ [try_link -Wl,--trace],
+ [$EGREP -o '/[[^ ]]*/libc.so.*' libctest.log | tail -n1],
dnl Solaris linker
[try_link -Wl,-m],
[set -- `$EGREP -o '/[[^ ]]*/libc.so' libctest.log`; echo $1]
@@ -359,7 +370,7 @@ AC_DEFINE_UNQUOTED([LIBC_PATH], ["$LIBC_PATH"], [Full path to the libc])
AC_MSG_RESULT([$LIBC_PATH])
AC_SUBST([LIBC_PATH])
-dnl when intercepting libc calls, we have to know the name of the
+dnl when intercepting libc calls, we have to know the name of the
dnl libc to load and search with dl*() calls
AC_MSG_CHECKING([libc version])
dnl the sed script at the end here looks funny but it's ok ...
@@ -367,7 +378,7 @@ echo "int main(void) { return 0; }" > libctest.c
$CC $CFLAGS $CPPFLAGS $LDFLAGS -o libctest libctest.c
LIBC_VERSION=$(
$READELF -d libctest | \
- $EGREP 'NEEDED.* \@<:@libc\.so' | \
+ $EGREP 'NEEDED.* \@<:@libc\..*so' | \
$AWK '{print $NF}' | [sed -e 's:\[::' -e 's:\]::']
)
rm -f libctest*
@@ -457,11 +468,7 @@ AC_CONFIG_FILES([src/sandbox.sh], [chmod +x src/sandbox.sh])
AC_CONFIG_FILES([
Makefile
etc/sandbox.d/00default
- libsandbox/Makefile
- libsbutil/Makefile
- src/Makefile
tests/atlocal
- tests/Makefile
tests/package.m4
])
AC_OUTPUT
diff --git a/data/sandbox.bashrc b/data/sandbox.bashrc
index 7601d35..3b953b8 100644
--- a/data/sandbox.bashrc
+++ b/data/sandbox.bashrc
@@ -9,7 +9,6 @@ fi
export BASH_ENV="${SANDBOX_BASHRC}"
-alias make="make LD_PRELOAD=${LD_PRELOAD}"
alias su="su -c '/bin/bash -rcfile ${SANDBOX_BASHRC}'"
declare -r SANDBOX_ACTIVE
@@ -29,8 +28,8 @@ if [[ ${SANDBOX_INTRACTV} == "1" && -t 1 ]] || [[ ${__SANDBOX_TESTING} == "yes"
(
[[ ${NOCOLOR} == "true" || ${NOCOLOR} == "yes" || ${NOCOLOR} == "1" ]] && \
export RC_NOCOLOR="yes"
- source /etc/init.d/functions.sh
- if [ $? -ne 0 ] ; then
+ source /lib/gentoo/functions.sh
+ if [[ $? -ne 0 ]] ; then
einfo() { echo " INFO: $*"; }
ewarn() { echo " WARN: $*"; }
eerror() { echo " ERR: $*"; }
@@ -71,7 +70,7 @@ if [[ ${SANDBOX_INTRACTV} == "1" && -t 1 ]] || [[ ${__SANDBOX_TESTING} == "yes"
sbs_tmpenvfile=${sbs_pdir}${sbs_bdir}/temp/environment
if [[ -e ${sbs_tmpenvfile} ]] ; then
echo "Found environment at ${sbs_tmpenvfile}"
- printf " * Would you like to enter the portage environment ? "
+ printf " * Would you like to enter the portage environment (y/N) ? "
read env
sbs_PREPWD=${PWD}
if [[ ${env} == "y" ]] ; then
@@ -80,7 +79,11 @@ if [[ ${SANDBOX_INTRACTV} == "1" && -t 1 ]] || [[ ${__SANDBOX_TESTING} == "yes"
-e '/^[[:alnum:]_-]* ()/Q' "${sbs_tmpenvfile}") 2>/dev/null
# Then grab everything (including functions)
source "${sbs_tmpenvfile}" 2> /dev/null
- export SANDBOX_WRITE=${SANDBOX_WRITE}:${sbs_pdir}${sbs_bdir}:${sbs_pdir}/homedir
+ # Some variables portage does not write out to th environment.
+ : "${T:=${sbs_tmpenvfile%/*}}"
+ HOME=${sbs_pdir}/homedir
+ SANDBOX_WRITE+=:${sbs_pdir}${sbs_bdir}:${HOME}
+ export T HOME SANDBOX_WRITE
fi
PWD=${sbs_PREPWD}
fi
@@ -103,7 +106,7 @@ if [[ ${SANDBOX_INTRACTV} == "1" && -t 1 ]] || [[ ${__SANDBOX_TESTING} == "yes"
sandboxon() { export SANDBOX_ON="1" ; }
sandboxoff() { export SANDBOX_ON="0" ; }
- [[ -z ${CCACHE_DIR} ]] && [[ -w /root/.ccache ]] && export CCACHE_DIR=/root/.ccache
+ [[ -z ${CCACHE_DIR} ]] && [[ -w $HOME/.ccache ]] && export CCACHE_DIR=$HOME/.ccache
for var in CCACHE_DIR DISTCC_DIR ; do
[[ ${!var+set} == "set" ]] && addwrite ${!var}
done
diff --git a/etc/sandbox.conf b/etc/sandbox.conf
index 5f09ee4..d8a6550 100644
--- a/etc/sandbox.conf
+++ b/etc/sandbox.conf
@@ -27,6 +27,17 @@
# Determine the use of color in the output. Default is "false" (ie, use color)
#NOCOLOR="false"
+# SANDBOX_METHOD
+#
+# Control how processes are monitored. See the README for system requirements
+# for each setting, as well as particular limitations. Changing this setting
+# is not recommended.
+#
+# Possible values:
+# any: (default) Use any method of tracing available on the system.
+# preload: Only use in-process LD_PRELOAD symbol interposing.
+#SANDBOX_METHOD="any"
+
#
# Namespace Section (Linux-only)
@@ -39,11 +50,13 @@
# particular type, it will be automatically skipped. Default to off as these
# are currently experimental.
# For more details on each type, see the namespaces(7) manpage.
+#NAMESPACE_CGROUP_ENABLE="no"
#NAMESPACE_IPC_ENABLE="no"
#NAMESPACE_MNT_ENABLE="no"
#NAMESPACE_NET_ENABLE="no"
#NAMESPACE_PID_ENABLE="no"
#NAMESPACE_SYSV_ENABLE="no"
+#NAMESPACE_TIME_ENABLE="no"
#NAMESPACE_USER_ENABLE="no"
#NAMESPACE_UTS_ENABLE="no"
@@ -86,7 +99,7 @@ SANDBOX_WRITE="/dev/console:/dev/tty:/dev/vc/:/dev/pty:/dev/tts"
# Device filesystems
SANDBOX_WRITE="/dev/ptmx:/dev/pts/:/dev/shm"
# Tempory storage
-SANDBOX_WRITE="/tmp/:/var/tmp/"
+SANDBOX_WRITE="/tmp/:/var/tmp/:/usr/tmp/"
# Needed for shells
SANDBOX_WRITE="${HOME}/.bash_history"
diff --git a/headers.h b/headers.h
index 13e005a..396002f 100644
--- a/headers.h
+++ b/headers.h
@@ -113,6 +113,9 @@
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
+#ifdef HAVE_SYS_PRCTL_H
+# include <sys/prctl.h>
+#endif
#ifdef HAVE_SYS_PTRACE_H
# include <sys/ptrace.h>
#endif
@@ -143,6 +146,9 @@
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
+#ifdef HAVE_SYS_XATTR_H
+# include <sys/xattr.h>
+#endif
#ifdef __ia64__ /* what a pos */
# define ia64_fpreg FU_ia64_fpreg
diff --git a/libsandbox/Makefile b/libsandbox/Makefile
new file mode 100644
index 0000000..2db82ff
--- /dev/null
+++ b/libsandbox/Makefile
@@ -0,0 +1,4 @@
+# Helper for developers.
+all libsandbox libsandbox.la: libsandbox/libsandbox.la ;
+clean: ; rm -f *.o *.l[ao] .libs/*
+%: ; $(MAKE) -C .. $@
diff --git a/libsandbox/Makefile.am b/libsandbox/Makefile.am
deleted file mode 100644
index ac9a548..0000000
--- a/libsandbox/Makefile.am
+++ /dev/null
@@ -1,93 +0,0 @@
-AUTOMAKE_OPTIONS = foreign
-
-lib_LTLIBRARIES = libsandbox.la
-
-AM_CPPFLAGS = \
- -I$(top_srcdir) \
- -I$(top_srcdir)/libsbutil \
- -I$(top_srcdir)/libsbutil/include \
- $(SANDBOX_DEFINES)
-
-libsandbox_la_CFLAGS = $(CFLAG_EXCEPTIONS)
-# Could use the following to libsandbox_la_LIBADD, but then libtool links it
-# with --whole-archive, and libsandbox.so increase with a few KB in size:
-# $(top_builddir)/libsbutil/libsbutil.la
-libsandbox_la_LIBSBLIB = $(top_builddir)/libsbutil/.libs/libsbutil.a
-libsandbox_la_LIBADD = \
- -lc $(LIBDL) \
- $(libsandbox_la_LIBSBLIB)
-# Do not add -nostdlib or -nostartfiles, as then our constructor
-# and destructor will not be executed ...
-libsandbox_la_LDFLAGS = \
- -no-undefined \
- -avoid-version \
- $(LDFLAG_VER),libsandbox.map
-libsandbox_la_SOURCES = \
- libsandbox.h \
- libsandbox.c \
- lock.c \
- memory.c \
- trace.c \
- wrappers.h \
- wrappers.c \
- canonicalize.c
-
-install-exec-hook:
- rm -f $(DESTDIR)$(libdir)/libsandbox.la
-# Since we removed the .la file, libtool uninstall doesn't work,
-# so we have to manually uninstall libsandbox.so ourselves.
-uninstall-hook:
- rm -f $(DESTDIR)$(libdir)/libsandbox.so
-
-libsandbox.c: libsandbox.map sb_nr.h
-trace.c: trace_syscalls.h sb_nr.h $(TRACE_FILES)
-wrappers.c: symbols.h
-
-TRACE_FILES = $(wildcard $(srcdir)/trace/*.[ch] $(srcdir)/trace/*/*.[ch])
-
-SCRIPT_DIR = $(top_srcdir)/scripts
-
-SYMBOLS_FILE = $(srcdir)/symbols.h.in
-SYMBOLS_LIST = $(shell $(SED) -n '/^[^\#]/p' $(SYMBOLS_FILE))
-SYMBOLS_WRAPPERS = $(wildcard $(srcdir)/wrapper-funcs/*.[ch])
-GEN_VERSION_MAP_SCRIPT = $(SCRIPT_DIR)/gen_symbol_version_map.awk
-GEN_HEADER_SCRIPT = $(SCRIPT_DIR)/gen_symbol_header.awk
-GEN_TRACE_SCRIPT = $(SCRIPT_DIR)/gen_trace_header.awk
-SB_AWK = LC_ALL=C $(AWK) -v SYMBOLS_LIST="$(SYMBOLS_LIST)" -v srcdir="$(srcdir)" -f
-
-libsandbox.map: $(SYMBOLS_FILE) $(GEN_VERSION_MAP_SCRIPT)
- $(AM_V_GEN)$(READELF) -s $(LIBC_PATH) | $(SB_AWK) $(GEN_VERSION_MAP_SCRIPT) > $@
-
-symbols.h: $(SYMBOLS_FILE) $(GEN_HEADER_SCRIPT)
- $(AM_V_GEN)$(READELF) -s $(LIBC_PATH) | $(SB_AWK) $(GEN_HEADER_SCRIPT) > $@
-
-SB_NR_FILE = $(srcdir)/sb_nr.h.in
-sb_nr.h: symbols.h $(SB_NR_FILE)
- $(AM_V_GEN)$(EGREP) -h '^\#define SB_' $^ > $@
-
-TRACE_MAKE_HEADER = \
- $(SB_AWK) $(GEN_TRACE_SCRIPT) -v MODE=gen | \
- $(COMPILE) -E -P -include $(top_srcdir)/headers.h - $$f | \
- $(SB_AWK) $(GEN_TRACE_SCRIPT) -v syscall_prefix=$$t > $$header
-trace_syscalls.h: $(GEN_TRACE_SCRIPT) $(SB_SCHIZO_HEADERS)
-if SB_SCHIZO
- $(AM_V_GEN)touch $@
-else
- $(AM_V_GEN)t= f= header=$@; $(TRACE_MAKE_HEADER)
-endif
-
-$(SB_SCHIZO_HEADERS): $(GEN_TRACE_SCRIPT)
- $(AM_V_GEN)for pers in $(SB_SCHIZO_SETTINGS) ; do \
- t=_$${pers%:*}; \
- f=$${pers#*:}; \
- header="trace_syscalls$${t}.h"; \
- if [ "$$header" = "$@" ]; then \
- $(TRACE_MAKE_HEADER) || exit $$?; \
- break; \
- fi; \
- done
-
-EXTRA_DIST = $(SYMBOLS_FILE) $(SYMBOLS_WRAPPERS) $(SB_NR_FILE) $(TRACE_FILES) headers.h
-
-CLEANFILES = libsandbox.map sb_nr.h symbols.h trace_syscalls*.h
-DISTCLEANFILES = $(CLEANFILES)
diff --git a/libsandbox/canonicalize.c b/libsandbox/canonicalize.c
index 6519340..f8d32f0 100644
--- a/libsandbox/canonicalize.c
+++ b/libsandbox/canonicalize.c
@@ -49,7 +49,6 @@ erealpath(const char *name, char *resolved)
{
char *rpath, *dest, *recover;
const char *start, *end, *rpath_limit;
- long int path_max;
if (name == NULL) {
/* As per Single Unix Specification V2 we must return an error if
@@ -66,16 +65,9 @@ erealpath(const char *name, char *resolved)
__set_errno(ENOENT);
return NULL;
}
-#ifdef SB_PATH_MAX
- path_max = SB_PATH_MAX;
-#else
- path_max = pathconf(name, _PC_PATH_MAX);
- if (path_max <= 0)
- path_max = 1024;
-#endif
if (resolved == NULL) {
- rpath = xmalloc(path_max);
+ rpath = xmalloc(SB_PATH_MAX);
} else {
/* We can't handle resolving a buffer inline, so demand
* separate read and write strings.
@@ -83,16 +75,16 @@ erealpath(const char *name, char *resolved)
sb_assert(name != resolved);
rpath = resolved;
}
- rpath_limit = rpath + path_max;
+ rpath_limit = rpath + SB_PATH_MAX;
recover = NULL;
if (name[0] != '/') {
- if (!egetcwd(rpath, path_max)) {
+ if (!egetcwd(rpath, SB_PATH_MAX)) {
rpath[0] = '\0';
goto error;
}
- /* This stat() business uses relative paths atm */
+ /* This stat business uses relative paths atm. */
if (trace_pid)
goto no_recover;
@@ -100,26 +92,28 @@ erealpath(const char *name, char *resolved)
* If not, try a little harder to consume this path in
* case it has symlinks out into a better world ...
*/
- struct stat st;
- if (lstat(rpath, &st) == -1 && errno == EACCES) {
+ struct stat64 st;
+ if (lstat64(rpath, &st) == -1 && errno == EACCES) {
char *p = rpath;
strcpy(rpath, name);
do {
p = strchr(p, '/');
if (p) *p = '\0';
- if (lstat(rpath, &st))
+ if (lstat64(rpath, &st))
break;
if (S_ISLNK(st.st_mode)) {
- ssize_t cnt = readlink(rpath, rpath, path_max);
+ char buffer[SB_PATH_MAX];
+ ssize_t cnt = readlink(rpath, buffer, SB_PATH_MAX - 1);
if (cnt == -1)
break;
- rpath[cnt] = '\0';
+ buffer[cnt] = '\0';
+ strcpy(rpath, buffer);
if (p) {
size_t bytes_left = strlen(p);
- if (bytes_left >= path_max)
+ if (bytes_left >= SB_PATH_MAX)
break;
strncat(rpath, name + (p - rpath + 1),
- path_max - bytes_left - 1);
+ SB_PATH_MAX - bytes_left - 1);
}
/* Ok, we have a chance at something better. If
@@ -187,10 +181,10 @@ erealpath(const char *name, char *resolved)
goto error;
}
new_size = rpath_limit - rpath;
- if (end - start + 1 > path_max)
+ if (end - start + 1 > SB_PATH_MAX)
new_size += end - start + 1;
else
- new_size += path_max;
+ new_size += SB_PATH_MAX;
new_rpath = (char *) xrealloc(rpath, new_size);
rpath = new_rpath;
rpath_limit = rpath + new_size;
@@ -213,7 +207,7 @@ erealpath(const char *name, char *resolved)
error:
if (resolved)
- snprintf(resolved, path_max, "%s", rpath);
+ snprintf(resolved, SB_PATH_MAX, "%s", rpath);
else
free(rpath);
free(recover);
diff --git a/libsandbox/headers.h b/libsandbox/headers.h
deleted file mode 100644
index 7fcc3b2..0000000
--- a/libsandbox/headers.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../headers.h"
diff --git a/libsandbox/libsandbox.c b/libsandbox/libsandbox.c
index 77e9959..acd8585 100644
--- a/libsandbox/libsandbox.c
+++ b/libsandbox/libsandbox.c
@@ -29,6 +29,7 @@ char sandbox_lib[SB_PATH_MAX];
typedef struct {
bool show_access_violation, on, active, testing, verbose, debug;
+ sandbox_method_t method;
char *ld_library_path;
char **prefixes[5];
int num_prefixes[5];
@@ -53,6 +54,7 @@ static char message_path[SB_PATH_MAX];
bool sandbox_on = true;
static bool sb_init = false;
static bool sb_env_init = false;
+int (*sbio_faccessat)(int, const char *, int, int) = sb_unwrapped_faccessat;
int (*sbio_open)(const char *, int, mode_t) = sb_unwrapped_open;
FILE *(*sbio_popen)(const char *, const char *) = sb_unwrapped_popen;
@@ -94,6 +96,7 @@ void libsb_init(void)
sbcontext.verbose = is_env_on(ENV_SANDBOX_VERBOSE);
sbcontext.debug = is_env_on(ENV_SANDBOX_DEBUG);
sbcontext.testing = is_env_on(ENV_SANDBOX_TESTING);
+ sbcontext.method = get_sandbox_method();
if (sbcontext.testing) {
const char *ldpath = getenv("LD_LIBRARY_PATH");
if (ldpath)
@@ -101,6 +104,11 @@ void libsb_init(void)
}
}
+sandbox_method_t get_sandbox_method(void)
+{
+ return parse_sandbox_method(getenv(ENV_SANDBOX_METHOD));
+}
+
/* resolve_dirfd_path - get the path relative to a dirfd
*
* return value:
@@ -124,26 +132,31 @@ int resolve_dirfd_path(int dirfd, const char *path, char *resolved_path,
save_errno();
+ char *fd_path = xmalloc(SB_PATH_MAX * sizeof(char));
+
size_t at_len = resolved_path_len - 1 - 1 - (path ? strlen(path) : 0);
- if (trace_pid)
- sprintf(resolved_path, "/proc/%i/fd/%i", trace_pid, dirfd);
- else
- /* If /proc was mounted by a process in a different pid namespace,
- * getpid cannot be used to create a valid /proc/<pid> path. Instead
- * use sb_get_fd_dir() which works in any case.
- */
- sprintf(resolved_path, "%s/%i", sb_get_fd_dir(), dirfd);
- ssize_t ret = readlink(resolved_path, resolved_path, at_len);
+ if (trace_pid) {
+ sprintf(fd_path, "/proc/%i/fd/%i", trace_pid, dirfd);
+ } else {
+ /* If /proc was mounted by a process in a different pid namespace,
+ * getpid cannot be used to create a valid /proc/<pid> path. Instead
+ * use sb_get_fd_dir() which works in any case.
+ */
+ sprintf(fd_path, "%s/%i", sb_get_fd_dir(), dirfd);
+ }
+ ssize_t ret = readlink(fd_path, resolved_path, at_len);
if (ret == -1) {
/* see comments at end of check_syscall() */
if (errno_is_too_long()) {
restore_errno();
+ free(fd_path);
return 2;
}
- sb_debug_dyn("AT_FD LOOKUP fail: %s: %s\n", resolved_path, strerror(errno));
+ sb_debug_dyn("AT_FD LOOKUP fail: %s: %s\n", fd_path, strerror(errno));
/* If the fd isn't found, some guys (glibc) expect errno */
if (errno == ENOENT)
errno = EBADF;
+ free(fd_path);
return -1;
}
resolved_path[ret] = '/';
@@ -152,6 +165,7 @@ int resolve_dirfd_path(int dirfd, const char *path, char *resolved_path,
strcat(resolved_path, path);
restore_errno();
+ free(fd_path);
return 0;
}
@@ -276,7 +290,7 @@ static char *resolve_path(const char *path, int follow_link)
}
if (!ret) {
- char tmp_str1[SB_PATH_MAX];
+ char *tmp_str1 = xmalloc(SB_PATH_MAX * sizeof(char));
snprintf(tmp_str1, SB_PATH_MAX, "%s", path);
dname = dirname(tmp_str1);
@@ -294,7 +308,7 @@ static char *resolve_path(const char *path, int follow_link)
filtered_path = NULL;
}
} else {
- char tmp_str2[SB_PATH_MAX];
+ char *tmp_str2 = xmalloc(SB_PATH_MAX * sizeof(char));
/* OK, now add the basename to keep our access
* checking happy (don't want '/usr/lib' if we
* tried to do something with non-existing
@@ -306,7 +320,10 @@ static char *resolve_path(const char *path, int follow_link)
snprintf(filtered_path + len, SB_PATH_MAX - len, "%s%s",
(filtered_path[len - 1] != '/') ? "/" : "",
bname);
+ free(tmp_str2);
}
+
+ free(tmp_str1);
}
}
@@ -325,7 +342,7 @@ static char *resolve_path(const char *path, int follow_link)
char *egetcwd(char *buf, size_t size)
{
- struct stat st;
+ struct stat64 st;
char *tmpbuf;
/* We can't let the C lib allocate memory for us since we have our
@@ -339,14 +356,14 @@ char *egetcwd(char *buf, size_t size)
/* If tracing a child, our cwd may not be the same as the child's */
if (trace_pid) {
- char proc[20];
- sprintf(proc, "/proc/%i/cwd", trace_pid);
- ssize_t ret = readlink(proc, buf, size);
- if (ret == -1) {
+ char proc[22];
+ snprintf(proc, sizeof(proc), "/proc/%i/cwd", trace_pid);
+ ssize_t link_len = readlink(proc, buf, size - 1);
+ if (link_len == -1) {
errno = ESRCH;
return NULL;
}
- buf[ret] = '\0';
+ buf[link_len] = '\0';
return buf;
}
@@ -368,12 +385,12 @@ char *egetcwd(char *buf, size_t size)
*/
if ((tmpbuf) && (errno == 0)) {
save_errno();
- if (!lstat(buf, &st))
+ if (!lstat64(buf, &st))
/* errno is set only on failure */
errno = 0;
if (errno == ENOENT)
- /* If lstat() failed with eerror = ENOENT, then its
+ /* If lstat failed with eerror = ENOENT, then its
* possible that we are running on an older kernel
* which had issues with returning invalid paths if
* they got too long. Return with errno = ENAMETOOLONG,
@@ -388,8 +405,8 @@ char *egetcwd(char *buf, size_t size)
free(buf);
/* Not sure if we should quit here, but I guess if
- * lstat() fails, getcwd could have messed up. Not
- * sure what to do about errno - use lstat()'s for
+ * lstat fails, getcwd could have messed up. Not
+ * sure what to do about errno - use lstat's for
* now.
*/
return NULL;
@@ -427,12 +444,12 @@ void __sb_dump_backtrace(void)
static bool write_logfile(const char *logfile, const char *func, const char *path,
const char *apath, const char *rpath, bool access)
{
- struct stat log_stat;
+ struct stat64 log_stat;
int stat_ret;
int logfd;
bool ret = false;
- stat_ret = lstat(logfile, &log_stat);
+ stat_ret = lstat64(logfile, &log_stat);
/* Do not care about failure */
errno = 0;
if (stat_ret == 0 && S_ISREG(log_stat.st_mode) == 0)
@@ -663,33 +680,32 @@ static int check_prefixes(char **prefixes, int num_prefixes, const char *path)
}
/* Is this a func that works on symlinks, and is the file a symlink ? */
-static bool symlink_func(int sb_nr, int flags, const char *abs_path)
+static bool symlink_func(int sb_nr, int flags)
{
- struct stat st;
-
/* These funcs always operate on symlinks */
- if (!(sb_nr == SB_NR_UNLINK ||
- sb_nr == SB_NR_UNLINKAT ||
- sb_nr == SB_NR_LCHOWN ||
- sb_nr == SB_NR_REMOVE ||
- sb_nr == SB_NR_RENAME ||
- sb_nr == SB_NR_RENAMEAT ||
- sb_nr == SB_NR_RMDIR ||
- sb_nr == SB_NR_SYMLINK ||
- sb_nr == SB_NR_SYMLINKAT))
- {
- /* These funcs sometimes operate on symlinks */
- if (!((sb_nr == SB_NR_FCHOWNAT ||
- sb_nr == SB_NR_FCHMODAT ||
- sb_nr == SB_NR_UTIMENSAT) &&
- (flags & AT_SYMLINK_NOFOLLOW)))
- return false;
- }
+ if (sb_nr == SB_NR_UNLINK ||
+ sb_nr == SB_NR_UNLINKAT ||
+ sb_nr == SB_NR_LCHOWN ||
+ sb_nr == SB_NR_LREMOVEXATTR ||
+ sb_nr == SB_NR_LSETXATTR ||
+ sb_nr == SB_NR_LUTIMES ||
+ sb_nr == SB_NR_REMOVE ||
+ sb_nr == SB_NR_RENAME ||
+ sb_nr == SB_NR_RENAMEAT ||
+ sb_nr == SB_NR_RENAMEAT2 ||
+ sb_nr == SB_NR_RMDIR ||
+ sb_nr == SB_NR_SYMLINK ||
+ sb_nr == SB_NR_SYMLINKAT)
+ return true;
- if (-1 != lstat(abs_path, &st) && S_ISLNK(st.st_mode))
+ /* These funcs sometimes operate on symlinks */
+ if ((sb_nr == SB_NR_FCHOWNAT ||
+ sb_nr == SB_NR_FCHMODAT ||
+ sb_nr == SB_NR_UTIMENSAT) &&
+ (flags & AT_SYMLINK_NOFOLLOW))
return true;
- else
- return false;
+
+ return false;
}
static int check_access(sbcontext_t *sbcontext, int sb_nr, const char *func,
@@ -698,7 +714,7 @@ static int check_access(sbcontext_t *sbcontext, int sb_nr, const char *func,
int old_errno = errno;
int result = 0;
int retval;
- bool sym_func = symlink_func(sb_nr, flags, abs_path);
+ bool sym_func = symlink_func(sb_nr, flags);
retval = check_prefixes(sbcontext->deny_prefixes,
sbcontext->num_deny_prefixes, abs_path);
@@ -706,6 +722,12 @@ static int check_access(sbcontext_t *sbcontext, int sb_nr, const char *func,
/* Fall in a read/write denied path, Deny Access */
goto out;
+ if (!strncmp(resolv_path, "/memfd:", strlen("/memfd:"))) {
+ /* Allow operations on memfd objects #910561 */
+ result = 1;
+ goto out;
+ }
+
if (!sym_func) {
retval = check_prefixes(sbcontext->deny_prefixes,
sbcontext->num_deny_prefixes, resolv_path);
@@ -714,15 +736,6 @@ static int check_access(sbcontext_t *sbcontext, int sb_nr, const char *func,
goto out;
}
- /* Hardcode denying write to the whole log dir. While this is a
- * parial match and so rejects paths that also start with this
- * string, that isn't going to happen in real life so live with
- * it. We can't append a slash to this path either as that would
- * allow people to open the dir itself for writing.
- */
- if (!strncmp(resolv_path, SANDBOX_LOG_LOCATION, strlen(SANDBOX_LOG_LOCATION)))
- goto out;
-
if (sbcontext->read_prefixes &&
(sb_nr == SB_NR_ACCESS_RD ||
sb_nr == SB_NR_OPEN_RD ||
@@ -754,12 +767,23 @@ static int check_access(sbcontext_t *sbcontext, int sb_nr, const char *func,
}
}
+ /* Hardcode denying write to the whole log dir. While this is a
+ * parial match and so rejects paths that also start with this
+ * string, that isn't going to happen in real life so live with
+ * it. We can't append a slash to this path either as that would
+ * allow people to open the dir itself for writing.
+ */
+ if (!strncmp(resolv_path, SANDBOX_LOG_LOCATION, strlen(SANDBOX_LOG_LOCATION)))
+ goto out;
+
if (sb_nr == SB_NR_ACCESS_WR ||
sb_nr == SB_NR_CHMOD ||
sb_nr == SB_NR_CHOWN ||
sb_nr == SB_NR_CREAT ||
sb_nr == SB_NR_CREAT64 ||
+ sb_nr == SB_NR_FCHMOD ||
sb_nr == SB_NR_FCHMODAT ||
+ sb_nr == SB_NR_FCHOWN ||
sb_nr == SB_NR_FCHOWNAT ||
/*sb_nr == SB_NR_FTRUNCATE ||
sb_nr == SB_NR_FTRUNCATE64 ||*/
@@ -767,6 +791,8 @@ static int check_access(sbcontext_t *sbcontext, int sb_nr, const char *func,
sb_nr == SB_NR_LCHOWN ||
sb_nr == SB_NR_LINK ||
sb_nr == SB_NR_LINKAT ||
+ sb_nr == SB_NR_LREMOVEXATTR||
+ sb_nr == SB_NR_LSETXATTR ||
sb_nr == SB_NR_LUTIMES ||
sb_nr == SB_NR_MKDIR ||
sb_nr == SB_NR_MKDIRAT ||
@@ -785,9 +811,12 @@ static int check_access(sbcontext_t *sbcontext, int sb_nr, const char *func,
sb_nr == SB_NR_MKSTEMPS64 ||
sb_nr == SB_NR_OPEN_WR ||
sb_nr == SB_NR_REMOVE ||
+ sb_nr == SB_NR_REMOVEXATTR ||
sb_nr == SB_NR_RENAME ||
sb_nr == SB_NR_RENAMEAT ||
+ sb_nr == SB_NR_RENAMEAT2 ||
sb_nr == SB_NR_RMDIR ||
+ sb_nr == SB_NR_SETXATTR ||
sb_nr == SB_NR_SYMLINK ||
sb_nr == SB_NR_SYMLINKAT ||
sb_nr == SB_NR_TRUNCATE ||
@@ -852,20 +881,6 @@ static int check_access(sbcontext_t *sbcontext, int sb_nr, const char *func,
goto out;
}
- /* A very common bug (apparently) is for .py[co] files to fall out
- * of sync with their .py source files. Rather than trigger a hard
- * failure, let's just whine about it. Once python itself gets
- * sorted out, we can drop this #256953.
- */
- size_t len = strlen(resolv_path);
- if (len > 4) {
- const char *py = resolv_path + len - 4;
- if (!strcmp(py, ".pyc") || !strcmp(py, ".pyo")) {
- sbcontext->show_access_violation = false;
- goto out;
- }
- }
-
/* If we are here, and still no joy, and its the access() call,
* do not log it, but just return -1 */
if (sb_nr == SB_NR_ACCESS_WR) {
@@ -895,11 +910,14 @@ static int check_syscall(sbcontext_t *sbcontext, int sb_nr, const char *func,
bool access, debug, verbose, set;
absolute_path = resolve_path(file, 0);
+ if (!absolute_path)
+ goto error;
+
/* Do not bother dereferencing symlinks when we are using a function that
* itself does not dereference. This speeds things up and avoids updating
* the atime implicitly. #415475
*/
- if (symlink_func(sb_nr, flags, absolute_path))
+ if (symlink_func(sb_nr, flags))
resolved_path = absolute_path;
else
resolved_path = resolve_path(file, 1);
@@ -970,9 +988,24 @@ static int check_syscall(sbcontext_t *sbcontext, int sb_nr, const char *func,
if (trace_pid && errno == ESRCH)
return 2;
+ /* Underlying directory we operate on went away: #590084 */
+ if (!absolute_path && !resolved_path && errno == ENOENT) {
+ int sym_len = SB_MAX_STRING_LEN + 1 - strlen(func);
+ if (sbcontext->show_access_violation)
+ sb_eerror("%sACCESS DENIED%s: %s:%*s'%s' (from deleted directory, see https://bugs.gentoo.org/590084)\n",
+ COLOR_RED, COLOR_NORMAL, func, sym_len, "", file);
+ return 0;
+ }
+
/* If we get here, something bad happened */
- sb_ebort("ISE: %s(%s)\n\tabs_path: %s\n\tres_path: %s\n",
- func, file, absolute_path, resolved_path);
+ sb_ebort("ISE: %s('%s')\n"
+ "\tabs_path: %s\n"
+ "\tres_path: %s\n"
+ "\terrno=%i: %s\n",
+ func, file,
+ absolute_path,
+ resolved_path,
+ errno, strerror(errno));
}
bool is_sandbox_on(void)
@@ -1008,10 +1041,24 @@ bool is_sandbox_on(void)
return result;
}
+static int resolve_dirfd_path_alloc(int dirfd, const char *path, char **resolved_path)
+{
+ size_t resolved_path_size = SB_PATH_MAX * sizeof(char);
+ *resolved_path = xmalloc(resolved_path_size);
+ int result = resolve_dirfd_path(dirfd, path, *resolved_path, resolved_path_size);
+
+ if (result) {
+ free(*resolved_path);
+ *resolved_path = NULL;
+ }
+
+ return result;
+}
+
bool before_syscall(int dirfd, int sb_nr, const char *func, const char *file, int flags)
{
int result;
- char at_file_buf[SB_PATH_MAX];
+ char *at_file_buf;
/* Some funcs operate on a fd directly and so filename is NULL, but
* the rest should get rejected as "file/directory does not exist".
@@ -1030,7 +1077,7 @@ bool before_syscall(int dirfd, int sb_nr, const char *func, const char *file, in
}
}
- switch (resolve_dirfd_path(dirfd, file, at_file_buf, sizeof(at_file_buf))) {
+ switch (resolve_dirfd_path_alloc(dirfd, file, &at_file_buf)) {
case -1: return false;
case 0: file = at_file_buf; break;
case 2: return true;
@@ -1053,6 +1100,9 @@ bool before_syscall(int dirfd, int sb_nr, const char *func, const char *file, in
result = check_syscall(&sbcontext, sb_nr, func, file, flags);
+ if (at_file_buf)
+ free(at_file_buf);
+
sb_unlock();
if (0 == result) {
@@ -1071,8 +1121,11 @@ bool before_syscall_access(int dirfd, int sb_nr, const char *func, const char *f
const char *ext_func;
if (flags & W_OK)
sb_nr = SB_NR_ACCESS_WR, ext_func = "access_wr";
- else
+ else if (flags & R_OK)
sb_nr = SB_NR_ACCESS_RD, ext_func = "access_rd";
+ else
+ /* Must be F_OK or X_OK; we do not need to check either. */
+ return true;
return before_syscall(dirfd, sb_nr, ext_func, file, flags);
}
@@ -1086,6 +1139,21 @@ bool before_syscall_open_int(int dirfd, int sb_nr, const char *func, const char
return before_syscall(dirfd, sb_nr, ext_func, file, flags);
}
+bool before_syscall_fd(int sb_nr, const char *func, int fd) {
+#ifdef SANDBOX_PROC_SELF_FD
+ /* We only know how to handle e.g. fchmod() and fchown() on
+ * linux, where it's possible to (eventually) get a path out
+ * of the given file descriptor. The "64" below accounts for
+ * the length of an integer string, and is probably
+ * overkill. */
+ char path[sizeof("/proc/self/fd/") + 64];
+ snprintf(path, sizeof("/proc/self/fd/") + 64, "/proc/self/fd/%i", fd);
+ return before_syscall(AT_FDCWD, sb_nr, func, path, 0);
+#else
+ return true;
+#endif
+}
+
bool before_syscall_open_char(int dirfd, int sb_nr, const char *func, const char *file, const char *mode)
{
if (NULL == mode)
@@ -1104,7 +1172,7 @@ bool before_syscall_open_char(int dirfd, int sb_nr, const char *func, const char
typedef struct {
const char *name;
size_t len;
- char *value;
+ const char *value;
} env_pair;
#define ENV_PAIR(x, n, v) [x] = { .name = n, .len = sizeof(n) - 1, .value = v, }
@@ -1152,6 +1220,7 @@ struct sb_envp_ctx sb_new_envp(char **envp, bool insert)
ENV_PAIR(11, ENV_SANDBOX_DEBUG, NULL),
ENV_PAIR(12, "LD_LIBRARY_PATH", NULL),
ENV_PAIR(13, ENV_SANDBOX_TESTING, NULL),
+ ENV_PAIR(14, ENV_SANDBOX_METHOD, NULL),
};
size_t num_vars = ARRAY_SIZE(vars);
char *found_vars[num_vars];
@@ -1166,6 +1235,7 @@ struct sb_envp_ctx sb_new_envp(char **envp, bool insert)
found_var_cnt = 0;
memset(found_vars, 0, sizeof(found_vars));
+ /* Iterate through user's environment and check against expected. */
str_list_for_each_item(envp, entry, count) {
for (i = 0; i < num_vars; ++i) {
if (found_vars[i])
@@ -1177,6 +1247,14 @@ struct sb_envp_ctx sb_new_envp(char **envp, bool insert)
}
}
+ /* Treat unset and expected-unset variables as found. This will allow us
+ * to keep existing environment. */
+ for (i = 0; i < num_vars; ++i) {
+ if (vars[i].value == NULL && found_vars[i] == NULL) {
+ ++found_var_cnt;
+ }
+ }
+
/* Now specially handle merging of LD_PRELOAD */
char *ld_preload;
bool merge_ld_preload = found_vars[0] && !strstr(found_vars[0], sandbox_lib);
@@ -1215,6 +1293,8 @@ struct sb_envp_ctx sb_new_envp(char **envp, bool insert)
vars[12].value = sbcontext.ld_library_path;
vars[13].value = "1";
}
+ if (sbcontext.method != SANDBOX_METHOD_ANY)
+ vars[14].value = str_sandbox_method(sbcontext.method);
char ** my_env = NULL;
if (!insert) {
diff --git a/libsandbox/libsandbox.h b/libsandbox/libsandbox.h
index 70fc422..01a4c6c 100644
--- a/libsandbox/libsandbox.h
+++ b/libsandbox/libsandbox.h
@@ -46,11 +46,23 @@
#define SB_SAFE_OPEN_CHAR(_path, _mode) \
SB_SAFE_OPEN_CHAR_AT(AT_FDCWD, _path, _mode)
+#define _SB_SAFE_FD(_nr, _name, _fd) \
+ __SB_SAFE(before_syscall_fd(_nr, _name, fd))
+#define SB_SAFE_FD(_fd) \
+ _SB_SAFE_FD(WRAPPER_NR, STRING_NAME, _fd)
+
+/* Symbols that don't exist in the C library will be <= this value. */
+#define SB_NR_UNDEF -99999
+#define SB_NR_IS_DEFINED(nr) (nr > SB_NR_UNDEF)
+
bool is_sandbox_on(void);
bool before_syscall(int, int, const char *, const char *, int);
bool before_syscall_access(int, int, const char *, const char *, int);
bool before_syscall_open_int(int, int, const char *, const char *, int);
bool before_syscall_open_char(int, int, const char *, const char *, const char *);
+bool before_syscall_fd(int, const char *, int);
+
+enum sandbox_method_t get_sandbox_method(void);
void *get_dlsym(const char *symname, const char *symver);
@@ -77,7 +89,7 @@ extern void sb_lock(void);
extern void sb_unlock(void);
bool trace_possible(const char *filename, char *const argv[], const void *data);
-void trace_main(const char *filename, char *const argv[]);
+void trace_main(void);
/* glibc modified realpath() function */
char *erealpath(const char *, char *);
diff --git a/libsandbox/local.mk b/libsandbox/local.mk
new file mode 100644
index 0000000..dd78a76
--- /dev/null
+++ b/libsandbox/local.mk
@@ -0,0 +1,105 @@
+lib_LTLIBRARIES += %D%/libsandbox.la
+
+%C%_libsandbox_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I%D% \
+ -I$(top_srcdir)/%D% \
+ -I$(top_srcdir)/libsbutil \
+ -I$(top_srcdir)/libsbutil/include
+
+%C%_libsandbox_la_CFLAGS = $(CFLAG_EXCEPTIONS)
+# Could use the following to libsandbox_la_LIBADD, but then libtool links it
+# with --whole-archive, and libsandbox.so increase with a few KB in size:
+# libsbutil/libsbutil.la
+libsbutil/.libs/libsbutil.a: libsbutil/libsbutil.la
+%C%_libsandbox_la_LIBSBLIB = libsbutil/.libs/libsbutil.a
+%C%_libsandbox_la_LIBADD = \
+ -lc $(LIBDL) \
+ $(%C%_libsandbox_la_LIBSBLIB)
+# Do not add -nostdlib or -nostartfiles, as then our constructor
+# and destructor will not be executed ...
+%C%_libsandbox_la_LDFLAGS = \
+ -no-undefined \
+ -avoid-version \
+ $(LDFLAG_VER),%D%/libsandbox.map
+%C%_libsandbox_la_SOURCES = \
+ %D%/libsandbox.h \
+ %D%/libsandbox.c \
+ %D%/lock.c \
+ %D%/memory.c \
+ %D%/pre_check_at.c \
+ %D%/pre_check_mkdirat.c \
+ %D%/pre_check_openat64.c \
+ %D%/pre_check_openat.c \
+ %D%/pre_check_unlinkat.c \
+ %D%/trace.c \
+ %D%/wrappers.h \
+ %D%/wrappers.c \
+ %D%/canonicalize.c
+
+install-exec-hook:
+ rm -f $(DESTDIR)$(libdir)/libsandbox.la
+# Since we removed the .la file, libtool uninstall doesn't work,
+# so we have to manually uninstall libsandbox.so ourselves.
+uninstall-hook:
+ rm -f $(DESTDIR)$(libdir)/libsandbox.so
+
+%D%/libsandbox.c: %D%/libsandbox.map %D%/sb_nr.h
+%D%/trace.c: %D%/trace_syscalls.h %D%/sb_nr.h $(TRACE_FILES)
+%D%/wrappers.c: %D%/symbols.h
+
+TRACE_FILES = $(wildcard $(top_srcdir)/%D%/trace/*.[ch] $(top_srcdir)/%D%/trace/*/*.[ch])
+
+SCRIPT_DIR = $(top_srcdir)/scripts
+
+SYMBOLS_FILE = $(top_srcdir)/%D%/symbols.h.in
+SYMBOLS_WRAPPERS = $(wildcard $(top_srcdir)/%D%/wrapper-funcs/*.[ch])
+GEN_VERSION_MAP_SCRIPT = $(SCRIPT_DIR)/gen_symbol_version_map.awk
+GEN_HEADER_SCRIPT = $(SCRIPT_DIR)/gen_symbol_header.awk
+GEN_TRACE_SCRIPT = $(SCRIPT_DIR)/gen_trace_header.awk
+SB_AWK = LC_ALL=C $(AWK) -v SYMBOLS_FILE="$(SYMBOLS_FILE)" -v srcdir="$(top_srcdir)/%D%" -f
+
+%D%/libsandbox.map: $(SYMBOLS_FILE) $(GEN_VERSION_MAP_SCRIPT)
+ @$(MKDIR_P) %D%
+ $(AM_V_GEN)$(READELF) -sW $(LIBC_PATH) | $(SB_AWK) $(GEN_VERSION_MAP_SCRIPT) > $@
+
+%D%/symbols.h: $(SYMBOLS_FILE) $(GEN_HEADER_SCRIPT)
+ @$(MKDIR_P) %D%
+ $(AM_V_GEN)$(READELF) -sW $(LIBC_PATH) | $(SB_AWK) $(GEN_HEADER_SCRIPT) > $@
+
+SB_NR_FILE = %D%/sb_nr.h.in
+%D%/sb_nr.h: %D%/symbols.h $(SB_NR_FILE)
+ @$(MKDIR_P) %D%
+ $(AM_V_GEN)$(EGREP) -h '^\#define SB_' $^ > $@
+
+TRACE_MAKE_HEADER = \
+ $(SB_AWK) $(GEN_TRACE_SCRIPT) -v MODE=gen | \
+ $(COMPILE) -E -P -include $(top_srcdir)/headers.h - $$f | \
+ $(SB_AWK) $(GEN_TRACE_SCRIPT) -v syscall_prefix=$$t > $$header
+%D%/trace_syscalls.h: $(SYMBOLS_FILE) $(GEN_TRACE_SCRIPT) $(SB_PERSONALITIES_HEADERS)
+ @$(MKDIR_P) %D%
+if SB_PERSONALITIES
+ $(AM_V_GEN)touch $@
+else
+ $(AM_V_GEN)t= f= header=$@; $(TRACE_MAKE_HEADER)
+endif
+
+$(SB_PERSONALITIES_HEADERS): $(SYMBOLS_FILE) $(GEN_TRACE_SCRIPT)
+ @$(MKDIR_P) %D%
+ $(AM_V_GEN)for pers in $(SB_PERSONALITIES_SETTINGS) ; do \
+ t=_$${pers%:*}; \
+ f=$${pers#*:}; \
+ header="%D%/trace_syscalls$${t}.h"; \
+ if [ "$$header" = "$@" ]; then \
+ $(TRACE_MAKE_HEADER) || exit $$?; \
+ break; \
+ fi; \
+ done
+
+EXTRA_DIST += $(SYMBOLS_FILE) $(SYMBOLS_WRAPPERS) $(SB_NR_FILE) $(TRACE_FILES)
+
+CLEANFILES += \
+ %D%/libsandbox.map \
+ %D%/sb_nr.h \
+ %D%/symbols.h \
+ %D%/trace_syscalls*.h
diff --git a/libsandbox/wrapper-funcs/__pre_at_check.c b/libsandbox/pre_check_at.c
index f72c40c..be6e634 100644
--- a/libsandbox/wrapper-funcs/__pre_at_check.c
+++ b/libsandbox/pre_check_at.c
@@ -5,6 +5,11 @@
* Licensed under the GPL-2
*/
+#include "headers.h"
+#include "sbutil.h"
+#include "libsandbox.h"
+#include "wrappers.h"
+
/* We assume the parent has nested use with save/restore errno */
bool sb_common_at_pre_check(const char *func, const char **pathname, int dirfd,
char *dirfd_path, size_t dirfd_path_len)
diff --git a/libsandbox/wrapper-funcs/mkdirat_pre_check.c b/libsandbox/pre_check_mkdirat.c
index 0b48d1f..49c382a 100644
--- a/libsandbox/wrapper-funcs/mkdirat_pre_check.c
+++ b/libsandbox/pre_check_mkdirat.c
@@ -5,6 +5,11 @@
* Licensed under the GPL-2
*/
+#include "headers.h"
+#include "sbutil.h"
+#include "libsandbox.h"
+#include "wrappers.h"
+
bool sb_mkdirat_pre_check(const char *func, const char *pathname, int dirfd)
{
char canonic[SB_PATH_MAX];
@@ -31,8 +36,8 @@ bool sb_mkdirat_pre_check(const char *func, const char *pathname, int dirfd)
* not want to pass this attempt up to the higher levels as those
* will trigger a sandbox violation.
*/
- struct stat st;
- if (0 == lstat(canonic, &st)) {
+ struct stat64 st;
+ if (0 == lstat64(pathname, &st)) {
int new_errno;
sb_debug_dyn("EARLY FAIL: %s(%s[%s]) @ lstat: %s\n",
func, pathname, canonic, strerror(errno));
@@ -40,7 +45,7 @@ bool sb_mkdirat_pre_check(const char *func, const char *pathname, int dirfd)
new_errno = EEXIST;
/* Hmm, is this a broken symlink we're trying to extend ? */
- if (S_ISLNK(st.st_mode) && stat(pathname, &st) != 0) {
+ if (S_ISLNK(st.st_mode) && stat64(pathname, &st) != 0) {
/* XXX: This awful hack should probably be turned into a
* common func that does a better job. For now, we have
* enough crap to catch gnulib tests #297026.
diff --git a/libsandbox/pre_check_openat.c b/libsandbox/pre_check_openat.c
new file mode 100644
index 0000000..99c03eb
--- /dev/null
+++ b/libsandbox/pre_check_openat.c
@@ -0,0 +1,30 @@
+/*
+ * open*() pre-check.
+ *
+ * Copyright 1999-2012 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+#include "headers.h"
+#include "sbutil.h"
+#include "libsandbox.h"
+#include "wrappers.h"
+
+bool sb_openat_pre_check(const char *func, const char *pathname, int dirfd, int flags)
+{
+ /* If we're not trying to create, fail normally if file does not stat */
+ if (flags & O_CREAT)
+ return true;
+
+ save_errno();
+
+ /* Doesn't exist -> skip permission checks */
+ if (sb_exists(dirfd, pathname, (flags & O_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0) == -1) {
+ sb_debug_dyn("EARLY FAIL: %s(%s): %s\n", func, pathname, strerror(errno));
+ return false;
+ }
+
+ restore_errno();
+
+ return true;
+}
diff --git a/libsandbox/wrapper-funcs/openat64_pre_check.c b/libsandbox/pre_check_openat64.c
index 67dc0dc..d4dbe97 100644
--- a/libsandbox/wrapper-funcs/openat64_pre_check.c
+++ b/libsandbox/pre_check_openat64.c
@@ -5,8 +5,11 @@
* Licensed under the GPL-2
*/
-#include "__64_pre.h"
+#include "headers.h"
+#include "sbutil.h"
+#include "libsandbox.h"
+#include "wrappers.h"
+
#define sb_openat_pre_check sb_openat64_pre_check
-#include "openat_pre_check.c"
+#include "pre_check_openat.c"
#undef sb_openat_pre_check
-#include "__64_post.h"
diff --git a/libsandbox/wrapper-funcs/unlinkat_pre_check.c b/libsandbox/pre_check_unlinkat.c
index c004d15..93a0dd9 100644
--- a/libsandbox/wrapper-funcs/unlinkat_pre_check.c
+++ b/libsandbox/pre_check_unlinkat.c
@@ -5,6 +5,11 @@
* Licensed under the GPL-2
*/
+#include "headers.h"
+#include "sbutil.h"
+#include "libsandbox.h"
+#include "wrappers.h"
+
bool sb_unlinkat_pre_check(const char *func, const char *pathname, int dirfd)
{
char canonic[SB_PATH_MAX];
diff --git a/libsandbox/symbols.h.in b/libsandbox/symbols.h.in
index bdbce08..5805592 100644
--- a/libsandbox/symbols.h.in
+++ b/libsandbox/symbols.h.in
@@ -7,8 +7,10 @@
# before 'creat()' as 'creat()' uses 'open()' ...
chmod
+fchmod
fchmodat
chown
+fchown
fchownat
open
__open_2
@@ -34,6 +36,7 @@ faccessat
remove
rename
renameat
+renameat2
rmdir
symlink
symlinkat
@@ -68,9 +71,23 @@ execvpe
fexecve
system
popen
+removexattr
+lremovexattr
+setxattr
+lsetxattr
utime
+__utime64
utimes
+__utimes64
+__utimes_time64
utimensat
+__utimensat64 utimensat_time64
+__utimensat_time64
futimesat
+__futimesat64
+__futimesat_time64
lutimes
+__lutimes64
+__lutimes_time64
fork
+vfork
diff --git a/libsandbox/trace.c b/libsandbox/trace.c
index fb1fc32..75a749e 100644
--- a/libsandbox/trace.c
+++ b/libsandbox/trace.c
@@ -10,7 +10,16 @@
#include "sb_nr.h"
static long do_peekdata(long offset);
-static long _do_ptrace(enum __ptrace_request request, const char *srequest, void *addr, void *data);
+/* Note on _do_ptrace argument types:
+ glibc defines ptrace as:
+ long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
+ musl defines ptrace as:
+ long ptrace(int, ...);
+
+ Let's clobber to 'int' lowest common denominator.
+ */
+typedef int sb_ptrace_req_t;
+static long _do_ptrace(sb_ptrace_req_t request, const char *srequest, void *addr, void *data);
#define do_ptrace(request, addr, data) _do_ptrace(request, #request, addr, data)
#define _trace_possible(data) true
@@ -20,7 +29,7 @@ static long _do_ptrace(enum __ptrace_request request, const char *srequest, void
# define SBDEBUG 0
#endif
#define __sb_debug(fmt, args...) do { if (SBDEBUG) sb_eraw(fmt, ## args); } while (0)
-#define _sb_debug(fmt, args...) do { if (SBDEBUG) sb_ewarn("TRACE (pid=%i):%s: " fmt, getpid(), __func__, ## args); } while (0)
+#define _sb_debug(fmt, args...) do { if (SBDEBUG) sb_ewarn("TRACE (pid=%i<%i):%s: " fmt, getpid(), trace_pid, __func__, ## args); } while (0)
#define sb_debug(fmt, args...) _sb_debug(fmt "\n", ## args)
#include "trace/os.c"
@@ -37,6 +46,38 @@ pid_t trace_pid;
# define sb_openat_pre_check sb_openat64_pre_check
#endif
+static int trace_yama_level(void)
+{
+ char ch;
+ int fd, level;
+
+ fd = open64("/proc/sys/kernel/yama/ptrace_scope", O_RDONLY | O_CLOEXEC);
+ if (fd == -1)
+ return 0;
+
+ RETRY_EINTR(read(fd, &ch, 1));
+ close(fd);
+ level = ch - '0';
+
+ switch (level) {
+ case 0:
+ /* Normal levels work fine. */
+ return 0;
+
+ case 1:
+ case 2:
+ /* ptrace scope binds access to specific capabilities. Lets use uid==0 as a
+ * lazy proxy for "we have all capabilities" until we can refine this.
+ */
+ return getuid() == 0 ? 0 : level;
+
+ case 3:
+ default:
+ /* Level 3+ is not supported. */
+ sb_ebort("YAMA ptrace_scope=%i+ is not supported as it makes tracing impossible.\n", level);
+ }
+}
+
static void trace_exit(int status)
{
/* if we were vfork-ed, clear trace_pid and exit */
@@ -44,7 +85,7 @@ static void trace_exit(int status)
_exit(status);
}
-static long _do_ptrace(enum __ptrace_request request, const char *srequest, void *addr, void *data)
+static long _do_ptrace(sb_ptrace_req_t request, const char *srequest, void *addr, void *data)
{
long ret;
try_again:
@@ -169,20 +210,6 @@ static char *do_peekstr(unsigned long lptr)
}
}
-static const char *strcld_chld(int cld)
-{
- switch (cld) {
-#define C(c) case CLD_##c: return "CLD_"#c;
- C(CONTINUED)
- C(DUMPED)
- C(EXITED)
- C(KILLED)
- C(TRAPPED)
- C(STOPPED)
-#undef C
- default: return "CLD_???";
- }
-}
/* strsignal() translates the string when i want C define */
static const char *strsig(int sig)
{
@@ -205,47 +232,6 @@ static const char *strsig(int sig)
}
}
-static void trace_child_signal(int signo, siginfo_t *info, void *context)
-{
- sb_debug("got sig %s(%i): code:%s(%i) status:%s(%i)",
- strsig(signo), signo,
- strcld_chld(info->si_code), info->si_code,
- strsig(info->si_status), info->si_status);
-
- switch (info->si_code) {
- case CLD_DUMPED:
- case CLD_KILLED:
- trace_exit(128 + info->si_status);
-
- case CLD_EXITED:
- __sb_debug(" = %i\n", info->si_status);
- trace_exit(info->si_status);
-
- case CLD_TRAPPED:
- switch (info->si_status) {
- case SIGSTOP:
- kill(trace_pid, SIGCONT);
- case SIGTRAP:
- case SIGCONT:
- return;
- }
-
- /* For whatever signal the child caught, let's ignore it and
- * continue on. If it aborted, segfaulted, whatever, that's
- * its problem, not ours, so don't whine about it. We just
- * have to be sure to bubble it back up. #265072
- */
- do_ptrace(PTRACE_CONT, NULL, (void *)(long)info->si_status);
- return;
- }
-
- sb_eerror("ISE:trace_child_signal: child (%i) signal %s(%i), code %s(%i), status %s(%i)\n",
- trace_pid,
- strsig(signo), signo,
- strcld_chld(info->si_code), info->si_code,
- strsig(info->si_status), info->si_status);
-}
-
static const struct syscall_entry *lookup_syscall_in_tbl(const struct syscall_entry *tbl, int nr)
{
while (tbl->name)
@@ -263,6 +249,7 @@ struct syscall_state {
bool (*pre_check)(const char *func, const char *pathname, int dirfd);
};
+/* Check syscall that only takes a path as its |ibase| argument. */
static bool _trace_check_syscall_C(struct syscall_state *state, int ibase)
{
char *path = do_peekstr(trace_arg(state->regs, ibase));
@@ -279,6 +266,7 @@ static bool _trace_check_syscall_C(struct syscall_state *state, int ibase)
free(path);
return ret;
}
+/* Check syscall that only takes a path as its first argument. */
static bool trace_check_syscall_C(struct syscall_state *state)
{
return _trace_check_syscall_C(state, 1);
@@ -301,20 +289,24 @@ static bool __trace_check_syscall_DCF(struct syscall_state *state, int ibase, in
free(path);
return ret;
}
-static bool _trace_check_syscall_DCF(struct syscall_state *state, int ibase)
+/* Check syscall that takes a dirfd & path starting at |ibase| argument, and flags at |fbase|. */
+static bool _trace_check_syscall_DCF(struct syscall_state *state, int ibase, int fbase)
{
- int flags = trace_arg(state->regs, ibase + 2);
+ int flags = trace_arg(state->regs, fbase);
return __trace_check_syscall_DCF(state, ibase, flags);
}
+/* Check syscall that takes a dirfd, path, and flags as its first 3 arguments. */
static bool trace_check_syscall_DCF(struct syscall_state *state)
{
- return _trace_check_syscall_DCF(state, 1);
+ return _trace_check_syscall_DCF(state, 1, 3);
}
+/* Check syscall that takes a dirfd & path starting at |ibase| argument. */
static bool _trace_check_syscall_DC(struct syscall_state *state, int ibase)
{
return __trace_check_syscall_DCF(state, ibase, 0);
}
+/* Check syscall that takes a dirfd & path as its first 2 arguments (but no flags). */
static bool trace_check_syscall_DC(struct syscall_state *state)
{
return _trace_check_syscall_DC(state, 1);
@@ -345,7 +337,7 @@ static bool trace_check_syscall(const struct syscall_entry *se, void *regs)
state.regs = regs;
state.nr = nr = se->sys;
state.func = name = se->name;
- if (nr == SB_NR_UNDEF) goto done;
+ if (!SB_NR_IS_DEFINED(se->nr)) goto done;
else if (nr == SB_NR_MKDIR) state.pre_check = sb_mkdirat_pre_check;
else if (nr == SB_NR_MKDIRAT) state.pre_check = sb_mkdirat_pre_check;
else if (nr == SB_NR_UNLINK) state.pre_check = sb_unlinkat_pre_check;
@@ -353,22 +345,24 @@ static bool trace_check_syscall(const struct syscall_entry *se, void *regs)
else state.pre_check = NULL;
/* Hmm, add these functions to the syscall table and avoid this if() ? */
- if (nr == SB_NR_UNDEF) goto done;
- else if (nr == SB_NR_CHMOD) return trace_check_syscall_C (&state);
+ if (nr == SB_NR_CHMOD) return trace_check_syscall_C (&state);
else if (nr == SB_NR_CHOWN) return trace_check_syscall_C (&state);
else if (nr == SB_NR_CREAT) return trace_check_syscall_C (&state);
- else if (nr == SB_NR_FCHMODAT) return trace_check_syscall_DCF(&state);
- else if (nr == SB_NR_FCHOWNAT) return trace_check_syscall_DCF(&state);
+ /* NB: Linux syscall does not have a flags argument. */
+ else if (nr == SB_NR_FCHMODAT) return trace_check_syscall_DC (&state);
+ else if (nr == SB_NR_FCHOWNAT) return _trace_check_syscall_DCF(&state, 1, 5);
else if (nr == SB_NR_FUTIMESAT) return trace_check_syscall_DC (&state);
else if (nr == SB_NR_LCHOWN) return trace_check_syscall_C (&state);
else if (nr == SB_NR_LINK) return _trace_check_syscall_C (&state, 2);
- else if (nr == SB_NR_LINKAT) return _trace_check_syscall_DCF(&state, 3);
+ else if (nr == SB_NR_LINKAT) return _trace_check_syscall_DCF(&state, 3, 5);
else if (nr == SB_NR_MKDIR) return trace_check_syscall_C (&state);
else if (nr == SB_NR_MKDIRAT) return trace_check_syscall_DC (&state);
else if (nr == SB_NR_MKNOD) return trace_check_syscall_C (&state);
else if (nr == SB_NR_MKNODAT) return trace_check_syscall_DC (&state);
else if (nr == SB_NR_RENAME) return trace_check_syscall_C (&state) &&
_trace_check_syscall_C (&state, 2);
+ else if (nr == SB_NR_RENAMEAT2) return trace_check_syscall_DC (&state) &&
+ _trace_check_syscall_DC (&state, 3);
else if (nr == SB_NR_RENAMEAT) return trace_check_syscall_DC (&state) &&
_trace_check_syscall_DC (&state, 3);
else if (nr == SB_NR_RMDIR) return trace_check_syscall_C (&state);
@@ -380,7 +374,14 @@ static bool trace_check_syscall(const struct syscall_entry *se, void *regs)
else if (nr == SB_NR_UNLINKAT) return trace_check_syscall_DCF(&state);
else if (nr == SB_NR_UTIME) return trace_check_syscall_C (&state);
else if (nr == SB_NR_UTIMES) return trace_check_syscall_C (&state);
- else if (nr == SB_NR_UTIMENSAT) return _trace_check_syscall_DCF(&state, 1);
+
+ else if (nr == SB_NR_UTIMENSAT) {
+ utimensat:
+ return _trace_check_syscall_DCF(&state, 1, 4);
+ } else if (nr == SB_NR___UTIMENSAT64) {
+ state.nr = SB_NR_UTIMENSAT;
+ goto utimensat;
+ }
else if (nr == SB_NR_ACCESS) {
char *path = do_peekstr(trace_arg(regs, 1));
@@ -421,47 +422,218 @@ static bool trace_check_syscall(const struct syscall_entry *se, void *regs)
ret = 1;
free(path);
return ret;
+
+ } else if (nr == SB_NR_EXECVE || nr == SB_NR_EXECVEAT) {
+ /* Try to extract environ and merge with our own. */
+ char *path;
+ unsigned long environ, i = 0;
+
+ if (nr == SB_NR_EXECVEAT) {
+ int dirfd = do_peekdata(trace_arg(regs, 1));
+ unsigned long argv = trace_arg(regs, 3);
+ environ = trace_arg(regs, 4);
+ path = do_peekstr(trace_arg(regs, 2));
+ __sb_debug("(%i, \"%s\", %lx, %lx{", dirfd, path, argv, environ);
+ } else {
+ path = do_peekstr(trace_arg(regs, 1));
+ unsigned long argv = trace_arg(regs, 2);
+ environ = trace_arg(regs, 3);
+ __sb_debug("(\"%s\", %lx, %lx{", path, argv, environ);
+ }
+
+ while (1) {
+ unsigned long envp = do_peekdata(environ + i);
+ if (!envp)
+ break;
+
+ char *env = do_peekstr(envp);
+ if (strncmp(env, "SANDBOX_", 8) == 0) {
+ __sb_debug("\"%s\" ", env);
+ putenv(env);
+ }
+ i += sizeof(long);
+ }
+ __sb_debug("})");
+ return 1;
+ } else if (nr == SB_NR_FCHMOD) {
+ int fd = trace_arg(regs, 1);
+ mode_t mode = trace_arg(regs, 2);
+ __sb_debug("(%i, %o)", fd, mode);
+ return _SB_SAFE_FD(nr, name, fd);
+
+ } else if (nr == SB_NR_FCHOWN) {
+ int fd = trace_arg(regs, 1);
+ uid_t uid = trace_arg(regs, 2);
+ gid_t gid = trace_arg(regs, 3);
+ __sb_debug("(%i, %i, %i)", fd, uid, gid);
+ return _SB_SAFE_FD(nr, name, fd);
}
+
done:
__sb_debug("(...)");
return ret;
}
+static void trace_init_tracee(void)
+{
+ do_ptrace(PTRACE_SETOPTIONS, NULL, (void *)(uintptr_t)(
+ PTRACE_O_EXITKILL |
+ PTRACE_O_TRACECLONE |
+ PTRACE_O_TRACEEXEC |
+ PTRACE_O_TRACEEXIT |
+ PTRACE_O_TRACEFORK |
+ PTRACE_O_TRACEVFORK |
+ PTRACE_O_TRACESYSGOOD
+ ));
+}
+
static void trace_loop(void)
{
trace_regs regs;
bool before_exec, before_syscall, fake_syscall_ret;
+ unsigned event;
long ret;
- int nr, status;
- const struct syscall_entry *se, *tbl_after_fork;
+ int status, sig;
+ const struct syscall_entry *tbl_after_fork;
+ void *data;
before_exec = true;
before_syscall = false;
fake_syscall_ret = false;
tbl_after_fork = NULL;
+ data = NULL;
do {
- ret = do_ptrace(PTRACE_SYSCALL, NULL, NULL);
+ ret = do_ptrace(PTRACE_SYSCALL, NULL, data);
+ data = NULL;
waitpid(trace_pid, &status, 0);
- if (before_exec) {
- unsigned event = ((unsigned)status >> 16);
- if (event == PTRACE_EVENT_EXEC) {
- _sb_debug("hit exec!");
- before_exec = false;
- } else
+ event = (unsigned)status >> 16;
+
+ if (WIFSIGNALED(status)) {
+ int sig = WTERMSIG(status);
+ sb_debug("signaled %s %i", strsig(sig), sig);
+ kill(getpid(), sig);
+ trace_exit(128 + sig);
+
+ } else if (WIFEXITED(status)) {
+ ret = WEXITSTATUS(status);
+ sb_debug("exited %li", ret);
+ trace_exit(ret);
+
+ }
+
+ sb_assert(WIFSTOPPED(status));
+ sig = WSTOPSIG(status);
+
+ switch (event) {
+ case 0:
+ if (sig != (SIGTRAP | 0x80)) {
+ /* For whatever signal the child caught, let's ignore it and
+ * continue on. If it aborted, segfaulted, whatever, that's
+ * its problem, not ours, so don't whine about it. We just
+ * have to be sure to bubble it back up. #265072
+ *
+ * The next run of this loop should see the WIFSIGNALED status
+ * and we'll exit then.
+ */
+ sb_debug("passing signal through %s (%i)", strsig(sig), sig);
+ data = (void *)(uintptr_t)(sig);
+ continue;
+ }
+
+ if (before_exec) {
_sb_debug("waiting for exec; status: %#x", status);
+ continue;
+ }
+ break;
+
+ case PTRACE_EVENT_EXEC:
+ __sb_debug("hit exec!");
+ before_exec = false;
ret = trace_get_regs(&regs);
tbl_after_fork = trace_check_personality(&regs);
continue;
+
+ case PTRACE_EVENT_EXIT:
+ /* We'll tell the process to resume, which should make it exit,
+ * and then we'll pick up its exit status and exit above.
+ */
+ __sb_debug(" exit event!\n");
+ continue;
+
+ case PTRACE_EVENT_CLONE:
+ case PTRACE_EVENT_FORK:
+ case PTRACE_EVENT_VFORK: {
+ /* The tracee is forking, so fork a new tracer to handle it. */
+ long newpid;
+ do_ptrace(PTRACE_GETEVENTMSG, NULL, &newpid);
+ sb_debug("following forking event %i; pid=%li %i\n",
+ event, newpid, before_syscall);
+
+ /* If YAMA ptrace_scope is active, then we can't hand off the child
+ * to a new tracer. Give up. #821403
+ */
+ int yama = trace_yama_level();
+ if (yama >= 1) {
+ sb_eqawarn("Unable to trace children due to YAMA ptrace_scope=%i\n", yama);
+ ptrace(PTRACE_DETACH, newpid, NULL, NULL);
+ continue;
+ }
+
+ /* Pipe for synchronizing detach & attach events. */
+ int fds[2];
+ ret = pipe(fds);
+ sb_assert(ret == 0);
+ if (fork() == 0) {
+ /* New tracer needs to take control of new tracee. */
+ char ch;
+ close(fds[1]);
+ RETRY_EINTR(read(fds[0], &ch, 1));
+ close(fds[0]);
+ trace_pid = newpid;
+ retry_attach:
+ ret = do_ptrace(PTRACE_ATTACH, NULL, NULL);
+ if (ret) {
+ if (errno == EPERM)
+ goto retry_attach;
+ sb_ebort("ISE:PTRACE_ATTACH %s", strerror(errno));
+ }
+ trace_init_tracee();
+ before_syscall = true;
+ continue;
+ } else {
+ /* Existing tracer needs to release new tracee. */
+ retry_detach:
+ ret = ptrace(PTRACE_DETACH, newpid, NULL, (void *)SIGSTOP);
+ if (ret) {
+ if (errno == ESRCH) {
+ /* The kernel might not have the proc ready yet. */
+ struct timespec ts = {0, 500 * 1000 /* 0.5 millisec */};
+ nanosleep(&ts, NULL);
+ goto retry_detach;
+ }
+ sb_ebort("ISE:PTRACE_DETACH %s", strerror(errno));
+ }
+ close(fds[0]);
+ RETRY_EINTR(write(fds[1], "", 1));
+ close(fds[1]);
+ }
+ continue;
}
- ret = trace_get_regs(&regs);
- nr = trace_get_sysnum(&regs);
+ default:
+ sb_ebort("ISE: unhandle ptrace signal %s (%i) event %u\n",
+ strsig(sig), sig, event);
+ }
- se = lookup_syscall_in_tbl(tbl_after_fork, nr);
ret = trace_get_regs(&regs);
+
if (before_syscall) {
+ /* NB: The kernel guarantees syscall NR is valid only on entry. */
+ int nr = trace_get_sysnum(&regs);
+ const struct syscall_entry *se = lookup_syscall_in_tbl(tbl_after_fork, nr);
+
_sb_debug("%s:%i", se ? se->name : "IDK", nr);
if (!trace_check_syscall(se, &regs)) {
sb_debug_dyn("trace_loop: forcing EPERM after %s\n", se->name);
@@ -489,27 +661,21 @@ static void trace_loop(void)
} while (1);
}
-void trace_main(const char *filename, char *const argv[])
+void trace_main(void)
{
- struct sigaction sa, old_sa;
-
- sa.sa_flags = SA_RESTART | SA_SIGINFO;
- sa.sa_sigaction = trace_child_signal;
- sigaction(SIGCHLD, &sa, &old_sa);
-
- sb_debug_dyn("trace_main: tracing: %s\n", filename);
+ struct sigaction old_sa, sa = { .sa_handler = SIG_DFL, };
if (trace_pid)
sb_ebort("ISE: trace code assumes multiple threads are not forking\n");
+ sigaction(SIGCHLD, &sa, &old_sa);
trace_pid = fork();
if (unlikely(trace_pid == -1)) {
sb_ebort("ISE: vfork() failed: %s\n", strerror(errno));
} else if (trace_pid) {
sb_debug("parent waiting for child (pid=%i) to signal", trace_pid);
waitpid(trace_pid, NULL, 0);
- do_ptrace(PTRACE_SETOPTIONS, NULL,
- (void *)(PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEEXEC));
+ trace_init_tracee();
sb_close_all_fds();
trace_loop();
sb_ebort("ISE: child should have quit, as should we\n");
@@ -527,7 +693,7 @@ void trace_main(const char *filename, char *const argv[])
#undef _trace_possible
#define _trace_possible(data) false
-void trace_main(const char *filename, char *const argv[])
+void trace_main(void)
{
/* trace_possible() triggers a warning for us */
}
@@ -563,10 +729,26 @@ static char *flatten_args(char *const argv[])
bool trace_possible(const char *filename, char *const argv[], const void *data)
{
- if (_trace_possible(data))
- return true;
+ char *args;
+
+ /* If YAMA ptrace_scope is very high, then we can't trace at all. #771360 */
+ int yama = trace_yama_level();
+ if (yama >= 2) {
+ sb_eqawarn("YAMA ptrace_scope=%i is not currently supported\n", yama);
+ goto fail;
+ }
+
+ if (_trace_possible(data)) {
+ /* If we're in an environment like QEMU where ptrace doesn't work, then
+ * don't try to use it. If ptrace does work, this should fail with ESRCH.
+ */
+ errno = 0;
+ ptrace(PTRACE_CONT, 0, NULL, NULL);
+ return errno == ENOSYS ? false : true;
+ }
- char *args = flatten_args(argv);
+ fail:
+ args = flatten_args(argv);
sb_eqawarn("Unable to trace static ELF: %s: %s\n", filename, args);
free(args);
return false;
diff --git a/libsandbox/trace/common.c b/libsandbox/trace/common.c
index f426887..767839a 100644
--- a/libsandbox/trace/common.c
+++ b/libsandbox/trace/common.c
@@ -7,7 +7,7 @@ static int trace_get_sysnum(void *vregs);
static long trace_raw_ret(void *vregs);
static unsigned long trace_arg(void *vregs, int num);
-#ifndef SB_SCHIZO
+#ifndef SB_PERSONALITIES
static const struct syscall_entry syscall_table[] = {
#define S(s) { SB_SYS_##s, SB_NR_##s, #s },
#include "trace_syscalls.h"
diff --git a/libsandbox/trace/linux/aarch64.c b/libsandbox/trace/linux/aarch64.c
new file mode 100644
index 0000000..82e829c
--- /dev/null
+++ b/libsandbox/trace/linux/aarch64.c
@@ -0,0 +1,50 @@
+#define trace_reg_ret regs[0] /* x0 */
+
+#undef trace_get_regs
+static long trace_get_regs(void *vregs)
+{
+ struct iovec iov_regs = {
+ .iov_base = vregs,
+ .iov_len = sizeof(trace_regs),
+ };
+ return do_ptrace(PTRACE_GETREGSET, (void *)(uintptr_t)NT_PRSTATUS, &iov_regs);
+}
+
+#undef trace_set_regs
+static long trace_set_regs(void *vregs)
+{
+ struct iovec iov_regs = {
+ .iov_base = vregs,
+ .iov_len = sizeof(trace_regs),
+ };
+ return do_ptrace(PTRACE_SETREGSET, (void *)(uintptr_t)NT_PRSTATUS, &iov_regs);
+}
+
+static unsigned long trace_arg(void *vregs, int num)
+{
+ trace_regs *regs = vregs;
+ if (num < 7)
+ return regs->regs[num - 1]; /* x0 - x5 */
+ else
+ return -1;
+}
+
+static int trace_get_sysnum(void *vregs)
+{
+ int nr;
+ struct iovec iov_nr = {
+ .iov_base = &nr,
+ .iov_len = sizeof(nr),
+ };
+ do_ptrace(PTRACE_GETREGSET, (void *)(uintptr_t)NT_ARM_SYSTEM_CALL, &iov_nr);
+ return nr;
+}
+
+static void trace_set_sysnum(void *vregs, int nr)
+{
+ struct iovec iov_nr = {
+ .iov_base = &nr,
+ .iov_len = sizeof(nr),
+ };
+ do_ptrace(PTRACE_SETREGSET, (void *)(uintptr_t)NT_ARM_SYSTEM_CALL, &iov_nr);
+}
diff --git a/libsandbox/trace/linux/arch.c b/libsandbox/trace/linux/arch.c
index 4b3d615..16cdf9b 100644
--- a/libsandbox/trace/linux/arch.c
+++ b/libsandbox/trace/linux/arch.c
@@ -7,6 +7,8 @@
#if !defined(HAVE_PTRACE) || !defined(HAVE_SYS_PTRACE_H) || \
!defined(HAVE_SYS_USER_H) || !defined(PTRACE_SETOPTIONS)
# define SB_NO_TRACE_ARCH
+#elif defined(__aarch64__)
+# include "aarch64.c"
#elif defined(__alpha__)
# include "alpha.c"
#elif defined(__arm__)
@@ -27,6 +29,8 @@
# include "sparc.c"
#elif defined(__x86_64__)
# include "x86_64.c"
+#elif defined(HAVE_STRUCT_PTRACE_SYSCALL_INFO)
+# include "syscall_info.c"
#else
# define SB_NO_TRACE_ARCH
#endif
diff --git a/libsandbox/trace/linux/i386.c b/libsandbox/trace/linux/i386.c
index f9476aa..722efb4 100644
--- a/libsandbox/trace/linux/i386.c
+++ b/libsandbox/trace/linux/i386.c
@@ -8,7 +8,7 @@ static bool _trace_possible(const void *data)
(ehdr->e_machine == EM_386);
}
-#ifdef SB_SCHIZO
+#ifdef SB_PERSONALITIES
static const struct syscall_entry syscall_table[] = {
#define S(s) { SB_SYS_x86_##s, SB_NR_##s, #s },
#include "trace_syscalls_x86.h"
diff --git a/libsandbox/trace/linux/powerpc.c b/libsandbox/trace/linux/powerpc.c
index 6e9152c..b7fb76a 100644
--- a/libsandbox/trace/linux/powerpc.c
+++ b/libsandbox/trace/linux/powerpc.c
@@ -13,8 +13,14 @@ static long trace_raw_ret(void *vregs)
static void trace_set_ret(void *vregs, int err)
{
trace_regs *regs = vregs;
- regs->gpr[0] = -1;
- regs->gpr[3] = err;
+ if ((regs->trap & 0xfff0) == 0x3000) {
+ /* ppc64 */
+ regs->gpr[3] = -err;
+ } else {
+ /* ppc32 */
+ regs->gpr[3] = err;
+ regs->ccr |= 0x10000000;
+ }
trace_set_regs(regs);
}
diff --git a/libsandbox/trace/linux/s390.c b/libsandbox/trace/linux/s390.c
index acbf894..2c7a9be 100644
--- a/libsandbox/trace/linux/s390.c
+++ b/libsandbox/trace/linux/s390.c
@@ -1,10 +1,10 @@
#undef _trace_possible
#define _trace_possible _trace_possible
-#ifdef SB_SCHIZO
+#ifdef SB_PERSONALITIES
static const struct syscall_entry syscall_table_32[] = {
-#ifdef SB_SCHIZO_s390
+#ifdef SB_PERSONALITIES_s390
#define S(s) { SB_SYS_s390_##s, SB_NR_##s, #s },
#include "trace_syscalls_s390.h"
#undef S
@@ -12,7 +12,7 @@ static const struct syscall_entry syscall_table_32[] = {
{ SB_NR_UNDEF, SB_NR_UNDEF, NULL },
};
static const struct syscall_entry syscall_table_64[] = {
-#ifdef SB_SCHIZO_s390x
+#ifdef SB_PERSONALITIES_s390x
#define S(s) { SB_SYS_s390x_##s, SB_NR_##s, #s },
#include "trace_syscalls_s390x.h"
#undef S
diff --git a/libsandbox/trace/linux/sparc.c b/libsandbox/trace/linux/sparc.c
index b59a036..6050dc9 100644
--- a/libsandbox/trace/linux/sparc.c
+++ b/libsandbox/trace/linux/sparc.c
@@ -1,6 +1,3 @@
-#define SB_NO_TRACE_ARCH
-#if 0 /* XXX: broken sometimes #293632 */
-
/* Since sparc's g0 register is hardcoded to 0 in the ISA, the kernel does not
* bother copying it out when using the regs ptrace. Instead it shifts things
* by one and stores [g1..g7] in [0..6] and [o0..o7] in [7..14] (leaving the
@@ -16,11 +13,86 @@
#define U_REG_G1 0
#define U_REG_O0 7
+#undef _trace_possible
+#define _trace_possible _trace_possible
+
+#ifdef SB_PERSONALITIES
+
+static const struct syscall_entry syscall_table_32[] = {
+#ifdef SB_PERSONALITIES_sparc
+#define S(s) { SB_SYS_sparc_##s, SB_NR_##s, #s },
+#include "trace_syscalls_sparc.h"
+#undef S
+#endif
+ { SB_NR_UNDEF, SB_NR_UNDEF, NULL },
+};
+static const struct syscall_entry syscall_table_64[] = {
+#ifdef SB_PERSONALITIES_sparc64
+#define S(s) { SB_SYS_sparc64_##s, SB_NR_##s, #s },
+#include "trace_syscalls_sparc64.h"
+#undef S
+#endif
+ { SB_NR_UNDEF, SB_NR_UNDEF, NULL },
+};
+
+static bool pers_is_32(trace_regs *regs)
+{
+#ifdef __arch64__
+ /* Sparc does not make it easy to detect 32-bit vs 64-bit.
+ * Inspect the syscall trap insn to see which one it is.
+ */
+ unsigned long ret = do_ptrace(PTRACE_PEEKTEXT, (void *)regs->tpc, NULL);
+ return (ret >> 32) == 0x91d02010;
+#else
+ return true;
+#endif
+}
+
+static const struct syscall_entry *trace_check_personality(void *vregs)
+{
+ trace_regs *regs = vregs;
+ if (pers_is_32(regs))
+ return syscall_table_32;
+ else
+ return syscall_table_64;
+}
+
+static bool _trace_possible(const void *data)
+{
+#ifdef __arch64__
+ /* sparc64 can trace sparc32. */
+ return true;
+#else
+ /* sparc32 can only trace sparc32 :(. */
+ const Elf64_Ehdr *ehdr = data;
+ return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
+#endif
+}
+
+#else
+
+static bool _trace_possible(const void *data)
+{
+ const Elf64_Ehdr *ehdr = data;
+#ifdef __arch64__
+ return ehdr->e_ident[EI_CLASS] == ELFCLASS64;
+#else
+ return ehdr->e_ident[EI_CLASS] == ELFCLASS32;
+#endif
+}
+
+#endif
+
/* Sparc systems have swapped the addr/data args. */
#undef trace_get_regs
-#define trace_get_regs(regs) do_ptrace(PTRACE_GETREGS, regs, NULL)
#undef trace_set_regs
-#define trace_set_regs(regs) do_ptrace(PTRACE_SETREGS, regs, NULL)
+#ifdef __arch64__
+# define trace_get_regs(regs) do_ptrace(PTRACE_GETREGS64, regs, NULL)
+# define trace_set_regs(regs) do_ptrace(PTRACE_SETREGS64, regs, NULL)
+#else
+# define trace_get_regs(regs) do_ptrace(PTRACE_GETREGS, regs, NULL)
+# define trace_set_regs(regs) do_ptrace(PTRACE_SETREGS, regs, NULL)
+#endif
#define trace_reg_sysnum u_regs[U_REG_G1]
@@ -33,8 +105,12 @@ static long trace_raw_ret(void *vregs)
static void trace_set_ret(void *vregs, int err)
{
trace_regs *regs = vregs;
+#ifndef __arch64__
/* The carry bit is used to flag errors. */
regs->psr |= PSR_C;
+#else
+ regs->tstate |= 0x1100000000;
+#endif
/* Userland negates the value on sparc. */
regs->u_regs[U_REG_O0] = err;
trace_set_regs(regs);
@@ -48,5 +124,3 @@ static unsigned long trace_arg(void *vregs, int num)
else
return -1;
}
-
-#endif
diff --git a/libsandbox/trace/linux/syscall_info.c b/libsandbox/trace/linux/syscall_info.c
new file mode 100644
index 0000000..23cd509
--- /dev/null
+++ b/libsandbox/trace/linux/syscall_info.c
@@ -0,0 +1,24 @@
+#undef trace_regs
+#define trace_regs struct ptrace_syscall_info
+
+#define trace_reg_sysnum entry.nr
+#define trace_reg_ret exit.rval
+
+#undef trace_get_regs
+#define trace_get_regs(regs) do_ptrace(PTRACE_GET_SYSCALL_INFO, (void *)(uintptr_t)sizeof(trace_regs), regs)
+
+static unsigned long trace_arg(void *vregs, int num)
+{
+ trace_regs *regs = vregs;
+ if (num < 7)
+ return regs->entry.args[num - 1];
+ else
+ return -1;
+}
+
+#undef trace_set_regs
+static long trace_set_regs(void *vregs)
+{
+ sb_ewarn("sandbox: Unable to block violation\n");
+ return 0;
+}
diff --git a/libsandbox/trace/linux/x86_64.c b/libsandbox/trace/linux/x86_64.c
index aff1edb..d01e00f 100644
--- a/libsandbox/trace/linux/x86_64.c
+++ b/libsandbox/trace/linux/x86_64.c
@@ -1,10 +1,10 @@
#undef _trace_possible
#define _trace_possible _trace_possible
-#ifdef SB_SCHIZO
+#ifdef SB_PERSONALITIES
static const struct syscall_entry syscall_table_32[] = {
-#ifdef SB_SCHIZO_x86
+#ifdef SB_PERSONALITIES_x86
#define S(s) { SB_SYS_x86_##s, SB_NR_##s, #s },
#include "trace_syscalls_x86.h"
#undef S
@@ -12,7 +12,7 @@ static const struct syscall_entry syscall_table_32[] = {
{ SB_NR_UNDEF, SB_NR_UNDEF, NULL },
};
static const struct syscall_entry syscall_table_64[] = {
-#ifdef SB_SCHIZO_x86_64
+#ifdef SB_PERSONALITIES_x86_64
#define S(s) { SB_SYS_x86_64_##s, SB_NR_##s, #s },
#include "trace_syscalls_x86_64.h"
#undef S
@@ -20,7 +20,7 @@ static const struct syscall_entry syscall_table_64[] = {
{ SB_NR_UNDEF, SB_NR_UNDEF, NULL },
};
static const struct syscall_entry syscall_table_x32[] = {
-#ifdef SB_SCHIZO_x32
+#ifdef SB_PERSONALITIES_x32
#define S(s) { SB_SYS_x32_##s, SB_NR_##s, #s },
#include "trace_syscalls_x32.h"
#undef S
diff --git a/libsandbox/wrapper-funcs/__64_post.h b/libsandbox/wrapper-funcs/__64_post.h
deleted file mode 100644
index 82d2a16..0000000
--- a/libsandbox/wrapper-funcs/__64_post.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#undef SB64
-#undef stat
-#undef lstat
-#undef off_t
diff --git a/libsandbox/wrapper-funcs/__64_pre.h b/libsandbox/wrapper-funcs/__64_pre.h
deleted file mode 100644
index 0b34b25..0000000
--- a/libsandbox/wrapper-funcs/__64_pre.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#define SB64
-#define stat stat64
-#define lstat lstat64
-#define off_t off64_t
diff --git a/libsandbox/wrapper-funcs/__futimesat64.c b/libsandbox/wrapper-funcs/__futimesat64.c
new file mode 100644
index 0000000..9ad791e
--- /dev/null
+++ b/libsandbox/wrapper-funcs/__futimesat64.c
@@ -0,0 +1,13 @@
+/*
+ * __futimesat64() wrapper.
+ *
+ * Copyright 1999-2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+/*
+ * NB: Reusing the 32-bit time interface isn't entirely correct as the 64-bit time interface uses a
+ * different structure, but we never decode the time values in sandbox, so it doesn't matter to use.
+ */
+#define WRAPPER_SAFE() _SB_SAFE_AT(SB_NR_FUTIMESAT, STRING_NAME, dirfd, filename, 0)
+#include "futimesat.c"
diff --git a/libsandbox/wrapper-funcs/__futimesat_time64.c b/libsandbox/wrapper-funcs/__futimesat_time64.c
new file mode 120000
index 0000000..c3a9b23
--- /dev/null
+++ b/libsandbox/wrapper-funcs/__futimesat_time64.c
@@ -0,0 +1 @@
+__futimesat64.c \ No newline at end of file
diff --git a/libsandbox/wrapper-funcs/__lutimes64.c b/libsandbox/wrapper-funcs/__lutimes64.c
new file mode 100644
index 0000000..edab47c
--- /dev/null
+++ b/libsandbox/wrapper-funcs/__lutimes64.c
@@ -0,0 +1,13 @@
+/*
+ * __lutimes64() wrapper.
+ *
+ * Copyright 1999-2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+/*
+ * NB: Reusing the 32-bit time interface isn't entirely correct as the 64-bit time interface uses a
+ * different structure, but we never decode the time values in sandbox, so it doesn't matter to use.
+ */
+#define WRAPPER_SAFE() _SB_SAFE(SB_NR_LUTIMES, STRING_NAME, filename)
+#include "lutimes.c"
diff --git a/libsandbox/wrapper-funcs/__lutimes_time64.c b/libsandbox/wrapper-funcs/__lutimes_time64.c
new file mode 120000
index 0000000..1819ce7
--- /dev/null
+++ b/libsandbox/wrapper-funcs/__lutimes_time64.c
@@ -0,0 +1 @@
+__lutimes64.c \ No newline at end of file
diff --git a/libsandbox/wrapper-funcs/__open64_2.c b/libsandbox/wrapper-funcs/__open64_2.c
index bdbd5d8..52daff1 100644
--- a/libsandbox/wrapper-funcs/__open64_2.c
+++ b/libsandbox/wrapper-funcs/__open64_2.c
@@ -5,6 +5,6 @@
* Licensed under the GPL-2
*/
-#include "__64_pre.h"
+#define sb_openat_pre_check sb_openat64_pre_check
#include "__open_2.c"
-#include "__64_post.h"
+#undef sb_openat_pre_check
diff --git a/libsandbox/wrapper-funcs/__openat64_2.c b/libsandbox/wrapper-funcs/__openat64_2.c
index 445164a..ccc4fdd 100644
--- a/libsandbox/wrapper-funcs/__openat64_2.c
+++ b/libsandbox/wrapper-funcs/__openat64_2.c
@@ -5,6 +5,6 @@
* Licensed under the GPL-2
*/
-#include "__64_pre.h"
+#define sb_openat_pre_check sb_openat64_pre_check
#include "__openat_2.c"
-#include "__64_post.h"
+#undef sb_openat_pre_check
diff --git a/libsandbox/wrapper-funcs/__openat_2.c b/libsandbox/wrapper-funcs/__openat_2.c
index 4549a23..f2e85ea 100644
--- a/libsandbox/wrapper-funcs/__openat_2.c
+++ b/libsandbox/wrapper-funcs/__openat_2.c
@@ -13,11 +13,7 @@
# define dirfd AT_FDCWD
#endif
-#ifdef SB64
-# define WRAPPER_PRE_CHECKS() sb_openat64_pre_check(STRING_NAME, pathname, dirfd, flags)
-#else
-# define WRAPPER_PRE_CHECKS() sb_openat_pre_check(STRING_NAME, pathname, dirfd, flags)
-#endif
+#define WRAPPER_PRE_CHECKS() sb_openat_pre_check(STRING_NAME, pathname, dirfd, flags)
#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/__pre_check.c b/libsandbox/wrapper-funcs/__pre_check.c
deleted file mode 100644
index 28ad91f..0000000
--- a/libsandbox/wrapper-funcs/__pre_check.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * make sure some pre-checks are pulled in when needed
- *
- * Copyright 1999-2009 Gentoo Foundation
- * Licensed under the GPL-2
- */
-
-#if SB_NR_MKDIR != SB_NR_UNDEF && SB_NR_MKDIRAT == SB_NR_UNDEF
-# include "mkdirat_pre_check.c"
-#endif
-
-#if SB_NR_OPEN != SB_NR_UNDEF && SB_NR_OPENAT == SB_NR_UNDEF
-# include "openat_pre_check.c"
-#endif
-
-#if SB_NR_OPEN64 != SB_NR_UNDEF && SB_NR_OPENAT64 == SB_NR_UNDEF
-# include "openat64_pre_check.c"
-#endif
-
-#if SB_NR_UNLINK != SB_NR_UNDEF && SB_NR_UNLINKAT == SB_NR_UNDEF
-# include "unlinkat_pre_check.c"
-#endif
-
-#include "__pre_at_check.c"
diff --git a/libsandbox/wrapper-funcs/__utime64.c b/libsandbox/wrapper-funcs/__utime64.c
new file mode 100644
index 0000000..4e1b573
--- /dev/null
+++ b/libsandbox/wrapper-funcs/__utime64.c
@@ -0,0 +1,13 @@
+/*
+ * __utime64() wrapper.
+ *
+ * Copyright 1999-2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+/*
+ * NB: Reusing the 32-bit time interface isn't entirely correct as the 64-bit time interface uses a
+ * different structure, but we never decode the time values in sandbox, so it doesn't matter to use.
+ */
+#define WRAPPER_SAFE() _SB_SAFE(SB_NR_UTIME, STRING_NAME, filename)
+#include "utime.c"
diff --git a/libsandbox/wrapper-funcs/__utimensat64.c b/libsandbox/wrapper-funcs/__utimensat64.c
new file mode 100644
index 0000000..4ef1c69
--- /dev/null
+++ b/libsandbox/wrapper-funcs/__utimensat64.c
@@ -0,0 +1,13 @@
+/*
+ * __utimensat64() wrapper.
+ *
+ * Copyright 1999-2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+/*
+ * NB: Reusing the 32-bit time interface isn't entirely correct as the 64-bit time interface uses a
+ * different structure, but we never decode the time values in sandbox, so it doesn't matter to use.
+ */
+#define WRAPPER_SAFE() _SB_SAFE_AT(SB_NR_UTIMENSAT, STRING_NAME, dirfd, filename, flags)
+#include "utimensat.c"
diff --git a/libsandbox/wrapper-funcs/__utimensat_time64.c b/libsandbox/wrapper-funcs/__utimensat_time64.c
new file mode 120000
index 0000000..2dceb14
--- /dev/null
+++ b/libsandbox/wrapper-funcs/__utimensat_time64.c
@@ -0,0 +1 @@
+__utimensat64.c \ No newline at end of file
diff --git a/libsandbox/wrapper-funcs/__utimes64.c b/libsandbox/wrapper-funcs/__utimes64.c
new file mode 100644
index 0000000..3fa6688
--- /dev/null
+++ b/libsandbox/wrapper-funcs/__utimes64.c
@@ -0,0 +1,13 @@
+/*
+ * __utimes64() wrapper.
+ *
+ * Copyright 1999-2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+/*
+ * NB: Reusing the 32-bit time interface isn't entirely correct as the 64-bit time interface uses a
+ * different structure, but we never decode the time values in sandbox, so it doesn't matter to use.
+ */
+#define WRAPPER_SAFE() _SB_SAFE(SB_NR_UTIMES, STRING_NAME, filename)
+#include "utimes.c"
diff --git a/libsandbox/wrapper-funcs/__utimes_time64.c b/libsandbox/wrapper-funcs/__utimes_time64.c
new file mode 120000
index 0000000..3dea445
--- /dev/null
+++ b/libsandbox/wrapper-funcs/__utimes_time64.c
@@ -0,0 +1 @@
+__utimes64.c \ No newline at end of file
diff --git a/libsandbox/wrapper-funcs/__wrapper_exec.c b/libsandbox/wrapper-funcs/__wrapper_exec.c
index 974156e..f603257 100644
--- a/libsandbox/wrapper-funcs/__wrapper_exec.c
+++ b/libsandbox/wrapper-funcs/__wrapper_exec.c
@@ -27,14 +27,18 @@ static bool sb_check_exec(const char *filename, char *const argv[])
{
int fd;
unsigned char *elf;
- struct stat st;
+ struct stat64 st;
bool do_trace = false;
bool run_in_process = true;
+ sandbox_method_t method = get_sandbox_method();
+
+ if (unlikely(method == SANDBOX_METHOD_PRELOAD))
+ return true;
fd = sb_unwrapped_open_DEFAULT(filename, O_RDONLY|O_CLOEXEC, 0);
if (fd == -1)
return true;
- if (fstat(fd, &st))
+ if (fstat64(fd, &st))
goto out_fd;
if (st.st_size < sizeof(Elf64_Ehdr))
goto out_fd;
@@ -65,7 +69,7 @@ static bool sb_check_exec(const char *filename, char *const argv[])
run_in_process = false;
/* We also need to ptrace programs that interpose their own allocator.
- * http://crbug.com/586444
+ * https://crbug.com/586444
*/
if (run_in_process) {
static const char * const libc_alloc_syms[] = {
@@ -83,8 +87,8 @@ static bool sb_check_exec(const char *filename, char *const argv[])
({ \
Elf##n##_Ehdr *ehdr = (void *)elf; \
Elf##n##_Phdr *phdr = (void *)(elf + ehdr->e_phoff); \
- Elf##n##_Addr vaddr, filesz, vsym = 0, vstr = 0, vhash = 0, vliblist = 0; \
- Elf##n##_Off offset, symoff = 0, stroff = 0, hashoff = 0, liblistoff = 0; \
+ Elf##n##_Addr vaddr, filesz, vsym = 0, vstr = 0, vhash = 0, vgnuhash = 0; \
+ Elf##n##_Off offset, symoff = 0, stroff = 0, hashoff = 0, gnuhashoff = 0; \
Elf##n##_Dyn *dyn; \
Elf##n##_Sym *sym, *symend; \
uint##n##_t ent_size = 0, str_size = 0; \
@@ -107,7 +111,7 @@ static bool sb_check_exec(const char *filename, char *const argv[])
case DT_STRTAB: vstr = dyn->d_un.d_val; break; \
case DT_STRSZ: str_size = dyn->d_un.d_val; break; \
case DT_HASH: vhash = dyn->d_un.d_val; break; \
- case DT_GNU_LIBLIST: vliblist = dyn->d_un.d_val; break; \
+ case DT_GNU_HASH: vgnuhash = dyn->d_un.d_val; break; \
} \
++dyn; \
} \
@@ -127,8 +131,8 @@ static bool sb_check_exec(const char *filename, char *const argv[])
stroff = offset + (vstr - vaddr); \
if (vhash >= vaddr && vhash < vaddr + filesz) \
hashoff = offset + (vhash - vaddr); \
- if (vliblist >= vaddr && vliblist < vaddr + filesz) \
- liblistoff = offset + (vliblist - vaddr); \
+ if (vgnuhash >= vaddr && vgnuhash < vaddr + filesz) \
+ gnuhashoff = offset + (vgnuhash - vaddr); \
} \
\
/* Finally walk the symbol table. This should generally be fast as \
@@ -137,47 +141,81 @@ static bool sb_check_exec(const char *filename, char *const argv[])
*/ \
if (symoff && stroff) { \
/* Nowhere is the # of symbols recorded, or the size of the symbol \
- * table. Instead, we do what glibc does: use the sysv hash table \
- * if it exists, else assume that the string table always directly \
+ * table. Instead, we do what glibc does: use the gnu or sysv hash \
+ * table if it exists, else assume that the string table always directly \
* follows the symbol table. This seems like a poor assumption to \
* make, but glibc has gotten by this long. See determine_info in \
* glibc's elf/dl-addr.c. \
* \
- * Turns out prelink will violate that assumption. Fortunately it \
- * will insert its liblist at the same location all the time -- it \
- * replaces the string table with its liblist table. \
- * \
- * Long term, we should behave the same as glibc and walk the gnu \
- * hash table first before falling back to the raw symbol table. \
- * \
* We don't sanity check the ranges here as you aren't executing \
* corrupt programs in the sandbox. \
*/ \
sym = (void *)(elf + symoff); \
- if (vhash) { \
- /* Hash entries are always 32-bits. */ \
- uint32_t *hashes = (void *)(elf + hashoff); \
- symend = sym + hashes[1]; \
- } else if (vliblist) \
- symend = (void *)(elf + liblistoff); \
- else \
- symend = (void *)(elf + stroff); \
- \
- while (sym < symend) { \
- char *symname = (void *)(elf + stroff + sym->st_name); \
- if (ELF##n##_ST_VISIBILITY(sym->st_other) == STV_DEFAULT && \
- sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE && \
- sym->st_name && \
- /* Minor optimization to avoid strcmp. */ \
- symname[0] == '_' && symname[1] == '_') { \
- /* Blacklist internal C library symbols. */ \
- for (i = 0; i < ARRAY_SIZE(libc_alloc_syms); ++i) \
- if (!strcmp(symname, libc_alloc_syms[i])) { \
- run_in_process = false; \
- goto use_trace; \
- } \
+ if (vgnuhash) { \
+ uint32_t *hash32 = (void *)(elf + gnuhashoff); \
+ /* use glibc's elf/dl-lookup.c:_dl_setup_hash() as a reference */ \
+ /* DT_GNU_HASH header: */ \
+ uint32_t nbuckets = *hash32++; \
+ uint32_t symbias = *hash32++; \
+ uint32_t bitmask_nwords = *hash32++; \
+ hash32++; /* gnu_shift */ \
+ hash32 += n / 32 * bitmask_nwords; /* gnu_bitmask */ \
+ uint32_t *gnu_buckets = hash32; \
+ hash32 += nbuckets; \
+ uint32_t *gnu_chain_zero = hash32 - symbias; \
+ \
+ uint32_t bucket; \
+ \
+ for (bucket = 0; bucket < nbuckets; bucket++) { \
+ uint32_t symndx = gnu_buckets[bucket]; \
+ if (symndx != 0) { \
+ const uint32_t *hasharr = &gnu_chain_zero[symndx]; \
+ do { \
+ Elf##n##_Sym * s = &sym[symndx]; \
+ \
+ /* keep in sync with 'vhash' case */ \
+ char *symname = (void *)(elf + stroff + s->st_name); \
+ if (ELF##n##_ST_VISIBILITY(s->st_other) == STV_DEFAULT && \
+ s->st_shndx != SHN_UNDEF && s->st_shndx < SHN_LORESERVE && \
+ s->st_name && \
+ /* Minor optimization to avoid strcmp. */ \
+ symname[0] == '_' && symname[1] == '_') { \
+ /* Blacklist internal C library symbols. */ \
+ for (i = 0; i < ARRAY_SIZE(libc_alloc_syms); ++i) \
+ if (!strcmp(symname, libc_alloc_syms[i])) { \
+ run_in_process = false; \
+ goto use_trace; \
+ } \
+ } \
+ ++symndx; \
+ } while ((*hasharr++ & 1u) == 0); \
+ } \
+ } \
+ } else { \
+ if (vhash) { \
+ /* Hash entries are always 32-bits. */ \
+ uint32_t *hashes = (void *)(elf + hashoff); \
+ symend = sym + hashes[1]; \
+ } else \
+ symend = (void *)(elf + stroff); \
+ \
+ while (sym < symend) { \
+ /* keep insync with 'vgnuhash' case */ \
+ char *symname = (void *)(elf + stroff + sym->st_name); \
+ if (ELF##n##_ST_VISIBILITY(sym->st_other) == STV_DEFAULT && \
+ sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE && \
+ sym->st_name && \
+ /* Minor optimization to avoid strcmp. */ \
+ symname[0] == '_' && symname[1] == '_') { \
+ /* Blacklist internal C library symbols. */ \
+ for (i = 0; i < ARRAY_SIZE(libc_alloc_syms); ++i) \
+ if (!strcmp(symname, libc_alloc_syms[i])) { \
+ run_in_process = false; \
+ goto use_trace; \
+ } \
+ } \
+ ++sym; \
} \
- ++sym; \
} \
} \
\
@@ -204,8 +242,10 @@ static bool sb_check_exec(const char *filename, char *const argv[])
out_fd:
close(fd);
- if (do_trace)
- trace_main(filename, argv);
+ if (do_trace) {
+ sb_debug_dyn("tracing: %s\n", filename);
+ trace_main();
+ }
return run_in_process;
}
diff --git a/libsandbox/wrapper-funcs/fchmod.c b/libsandbox/wrapper-funcs/fchmod.c
new file mode 100644
index 0000000..04bfcea
--- /dev/null
+++ b/libsandbox/wrapper-funcs/fchmod.c
@@ -0,0 +1,11 @@
+/*
+ * fchmod() wrapper.
+ *
+ * Copyright 1999-2018 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+#define WRAPPER_ARGS_PROTO int fd, mode_t mode
+#define WRAPPER_ARGS fd, mode
+#define WRAPPER_SAFE() SB_SAFE_FD(fd)
+#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/fchown.c b/libsandbox/wrapper-funcs/fchown.c
new file mode 100644
index 0000000..ab79d5c
--- /dev/null
+++ b/libsandbox/wrapper-funcs/fchown.c
@@ -0,0 +1,11 @@
+/*
+ * fchown() wrapper.
+ *
+ * Copyright 1999-2018 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+#define WRAPPER_ARGS_PROTO int fd, uid_t owner, gid_t group
+#define WRAPPER_ARGS fd, owner, group
+#define WRAPPER_SAFE() SB_SAFE_FD(fd)
+#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/fopen.c b/libsandbox/wrapper-funcs/fopen.c
index ce2fdf3..5d36ffa 100644
--- a/libsandbox/wrapper-funcs/fopen.c
+++ b/libsandbox/wrapper-funcs/fopen.c
@@ -10,11 +10,6 @@
#define WRAPPER_SAFE() SB_SAFE_OPEN_CHAR(pathname, mode)
#define WRAPPER_RET_TYPE FILE *
#define WRAPPER_RET_DEFAULT NULL
-
-#ifdef SB64
-# define WRAPPER_PRE_CHECKS() sb_fopen64_pre_check(STRING_NAME, pathname, mode)
-#else
-# define WRAPPER_PRE_CHECKS() sb_fopen_pre_check(STRING_NAME, pathname, mode)
-#endif
+#define WRAPPER_PRE_CHECKS() sb_fopen_pre_check(STRING_NAME, pathname, mode)
#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/fopen64.c b/libsandbox/wrapper-funcs/fopen64.c
index 8e0cdb0..c9b42ef 100644
--- a/libsandbox/wrapper-funcs/fopen64.c
+++ b/libsandbox/wrapper-funcs/fopen64.c
@@ -5,6 +5,6 @@
* Licensed under the GPL-2
*/
-#include "__64_pre.h"
+#define sb_fopen_pre_check sb_fopen64_pre_check
#include "fopen.c"
-#include "__64_post.h"
+#undef sb_fopen_pre_check
diff --git a/libsandbox/wrapper-funcs/fopen64_pre_check.c b/libsandbox/wrapper-funcs/fopen64_pre_check.c
index 3f7a737..4dbd171 100644
--- a/libsandbox/wrapper-funcs/fopen64_pre_check.c
+++ b/libsandbox/wrapper-funcs/fopen64_pre_check.c
@@ -5,8 +5,6 @@
* Licensed under the GPL-2
*/
-#include "__64_pre.h"
#define sb_fopen_pre_check sb_fopen64_pre_check
#include "fopen_pre_check.c"
#undef sb_fopen_pre_check
-#include "__64_post.h"
diff --git a/libsandbox/wrapper-funcs/fopen_pre_check.c b/libsandbox/wrapper-funcs/fopen_pre_check.c
index 765526e..e3ed2c6 100644
--- a/libsandbox/wrapper-funcs/fopen_pre_check.c
+++ b/libsandbox/wrapper-funcs/fopen_pre_check.c
@@ -11,8 +11,7 @@ bool sb_fopen_pre_check(const char *func, const char *pathname, const char *mode
save_errno();
/* If we're trying to read, fail normally if file does not stat */
- struct stat st;
- if (-1 == stat(pathname, &st)) {
+ if (sb_exists(AT_FDCWD, pathname, 0) == -1) {
sb_debug_dyn("EARLY FAIL: %s(%s): %s\n",
func, pathname, strerror(errno));
return false;
diff --git a/libsandbox/wrapper-funcs/futimesat.c b/libsandbox/wrapper-funcs/futimesat.c
index d549e6a..bc1a966 100644
--- a/libsandbox/wrapper-funcs/futimesat.c
+++ b/libsandbox/wrapper-funcs/futimesat.c
@@ -5,7 +5,9 @@
* Licensed under the GPL-2
*/
-#define WRAPPER_ARGS_PROTO int dirfd, const char *filename, const struct timeval times[]
+#define WRAPPER_ARGS_PROTO int dirfd, const char *filename, const struct timeval times[2]
#define WRAPPER_ARGS dirfd, filename, times
-#define WRAPPER_SAFE() SB_SAFE_AT(dirfd, filename, 0)
+#ifndef WRAPPER_SAFE
+# define WRAPPER_SAFE() SB_SAFE_AT(dirfd, filename, 0)
+#endif
#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/lremovexattr.c b/libsandbox/wrapper-funcs/lremovexattr.c
new file mode 100644
index 0000000..bfcb931
--- /dev/null
+++ b/libsandbox/wrapper-funcs/lremovexattr.c
@@ -0,0 +1,11 @@
+/*
+ * lremovexattr() wrapper.
+ *
+ * Copyright 1999-2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+#define WRAPPER_ARGS_PROTO const char *path, const char *name
+#define WRAPPER_ARGS path, name
+#define WRAPPER_SAFE() SB_SAFE(path)
+#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/lsetxattr.c b/libsandbox/wrapper-funcs/lsetxattr.c
new file mode 100644
index 0000000..2369e51
--- /dev/null
+++ b/libsandbox/wrapper-funcs/lsetxattr.c
@@ -0,0 +1,11 @@
+/*
+ * setxattr() wrapper.
+ *
+ * Copyright 1999-2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+#define WRAPPER_ARGS_PROTO const char *path, const char *name, const void *value, size_t size, int flags
+#define WRAPPER_ARGS path, name, value, size, flags
+#define WRAPPER_SAFE() SB_SAFE(path)
+#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/lutimes.c b/libsandbox/wrapper-funcs/lutimes.c
index c608231..fb9ae68 100644
--- a/libsandbox/wrapper-funcs/lutimes.c
+++ b/libsandbox/wrapper-funcs/lutimes.c
@@ -5,7 +5,9 @@
* Licensed under the GPL-2
*/
-#define WRAPPER_ARGS_PROTO const char *filename, const struct timeval times[]
+#define WRAPPER_ARGS_PROTO const char *filename, const struct timeval times[2]
#define WRAPPER_ARGS filename, times
-#define WRAPPER_SAFE() SB_SAFE(filename)
+#ifndef WRAPPER_SAFE
+# define WRAPPER_SAFE() SB_SAFE(filename)
+#endif
#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/open64.c b/libsandbox/wrapper-funcs/open64.c
index 622b8ea..8b03ea8 100644
--- a/libsandbox/wrapper-funcs/open64.c
+++ b/libsandbox/wrapper-funcs/open64.c
@@ -5,6 +5,6 @@
* Licensed under the GPL-2
*/
-#include "__64_pre.h"
+#define sb_openat_pre_check sb_openat64_pre_check
#include "open.c"
-#include "__64_post.h"
+#undef sb_openat_pre_check
diff --git a/libsandbox/wrapper-funcs/openat.c b/libsandbox/wrapper-funcs/openat.c
index 846c63f..d09e63d 100644
--- a/libsandbox/wrapper-funcs/openat.c
+++ b/libsandbox/wrapper-funcs/openat.c
@@ -16,11 +16,7 @@
# define dirfd AT_FDCWD
#endif
-#ifdef SB64
-# define WRAPPER_PRE_CHECKS() sb_openat64_pre_check(STRING_NAME, pathname, dirfd, flags)
-#else
-# define WRAPPER_PRE_CHECKS() sb_openat_pre_check(STRING_NAME, pathname, dirfd, flags)
-#endif
+#define WRAPPER_PRE_CHECKS() sb_openat_pre_check(STRING_NAME, pathname, dirfd, flags)
#define WRAPPER_SAFE_POST_EXPAND \
int mode = 0; \
diff --git a/libsandbox/wrapper-funcs/openat64.c b/libsandbox/wrapper-funcs/openat64.c
index b410af2..66c2089 100644
--- a/libsandbox/wrapper-funcs/openat64.c
+++ b/libsandbox/wrapper-funcs/openat64.c
@@ -5,6 +5,6 @@
* Licensed under the GPL-2
*/
-#include "__64_pre.h"
+#define sb_openat_pre_check sb_openat64_pre_check
#include "openat.c"
-#include "__64_post.h"
+#undef sb_openat_pre_check
diff --git a/libsandbox/wrapper-funcs/openat_pre_check.c b/libsandbox/wrapper-funcs/openat_pre_check.c
deleted file mode 100644
index 5fd5eaa..0000000
--- a/libsandbox/wrapper-funcs/openat_pre_check.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * open*() pre-check.
- *
- * Copyright 1999-2012 Gentoo Foundation
- * Licensed under the GPL-2
- */
-
-bool sb_openat_pre_check(const char *func, const char *pathname, int dirfd, int flags)
-{
- /* If we're not trying to create, fail normally if
- * file does not stat
- */
- if (flags & O_CREAT)
- return true;
-
- save_errno();
-
- /* Check incoming args against common *at issues */
- char dirfd_path[SB_PATH_MAX];
- if (!sb_common_at_pre_check(func, &pathname, dirfd, dirfd_path, sizeof(dirfd_path)))
- return false;
-
- /* Doesn't exist -> skip permission checks */
- struct stat st;
- if (((flags & O_NOFOLLOW) ? lstat(pathname, &st) : stat(pathname, &st)) == -1) {
- sb_debug_dyn("EARLY FAIL: %s(%s): %s\n",
- func, pathname, strerror(errno));
- return false;
- }
-
- restore_errno();
-
- return true;
-}
diff --git a/libsandbox/wrapper-funcs/removexattr.c b/libsandbox/wrapper-funcs/removexattr.c
new file mode 100644
index 0000000..4e33fe6
--- /dev/null
+++ b/libsandbox/wrapper-funcs/removexattr.c
@@ -0,0 +1,11 @@
+/*
+ * removexattr() wrapper.
+ *
+ * Copyright 1999-2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+#define WRAPPER_ARGS_PROTO const char *path, const char *name
+#define WRAPPER_ARGS path, name
+#define WRAPPER_SAFE() SB_SAFE(path)
+#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/renameat2.c b/libsandbox/wrapper-funcs/renameat2.c
new file mode 100644
index 0000000..4a2e29b
--- /dev/null
+++ b/libsandbox/wrapper-funcs/renameat2.c
@@ -0,0 +1,11 @@
+/*
+ * renameat2() wrapper.
+ *
+ * Copyright 1999-2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+#define WRAPPER_ARGS_PROTO int olddirfd, const char *oldpath, int newdirfd, const char *newpath, unsigned int flags
+#define WRAPPER_ARGS olddirfd, oldpath, newdirfd, newpath, flags
+#define WRAPPER_SAFE() (SB_SAFE_AT(olddirfd, oldpath, 0) && SB_SAFE_AT(newdirfd, newpath, 0))
+#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/setxattr.c b/libsandbox/wrapper-funcs/setxattr.c
new file mode 100644
index 0000000..2369e51
--- /dev/null
+++ b/libsandbox/wrapper-funcs/setxattr.c
@@ -0,0 +1,11 @@
+/*
+ * setxattr() wrapper.
+ *
+ * Copyright 1999-2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+#define WRAPPER_ARGS_PROTO const char *path, const char *name, const void *value, size_t size, int flags
+#define WRAPPER_ARGS path, name, value, size, flags
+#define WRAPPER_SAFE() SB_SAFE(path)
+#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/truncate.c b/libsandbox/wrapper-funcs/truncate.c
index b0b5674..2bfbec7 100644
--- a/libsandbox/wrapper-funcs/truncate.c
+++ b/libsandbox/wrapper-funcs/truncate.c
@@ -5,7 +5,9 @@
* Licensed under the GPL-2
*/
-#define WRAPPER_ARGS_PROTO const char *path, off_t length
+#ifndef WRAPPER_ARGS_PROTO
+# define WRAPPER_ARGS_PROTO const char *path, off_t length
+#endif
#define WRAPPER_ARGS path, length
#define WRAPPER_SAFE() SB_SAFE(path)
#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/truncate64.c b/libsandbox/wrapper-funcs/truncate64.c
index a06b895..6e2266d 100644
--- a/libsandbox/wrapper-funcs/truncate64.c
+++ b/libsandbox/wrapper-funcs/truncate64.c
@@ -5,6 +5,5 @@
* Licensed under the GPL-2
*/
-#include "__64_pre.h"
+#define WRAPPER_ARGS_PROTO const char *path, off64_t length
#include "truncate.c"
-#include "__64_post.h"
diff --git a/libsandbox/wrapper-funcs/utime.c b/libsandbox/wrapper-funcs/utime.c
index f0a6814..4bbf374 100644
--- a/libsandbox/wrapper-funcs/utime.c
+++ b/libsandbox/wrapper-funcs/utime.c
@@ -7,5 +7,7 @@
#define WRAPPER_ARGS_PROTO const char *filename, const struct utimbuf *times
#define WRAPPER_ARGS filename, times
-#define WRAPPER_SAFE() SB_SAFE(filename)
+#ifndef WRAPPER_SAFE
+# define WRAPPER_SAFE() SB_SAFE(filename)
+#endif
#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/utimensat.c b/libsandbox/wrapper-funcs/utimensat.c
index e0d8ee1..3baf89c 100644
--- a/libsandbox/wrapper-funcs/utimensat.c
+++ b/libsandbox/wrapper-funcs/utimensat.c
@@ -5,7 +5,9 @@
* Licensed under the GPL-2
*/
-#define WRAPPER_ARGS_PROTO int dirfd, const char *filename, const struct timespec times[], int flags
+#define WRAPPER_ARGS_PROTO int dirfd, const char *filename, const struct timespec times[2], int flags
#define WRAPPER_ARGS dirfd, filename, times, flags
-#define WRAPPER_SAFE() SB_SAFE_AT(dirfd, filename, flags)
+#ifndef WRAPPER_SAFE
+# define WRAPPER_SAFE() SB_SAFE_AT(dirfd, filename, flags)
+#endif
#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/utimes.c b/libsandbox/wrapper-funcs/utimes.c
index c361c36..902c6f5 100644
--- a/libsandbox/wrapper-funcs/utimes.c
+++ b/libsandbox/wrapper-funcs/utimes.c
@@ -5,7 +5,9 @@
* Licensed under the GPL-2
*/
-#define WRAPPER_ARGS_PROTO const char *filename, const struct timeval times[]
+#define WRAPPER_ARGS_PROTO const char *filename, const struct timeval times[2]
#define WRAPPER_ARGS filename, times
-#define WRAPPER_SAFE() SB_SAFE(filename)
+#ifndef WRAPPER_SAFE
+# define WRAPPER_SAFE() SB_SAFE(filename)
+#endif
#include "__wrapper_simple.c"
diff --git a/libsandbox/wrapper-funcs/vfork.c b/libsandbox/wrapper-funcs/vfork.c
new file mode 100644
index 0000000..b28e74c
--- /dev/null
+++ b/libsandbox/wrapper-funcs/vfork.c
@@ -0,0 +1,28 @@
+/*
+ * vfork() wrapper.
+ *
+ * Copyright 1999-2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+/* We're only wrapping vfork() as a poor man's pthread_atfork(). That would
+ * require dedicated linkage against libpthread. So here we force the locks
+ * to a consistent state before forking.
+ *
+ * We also implement vfork() as fork() because sandbox does not meet vfork()
+ * requirements bet ween vfork()/exec("some-static-bianary") because we launch
+ * ptrace in the middle.
+ */
+
+#define WRAPPER_ARGS_PROTO
+#define WRAPPER_ARGS
+#define WRAPPER_SAFE() 0
+#define WRAPPER_PRE_CHECKS() \
+({ \
+ /* pthread_atfork(sb_lock, sb_unlock, sb_unlock); */ \
+ sb_lock(); \
+ result = sb_unwrapped_fork_DEFAULT(WRAPPER_ARGS_FULL); \
+ sb_unlock(); \
+ false; \
+})
+#include "__wrapper_simple.c"
diff --git a/libsandbox/wrappers.h b/libsandbox/wrappers.h
index bf5bf64..3237397 100644
--- a/libsandbox/wrappers.h
+++ b/libsandbox/wrappers.h
@@ -15,6 +15,8 @@
*/
#define sb_unwrapped_access sb_unwrapped_access_DEFAULT
attribute_hidden int sb_unwrapped_access (const char *, int);
+#define sb_unwrapped_faccessat sb_unwrapped_faccessat_DEFAULT
+attribute_hidden int sb_unwrapped_faccessat (int, const char *, int, int);
#define sb_unwrapped_getcwd sb_unwrapped_getcwd_DEFAULT
attribute_hidden char *sb_unwrapped_getcwd (char *, size_t);
#define sb_unwrapped_open sb_unwrapped_open_DEFAULT
diff --git a/libsbutil/Makefile b/libsbutil/Makefile
new file mode 100644
index 0000000..f5638c7
--- /dev/null
+++ b/libsbutil/Makefile
@@ -0,0 +1,4 @@
+# Helper for developers.
+all libsbutil libsbutil.la: libsbutil/libsbutil.la ;
+clean: ; rm -f *.o *.l[ao] .libs/*
+%: ; $(MAKE) -C .. $@
diff --git a/libsbutil/Makefile.am b/libsbutil/Makefile.am
deleted file mode 100644
index 684d126..0000000
--- a/libsbutil/Makefile.am
+++ /dev/null
@@ -1,70 +0,0 @@
-AUTOMAKE_OPTIONS = foreign
-
-AM_CPPFLAGS = \
- -I$(top_srcdir) \
- -I$(srcdir)/include \
- $(SANDBOX_DEFINES)
-
-LOCAL_INCLUDES = $(top_srcdir)/localdecls.h
-
-noinst_LTLIBRARIES = libsbutil.la
-
-libsbutil_la_LDFLAGS = -no-undefined
-libsbutil_la_SOURCES = \
- sbutil.h \
- get_sandbox_conf.c \
- get_sandbox_confd.c \
- get_sandbox_lib.c \
- get_sandbox_rc.c \
- get_sandbox_log.c \
- get_tmp_dir.c \
- environment.c \
- sb_backtrace.c \
- sb_efuncs.c \
- sb_gdb.c \
- sb_open.c \
- sb_read.c \
- sb_write.c \
- sb_write_fd.c \
- sb_close.c \
- sb_printf.c \
- sb_proc.c \
- sb_memory.c \
- include/rcscripts/rcutil.h \
- include/rcscripts/util/str_list.h \
- include/rcscripts/util/debug.h \
- src/debug.c \
- include/rcscripts/util/string.h \
- src/string.c \
- include/rcscripts/util/file.h \
- src/file.c \
- include/rcscripts/util/config.h \
- src/config.c \
- include/rcscripts/util/dynbuf.h \
- src/dynbuf.c \
- gnulib/areadlink.h \
- gnulib/areadlink-with-size.c \
- gnulib/bitrotate.c \
- gnulib/bitrotate.h \
- gnulib/canonicalize.c \
- gnulib/canonicalize.h \
- gnulib/careadlinkat.h \
- gnulib/dosname.h \
- gnulib/file-set.c \
- gnulib/file-set.h \
- gnulib/gl-inline.h \
- gnulib/glue.h \
- gnulib/hash.c \
- gnulib/hash.h \
- gnulib/hash-pjw.c \
- gnulib/hash-pjw.h \
- gnulib/hash-triple.c \
- gnulib/hash-triple.h \
- gnulib/pathmax.h \
- gnulib/same-inode.h \
- gnulib/xalloc.h \
- gnulib/xalloc-oversized.h \
- gnulib/xgetcwd.h \
- $(LOCAL_INCLUDES)
-
-EXTRA_DIST = headers.h
diff --git a/libsbutil/get_sandbox_conf.c b/libsbutil/get_sandbox_conf.c
index af0140e..1178f8a 100644
--- a/libsbutil/get_sandbox_conf.c
+++ b/libsbutil/get_sandbox_conf.c
@@ -19,6 +19,7 @@ char *get_sandbox_conf(void)
save_errno();
if (is_env_on(ENV_SANDBOX_TESTING)) {
char *abs = getenv("abs_top_srcdir");
+ sb_assert(abs != NULL);
ret = xmalloc(strlen(abs) + strlen(LOCAL_SANDBOX_CONF_FILE) + 1);
sprintf(ret, "%s%s", abs, LOCAL_SANDBOX_CONF_FILE);
}
diff --git a/libsbutil/headers.h b/libsbutil/headers.h
deleted file mode 100644
index 7fcc3b2..0000000
--- a/libsbutil/headers.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../headers.h"
diff --git a/libsbutil/include/rcscripts/util/file.h b/libsbutil/include/rcscripts/util/file.h
index 197f211..8bbde00 100644
--- a/libsbutil/include/rcscripts/util/file.h
+++ b/libsbutil/include/rcscripts/util/file.h
@@ -23,7 +23,7 @@ bool rc_is_dir (const char *pathname, bool follow_link);
/* The following functions do not care about errors - it only returns
* the size/mtime of 'pathname' if it exists, and is the type requested,
* or else 0. */
-off_t rc_get_size (const char *pathname, bool follow_link);
+off64_t rc_get_size (const char *pathname, bool follow_link);
/* The following return a pointer on success, or NULL with errno set on error.
* If it returned NULL, but errno is not set, then there was no error, but
diff --git a/libsbutil/local.mk b/libsbutil/local.mk
new file mode 100644
index 0000000..1cb5de7
--- /dev/null
+++ b/libsbutil/local.mk
@@ -0,0 +1,64 @@
+noinst_LTLIBRARIES += %D%/libsbutil.la
+
+%C%_libsbutil_la_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir)/%D% \
+ -I$(top_srcdir)/%D%/include
+%C%_libsbutil_la_LDFLAGS = -no-undefined
+%C%_libsbutil_la_SOURCES = \
+ %D%/sbutil.h \
+ %D%/get_sandbox_conf.c \
+ %D%/get_sandbox_confd.c \
+ %D%/get_sandbox_lib.c \
+ %D%/get_sandbox_rc.c \
+ %D%/get_sandbox_log.c \
+ %D%/get_tmp_dir.c \
+ %D%/environment.c \
+ %D%/sb_backtrace.c \
+ %D%/sb_efuncs.c \
+ %D%/sb_exists.c \
+ %D%/sb_gdb.c \
+ %D%/sb_method.c \
+ %D%/sb_open.c \
+ %D%/sb_read.c \
+ %D%/sb_write.c \
+ %D%/sb_write_fd.c \
+ %D%/sb_close.c \
+ %D%/sb_printf.c \
+ %D%/sb_proc.c \
+ %D%/sb_memory.c \
+ %D%/include/rcscripts/rcutil.h \
+ %D%/include/rcscripts/util/str_list.h \
+ %D%/include/rcscripts/util/debug.h \
+ %D%/src/debug.c \
+ %D%/include/rcscripts/util/string.h \
+ %D%/src/string.c \
+ %D%/include/rcscripts/util/file.h \
+ %D%/src/file.c \
+ %D%/include/rcscripts/util/config.h \
+ %D%/src/config.c \
+ %D%/include/rcscripts/util/dynbuf.h \
+ %D%/src/dynbuf.c \
+ %D%/gnulib/areadlink.h \
+ %D%/gnulib/areadlink-with-size.c \
+ %D%/gnulib/bitrotate.c \
+ %D%/gnulib/bitrotate.h \
+ %D%/gnulib/canonicalize.c \
+ %D%/gnulib/canonicalize.h \
+ %D%/gnulib/careadlinkat.h \
+ %D%/gnulib/dosname.h \
+ %D%/gnulib/file-set.c \
+ %D%/gnulib/file-set.h \
+ %D%/gnulib/gl-inline.h \
+ %D%/gnulib/glue.h \
+ %D%/gnulib/hash.c \
+ %D%/gnulib/hash.h \
+ %D%/gnulib/hash-pjw.c \
+ %D%/gnulib/hash-pjw.h \
+ %D%/gnulib/hash-triple.c \
+ %D%/gnulib/hash-triple.h \
+ %D%/gnulib/pathmax.h \
+ %D%/gnulib/same-inode.h \
+ %D%/gnulib/xalloc.h \
+ %D%/gnulib/xalloc-oversized.h \
+ %D%/gnulib/xgetcwd.h
diff --git a/libsbutil/sb_close.c b/libsbutil/sb_close.c
index 5379197..113deab 100644
--- a/libsbutil/sb_close.c
+++ b/libsbutil/sb_close.c
@@ -34,7 +34,7 @@ int sb_close(int fd)
void sb_close_all_fds(void)
{
DIR *dirp;
- struct dirent *de;
+ struct dirent64 *de;
int dfd, fd;
const char *fd_dir = sb_get_fd_dir();
@@ -43,7 +43,7 @@ void sb_close_all_fds(void)
sb_ebort("could not process %s\n", fd_dir);
dfd = dirfd(dirp);
- while ((de = readdir(dirp)) != NULL) {
+ while ((de = readdir64(dirp)) != NULL) {
if (de->d_name[0] == '.')
continue;
fd = atoi(de->d_name);
diff --git a/libsbutil/sb_exists.c b/libsbutil/sb_exists.c
new file mode 100644
index 0000000..c2171fe
--- /dev/null
+++ b/libsbutil/sb_exists.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2023 Gentoo Authors
+ * Distributed under the terms of the GNU General Public License v2
+ */
+
+#include "headers.h"
+#include "sbutil.h"
+
+/* Wrapper for faccessat to work around buggy behavior on musl */
+int sb_exists(int dirfd, const char *pathname, int flags)
+{
+ struct stat64 buf;
+
+ if (sbio_faccessat(dirfd, pathname, F_OK, flags|AT_EACCESS) == 0)
+ return 0;
+
+ /* musl's faccessat gives EINVAL when the kernel does not support
+ * faccessat2 and AT_SYMLINK_NOFOLLOW is set.
+ * https://www.openwall.com/lists/musl/2023/06/19/1 */
+ if (errno != EINVAL)
+ return -1;
+
+ return fstatat64(dirfd, pathname, &buf, flags);
+}
diff --git a/libsbutil/sb_method.c b/libsbutil/sb_method.c
new file mode 100644
index 0000000..b2d62a7
--- /dev/null
+++ b/libsbutil/sb_method.c
@@ -0,0 +1,34 @@
+/*
+ * sb_method.c
+ *
+ * Util functions for sandbox method settings.
+ *
+ * Copyright 2021 Gentoo Foundation
+ * Licensed under the GPL-2
+ */
+
+#include "headers.h"
+#include "sbutil.h"
+
+sandbox_method_t parse_sandbox_method(const char *method)
+{
+ if (method == NULL || streq(method, "") || streq(method, "any"))
+ return SANDBOX_METHOD_ANY;
+
+ if (streq(method, "preload"))
+ return SANDBOX_METHOD_PRELOAD;
+
+ return SANDBOX_METHOD_ANY;
+}
+
+const char *str_sandbox_method(sandbox_method_t method)
+{
+ switch (method) {
+ case SANDBOX_METHOD_PRELOAD:
+ return "preload";
+ case SANDBOX_METHOD_ANY:
+ return "any";
+ default:
+ return "";
+ }
+}
diff --git a/libsbutil/sbutil.h b/libsbutil/sbutil.h
index 66c6f73..6d284f1 100644
--- a/libsbutil/sbutil.h
+++ b/libsbutil/sbutil.h
@@ -54,8 +54,11 @@
#define ENV_SANDBOX_WRITE "SANDBOX_WRITE"
#define ENV_SANDBOX_PREDICT "SANDBOX_PREDICT"
+#define ENV_SANDBOX_METHOD "SANDBOX_METHOD"
#define ENV_SANDBOX_ON "SANDBOX_ON"
+#define ENV_SANDBOX_INTRACTV "SANDBOX_INTRACTV"
+
#define ENV_SANDBOX_ACTIVE "SANDBOX_ACTIVE"
#define SANDBOX_ACTIVE "armedandready"
@@ -84,12 +87,20 @@ static inline bool is_env_var(const char *env, const char *var, size_t vlen)
return !strncmp(env, var, vlen) && env[vlen] == '=';
}
+typedef enum sandbox_method_t {
+ SANDBOX_METHOD_ANY = 0,
+ SANDBOX_METHOD_PRELOAD,
+} sandbox_method_t;
+sandbox_method_t parse_sandbox_method(const char *);
+const char *str_sandbox_method(sandbox_method_t);
+
/* proc helpers */
extern const char sb_fd_dir[];
#define sb_get_fd_dir() sb_fd_dir
const char *sb_get_cmdline(pid_t pid);
/* libsandbox need to use a wrapper for open */
+attribute_hidden extern int (*sbio_faccessat)(int, const char *, int, int);
attribute_hidden extern int (*sbio_open)(const char *, int, mode_t);
attribute_hidden extern FILE *(*sbio_popen)(const char *, const char *);
extern const char *sbio_message_path;
@@ -101,6 +112,7 @@ size_t sb_write(int fd, const void *buf, size_t count);
int sb_close(int fd);
void sb_close_all_fds(void);
int sb_copy_file_to_fd(const char *file, int ofd);
+int sb_exists(int dirfd, const char *pathname, int flags);
/* Reliable output */
__printf(1, 2) void sb_printf(const char *format, ...);
@@ -130,7 +142,14 @@ void sb_maybe_gdb(void);
#define sb_fprintf(fp, ...) sb_fdprintf(fileno(fp), __VA_ARGS__)
#define sb_vfprintf(fp, ...) sb_vfdprintf(fileno(fp), __VA_ARGS__)
-/* Memory functions */
+/*
+ * Memory functions.
+ *
+ * NB: These are wrappers around libsbutil functions that build off memory calls that we
+ * implement directly (see libsandbox/memory.c). Do not add any helpers here that cannot
+ * be mirrored in libsandbox as attempts to pass memory between the two allocators will
+ * lead to corruption & crashes.
+ */
void *__xcalloc(size_t nmemb, size_t size, const char *file, const char *func, size_t line);
void *__xmalloc(size_t size, const char *file, const char *func, size_t line);
void *__xzalloc(size_t size /*, const char *file, const char *func, size_t line */);
@@ -145,11 +164,23 @@ char *__xstrndup(const char *str, size_t size, const char *file, const char *fun
#define xstrndup(_str, _size) __xstrndup(_str, _size, __FILE__, __func__, __LINE__)
#define xalloc_die() __sb_ebort(__FILE__, __func__, __LINE__, "out of memory")
+/* string helpers */
+#define streq(s1, s2) (strcmp(s1, s2) == 0)
+
/* errno helpers */
#define save_errno() int old_errno = errno;
#define restore_errno() errno = old_errno;
#define saved_errno old_errno
+#define RETRY_EINTR(call) \
+({ \
+ long result; \
+ do { \
+ result = (call); \
+ } while (result == -1 && errno == EINTR); \
+ result; \
+})
+
#include "gnulib/canonicalize.h"
#endif /* __SBUTIL_H__ */
diff --git a/libsbutil/src/debug.c b/libsbutil/src/debug.c
index 42652a3..b901fe8 100644
--- a/libsbutil/src/debug.c
+++ b/libsbutil/src/debug.c
@@ -11,7 +11,7 @@
#include "headers.h"
#include "rcscripts/rcutil.h"
-volatile static int debug_errno = 0;
+static volatile int debug_errno = 0;
#define log_domain "sandbox"
diff --git a/libsbutil/src/file.c b/libsbutil/src/file.c
index 4542ae5..64a6f0e 100644
--- a/libsbutil/src/file.c
+++ b/libsbutil/src/file.c
@@ -15,31 +15,19 @@
bool
rc_file_exists (const char *pathname)
{
- struct stat buf;
- int retval;
-
- if (!check_str (pathname))
- return false;
-
- retval = lstat (pathname, &buf);
- if (-1 != retval)
- retval = true;
- else
- retval = false;
-
- return retval;
+ return sb_exists(AT_FDCWD, pathname, AT_SYMLINK_NOFOLLOW) == 0;
}
bool
rc_is_file (const char *pathname, bool follow_link)
{
- struct stat buf;
+ struct stat64 buf;
int retval;
if (!check_str (pathname))
return false;
- retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf);
+ retval = follow_link ? stat64 (pathname, &buf) : lstat64 (pathname, &buf);
if ((-1 != retval) && (S_ISREG (buf.st_mode)))
retval = true;
else
@@ -51,13 +39,13 @@ rc_is_file (const char *pathname, bool follow_link)
bool
rc_is_dir (const char *pathname, bool follow_link)
{
- struct stat buf;
+ struct stat64 buf;
int retval;
if (!check_str (pathname))
return false;
- retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf);
+ retval = follow_link ? stat64 (pathname, &buf) : lstat64 (pathname, &buf);
if ((-1 != retval) && (S_ISDIR (buf.st_mode)))
retval = true;
else
@@ -66,16 +54,16 @@ rc_is_dir (const char *pathname, bool follow_link)
return retval;
}
-off_t
+off64_t
rc_get_size (const char *pathname, bool follow_link)
{
- struct stat buf;
+ struct stat64 buf;
int retval;
if (!check_str (pathname))
return 0;
- retval = follow_link ? stat (pathname, &buf) : lstat (pathname, &buf);
+ retval = follow_link ? stat64 (pathname, &buf) : lstat64 (pathname, &buf);
if (-1 != retval)
retval = buf.st_size;
else
@@ -88,7 +76,7 @@ char **
rc_ls_dir (const char *pathname, bool hidden, bool sort)
{
DIR *dp;
- struct dirent *dir_entry;
+ struct dirent64 *dir_entry;
char **dirlist = NULL;
if (!check_arg_str (pathname))
@@ -114,7 +102,7 @@ rc_ls_dir (const char *pathname, bool hidden, bool sort)
{
/* Clear errno to distinguish between EOF and error */
errno = 0;
- dir_entry = readdir (dp);
+ dir_entry = readdir64 (dp);
/* Only an error if 'errno' != 0, else EOF */
if ((NULL == dir_entry) && (0 != errno))
{
@@ -196,10 +184,10 @@ error:
int
rc_file_map (const char *filename, char **buf, size_t * bufsize)
{
- struct stat stats;
+ struct stat64 stats;
int fd;
- fd = open (filename, O_RDONLY);
+ fd = open64 (filename, O_RDONLY);
if (fd < 0)
{
rc_errno_set (errno);
@@ -207,7 +195,7 @@ rc_file_map (const char *filename, char **buf, size_t * bufsize)
return -1;
}
- if (fstat (fd, &stats) < 0)
+ if (fstat64 (fd, &stats) < 0)
{
rc_errno_set (errno);
DBG_MSG ("Failed to stat file!\n");
diff --git a/localdecls.h b/localdecls.h
index ecc5856..6b727ff 100644
--- a/localdecls.h
+++ b/localdecls.h
@@ -11,9 +11,8 @@
/* take care of broken ld loading */
#if defined(__GLIBC__) && !defined(__UCLIBC__)
-# if __GLIBC__ <= 2 && __GLIBC_MINOR__ <= 2
-# define BROKEN_RTLD_NEXT
-# define LIBC 5
+# if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 2)
+# error "glibc-2.3+ required"
# endif
# if !defined(BROKEN_RTLD_NEXT)
@@ -22,14 +21,6 @@
# endif
# endif
-#else
-
-#if 0
-# if defined(__FreeBSD__)
-# define BROKEN_RTLD_NEXT
-# endif
-#endif
-
#endif
#ifdef PATH_MAX
diff --git a/m4/ax_append_compile_flags.m4 b/m4/ax_append_compile_flags.m4
deleted file mode 100644
index 5b6f1af..0000000
--- a/m4/ax_append_compile_flags.m4
+++ /dev/null
@@ -1,67 +0,0 @@
-# ============================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html
-# ============================================================================
-#
-# SYNOPSIS
-#
-# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
-#
-# DESCRIPTION
-#
-# For every FLAG1, FLAG2 it is checked whether the compiler works with the
-# flag. If it does, the flag is added FLAGS-VARIABLE
-#
-# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
-# CFLAGS) is used. During the check the flag is always added to the
-# current language's flags.
-#
-# If EXTRA-FLAGS is defined, it is added to the current language's default
-# flags (e.g. CFLAGS) when the check is done. The check is thus made with
-# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
-# force the compiler to issue an error when a bad flag is given.
-#
-# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
-#
-# NOTE: This macro depends on the AX_APPEND_FLAG and
-# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
-# AX_APPEND_LINK_FLAGS.
-#
-# LICENSE
-#
-# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation, either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program 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 General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <https://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 6
-
-AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
-[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
-AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
-for flag in $1; do
- AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4])
-done
-])dnl AX_APPEND_COMPILE_FLAGS
diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4
deleted file mode 100644
index e8c5312..0000000
--- a/m4/ax_append_flag.m4
+++ /dev/null
@@ -1,71 +0,0 @@
-# ===========================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_append_flag.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
-#
-# DESCRIPTION
-#
-# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
-# added in between.
-#
-# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
-# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
-# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
-# FLAG.
-#
-# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
-# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation, either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program 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 General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <https://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 7
-
-AC_DEFUN([AX_APPEND_FLAG],
-[dnl
-AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
-AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
-AS_VAR_SET_IF(FLAGS,[
- AS_CASE([" AS_VAR_GET(FLAGS) "],
- [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
- [
- AS_VAR_APPEND(FLAGS,[" $1"])
- AC_RUN_LOG([: FLAGS="$FLAGS"])
- ])
- ],
- [
- AS_VAR_SET(FLAGS,[$1])
- AC_RUN_LOG([: FLAGS="$FLAGS"])
- ])
-AS_VAR_POPDEF([FLAGS])dnl
-])dnl AX_APPEND_FLAG
diff --git a/m4/ax_append_link_flags.m4 b/m4/ax_append_link_flags.m4
deleted file mode 100644
index 6f7f174..0000000
--- a/m4/ax_append_link_flags.m4
+++ /dev/null
@@ -1,65 +0,0 @@
-# ===========================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_append_link_flags.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
-#
-# DESCRIPTION
-#
-# For every FLAG1, FLAG2 it is checked whether the linker works with the
-# flag. If it does, the flag is added FLAGS-VARIABLE
-#
-# If FLAGS-VARIABLE is not specified, the linker's flags (LDFLAGS) is
-# used. During the check the flag is always added to the linker's flags.
-#
-# If EXTRA-FLAGS is defined, it is added to the linker's default flags
-# when the check is done. The check is thus made with the flags: "LDFLAGS
-# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
-# issue an error when a bad flag is given.
-#
-# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
-#
-# NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG.
-# Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS.
-#
-# LICENSE
-#
-# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
-#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation, either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program 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 General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <https://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 6
-
-AC_DEFUN([AX_APPEND_LINK_FLAGS],
-[AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
-AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
-for flag in $1; do
- AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3], [$4])
-done
-])dnl AX_APPEND_LINK_FLAGS
diff --git a/m4/ax_cflags_force_c89.m4 b/m4/ax_cflags_force_c89.m4
deleted file mode 100644
index 59b33c1..0000000
--- a/m4/ax_cflags_force_c89.m4
+++ /dev/null
@@ -1,93 +0,0 @@
-# ===========================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_cflags_force_c89.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_CFLAGS_FORCE_C89 [(shellvar [,default, [A/NA]])]
-#
-# DESCRIPTION
-#
-# Try to find a compiler option that enables strict C89 mode.
-#
-# For the GNU CC compiler it will be -ansi -pedantic. The result is added
-# to the shellvar being CFLAGS by default.
-#
-# Currently this macro knows about GCC, Solaris C compiler, Digital Unix C
-# compiler, C for AIX Compiler, HP-UX C compiler, IRIX C compiler, NEC
-# SX-5 (Super-UX 10) C compiler, and Cray J90 (Unicos 10.0.0.8) C
-# compiler.
-#
-# - $1 shell-variable-to-add-to : CFLAGS
-# - $2 add-value-if-not-found : nothing
-# - $3 action-if-found : add value to shellvariable
-# - $4 action-if-not-found : nothing
-#
-# NOTE: These macros depend on AX_APPEND_FLAG.
-#
-# LICENSE
-#
-# Copyright (c) 2009 Guido U. Draheim <guidod@gmx.de>
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program 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 General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <https://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 10
-
-AC_DEFUN([AX_CFLAGS_FORCE_C89],[dnl
-AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl
-AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_force_c89])dnl
-AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for C89 mode],
-VAR,[VAR="no, unknown"
- AC_LANG_SAVE
- AC_LANG_C
- ac_save_[]FLAGS="$[]FLAGS"
-for ac_arg dnl
-in "-pedantic % -ansi -pedantic" dnl GCC
- "-xstrconst % -v -Xc" dnl Solaris C
- "-std1 % -std1" dnl Digital Unix
- " % -qlanglvl=ansi" dnl AIX
- " % -ansi -ansiE" dnl IRIX
- "+ESlit % -Aa" dnl HP-UX C
- "-Xc % -Xc" dnl NEC SX-5 (Super-UX 10)
- "-h conform % -h conform" dnl Cray C (Unicos)
- #
-do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
- AC_TRY_COMPILE([],[return 0;],
- [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
-done
- FLAGS="$ac_save_[]FLAGS"
- AC_LANG_RESTORE
-])
-AS_VAR_POPDEF([FLAGS])dnl
-AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
-case ".$VAR" in
- .ok|.ok,*) m4_ifvaln($3,$3) ;;
- .|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;;
- *) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;;
-esac
-AS_VAR_POPDEF([VAR])dnl
-])
diff --git a/m4/ax_cflags_no_writable_strings.m4 b/m4/ax_cflags_no_writable_strings.m4
deleted file mode 100644
index 48831fa..0000000
--- a/m4/ax_cflags_no_writable_strings.m4
+++ /dev/null
@@ -1,121 +0,0 @@
-# ==================================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_cflags_no_writable_strings.html
-# ==================================================================================
-#
-# SYNOPSIS
-#
-# AX_CFLAGS_NO_WRITABLE_STRINGS [(shellvar [,default, [A/NA]])]
-#
-# DESCRIPTION
-#
-# Try to find a compiler option that makes all string literals readonly.
-#
-# The sanity check is done by looking at string.h which has a set of
-# strcpy definitions that should be defined with const-modifiers to not
-# emit a warning in all so many places.
-#
-# For the GNU CC compiler it will be -fno-writable-strings -Wwrite-strings
-# The result is added to the shellvar being CFLAGS by default.
-#
-# DEFAULTS:
-#
-# - $1 shell-variable-to-add-to : CFLAGS
-# - $2 add-value-if-not-found : nothing
-# - $3 action-if-found : add value to shellvariable
-# - $4 action-if-not-found : nothing
-#
-# NOTE: These macros depend on AX_APPEND_FLAG.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program 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 General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <https://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 14
-
-AC_DEFUN([AX_FLAGS_NO_WRITABLE_STRINGS],[dnl
-AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl
-AS_VAR_PUSHDEF([VAR],[ax_cv_[]_AC_LANG_ABBREV[]flags_no_writable_strings])dnl
-AC_CACHE_CHECK([m4_ifval([$1],[$1],FLAGS) making strings readonly],
-VAR,[VAR="no, unknown"
-ac_save_[]FLAGS="$[]FLAGS"
-# IRIX C compiler:
-# -use_readonly_const is the default for IRIX C,
-# puts them into .rodata, but they are copied later.
-# need to be "-G0 -rdatashared" for strictmode but
-# I am not sure what effect that has really. - guidod
-for ac_arg dnl
-in "-pedantic -Werror % -fno-writable-strings -Wwrite-strings" dnl GCC
- "-pedantic -Werror % -fconst-strings -Wwrite-strings" dnl newer GCC
- "-pedantic % -fconst-strings %% no, const-strings is default" dnl newer GCC
- "-v -Xc % -xstrconst" dnl Solaris C - strings go into readonly segment
- "+w1 -Aa % +ESlit" dnl HP-UX C - strings go into readonly segment
- "-w0 -std1 % -readonly_strings" dnl Digital Unix - again readonly segment
- "-fullwarn -use_readonly_const %% ok, its the default" dnl IRIX C
- #
-do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
- AC_TRY_COMPILE([],[return 0;],
- [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
-done
-case ".$VAR" in
- .|.no|.no,*) ;;
- *) # sanity check - testing strcpy() from string.h
- cp config.log config.tmp
- AC_TRY_COMPILE([#include <string.h>],[
- char test[16];
- if (strcpy (test, "test")) return 1;],
- dnl the original did use test -n `$CC testprogram.c`
- [if test `diff config.log config.tmp | grep -i warning | wc -l` != 0
- then VAR="no, suppressed, string.h," ; fi],
- [VAR="no, suppressed, string.h"])
- rm config.tmp
- ;;
-esac
-FLAGS="$ac_save_[]FLAGS"
-])
-AS_VAR_POPDEF([FLAGS])dnl
-AC_REQUIRE([AX_APPEND_FLAG])
-case ".$VAR" in
- .ok|.ok,*) m4_ifvaln($3,$3) ;;
- .|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;;
- *) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;;
-esac
-AS_VAR_POPDEF([VAR])dnl
-])dnl AX_FLAGS_NO_WRITABLE_STRINGS
-
-AC_DEFUN([AX_CFLAGS_NO_WRITABLE_STRINGS],[dnl
-AC_LANG_PUSH([C])
-AX_FLAGS_NO_WRITABLE_STRINGS([$1], [$2], [$3], [$4])
-AC_LANG_POP([C])
-])
-
-AC_DEFUN([AX_CXXFLAGS_NO_WRITABLE_STRINGS],[dnl
-AC_LANG_PUSH([C++])
-AX_FLAGS_NO_WRITABLE_STRINGS([$1], [$2], [$3], [$4])
-AC_LANG_POP([C++])
-])
diff --git a/m4/ax_cflags_strict_prototypes.m4 b/m4/ax_cflags_strict_prototypes.m4
deleted file mode 100644
index 1bc5db4..0000000
--- a/m4/ax_cflags_strict_prototypes.m4
+++ /dev/null
@@ -1,118 +0,0 @@
-# ================================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_cflags_strict_prototypes.html
-# ================================================================================
-#
-# SYNOPSIS
-#
-# AX_CFLAGS_STRICT_PROTOTYPES [(shellvar [,default, [A/NA]]
-#
-# DESCRIPTION
-#
-# Try to find a compiler option that requires strict prototypes.
-#
-# The sanity check is done by looking at sys/signal.h which has a set of
-# macro-definitions SIG_DFL and SIG_IGN that are cast to the local
-# signal-handler type. If that signal-handler type is not fully qualified
-# then the system headers are not seen as strictly prototype clean.
-#
-# For the GNU CC compiler it will be -fstrict-prototypes
-# -Wstrict-prototypes The result is added to the shellvar being CFLAGS by
-# default.
-#
-# DEFAULTS:
-#
-# - $1 shell-variable-to-add-to : CFLAGS
-# - $2 add-value-if-not-found : nothing
-# - $3 action-if-found : add value to shellvariable
-# - $4 action-if-not-found : nothing
-#
-# NOTE: These macros depend on AX_APPEND_FLAG.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program 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 General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <https://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 16
-
-AC_DEFUN([AX_FLAGS_STRICT_PROTOTYPES],[dnl
-AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl
-AS_VAR_PUSHDEF([VAR],[ac_cv_[]_AC_LANG_ABBREV[]flags_strict_prototypes])dnl
-AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for strict prototypes],
-VAR,[VAR="no, unknown"
-ac_save_[]FLAGS="$[]FLAGS"
-for ac_arg dnl
-in "-pedantic -Werror % -fstrict-prototypes -Wstrict-prototypes" dnl GCC
- "-pedantic -Werror % -Wstrict-prototypes" dnl try to warn at least
- "-pedantic -Werror % -Wmissing-prototypes" dnl try to warn at least
- "-pedantic -Werror % -Werror-implicit-function-declaration" dnl
- "-pedantic -Werror % -Wimplicit-function-declaration" dnl
- "-pedantic % -Wstrict-prototypes %% no, unsupported" dnl oops
- #
-do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
- AC_TRY_COMPILE([],[return 0;],
- [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
-done
-case ".$VAR" in
- .|.no|.no,*) ;;
- *) # sanity check with signal() from sys/signal.h
- cp config.log config.tmp
- AC_TRY_COMPILE([#include <signal.h>],[
- if (signal (SIGINT, SIG_IGN) == SIG_DFL) return 1;
- if (signal (SIGINT, SIG_IGN) != SIG_DFL) return 2;],
- dnl the original did use test -n `$CC testprogram.c`
- [if test `diff config.log config.tmp | grep -i warning | wc -l` != 0
-then if test `diff config.log config.tmp | grep -i warning | wc -l` != 1
-then VAR="no, suppressed, signal.h," ; fi ; fi],
- [VAR="no, suppressed, signal.h"])
- rm config.tmp
- ;;
-esac
-FLAGS="$ac_save_[]FLAGS"
-])
-AS_VAR_POPDEF([FLAGS])dnl
-AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
-case ".$VAR" in
- .ok|.ok,*) m4_ifvaln($3,$3) ;;
- .|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;;
- *) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;;
-esac
-AS_VAR_POPDEF([VAR])dnl
-])dnl AX_FLAGS_STRICT_PROTOTYPES
-
-AC_DEFUN([AX_CFLAGS_STRICT_PROTOTYPES],[dnl
-AC_LANG_PUSH([C])
-AX_FLAGS_STRICT_PROTOTYPES([$1], [$2], [$3], [$4])
-AC_LANG_POP([C])
-])
-
-AC_DEFUN([AX_CXXFLAGS_STRICT_PROTOTYPES],[dnl
-AC_LANG_PUSH([C++])
-AX_FLAGS_STRICT_PROTOTYPES([$1], [$2], [$3], [$4])
-AC_LANG_POP([C++])
-])
diff --git a/m4/ax_cflags_warn_all.m4 b/m4/ax_cflags_warn_all.m4
index 094577e..9235a18 100644
--- a/m4/ax_cflags_warn_all.m4
+++ b/m4/ax_cflags_warn_all.m4
@@ -4,33 +4,54 @@
#
# SYNOPSIS
#
-# AX_CFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])]
-# AX_CXXFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])]
-# AX_FCFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])]
+# AX_CFLAGS_WARN_ALL [(shellvar[, default[, action-if-found[, action-if-not-found]]])]
+# AX_CXXFLAGS_WARN_ALL [(shellvar[, default[, action-if-found[, action-if-not-found]]])]
+# AX_FCFLAGS_WARN_ALL [(shellvar[, default[, action-if-found[, action-if-not-found]]])]
#
# DESCRIPTION
#
-# Try to find a compiler option that enables most reasonable warnings.
+# Specify compiler options that enable most reasonable warnings. For the
+# GNU Compiler Collection (GCC), for example, it will be "-Wall". The
+# result is added to shellvar, one of CFLAGS, CXXFLAGS or FCFLAGS if the
+# first parameter is not specified.
#
-# For the GNU compiler it will be -Wall (and -ansi -pedantic) The result
-# is added to the shellvar being CFLAGS, CXXFLAGS, or FCFLAGS by default.
+# Each of these macros accepts the following optional arguments:
#
-# Currently this macro knows about the GCC, Solaris, Digital Unix, AIX,
-# HP-UX, IRIX, NEC SX-5 (Super-UX 10), Cray J90 (Unicos 10.0.0.8), and
-# Intel compilers. For a given compiler, the Fortran flags are much more
-# experimental than their C equivalents.
+# - $1 - shellvar
+# shell variable to use (CFLAGS, CXXFLAGS or FCFLAGS if not
+# specified, depending on macro)
#
-# - $1 shell-variable-to-add-to : CFLAGS, CXXFLAGS, or FCFLAGS
-# - $2 add-value-if-not-found : nothing
-# - $3 action-if-found : add value to shellvariable
-# - $4 action-if-not-found : nothing
+# - $2 - default
+# value to use for flags if compiler vendor cannot be determined (by
+# default, "")
#
-# NOTE: These macros depend on AX_APPEND_FLAG.
+# - $3 - action-if-found
+# action to take if the compiler vendor has been successfully
+# determined (by default, add the appropriate compiler flags to
+# shellvar)
+#
+# - $4 - action-if-not-found
+# action to take if the compiler vendor has not been determined or
+# is unknown (by default, add the default flags, or "" if not
+# specified, to shellvar)
+#
+# These macros use AX_COMPILER_VENDOR to determine which flags should be
+# returned for a given compiler. Not all compilers currently have flags
+# defined for them; patches are welcome. If need be, compiler flags may
+# be made language-dependent: use a construct like the following:
+#
+# [vendor_name], [m4_if(_AC_LANG_PREFIX,[C], VAR="--relevant-c-flags",dnl
+# m4_if(_AC_LANG_PREFIX,[CXX], VAR="--relevant-c++-flags",dnl
+# m4_if(_AC_LANG_PREFIX,[FC], VAR="--relevant-fortran-flags",dnl
+# VAR="$2"; FOUND="no")))],
+#
+# Note: These macros also depend on AX_PREPEND_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2010 Rhys Ulerich <rhys.ulerich@gmail.com>
+# Copyright (c) 2018 John Zaitseff <J.Zaitseff@zap.org.au>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
@@ -58,65 +79,80 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
-#serial 16
+#serial 25
+
+AC_DEFUN([AX_FLAGS_WARN_ALL], [
+ AX_REQUIRE_DEFINED([AX_PREPEND_FLAG])dnl
+ AC_REQUIRE([AX_COMPILER_VENDOR])dnl
+
+ AS_VAR_PUSHDEF([FLAGS], [m4_default($1,_AC_LANG_PREFIX[]FLAGS)])dnl
+ AS_VAR_PUSHDEF([VAR], [ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl
+ AS_VAR_PUSHDEF([FOUND], [ac_save_[]_AC_LANG_ABBREV[]flags_warn_all_found])dnl
+
+ AC_CACHE_CHECK([FLAGS for most reasonable warnings], VAR, [
+ VAR=""
+ FOUND="yes"
+ dnl Cases are listed in the order found in ax_compiler_vendor.m4
+ AS_CASE("$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor",
+ [intel], [VAR="-w2"],
+ [ibm], [VAR="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd"],
+ [pathscale], [],
+ [clang], [VAR="-Wall"],
+ [cray], [VAR="-h msglevel 2"],
+ [fujitsu], [],
+ [sdcc], [],
+ [sx], [VAR="-pvctl[,]fullmsg"],
+ [portland], [],
+ [gnu], [VAR="-Wall"],
+ [sun], [VAR="-v"],
+ [hp], [VAR="+w1"],
+ [dec], [VAR="-verbose -w0 -warnprotos"],
+ [borland], [],
+ [comeau], [],
+ [kai], [],
+ [lcc], [],
+ [sgi], [VAR="-fullwarn"],
+ [microsoft], [],
+ [metrowerks], [],
+ [watcom], [],
+ [tcc], [],
+ [unknown], [
+ VAR="$2"
+ FOUND="no"
+ ],
+ [
+ AC_MSG_WARN([Unknown compiler vendor returned by [AX_COMPILER_VENDOR]])
+ VAR="$2"
+ FOUND="no"
+ ]
+ )
+
+ AS_IF([test "x$FOUND" = "xyes"], [dnl
+ m4_default($3, [AS_IF([test "x$VAR" != "x"], [AX_PREPEND_FLAG([$VAR], [FLAGS])])])
+ ], [dnl
+ m4_default($4, [m4_ifval($2, [AX_PREPEND_FLAG([$VAR], [FLAGS])], [true])])
+ ])dnl
+ ])dnl
-AC_DEFUN([AX_FLAGS_WARN_ALL],[dnl
-AS_VAR_PUSHDEF([FLAGS],[_AC_LANG_PREFIX[]FLAGS])dnl
-AS_VAR_PUSHDEF([VAR],[ac_cv_[]_AC_LANG_ABBREV[]flags_warn_all])dnl
-AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings],
-VAR,[VAR="no, unknown"
-ac_save_[]FLAGS="$[]FLAGS"
-for ac_arg dnl
-in "-warn all % -warn all" dnl Intel
- "-pedantic % -Wall" dnl GCC
- "-xstrconst % -v" dnl Solaris C
- "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix
- "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
- "-ansi -ansiE % -fullwarn" dnl IRIX
- "+ESlit % +w1" dnl HP-UX C
- "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10)
- "-h conform % -h msglevel 2" dnl Cray C (Unicos)
- #
-do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
- [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
-done
-FLAGS="$ac_save_[]FLAGS"
-])
-AS_VAR_POPDEF([FLAGS])dnl
-AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
-case ".$VAR" in
- .ok|.ok,*) m4_ifvaln($3,$3) ;;
- .|.no|.no,*) m4_default($4,[m4_ifval($2,[AX_APPEND_FLAG([$2], [$1])])]) ;;
- *) m4_default($3,[AX_APPEND_FLAG([$VAR], [$1])]) ;;
-esac
-AS_VAR_POPDEF([VAR])dnl
+ AS_VAR_POPDEF([FOUND])dnl
+ AS_VAR_POPDEF([VAR])dnl
+ AS_VAR_POPDEF([FLAGS])dnl
])dnl AX_FLAGS_WARN_ALL
-dnl implementation tactics:
-dnl the for-argument contains a list of options. The first part of
-dnl these does only exist to detect the compiler - usually it is
-dnl a global option to enable -ansi or -extrawarnings. All other
-dnl compilers will fail about it. That was needed since a lot of
-dnl compilers will give false positives for some option-syntax
-dnl like -Woption or -Xoption as they think of it is a pass-through
-dnl to later compile stages or something. The "%" is used as a
-dnl delimiter. A non-option comment can be given after "%%" marks
-dnl which will be shown but not added to the respective C/CXXFLAGS.
-AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl
-AC_LANG_PUSH([C])
-AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
-AC_LANG_POP([C])
-])
+AC_DEFUN([AX_CFLAGS_WARN_ALL], [dnl
+ AC_LANG_PUSH([C])
+ AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
+ AC_LANG_POP([C])
+])dnl
-AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl
-AC_LANG_PUSH([C++])
-AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
-AC_LANG_POP([C++])
-])
+AC_DEFUN([AX_CXXFLAGS_WARN_ALL], [dnl
+ AC_LANG_PUSH([C++])
+ AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
+ AC_LANG_POP([C++])
+])dnl
-AC_DEFUN([AX_FCFLAGS_WARN_ALL],[dnl
-AC_LANG_PUSH([Fortran])
-AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
-AC_LANG_POP([Fortran])
-])
+AC_DEFUN([AX_FCFLAGS_WARN_ALL], [dnl
+ AC_LANG_PUSH([Fortran])
+ AX_FLAGS_WARN_ALL([$1], [$2], [$3], [$4])
+ AC_LANG_POP([Fortran])
+])dnl
diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4
index dcabb92..bd753b3 100644
--- a/m4/ax_check_compile_flag.m4
+++ b/m4/ax_check_compile_flag.m4
@@ -29,33 +29,12 @@
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation, either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program 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 General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <https://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
-#serial 5
+#serial 6
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
diff --git a/m4/ax_check_link_flag.m4 b/m4/ax_check_link_flag.m4
index 819409a..03a30ce 100644
--- a/m4/ax_check_link_flag.m4
+++ b/m4/ax_check_link_flag.m4
@@ -29,33 +29,12 @@
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation, either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program 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 General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <https://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
-#serial 5
+#serial 6
AC_DEFUN([AX_CHECK_LINK_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
diff --git a/m4/ax_compiler_flags.m4 b/m4/ax_compiler_flags.m4
deleted file mode 100644
index ddb0456..0000000
--- a/m4/ax_compiler_flags.m4
+++ /dev/null
@@ -1,158 +0,0 @@
-# ===========================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_compiler_flags.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_COMPILER_FLAGS([CFLAGS-VARIABLE], [LDFLAGS-VARIABLE], [IS-RELEASE], [EXTRA-BASE-CFLAGS], [EXTRA-YES-CFLAGS], [UNUSED], [UNUSED], [UNUSED], [EXTRA-BASE-LDFLAGS], [EXTRA-YES-LDFLAGS], [UNUSED], [UNUSED], [UNUSED])
-#
-# DESCRIPTION
-#
-# Check for the presence of an --enable-compile-warnings option to
-# configure, defaulting to "error" in normal operation, or "yes" if
-# IS-RELEASE is equal to "yes". Return the value in the variable
-# $ax_enable_compile_warnings.
-#
-# Depending on the value of --enable-compile-warnings, different compiler
-# warnings are checked to see if they work with the current compiler and,
-# if so, are appended to CFLAGS-VARIABLE and LDFLAGS-VARIABLE. This
-# allows a consistent set of baseline compiler warnings to be used across
-# a code base, irrespective of any warnings enabled locally by individual
-# developers. By standardising the warnings used by all developers of a
-# project, the project can commit to a zero-warnings policy, using -Werror
-# to prevent compilation if new warnings are introduced. This makes
-# catching bugs which are flagged by warnings a lot easier.
-#
-# By providing a consistent --enable-compile-warnings argument across all
-# projects using this macro, continuous integration systems can easily be
-# configured the same for all projects. Automated systems or build
-# systems aimed at beginners may want to pass the --disable-Werror
-# argument to unconditionally prevent warnings being fatal.
-#
-# --enable-compile-warnings can take the values:
-#
-# * no: Base compiler warnings only; not even -Wall.
-# * yes: The above, plus a broad range of useful warnings.
-# * error: The above, plus -Werror so that all warnings are fatal.
-# Use --disable-Werror to override this and disable fatal
-# warnings.
-#
-# The set of base and enabled flags can be augmented using the
-# EXTRA-*-CFLAGS and EXTRA-*-LDFLAGS variables, which are tested and
-# appended to the output variable if --enable-compile-warnings is not
-# "no". Flags should not be disabled using these arguments, as the entire
-# point of AX_COMPILER_FLAGS is to enforce a consistent set of useful
-# compiler warnings on code, using warnings which have been chosen for low
-# false positive rates. If a compiler emits false positives for a
-# warning, a #pragma should be used in the code to disable the warning
-# locally. See:
-#
-# https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas
-#
-# The EXTRA-* variables should only be used to supply extra warning flags,
-# and not general purpose compiler flags, as they are controlled by
-# configure options such as --disable-Werror.
-#
-# IS-RELEASE can be used to disable -Werror when making a release, which
-# is useful for those hairy moments when you just want to get the release
-# done as quickly as possible. Set it to "yes" to disable -Werror. By
-# default, it uses the value of $ax_is_release, so if you are using the
-# AX_IS_RELEASE macro, there is no need to pass this parameter. For
-# example:
-#
-# AX_IS_RELEASE([git-directory])
-# AX_COMPILER_FLAGS()
-#
-# CFLAGS-VARIABLE defaults to WARN_CFLAGS, and LDFLAGS-VARIABLE defaults
-# to WARN_LDFLAGS. Both variables are AC_SUBST-ed by this macro, but must
-# be manually added to the CFLAGS and LDFLAGS variables for each target in
-# the code base.
-#
-# If C++ language support is enabled with AC_PROG_CXX, which must occur
-# before this macro in configure.ac, warning flags for the C++ compiler
-# are AC_SUBST-ed as WARN_CXXFLAGS, and must be manually added to the
-# CXXFLAGS variables for each target in the code base. EXTRA-*-CFLAGS can
-# be used to augment the base and enabled flags.
-#
-# Warning flags for g-ir-scanner (from GObject Introspection) are
-# AC_SUBST-ed as WARN_SCANNERFLAGS. This variable must be manually added
-# to the SCANNERFLAGS variable for each GIR target in the code base. If
-# extra g-ir-scanner flags need to be enabled, the AX_COMPILER_FLAGS_GIR
-# macro must be invoked manually.
-#
-# AX_COMPILER_FLAGS may add support for other tools in future, in addition
-# to the compiler and linker. No extra EXTRA-* variables will be added
-# for those tools, and all extra support will still use the single
-# --enable-compile-warnings configure option. For finer grained control
-# over the flags for individual tools, use AX_COMPILER_FLAGS_CFLAGS,
-# AX_COMPILER_FLAGS_LDFLAGS and AX_COMPILER_FLAGS_* for new tools.
-#
-# The UNUSED variables date from a previous version of this macro, and are
-# automatically appended to the preceding non-UNUSED variable. They should
-# be left empty in new uses of the macro.
-#
-# LICENSE
-#
-# Copyright (c) 2014, 2015 Philip Withnall <philip@tecnocode.co.uk>
-# Copyright (c) 2015 David King <amigadave@amigadave.com>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 14
-
-# _AX_COMPILER_FLAGS_LANG([LANGNAME])
-m4_defun([_AX_COMPILER_FLAGS_LANG],
-[m4_ifdef([_AX_COMPILER_FLAGS_LANG_]$1[_enabled], [],
- [m4_define([_AX_COMPILER_FLAGS_LANG_]$1[_enabled], [])dnl
- AX_REQUIRE_DEFINED([AX_COMPILER_FLAGS_]$1[FLAGS])])dnl
-])
-
-AC_DEFUN([AX_COMPILER_FLAGS],[
- # C support is enabled by default.
- _AX_COMPILER_FLAGS_LANG([C])
- # Only enable C++ support if AC_PROG_CXX is called. The redefinition of
- # AC_PROG_CXX is so that a fatal error is emitted if this macro is called
- # before AC_PROG_CXX, which would otherwise cause no C++ warnings to be
- # checked.
- AC_PROVIDE_IFELSE([AC_PROG_CXX],
- [_AX_COMPILER_FLAGS_LANG([CXX])],
- [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AX_COMPILER_FLAGS_LANG([CXX])])])
- AX_REQUIRE_DEFINED([AX_COMPILER_FLAGS_LDFLAGS])
-
- # Default value for IS-RELEASE is $ax_is_release
- ax_compiler_flags_is_release=m4_tolower(m4_normalize(ifelse([$3],,
- [$ax_is_release],
- [$3])))
-
- AC_ARG_ENABLE([compile-warnings],
- AS_HELP_STRING([--enable-compile-warnings=@<:@no/yes/error@:>@],
- [Enable compiler warnings and errors]),,
- [AS_IF([test "$ax_compiler_flags_is_release" = "yes"],
- [enable_compile_warnings="yes"],
- [enable_compile_warnings="error"])])
- AC_ARG_ENABLE([Werror],
- AS_HELP_STRING([--disable-Werror],
- [Unconditionally make all compiler warnings non-fatal]),,
- [enable_Werror=maybe])
-
- # Return the user's chosen warning level
- AS_IF([test "$enable_Werror" = "no" -a \
- "$enable_compile_warnings" = "error"],[
- enable_compile_warnings="yes"
- ])
-
- ax_enable_compile_warnings=$enable_compile_warnings
-
- AX_COMPILER_FLAGS_CFLAGS([$1],[$ax_compiler_flags_is_release],
- [$4],[$5 $6 $7 $8])
- m4_ifdef([_AX_COMPILER_FLAGS_LANG_CXX_enabled],
- [AX_COMPILER_FLAGS_CXXFLAGS([WARN_CXXFLAGS],
- [$ax_compiler_flags_is_release],
- [$4],[$5 $6 $7 $8])])
- AX_COMPILER_FLAGS_LDFLAGS([$2],[$ax_compiler_flags_is_release],
- [$9],[$10 $11 $12 $13])
- AX_COMPILER_FLAGS_GIR([WARN_SCANNERFLAGS],[$ax_compiler_flags_is_release])
-])dnl AX_COMPILER_FLAGS
diff --git a/m4/ax_compiler_flags_cflags.m4 b/m4/ax_compiler_flags_cflags.m4
deleted file mode 100644
index aeb16e3..0000000
--- a/m4/ax_compiler_flags_cflags.m4
+++ /dev/null
@@ -1,140 +0,0 @@
-# =============================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_compiler_flags_cflags.html
-# =============================================================================
-#
-# SYNOPSIS
-#
-# AX_COMPILER_FLAGS_CFLAGS([VARIABLE], [IS-RELEASE], [EXTRA-BASE-FLAGS], [EXTRA-YES-FLAGS])
-#
-# DESCRIPTION
-#
-# Add warning flags for the C compiler to VARIABLE, which defaults to
-# WARN_CFLAGS. VARIABLE is AC_SUBST-ed by this macro, but must be
-# manually added to the CFLAGS variable for each target in the code base.
-#
-# This macro depends on the environment set up by AX_COMPILER_FLAGS.
-# Specifically, it uses the value of $ax_enable_compile_warnings to decide
-# which flags to enable.
-#
-# LICENSE
-#
-# Copyright (c) 2014, 2015 Philip Withnall <philip@tecnocode.co.uk>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 14
-
-AC_DEFUN([AX_COMPILER_FLAGS_CFLAGS],[
- AC_REQUIRE([AC_PROG_SED])
- AX_REQUIRE_DEFINED([AX_APPEND_COMPILE_FLAGS])
- AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
- AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
-
- # Variable names
- m4_define([ax_warn_cflags_variable],
- [m4_normalize(ifelse([$1],,[WARN_CFLAGS],[$1]))])
-
- AC_LANG_PUSH([C])
-
- # Always pass -Werror=unknown-warning-option to get Clang to fail on bad
- # flags, otherwise they are always appended to the warn_cflags variable, and
- # Clang warns on them for every compilation unit.
- # If this is passed to GCC, it will explode, so the flag must be enabled
- # conditionally.
- AX_CHECK_COMPILE_FLAG([-Werror=unknown-warning-option],[
- ax_compiler_flags_test="-Werror=unknown-warning-option"
- ],[
- ax_compiler_flags_test=""
- ])
-
- # Check that -Wno-suggest-attribute=format is supported
- AX_CHECK_COMPILE_FLAG([-Wno-suggest-attribute=format],[
- ax_compiler_no_suggest_attribute_flags="-Wno-suggest-attribute=format"
- ],[
- ax_compiler_no_suggest_attribute_flags=""
- ])
-
- # Base flags
- AX_APPEND_COMPILE_FLAGS([ dnl
- -fno-strict-aliasing dnl
- $3 dnl
- ],ax_warn_cflags_variable,[$ax_compiler_flags_test])
-
- AS_IF([test "$ax_enable_compile_warnings" != "no"],[
- # "yes" flags
- AX_APPEND_COMPILE_FLAGS([ dnl
- -Wall dnl
- -Wextra dnl
- -Wundef dnl
- -Wnested-externs dnl
- -Wwrite-strings dnl
- -Wpointer-arith dnl
- -Wmissing-declarations dnl
- -Wmissing-prototypes dnl
- -Wstrict-prototypes dnl
- -Wredundant-decls dnl
- -Wno-unused-parameter dnl
- -Wno-missing-field-initializers dnl
- -Wdeclaration-after-statement dnl
- -Wformat=2 dnl
- -Wold-style-definition dnl
- -Wcast-align dnl
- -Wformat-nonliteral dnl
- -Wformat-security dnl
- -Wsign-compare dnl
- -Wstrict-aliasing dnl
- -Wshadow dnl
- -Winline dnl
- -Wpacked dnl
- -Wmissing-format-attribute dnl
- -Wmissing-noreturn dnl
- -Winit-self dnl
- -Wredundant-decls dnl
- -Wmissing-include-dirs dnl
- -Wunused-but-set-variable dnl
- -Warray-bounds dnl
- -Wimplicit-function-declaration dnl
- -Wreturn-type dnl
- -Wswitch-enum dnl
- -Wswitch-default dnl
- $4 dnl
- $5 dnl
- $6 dnl
- $7 dnl
- ],ax_warn_cflags_variable,[$ax_compiler_flags_test])
- ])
- AS_IF([test "$ax_enable_compile_warnings" = "error"],[
- # "error" flags; -Werror has to be appended unconditionally because
- # it's not possible to test for
- #
- # suggest-attribute=format is disabled because it gives too many false
- # positives
- AX_APPEND_FLAG([-Werror],ax_warn_cflags_variable)
-
- AX_APPEND_COMPILE_FLAGS([ dnl
- [$ax_compiler_no_suggest_attribute_flags] dnl
- ],ax_warn_cflags_variable,[$ax_compiler_flags_test])
- ])
-
- # In the flags below, when disabling specific flags, always add *both*
- # -Wno-foo and -Wno-error=foo. This fixes the situation where (for example)
- # we enable -Werror, disable a flag, and a build bot passes CFLAGS=-Wall,
- # which effectively turns that flag back on again as an error.
- for flag in $ax_warn_cflags_variable; do
- AS_CASE([$flag],
- [-Wno-*=*],[],
- [-Wno-*],[
- AX_APPEND_COMPILE_FLAGS([-Wno-error=$(AS_ECHO([$flag]) | $SED 's/^-Wno-//')],
- ax_warn_cflags_variable,
- [$ax_compiler_flags_test])
- ])
- done
-
- AC_LANG_POP([C])
-
- # Substitute the variables
- AC_SUBST(ax_warn_cflags_variable)
-])dnl AX_COMPILER_FLAGS
diff --git a/m4/ax_compiler_flags_cxxflags.m4 b/m4/ax_compiler_flags_cxxflags.m4
deleted file mode 100644
index 3067d9b..0000000
--- a/m4/ax_compiler_flags_cxxflags.m4
+++ /dev/null
@@ -1,136 +0,0 @@
-# ===============================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_compiler_flags_cxxflags.html
-# ===============================================================================
-#
-# SYNOPSIS
-#
-# AX_COMPILER_FLAGS_CXXFLAGS([VARIABLE], [IS-RELEASE], [EXTRA-BASE-FLAGS], [EXTRA-YES-FLAGS])
-#
-# DESCRIPTION
-#
-# Add warning flags for the C++ compiler to VARIABLE, which defaults to
-# WARN_CXXFLAGS. VARIABLE is AC_SUBST-ed by this macro, but must be
-# manually added to the CXXFLAGS variable for each target in the code
-# base.
-#
-# This macro depends on the environment set up by AX_COMPILER_FLAGS.
-# Specifically, it uses the value of $ax_enable_compile_warnings to decide
-# which flags to enable.
-#
-# LICENSE
-#
-# Copyright (c) 2015 David King <amigadave@amigadave.com>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 10
-
-AC_DEFUN([AX_COMPILER_FLAGS_CXXFLAGS],[
- AC_REQUIRE([AC_PROG_SED])
- AX_REQUIRE_DEFINED([AX_APPEND_COMPILE_FLAGS])
- AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
- AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
-
- # Variable names
- m4_define([ax_warn_cxxflags_variable],
- [m4_normalize(ifelse([$1],,[WARN_CXXFLAGS],[$1]))])
-
- AC_LANG_PUSH([C++])
-
- # Always pass -Werror=unknown-warning-option to get Clang to fail on bad
- # flags, otherwise they are always appended to the warn_cxxflags variable,
- # and Clang warns on them for every compilation unit.
- # If this is passed to GCC, it will explode, so the flag must be enabled
- # conditionally.
- AX_CHECK_COMPILE_FLAG([-Werror=unknown-warning-option],[
- ax_compiler_flags_test="-Werror=unknown-warning-option"
- ],[
- ax_compiler_flags_test=""
- ])
-
- # Check that -Wno-suggest-attribute=format is supported
- AX_CHECK_COMPILE_FLAG([-Wno-suggest-attribute=format],[
- ax_compiler_no_suggest_attribute_flags="-Wno-suggest-attribute=format"
- ],[
- ax_compiler_no_suggest_attribute_flags=""
- ])
-
- # Base flags
- AX_APPEND_COMPILE_FLAGS([ dnl
- -fno-strict-aliasing dnl
- $3 dnl
- ],ax_warn_cxxflags_variable,[$ax_compiler_flags_test])
-
- AS_IF([test "$ax_enable_compile_warnings" != "no"],[
- # "yes" flags
- AX_APPEND_COMPILE_FLAGS([ dnl
- -Wall dnl
- -Wextra dnl
- -Wundef dnl
- -Wwrite-strings dnl
- -Wpointer-arith dnl
- -Wmissing-declarations dnl
- -Wredundant-decls dnl
- -Wno-unused-parameter dnl
- -Wno-missing-field-initializers dnl
- -Wformat=2 dnl
- -Wcast-align dnl
- -Wformat-nonliteral dnl
- -Wformat-security dnl
- -Wsign-compare dnl
- -Wstrict-aliasing dnl
- -Wshadow dnl
- -Winline dnl
- -Wpacked dnl
- -Wmissing-format-attribute dnl
- -Wmissing-noreturn dnl
- -Winit-self dnl
- -Wredundant-decls dnl
- -Wmissing-include-dirs dnl
- -Wunused-but-set-variable dnl
- -Warray-bounds dnl
- -Wreturn-type dnl
- -Wno-overloaded-virtual dnl
- -Wswitch-enum dnl
- -Wswitch-default dnl
- $4 dnl
- $5 dnl
- $6 dnl
- $7 dnl
- ],ax_warn_cxxflags_variable,[$ax_compiler_flags_test])
- ])
- AS_IF([test "$ax_enable_compile_warnings" = "error"],[
- # "error" flags; -Werror has to be appended unconditionally because
- # it's not possible to test for
- #
- # suggest-attribute=format is disabled because it gives too many false
- # positives
- AX_APPEND_FLAG([-Werror],ax_warn_cxxflags_variable)
-
- AX_APPEND_COMPILE_FLAGS([ dnl
- [$ax_compiler_no_suggest_attribute_flags] dnl
- ],ax_warn_cxxflags_variable,[$ax_compiler_flags_test])
- ])
-
- # In the flags below, when disabling specific flags, always add *both*
- # -Wno-foo and -Wno-error=foo. This fixes the situation where (for example)
- # we enable -Werror, disable a flag, and a build bot passes CXXFLAGS=-Wall,
- # which effectively turns that flag back on again as an error.
- for flag in $ax_warn_cxxflags_variable; do
- AS_CASE([$flag],
- [-Wno-*=*],[],
- [-Wno-*],[
- AX_APPEND_COMPILE_FLAGS([-Wno-error=$(AS_ECHO([$flag]) | $SED 's/^-Wno-//')],
- ax_warn_cxxflags_variable,
- [$ax_compiler_flags_test])
- ])
- done
-
- AC_LANG_POP([C++])
-
- # Substitute the variables
- AC_SUBST(ax_warn_cxxflags_variable)
-])dnl AX_COMPILER_FLAGS_CXXFLAGS
diff --git a/m4/ax_compiler_flags_gir.m4 b/m4/ax_compiler_flags_gir.m4
deleted file mode 100644
index 5b4924a..0000000
--- a/m4/ax_compiler_flags_gir.m4
+++ /dev/null
@@ -1,60 +0,0 @@
-# ===========================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_compiler_flags_gir.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_COMPILER_FLAGS_GIR([VARIABLE], [IS-RELEASE], [EXTRA-BASE-FLAGS], [EXTRA-YES-FLAGS])
-#
-# DESCRIPTION
-#
-# Add warning flags for the g-ir-scanner (from GObject Introspection) to
-# VARIABLE, which defaults to WARN_SCANNERFLAGS. VARIABLE is AC_SUBST-ed
-# by this macro, but must be manually added to the SCANNERFLAGS variable
-# for each GIR target in the code base.
-#
-# This macro depends on the environment set up by AX_COMPILER_FLAGS.
-# Specifically, it uses the value of $ax_enable_compile_warnings to decide
-# which flags to enable.
-#
-# LICENSE
-#
-# Copyright (c) 2015 Philip Withnall <philip@tecnocode.co.uk>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 6
-
-AC_DEFUN([AX_COMPILER_FLAGS_GIR],[
- AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
-
- # Variable names
- m4_define([ax_warn_scannerflags_variable],
- [m4_normalize(ifelse([$1],,[WARN_SCANNERFLAGS],[$1]))])
-
- # Base flags
- AX_APPEND_FLAG([$3],ax_warn_scannerflags_variable)
-
- AS_IF([test "$ax_enable_compile_warnings" != "no"],[
- # "yes" flags
- AX_APPEND_FLAG([ dnl
- --warn-all dnl
- $4 dnl
- $5 dnl
- $6 dnl
- $7 dnl
- ],ax_warn_scannerflags_variable)
- ])
- AS_IF([test "$ax_enable_compile_warnings" = "error"],[
- # "error" flags
- AX_APPEND_FLAG([ dnl
- --warn-error dnl
- ],ax_warn_scannerflags_variable)
- ])
-
- # Substitute the variables
- AC_SUBST(ax_warn_scannerflags_variable)
-])dnl AX_COMPILER_FLAGS
diff --git a/m4/ax_compiler_flags_ldflags.m4 b/m4/ax_compiler_flags_ldflags.m4
deleted file mode 100644
index 842e329..0000000
--- a/m4/ax_compiler_flags_ldflags.m4
+++ /dev/null
@@ -1,92 +0,0 @@
-# ==============================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_compiler_flags_ldflags.html
-# ==============================================================================
-#
-# SYNOPSIS
-#
-# AX_COMPILER_FLAGS_LDFLAGS([VARIABLE], [IS-RELEASE], [EXTRA-BASE-FLAGS], [EXTRA-YES-FLAGS])
-#
-# DESCRIPTION
-#
-# Add warning flags for the linker to VARIABLE, which defaults to
-# WARN_LDFLAGS. VARIABLE is AC_SUBST-ed by this macro, but must be
-# manually added to the LDFLAGS variable for each target in the code base.
-#
-# This macro depends on the environment set up by AX_COMPILER_FLAGS.
-# Specifically, it uses the value of $ax_enable_compile_warnings to decide
-# which flags to enable.
-#
-# LICENSE
-#
-# Copyright (c) 2014, 2015 Philip Withnall <philip@tecnocode.co.uk>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 8
-
-AC_DEFUN([AX_COMPILER_FLAGS_LDFLAGS],[
- AX_REQUIRE_DEFINED([AX_APPEND_LINK_FLAGS])
- AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
- AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
- AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
-
- # Variable names
- m4_define([ax_warn_ldflags_variable],
- [m4_normalize(ifelse([$1],,[WARN_LDFLAGS],[$1]))])
-
- # Always pass -Werror=unknown-warning-option to get Clang to fail on bad
- # flags, otherwise they are always appended to the warn_ldflags variable,
- # and Clang warns on them for every compilation unit.
- # If this is passed to GCC, it will explode, so the flag must be enabled
- # conditionally.
- AX_CHECK_COMPILE_FLAG([-Werror=unknown-warning-option],[
- ax_compiler_flags_test="-Werror=unknown-warning-option"
- ],[
- ax_compiler_flags_test=""
- ])
-
- # macOS linker does not have --as-needed
- AX_CHECK_LINK_FLAG([-Wl,--no-as-needed], [
- ax_compiler_flags_as_needed_option="-Wl,--no-as-needed"
- ], [
- ax_compiler_flags_as_needed_option=""
- ])
-
- # macOS linker speaks with a different accent
- ax_compiler_flags_fatal_warnings_option=""
- AX_CHECK_LINK_FLAG([-Wl,--fatal-warnings], [
- ax_compiler_flags_fatal_warnings_option="-Wl,--fatal-warnings"
- ])
- AX_CHECK_LINK_FLAG([-Wl,-fatal_warnings], [
- ax_compiler_flags_fatal_warnings_option="-Wl,-fatal_warnings"
- ])
-
- # Base flags
- AX_APPEND_LINK_FLAGS([ dnl
- $ax_compiler_flags_as_needed_option dnl
- $3 dnl
- ],ax_warn_ldflags_variable,[$ax_compiler_flags_test])
-
- AS_IF([test "$ax_enable_compile_warnings" != "no"],[
- # "yes" flags
- AX_APPEND_LINK_FLAGS([$4 $5 $6 $7],
- ax_warn_ldflags_variable,
- [$ax_compiler_flags_test])
- ])
- AS_IF([test "$ax_enable_compile_warnings" = "error"],[
- # "error" flags; -Werror has to be appended unconditionally because
- # it's not possible to test for
- #
- # suggest-attribute=format is disabled because it gives too many false
- # positives
- AX_APPEND_LINK_FLAGS([ dnl
- $ax_compiler_flags_fatal_warnings_option dnl
- ],ax_warn_ldflags_variable,[$ax_compiler_flags_test])
- ])
-
- # Substitute the variables
- AC_SUBST(ax_warn_ldflags_variable)
-])dnl AX_COMPILER_FLAGS
diff --git a/m4/ax_compiler_vendor.m4 b/m4/ax_compiler_vendor.m4
new file mode 100644
index 0000000..039f99d
--- /dev/null
+++ b/m4/ax_compiler_vendor.m4
@@ -0,0 +1,119 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_COMPILER_VENDOR
+#
+# DESCRIPTION
+#
+# Determine the vendor of the C, C++ or Fortran compiler. The vendor is
+# returned in the cache variable $ax_cv_c_compiler_vendor for C,
+# $ax_cv_cxx_compiler_vendor for C++ or $ax_cv_fc_compiler_vendor for
+# (modern) Fortran. The value is one of "intel", "ibm", "pathscale",
+# "clang" (LLVM), "cray", "fujitsu", "sdcc", "sx", "nvhpc" (NVIDIA HPC
+# Compiler), "portland" (PGI), "gnu" (GCC), "sun" (Oracle Developer
+# Studio), "hp", "dec", "borland", "comeau", "kai", "lcc", "sgi",
+# "microsoft", "metrowerks", "watcom", "tcc" (Tiny CC) or "unknown" (if
+# the compiler cannot be determined).
+#
+# To check for a Fortran compiler, you must first call AC_FC_PP_SRCEXT
+# with an appropriate preprocessor-enabled extension. For example:
+#
+# AC_LANG_PUSH([Fortran])
+# AC_PROG_FC
+# AC_FC_PP_SRCEXT([F])
+# AX_COMPILER_VENDOR
+# AC_LANG_POP([Fortran])
+#
+# LICENSE
+#
+# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
+# Copyright (c) 2008 Matteo Frigo
+# Copyright (c) 2018-19 John Zaitseff <J.Zaitseff@zap.org.au>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program 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 General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 32
+
+AC_DEFUN([AX_COMPILER_VENDOR], [dnl
+ AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, [dnl
+ dnl If you modify this list of vendors, please add similar support
+ dnl to ax_compiler_version.m4 if at all possible.
+ dnl
+ dnl Note: Do NOT check for GCC first since some other compilers
+ dnl define __GNUC__ to remain compatible with it. Compilers that
+ dnl are very slow to start (such as Intel) are listed first.
+
+ vendors="
+ intel: __ICC,__ECC,__INTEL_COMPILER
+ ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__,__ibmxl__
+ pathscale: __PATHCC__,__PATHSCALE__
+ clang: __clang__
+ cray: _CRAYC
+ fujitsu: __FUJITSU
+ sdcc: SDCC,__SDCC
+ sx: _SX
+ nvhpc: __NVCOMPILER
+ portland: __PGI
+ gnu: __GNUC__
+ sun: __SUNPRO_C,__SUNPRO_CC,__SUNPRO_F90,__SUNPRO_F95
+ hp: __HP_cc,__HP_aCC
+ dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER
+ borland: __BORLANDC__,__CODEGEARC__,__TURBOC__
+ comeau: __COMO__
+ kai: __KCC
+ lcc: __LCC__
+ sgi: __sgi,sgi
+ microsoft: _MSC_VER
+ metrowerks: __MWERKS__
+ watcom: __WATCOMC__
+ tcc: __TINYC__
+ unknown: UNKNOWN
+ "
+ for ventest in $vendors; do
+ case $ventest in
+ *:)
+ vendor=$ventest
+ continue
+ ;;
+ *)
+ vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")"
+ ;;
+ esac
+
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[
+#if !($vencpp)
+ thisisanerror;
+#endif
+ ]])], [break])
+ done
+
+ ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1`
+ ])
+])dnl
diff --git a/m4/ax_prepend_flag.m4 b/m4/ax_prepend_flag.m4
new file mode 100644
index 0000000..adac8c5
--- /dev/null
+++ b/m4/ax_prepend_flag.m4
@@ -0,0 +1,51 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_prepend_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_PREPEND_FLAG(FLAG, [FLAGS-VARIABLE])
+#
+# DESCRIPTION
+#
+# FLAG is added to the front of the FLAGS-VARIABLE shell variable, with a
+# space added in between.
+#
+# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
+# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
+# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
+# FLAG.
+#
+# NOTE: Implementation based on AX_APPEND_FLAG.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+# Copyright (c) 2018 John Zaitseff <J.Zaitseff@zap.org.au>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 2
+
+AC_DEFUN([AX_PREPEND_FLAG],
+[dnl
+AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
+AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
+AS_VAR_SET_IF(FLAGS,[
+ AS_CASE([" AS_VAR_GET(FLAGS) "],
+ [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
+ [
+ FLAGS="$1 $FLAGS"
+ AC_RUN_LOG([: FLAGS="$FLAGS"])
+ ])
+ ],
+ [
+ AS_VAR_SET(FLAGS,[$1])
+ AC_RUN_LOG([: FLAGS="$FLAGS"])
+ ])
+AS_VAR_POPDEF([FLAGS])dnl
+])dnl AX_PREPEND_FLAG
diff --git a/scripts/gen_symbol_header.awk b/scripts/gen_symbol_header.awk
index c9af7f9..0180f6c 100644
--- a/scripts/gen_symbol_header.awk
+++ b/scripts/gen_symbol_header.awk
@@ -1,5 +1,21 @@
+# Read the symbols list and create regexs to use for processing readelf output.
BEGIN {
- COUNT = split(" " SYMBOLS_LIST, SYMBOLS);
+ COUNT = 0;
+
+ sym_regex = "";
+ while ((getline line < SYMBOLS_FILE) > 0) {
+ if (line ~ /^ *#/ || line ~ /^$/)
+ continue;
+ split(line, fields);
+ symbol = fields[1];
+
+ SYMBOLS[++COUNT] = symbol;
+ if (sym_regex)
+ sym_regex = sym_regex "|";
+ sym_regex = sym_regex symbol;
+ }
+ SYMBOL_REGEX = "^(" sym_regex ")(@|$)";
+ WEAK_SYMBOL_REGEX = "^__(" sym_regx ")(@@|$)";
}
/^ OS\/ABI:/ {
@@ -12,73 +28,69 @@ BEGIN {
if ($0 ~ "^Symbol (.*)table '.symtab'")
nextfile;
- for (x in SYMBOLS) {
- sym_regex = "^" SYMBOLS[x] "(@|$)";
- # On x86, x86_64 and others, $8 is the symbol name, but on
- # alpha, its $10, so rather use $NF, as it should be the
- # last field
- if ($NF ~ sym_regex) {
- split($NF, symbol_array, /@|@@/);
-
- # Don't add local symbols of versioned libc's
- if (VERSIONED_LIBC && !symbol_array[2])
- continue;
-
- # We have a versioned libc
- if (symbol_array[2] && !VERSIONED_LIBC)
- VERSIONED_LIBC = 1;
-
- ADD = 1;
- # Check that we do not add duplicates
- for (y in PROCESSED_SYMBOLS) {
- if (y == $NF) {
- ADD = 0;
- break;
- }
+ # On x86, x86_64 and others, $8 is the symbol name, but on
+ # alpha, its $10, so rather use $NF, as it should be the
+ # last field
+ if ($NF ~ SYMBOL_REGEX) {
+ split($NF, symbol_array, /@|@@/);
+
+ # Don't add local symbols of versioned libc's
+ if (VERSIONED_LIBC && !symbol_array[2])
+ next;
+
+ # We have a versioned libc
+ if (symbol_array[2] && !VERSIONED_LIBC)
+ VERSIONED_LIBC = 1;
+
+ ADD = 1;
+ # Check that we do not add duplicates
+ for (y in PROCESSED_SYMBOLS) {
+ if (y == $NF) {
+ ADD = 0;
+ break;
}
+ }
- if (ADD) {
- SYMBOL_LIST[symbol_array[1]] = SYMBOL_LIST[symbol_array[1]] " " $NF;
- PROCESSED_SYMBOLS[$NF] = $NF;
- }
+ if (ADD) {
+ SYMBOL_LIST[symbol_array[1]] = SYMBOL_LIST[symbol_array[1]] " " $NF;
+ PROCESSED_SYMBOLS[$NF] = $NF;
}
+ }
- # No apparent need to handle weak __XXX symbols ... so disable
- # until we have documentation on why ...
- # If we do re-add this, need to update the `readelf` call in
- # libsandbox/ to include the -h flag again.
- continue;
-
- sym_regex = "^__" SYMBOLS[x] "(@@|$)";
- if (($5 == "WEAK") && ($NF ~ sym_regex)) {
- split($NF, symbol_array, /@@/);
-
- # Don't add local symbols of versioned libc's
- if (VERSIONED_LIBC && !symbol_array[2])
- continue;
-
- # Blacklist __getcwd on FreeBSD
- # Unleashed - May 2006
- if ((symbol_array[1] == "__getcwd") && (ABI == "FreeBSD"))
- continue;
-
- # We have a versioned libc
- if (symbol_array[2] && !VERSIONED_LIBC)
- VERSIONED_LIBC = 1;
-
- ADD = 1;
- # Check that we do not add duplicates
- for (y in PROCESSED_SYMBOLS) {
- if (y == $NF) {
- ADD = 0;
- break;
- }
+ # No apparent need to handle weak __XXX symbols ... so disable
+ # until we have documentation on why ...
+ # If we do re-add this, need to update the `readelf` call in
+ # libsandbox/ to include the -h flag again.
+ next;
+
+ if (($5 == "WEAK") && ($NF ~ WEAK_SYMBOL_REGEX)) {
+ split($NF, symbol_array, /@@/);
+
+ # Don't add local symbols of versioned libc's
+ if (VERSIONED_LIBC && !symbol_array[2])
+ next;
+
+ # Blacklist __getcwd on FreeBSD
+ # Unleashed - May 2006
+ if ((symbol_array[1] == "__getcwd") && (ABI == "FreeBSD"))
+ next;
+
+ # We have a versioned libc
+ if (symbol_array[2] && !VERSIONED_LIBC)
+ VERSIONED_LIBC = 1;
+
+ ADD = 1;
+ # Check that we do not add duplicates
+ for (y in PROCESSED_SYMBOLS) {
+ if (y == $NF) {
+ ADD = 0;
+ break;
}
+ }
- if (ADD) {
- WEAK_SYMBOLS[SYMBOLS[x]] = WEAK_SYMBOLS[SYMBOLS[x]] " " $NF;
- PROCESSED_SYMBOLS[$NF] = $NF;
- }
+ if (ADD) {
+ WEAK_SYMBOLS[SYMBOLS[x]] = WEAK_SYMBOLS[SYMBOLS[x]] " " $NF;
+ PROCESSED_SYMBOLS[$NF] = $NF;
}
}
}
@@ -86,7 +98,6 @@ BEGIN {
END {
printf("#ifndef __symbols_h\n");
printf("#define __symbols_h\n\n");
- printf("#define SB_NR_UNDEF -99999\n\n");
SB_MAX_STRING_LEN = 0
@@ -99,7 +110,7 @@ END {
SB_MAX_STRING_LEN = length(sym_index);
if (full_count == 0)
- printf("#define SB_NR_%s SB_NR_UNDEF\n", toupper(sym_index));
+ printf("#define SB_NR_%s (SB_NR_UNDEF - %i)\n", toupper(sym_index), i);
for (x in sym_full_names) {
split(sym_full_names[x], symbol_array, /@|@@/);
@@ -117,6 +128,10 @@ END {
gsub(/@|\./, "_", sym_real_name);
}
+ # Avoid libc's symbol rename via #define. musl defines aliases as:
+ # #define mkstemp64 mkstemp
+ # #define mkstemps64 mkstemps
+ printf("#undef %s\n", sym_index);
printf("#define symname_%s \"%s\"\n", sym_real_name, sym_index);
# We handle non-versioned libc's by setting symver_*
@@ -186,8 +201,6 @@ END {
}
}
- printf("#include \"wrapper-funcs/__pre_check.c\"\n");
-
printf("#define SB_MAX_STRING_LEN %i\n\n", SB_MAX_STRING_LEN);
printf("#endif /* __symbols_h */\n");
diff --git a/scripts/gen_symbol_version_map.awk b/scripts/gen_symbol_version_map.awk
index a0a43c0..661cb1d 100644
--- a/scripts/gen_symbol_version_map.awk
+++ b/scripts/gen_symbol_version_map.awk
@@ -1,5 +1,18 @@
+# Read the symbols list and create regexs to use for processing readelf output.
BEGIN {
- split(" " SYMBOLS_LIST, SYMBOLS);
+ sym_regex = "";
+ while ((getline line < SYMBOLS_FILE) > 0) {
+ if (line ~ /^ *#/ || line ~ /^$/)
+ continue;
+ split(line, fields);
+ symbol = fields[1];
+
+ if (sym_regex)
+ sym_regex = sym_regex "|";
+ sym_regex = sym_regex symbol;
+ }
+ SYMBOL_REGEX = "^(" sym_regex ")(@|$)";
+ WEAK_SYMBOL_REGEX = "^__(" sym_regx ")(@@|$)";
}
/^ OS\/ABI:/ {
@@ -17,81 +30,77 @@ BEGIN {
if ($4 != "FUNC" || $5 == "LOCAL" || $6 != "DEFAULT")
next;
- for (x in SYMBOLS) {
- sym_regex = "^" SYMBOLS[x] "(@|$)";
- # On x86, x86_64 and others, $8 is the symbol name, but on
- # alpha, its $10, so rather use $NF, as it should be the
- # last field
- if ($NF ~ sym_regex) {
- split($NF, symbol_array, /@|@@/);
+ # On x86, x86_64 and others, $8 is the symbol name, but on
+ # alpha, its $10, so rather use $NF, as it should be the
+ # last field
+ if ($NF ~ SYMBOL_REGEX) {
+ split($NF, symbol_array, /@|@@/);
- # Don't add local symbols of versioned libc's
- if (VERSIONED_LIBC && !symbol_array[2])
- continue;
+ # Don't add local symbols of versioned libc's
+ if (VERSIONED_LIBC && !symbol_array[2])
+ next;
- # Handle non-versioned libc's like uClibc ...
- if (!symbol_array[2])
- symbol_array[2] = "";
-
- # We have a versioned libc
- if (symbol_array[2] && !VERSIONED_LIBC)
- VERSIONED_LIBC = 1;
-
- ADD = 1;
- # Check that we do not add duplicates
- for (y in PROCESSED_SYMBOLS) {
- if (y == $NF) {
- ADD = 0;
- break;
- }
+ # Handle non-versioned libc's like uClibc ...
+ if (!symbol_array[2])
+ symbol_array[2] = "";
+
+ # We have a versioned libc
+ if (symbol_array[2] && !VERSIONED_LIBC)
+ VERSIONED_LIBC = 1;
+
+ ADD = 1;
+ # Check that we do not add duplicates
+ for (y in PROCESSED_SYMBOLS) {
+ if (y == $NF) {
+ ADD = 0;
+ break;
}
+ }
- if (ADD) {
- SYMBOL_LIST[symbol_array[2]] = SYMBOL_LIST[symbol_array[2]] " " symbol_array[1];
- PROCESSED_SYMBOLS[$NF] = $NF;
- }
+ if (ADD) {
+ SYMBOL_LIST[symbol_array[2]] = SYMBOL_LIST[symbol_array[2]] " " symbol_array[1];
+ PROCESSED_SYMBOLS[$NF] = $NF;
}
+ }
- # No apparent need to handle weak __XXX symbols ... so disable
- # until we have documentation on why ...
- # If we do re-add this, need to update the `readelf` call in
- # libsandbox/ to include the -h flag again.
- continue;
+ # No apparent need to handle weak __XXX symbols ... so disable
+ # until we have documentation on why ...
+ # If we do re-add this, need to update the `readelf` call in
+ # libsandbox/ to include the -h flag again.
+ next;
- sym_regex = "^__" SYMBOLS[x] "(@@|$)";
- if (($5 == "WEAK") && ($NF ~ sym_regex)) {
- split($NF, symbol_array, /@@/);
+ if (($5 == "WEAK") && ($NF ~ WEAK_SYMBOL_REGEX)) {
+ split($NF, symbol_array, /@@/);
- # Don't add local symbols of versioned libc's
- if (VERSIONED_LIBC && !symbol_array[2])
- continue;
+ # Don't add local symbols of versioned libc's
+ if (VERSIONED_LIBC && !symbol_array[2])
+ next;
- # Blacklist __getcwd on FreeBSD
- # Unleashed - May 2006
- if ((symbol_array[1] == "__getcwd") && (ABI == "FreeBSD"))
- continue;
+ # Blacklist __getcwd on FreeBSD
+ # Unleashed - May 2006
+ if ((symbol_array[1] == "__getcwd") && (ABI == "FreeBSD"))
+ next;
- # Handle non-versioned libc's like uClibc ...
- if (!symbol_array[2])
- symbol_array[2] = "";
-
- # We have a versioned libc
- if (symbol_array[2] && !VERSIONED_LIBC)
- VERSIONED_LIBC = 1;
-
- ADD = 1;
- # Check that we do not add duplicates
- for (y in PROCESSED_SYMBOLS) {
- if (y == $NF) {
- ADD = 0;
- break;
- }
+ # Handle non-versioned libc's like uClibc ...
+ if (!symbol_array[2])
+ symbol_array[2] = "";
+
+ # We have a versioned libc
+ if (symbol_array[2] && !VERSIONED_LIBC)
+ VERSIONED_LIBC = 1;
+
+ ADD = 1;
+ # Check that we do not add duplicates
+ for (y in PROCESSED_SYMBOLS) {
+ if (y == $NF) {
+ ADD = 0;
+ break;
}
+ }
- if (ADD) {
- SYMBOL_LIST[symbol_array[2]] = SYMBOL_LIST[symbol_array[2]] " " symbol_array[1];
- PROCESSED_SYMBOLS[$NF] = $NF;
- }
+ if (ADD) {
+ SYMBOL_LIST[symbol_array[2]] = SYMBOL_LIST[symbol_array[2]] " " symbol_array[1];
+ PROCESSED_SYMBOLS[$NF] = $NF;
}
}
}
diff --git a/scripts/gen_trace_header.awk b/scripts/gen_trace_header.awk
index 846294c..0bb53b1 100644
--- a/scripts/gen_trace_header.awk
+++ b/scripts/gen_trace_header.awk
@@ -1,20 +1,39 @@
+# Read the symbols list and create regexs to use for processing readelf output.
+function read_symbols() {
+ COUNT = 0;
+ while ((getline line < SYMBOLS_FILE) > 0) {
+ if (line ~ /^ *#/ || line ~ /^$/)
+ continue;
+ nfields = split(line, fields);
+ symbol = fields[1];
+ syscall = nfields > 1 ? fields[2] : symbol;
+
+ c = ++COUNT
+ SYMBOLS[c] = symbol;
+ SYSCALLS[c] = syscall;
+ }
+}
+
BEGIN {
- COUNT = split(" " SYMBOLS_LIST, SYMBOLS);
+ read_symbols();
if (MODE == "gen") {
- for (x in SYMBOLS) {
- s = SYMBOLS[x]
- print "SB_" s " = SYS_" s
+ for (x in SYSCALLS) {
+ print "SB_" SYMBOLS[x] " = SYS_" SYSCALLS[x];
}
exit(0);
}
}
-function out(name, val)
+function out(name, syscall, val)
{
- name = toupper(name)
- print "#define SB_SYS" syscall_prefix "_" name " " val;
- print "S(" name ")";
+ uname = toupper(name)
+ syscall_define = "SB_SYS" syscall_prefix "_" uname
+ print "#define " syscall_define " " val;
+ if (name == syscall)
+ print "S(" uname ")";
+ else
+ print "{ " syscall_define ", SB_NR_" uname ", \"" uname "\" },";
}
{
@@ -31,21 +50,23 @@ function out(name, val)
# a straight number or an expression (a syscall base)
sub(/^[^=]*= /, "");
- for (i = 1; i <= COUNT; ++i)
+ syscall = "<awk_script_error>";
+ for (i = 1; i <= COUNT; ++i) {
if (SYMBOLS[i] == name) {
- SYMBOLS[i] = "";
+ FOUND[i] = 1;
+ syscall = SYSCALLS[i];
break;
}
+ }
- out(name, $0);
+ out(name, syscall, $0);
}
END {
if (MODE != "gen") {
for (x in SYMBOLS) {
- s = SYMBOLS[x];
- if (s != "")
- out(s, "SB_NR_UNDEF");
+ if (!FOUND[x])
+ out(SYMBOLS[x], SYSCALLS[x], "SB_NR_UNDEF");
}
}
}
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..4b2bc35
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,4 @@
+# Helper for developers.
+all sandbox: src/sandbox ;
+clean: ; rm -f *.o *.l[ao] .libs/* sandbox
+%: ; $(MAKE) -C .. $@
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index e7aeb30..0000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,17 +0,0 @@
-AUTOMAKE_OPTIONS = foreign
-
-bin_PROGRAMS = sandbox
-
-AM_CPPFLAGS = \
- -I$(top_srcdir) \
- -I$(top_srcdir)/libsbutil \
- -I$(top_srcdir)/libsbutil/include \
- $(SANDBOX_DEFINES)
-
-sandbox_LDADD = $(top_builddir)/libsbutil/libsbutil.la $(LIBDL)
-sandbox_SOURCES = \
- environ.c \
- namespaces.c \
- options.c \
- sandbox.h \
- sandbox.c
diff --git a/src/environ.c b/src/environ.c
index 346bc26..df8595b 100644
--- a/src/environ.c
+++ b/src/environ.c
@@ -96,7 +96,7 @@ static void setup_cfg_var(const char *env_var)
* environment if not already present. */
config = rc_get_cnf_entry(sb_conf_file(), env_var, NULL);
if (NULL != config) {
- setenv(ENV_SANDBOX_VERBOSE, config, 0);
+ setenv(env_var, config, 0);
free(config);
}
}
@@ -195,6 +195,7 @@ static int setup_cfg_vars(struct sandbox_info_t *sandbox_info)
setup_cfg_var(ENV_SANDBOX_VERBOSE);
setup_cfg_var(ENV_SANDBOX_DEBUG);
setup_cfg_var(ENV_NOCOLOR);
+ setup_cfg_var(ENV_SANDBOX_METHOD);
if (-1 == setup_access_var(ENV_SANDBOX_DENY))
return -1;
@@ -207,7 +208,7 @@ static int setup_cfg_vars(struct sandbox_info_t *sandbox_info)
if (-1 == setup_access_var(ENV_SANDBOX_WRITE))
return -1;
if ((NULL == getenv(ENV_SANDBOX_WRITE)) &&
- (NULL != sandbox_info->work_dir))
+ strlen(sandbox_info->work_dir))
setenv(ENV_SANDBOX_WRITE, sandbox_info->work_dir, 1);
if (-1 == setup_access_var(ENV_SANDBOX_PREDICT))
@@ -240,7 +241,7 @@ static void sb_setenv(char ***envp, const char *name, const char *val)
/* We setup the environment child side only to prevent issues with
* setting LD_PRELOAD parent side */
-char **setup_environ(struct sandbox_info_t *sandbox_info)
+char **setup_environ(struct sandbox_info_t *sandbox_info, bool interactive)
{
int have_ld_preload = 0;
@@ -263,6 +264,7 @@ char **setup_environ(struct sandbox_info_t *sandbox_info)
unsetenv(ENV_SANDBOX_MESSAGE_PATH);
unsetenv(ENV_SANDBOX_WORKDIR);
unsetenv(ENV_SANDBOX_ACTIVE);
+ unsetenv(ENV_SANDBOX_INTRACTV);
unsetenv(ENV_BASH_ENV);
orig_ld_preload_envvar = getenv(ENV_LD_PRELOAD);
@@ -294,13 +296,18 @@ char **setup_environ(struct sandbox_info_t *sandbox_info)
sb_setenv(&new_environ, ENV_SANDBOX_LOG, sandbox_info->sandbox_log);
sb_setenv(&new_environ, ENV_SANDBOX_DEBUG_LOG, sandbox_info->sandbox_debug_log);
sb_setenv(&new_environ, ENV_SANDBOX_MESSAGE_PATH, sandbox_info->sandbox_message_path);
+ /* Is this an interactive session? */
+ if (interactive)
+ sb_setenv(&new_environ, ENV_SANDBOX_INTRACTV, "1");
/* Just set the these if not already set so that is_env_on() work */
if (!getenv(ENV_SANDBOX_VERBOSE))
sb_setenv(&new_environ, ENV_SANDBOX_VERBOSE, "1");
if (!getenv(ENV_SANDBOX_DEBUG))
- sb_setenv(&new_environ, ENV_SANDBOX_DEBUG, "0");
+ sb_setenv(&new_environ, ENV_SANDBOX_DEBUG, opt_debug ? "1" : "0");
if (!getenv(ENV_NOCOLOR))
sb_setenv(&new_environ, ENV_NOCOLOR, "no");
+ if (!getenv(ENV_SANDBOX_METHOD))
+ sb_setenv(&new_environ, ENV_SANDBOX_METHOD, "any");
/* If LD_PRELOAD was not set, set it here, else do it below */
if (!have_ld_preload)
sb_setenv(&new_environ, ENV_LD_PRELOAD, ld_preload_envvar);
diff --git a/src/local.mk b/src/local.mk
new file mode 100644
index 0000000..61877ae
--- /dev/null
+++ b/src/local.mk
@@ -0,0 +1,14 @@
+bin_PROGRAMS += %D%/sandbox
+
+%C%_sandbox_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -I$(top_srcdir)/libsbutil \
+ -I$(top_srcdir)/libsbutil/include
+
+%C%_sandbox_LDADD = libsbutil/libsbutil.la $(LIBDL)
+%C%_sandbox_SOURCES = \
+ %D%/environ.c \
+ %D%/namespaces.c \
+ %D%/options.c \
+ %D%/sandbox.h \
+ %D%/sandbox.c
diff --git a/src/namespaces.c b/src/namespaces.c
index 5be42f6..290111a 100644
--- a/src/namespaces.c
+++ b/src/namespaces.c
@@ -26,16 +26,9 @@
#define xchmod(...) sb_assert(chmod(__VA_ARGS__) == 0)
#define xsymlink(...) sb_assert(symlink(__VA_ARGS__) == 0)
-#define xasprintf(fmt, ...) \
-({ \
- int _ret = asprintf(fmt, __VA_ARGS__); \
- if (_ret == 0) \
- sb_perr("asprintf(%s) failed", #fmt); \
- _ret; \
-})
#define xfopen(path, ...) \
({ \
- FILE *_ret = fopen(path, __VA_ARGS__); \
+ FILE *_ret = fopen64(path, __VA_ARGS__); \
if (_ret == 0) \
sb_perr("fopen(%s) failed", #path); \
_ret; \
@@ -114,7 +107,7 @@ static void ns_mount_setup(void)
/* Now map in all the files/dirs we do want to expose. */
int fd;
#define bind_file(node) \
- fd = open("/dev/shm/" node, O_CREAT, 0); \
+ fd = open64("/dev/shm/" node, O_CREAT, 0); \
sb_assert(fd != -1); \
close(fd); \
xmount("/dev/" node, "/dev/shm/" node, NULL, MS_BIND, NULL)
@@ -182,6 +175,10 @@ pid_t setup_namespaces(void)
if (opt_use_ns_user)
ns_user_switch(uid, gid, 0, 0);
+#ifdef CLONE_NEWCGROUP
+ if (opt_use_ns_cgroup)
+ unshare(CLONE_NEWCGROUP);
+#endif
#ifdef CLONE_NEWIPC
if (opt_use_ns_ipc)
unshare(CLONE_NEWIPC);
@@ -190,6 +187,10 @@ pid_t setup_namespaces(void)
if (opt_use_ns_sysv)
unshare(CLONE_SYSVSEM);
#endif
+#ifdef CLONE_NEWTIME
+ if (opt_use_ns_time)
+ unshare(CLONE_NEWTIME);
+#endif
#ifdef CLONE_NEWUTS
if (opt_use_ns_uts && unshare(CLONE_NEWUTS) == 0) {
diff --git a/src/options.c b/src/options.c
index 295ee75..2105fdc 100644
--- a/src/options.c
+++ b/src/options.c
@@ -11,13 +11,17 @@
/* Setting to -1 will load defaults from the config file. */
int opt_use_namespaces = -1;
+int opt_use_ns_cgroup = -1;
int opt_use_ns_ipc = -1;
int opt_use_ns_mnt = -1;
int opt_use_ns_net = -1;
int opt_use_ns_pid = -1;
int opt_use_ns_sysv = -1;
+int opt_use_ns_time = -1;
int opt_use_ns_user = -1;
int opt_use_ns_uts = -1;
+bool opt_use_bash = false;
+int opt_debug = -1;
static const struct {
const char *name;
@@ -25,14 +29,17 @@ static const struct {
int default_val;
} config_opts[] = {
/* Default these to off until they can get more testing. */
- { "NAMESPACES_ENABLE", &opt_use_namespaces, false, },
- { "NAMESPACE_IPC_ENABLE", &opt_use_ns_ipc, false, },
- { "NAMESPACE_MNT_ENABLE", &opt_use_ns_mnt, false, },
- { "NAMESPACE_NET_ENABLE", &opt_use_ns_net, false, },
- { "NAMESPACE_PID_ENABLE", &opt_use_ns_pid, false, },
- { "NAMESPACE_SYSV_ENABLE", &opt_use_ns_sysv, false, },
- { "NAMESPACE_USER_ENABLE", &opt_use_ns_user, false, },
- { "NAMESPACE_UTS_ENABLE", &opt_use_ns_uts, false, },
+ { "NAMESPACES_ENABLE", &opt_use_namespaces, false, },
+ { "NAMESPACE_CGROUP_ENABLE", &opt_use_ns_cgroup, false, },
+ { "NAMESPACE_IPC_ENABLE", &opt_use_ns_ipc, false, },
+ { "NAMESPACE_MNT_ENABLE", &opt_use_ns_mnt, false, },
+ { "NAMESPACE_NET_ENABLE", &opt_use_ns_net, false, },
+ { "NAMESPACE_PID_ENABLE", &opt_use_ns_pid, false, },
+ { "NAMESPACE_SYSV_ENABLE", &opt_use_ns_sysv, false, },
+ { "NAMESPACE_TIME_ENABLE", &opt_use_ns_time, false, },
+ { "NAMESPACE_USER_ENABLE", &opt_use_ns_user, false, },
+ { "NAMESPACE_UTS_ENABLE", &opt_use_ns_uts, false, },
+ { "SANDBOX_DEBUG", &opt_debug, false, },
};
static void read_config(void)
@@ -46,35 +53,39 @@ static void read_config(void)
}
}
+static const char sb_sonfigure_opts[] = SANDBOX_CONFIGURE_OPTS;
+
static void show_version(void)
{
- puts(
+ printf(
"Gentoo path sandbox\n"
" version: " PACKAGE_VERSION "\n"
" C lib: " LIBC_VERSION " (" LIBC_PATH ")\n"
" build: " __DATE__ " " __TIME__ "\n"
- " contact: " PACKAGE_BUGREPORT " via http://bugs.gentoo.org/\n"
+ " contact: " PACKAGE_BUGREPORT " via https://bugs.gentoo.org/\n"
" rtld: "
#ifdef BROKEN_RTLD_NEXT
"next is broken ;(\n"
#else
"next is OK! :D\n"
#endif
-#ifndef SB_SCHIZO
-# define SB_SCHIZO "no"
+#ifndef SB_PERSONALITIES
+# define SB_PERSONALITIES "no"
#endif
- " schizo: " SB_SCHIZO "\n"
- "\nconfigured with these options:\n"
- SANDBOX_CONFIGURE_OPTS
+ " personalities: " SB_PERSONALITIES "\n"
+ "\nconfigured with these options:\n%s\n",
+ sb_sonfigure_opts
);
exit(0);
}
-#define PARSE_FLAGS "+hV"
+#define PARSE_FLAGS "+cdhV"
#define a_argument required_argument
static struct option const long_opts[] = {
{"ns-on", no_argument, &opt_use_namespaces, true},
{"ns-off", no_argument, &opt_use_namespaces, false},
+ {"ns-cgroup-on", no_argument, &opt_use_ns_cgroup, true},
+ {"ns-cgroup-off", no_argument, &opt_use_ns_cgroup, false},
{"ns-ipc-on", no_argument, &opt_use_ns_ipc, true},
{"ns-ipc-off", no_argument, &opt_use_ns_ipc, false},
{"ns-mnt-on", no_argument, &opt_use_ns_mnt, true},
@@ -85,17 +96,24 @@ static struct option const long_opts[] = {
{"ns-pid-off", no_argument, &opt_use_ns_pid, false},
{"ns-sysv-on", no_argument, &opt_use_ns_sysv, true},
{"ns-sysv-off", no_argument, &opt_use_ns_sysv, false},
+ {"ns-time-on", no_argument, &opt_use_ns_time, true},
+ {"ns-time-off", no_argument, &opt_use_ns_time, false},
{"ns-user-on", no_argument, &opt_use_ns_user, true},
{"ns-user-off", no_argument, &opt_use_ns_user, false},
{"ns-uts-on", no_argument, &opt_use_ns_uts, true},
{"ns-uts-off", no_argument, &opt_use_ns_uts, false},
+ {"bash", no_argument, NULL, 'c'},
+ {"debug", no_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
+ {"run-configure", no_argument, NULL, 0x800},
{NULL, no_argument, NULL, 0x0}
};
static const char * const opts_help[] = {
"Enable the use of namespaces",
"Disable the use of namespaces",
+ "Enable the use of cgroup namespaces",
+ "Disable the use of cgroup namespaces",
"Enable the use of IPC (and System V) namespaces",
"Disable the use of IPC (and System V) namespaces",
"Enable the use of mount namespaces",
@@ -106,12 +124,17 @@ static const char * const opts_help[] = {
"Disable the use of process (pid) namespaces",
"Enable the use of System V namespaces",
"Disable the use of System V namespaces",
+ "Enable the use of time namespaces",
+ "Disable the use of time namespaces",
"Enable the use of user namespaces",
"Disable the use of user namespaces",
"Enable the use of UTS (hostname/uname) namespaces",
"Disable the use of UTS (hostname/uname) namespaces",
+ "Run command through bash shell",
+ "Enable debug output",
"Print this help and exit",
"Print version and exit",
+ "Run local sandbox configure in same way and exit (developer only)",
NULL
};
@@ -163,23 +186,47 @@ static void show_usage(int status)
printf(" * %s\n", opts_help[i]);
}
- fprintf(fp, "\nContact: " PACKAGE_BUGREPORT " via http://bugs.gentoo.org/\n");
+ fprintf(fp, "\nContact: " PACKAGE_BUGREPORT " via https://bugs.gentoo.org/\n");
exit(status);
}
+static void run_configure(int argc, char *argv[])
+{
+ int i;
+ char *cmd;
+ xasprintf(&cmd, "set -x; ./configure %s", sb_sonfigure_opts);
+ /* This doesn't need to be fast, so keep it simple. */
+ for (i = optind; i < argc; ++i)
+ xasprintf(&cmd, "%s %s", cmd, argv[i]);
+ exit(system(cmd));
+}
+
void parseargs(int argc, char *argv[])
{
int i;
while ((i = getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
switch (i) {
+ case 'c':
+ opt_use_bash = true;
+ break;
+ case 'd':
+ if (opt_debug <= 0)
+ opt_debug = 1;
+ else
+ ++opt_debug;
+ break;
case 'V':
show_version();
case 'h':
show_usage(0);
+ case 0x800:
+ run_configure(argc, argv);
case '?':
show_usage(1);
+ default:
+ sb_ebort("ISE: unhandled CLI option %c\n", i);
}
}
diff --git a/src/sandbox.c b/src/sandbox.c
index 503ad0b..071cad0 100644
--- a/src/sandbox.c
+++ b/src/sandbox.c
@@ -15,14 +15,18 @@
#include "sbutil.h"
#include "sandbox.h"
+/* The C library might have a macro for this. */
+#undef dprintf
+
static int print_debug = 0;
#define dprintf(fmt, args...) do { if (print_debug) printf(fmt, ## args); } while (0)
#define dputs(str) do { if (print_debug) puts(str); } while (0)
+int (*sbio_faccessat)(int, const char *, int, int) = faccessat;
int (*sbio_open)(const char *, int, mode_t) = (void *)open;
FILE *(*sbio_popen)(const char *, const char *) = popen;
-volatile static int stop_called = 0;
-volatile static pid_t child_pid = 0;
+static volatile int stop_called = 0;
+static volatile pid_t child_pid = 0;
static const char sandbox_banner[] = "============================= Gentoo path sandbox ==============================";
static const char sandbox_footer[] = "--------------------------------------------------------------------------------";
@@ -111,7 +115,7 @@ static void print_sandbox_log(char *sandbox_log)
return;
}
- sb_eerror("--------------------------- ACCESS VIOLATION SUMMARY ---------------------------\n");
+ sb_eerror("----------------------- SANDBOX ACCESS VIOLATION SUMMARY -----------------------\n");
sb_eerror("LOG FILE: \"%s\"\n", sandbox_log);
while (1) {
@@ -172,7 +176,9 @@ static int spawn_shell(char *argv_bash[], char **env, int debug)
/* Child's process */
if (0 == child_pid) {
- int ret = execve(argv_bash[0], argv_bash, env);
+ /* Would be nice if execvpe were in POSIX. */
+ environ = env;
+ int ret = execvp(argv_bash[0], argv_bash);
sb_pwarn("failed to exec child");
_exit(ret);
} else if (child_pid < 0) {
@@ -205,7 +211,7 @@ int main(int argc, char **argv)
{
int sandbox_log_presence = 0;
- struct sandbox_info_t sandbox_info;
+ struct sandbox_info_t sandbox_info = {};
char **sandbox_environ;
char **argv_bash = NULL;
@@ -229,19 +235,22 @@ int main(int argc, char **argv)
sb_err("not launching a new sandbox as one is already running in this process hierarchy");
/* determine the location of all the sandbox support files */
- dputs("Detection of the support files.");
+ if (opt_debug)
+ dputs("Detection of the support files.");
if (-1 == setup_sandbox(&sandbox_info, print_debug))
sb_err("failed to setup sandbox");
/* verify the existance of required files */
- dputs("Verification of the required files.");
+ if (opt_debug)
+ dputs("Verification of the required files.");
if (!rc_file_exists(sandbox_info.sandbox_rc))
sb_perr("could not open the sandbox rc file: %s", sandbox_info.sandbox_rc);
/* set up the required environment variables */
- dputs("Setting up the required environment variables.");
+ if (opt_debug)
+ dputs("Setting up the required environment variables.");
/* If not in portage, cd into it work directory */
if ('\0' != sandbox_info.work_dir[0])
@@ -250,33 +259,61 @@ int main(int argc, char **argv)
/* Setup the child environment stuff.
* XXX: We free this in spawn_shell(). */
- sandbox_environ = setup_environ(&sandbox_info);
+ sandbox_environ = setup_environ(&sandbox_info, print_debug);
if (NULL == sandbox_environ)
goto oom_error;
/* Setup bash argv */
- str_list_add_item_copy(argv_bash, "/bin/bash", oom_error);
- str_list_add_item_copy(argv_bash, "-rcfile", oom_error);
- str_list_add_item_copy(argv_bash, sandbox_info.sandbox_rc, oom_error);
- if (argc >= 2) {
- int i;
-
- str_list_add_item_copy(argv_bash, run_str, oom_error);
- str_list_add_item_copy(argv_bash, argv[1], oom_error);
- for (i = 2; i < argc; i++) {
- char *tmp_ptr;
-
- tmp_ptr = xrealloc(argv_bash[4],
- (strlen(argv_bash[4]) +
- strlen(argv[i]) + 2) *
- sizeof(char));
- argv_bash[4] = tmp_ptr;
+ if (!opt_use_bash && argc == 2) {
+ /* Backwards compatibility hack: if there's only one argument, and it
+ * appears to be a shell command (not an absolute path to a program),
+ * then fallback to running through the shell.
+ */
+ if (access(argv[1], X_OK))
+ opt_use_bash = true;
+ }
- snprintf(argv_bash[4] + strlen(argv_bash[4]),
- strlen(argv[i]) + 2, " %s",
- argv[i]);
+ if (opt_use_bash || argc == 1) {
+ str_list_add_item_copy(argv_bash, "/bin/bash", oom_error);
+ str_list_add_item_copy(argv_bash, "-rcfile", oom_error);
+ str_list_add_item_copy(argv_bash, sandbox_info.sandbox_rc, oom_error);
+ if (argc >= 2) {
+ int i;
+ size_t cmdlen;
+
+ str_list_add_item_copy(argv_bash, run_str, oom_error);
+ str_list_add_item_copy(argv_bash, argv[1], oom_error);
+ cmdlen = strlen(argv_bash[4]);
+ for (i = 2; i < argc; i++) {
+ size_t arglen = strlen(argv[i]);
+ argv_bash[4] = xrealloc(argv_bash[4], cmdlen + arglen + 2);
+ argv_bash[4][cmdlen] = ' ';
+ memcpy(argv_bash[4] + cmdlen + 1, argv[i], arglen);
+ cmdlen += arglen + 1;
+ argv_bash[4][cmdlen] = '\0';
+ }
}
+ } else {
+ int i;
+ for (i = 1; i < argc; ++i)
+ str_list_add_item_copy(argv_bash, argv[i], oom_error);
+ }
+
+#ifdef HAVE_PRCTL
+ /* Lock down access to elevated privileges. In practice, this will block
+ * use of tools like su and sudo, and will allow use of seccomp bpf.
+ */
+# ifdef PR_SET_NO_NEW_PRIVS
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
+ /* Ignore EINVAL in case we're on old kernels. Unfortunately we can't
+ * differentiate between EINVAL due to unsupported PR_xxx and EINVAL
+ * due to bad 2nd/3rd/4th/5th args.
+ */
+ if (errno != EINVAL)
+ sb_eerror("prctl(PR_SET_NO_NEW_PRIVS) failed");
}
+# endif
+#endif
/* Set up the required signal handlers */
int sigs[] = { SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGUSR1, };
@@ -313,9 +350,8 @@ int main(int argc, char **argv)
sigaction(SIGHUP, &act_old[0], NULL);
/* STARTING PROTECTED ENVIRONMENT */
- dputs("The protected environment has been started.");
- dputs(sandbox_footer);
- dputs("Process being started in forked instance.");
+ if (opt_debug)
+ dputs("The protected environment has been started.");
/* Start Bash */
int shell_exit = spawn_shell(argv_bash, sandbox_environ, print_debug);
@@ -326,8 +362,6 @@ int main(int argc, char **argv)
argv_bash = NULL;
sandbox_environ = NULL;
- dputs("Cleaning up sandbox process");
- dputs(sandbox_banner);
dputs("The protected environment has been shut down.");
if (rc_file_exists(sandbox_info.sandbox_log)) {
@@ -337,7 +371,7 @@ int main(int argc, char **argv)
dputs(sandbox_footer);
/* Do the right thing and pass the signal back up. See:
- * http://www.cons.org/cracauer/sigint.html
+ * https://www.cons.org/cracauer/sigint.html
*/
if (stop_called != SIGUSR1 && WIFSIGNALED(shell_exit)) {
int signum = WTERMSIG(shell_exit);
diff --git a/src/sandbox.h b/src/sandbox.h
index 303dac4..477973a 100644
--- a/src/sandbox.h
+++ b/src/sandbox.h
@@ -24,7 +24,7 @@ struct sandbox_info_t {
char *home_dir;
};
-extern char **setup_environ(struct sandbox_info_t *sandbox_info);
+extern char **setup_environ(struct sandbox_info_t *sandbox_info, bool interactive);
extern bool sb_get_cnf_bool(const char *, bool);
@@ -40,15 +40,27 @@ extern pid_t setup_namespaces(void);
#define sb_err(fmt, args...) _sb_err(warn, fmt, ## args)
#define sb_perr(fmt, args...) _sb_err(pwarn, fmt, ## args)
+#define xasprintf(fmt, ...) \
+({ \
+ int _ret = asprintf(fmt, __VA_ARGS__); \
+ if (_ret == 0) \
+ sb_perr("asprintf(%s) failed", #fmt); \
+ _ret; \
+})
+
/* Option parsing related code */
extern void parseargs(int argc, char *argv[]);
extern int opt_use_namespaces;
+extern int opt_use_ns_cgroup;
extern int opt_use_ns_ipc;
extern int opt_use_ns_mnt;
extern int opt_use_ns_net;
extern int opt_use_ns_pid;
extern int opt_use_ns_sysv;
+extern int opt_use_ns_time;
extern int opt_use_ns_user;
extern int opt_use_ns_uts;
+extern bool opt_use_bash;
+extern int opt_debug;
#endif
diff --git a/tests/Makefile b/tests/Makefile
new file mode 100644
index 0000000..2eed23e
--- /dev/null
+++ b/tests/Makefile
@@ -0,0 +1,4 @@
+# Helper for developers.
+all: tests ;
+clean: clean-checkPROGRAMS ; rm -f *.o *.l[ao] .libs/*
+%: ; $(MAKE) -C .. $@
diff --git a/tests/Makefile.am b/tests/Makefile.am
deleted file mode 100644
index 3baf5b1..0000000
--- a/tests/Makefile.am
+++ /dev/null
@@ -1,123 +0,0 @@
-AT_FILES = $(wildcard $(srcdir)/*.at)
-TESTSUITE = $(srcdir)/testsuite
-DISTCLEANFILES = atconfig
-EXTRA_DIST = atlocal.in package.m4.in $(AT_FILES) $(TESTSUITE) \
- test-skel-0.c \
- tests.h
-
-AM_CPPFLAGS = -I$(top_srcdir) $(SANDBOX_DEFINES)
-
-check_PROGRAMS = \
- get-group \
- get-user \
- sb_true \
- sb_true_static \
- \
- access-0 \
- chmod-0 \
- chown-0 \
- creat-0 \
- creat64-0 \
- execv-0 \
- execvp-0 \
- faccessat-0 \
- fchmodat-0 \
- fchownat-0 \
- fopen-0 \
- fopen64-0 \
- futimesat-0 \
- lchown-0 \
- link-0 \
- linkat-0 \
- linkat_static-0 \
- lutimes-0 \
- mkdtemp-0 \
- mkdir-0 \
- mkdir_static-0 \
- mkdirat-0 \
- mkfifo-0 \
- mkfifoat-0 \
- mknod-0 \
- mknodat-0 \
- mkostemp-0 \
- mkostemp64-0 \
- mkostemps-0 \
- mkostemps64-0 \
- mkstemp-0 \
- mkstemp64-0 \
- mkstemps-0 \
- mkstemps64-0 \
- open-0 \
- open_static-0 \
- open64-0 \
- openat-0 \
- openat_static-0 \
- openat64-0 \
- opendir-0 \
- remove-0 \
- rename-0 \
- renameat-0 \
- rmdir-0 \
- signal_static-0 \
- symlink-0 \
- symlinkat-0 \
- truncate-0 \
- truncate64-0 \
- unlink-0 \
- unlink_static-0 \
- unlinkat-0 \
- utime-0 \
- utimensat-0 \
- utimensat_static-0 \
- utimes-0 \
- vfork-0 \
- \
- getcwd-gnulib_tst \
- libsigsegv_tst \
- malloc_hooked_tst \
- malloc_mmap_tst \
- pipe-fork_tst \
- pipe-fork_static_tst \
- sb_printf_tst \
- sigsuspend-zsh_tst \
- sigsuspend-zsh_static_tst \
- trace-memory_static_tst
-
-dist_check_SCRIPTS = \
- $(wildcard $(srcdir)/*-[0-9]*.sh) \
- malloc-0 \
- script-0 \
- trace-0
-
-AM_LDFLAGS = `expr $@ : .*_static >/dev/null && echo -all-static`
-
-sb_printf_tst_CFLAGS = -I$(top_srcdir)/libsbutil -I$(top_srcdir)/libsbutil/include
-sb_printf_tst_LDADD = $(top_builddir)/libsbutil/libsbutil.la
-
-malloc_hooked_tst_LDFLAGS = $(AM_LDFLAGS) -pthread
-
-if HAVE_LIBSIGSEGV
-libsigsegv_tst_LDADD = -lsigsegv
-endif
-
-TESTSUITEFLAGS = --jobs=`getconf _NPROCESSORS_ONLN || echo 1`
-
-check-local: atconfig atlocal $(TESTSUITE)
- $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='src:tests' $(TESTSUITEFLAGS)
-
-installcheck-local: atconfig atlocal $(TESTSUITE)
- $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='src:tests:$(bindir)' $(TESTSUITEFLAGS)
-
-clean-local:
- test ! -f '$(TESTSUITE)' || \
- $(SHELL) '$(TESTSUITE)' --clean
-
-AUTOTEST = $(AUTOM4TE) --language=autotest
-$(TESTSUITE): $(AT_FILES) testsuite.list.at
- $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
- mv $@.tmp $@
-
-testsuite.list.at: $(AT_FILES)
- ( echo "dnl DO NOT EDIT: GENERATED BY MAKEFILE.AM"; \
- $(GREP) -l -e '^SB_CHECK' -e '^AT_CHECK' $(AT_FILES) | LC_ALL=C sort | \
- $(SED) -e 's:^[.]/:sb_inc([:' -e 's:[.]at$$:]):' ) > $@
diff --git a/tests/atlocal.in b/tests/atlocal.in
index b9a631b..adf3bad 100644
--- a/tests/atlocal.in
+++ b/tests/atlocal.in
@@ -2,6 +2,7 @@
export abs_top_srcdir abs_top_builddir abs_srcdir abs_builddir
export AWK="@AWK@"
+export HOST="@host@"
if ! ${at_clean} ; then
export SB_UID=$(./get-user)
@@ -23,5 +24,32 @@ export SANDBOX_VERBOSE=0
# If the terminal has this flag set, the tests get all messed up.
stty -tostop 2>/dev/null || :
+# Some tests want this internal path.
+for devfd in /proc/self/fd /dev/fd ; do
+ [ -e "${devfd}" ] && break
+done
+
+# GNU make likes to leak fds when using jobservers (i.e. using -j).
+case "${MAKEFLAGS}" in
+*--jobserver-auth=*)
+ flags=${MAKEFLAGS#*--jobserver-auth=}
+ flags=${flags%% *}
+ for fd in $(echo "${flags}" | tr ',' ' ') ; do
+ if [ -e "${devfd}/${fd}" ] ; then
+ eval "exec ${fd}>&-"
+ fi
+ done
+ ;;
+esac
+
+# Figure out currently YAMA ptrace_scope restriction level.
+at_yama_ptrace_scope=$(cat /proc/sys/kernel/yama/ptrace_scope 2>/dev/null || echo 0)
+if [ ${at_yama_ptrace_scope} -gt 0 ] ; then
+ if [ "$(id -u)" -eq 0 ] ; then
+ at_yama_ptrace_scope=0
+ fi
+fi
+export at_yama_ptrace_scope
+
# This script must finish with ($? == 0) else the autotest runner gets upset.
:
diff --git a/tests/fchmod-0.c b/tests/fchmod-0.c
new file mode 100644
index 0000000..de0c237
--- /dev/null
+++ b/tests/fchmod-0.c
@@ -0,0 +1,35 @@
+/*
+ * https://bugs.gentoo.org/599706
+ *
+ */
+
+#include "headers.h"
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2)
+ return -2;
+
+ int mode = 0;
+ sscanf(argv[1], "%i", &mode);
+ /* The sandbox catches this:
+ *
+ * int fd = open(argv[2], O_RDWR);
+ *
+ * And it /should/ catch this:
+ *
+ * int fd = open(argv[2], O_RDONLY);
+ *
+ * ...but the latter only works when /proc/self/fd/%i
+ * is available.
+ *
+ */
+#ifdef SANDBOX_PROC_SELF_FD
+ int fd = open(argv[2], O_RDONLY);
+#else
+ int fd = open(argv[2], O_RDWR);
+#endif
+ int fchmod_result = fchmod(fd, (mode_t)mode);
+ close(fd);
+ return fchmod_result;
+}
diff --git a/tests/fchmod-1.sh b/tests/fchmod-1.sh
new file mode 100755
index 0000000..140d84f
--- /dev/null
+++ b/tests/fchmod-1.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+#
+# https://bugs.gentoo.org/599706
+#
+
+addwrite $PWD
+rm -f deny || exit 1
+touch deny || exit 1
+adddeny $PWD/deny
+
+# The sandbox doesn't log anything when it returns a junk file
+# descriptor? It doesn't look like we can test the contents of
+# sandbox.log here... instead, we just have to count on fchmod
+# failing, which it does if you use O_RDWR, and it *should* if you use
+# O_RDONLY (because that won't stop the change of permissions).
+fchmod-0 $(stat --format='%#04a' $PWD/deny) $PWD/deny && exit 1
+
+exit 0
diff --git a/tests/fchmod-2.sh b/tests/fchmod-2.sh
new file mode 100755
index 0000000..96d7cc9
--- /dev/null
+++ b/tests/fchmod-2.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+#
+# Ensure that fchmod() doesn't trigger spurious violations in the most
+# basic of cases.
+#
+addwrite $PWD
+
+# This should not trigger a violation.
+rm -f file
+touch file
+fchmod-0 0644 file || exit 1
diff --git a/tests/fchmod.at b/tests/fchmod.at
new file mode 100644
index 0000000..d364b4b
--- /dev/null
+++ b/tests/fchmod.at
@@ -0,0 +1,2 @@
+SB_CHECK(1)
+SB_CHECK(2)
diff --git a/tests/fchown-0.c b/tests/fchown-0.c
new file mode 100644
index 0000000..7fdca73
--- /dev/null
+++ b/tests/fchown-0.c
@@ -0,0 +1,34 @@
+/*
+ * https://bugs.gentoo.org/599706
+ *
+ */
+
+#include "headers.h"
+
+int main(int argc, char *argv[])
+{
+ if (argc < 3)
+ return -2;
+
+ uid_t uid = atoi(argv[1]);
+ gid_t gid = atoi(argv[2]);
+ /* The sandbox catches this:
+ *
+ * int fd = open(argv[3], O_RDWR);
+ *
+ * And it /should/ catch this:
+ *
+ * int fd = open(argv[3], O_RDONLY);
+ *
+ * ...but the latter only works when /proc/self/fd/%i
+ * is available.
+ */
+#ifdef SANDBOX_PROC_SELF_FD
+ int fd = open(argv[3], O_RDONLY);
+#else
+ int fd = open(argv[3], O_RDWR);
+#endif
+ int fchown_result = fchown(fd, uid, gid);
+ close(fd);
+ return fchown_result;
+}
diff --git a/tests/fchown-1.sh b/tests/fchown-1.sh
new file mode 100755
index 0000000..6c1178e
--- /dev/null
+++ b/tests/fchown-1.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+#
+# https://bugs.gentoo.org/599706
+#
+
+addwrite $PWD
+rm -f deny || exit 1
+touch deny || exit 1
+adddeny $PWD/deny
+
+# The sandbox doesn't log anything when it returns a junk file
+# descriptor? It doesn't look like we can test the contents of
+# sandbox.log here... instead, we just have to count on fchown
+# failing, which it does if you use O_RDWR, and it *should* if you use
+# O_RDONLY (because that won't stop the change of ownership).
+fchown-0 ${SB_UID} ${SB_GID} $PWD/deny && exit 1
+
+exit 0
diff --git a/tests/fchown-2.sh b/tests/fchown-2.sh
new file mode 100755
index 0000000..dedfbe4
--- /dev/null
+++ b/tests/fchown-2.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+#
+# Ensure that fchown() doesn't trigger spurious violations in the most
+# basic of cases.
+#
+addwrite $PWD
+
+# This should not trigger a violation.
+rm -f file
+touch file
+fchown-0 ${SB_UID} ${SB_GID} file || exit 1
diff --git a/tests/fchown.at b/tests/fchown.at
new file mode 100644
index 0000000..d364b4b
--- /dev/null
+++ b/tests/fchown.at
@@ -0,0 +1,2 @@
+SB_CHECK(1)
+SB_CHECK(2)
diff --git a/tests/fork-follow_static_tst.c b/tests/fork-follow_static_tst.c
new file mode 100644
index 0000000..363384e
--- /dev/null
+++ b/tests/fork-follow_static_tst.c
@@ -0,0 +1 @@
+#include "fork-follow_tst.c"
diff --git a/tests/fork-follow_tst.c b/tests/fork-follow_tst.c
new file mode 100644
index 0000000..2e3bb95
--- /dev/null
+++ b/tests/fork-follow_tst.c
@@ -0,0 +1,34 @@
+/*
+ * Make sure violations in children are caught.
+ */
+
+#include "tests.h"
+
+int main(int argc, char *argv[])
+{
+ if (argc != 3) {
+ printf("usage: %s <number forks> <path to remove>\n", argv[0]);
+ exit(1);
+ }
+
+ int i, forks = atoi(argv[1]);
+ const char *path = argv[2];
+
+ for (i = 0; i < forks; ++i) {
+ pid_t pid = fork();
+ if (pid < 0)
+ errp("unable to fork");
+
+ if (pid > 0) {
+ /* parent -- wait for child */
+ int status;
+ if (waitpid(pid, &status, 0) == pid)
+ exit(WEXITSTATUS(status));
+ errp("waitpid failed");
+ }
+ /* child -- keep looping */
+ }
+
+ /* final child -- try to create the path */
+ exit(creat(path, 0666) < 0 ? 0 : 1);
+}
diff --git a/tests/get-group.c b/tests/get-group.c
index 8138967..30cdfc9 100644
--- a/tests/get-group.c
+++ b/tests/get-group.c
@@ -31,8 +31,8 @@ int main(int argc, char *argv[])
printf("%i\n", grp->gr_gid);
} else {
const char *file = argv[1];
- struct stat st;
- if (lstat(file, &st))
+ struct stat64 st;
+ if (lstat64(file, &st))
errp("lstat(%s) failed", file);
printf("%i\n", st.st_gid);
}
diff --git a/tests/get-user.c b/tests/get-user.c
index f85e299..be448d7 100644
--- a/tests/get-user.c
+++ b/tests/get-user.c
@@ -31,8 +31,8 @@ int main(int argc, char *argv[])
printf("%i\n", pwd->pw_uid);
} else {
const char *file = argv[1];
- struct stat st;
- if (lstat(file, &st))
+ struct stat64 st;
+ if (lstat64(file, &st))
errp("lstat(%s) failed", file);
printf("%i\n", st.st_uid);
}
diff --git a/tests/git-bisector.sh b/tests/git-bisector.sh
index c45db6e..b64dff6 100755
--- a/tests/git-bisector.sh
+++ b/tests/git-bisector.sh
@@ -21,10 +21,21 @@ make="make -s -j"
cat << EOF > git-run.sh
#!/bin/sh
./autogen.sh
-./configure -q -C $(sandbox -V | tail -n1)
+# Newer versions of sandbox can run configure for us.
+# Should drop old support around Jan 2023.
+if sandbox --help | grep -q -e--run-configure ; then
+ sandbox --run-configure -q -C
+else
+ ./configure -q -C $(sandbox -V | tail -n1)
+fi
${make} clean
${make}
-./src/sandbox.sh . ./data/sandbox.bashrc \; . ./git-run-sandbox.sh
+opt=
+# Older versions of sandbox implied -c all the time.
+if ./src/sandbox.sh --help | grep -q -e--bash ; then
+ opt="-c"
+fi
+./src/sandbox.sh ${opt} . ./data/sandbox.bashrc \; . ./git-run-sandbox.sh
EOF
chmod a+rx git-run.sh
diff --git a/tests/libsigsegv_tst.c b/tests/libsigsegv_tst.c
index 82ed21b..2b17fa4 100644
--- a/tests/libsigsegv_tst.c
+++ b/tests/libsigsegv_tst.c
@@ -11,7 +11,7 @@
#define WRITE(msg) ({ ssize_t w = write(1, msg, sizeof(msg) - 1); w; })
-#ifdef HAVE_SIGSEGV_H
+#if defined(HAVE_SIGSEGV_H) && defined(HAVE_LIBSIGSEGV)
#include <sigsegv.h>
static int segv_handler(void *address, int serious)
diff --git a/tests/local.at b/tests/local.at
index 95db774..028961d 100644
--- a/tests/local.at
+++ b/tests/local.at
@@ -6,7 +6,7 @@ dnl due to the default PM test env having that predict.
m4_defun([SB_RUN],[\
env \
SANDBOX_LOG="$PWD/sandbox.log" \
- sandbox.sh \
+ sandbox.sh -c \
addpredict / \; \
addwrite "${PWD%/*}" \; \
set -x \; \
diff --git a/tests/local.mk b/tests/local.mk
new file mode 100644
index 0000000..f1f4ac0
--- /dev/null
+++ b/tests/local.mk
@@ -0,0 +1,150 @@
+AT_FILES = $(wildcard $(top_srcdir)/%D%/*.at)
+DISTCLEANFILES += %D%/atconfig
+
+# Use top_srcdir for dependencies, and abs_top_srcdir to execute it.
+TESTSUITE = $(top_srcdir)/%D%/testsuite
+ABS_TESTSUITE = $(abs_top_srcdir)/%D%/testsuite
+
+EXTRA_DIST += \
+ $(AT_FILES) \
+ $(TESTSUITE) \
+ $(TESTSUITE_LIST) \
+ %D%/atlocal.in \
+ %D%/package.m4.in \
+ %D%/test-skel-0.c \
+ %D%/tests.h \
+ %D%/xattr-0
+
+check_PROGRAMS += \
+ %D%/get-group \
+ %D%/get-user \
+ %D%/sb_true \
+ %D%/sb_true_static \
+ \
+ %D%/access-0 \
+ %D%/chmod-0 \
+ %D%/chown-0 \
+ %D%/creat-0 \
+ %D%/creat64-0 \
+ %D%/execv-0 \
+ %D%/execvp-0 \
+ %D%/faccessat-0 \
+ %D%/fchmod-0 \
+ %D%/fchmodat-0 \
+ %D%/fchown-0 \
+ %D%/fchownat-0 \
+ %D%/fopen-0 \
+ %D%/fopen64-0 \
+ %D%/futimesat-0 \
+ %D%/lchown-0 \
+ %D%/link-0 \
+ %D%/linkat-0 \
+ %D%/linkat_static-0 \
+ %D%/lremovexattr-0 \
+ %D%/lsetxattr-0 \
+ %D%/lutimes-0 \
+ %D%/mkdtemp-0 \
+ %D%/mkdir-0 \
+ %D%/mkdir_static-0 \
+ %D%/mkdirat-0 \
+ %D%/mkfifo-0 \
+ %D%/mkfifoat-0 \
+ %D%/mknod-0 \
+ %D%/mknodat-0 \
+ %D%/mkostemp-0 \
+ %D%/mkostemp64-0 \
+ %D%/mkostemps-0 \
+ %D%/mkostemps64-0 \
+ %D%/mkstemp-0 \
+ %D%/mkstemp64-0 \
+ %D%/mkstemps-0 \
+ %D%/mkstemps64-0 \
+ %D%/open-0 \
+ %D%/open_static-0 \
+ %D%/open64-0 \
+ %D%/openat-0 \
+ %D%/openat_static-0 \
+ %D%/openat64-0 \
+ %D%/opendir-0 \
+ %D%/remove-0 \
+ %D%/removexattr-0 \
+ %D%/rename-0 \
+ %D%/renameat-0 \
+ %D%/renameat2-0 \
+ %D%/rmdir-0 \
+ %D%/setxattr-0 \
+ %D%/signal_static-0 \
+ %D%/symlink-0 \
+ %D%/symlinkat-0 \
+ %D%/truncate-0 \
+ %D%/truncate64-0 \
+ %D%/unlink-0 \
+ %D%/unlink_static-0 \
+ %D%/unlinkat-0 \
+ %D%/utime-0 \
+ %D%/utimensat-0 \
+ %D%/utimensat64-0 \
+ %D%/utimensat_static-0 \
+ %D%/utimensat64_static-0 \
+ %D%/utimes-0 \
+ %D%/vfork-0 \
+ \
+ %D%/fork-follow_tst \
+ %D%/fork-follow_static_tst \
+ %D%/getcwd-gnulib_tst \
+ %D%/libsigsegv_tst \
+ %D%/malloc_hooked_tst \
+ %D%/malloc_mmap_tst \
+ %D%/pipe-fork_tst \
+ %D%/pipe-fork_static_tst \
+ %D%/sb_printf_tst \
+ %D%/sigsuspend-zsh_tst \
+ %D%/sigsuspend-zsh_static_tst \
+ %D%/trace-memory_static_tst
+
+dist_check_SCRIPTS += \
+ $(wildcard $(top_srcdir)/%D%/*-[0-9]*.sh) \
+ %D%/malloc-0 \
+ %D%/script-0 \
+ %D%/trace-0
+
+# This will be used by all programs, not just tests/ ...
+AM_LDFLAGS = `expr $@ : .*_static >/dev/null && echo -all-static`
+
+%C%_sb_printf_tst_CFLAGS = -I$(top_srcdir)/libsbutil -I$(top_srcdir)/libsbutil/include
+%C%_sb_printf_tst_LDADD = libsbutil/libsbutil.la
+
+%C%_malloc_hooked_tst_LDFLAGS = $(AM_LDFLAGS) -pthread
+
+%C%_libsigsegv_tst_CPPFLAGS = ${AM_CPPFLAGS}
+if HAVE_LIBSIGSEGV
+%C%_libsigsegv_tst_CPPFLAGS += -DHAVE_LIBSIGSEGV
+%C%_libsigsegv_tst_LDADD = -lsigsegv
+endif
+
+TESTSUITEFLAGS = --jobs=`getconf _NPROCESSORS_ONLN || echo 1`
+
+# Helper target for devs to precompile.
+tests: $(check_PROGRAMS) $(TESTSUITE)
+
+check-local: %D%/atconfig %D%/atlocal $(TESTSUITE)
+ cd %D% && $(SHELL) '$(ABS_TESTSUITE)' AUTOTEST_PATH='src:tests' $(TESTSUITEFLAGS)
+
+installcheck-local: %D%/atconfig %D%/atlocal $(TESTSUITE)
+ cd %D% && $(SHELL) '$(ABS_TESTSUITE)' AUTOTEST_PATH='src:tests:$(bindir)' $(TESTSUITEFLAGS)
+
+clean-local:
+ test ! -f '$(TESTSUITE)' || { cd %D% && $(SHELL) '$(ABS_TESTSUITE)' --clean; }
+
+TESTSUITE_LIST = $(top_srcdir)/%D%/testsuite.list.at
+AUTOTEST = $(AUTOM4TE) --language=autotest
+$(TESTSUITE): $(AT_FILES) $(TESTSUITE_LIST)
+ @$(MKDIR_P) $(top_srcdir)/%D%
+ $(AM_V_GEN)cd $(top_srcdir)/%D% && $(AUTOTEST) -I. -o testsuite.tmp testsuite.at
+ $(AM_V_at)mv $@.tmp $@
+
+$(TESTSUITE_LIST): $(AT_FILES)
+ @$(MKDIR_P) $(top_srcdir)/%D%
+ $(AM_V_GEN)( echo "dnl DO NOT EDIT: GENERATED BY MAKEFILE.AM"; \
+ $(GREP) -l -e '^SB_CHECK' -e '^AT_CHECK' $(AT_FILES) | LC_ALL=C sort | \
+ $(SED) -e 's:^[^/]*/%D%/:sb_inc([:' -e 's:[.]at$$:]):' ) > $@
diff --git a/tests/lremovexattr-0.c b/tests/lremovexattr-0.c
new file mode 100644
index 0000000..ca925f1
--- /dev/null
+++ b/tests/lremovexattr-0.c
@@ -0,0 +1,15 @@
+#define FUNC lremovexattr
+#define SFUNC "lremovexattr"
+#define FUNC_STR "\"%s\", \"%s\""
+#define FUNC_IMP path, name
+#define ARG_CNT 2
+#define ARG_USE "<path> <name>"
+
+#define process_args() \
+ s = argv[i++]; \
+ char *path = s; \
+ \
+ s = argv[i++]; \
+ char *name = s;
+
+#include "test-skel-0.c"
diff --git a/tests/lsetxattr-0.c b/tests/lsetxattr-0.c
new file mode 100644
index 0000000..b1ed475
--- /dev/null
+++ b/tests/lsetxattr-0.c
@@ -0,0 +1,24 @@
+#define FUNC lsetxattr
+#define SFUNC "lsetxattr"
+#define FUNC_STR "\"%s\", \"%s\", \"%s\", %zu, %i"
+#define FUNC_IMP path, name, value, size, flags
+#define ARG_CNT 5
+#define ARG_USE "<path> <name> <value> <size> <flags>"
+
+#define process_args() \
+ s = argv[i++]; \
+ char *path = s; \
+ \
+ s = argv[i++]; \
+ char *name = s; \
+ \
+ s = argv[i++]; \
+ char *value = s; \
+ \
+ s = argv[i++]; \
+ size_t size = atoi(s); \
+ \
+ s = argv[i++]; \
+ int flags = atoi(s);
+
+#include "test-skel-0.c"
diff --git a/tests/lutimes-1.sh b/tests/lutimes-1.sh
new file mode 100755
index 0000000..8638bb2
--- /dev/null
+++ b/tests/lutimes-1.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+addwrite "${PWD}"
+
+sym="lutimes-1.sym"
+ln -s /bad/path "${sym}"
+
+lutimes-0 0 "${sym}" NULL || exit 1
+lutimes-0 -1,EACCES /bin/sh NULL || exit 1
diff --git a/tests/lutimes.at b/tests/lutimes.at
new file mode 100644
index 0000000..081d7d2
--- /dev/null
+++ b/tests/lutimes.at
@@ -0,0 +1 @@
+SB_CHECK(1)
diff --git a/tests/malloc_hooked_tst.c b/tests/malloc_hooked_tst.c
index 18737fe..8d0922e 100644
--- a/tests/malloc_hooked_tst.c
+++ b/tests/malloc_hooked_tst.c
@@ -9,7 +9,7 @@
* libsandbox tries to initialize itself (since it never finished originally) ->
* libsandbox's malloc() ->
* dlsym() -> deadlock
- * http://crbug.com/586444
+ * https://crbug.com/586444
*/
#include "headers.h"
diff --git a/tests/removexattr-0.c b/tests/removexattr-0.c
new file mode 100644
index 0000000..4abdfff
--- /dev/null
+++ b/tests/removexattr-0.c
@@ -0,0 +1,15 @@
+#define FUNC removexattr
+#define SFUNC "removexattr"
+#define FUNC_STR "\"%s\", \"%s\""
+#define FUNC_IMP path, name
+#define ARG_CNT 2
+#define ARG_USE "<path> <name>"
+
+#define process_args() \
+ s = argv[i++]; \
+ char *path = s; \
+ \
+ s = argv[i++]; \
+ char *name = s;
+
+#include "test-skel-0.c"
diff --git a/tests/removexattr-1.sh b/tests/removexattr-1.sh
new file mode 100755
index 0000000..327f4dd
--- /dev/null
+++ b/tests/removexattr-1.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Make sure we catch removexattr.
+[ "${at_xfail}" = "yes" ] && exit 77 # see trace-0
+xattr-0 ; ret=$? ; [ ${ret} -eq 0 ] || exit ${ret}
+
+# Set it to something to make sure it works.
+touch f
+setxattr-0 0 f user.sandbox test 4 0 || exit 1
+
+# Try to remove it and get rejected.
+adddeny "${PWD}"
+removexattr-0 0 f user.sandbox
+test -e sandbox.log
diff --git a/tests/removexattr.at b/tests/removexattr.at
new file mode 100644
index 0000000..081d7d2
--- /dev/null
+++ b/tests/removexattr.at
@@ -0,0 +1 @@
+SB_CHECK(1)
diff --git a/tests/renameat2-0.c b/tests/renameat2-0.c
new file mode 100644
index 0000000..6041d69
--- /dev/null
+++ b/tests/renameat2-0.c
@@ -0,0 +1,22 @@
+#define CONFIG HAVE_RENAMEAT2
+#define FUNC renameat2
+#define SFUNC "renameat2"
+#define FUNC_STR "%i, \"%s\", %i, \"%s\", %i"
+#define FUNC_IMP olddirfd, oldpath, newdirfd, newpath, 0
+#define ARG_CNT 4
+#define ARG_USE "<dirfd>(old) <path>(old) <dirfd>(new) <path>(new)"
+
+#define process_args() \
+ s = argv[i++]; \
+ int olddirfd = at_get_fd(s); \
+ \
+ s = argv[i++]; \
+ char *oldpath = s; \
+ \
+ s = argv[i++]; \
+ int newdirfd = at_get_fd(s); \
+ \
+ s = argv[i++]; \
+ char *newpath = s;
+
+#include "test-skel-0.c"
diff --git a/tests/renameat2-1.sh b/tests/renameat2-1.sh
new file mode 100755
index 0000000..9f91c05
--- /dev/null
+++ b/tests/renameat2-1.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+# basic functionality check
+
+addwrite $PWD
+
+touch old || exit 1
+renameat2-0 0 AT_FDCWD old AT_FDCWD new || exit 1
+[ ! -e old -a -e new ]
diff --git a/tests/renameat2-2.sh b/tests/renameat2-2.sh
new file mode 100755
index 0000000..420b36d
--- /dev/null
+++ b/tests/renameat2-2.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+# make sure we can clobber symlinks #612202
+
+addwrite $PWD
+
+ln -s /asdf sym || exit 1
+touch file
+renameat2-0 0 AT_FDCWD file AT_FDCWD sym || exit 1
+[ ! -e file ]
+[ ! -L sym ]
+[ -e sym ]
+test ! -s "${SANDBOX_LOG}"
diff --git a/tests/renameat2-3.sh b/tests/renameat2-3.sh
new file mode 100755
index 0000000..ca945a5
--- /dev/null
+++ b/tests/renameat2-3.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+# make sure we reject bad renames #612202
+
+addwrite $PWD
+mkdir deny
+adddeny $PWD/deny
+
+touch file
+renameat2-0 -1,EACCES AT_FDCWD file AT_FDCWD deny/file || exit 1
+[ -e file ]
+test -s "${SANDBOX_LOG}"
diff --git a/tests/renameat2.at b/tests/renameat2.at
new file mode 100644
index 0000000..eec4638
--- /dev/null
+++ b/tests/renameat2.at
@@ -0,0 +1,3 @@
+SB_CHECK(1)
+SB_CHECK(2)
+SB_CHECK(3)
diff --git a/tests/script-1.sh b/tests/script-1.sh
index 3ac6252..8eb46bf 100755
--- a/tests/script-1.sh
+++ b/tests/script-1.sh
@@ -1,5 +1,8 @@
#!/bin/sh
-# http://bugs.gentoo.org/257418
+# https://bugs.gentoo.org/257418
[ "${at_xfail}" = "yes" ] && exit 77 # see script-0
-(>/dev/fd/3)
+(
+cd "${devfd}"
+>3
+)
exit 0
diff --git a/tests/script-14.sh b/tests/script-14.sh
index 6fa55a0..6fa55a0 100644..100755
--- a/tests/script-14.sh
+++ b/tests/script-14.sh
diff --git a/tests/script-15.sh b/tests/script-15.sh
index b2acddc..b2acddc 100644..100755
--- a/tests/script-15.sh
+++ b/tests/script-15.sh
diff --git a/tests/script-16.sh b/tests/script-16.sh
new file mode 100755
index 0000000..73b7803
--- /dev/null
+++ b/tests/script-16.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+# https://bugs.gentoo.org/139591
+[ "${at_xfail}" = "yes" ] && exit 77 # see script-0
+addwrite $PWD
+
+mkdir -p to-be/deleted
+cd to-be/deleted
+rmdir ../deleted
+
+# In https://bugs.gentoo.org/590084 sanbox should deny
+# access here and touch should fail:
+! touch ../foo
diff --git a/tests/script-17.sh b/tests/script-17.sh
new file mode 100755
index 0000000..83c51f9
--- /dev/null
+++ b/tests/script-17.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Make sure forked children are caught. Historically, dynamic worked fine, but
+# static missed forks.
+[ "${at_xfail}" = "yes" ] && exit 77 # see script-0
+
+# Setup scratch path.
+mkdir subdir
+adddeny "${PWD}/subdir"
+
+for child in 0 1 2 3 4 5 ; do
+ fork-follow_tst ${child} subdir/dyn${child} || exit $?
+done
+
+depth="0"
+# We can't trace static children currently with YAMA ptrace_scope 1+.
+if [ ${at_yama_ptrace_scope} -eq 0 ] ; then
+ depth="${depth} 1 2 3 4 5"
+fi
+for child in ${depth} ; do
+ fork-follow_static_tst ${child} subdir/static${child} || exit $?
+done
+
+exit 0
diff --git a/tests/script-2.sh b/tests/script-2.sh
index ec10fa9..3c7d66e 100755
--- a/tests/script-2.sh
+++ b/tests/script-2.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# http://bugs.gentoo.org/139591
+# https://bugs.gentoo.org/139591
[ "${at_xfail}" = "yes" ] && exit 77 # see script-0
addwrite $PWD
diff --git a/tests/script-3.sh b/tests/script-3.sh
index be7f7a3..60ca5ce 100755
--- a/tests/script-3.sh
+++ b/tests/script-3.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# http://bugs.gentoo.org/260765
+# https://bugs.gentoo.org/260765
[ "${at_xfail}" = "yes" ] && exit 77 # see script-0
addwrite $PWD
diff --git a/tests/script-8.sh b/tests/script-8.sh
index 6d9de55..9d8ca11 100755
--- a/tests/script-8.sh
+++ b/tests/script-8.sh
@@ -6,6 +6,9 @@ sigsuspend-zsh_tst
d=$?
echo "ret = $d"
+# We can't trace static children currently with YAMA ptrace_scope 1+.
+[ ${at_yama_ptrace_scope} -gt 0 ] && exit ${d}
+
sigsuspend-zsh_static_tst
s=$?
echo "ret = $s"
diff --git a/tests/script.at b/tests/script.at
index 8837bda..037d27e 100644
--- a/tests/script.at
+++ b/tests/script.at
@@ -13,3 +13,5 @@ SB_CHECK(12)
SB_CHECK(13)
SB_CHECK(14)
SB_CHECK(15)
+SB_CHECK(16)
+SB_CHECK(17)
diff --git a/tests/setxattr-0.c b/tests/setxattr-0.c
new file mode 100644
index 0000000..2717b85
--- /dev/null
+++ b/tests/setxattr-0.c
@@ -0,0 +1,24 @@
+#define FUNC setxattr
+#define SFUNC "setxattr"
+#define FUNC_STR "\"%s\", \"%s\", \"%s\", %zu, %i"
+#define FUNC_IMP path, name, value, size, flags
+#define ARG_CNT 5
+#define ARG_USE "<path> <name> <value> <size> <flags>"
+
+#define process_args() \
+ s = argv[i++]; \
+ char *path = s; \
+ \
+ s = argv[i++]; \
+ char *name = s; \
+ \
+ s = argv[i++]; \
+ char *value = s; \
+ \
+ s = argv[i++]; \
+ size_t size = atoi(s); \
+ \
+ s = argv[i++]; \
+ int flags = atoi(s);
+
+#include "test-skel-0.c"
diff --git a/tests/setxattr-1.sh b/tests/setxattr-1.sh
new file mode 100755
index 0000000..6bbe1df
--- /dev/null
+++ b/tests/setxattr-1.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+# Make sure we catch setxattr.
+[ "${at_xfail}" = "yes" ] && exit 77 # see trace-0
+xattr-0 ; ret=$? ; [ ${ret} -eq 0 ] || exit ${ret}
+
+# Set it to something to make sure it works.
+touch f
+setxattr-0 0 f user.sandbox test 4 0 || exit 1
+
+# Try to set it again and get rejected.
+adddeny "${PWD}"
+setxattr-0 0 f user.sandbox test 4 0
+test -e sandbox.log
diff --git a/tests/setxattr.at b/tests/setxattr.at
new file mode 100644
index 0000000..081d7d2
--- /dev/null
+++ b/tests/setxattr.at
@@ -0,0 +1 @@
+SB_CHECK(1)
diff --git a/tests/test-skel-0.c b/tests/test-skel-0.c
index 96e42ae..91128d3 100644
--- a/tests/test-skel-0.c
+++ b/tests/test-skel-0.c
@@ -128,7 +128,7 @@ int at_get_fd(const char *str_dirfd)
}
str_mode = strtok(NULL, ":");
- return open(str_path, f_get_flags(str_flags), sscanf_mode_t(str_mode));
+ return open64(str_path, f_get_flags(str_flags), sscanf_mode_t(str_mode));
}
#define V_TIMESPEC "NULL | NOW | #[,#]"
@@ -144,8 +144,8 @@ struct timespec *parse_timespec(const char *s)
if (!strcmp(s, "NOW")) {
times->tv_sec = time(0);
} else {
- long sec = 0, nsec = 0;
- sscanf(s, "%li,%li", &sec, &nsec);
+ int64_t sec = 0, nsec = 0;
+ sscanf(s, "%" PRIi64 ",%" PRIi64, &sec, &nsec);
times->tv_sec = sec;
times->tv_nsec = nsec;
}
diff --git a/tests/tests.h b/tests/tests.h
index 22733ca..610388d 100644
--- a/tests/tests.h
+++ b/tests/tests.h
@@ -73,6 +73,7 @@ const value_pair tbl_errno[] = {
PAIR(EMLINK)
PAIR(ENAMETOOLONG)
PAIR(ENOBUFS)
+ PAIR(ENODATA)
PAIR(ENODEV)
PAIR(ENOENT)
PAIR(ENOEXEC)
diff --git a/tests/trace-0 b/tests/trace-0
index 5a91c7a..99f3037 100755
--- a/tests/trace-0
+++ b/tests/trace-0
@@ -1,6 +1,6 @@
#!/bin/sh
# make sure trace support exists
-if grep -q trace_child_signal "$abs_top_builddir"/libsandbox/.libs/libsandbox.so ; then
+if grep -q trace_loop "$abs_top_builddir"/libsandbox/.libs/libsandbox.so ; then
# see comment at top of script-0 -- same issue applies here because
# the ld.so isn't around to load the correct sandbox lib for us
exec script-0
diff --git a/tests/trace-memory_static_tst.c b/tests/trace-memory_static_tst.c
index 14c6477..86a47fe 100644
--- a/tests/trace-memory_static_tst.c
+++ b/tests/trace-memory_static_tst.c
@@ -26,7 +26,7 @@ volatile uintptr_t offset = 0;
#define check_ptr(addr) \
({ \
printf(" open(%p)\n", addr); \
- ret = open(non_const_ptr(addr), O_RDONLY); \
+ ret = open64(non_const_ptr(addr), O_RDONLY); \
assert(ret == -1 && errno == EFAULT); \
})
@@ -53,7 +53,7 @@ int main(int argc, char *argv[])
printf(" open(%p -> %p [+%#zx])\n", p, p + len, len);
memset(p, 'a', len);
path[end] = '\0';
- ret = open(p, O_RDONLY);
+ ret = open64(p, O_RDONLY);
assert(ret == -1 && (errno == ENOENT || errno == ENAMETOOLONG));
}
}
diff --git a/tests/utimensat-3.sh b/tests/utimensat-3.sh
index 4ecd4b3..a7b9843 100755
--- a/tests/utimensat-3.sh
+++ b/tests/utimensat-3.sh
@@ -1,6 +1,17 @@
#!/bin/sh
# make sure NULL filename is handled correctly
+# Note: this test is dependent on glibc internals
+# other libcs chose not to validate invalid parameters:
+# https://bugs.gentoo.org/549108#c28
+# https://www.openwall.com/lists/musl/2019/06/25/1
+# Run this test only on glibc systems.
+
+case $HOST in
+ *-linux-gnu);;
+ *) exit 77;;
+esac
+
addwrite $PWD
exec utimensat-0 -1:22 'f:O_WRONLY|O_CREAT:0666' NULL NULL 0
diff --git a/tests/utimensat64-0.c b/tests/utimensat64-0.c
new file mode 100644
index 0000000..bbacef5
--- /dev/null
+++ b/tests/utimensat64-0.c
@@ -0,0 +1,3 @@
+#define _TIME_BITS 64
+#define _FILE_OFFSET_BITS 64
+#include "utimensat-0.c"
diff --git a/tests/utimensat64-1.sh b/tests/utimensat64-1.sh
new file mode 100755
index 0000000..2aebc5f
--- /dev/null
+++ b/tests/utimensat64-1.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+# basic functionality check
+
+addwrite $PWD
+
+touch -r / file || exit 1
+utimensat64-0 0 AT_FDCWD . NULL 0 || exit 1
+utimensat64-0 0 AT_FDCWD file NULL 0 || exit 1
+[ file -nt / ]
diff --git a/tests/utimensat64.at b/tests/utimensat64.at
new file mode 100644
index 0000000..081d7d2
--- /dev/null
+++ b/tests/utimensat64.at
@@ -0,0 +1 @@
+SB_CHECK(1)
diff --git a/tests/utimensat64_static-0.c b/tests/utimensat64_static-0.c
new file mode 100644
index 0000000..73e7602
--- /dev/null
+++ b/tests/utimensat64_static-0.c
@@ -0,0 +1 @@
+#include "utimensat64-0.c"
diff --git a/tests/utimensat64_static-1.sh b/tests/utimensat64_static-1.sh
new file mode 100755
index 0000000..7b0355c
--- /dev/null
+++ b/tests/utimensat64_static-1.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+# basic functionality check
+[ "${at_xfail}" = "yes" ] && exit 77 # see trace-0
+
+addwrite $PWD
+
+touch -r / file || exit 1
+utimensat64_static-0 0 AT_FDCWD . NULL 0 || exit 1
+utimensat64_static-0 0 AT_FDCWD file NULL 0 || exit 1
+[ file -nt / ]
diff --git a/tests/utimensat64_static.at b/tests/utimensat64_static.at
new file mode 100644
index 0000000..081d7d2
--- /dev/null
+++ b/tests/utimensat64_static.at
@@ -0,0 +1 @@
+SB_CHECK(1)
diff --git a/tests/xattr-0 b/tests/xattr-0
new file mode 100755
index 0000000..5504443
--- /dev/null
+++ b/tests/xattr-0
@@ -0,0 +1,7 @@
+#!/bin/sh
+# Make sure the filesystem supports xattrs.
+file=".test.xattrs"
+touch "${file}"
+setxattr-0 0 "${file}" user.sandbox test 4 0 && ret=0 || ret=77
+rm -f "${file}"
+exit "${ret}"