summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRenaud Métrich <rmetrich@redhat.com>2020-01-29 15:22:47 +0100
committerDmitry V. Levin <ldv@strace.io>2021-04-04 12:04:24 +0000
commite921913eecd5025dae688fdf9c365023fe3b8a0c (patch)
treeb0ba2a6ba4ef974badff858496d0df13474de545
parentb19eaf8aa02f95b7e0e395d74e0c6af0600b5fac (diff)
downloadstrace-ldv/secontext.tar.gz
Implement --secontext[=full] option to display SELinux contextsldv/secontext
This is very useful when debugging SELinux issues, in particular, when a process runs in an unexpected context or didn't transition properly, or typically when a file being opened does not have the proper context. When --secontext=full is specified, strace will print the complete context (user, role, type and category) instead of just the type which is printed for --secontext option, as shown in the examples below: Without any "--secontext" options: ----------------------------------------------------------------------- 118104 16:52:11.141122 select(9, [4<TCP:[0.0.0.0:22]> 6<TCPv6:[[::]:22]>], NULL, NULL, NULL) = 1 (in [4]) <1.845416> 119820 16:52:13.133319 openat(AT_FDCWD, "/home/rmetrich/.ssh/authorized_keys", O_RDONLY|O_NONBLOCK) = 11</home/rmetrich/.ssh/authorized_keys> <0.000399> ----------------------------------------------------------------------- With "--secontext=full" option: ----------------------------------------------------------------------- 118104 [system_u:system_r:sshd_t:s0-s0:c0.c1023] 16:52:11.141122 select(9, [4<TCP:[0.0.0.0:22]> 6<TCPv6:[[::]:22]>], NULL, NULL, NULL) = 1 (in [4]) <1.845416> 119820 [system_u:system_r:sshd_t:s0-s0:c0.c1023] 16:52:13.133319 openat(AT_FDCWD, "/home/rmetrich/.ssh/authorized_keys" [system_u:object_r:nfs_t:s0], O_RDONLY|O_NONBLOCK) = 11</home/rmetrich/.ssh/authorized_keys> [system_u:object_r:nfs_t:s0] <0.000399> ----------------------------------------------------------------------- With "--secontext" option: ----------------------------------------------------------------------- 118104 [sshd_t] 16:52:11.141122 select(9, [4<TCP:[0.0.0.0:22]> 6<TCPv6:[[::]:22]>], NULL, NULL, NULL) = 1 (in [4]) <1.845416> 119820 [sshd_t] 16:52:13.133319 openat(AT_FDCWD, "/home/rmetrich/.ssh/authorized_keys" [nfs_t], O_RDONLY|O_NONBLOCK) = 11</home/rmetrich/.ssh/authorized_keys> [nfs_t] <0.000399> ----------------------------------------------------------------------- To implement this, a new "--with-libselinux" configure option has been introduced. It defaults to "check", which means automatic support on SELinux aware systems. Co-authored-by: Dmitry V. Levin <ldv@strace.io>
-rw-r--r--NEWS1
-rwxr-xr-xbootstrap11
-rw-r--r--configure.ac2
-rw-r--r--doc/strace.1.in9
-rw-r--r--m4/mpers.m426
-rw-r--r--m4/st_selinux.m480
-rw-r--r--src/Makefile.am9
-rw-r--r--src/defs.h9
-rw-r--r--src/dirent.c3
-rw-r--r--src/open.c3
-rw-r--r--src/secontext.c139
-rw-r--r--src/secontext.h21
-rw-r--r--src/strace.c53
-rw-r--r--src/syscall.c5
-rw-r--r--src/util.c16
-rw-r--r--src/xgetdents.c3
-rw-r--r--strace.spec.in3
-rw-r--r--tests/.gitignore5
-rw-r--r--tests/Makefile.am11
-rw-r--r--tests/access.c23
-rw-r--r--tests/chmod.c35
-rw-r--r--tests/execve.c53
-rwxr-xr-xtests/execve.test2
-rw-r--r--tests/execveat.c122
-rw-r--r--tests/faccessat.c137
-rwxr-xr-xtests/faccessat.test2
-rw-r--r--tests/fanotify_mark.c121
-rw-r--r--tests/fchmod.c23
-rw-r--r--tests/fchmodat.c67
-rw-r--r--tests/fchownat.c73
-rw-r--r--tests/file_handle.c204
-rwxr-xr-xtests/gen_secontext.sh72
-rw-r--r--tests/gen_tests.in30
-rw-r--r--tests/linkat.c150
-rw-r--r--tests/open.c18
-rw-r--r--tests/openat.c91
-rwxr-xr-xtests/options-syntax.test11
-rw-r--r--tests/secontext.c201
-rw-r--r--tests/secontext.h46
-rwxr-xr-xtests/strace-V.test4
40 files changed, 1699 insertions, 195 deletions
diff --git a/NEWS b/NEWS
index 8778c6a91..68443e295 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ Noteworthy changes in release ?.?? (????-??-??)
===============================================
* Improvements
+ * Implemented --secontext[=full] option to display SELinux contexts.
* Updated decoding of IFLA_BRPORT_* netlink attributes to match Linux 5.12.
* Updated lists of DEVCONF_*, IORING_*, KVM_*, MPOL_*, MTD_*, RESOLVE_*,
RTM_*, ST_*, and V4L2_* constants.
diff --git a/bootstrap b/bootstrap
index 137840010..36fcae380 100755
--- a/bootstrap
+++ b/bootstrap
@@ -9,6 +9,7 @@
./src/generate_mpers_am.sh
./src/xlat/gen.sh
./tests/gen_pure_executables.sh
+./tests/gen_secontext.sh
./tests/gen_tests.sh
for m in m32 mx32; do
@@ -24,11 +25,17 @@ for m in m32 mx32; do
s/^MPERS_NAME$s=.*/& $m/;
s/^\\(CC$s=\\).*/\\1 @CC_FOR_${m_upper}@/;
s/^MPERS_CC_FLAGS$s=.*/& @CFLAGS_FOR_${m_upper}@ @cc_flags_$m@/;
- s/^ARCH_MFLAGS$s=.*/& -DMPERS_IS_\$(MPERS_NAME) \$(MPERS_CC_FLAGS)/" \
+ s/^ARCH_MFLAGS$s=.*/& -DMPERS_IS_\$(MPERS_NAME) \$(MPERS_CC_FLAGS)/; \
+ s/HAVE_SELINUX_RUNTIME/HAVE_${m_upper}_SELINUX_RUNTIME/" \
tests/Makefile.am > $tests/Makefile.am
for f in tests/*; do
- case "${f##*/}" in
+ fname="${f##*/}"
+ case "$fname" in
Makefile*) continue;;
+ *--secontext.c)
+ sed "s/HAVE_SELINUX_RUNTIME/HAVE_${m_upper}_SELINUX_RUNTIME/" \
+ "$f" > $tests/"$fname"
+ continue;;
esac
ln -s ../"$f" $tests/
done
diff --git a/configure.ac b/configure.ac
index f801dc677..7e3194216 100644
--- a/configure.ac
+++ b/configure.ac
@@ -619,6 +619,8 @@ AC_CHECK_TOOL([READELF], [readelf])
st_STACKTRACE
+st_SELINUX
+
if test "$arch" = mips && test "$no_create" != yes; then
mkdir -p src/linux/mips
if $srcdir/src/linux/mips/genstub.sh \
diff --git a/doc/strace.1.in b/doc/strace.1.in
index 05c32d902..003e9e58e 100644
--- a/doc/strace.1.in
+++ b/doc/strace.1.in
@@ -53,6 +53,7 @@ strace \- trace system calls and signals
.OM \-P path
.OM \-p pid
.OP \-\-seccomp\-bpf
+.if '@ENABLE_SECONTEXT_FALSE@'#' .OP \-\-secontext\fR[=full]
.BR "" {
.OR \-p pid
.BR "" |
@@ -1084,6 +1085,14 @@ and PIDs associated with pidfd file descriptors.
.B \-\-pidns\-translation
If strace and tracee are in different PID namespaces, print PIDs in
strace's namespace, too.
+.if '@ENABLE_SECONTEXT_FALSE@'#' .TP
+.if '@ENABLE_SECONTEXT_FALSE@'#' .BR \-\-secontext "[=full]"
+.if '@ENABLE_SECONTEXT_FALSE@'#' When SELinux is available and is not disabled,
+.if '@ENABLE_SECONTEXT_FALSE@'#' print in square brackets SELinux contexts of
+.if '@ENABLE_SECONTEXT_FALSE@'#' processes, files, and descriptors. When
+.if '@ENABLE_SECONTEXT_FALSE@'#' .B full
+.if '@ENABLE_SECONTEXT_FALSE@'#' is specified, print the complete context (user,
+.if '@ENABLE_SECONTEXT_FALSE@'#' role, type and category) instead of just the type.
.SS Statistics
.TP 12
.B \-c
diff --git a/m4/mpers.m4 b/m4/mpers.m4
index 510aabe84..0d4b95ca4 100644
--- a/m4/mpers.m4
+++ b/m4/mpers.m4
@@ -63,9 +63,11 @@ pushdef([mpers_name], [$1])
pushdef([MPERS_NAME], translit([$1], [a-z], [A-Z]))
pushdef([HAVE_MPERS], [HAVE_]MPERS_NAME[_MPERS])
pushdef([HAVE_RUNTIME], [HAVE_]MPERS_NAME[_RUNTIME])
+pushdef([HAVE_SELINUX_RUNTIME], [HAVE_]MPERS_NAME[_SELINUX_RUNTIME])
pushdef([MPERS_CFLAGS], [$cc_flags_$1])
pushdef([st_cv_cc], [st_cv_$1_cc])
pushdef([st_cv_runtime], [st_cv_$1_runtime])
+pushdef([st_cv_selinux_runtime], [st_cv_$1_selinux_runtime])
pushdef([st_cv_mpers], [st_cv_$1_mpers])
pushdef([EXEEXT], MPERS_NAME[_EXEEXT])dnl
@@ -126,6 +128,26 @@ case "$arch" in
else
st_cv_mpers=no
fi])
+ AS_IF([test "x$enable_secontext$st_cv_mpers$st_cv_runtime" = xyesyesyes],
+ [AC_CACHE_CHECK([whether selinux runtime works with mpers_name personality],
+ [st_cv_selinux_runtime],
+ [saved_CPPFLAGS="$CPPFLAGS"
+ saved_LDFLAGS="$LDFLAGS"
+ saved_LIBS="$LIBS"
+ CPPFLAGS="$CPPFLAGS $libselinux_CPPFLAGS"
+ LDFLAGS="$LDFLAGS $libselinux_LDFLAGS"
+ LIBS="$LIBS $libselinux_LIBS"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <selinux/selinux.h>]],
+ [[return 0]])],
+ [st_cv_selinux_runtime=yes],
+ [st_cv_selinux_runtime=no],
+ [st_cv_selinux_runtime=no])
+ LIBS="$saved_LIBS"
+ LDFLAGS="$saved_LDFLAGS"
+ CPPFLAGS="$saved_CPPFLAGS"
+ ])
+ ],
+ [st_cv_selinux_runtime=no])
if test $st_cv_mpers = yes; then
AC_DEFINE(HAVE_MPERS, [1],
[Define to 1 if you have mpers_name mpers support])
@@ -165,6 +187,7 @@ case "$arch" in
*) # case "$enable_mpers"
st_cv_runtime=no
st_cv_mpers=no
+ st_cv_selinux_runtime=no
;;
esac
@@ -187,6 +210,7 @@ case "$arch" in
esac
AM_CONDITIONAL(HAVE_RUNTIME, [test "$st_cv_mpers$st_cv_runtime" = yesyes])
+AM_CONDITIONAL(HAVE_SELINUX_RUNTIME, [test "$st_cv_mpers$st_cv_selinux_runtime" = yesyes])
AM_CONDITIONAL(HAVE_MPERS, [test "$st_cv_mpers" = yes])
st_RESTORE_VAR([CC])
@@ -201,9 +225,11 @@ popdef([EXEEXT])dnl
popdef([st_cv_mpers])
popdef([st_cv_runtime])
+popdef([st_cv_selinux_runtime])
popdef([st_cv_cc])
popdef([MPERS_CFLAGS])
popdef([HAVE_RUNTIME])
+popdef([HAVE_SELINUX_RUNTIME])
popdef([HAVE_MPERS])
popdef([MPERS_NAME])
popdef([mpers_name])
diff --git a/m4/st_selinux.m4 b/m4/st_selinux.m4
new file mode 100644
index 000000000..da72a485d
--- /dev/null
+++ b/m4/st_selinux.m4
@@ -0,0 +1,80 @@
+#!/usr/bin/m4
+#
+# Copyright (c) 2020 The strace developers.
+# All rights reserved.
+#
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+AC_DEFUN([st_SELINUX], [dnl
+
+libselinux_CPPFLAGS=
+libselinux_LDFLAGS=
+libselinux_LIBS=
+enable_secontext=no
+
+AC_ARG_WITH([libselinux],
+ [AS_HELP_STRING([--with-libselinux],
+ [use libselinux to collect security contexts])],
+ [case "${withval}" in
+ yes|no|check) ;;
+ *) with_libselinux=yes
+ libselinux_CPPFLAGS="-I${withval}/include"
+ libselinux_LDFLAGS="-L${withval}/lib" ;;
+ esac],
+ [with_libselinux=check]
+)
+
+AS_IF([test "x$with_libselinux" != xno],
+ [saved_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $libselinux_CPPFLAGS"
+ found_selinux_h=no
+ AC_CHECK_HEADERS([selinux/selinux.h],
+ [found_selinux_h=yes])
+ CPPFLAGS="$saved_CPPFLAGS"
+ AS_IF([test "x$found_selinux_h" = xyes],
+ [saved_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $libselinux_LDFLAGS"
+ AC_CHECK_LIB([selinux],[getpidcon],
+ [libselinux_LIBS="-lselinux"
+ enable_secontext=yes
+ ],
+ [if test "x$with_libselinux" != xcheck; then
+ AC_MSG_FAILURE([failed to find getpidcon in libselinux])
+ fi
+ ]
+ )
+ AC_CHECK_LIB([selinux],[getfilecon],
+ [libselinux_LIBS="-lselinux"
+ enable_secontext=yes
+ ],
+ [if test "x$with_libselinux" != xcheck; then
+ AC_MSG_FAILURE([failed to find getfilecon in libselinux])
+ fi
+ ]
+ )
+ LDFLAGS="$saved_LDFLAGS"
+ ],
+ [if test "x$with_libselinux" != xcheck; then
+ AC_MSG_FAILURE([failed to find selinux.h])
+ fi
+ ]
+ )
+ ]
+)
+
+AC_MSG_CHECKING([whether to enable security contexts support])
+AS_IF([test "x$enable_secontext" = xyes],
+ [AC_DEFINE([ENABLE_SECONTEXT], [1],
+ [Define to enable SELinux security contexts support])
+ AC_DEFINE([HAVE_SELINUX_RUNTIME], [1],
+ [Define to enable SELinux security contexts testing])
+ AC_SUBST(libselinux_LIBS)
+ AC_SUBST(libselinux_LDFLAGS)
+ AC_SUBST(libselinux_CPPFLAGS)
+ AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])])
+
+AM_CONDITIONAL([ENABLE_SECONTEXT], [test "x$enable_secontext" = xyes])
+AM_CONDITIONAL([HAVE_SELINUX_RUNTIME], [test "x$enable_secontext" = xyes])
+
+])
diff --git a/src/Makefile.am b/src/Makefile.am
index b5abd1c86..3ba304801 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -406,6 +406,15 @@ strace_LDADD += $(libiberty_LIBS)
endif
endif
+if ENABLE_SECONTEXT
+libstrace_a_SOURCES += \
+ secontext.c \
+ secontext.h
+strace_CPPFLAGS += $(libselinux_CPPFLAGS)
+strace_LDFLAGS += $(libselinux_LDFLAGS)
+strace_LDADD += $(libselinux_LIBS)
+endif
+
strace_CPPFLAGS += $(CODE_COVERAGE_CPPFLAGS)
strace_CFLAGS += $(CODE_COVERAGE_CFLAGS)
strace_LDADD += $(CODE_COVERAGE_LIBS)
diff --git a/src/defs.h b/src/defs.h
index 08a293130..58e484f23 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -293,6 +293,10 @@ struct tcb {
*/
unsigned int pid_ns;
+#ifdef ENABLE_SECONTEXT
+ int last_dirfd; /* Use AT_FDCWD for 'not set' */
+#endif
+
struct mmap_cache_t *mmap_cache;
/*
@@ -1164,6 +1168,11 @@ extern void print_ax25_addr(const void /* ax25_address */ *addr);
extern void print_x25_addr(const void /* struct x25_address */ *addr);
extern const char *get_sockaddr_by_inode(struct tcb *, int fd, unsigned long inode);
extern bool print_sockaddr_by_inode(struct tcb *, int fd, unsigned long inode);
+
+/**
+ * Prints dirfd file descriptor and saves it in tcp->last_dirfd,
+ * the latter is used when printing SELinux contexts.
+ */
extern void print_dirfd(struct tcb *, int);
extern int
diff --git a/src/dirent.c b/src/dirent.c
index 3c2c09e9b..d37d7d577 100644
--- a/src/dirent.c
+++ b/src/dirent.c
@@ -106,6 +106,9 @@ SYS_FUNC(readdir)
if (entering(tcp)) {
/* fd */
printfd(tcp, tcp->u_arg[0]);
+#ifdef ENABLE_SECONTEXT
+ tcp->last_dirfd = (int) tcp->u_arg[0];
+#endif
tprint_arg_next();
} else {
/* dirp */
diff --git a/src/open.c b/src/open.c
index b48fc087a..1dd79e9dc 100644
--- a/src/open.c
+++ b/src/open.c
@@ -33,6 +33,9 @@ print_dirfd(struct tcb *tcp, int fd)
print_xlat_d(AT_FDCWD);
else
printfd(tcp, fd);
+#ifdef ENABLE_SECONTEXT
+ tcp->last_dirfd = fd;
+#endif
}
/*
diff --git a/src/secontext.c b/src/secontext.c
new file mode 100644
index 000000000..ccf9b346b
--- /dev/null
+++ b/src/secontext.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2020-2021 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "defs.h"
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <selinux/selinux.h>
+
+#include "secontext.h"
+#include "xstring.h"
+
+bool selinux_context = false;
+bool selinux_context_full = false;
+
+static int
+getcontext(int rc, char **secontext, char **result)
+{
+ if (rc < 0)
+ return rc;
+
+ *result = NULL;
+ if (!selinux_context_full) {
+ char *saveptr = NULL;
+ char *secontext_copy = xstrdup(*secontext);
+ const char *token;
+ unsigned int i;
+
+ /*
+ * We only want to keep the type (3rd field, ':' separator).
+ */
+ for (token = strtok_r(secontext_copy, ":", &saveptr), i = 0;
+ token; token = strtok_r(NULL, ":", &saveptr), i++) {
+ if (i == 2) {
+ *result = xstrdup(token);
+ break;
+ }
+ }
+ free(secontext_copy);
+ }
+
+ if (*result == NULL) {
+ /*
+ * On the CI at least, the context may have a trailing \n,
+ * let's remove it just in case.
+ */
+ size_t len = strlen(*secontext);
+ for (; len > 0; --len) {
+ if ((*secontext)[len - 1] != '\n')
+ break;
+ }
+ *result = xstrndup(*secontext, len);
+ }
+ freecon(*secontext);
+ return 0;
+}
+/*
+ * Retrieves the SELinux context of the given PID (extracted from the tcb).
+ * Memory must be freed.
+ * Returns 0 on success, -1 on failure.
+ */
+int
+selinux_getpidcon(struct tcb *tcp, char **result)
+{
+ if (!selinux_context)
+ return -1;
+
+ int proc_pid = 0;
+ translate_pid(NULL, tcp->pid, PT_TID, &proc_pid);
+ if (!proc_pid)
+ return -1;
+
+ char *secontext;
+ return getcontext(getpidcon(proc_pid, &secontext), &secontext, result);
+}
+
+/*
+ * Retrieves the SELinux context of the given pid and descriptor.
+ * Memory must be freed.
+ * Returns 0 on success, -1 on failure.
+ */
+int
+selinux_getfdcon(pid_t pid, int fd, char **result)
+{
+ if (!selinux_context || pid <= 0 || fd < 0)
+ return -1;
+
+ int proc_pid = 0;
+ translate_pid(NULL, pid, PT_TID, &proc_pid);
+ if (!proc_pid)
+ return -1;
+
+ char linkpath[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3];
+ xsprintf(linkpath, "/proc/%u/fd/%u", proc_pid, fd);
+
+ char *secontext;
+ return getcontext(getfilecon(linkpath, &secontext), &secontext, result);
+}
+
+/*
+ * Retrieves the SELinux context of the given path.
+ * Memory must be freed.
+ * Returns 0 on success, -1 on failure.
+ */
+int
+selinux_getfilecon(struct tcb *tcp, const char *path, char **result)
+{
+ if (!selinux_context)
+ return -1;
+
+ int proc_pid = 0;
+ translate_pid(NULL, tcp->pid, PT_TID, &proc_pid);
+ if (!proc_pid)
+ return -1;
+
+ int ret = -1;
+ char fname[PATH_MAX];
+
+ if (path[0] == '/')
+ ret = snprintf(fname, sizeof(fname), "/proc/%u/root%s",
+ proc_pid, path);
+ else if (tcp->last_dirfd == AT_FDCWD)
+ ret = snprintf(fname, sizeof(fname), "/proc/%u/cwd/%s",
+ proc_pid, path);
+ else if (tcp->last_dirfd >= 0 )
+ ret = snprintf(fname, sizeof(fname), "/proc/%u/fd/%u/%s",
+ proc_pid, tcp->last_dirfd, path);
+
+ if ((unsigned int) ret >= sizeof(fname))
+ return -1;
+
+ char *secontext;
+ return getcontext(getfilecon(fname, &secontext), &secontext, result);
+}
diff --git a/src/secontext.h b/src/secontext.h
new file mode 100644
index 000000000..e3b3e877e
--- /dev/null
+++ b/src/secontext.h
@@ -0,0 +1,21 @@
+/*
+ * SELinux interface.
+ *
+ * Copyright (c) 2020-2021 The strace developers.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef STRACE_SECONTEXT_H
+#define STRACE_SECONTEXT_H
+
+#include "defs.h"
+
+extern bool selinux_context;
+extern bool selinux_context_full;
+
+int selinux_getfdcon(pid_t pid, int fd, char **context);
+int selinux_getfilecon(struct tcb *tcp, const char *path, char **context);
+int selinux_getpidcon(struct tcb *tcp, char **context);
+
+#endif /* !STRACE_SECONTEXT_H */
diff --git a/src/strace.c b/src/strace.c
index 950db7af1..61a598cb1 100644
--- a/src/strace.c
+++ b/src/strace.c
@@ -40,6 +40,7 @@
#include "xstring.h"
#include "delay.h"
#include "wait.h"
+#include "secontext.h"
/* In some libc, these aren't declared. Do it ourself: */
extern char **environ;
@@ -240,6 +241,9 @@ print_version(void)
" no-mx32-mpers"
# endif
#endif /* SUPPORTED_PERSONALITIES > 2 */
+#ifdef ENABLE_SECONTEXT
+ " secontext"
+#endif
"";
printf("%s -- version %s\n"
@@ -259,11 +263,17 @@ usage(void)
#else
# define K_OPT ""
#endif
+#ifdef ENABLE_SECONTEXT
+# define SECONTEXT_OPT "[--secontext[=full]]\n"
+#else
+# define SECONTEXT_OPT ""
+#endif
printf("\
Usage: strace [-ACdffhi" K_OPT "qqrtttTvVwxxyyzZ] [-I N] [-b execve] [-e EXPR]...\n\
[-a COLUMN] [-o FILE] [-s STRSIZE] [-X FORMAT] [-O OVERHEAD]\n\
- [-S SORTBY] [-P PATH]... [-p PID]... [-U COLUMNS] [--seccomp-bpf]\n\
+ [-S SORTBY] [-P PATH]... [-p PID]... [-U COLUMNS] [--seccomp-bpf]\n"\
+ SECONTEXT_OPT "\
{ -p PID | [-DDD] [-E VAR=VAL]... [-u USERNAME] PROG [ARGS] }\n\
or: strace -c[dfwzZ] [-I N] [-b execve] [-e EXPR]... [-O OVERHEAD]\n\
[-S SORTBY] [-P PATH]... [-p PID]... [-U COLUMNS] [--seccomp-bpf]\n\
@@ -404,6 +414,14 @@ Output format:\n\
-yy, --decode-fds=all\n\
print all available information associated with file\n\
descriptors in addition to paths\n\
+"
+#ifdef ENABLE_SECONTEXT
+"\
+ --secontext[=full]\n\
+ print SELinux contexts (type only unless 'full' is specified)\n\
+"
+#endif
+"\
\n\
Statistics:\n\
-c, --summary-only\n\
@@ -783,6 +801,14 @@ printleader(struct tcb *tcp)
else if (nprocs > 1 && !outfname)
tprintf("[pid %5u] ", tcp->pid);
+#ifdef ENABLE_SECONTEXT
+ char *context;
+ if (!selinux_getpidcon(tcp, &context)) {
+ tprintf("[%s] ", context);
+ free(context);
+ }
+#endif
+
if (tflag_format) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
@@ -897,6 +923,9 @@ alloctcb(int pid)
#if SUPPORTED_PERSONALITIES > 1
tcp->currpers = current_personality;
#endif
+#ifdef ENABLE_SECONTEXT
+ tcp->last_dirfd = AT_FDCWD;
+#endif
nprocs++;
debug_msg("new tcb for pid %d, active tcbs:%d",
tcp->pid, nprocs);
@@ -2037,6 +2066,9 @@ init(int argc, char *argv[])
GETOPT_OUTPUT_SEPARATELY,
GETOPT_TS,
GETOPT_PIDNS_TRANSLATION,
+#ifdef ENABLE_SECONTEXT
+ GETOPT_SECONTEXT,
+#endif
GETOPT_QUAL_TRACE,
GETOPT_QUAL_ABBREV,
@@ -2093,6 +2125,9 @@ init(int argc, char *argv[])
{ "failed-only", no_argument, 0, 'Z' },
{ "failing-only", no_argument, 0, 'Z' },
{ "seccomp-bpf", no_argument, 0, GETOPT_SECCOMP },
+#ifdef ENABLE_SECONTEXT
+ { "secontext", optional_argument, 0, GETOPT_SECONTEXT },
+#endif
{ "trace", required_argument, 0, GETOPT_QUAL_TRACE },
{ "abbrev", required_argument, 0, GETOPT_QUAL_ABBREV },
@@ -2321,6 +2356,17 @@ init(int argc, char *argv[])
case GETOPT_SECCOMP:
seccomp_filtering = true;
break;
+#ifdef ENABLE_SECONTEXT
+ case GETOPT_SECONTEXT:
+ selinux_context = true;
+ if (optarg) {
+ if (!strcmp(optarg, "full"))
+ selinux_context_full = true;
+ else
+ error_opt_arg(c, lopt, optarg);
+ }
+ break;
+#endif
case GETOPT_QUAL_TRACE:
qualify_trace(optarg);
break;
@@ -2503,6 +2549,11 @@ init(int argc, char *argv[])
if (!number_set_array_is_empty(decode_fd_set, 0))
error_msg("-y/--decode-fds has no effect "
"with -c/--summary-only");
+#ifdef ENABLE_SECONTEXT
+ if (selinux_context)
+ error_msg("--secontext has no effect with "
+ "-c/--summary-only");
+#endif
}
if (!outfname) {
diff --git a/src/syscall.c b/src/syscall.c
index d143f257b..ebe5dd9b6 100644
--- a/src/syscall.c
+++ b/src/syscall.c
@@ -24,6 +24,7 @@
#include "poke.h"
#include "retval.h"
#include <limits.h>
+#include <fcntl.h>
/* for struct iovec */
#include <sys/uio.h>
@@ -1019,6 +1020,10 @@ syscall_exiting_finish(struct tcb *tcp)
tcp->sys_func_rval = 0;
free_tcb_priv_data(tcp);
+#ifdef ENABLE_SECONTEXT
+ tcp->last_dirfd = AT_FDCWD;
+#endif
+
if (cflag)
tcp->ltime = tcp->stime;
}
diff --git a/src/util.c b/src/util.c
index 9cb555ecb..7e247f945 100644
--- a/src/util.c
+++ b/src/util.c
@@ -26,6 +26,7 @@
#include "largefile_wrappers.h"
#include "number_set.h"
#include "print_utils.h"
+#include "secontext.h"
#include "static_assert.h"
#include "string_to_uint.h"
#include "xlat.h"
@@ -667,6 +668,13 @@ printed:
} else {
tprintf("%d", fd);
}
+#ifdef ENABLE_SECONTEXT
+ char *context;
+ if (!selinux_getfdcon(pid, fd, &context)) {
+ tprintf(" [%s]", context);
+ free(context);
+ }
+#endif
}
void
@@ -959,6 +967,14 @@ printpathn(struct tcb *const tcp, const kernel_ulong_t addr, unsigned int n)
else {
path[n++] = !nul_seen;
print_quoted_cstring(path, n);
+
+#ifdef ENABLE_SECONTEXT
+ char *context;
+ if (nul_seen && !selinux_getfilecon(tcp, path, &context)) {
+ tprintf(" [%s]", context);
+ free(context);
+ }
+#endif
}
return nul_seen;
diff --git a/src/xgetdents.c b/src/xgetdents.c
index 7985f409d..6f329461a 100644
--- a/src/xgetdents.c
+++ b/src/xgetdents.c
@@ -123,6 +123,9 @@ xgetdents(struct tcb *const tcp, const unsigned int header_size,
if (entering(tcp)) {
/* fd */
printfd(tcp, tcp->u_arg[0]);
+#ifdef ENABLE_SECONTEXT
+ tcp->last_dirfd = (int) tcp->u_arg[0];
+#endif
tprint_arg_next();
return 0;
}
diff --git a/strace.spec.in b/strace.spec.in
index c8f281f18..107715f46 100644
--- a/strace.spec.in
+++ b/strace.spec.in
@@ -29,11 +29,14 @@ BuildRequires: pkgconfig(bluez)
# Install binutils-devel to enable symbol demangling.
%if 0%{?fedora} >= 20 || 0%{?centos} >= 6 || 0%{?rhel} >= 6
%define buildrequires_stacktrace BuildRequires: elfutils-devel binutils-devel
+%define buildrequires_selinux BuildRequires: libselinux-devel
%endif
%if 0%{?suse_version} >= 1100
%define buildrequires_stacktrace BuildRequires: libdw-devel binutils-devel
+%define buildrequires_selinux BuildRequires: libselinux-devel
%endif
%{?buildrequires_stacktrace}
+%{?buildrequires_selinux}
# OBS compatibility
%{?!buildroot:BuildRoot: %_tmppath/buildroot-%name-%version-%release}
diff --git a/tests/.gitignore b/tests/.gitignore
index bed7c5b7f..6532542b5 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,3 +1,7 @@
+*--secontext
+*--secontext.c
+*--secontext_full
+*--secontext_full.c
*.dir
*.gen.test
*.log
@@ -711,6 +715,7 @@ seccomp-filter
seccomp-filter-v
seccomp-strict
seccomp_get_action_avail
+secontext.am
select
select-P
semop
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8327e84cf..cb6e7ef1c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -31,6 +31,12 @@ AM_CPPFLAGS = $(ARCH_MFLAGS) \
-DTESTS_SIZEOF_LONG=$(SIZEOF_LONG)
AM_LDFLAGS = $(ARCH_MFLAGS)
+if HAVE_SELINUX_RUNTIME
+libselinux_LDADD = $(libselinux_LIBS)
+else
+libselinux_LDADD =
+endif
+
libtests_a_SOURCES = \
create_nl_socket.c \
create_tmpfile.c \
@@ -57,6 +63,8 @@ libtests_a_SOURCES = \
printxval-Xabbrev.c \
printxval-Xraw.c \
printxval-Xverbose.c \
+ secontext.c \
+ secontext.h \
signal2name.c \
skip_unavailable.c \
sprintrc.c \
@@ -79,7 +87,10 @@ LDADD = libtests.a
include pure_executables.am
+include secontext.am
+
check_PROGRAMS = $(PURE_EXECUTABLES) \
+ $(secontext_EXECUTABLES) \
_newselect-P \
answer \
attach-f-p \
diff --git a/tests/access.c b/tests/access.c
index fe7e21d5b..5d37ba534 100644
--- a/tests/access.c
+++ b/tests/access.c
@@ -10,9 +10,12 @@
#ifdef __NR_access
+# include <fcntl.h>
# include <stdio.h>
# include <unistd.h>
+# include "secontext.h"
+
int
main(void)
{
@@ -22,15 +25,27 @@ main(void)
*/
create_and_enter_subdir("access_subdir");
+ char *my_secontext = SECONTEXT_PID_MY();
+
static const char sample[] = "access_sample";
+ (void) unlink(sample);
+ if (open(sample, O_CREAT|O_RDONLY, 0400) == -1)
+ perror_msg_and_fail("open: %s", sample);
long rc = syscall(__NR_access, sample, F_OK);
- printf("access(\"%s\", F_OK) = %ld %s (%m)\n",
- sample, rc, errno2name());
+ printf("%s%s(\"%s\"%s, F_OK) = %s\n",
+ my_secontext, "access",
+ sample, SECONTEXT_FILE(sample),
+ sprintrc(rc));
+
+ if (unlink(sample))
+ perror_msg_and_fail("unlink: %s", sample);
rc = syscall(__NR_access, sample, R_OK|W_OK|X_OK);
- printf("access(\"%s\", R_OK|W_OK|X_OK) = %ld %s (%m)\n",
- sample, rc, errno2name());
+ printf("%s%s(\"%s\", R_OK|W_OK|X_OK) = %s\n",
+ my_secontext, "access",
+ sample,
+ sprintrc(rc));
leave_and_remove_subdir();
diff --git a/tests/chmod.c b/tests/chmod.c
index 845e54aac..7d0ef5657 100644
--- a/tests/chmod.c
+++ b/tests/chmod.c
@@ -16,6 +16,8 @@
# include <stdio.h>
# include <unistd.h>
+# include "secontext.h"
+
int
main(void)
{
@@ -25,22 +27,33 @@ main(void)
*/
create_and_enter_subdir("chmod_subdir");
- static const char fname[] = "chmod_test_file";
+ char *my_secontext = SECONTEXT_PID_MY();
- if (open(fname, O_CREAT|O_RDONLY, 0400) < 0)
- perror_msg_and_fail("open");
+ static const char sample[] = "chmod_test_file";
+ (void) unlink(sample);
+ if (open(sample, O_CREAT|O_RDONLY, 0400) < 0)
+ perror_msg_and_fail("open: %s", sample);
- long rc = syscall(__NR_chmod, fname, 0600);
- printf("chmod(\"%s\", 0600) = %s\n", fname, sprintrc(rc));
+ long rc = syscall(__NR_chmod, sample, 0600);
+ printf("%s%s(\"%s\"%s, 0600) = %s\n",
+ my_secontext, "chmod",
+ sample, SECONTEXT_FILE(sample),
+ sprintrc(rc));
- if (unlink(fname))
- perror_msg_and_fail("unlink");
+ if (unlink(sample))
+ perror_msg_and_fail("unlink: %s", sample);
- rc = syscall(__NR_chmod, fname, 051);
- printf("chmod(\"%s\", 051) = %s\n", fname, sprintrc(rc));
+ rc = syscall(__NR_chmod, sample, 051);
+ printf("%s%s(\"%s\", 051) = %s\n",
+ my_secontext, "chmod",
+ sample,
+ sprintrc(rc));
- rc = syscall(__NR_chmod, fname, 004);
- printf("chmod(\"%s\", 004) = %s\n", fname, sprintrc(rc));
+ rc = syscall(__NR_chmod, sample, 004);
+ printf("%s%s(\"%s\", 004) = %s\n",
+ my_secontext, "chmod",
+ sample,
+ sprintrc(rc));
leave_and_remove_subdir();
diff --git a/tests/execve.c b/tests/execve.c
index 961d284a1..baf3eeb61 100644
--- a/tests/execve.c
+++ b/tests/execve.c
@@ -9,9 +9,12 @@
*/
#include "tests.h"
+#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
+#include "secontext.h"
+
static const char *errstr;
static int
@@ -52,9 +55,16 @@ main(void)
char ** const tail_argv = tail_memdup(argv, sizeof(argv));
char ** const tail_envp = tail_memdup(envp, sizeof(envp));
+ char *my_secontext = SECONTEXT_PID_MY();
+
+ (void) unlink(FILENAME);
+ if (open(FILENAME, O_RDONLY | O_CREAT, 0400) < 0)
+ perror_msg_and_fail("open");
+
+ char *FILENAME_secontext = SECONTEXT_FILE(FILENAME);
call_execve(FILENAME, tail_argv, tail_envp);
- printf("execve(\"%s\""
+ printf("%s%s(\"%s\"%s"
", [\"%s\", \"%s\", \"%s\", %p, %p, %p, ... /* %p */]"
#if VERBOSE
", [\"%s\", \"%s\", %p, %p, %p, ... /* %p */]"
@@ -62,7 +72,9 @@ main(void)
", %p /* 5 vars, unterminated */"
#endif
") = %s\n",
- Q_FILENAME, q_argv[0], q_argv[1], q_argv[2],
+ my_secontext, "execve",
+ Q_FILENAME, FILENAME_secontext,
+ q_argv[0], q_argv[1], q_argv[2],
argv[3], argv[4], argv[5], (char *) tail_argv + sizeof(argv)
#if VERBOSE
, q_envp[0], q_envp[1], envp[2], envp[3], envp[4],
@@ -77,14 +89,16 @@ main(void)
(void) q_envp; /* workaround for clang bug #33068 */
call_execve(FILENAME, tail_argv, tail_envp);
- printf("execve(\"%s\", [\"%s\", \"%s\", \"%s\"]"
+ printf("%s%s(\"%s\"%s, [\"%s\", \"%s\", \"%s\"]"
#if VERBOSE
", [\"%s\", \"%s\"]"
#else
", %p /* 2 vars */"
#endif
") = %s\n",
- Q_FILENAME, q_argv[0], q_argv[1], q_argv[2]
+ my_secontext, "execve",
+ Q_FILENAME, FILENAME_secontext,
+ q_argv[0], q_argv[1], q_argv[2]
#if VERBOSE
, q_envp[0], q_envp[1]
#else
@@ -93,14 +107,16 @@ main(void)
, errstr);
call_execve(FILENAME, tail_argv + 2, tail_envp + 1);
- printf("execve(\"%s\", [\"%s\"]"
+ printf("%s%s(\"%s\"%s, [\"%s\"]"
#if VERBOSE
", [\"%s\"]"
#else
", %p /* 1 var */"
#endif
") = %s\n",
- Q_FILENAME, q_argv[2]
+ my_secontext, "execve",
+ Q_FILENAME, FILENAME_secontext,
+ q_argv[2]
#if VERBOSE
, q_envp[1]
#else
@@ -113,13 +129,15 @@ main(void)
*empty = NULL;
call_execve(FILENAME, empty, empty);
- printf("execve(\"%s\", []"
+ printf("%s%s(\"%s\"%s, []"
#if VERBOSE
", []"
#else
", %p /* 0 vars */"
#endif
- ") = %s\n", Q_FILENAME
+ ") = %s\n",
+ my_secontext, "execve",
+ Q_FILENAME, FILENAME_secontext
#if !VERBOSE
, empty
#endif
@@ -143,7 +161,10 @@ main(void)
a[i] = b[i] = NULL;
call_execve(FILENAME, a, b);
- printf("execve(\"%s\", [\"%.*s\"...", Q_FILENAME, DEFAULT_STRLEN, a[0]);
+ printf("%s%s(\"%s\"%s, [\"%.*s\"...",
+ my_secontext, "execve",
+ Q_FILENAME, FILENAME_secontext,
+ DEFAULT_STRLEN, a[0]);
for (i = 1; i < DEFAULT_STRLEN; ++i)
printf(", \"%s\"", a[i]);
#if VERBOSE
@@ -162,7 +183,10 @@ main(void)
printf(") = %s\n", errstr);
call_execve(FILENAME, a + 1, b + 1);
- printf("execve(\"%s\", [\"%s\"", Q_FILENAME, a[1]);
+ printf("%s%s(\"%s\"%s, [\"%s\"",
+ my_secontext, "execve",
+ Q_FILENAME, FILENAME_secontext,
+ a[1]);
for (i = 2; i <= DEFAULT_STRLEN; ++i)
printf(", \"%s\"", a[i]);
#if VERBOSE
@@ -175,12 +199,17 @@ main(void)
#endif
printf(") = %s\n", errstr);
+ if (unlink(FILENAME))
+ perror_msg_and_fail("unlink");
+
call_execve(FILENAME, (char **) tail_argv[ARRAY_SIZE(q_argv)], efault);
- printf("execve(\"%s\", NULL, %p) = %s\n",
+ printf("%s%s(\"%s\", NULL, %p) = %s\n",
+ my_secontext, "execve",
Q_FILENAME, efault, errstr);
call_execve(FILENAME, efault, NULL);
- printf("execve(\"%s\", %p, NULL) = %s\n",
+ printf("%s%s(\"%s\", %p, NULL) = %s\n",
+ my_secontext, "execve",
Q_FILENAME, efault, errstr);
leave_and_remove_subdir();
diff --git a/tests/execve.test b/tests/execve.test
index 0824bab48..3275226ae 100755
--- a/tests/execve.test
+++ b/tests/execve.test
@@ -11,7 +11,7 @@
check_prog grep
run_prog > /dev/null
-run_strace -eexecve $args > "$EXP"
+run_strace -eexecve "$@" $args > "$EXP"
# Filter out execve() call made by strace.
grep -F test.execve < "$LOG" > "$OUT"
diff --git a/tests/execveat.c b/tests/execveat.c
index 43b53edb1..a41c42319 100644
--- a/tests/execveat.c
+++ b/tests/execveat.c
@@ -13,9 +13,102 @@
#ifdef __NR_execveat
+# include <fcntl.h>
# include <stdio.h>
# include <unistd.h>
+# include "secontext.h"
+
+static void
+tests_with_existing_file(void)
+{
+ /*
+ * Make sure the current workdir of the tracee
+ * is different from the current workdir of the tracer.
+ */
+ create_and_enter_subdir("execveat_subdir");
+
+ char *my_secontext = SECONTEXT_PID_MY();
+
+ static const char sample[] = "execveat_sample";
+ (void) unlink(sample);
+ if (open(sample, O_RDONLY | O_CREAT, 0400) < 0)
+ perror_msg_and_fail("open");
+
+ char *sample_secontext = SECONTEXT_FILE(sample);
+ static const char *argv[] = { sample, NULL };
+
+ /*
+ * Tests with AT_FDCWD.
+ */
+
+ long rc = syscall(__NR_execveat, -100, sample, argv, NULL, 0);
+ printf("%s%s(AT_FDCWD, \"%s\"%s, [\"%s\"], NULL, 0) = %s\n",
+ my_secontext, "execveat",
+ sample, sample_secontext,
+ argv[0],
+ sprintrc(rc));
+
+ if (unlink(sample))
+ perror_msg_and_fail("unlink");
+
+ rc = syscall(__NR_execveat, -100, sample, argv, NULL, 0);
+ printf("%s%s(AT_FDCWD, \"%s\", [\"%s\"], NULL, 0) = %s\n",
+ my_secontext, "execveat",
+ sample,
+ argv[0],
+ sprintrc(rc));
+
+ /*
+ * Tests with dirfd.
+ */
+
+ int cwd_fd = get_dir_fd(".");
+ char *cwd = get_fd_path(cwd_fd);
+ char *cwd_secontext = SECONTEXT_FILE(".");
+ char *sample_realpath = xasprintf("%s/%s", cwd, sample);
+
+ /* no file */
+ rc = syscall(__NR_execveat, cwd_fd, sample, argv, NULL, 0);
+ printf("%s%s(%d%s, \"%s\", [\"%s\"], NULL, 0) = %s\n",
+ my_secontext, "execveat",
+ cwd_fd, cwd_secontext,
+ sample,
+ argv[0],
+ sprintrc(rc));
+
+ if (open(sample, O_RDONLY | O_CREAT, 0400) < 0)
+ perror_msg_and_fail("open");
+
+ rc = syscall(__NR_execveat, cwd_fd, sample, argv, NULL, 0);
+ printf("%s%s(%d%s, \"%s\"%s, [\"%s\"], NULL, 0) = %s\n",
+ my_secontext, "execveat",
+ cwd_fd, cwd_secontext,
+ sample, sample_secontext,
+ argv[0],
+ sprintrc(rc));
+
+ /* cwd_fd ignored when path is absolute */
+ if (chdir("../.."))
+ perror_msg_and_fail("chdir");
+
+ rc = syscall(__NR_execveat, cwd_fd, sample_realpath, argv, NULL, 0);
+ printf("%s%s(%d%s, \"%s\"%s, [\"%s\"], NULL, 0) = %s\n",
+ my_secontext, "execveat",
+ cwd_fd, cwd_secontext,
+ sample_realpath, sample_secontext,
+ argv[0],
+ sprintrc(rc));
+
+ if (fchdir(cwd_fd))
+ perror_msg_and_fail("fchdir");
+
+ if (unlink(sample))
+ perror_msg_and_fail("unlink");
+
+ leave_and_remove_subdir();
+}
+
# define FILENAME "test.execveat\nfilename"
# define Q_FILENAME "test.execveat\\nfilename"
@@ -40,9 +133,10 @@ main(void)
{
const char ** const tail_argv = tail_memdup(argv, sizeof(argv));
const char ** const tail_envp = tail_memdup(envp, sizeof(envp));
+ char *my_secontext = SECONTEXT_PID_MY();
syscall(__NR_execveat, -100, FILENAME, tail_argv, tail_envp, 0x1100);
- printf("execveat(AT_FDCWD, \"%s\""
+ printf("%s%s(AT_FDCWD, \"%s\""
", [\"%s\", \"%s\", \"%s\", %p, %p, %p, ... /* %p */]"
# if VERBOSE
", [\"%s\", \"%s\", %p, %p, %p, ... /* %p */]"
@@ -50,6 +144,7 @@ main(void)
", %p /* 5 vars, unterminated */"
# endif
", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
+ my_secontext, "execveat",
Q_FILENAME, q_argv[0], q_argv[1], q_argv[2],
argv[3], argv[4], argv[5], (char *) tail_argv + sizeof(argv),
# if VERBOSE
@@ -65,13 +160,14 @@ main(void)
(void) q_envp; /* workaround for clang bug #33068 */
syscall(__NR_execveat, -100, FILENAME, tail_argv, tail_envp, 0x1100);
- printf("execveat(AT_FDCWD, \"%s\", [\"%s\", \"%s\", \"%s\"]"
+ printf("%s%s(AT_FDCWD, \"%s\", [\"%s\", \"%s\", \"%s\"]"
# if VERBOSE
", [\"%s\", \"%s\"]"
# else
", %p /* 2 vars */"
# endif
", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
+ my_secontext, "execveat",
Q_FILENAME, q_argv[0], q_argv[1], q_argv[2],
# if VERBOSE
q_envp[0], q_envp[1],
@@ -81,13 +177,14 @@ main(void)
errno2name());
syscall(__NR_execveat, -100, FILENAME, tail_argv + 2, tail_envp + 1, 0x1100);
- printf("execveat(AT_FDCWD, \"%s\", [\"%s\"]"
+ printf("%s%s(AT_FDCWD, \"%s\", [\"%s\"]"
# if VERBOSE
", [\"%s\"]"
# else
", %p /* 1 var */"
# endif
", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
+ my_secontext, "execveat",
Q_FILENAME, q_argv[2],
# if VERBOSE
q_envp[1],
@@ -101,13 +198,14 @@ main(void)
*empty = NULL;
syscall(__NR_execveat, -100, FILENAME, empty, empty, 0x1100);
- printf("execveat(AT_FDCWD, \"%s\", []"
+ printf("%s%s(AT_FDCWD, \"%s\", []"
# if VERBOSE
", []"
# else
", %p /* 0 vars */"
# endif
", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
+ my_secontext, "execveat",
Q_FILENAME,
# if !VERBOSE
empty,
@@ -132,7 +230,9 @@ main(void)
a[i] = b[i] = NULL;
syscall(__NR_execveat, -100, FILENAME, a, b, 0x1100);
- printf("execveat(AT_FDCWD, \"%s\", [\"%.*s\"...", Q_FILENAME, DEFAULT_STRLEN, a[0]);
+ printf("%s%s(AT_FDCWD, \"%s\", [\"%.*s\"...",
+ my_secontext, "execveat",
+ Q_FILENAME, DEFAULT_STRLEN, a[0]);
for (i = 1; i < DEFAULT_STRLEN; ++i)
printf(", \"%s\"", a[i]);
# if VERBOSE
@@ -152,7 +252,9 @@ main(void)
errno2name());
syscall(__NR_execveat, -100, FILENAME, a + 1, b + 1, 0x1100);
- printf("execveat(AT_FDCWD, \"%s\", [\"%s\"", Q_FILENAME, a[1]);
+ printf("%s%s(AT_FDCWD, \"%s\", [\"%s\"",
+ my_secontext, "execveat",
+ Q_FILENAME, a[1]);
for (i = 2; i <= DEFAULT_STRLEN; ++i)
printf(", \"%s\"", a[i]);
# if VERBOSE
@@ -167,15 +269,19 @@ main(void)
errno2name());
syscall(__NR_execveat, -100, FILENAME, NULL, efault, 0x1100);
- printf("execveat(AT_FDCWD, \"%s\", NULL, %p"
+ printf("%s%s(AT_FDCWD, \"%s\", NULL, %p"
", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
+ my_secontext, "execveat",
Q_FILENAME, efault, errno2name());
syscall(__NR_execveat, -100, FILENAME, efault, NULL, 0x1100);
- printf("execveat(AT_FDCWD, \"%s\", %p, NULL"
+ printf("%s%s(AT_FDCWD, \"%s\", %p, NULL"
", AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) = -1 %s (%m)\n",
+ my_secontext, "execveat",
Q_FILENAME, efault, errno2name());
+ tests_with_existing_file();
+
puts("+++ exited with 0 +++");
return 0;
}
diff --git a/tests/faccessat.c b/tests/faccessat.c
index 670e9b21f..2b05a8b5a 100644
--- a/tests/faccessat.c
+++ b/tests/faccessat.c
@@ -12,12 +12,16 @@
#ifdef __NR_faccessat
-# include "xmalloc.h"
# include <fcntl.h>
# include <stdio.h>
# include <unistd.h>
-# ifndef FD_PATH
+# include "secontext.h"
+# include "xmalloc.h"
+
+# ifdef FD_PATH
+# define YFLAG
+# else
# define FD_PATH ""
# endif
# ifndef SKIP_IF_PROC_IS_UNAVAILABLE
@@ -43,11 +47,130 @@ k_faccessat(const unsigned int dirfd,
return rc;
}
+# ifndef PATH_TRACING
+static void
+tests_with_existing_file(void)
+{
+ /*
+ * Make sure the current workdir of the tracee
+ * is different from the current workdir of the tracer.
+ */
+ create_and_enter_subdir("faccessat_subdir");
+
+ char *my_secontext = SECONTEXT_PID_MY();
+
+ k_faccessat(-1, NULL, F_OK);
+ printf("%s%s(-1, NULL, F_OK) = %s\n",
+ my_secontext, "faccessat", errstr);
+
+ static const char sample[] = "faccessat_sample";
+ (void) unlink(sample);
+ int fd = open(sample, O_CREAT|O_RDONLY, 0400);
+ if (fd == -1)
+ perror_msg_and_fail("open");
+ close(fd);
+ char *sample_secontext = SECONTEXT_FILE(sample);
+
+ /*
+ * Tests with AT_FDCWD.
+ */
+
+ k_faccessat(-100, sample, F_OK);
+ printf("%s%s(AT_FDCWD, \"%s\"%s, F_OK) = %s\n",
+ my_secontext, "faccessat",
+ sample, sample_secontext,
+ errstr);
+
+ if (unlink(sample))
+ perror_msg_and_fail("unlink");
+
+ k_faccessat(-100, sample, F_OK);
+ printf("%s%s(AT_FDCWD, \"%s\", F_OK) = %s\n",
+ my_secontext, "faccessat",
+ sample,
+ errstr);
+
+ /*
+ * Tests with dirfd.
+ */
+
+ int cwd_fd = get_dir_fd(".");
+ char *cwd = get_fd_path(cwd_fd);
+ char *cwd_secontext = SECONTEXT_FILE(".");
+ char *sample_realpath = xasprintf("%s/%s", cwd, sample);
+
+ /* no file */
+ k_faccessat(cwd_fd, sample, F_OK);
+# ifdef YFLAG
+ printf("%s%s(%d<%s>%s, \"%s\", F_OK) = %s\n",
+# else
+ printf("%s%s(%d%s, \"%s\", F_OK) = %s\n",
+# endif
+ my_secontext, "faccessat",
+ cwd_fd,
+# ifdef YFLAG
+ cwd,
+# endif
+ cwd_secontext,
+ sample,
+ errstr);
+
+ fd = open(sample, O_CREAT|O_RDONLY, 0400);
+ if (fd == -1)
+ perror_msg_and_fail("open");
+ close(fd);
+
+ k_faccessat(cwd_fd, sample, F_OK);
+# ifdef YFLAG
+ printf("%s%s(%d<%s>%s, \"%s\"%s, F_OK) = %s\n",
+# else
+ printf("%s%s(%d%s, \"%s\"%s, F_OK) = %s\n",
+# endif
+ my_secontext, "faccessat",
+ cwd_fd,
+# ifdef YFLAG
+ cwd,
+# endif
+ cwd_secontext,
+ sample, sample_secontext,
+ errstr);
+
+ /* cwd_fd ignored when path is absolute */
+ if (chdir("../.."))
+ perror_msg_and_fail("chdir");
+
+ k_faccessat(cwd_fd, sample_realpath, F_OK);
+# ifdef YFLAG
+ printf("%s%s(%d<%s>%s, \"%s\"%s, F_OK) = %s\n",
+# else
+ printf("%s%s(%d%s, \"%s\"%s, F_OK) = %s\n",
+# endif
+ my_secontext, "faccessat",
+ cwd_fd,
+# ifdef YFLAG
+ cwd,
+# endif
+ cwd_secontext,
+ sample_realpath, sample_secontext,
+ errstr);
+
+ if (fchdir(cwd_fd))
+ perror_msg_and_fail("fchdir");
+
+ if (unlink(sample))
+ perror_msg_and_fail("unlink");
+
+ leave_and_remove_subdir();
+}
+# endif
+
int
main(void)
{
SKIP_IF_PROC_IS_UNAVAILABLE;
+# ifndef TEST_SECONTEXT
+
TAIL_ALLOC_OBJECT_CONST_PTR(const char, unterminated);
char *unterminated_str = xasprintf("%p", unterminated);
const void *const efault = unterminated + 1;
@@ -120,10 +243,10 @@ main(void)
k_faccessat(dirfds[dirfd_i].val,
paths[path_i].val,
modes[mode_i].val);
-# ifdef PATH_TRACING
+# ifdef PATH_TRACING
if (dirfds[dirfd_i].val == fd ||
paths[path_i].val == fd_path)
-# endif
+# endif
printf("faccessat(%s, %s, %s) = %s\n",
dirfds[dirfd_i].str,
paths[path_i].str,
@@ -133,6 +256,12 @@ main(void)
}
}
+# endif /* !TEST_SECONTEXT */
+
+# ifndef PATH_TRACING
+ tests_with_existing_file();
+# endif
+
puts("+++ exited with 0 +++");
return 0;
}
diff --git a/tests/faccessat.test b/tests/faccessat.test
index 83f94ba40..325e343b7 100755
--- a/tests/faccessat.test
+++ b/tests/faccessat.test
@@ -15,5 +15,5 @@ run_prog > /dev/null
run_strace -a23 --trace=faccessat "$@" $args > "$EXP"
# Filter out faccessat() calls made by ld.so and libc.
-sed -n '/^faccessat(-1, NULL,/,$p' < "$LOG" > "$OUT"
+sed -n '/faccessat(-1, NULL,/,$p' < "$LOG" > "$OUT"
match_diff "$OUT" "$EXP"
diff --git a/tests/fanotify_mark.c b/tests/fanotify_mark.c
index bd14f4790..15eab3e01 100644
--- a/tests/fanotify_mark.c
+++ b/tests/fanotify_mark.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
* Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
- * Copyright (c) 2015-2020 The strace developers.
+ * Copyright (c) 2015-2021 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later
@@ -21,6 +21,8 @@
# include <unistd.h>
# include <sys/fanotify.h>
+# include "secontext.h"
+
# if XLAT_RAW
# define str_fan_mark_add "0x1"
# define str_fan_modify_ondir "0x40000002"
@@ -35,6 +37,7 @@
# define str_at_fdcwd "AT_FDCWD"
# endif
+# ifndef TEST_SECONTEXT
/* Performs fanotify_mark call via the syscall interface. */
static void
do_call(kernel_ulong_t fd, kernel_ulong_t flags, const char *flags_str,
@@ -44,18 +47,18 @@ do_call(kernel_ulong_t fd, kernel_ulong_t flags, const char *flags_str,
long rc;
rc = syscall(__NR_fanotify_mark, fd, flags,
-# if (LONG_MAX > INT_MAX) \
- || (defined __x86_64__ && defined __ILP32__) \
- || defined LINUX_MIPSN32
+# if (LONG_MAX > INT_MAX) \
+ || (defined __x86_64__ && defined __ILP32__) \
+ || defined LINUX_MIPSN32
mask,
-# else
+# else
/* arch/parisc/kernel/sys_parisc32.c, commit ab8a261b */
-# ifdef HPPA
+# ifdef HPPA
LL_VAL_TO_PAIR((mask << 32) | (mask >> 32)),
-# else
+# else
LL_VAL_TO_PAIR(mask),
+# endif
# endif
-# endif
dirfd, path);
printf("fanotify_mark(%d, %s, %s, %s, %s) = %s\n",
@@ -68,12 +71,14 @@ struct strval {
const char *str;
};
-# define STR16 "0123456789abcdef"
-# define STR64 STR16 STR16 STR16 STR16
+# define STR16 "0123456789abcdef"
+# define STR64 STR16 STR16 STR16 STR16
+# endif /* !TEST_SECONTEXT */
int
main(void)
{
+# ifndef TEST_SECONTEXT
enum {
PATH1_SIZE = 64,
};
@@ -87,47 +92,47 @@ main(void)
{ F8ILL_KULONG_MASK, "0" },
{ (kernel_ulong_t) 0xdec0deddefacec00ULL,
"0xefacec00"
-# if !XLAT_RAW
+# if !XLAT_RAW
" /* FAN_MARK_??? */"
-# endif
+# endif
},
{ (kernel_ulong_t) 0xda7a105700000040ULL,
-# if XLAT_RAW
+# if XLAT_RAW
"0x40"
-# elif XLAT_VERBOSE
+# elif XLAT_VERBOSE
"0x40 /* FAN_MARK_IGNORED_SURV_MODIFY */"
-# else
+# else
"FAN_MARK_IGNORED_SURV_MODIFY"
-# endif
+# endif
},
{ (kernel_ulong_t) 0xbadc0deddeadffffULL,
-# if XLAT_RAW || XLAT_VERBOSE
+# if XLAT_RAW || XLAT_VERBOSE
"0xdeadffff"
-# endif
-# if XLAT_VERBOSE
+# endif
+# if XLAT_VERBOSE
" /* "
-# endif
-# if !XLAT_RAW
+# endif
+# if !XLAT_RAW
"FAN_MARK_ADD|FAN_MARK_REMOVE|FAN_MARK_DONT_FOLLOW|"
"FAN_MARK_ONLYDIR|FAN_MARK_MOUNT|FAN_MARK_IGNORED_MASK|"
"FAN_MARK_IGNORED_SURV_MODIFY|FAN_MARK_FLUSH|"
"FAN_MARK_FILESYSTEM|0xdeadfe00"
-# endif
-# if XLAT_VERBOSE
+# endif
+# if XLAT_VERBOSE
" */"
-# endif
+# endif
},
};
static const struct strval64 masks[] = {
{ ARG_ULL_STR(0) },
{ 0xdeadfeedffffffffULL,
-# if XLAT_RAW || XLAT_VERBOSE
+# if XLAT_RAW || XLAT_VERBOSE
"0xdeadfeedffffffff"
-# endif
-# if XLAT_VERBOSE
+# endif
+# if XLAT_VERBOSE
" /* "
-# endif
-# if !XLAT_RAW
+# endif
+# if !XLAT_RAW
"FAN_ACCESS|"
"FAN_MODIFY|"
"FAN_ATTRIB|"
@@ -149,27 +154,27 @@ main(void)
"FAN_ONDIR|"
"FAN_EVENT_ON_CHILD|"
"0xdeadfeedb7f0a000"
-# endif
-# if XLAT_VERBOSE
+# endif
+# if XLAT_VERBOSE
" */"
-# endif
+# endif
},
{ ARG_ULL_STR(0xffffffffb7f0a000)
-# if !XLAT_RAW
+# if !XLAT_RAW
" /* FAN_??? */"
-# endif
+# endif
},
};
static const struct strval dirfds[] = {
{ (kernel_ulong_t) 0xfacefeed00000001ULL, "1" },
{ (kernel_ulong_t) 0xdec0ded0ffffffffULL,
-# if XLAT_RAW
+# if XLAT_RAW
"-1"
-# elif XLAT_VERBOSE
+# elif XLAT_VERBOSE
"-1 /* FAN_NOFD */"
-# else
+# else
"FAN_NOFD"
-# endif
+# endif
},
{ (kernel_ulong_t) 0xbadfacedffffff9cULL, str_at_fdcwd },
{ (kernel_ulong_t) 0xdefaced1beeff00dULL, "-1091571699" },
@@ -202,12 +207,6 @@ main(void)
snprintf(bogus_path1_after_addr, sizeof(bogus_path1_after_addr), "%p",
bogus_path1 + PATH1_SIZE);
- rc = fanotify_mark(-1, FAN_MARK_ADD, FAN_MODIFY | FAN_ONDIR,
- -100, ".");
- printf("fanotify_mark(-1, %s, %s, %s, \".\") = %s\n",
- str_fan_mark_add, str_fan_modify_ondir, str_at_fdcwd,
- sprintrc(rc));
-
for (i = 0; i < ARRAY_SIZE(fds); i++) {
for (j = 0; j < ARRAY_SIZE(flags); j++) {
for (k = 0; k < ARRAY_SIZE(masks); k++) {
@@ -226,6 +225,40 @@ main(void)
}
}
}
+# else /* TEST_SECONTEXT */
+ int rc;
+# endif
+ /*
+ * Test with AT_FDCWD.
+ */
+
+ char *my_secontext = SECONTEXT_PID_MY();
+ char path[] = ".";
+ char *path_secontext = SECONTEXT_FILE(path);
+
+ rc = fanotify_mark(-1, FAN_MARK_ADD, FAN_MODIFY | FAN_ONDIR,
+ -100, path);
+ printf("%s%s(-1, %s, %s, %s, \"%s\"%s) = %s\n",
+ my_secontext, "fanotify_mark",
+ str_fan_mark_add, str_fan_modify_ondir, str_at_fdcwd,
+ path, path_secontext,
+ sprintrc(rc));
+
+ /*
+ * Test with dirfd.
+ */
+
+ int cwd_fd = get_dir_fd(".");
+ char *cwd_secontext = SECONTEXT_FILE(".");
+
+ rc = fanotify_mark(-1, FAN_MARK_ADD, FAN_MODIFY | FAN_ONDIR,
+ cwd_fd, path);
+ printf("%s%s(-1, %s, %s, %d%s, \"%s\"%s) = %s\n",
+ my_secontext, "fanotify_mark",
+ str_fan_mark_add, str_fan_modify_ondir,
+ cwd_fd, cwd_secontext,
+ path, path_secontext,
+ sprintrc(rc));
puts("+++ exited with 0 +++");
return 0;
diff --git a/tests/fchmod.c b/tests/fchmod.c
index 4da4f0658..0b0570cfe 100644
--- a/tests/fchmod.c
+++ b/tests/fchmod.c
@@ -18,6 +18,8 @@
# include <stdio.h>
# include <unistd.h>
+# include "secontext.h"
+
int
main(void)
{
@@ -27,6 +29,8 @@ main(void)
*/
create_and_enter_subdir("fchmod_subdir");
+ char *my_secontext = SECONTEXT_PID_MY();
+
static const char sample[] = "fchmod_sample_file";
(void) unlink(sample);
int fd = open(sample, O_CREAT|O_RDONLY, 0400);
@@ -37,16 +41,19 @@ main(void)
char *sample_realpath = get_fd_path(fd);
# endif
+ const char *sample_secontext = SECONTEXT_FILE(sample);
long rc = syscall(__NR_fchmod, fd, 0600);
# ifdef YFLAG
- printf("fchmod(%d<%s>, 0600) = %s\n",
+ printf("%s%s(%d<%s>%s, 0600) = %s\n",
# else
- printf("fchmod(%d, 0600) = %s\n",
+ printf("%s%s(%d%s, 0600) = %s\n",
# endif
+ my_secontext, "fchmod",
fd,
# ifdef YFLAG
sample_realpath,
# endif
+ sample_secontext,
sprintrc(rc));
if (unlink(sample))
@@ -54,26 +61,30 @@ main(void)
rc = syscall(__NR_fchmod, fd, 051);
# ifdef YFLAG
- printf("fchmod(%d<%s (deleted)>, 051) = %s\n",
+ printf("%s%s(%d<%s (deleted)>%s, 051) = %s\n",
# else
- printf("fchmod(%d, 051) = %s\n",
+ printf("%s%s(%d%s, 051) = %s\n",
# endif
+ my_secontext, "fchmod",
fd,
# ifdef YFLAG
sample_realpath,
# endif
+ sample_secontext,
sprintrc(rc));
rc = syscall(__NR_fchmod, fd, 004);
# ifdef YFLAG
- printf("fchmod(%d<%s (deleted)>, 004) = %s\n",
+ printf("%s%s(%d<%s (deleted)>%s, 004) = %s\n",
# else
- printf("fchmod(%d, 004) = %s\n",
+ printf("%s%s(%d%s, 004) = %s\n",
# endif
+ my_secontext, "fchmod",
fd,
# ifdef YFLAG
sample_realpath,
# endif
+ sample_secontext,
sprintrc(rc));
leave_and_remove_subdir();
diff --git a/tests/fchmodat.c b/tests/fchmodat.c
index 37dc6b563..2c69f4624 100644
--- a/tests/fchmodat.c
+++ b/tests/fchmodat.c
@@ -17,6 +17,8 @@
# include <stdio.h>
# include <unistd.h>
+# include "secontext.h"
+
int
main(void)
{
@@ -26,26 +28,81 @@ main(void)
*/
create_and_enter_subdir("fchmodat_subdir");
- static const char sample[] = "fchmodat_sample";
+ char *my_secontext = SECONTEXT_PID_MY();
+ static const char sample[] = "fchmodat_sample_file";
if (open(sample, O_RDONLY | O_CREAT, 0400) < 0)
perror_msg_and_fail("open");
+ char *sample_secontext = SECONTEXT_FILE(sample);
+
+ /*
+ * Tests with AT_FDCWD.
+ */
+
long rc = syscall(__NR_fchmodat, -100, sample, 0600);
- printf("fchmodat(AT_FDCWD, \"%s\", 0600) = %s\n",
- sample, sprintrc(rc));
+ printf("%s%s(AT_FDCWD, \"%s\"%s, 0600) = %s\n",
+ my_secontext, "fchmodat",
+ sample, sample_secontext,
+ sprintrc(rc));
if (unlink(sample))
perror_msg_and_fail("unlink");
rc = syscall(__NR_fchmodat, -100, sample, 051);
- printf("fchmodat(AT_FDCWD, \"%s\", 051) = %s\n",
+ printf("%s%s(AT_FDCWD, \"%s\", 051) = %s\n",
+ my_secontext, "fchmodat",
sample, sprintrc(rc));
rc = syscall(__NR_fchmodat, -100, sample, 004);
- printf("fchmodat(AT_FDCWD, \"%s\", 004) = %s\n",
+ printf("%s%s(AT_FDCWD, \"%s\", 004) = %s\n",
+ my_secontext, "fchmodat",
sample, sprintrc(rc));
+ /*
+ * Tests with dirfd.
+ */
+
+ int cwd_fd = get_dir_fd(".");
+ char *cwd = get_fd_path(cwd_fd);
+ char *cwd_secontext = SECONTEXT_FILE(".");
+ char *sample_realpath = xasprintf("%s/%s", cwd, sample);
+
+ /* no file */
+ rc = syscall(__NR_fchmodat, cwd_fd, sample, 0400);
+ printf("%s%s(%d%s, \"%s\", 0400) = %s\n",
+ my_secontext, "fchmodat",
+ cwd_fd, cwd_secontext,
+ sample,
+ sprintrc(rc));
+
+ if (open(sample, O_RDONLY | O_CREAT, 0400) < 0)
+ perror_msg_and_fail("open");
+
+ rc = syscall(__NR_fchmodat, cwd_fd, sample, 0400);
+ printf("%s%s(%d%s, \"%s\"%s, 0400) = %s\n",
+ my_secontext, "fchmodat",
+ cwd_fd, cwd_secontext,
+ sample, sample_secontext,
+ sprintrc(rc));
+
+ /* cwd_fd ignored when path is absolute */
+ if (chdir("../.."))
+ perror_msg_and_fail("chdir");
+
+ rc = syscall(__NR_fchmodat, cwd_fd, sample_realpath, 0400);
+ printf("%s%s(%d%s, \"%s\"%s, 0400) = %s\n",
+ my_secontext, "fchmodat",
+ cwd_fd, cwd_secontext,
+ sample_realpath, sample_secontext,
+ sprintrc(rc));
+
+ if (fchdir(cwd_fd))
+ perror_msg_and_fail("fchdir");
+
+ if (unlink(sample))
+ perror_msg_and_fail("unlink");
+
leave_and_remove_subdir();
puts("+++ exited with 0 +++");
diff --git a/tests/fchownat.c b/tests/fchownat.c
index 766fd0241..bebb25445 100644
--- a/tests/fchownat.c
+++ b/tests/fchownat.c
@@ -17,6 +17,8 @@
# include <stdio.h>
# include <unistd.h>
+# include "secontext.h"
+
int
main(void)
{
@@ -26,25 +28,86 @@ main(void)
*/
create_and_enter_subdir("fchownat_subdir");
- static const char sample[] = "fchownat_sample";
+ char *my_secontext = SECONTEXT_PID_MY();
uid_t uid = geteuid();
uid_t gid = getegid();
- if (open(sample, O_RDONLY | O_CREAT, 0400) == -1)
+ static const char sample[] = "fchownat_sample";
+ int fd = open(sample, O_RDONLY | O_CREAT, 0400);
+ if (fd == -1)
perror_msg_and_fail("open");
+ close(fd);
+
+ char *sample_secontext = SECONTEXT_FILE(sample);
+
+ /*
+ * Tests with AT_FDCWD.
+ */
long rc = syscall(__NR_fchownat, AT_FDCWD, sample, uid, gid, 0);
- printf("fchownat(AT_FDCWD, \"%s\", %d, %d, 0) = %s\n",
- sample, uid, gid, sprintrc(rc));
+ printf("%s%s(AT_FDCWD, \"%s\"%s, %d, %d, 0) = %s\n",
+ my_secontext, "fchownat",
+ sample, sample_secontext,
+ uid, gid, sprintrc(rc));
if (unlink(sample))
perror_msg_and_fail("unlink");
rc = syscall(__NR_fchownat, AT_FDCWD,
sample, -1, -1L, AT_SYMLINK_NOFOLLOW);
- printf("fchownat(AT_FDCWD, \"%s\", -1, -1, AT_SYMLINK_NOFOLLOW) = %s\n",
+ printf("%s%s(AT_FDCWD, \"%s\", -1, -1, AT_SYMLINK_NOFOLLOW) = %s\n",
+ my_secontext, "fchownat",
sample, sprintrc(rc));
+ /*
+ * Tests with dirfd.
+ */
+
+ int cwd_fd = get_dir_fd(".");
+ char *cwd = get_fd_path(cwd_fd);
+ char *cwd_secontext = SECONTEXT_FILE(".");
+ char *sample_realpath = xasprintf("%s/%s", cwd, sample);
+
+ /* no file */
+ rc = syscall(__NR_fchownat, cwd_fd, sample, uid, gid, 0);
+ printf("%s%s(%d%s, \"%s\", %d, %d, 0) = %s\n",
+ my_secontext, "fchownat",
+ cwd_fd, cwd_secontext,
+ sample,
+ uid, gid,
+ sprintrc(rc));
+
+ fd = open(sample, O_RDONLY | O_CREAT, 0400);
+ if (fd == -1)
+ perror_msg_and_fail("open");
+ close(fd);
+
+ rc = syscall(__NR_fchownat, cwd_fd, sample, uid, gid, 0);
+ printf("%s%s(%d%s, \"%s\"%s, %d, %d, 0) = %s\n",
+ my_secontext, "fchownat",
+ cwd_fd, cwd_secontext,
+ sample, sample_secontext,
+ uid, gid,
+ sprintrc(rc));
+
+ /* cwd_fd ignored when path is absolute */
+ if (chdir("../.."))
+ perror_msg_and_fail("chdir");
+
+ rc = syscall(__NR_fchownat, cwd_fd, sample_realpath, uid, gid, 0);
+ printf("%s%s(%d%s, \"%s\"%s, %d, %d, 0) = %s\n",
+ my_secontext, "fchownat",
+ cwd_fd, cwd_secontext,
+ sample_realpath, sample_secontext,
+ uid, gid,
+ sprintrc(rc));
+
+ if (fchdir(cwd_fd))
+ perror_msg_and_fail("fchdir");
+
+ if (unlink(sample))
+ perror_msg_and_fail("unlink");
+
leave_and_remove_subdir();
puts("+++ exited with 0 +++");
diff --git a/tests/file_handle.c b/tests/file_handle.c
index e6a69910b..86d51b636 100644
--- a/tests/file_handle.c
+++ b/tests/file_handle.c
@@ -21,6 +21,8 @@
# include <stdio.h>
# include <unistd.h>
+# include "secontext.h"
+
enum assert_rc {
ASSERT_NONE,
ASSERT_SUCCESS,
@@ -48,6 +50,7 @@ print_handle_data(unsigned char *bytes, unsigned int size)
printf("...");
}
+# ifndef TEST_SECONTEXT
void
do_name_to_handle_at(kernel_ulong_t dirfd, const char *dirfd_str,
kernel_ulong_t pathname, const char *pathname_str,
@@ -129,6 +132,7 @@ do_open_by_handle_at(kernel_ulong_t mount_fd,
printf("%s\n", sprintrc(rc));
}
+# endif /* !TEST_SECONTEXT */
struct strval {
kernel_ulong_t val;
@@ -141,12 +145,86 @@ struct strval {
int
main(void)
{
+ char *my_secontext = SECONTEXT_PID_MY();
enum {
PATH1_SIZE = 64,
};
static const kernel_ulong_t fdcwd =
(kernel_ulong_t) 0x87654321ffffff9cULL;
+
+ struct file_handle *handle =
+ tail_alloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
+ struct file_handle *handle_0 =
+ tail_alloc(sizeof(struct file_handle) + 0);
+ struct file_handle *handle_8 =
+ tail_alloc(sizeof(struct file_handle) + 8);
+ struct file_handle *handle_128 =
+ tail_alloc(sizeof(struct file_handle) + 128);
+ struct file_handle *handle_256 =
+ tail_alloc(sizeof(struct file_handle) + 256);
+ TAIL_ALLOC_OBJECT_CONST_PTR(int, bogus_mount_id);
+
+ char handle_0_addr[sizeof("0x") + sizeof(void *) * 2];
+
+ const int flags = 0x400;
+ int mount_id;
+
+ handle_0->handle_bytes = 256;
+ handle_8->handle_bytes = 0;
+ handle_128->handle_bytes = 128;
+ handle_256->handle_bytes = 256;
+
+ fill_memory((char *) handle_128 + sizeof(struct file_handle), 128);
+ fill_memory((char *) handle_256 + sizeof(struct file_handle), 256);
+
+ snprintf(handle_0_addr, sizeof(handle_0_addr), "%p",
+ handle_0 + sizeof(struct file_handle));
+
+ handle->handle_bytes = 0;
+
+ char path[] = ".";
+ char *path_secontext = SECONTEXT_FILE(path);
+
+ assert(syscall(__NR_name_to_handle_at, fdcwd, path, handle, &mount_id,
+ flags | 1) == -1);
+ if (EINVAL != errno)
+ perror_msg_and_skip("name_to_handle_at");
+ printf("%s%s(AT_FDCWD, \"%s\"%s, {handle_bytes=0}, %p"
+ ", AT_SYMLINK_FOLLOW|0x1) = -1 EINVAL (%m)\n",
+ my_secontext, "name_to_handle_at",
+ path, path_secontext,
+ &mount_id);
+
+ assert(syscall(__NR_name_to_handle_at, fdcwd, path, handle, &mount_id,
+ flags) == -1);
+ if (EOVERFLOW != errno)
+ perror_msg_and_skip("name_to_handle_at");
+ printf("%s%s(AT_FDCWD, \"%s\"%s, {handle_bytes=0 => %u}"
+ ", %p, AT_SYMLINK_FOLLOW) = -1 EOVERFLOW (%m)\n",
+ my_secontext, "name_to_handle_at",
+ path, path_secontext,
+ handle->handle_bytes, &mount_id);
+
+ assert(syscall(__NR_name_to_handle_at, fdcwd, path, handle, &mount_id,
+ flags) == 0);
+ printf("%s%s(AT_FDCWD, \"%s\"%s, {handle_bytes=%u"
+ ", handle_type=%d, f_handle=",
+ my_secontext, "name_to_handle_at",
+ path, path_secontext,
+ handle->handle_bytes, handle->handle_type);
+ print_handle_data(handle->f_handle, handle->handle_bytes);
+ printf("}, [%d], AT_SYMLINK_FOLLOW) = 0\n", mount_id);
+
+ printf("%s%s(-1, {handle_bytes=%u, handle_type=%d, f_handle=",
+ my_secontext, "open_by_handle_at",
+ handle->handle_bytes, handle->handle_type);
+ print_handle_data(handle->f_handle, handle->handle_bytes);
+ int rc = syscall(__NR_open_by_handle_at, -1, handle,
+ O_RDONLY | O_DIRECTORY);
+ printf("}, O_RDONLY|O_DIRECTORY) = %d %s (%m)\n", rc, errno2name());
+
+# ifndef TEST_SECONTEXT
static const struct strval dirfds[] = {
{ (kernel_ulong_t) 0xdeadca57badda7a1ULL, "-1159878751" },
{ (kernel_ulong_t) 0x12345678ffffff9cULL, "AT_FDCWD" },
@@ -171,29 +249,11 @@ main(void)
};
static const char str64[] = STR64;
-
-
char *bogus_path1 = tail_memdup(str64, PATH1_SIZE);
char *bogus_path2 = tail_memdup(str64, sizeof(str64));
-
- struct file_handle *handle =
- tail_alloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
- struct file_handle *handle_0 =
- tail_alloc(sizeof(struct file_handle) + 0);
- struct file_handle *handle_8 =
- tail_alloc(sizeof(struct file_handle) + 8);
- struct file_handle *handle_128 =
- tail_alloc(sizeof(struct file_handle) + 128);
- struct file_handle *handle_256 =
- tail_alloc(sizeof(struct file_handle) + 256);
- TAIL_ALLOC_OBJECT_CONST_PTR(int, bogus_mount_id);
-
- char handle_0_addr[sizeof("0x") + sizeof(void *) * 2];
-
char bogus_path1_addr[sizeof("0x") + sizeof(void *) * 2];
char bogus_path1_after_addr[sizeof("0x") + sizeof(void *) * 2];
-
struct strval paths[] = {
{ (kernel_ulong_t) 0, "NULL" },
{ (kernel_ulong_t) (uintptr_t) (bogus_path1 + PATH1_SIZE),
@@ -229,62 +289,16 @@ main(void)
(kernel_ulong_t) (uintptr_t) bogus_mount_id,
};
- const int flags = 0x400;
- int mount_id;
unsigned int i;
unsigned int j;
unsigned int k;
unsigned int l;
unsigned int m;
-
snprintf(bogus_path1_addr, sizeof(bogus_path1_addr), "%p", bogus_path1);
snprintf(bogus_path1_after_addr, sizeof(bogus_path1_after_addr), "%p",
bogus_path1 + PATH1_SIZE);
- handle_0->handle_bytes = 256;
- handle_8->handle_bytes = 0;
- handle_128->handle_bytes = 128;
- handle_256->handle_bytes = 256;
-
- fill_memory((char *) handle_128 + sizeof(struct file_handle), 128);
- fill_memory((char *) handle_256 + sizeof(struct file_handle), 256);
-
- snprintf(handle_0_addr, sizeof(handle_0_addr), "%p",
- handle_0 + sizeof(struct file_handle));
-
- handle->handle_bytes = 0;
-
- assert(syscall(__NR_name_to_handle_at, fdcwd, ".", handle, &mount_id,
- flags | 1) == -1);
- if (EINVAL != errno)
- perror_msg_and_skip("name_to_handle_at");
- printf("name_to_handle_at(AT_FDCWD, \".\", {handle_bytes=0}, %p"
- ", AT_SYMLINK_FOLLOW|0x1) = -1 EINVAL (%m)\n", &mount_id);
-
- assert(syscall(__NR_name_to_handle_at, fdcwd, ".", handle, &mount_id,
- flags) == -1);
- if (EOVERFLOW != errno)
- perror_msg_and_skip("name_to_handle_at");
- printf("name_to_handle_at(AT_FDCWD, \".\", {handle_bytes=0 => %u}"
- ", %p, AT_SYMLINK_FOLLOW) = -1 EOVERFLOW (%m)\n",
- handle->handle_bytes, &mount_id);
-
- assert(syscall(__NR_name_to_handle_at, fdcwd, ".", handle, &mount_id,
- flags) == 0);
- printf("name_to_handle_at(AT_FDCWD, \".\", {handle_bytes=%u"
- ", handle_type=%d, f_handle=",
- handle->handle_bytes, handle->handle_type);
- print_handle_data(handle->f_handle, handle->handle_bytes);
- printf("}, [%d], AT_SYMLINK_FOLLOW) = 0\n", mount_id);
-
- printf("open_by_handle_at(-1, {handle_bytes=%u, handle_type=%d"
- ", f_handle=", handle->handle_bytes, handle->handle_type);
- print_handle_data(handle->f_handle, handle->handle_bytes);
- int rc = syscall(__NR_open_by_handle_at, -1, handle,
- O_RDONLY | O_DIRECTORY);
- printf("}, O_RDONLY|O_DIRECTORY) = %d %s (%m)\n", rc, errno2name());
-
for (i = 0; i < ARRAY_SIZE(dirfds); i++) {
for (j = 0; j < ARRAY_SIZE(paths); j++) {
for (k = 0; k < ARRAY_SIZE(name_handles); k++) {
@@ -320,6 +334,68 @@ main(void)
}
}
}
+# endif
+
+ /*
+ * Tests with dirfd.
+ */
+
+ int cwd_fd = get_dir_fd(".");
+ char *cwd = get_fd_path(cwd_fd);
+ char *cwd_secontext = SECONTEXT_FILE(".");
+
+ assert(syscall(__NR_name_to_handle_at, cwd_fd, path, handle, &mount_id,
+ flags) == 0);
+ printf("%s%s(%d%s, \"%s\"%s, {handle_bytes=%u, handle_type=%d"
+ ", f_handle=",
+ my_secontext, "name_to_handle_at",
+ cwd_fd, cwd_secontext,
+ path, path_secontext,
+ handle->handle_bytes, handle->handle_type);
+ print_handle_data((unsigned char *) handle +
+ sizeof(struct file_handle),
+ handle->handle_bytes);
+ printf("}, [%d], AT_SYMLINK_FOLLOW) = 0\n", mount_id);
+
+ printf("%s%s(-1, {handle_bytes=%u, handle_type=%d, f_handle=",
+ my_secontext, "open_by_handle_at",
+ handle->handle_bytes, handle->handle_type);
+ print_handle_data((unsigned char *) handle +
+ sizeof(struct file_handle),
+ handle->handle_bytes);
+ rc = syscall(__NR_open_by_handle_at, -1, handle,
+ O_RDONLY | O_DIRECTORY);
+ printf("}, O_RDONLY|O_DIRECTORY) = %s\n", sprintrc(rc));
+
+ /* cwd_fd ignored when path is absolute */
+ if (chdir(".."))
+ perror_msg_and_fail("chdir");
+
+ assert(syscall(__NR_name_to_handle_at, cwd_fd, cwd, handle, &mount_id,
+ flags) == 0);
+ printf("%s%s(%d%s, \"%s\"%s, {handle_bytes=%u"
+ ", handle_type=%d, f_handle=",
+ my_secontext, "name_to_handle_at",
+ cwd_fd, cwd_secontext,
+ cwd, cwd_secontext,
+ handle->handle_bytes, handle->handle_type);
+ print_handle_data((unsigned char *) handle +
+ sizeof(struct file_handle),
+ handle->handle_bytes);
+ printf("}, [%d], AT_SYMLINK_FOLLOW) = 0\n", mount_id);
+
+ printf("%s%s(-1, {handle_bytes=%u, handle_type=%d, f_handle=",
+ my_secontext, "open_by_handle_at",
+ handle->handle_bytes, handle->handle_type);
+ print_handle_data((unsigned char *) handle +
+ sizeof(struct file_handle),
+ handle->handle_bytes);
+ rc = syscall(__NR_open_by_handle_at, -1, handle,
+ O_RDONLY | O_DIRECTORY);
+ printf("}, O_RDONLY|O_DIRECTORY) = %s\n", sprintrc(rc));
+
+ if (fchdir(cwd_fd))
+ perror_msg_and_fail("fchdir");
puts("+++ exited with 0 +++");
return 0;
diff --git a/tests/gen_secontext.sh b/tests/gen_secontext.sh
new file mode 100755
index 000000000..407a39b9f
--- /dev/null
+++ b/tests/gen_secontext.sh
@@ -0,0 +1,72 @@
+#!/bin/sh -efu
+#
+# Copyright (c) 2021 The strace developers.
+# All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+usage()
+{
+ cat >&2 <<EOF
+Usage: $0 [<input>]
+
+Generate secontext files from <input> list.
+EOF
+ exit 1
+}
+
+if [ $# -eq 0 ]; then
+ input="${0%/*}/gen_tests.in"
+else
+ input="$1"
+ shift
+fi
+dir="$(dirname "$input")"
+[ $# -eq 0 ] || usage
+
+{
+ cat <<EOF
+# Generated by $0 from $input; do not edit.
+
+secontext_EXECUTABLES = \\
+EOF
+ sed -r -n 's/^([^#[:space:]]+--secontext(_full)?)[[:space:]].*/ \1 \\/p' < "$input"
+ cat <<EOF
+ #
+
+EOF
+ sed -r -n 's/-/_/g; s/^([^#[:space:]]+__secontext(_full)?)[[:space:]].*/\1_LDADD = \$(LDADD) \$(libselinux_LDADD)/p' < "$input"
+} > "$dir/secontext.am"
+
+sed -r -n 's/^([^#[:space:]]+--secontext)[[:space:]].*/\1/p' < "$input" |
+while read -r name; do {
+ cat <<-EOF > "$dir/$name.c"
+ /*
+ * Copyright (c) 2021 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+ #include "tests.h"
+
+ #ifdef HAVE_SELINUX_RUNTIME
+
+ # define TEST_SECONTEXT
+ # include "${name%--secontext}.c"
+
+ #else
+
+ SKIP_MAIN_UNDEFINED("HAVE_SELINUX_RUNTIME")
+
+ #endif
+ EOF
+} < /dev/null; done
+
+sed -r -n 's/^([^#[:space:]]+--secontext_full)[[:space:]].*/\1/p' < "$input" |
+while read -r name; do {
+ cat <<-EOF > "$dir/$name.c"
+ #define PRINT_SECONTEXT_FULL
+ #include "${name%_full}.c"
+ EOF
+} < /dev/null; done
diff --git a/tests/gen_tests.in b/tests/gen_tests.in
index 93702bafe..5ca88e29a 100644
--- a/tests/gen_tests.in
+++ b/tests/gen_tests.in
@@ -10,6 +10,8 @@ _newselect-P -e trace=_newselect -P /dev/full 9>>/dev/full
accept -a22
accept4 -a37
access -a30 --trace-path=access_sample
+access--secontext -a30 --secontext --trace-path=access_sample -e trace=access
+access--secontext_full -a30 --secontext=full --trace-path=access_sample -e trace=access
acct -a20
add_key -a30 -s12
adjtimex -a15
@@ -25,6 +27,8 @@ bpf-v -a20 -v -e trace=bpf
btrfs +ioctl.test
chdir -a10
chmod -a28
+chmod--secontext -a28 --secontext -e trace=chmod
+chmod--secontext_full -a28 --secontext=full -e trace=chmod
chown -a28
chown32 -a31
chroot -a13
@@ -81,10 +85,18 @@ epoll_pwait2-P --trace=epoll_pwait2 -P /dev/full
epoll_pwait2-y --trace=epoll_pwait2 -y
epoll_wait -a26
erestartsys -a34 -e signal=none -e trace=recvfrom
+execve--secontext +execve.test --secontext
+execve--secontext_full +execve.test --secontext=full
execveat
+execveat--secontext --secontext --trace=execveat
+execveat--secontext_full --secontext=full --trace=execveat
execveat-v -v -e trace=execveat
+faccessat--secontext +faccessat.test -a24 --secontext
+faccessat--secontext_full +faccessat.test -a24 --secontext=full
faccessat-P -a23 --trace=faccessat -P /dev/full
faccessat-y +faccessat.test -a24 -y
+faccessat-y--secontext +faccessat.test -a24 -y --secontext
+faccessat-y--secontext_full +faccessat.test -a24 -y --secontext=full
faccessat-yy +faccessat.test -a24 -yy
faccessat2-P -a27 --trace=faccessat2 -P /dev/full
faccessat2-y +faccessat2.test -a28 -y
@@ -93,22 +105,34 @@ fadvise64_64 +fadvise64.test
fallocate -a18
fanotify_init
fanotify_mark -a32
+fanotify_mark--secontext -a32 --secontext -e trace=fanotify_mark
+fanotify_mark--secontext_full -a32 --secontext=full -e trace=fanotify_mark
fanotify_mark-Xabbrev -a32 -Xabbrev -e trace=fanotify_mark
fanotify_mark-Xraw -a32 -Xraw -e trace=fanotify_mark
fanotify_mark-Xverbose -a32 -Xverbose -e trace=fanotify_mark
fchdir -a11
fchmod -a15
+fchmod--secontext -a15 --secontext -e trace=fchmod
+fchmod--secontext_full -a15 --secontext=full -e trace=fchmod
fchmod-y -y -e trace=fchmod
+fchmod-y--secontext -a15 -y --secontext -e trace=fchmod
+fchmod-y--secontext_full -a15 -y --secontext=full -e trace=fchmod
fchmodat
+fchmodat--secontext --secontext -e trace=fchmodat
+fchmodat--secontext_full --secontext=full -e trace=fchmodat
fchown -a16
fchown32 -a18
fchownat
+fchownat--secontext --secontext -e trace=fchownat
+fchownat--secontext_full --secontext=full -e trace=fchownat
fcntl -a8
fcntl--pidns-translation test_pidns -a8 -e trace=fcntl
fcntl64 -a8
fcntl64--pidns-translation test_pidns -a8 -e trace=fcntl64
fdatasync -a14
file_handle -e trace=name_to_handle_at,open_by_handle_at
+file_handle--secontext --secontext -e trace=name_to_handle_at,open_by_handle_at
+file_handle--secontext_full --secontext=full -e trace=name_to_handle_at,open_by_handle_at
filter_seccomp . "${srcdir=.}/filter_seccomp.sh"; test_prog_set --seccomp-bpf -f
filter_seccomp-flag ../$NAME
finit_module -a25
@@ -353,6 +377,8 @@ lchown -a30
lchown32 -a32
link
linkat
+linkat--secontext --secontext -e trace=linkat
+linkat--secontext_full --secontext=full -e trace=linkat
lookup_dcookie -a27
lstat -a31 --no-abbrev --trace-path=stat.sample --trace-path=/dev/full
lstat64 -a32 --no-abbrev --trace-path=stat.sample --trace-path=/dev/full
@@ -492,9 +518,13 @@ oldselect-efault -a13 -e trace=select
oldselect-efault-P -a13 -e trace=select -P /dev/full 9>>/dev/full
oldstat -a32 -v -P stat.sample -P /dev/full
open -a30 -P $NAME.sample
+open--secontext -a30 -P open.sample --secontext --trace=open
+open--secontext_full -a30 -P open.sample --secontext=full --trace=open
open_tree -a30 -y
open_tree-P -a30 --decode-fds -P /dev/full -e trace=open_tree
openat -a36 -P $NAME.sample
+openat--secontext -a36 -P openat.sample -P $PWD/openat.sample --secontext -e trace=openat
+openat--secontext_full -a36 -P openat.sample -P $PWD/openat.sample --secontext=full -e trace=openat
openat2 -a35
openat2-Xabbrev --trace=openat2 -a35 -Xabbrev
openat2-Xraw --trace=openat2 -a32 -Xraw
diff --git a/tests/linkat.c b/tests/linkat.c
index 6fcc6b4cf..bf6b6e39e 100644
--- a/tests/linkat.c
+++ b/tests/linkat.c
@@ -10,8 +10,14 @@
#ifdef __NR_linkat
+# include <fcntl.h>
# include <stdio.h>
+# include <stdlib.h>
# include <unistd.h>
+# include <sys/stat.h>
+
+# include "secontext.h"
+# include "xmalloc.h"
int
main(void)
@@ -27,18 +33,158 @@ main(void)
const long fd_old = (long) 0xdeadbeefffffffffULL;
const long fd_new = (long) 0xdeadbeeffffffffeULL;
+ char *my_secontext = SECONTEXT_PID_MY();
+
+ (void) unlink(sample_1);
+ (void) unlink(sample_2);
+
long rc = syscall(__NR_linkat, fd_old, sample_1, fd_new, sample_2, 0);
- printf("linkat(%d, \"%s\", %d, \"%s\", 0) = %ld %s (%m)\n",
+ printf("%s%s(%d, \"%s\", %d, \"%s\", 0) = %ld %s (%m)\n",
+ my_secontext, "linkat",
(int) fd_old, sample_1, (int) fd_new, sample_2,
rc, errno2name());
rc = syscall(__NR_linkat, -100, sample_1, -100, sample_2, -1L);
- printf("linkat(%s, \"%s\", %s, \"%s\", %s) = %ld %s (%m)\n",
+ printf("%s%s(%s, \"%s\", %s, \"%s\", %s) = %ld %s (%m)\n",
+ my_secontext, "linkat",
"AT_FDCWD", sample_1, "AT_FDCWD", sample_2,
"AT_SYMLINK_NOFOLLOW|AT_REMOVEDIR|AT_SYMLINK_FOLLOW"
"|AT_NO_AUTOMOUNT|AT_EMPTY_PATH|AT_RECURSIVE|0xffff60ff",
rc, errno2name());
+ /*
+ * Tests with AT_FDCWD.
+ */
+
+ int fd_sample_1 = open(sample_1, O_RDONLY | O_CREAT, 0400);
+ if (fd_sample_1 < 0)
+ perror_msg_and_fail("open");
+ if (close(fd_sample_1))
+ perror_msg_and_fail("close");
+
+ char *sample_1_secontext = SECONTEXT_FILE(sample_1);
+
+ rc = syscall(__NR_linkat, -100, sample_1, -100, sample_2, 0);
+ /* no context printed for sample_2 since file doesn't exist yet */
+ printf("%s%s(AT_FDCWD, \"%s\"%s, AT_FDCWD, \"%s\", 0) = %s\n",
+ my_secontext, "linkat",
+ sample_1, sample_1_secontext,
+ sample_2,
+ sprintrc(rc));
+
+ const char *sample_2_secontext = sample_1_secontext;
+
+ rc = syscall(__NR_linkat, -100, sample_1, -100, sample_2, 0);
+ printf("%s%s(AT_FDCWD, \"%s\"%s, AT_FDCWD, \"%s\"%s, 0) = %s\n",
+ my_secontext, "linkat",
+ sample_1, sample_1_secontext,
+ sample_2, sample_2_secontext,
+ sprintrc(rc));
+
+ int fd_sample_2 = open(sample_2, O_RDONLY | O_CREAT, 0400);
+ if (fd_sample_2 < 0)
+ perror_msg_and_fail("open");
+ if (close(fd_sample_2))
+ perror_msg_and_fail("close");
+
+ free(sample_1_secontext);
+ update_secontext_type(sample_1, "default_t");
+ sample_1_secontext = SECONTEXT_FILE(sample_1);
+ sample_2_secontext = sample_1_secontext;
+
+ rc = syscall(__NR_linkat, -100, sample_1, -100, sample_2, 0);
+ printf("%s%s(AT_FDCWD, \"%s\"%s, AT_FDCWD, \"%s\"%s, 0) = %s\n",
+ my_secontext, "linkat",
+ sample_1, sample_1_secontext,
+ sample_2, sample_2_secontext,
+ sprintrc(rc));
+
+ if (unlink(sample_2))
+ perror_msg_and_fail("unlink: %s", sample_2);
+
+ /*
+ * Tests with dirfd.
+ */
+
+ int dfd_old = get_dir_fd(".");
+ char *cwd = get_fd_path(dfd_old);
+ char *dfd_old_secontext = SECONTEXT_FILE(".");
+
+ rc = syscall(__NR_linkat, dfd_old, sample_1, -100, sample_2, 0);
+ /* no context printed for sample_2 since file doesn't exist yet */
+ printf("%s%s(%d%s, \"%s\"%s, AT_FDCWD, \"%s\", 0) = %s\n",
+ my_secontext, "linkat",
+ dfd_old, dfd_old_secontext,
+ sample_1, sample_1_secontext,
+ sample_2,
+ sprintrc(rc));
+
+ rc = syscall(__NR_linkat, dfd_old, sample_1, -100, sample_2, 0);
+ printf("%s%s(%d%s, \"%s\"%s, AT_FDCWD, \"%s\"%s, 0) = %s\n",
+ my_secontext, "linkat",
+ dfd_old, dfd_old_secontext,
+ sample_1, sample_1_secontext,
+ sample_2, sample_2_secontext,
+ sprintrc(rc));
+
+ if (unlink(sample_2))
+ perror_msg_and_fail("unlink: %s", sample_2);
+
+ static const char new_dir[] = "new";
+ char *new_sample_2 = xasprintf("%s/%s", new_dir, sample_2);
+
+ (void) unlink(new_sample_2);
+ (void) rmdir(new_dir);
+
+ if (mkdir(new_dir, 0700))
+ perror_msg_and_fail("mkdir");
+ char *new_dir_realpath = xasprintf("%s/%s", cwd, new_dir);
+ char *new_dir_secontext = SECONTEXT_FILE(new_dir);
+ int dfd_new = get_dir_fd(new_dir);
+
+ rc = syscall(__NR_linkat, dfd_old, sample_1, dfd_new, sample_2, 0);
+ /* no context printed for sample_2 since file doesn't exist yet */
+ printf("%s%s(%d%s, \"%s\"%s, %d%s, \"%s\", 0) = %s\n",
+ my_secontext, "linkat",
+ dfd_old, dfd_old_secontext,
+ sample_1, sample_1_secontext,
+ dfd_new, new_dir_secontext,
+ sample_2,
+ sprintrc(rc));
+
+ rc = syscall(__NR_linkat, dfd_old, sample_1, dfd_new, sample_2, 0);
+ printf("%s%s(%d%s, \"%s\"%s, %d%s, \"%s\"%s, 0) = %s\n",
+ my_secontext, "linkat",
+ dfd_old, dfd_old_secontext,
+ sample_1, sample_1_secontext,
+ dfd_new, new_dir_secontext,
+ sample_2, SECONTEXT_FILE(new_sample_2),
+ sprintrc(rc));
+
+ char *new_sample_2_realpath = xasprintf("%s/%s", new_dir_realpath, sample_2);
+
+ /* dfd ignored when path is absolute */
+ if (chdir("../.."))
+ perror_msg_and_fail("chdir");
+
+ rc = syscall(__NR_linkat, dfd_old, sample_1, -100, new_sample_2_realpath, 0);
+ printf("%s%s(%d%s, \"%s\"%s, AT_FDCWD, \"%s\"%s, 0) = %s\n",
+ my_secontext, "linkat",
+ dfd_old, dfd_old_secontext,
+ sample_1, sample_1_secontext,
+ new_sample_2_realpath, SECONTEXT_FILE(new_sample_2_realpath),
+ sprintrc(rc));
+
+ if (fchdir(dfd_old))
+ perror_msg_and_fail("fchdir");
+
+ if (unlink(sample_1))
+ perror_msg_and_fail("unlink: %s", sample_1);
+ if (unlink(new_sample_2))
+ perror_msg_and_fail("unlink: %s", new_sample_2);
+ if (rmdir(new_dir))
+ perror_msg_and_fail("rmdir: %s", new_dir);
+
leave_and_remove_subdir();
puts("+++ exited with 0 +++");
diff --git a/tests/open.c b/tests/open.c
index 3fce327ba..5c7295395 100644
--- a/tests/open.c
+++ b/tests/open.c
@@ -15,6 +15,8 @@
# include <stdio.h>
# include <unistd.h>
+# include "secontext.h"
+
int
main(void)
{
@@ -25,10 +27,12 @@ main(void)
create_and_enter_subdir("open_subdir");
static const char sample[] = "open.sample";
+ char *my_secontext = SECONTEXT_PID_MY();
long fd = syscall(__NR_open, sample, O_RDONLY|O_CREAT, 0400);
- printf("open(\"%s\", O_RDONLY|O_CREAT, 0400) = %s\n",
- sample, sprintrc(fd));
+ printf("%s%s(\"%s\", O_RDONLY|O_CREAT, 0400) = %s%s\n",
+ my_secontext, "open",
+ sample, sprintrc(fd), SECONTEXT_FILE(sample));
if (fd != -1) {
close(fd);
@@ -36,16 +40,18 @@ main(void)
perror_msg_and_fail("unlink");
fd = syscall(__NR_open, sample, O_RDONLY);
- printf("open(\"%s\", O_RDONLY) = %s\n", sample, sprintrc(fd));
+ printf("%s%s(\"%s\", O_RDONLY) = %s\n",
+ my_secontext, "open", sample, sprintrc(fd));
fd = syscall(__NR_open, sample, O_WRONLY|O_NONBLOCK|0x80000000);
- printf("open(\"%s\", O_WRONLY|O_NONBLOCK|0x80000000) = %s\n",
- sample, sprintrc(fd));
+ printf("%s%s(\"%s\", O_WRONLY|O_NONBLOCK|0x80000000) = %s\n",
+ my_secontext, "open", sample, sprintrc(fd));
}
# ifdef O_TMPFILE
fd = syscall(__NR_open, sample, O_WRONLY|O_TMPFILE, 0600);
- printf("open(\"%s\", O_WRONLY|O_TMPFILE, 0600) = %s\n",
+ printf("%s%s(\"%s\", O_WRONLY|O_TMPFILE, 0600) = %s\n",
+ my_secontext, "open",
sample, sprintrc(fd));
# endif /* O_TMPFILE */
diff --git a/tests/openat.c b/tests/openat.c
index 0c4bb3d10..b43055d3c 100644
--- a/tests/openat.c
+++ b/tests/openat.c
@@ -15,6 +15,8 @@
# include <stdio.h>
# include <unistd.h>
+# include "secontext.h"
+
# ifdef O_TMPFILE
/* The kernel & C libraries often inline O_DIRECTORY. */
# define STRACE_O_TMPFILE (O_TMPFILE & ~O_DIRECTORY)
@@ -26,10 +28,12 @@ static const char sample[] = "openat.sample";
static void
test_mode_flag(unsigned int mode_val, const char *mode_str,
- unsigned int flag_val, const char *flag_str)
+ unsigned int flag_val, const char *flag_str,
+ const char *my_secontext)
{
long rc = syscall(__NR_openat, -1, sample, mode_val | flag_val, 0);
- printf("openat(-1, \"%s\", %s%s%s%s) = %s\n",
+ printf("%s%s(-1, \"%s\", %s%s%s%s) = %s\n",
+ my_secontext, "openat",
sample, mode_str,
flag_val ? "|" : "", flag_str,
flag_val & (O_CREAT | STRACE_O_TMPFILE) ? ", 000" : "",
@@ -45,20 +49,7 @@ main(void)
*/
create_and_enter_subdir("openat_subdir");
- long fd = syscall(__NR_openat, -100, sample, O_RDONLY|O_CREAT, 0400);
- printf("openat(AT_FDCWD, \"%s\", O_RDONLY|O_CREAT, 0400) = %s\n",
- sample, sprintrc(fd));
-
- if (fd != -1) {
- close(fd);
- if (unlink(sample) == -1)
- perror_msg_and_fail("unlink");
-
- fd = syscall(__NR_openat, -100, sample, O_RDONLY);
- printf("openat(AT_FDCWD, \"%s\", O_RDONLY) = %s\n",
- sample, sprintrc(fd));
- }
-
+ char *my_secontext = SECONTEXT_PID_MY();
struct {
unsigned int val;
const char *str;
@@ -105,7 +96,73 @@ main(void)
for (unsigned int m = 0; m < ARRAY_SIZE(modes); ++m)
for (unsigned int f = 0; f < ARRAY_SIZE(flags); ++f)
test_mode_flag(modes[m].val, modes[m].str,
- flags[f].val, flags[f].str);
+ flags[f].val, flags[f].str,
+ my_secontext);
+
+ /*
+ * Tests with AT_FDCWD.
+ */
+
+ (void) unlink(sample);
+ long fd = syscall(__NR_openat, -100, sample, O_RDONLY|O_CREAT, 0400);
+
+ char *sample_secontext = SECONTEXT_FILE(sample);
+
+ /*
+ * File context in openat() is not displayed because file doesn't exist
+ * yet, but is displayed in return value since the file got created.
+ */
+ printf("%s%s(AT_FDCWD, \"%s\", O_RDONLY|O_CREAT, 0400) = %s%s\n",
+ my_secontext, "openat",
+ sample,
+ sprintrc(fd), sample_secontext);
+
+ close(fd);
+
+ fd = syscall(__NR_openat, -100, sample, O_RDONLY);
+ printf("%s%s(AT_FDCWD, \"%s\"%s, O_RDONLY) = %s%s\n",
+ my_secontext, "openat",
+ sample, sample_secontext,
+ sprintrc(fd), sample_secontext);
+ if (fd != -1) {
+ close(fd);
+ if (unlink(sample))
+ perror_msg_and_fail("unlink");
+ }
+
+ /*
+ * Tests with dirfd.
+ */
+
+ int cwd_fd = get_dir_fd(".");
+ char *cwd_secontext = SECONTEXT_FILE(".");
+
+ fd = syscall(__NR_openat, cwd_fd, sample, O_RDONLY|O_CREAT, 0400);
+ if (fd == -1)
+ perror_msg_and_fail("openat");
+ close(fd);
+
+ /*
+ * File context in openat() is not displayed because file doesn't exist
+ * yet, but is displayed in return value since the file got created.
+ */
+ printf("%s%s(%d%s, \"%s\", O_RDONLY|O_CREAT, 0400) = %s%s\n",
+ my_secontext, "openat",
+ cwd_fd, cwd_secontext,
+ sample,
+ sprintrc(fd), sample_secontext);
+
+ fd = syscall(__NR_openat, cwd_fd, sample, O_RDONLY);
+ printf("%s%s(%d%s, \"%s\"%s, O_RDONLY) = %s%s\n",
+ my_secontext, "openat",
+ cwd_fd, cwd_secontext,
+ sample, sample_secontext,
+ sprintrc(fd), sample_secontext);
+ if (fd != -1) {
+ close(fd);
+ if (unlink(sample))
+ perror_msg_and_fail("unlink");
+ }
leave_and_remove_subdir();
diff --git a/tests/options-syntax.test b/tests/options-syntax.test
index 4c071ac5a..765b2f867 100755
--- a/tests/options-syntax.test
+++ b/tests/options-syntax.test
@@ -3,13 +3,15 @@
# Check strace options syntax.
#
# Copyright (c) 2016 Dmitry V. Levin <ldv@strace.io>
-# Copyright (c) 2016-2020 The strace developers.
+# Copyright (c) 2016-2021 The strace developers.
# All rights reserved.
#
# SPDX-License-Identifier: GPL-2.0-or-later
. "${srcdir=.}/syntax.sh"
+compiled_with_secontext=$(get_config_option ENABLE_SECONTEXT "y")
+
check_e "Invalid process id: '0'" -p 0
check_e "Invalid process id: '0'" --attach=0
check_e "Invalid process id: '-42'" -p -42
@@ -46,6 +48,8 @@ check_e '-t and --absolute-timestamps cannot be provided simultaneously' -t --ti
check_e '-t and --absolute-timestamps cannot be provided simultaneously' --absolute-timestamps -ttt -p $$
check_e '-t and --absolute-timestamps cannot be provided simultaneously' -t --timestamps=ns -t -p $$
check_e '-t and --absolute-timestamps cannot be provided simultaneously' --timestamps=ns -t --absolute-timestamps=unix -p $$
+[ -z "$compiled_with_secontext" ] ||
+ check_h "invalid --secontext argument: 'ss'" --secontext=ss
check_h 'PROG [ARGS] must be specified with -D/--daemonize' -D -p $$
check_h 'PROG [ARGS] must be specified with -D/--daemonize' -DD -p $$
check_h 'PROG [ARGS] must be specified with -D/--daemonize' -DDD -p $$
@@ -282,6 +286,11 @@ $STRACE_EXE: -y/--decode-fds has no effect with -c/--summary-only
$STRACE_EXE: Only the last of -z/--successful-only/-Z/--failed-only options will take effect. See status qualifier for more complex filters.
$STRACE_EXE: $umsg" -u :nosuchuser: -cinrtTyzZ true
+ if [ -n "$compiled_with_secontext" ]; then
+ check_e "--secontext has no effect with -c/--summary-only
+$STRACE_EXE: $umsg" -u :nosuchuser: -c --secontext true
+ fi
+
for c in --output-separately -A/--output-append-mode; do
check_e "$c has no effect without -o/--output
$STRACE_EXE: $umsg" -u :nosuchuser: ${c%%/*} true
diff --git a/tests/secontext.c b/tests/secontext.c
new file mode 100644
index 000000000..21c6370c9
--- /dev/null
+++ b/tests/secontext.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2021 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "tests.h"
+
+#ifdef HAVE_SELINUX_RUNTIME
+
+# include <assert.h>
+# include <errno.h>
+# include <stdlib.h>
+# include <string.h>
+# include <unistd.h>
+# include <selinux/selinux.h>
+
+# include "xmalloc.h"
+
+# define TEST_SECONTEXT
+# include "secontext.h"
+
+static char *
+secontext_format(char *context, const char *fmt)
+ ATTRIBUTE_FORMAT((printf, 2, 0)) ATTRIBUTE_MALLOC;
+
+static char *
+secontext_format(char *context, const char *fmt)
+{
+ int saved_errno = errno;
+ char *res = context ? xasprintf(fmt, context) : xstrdup("");
+ free(context);
+ errno = saved_errno;
+ return res;
+}
+
+# define FORMAT_SPACE_BEFORE(string) secontext_format(string, " [%s]")
+# define FORMAT_SPACE_AFTER(string) secontext_format(string, "[%s] ")
+
+static char *
+strip_trailing_newlines(char *context)
+{
+ /*
+ * On the CI at least, the context may have a trailing \n,
+ * let's remove it just in case.
+ */
+ size_t len = strlen(context);
+ for (; len > 0; --len) {
+ if (context[len - 1] != '\n')
+ break;
+ }
+ context[len] = '\0';
+ return context;
+}
+
+static char *
+raw_secontext_full_file(const char *filename)
+{
+ int saved_errno = errno;
+ char *full_secontext = NULL;
+ char *secontext;
+
+ if (getfilecon(filename, &secontext) >= 0) {
+ full_secontext = strip_trailing_newlines(xstrdup(secontext));
+ freecon(secontext);
+ }
+ errno = saved_errno;
+ return full_secontext;
+}
+
+static char *
+raw_secontext_short_file(const char *filename)
+{
+ int saved_errno = errno;
+
+ char *ctx = raw_secontext_full_file(filename);
+ if (ctx == NULL)
+ return ctx;
+
+ char *saveptr = NULL;
+ const char *token;
+ unsigned int i;
+
+ char *ctx_copy = xstrdup(ctx);
+ char *context = NULL;
+ for (token = strtok_r(ctx_copy, ":", &saveptr), i = 0;
+ token; token = strtok_r(NULL, ":", &saveptr), i++) {
+ if (i == 2) {
+ context = xstrdup(token);
+ break;
+ }
+ }
+ if (context == NULL)
+ context = xstrdup(ctx);
+ free(ctx_copy);
+ free(ctx);
+
+ errno = saved_errno;
+ return context;
+}
+
+static char *
+raw_secontext_full_pid(pid_t pid)
+{
+ int saved_errno = errno;
+ char *full_secontext = NULL;
+ char *secontext;
+
+ if (getpidcon(pid, &secontext) == 0) {
+ full_secontext = strip_trailing_newlines(xstrdup(secontext));
+ freecon(secontext);
+ }
+ errno = saved_errno;
+ return full_secontext;
+}
+
+static char *
+raw_secontext_short_pid(pid_t pid)
+{
+ int saved_errno = errno;
+
+ char *ctx = raw_secontext_full_pid(pid);
+ if (ctx == NULL)
+ return ctx;
+
+ char *saveptr = NULL;
+ const char *token;
+ int i;
+
+ char *ctx_copy = xstrdup(ctx);
+ char *context = NULL;
+ for (token = strtok_r(ctx_copy, ":", &saveptr), i = 0;
+ token; token = strtok_r(NULL, ":", &saveptr), i++) {
+ if (i == 2) {
+ context = xstrdup(token);
+ break;
+ }
+ }
+ if (context == NULL)
+ context = xstrdup(ctx);
+ free(ctx_copy);
+ free(ctx);
+
+ errno = saved_errno;
+ return context;
+}
+
+char *
+secontext_full_file(const char *filename)
+{
+ return FORMAT_SPACE_BEFORE(raw_secontext_full_file(filename));
+}
+
+char *
+secontext_full_pid(pid_t pid)
+{
+ return FORMAT_SPACE_AFTER(raw_secontext_full_pid(pid));
+}
+
+char *
+secontext_short_file(const char *filename)
+{
+ return FORMAT_SPACE_BEFORE(raw_secontext_short_file(filename));
+}
+
+char *
+secontext_short_pid(pid_t pid)
+{
+ return FORMAT_SPACE_AFTER(raw_secontext_short_pid(pid));
+}
+
+void
+update_secontext_type(const char *file, const char *newtype)
+{
+ char *ctx = raw_secontext_full_file(file);
+ if (ctx == NULL)
+ return;
+
+ char *saveptr = NULL;
+ char *token;
+ int field;
+ char *split[4];
+
+ for (token = strtok_r(ctx, ":", &saveptr), field = 0;
+ token; token = strtok_r(NULL, ":", &saveptr), field++) {
+ assert(field < 4);
+ split[field] = token;
+ }
+ assert(field == 4);
+
+ char *newcontext = xasprintf("%s:%s:%s:%s", split[0], split[1],
+ newtype, split[3]);
+
+ (void) setfilecon(file, newcontext);
+
+ free(newcontext);
+ free(ctx);
+}
+
+#endif /* HAVE_SELINUX_RUNTIME */
diff --git a/tests/secontext.h b/tests/secontext.h
new file mode 100644
index 000000000..64bcd060f
--- /dev/null
+++ b/tests/secontext.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021 The strace developers.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "tests.h"
+#include "xmalloc.h"
+#include <unistd.h>
+
+#if defined TEST_SECONTEXT && defined HAVE_SELINUX_RUNTIME
+
+void update_secontext_type(const char *file, const char *newtype);
+
+# ifdef PRINT_SECONTEXT_FULL
+
+char *secontext_full_file(const char *) ATTRIBUTE_MALLOC;
+char *secontext_full_pid(pid_t) ATTRIBUTE_MALLOC;
+
+# define SECONTEXT_FILE(filename) secontext_full_file(filename)
+# define SECONTEXT_PID(pid) secontext_full_pid(pid)
+
+# else
+
+char *secontext_short_file(const char *) ATTRIBUTE_MALLOC;
+char *secontext_short_pid(pid_t) ATTRIBUTE_MALLOC;
+
+# define SECONTEXT_FILE(filename) secontext_short_file(filename)
+# define SECONTEXT_PID(pid) secontext_short_pid(pid)
+
+# endif
+
+#else
+
+static inline void
+update_secontext_type(const char *file, const char *newtype)
+{
+}
+
+# define SECONTEXT_FILE(filename) xstrdup("")
+# define SECONTEXT_PID(pid) xstrdup("")
+
+#endif
+
+#define SECONTEXT_PID_MY() SECONTEXT_PID(getpid())
diff --git a/tests/strace-V.test b/tests/strace-V.test
index 30f10808c..fdac7a3e4 100755
--- a/tests/strace-V.test
+++ b/tests/strace-V.test
@@ -33,7 +33,9 @@ aarch64|powerpc64|s390x|sparc64|tile|x32)
;;
esac
-features="${option_unwind}${option_demangle}${option_m32}${option_mx32}"
+option_secontext=$(get_config_option ENABLE_SECONTEXT " secontext")
+
+features="${option_unwind}${option_demangle}${option_m32}${option_mx32}${option_secontext}"
[ -n "$features" ] || features=" (none)"
cat > "$EXP" << __EOF__