Proposing SELinux support in strace

Dmitry V. Levin ldv at altlinux.org
Mon Mar 15 01:10:00 UTC 2021


Hi,

On Wed, Mar 10, 2021 at 10:42:21AM +0100, Renaud Métrich wrote:
> Hello,
> 
> Please find the latest patch attached. PR's build is green.

Thanks, this is a big step forward.
I've got quite a few comments, see below.

> --- a/bootstrap
> +++ b/bootstrap
> @@ -24,11 +24,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

OK

> 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 \

OK

> diff --git a/m4/mpers.m4 b/m4/mpers.m4
> index 510aabe84..c1c5d38f1 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

OK

> @@ -126,6 +128,18 @@ case "$arch" in
>  			 else
>  				st_cv_mpers=no
>  			 fi])
> +		AC_CACHE_CHECK([whether selinux runtime works with mpers_name personality],
> +			[st_cv_selinux_runtime],
> +			[
> +			 saved_LIBS="$LIBS"
> +			 LIBS="-lselinux $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"
> +			])
>  		if test $st_cv_mpers = yes; then
>  			AC_DEFINE(HAVE_MPERS, [1],
>  				  [Define to 1 if you have mpers_name mpers support])

Since st_MPERS code is executed after st_SELINUX, its results can be used
here.  If with_secontexts was set to "no" by st_SELINUX, there is no need
to bother about selinux runtime here.  Also, if st_cv_runtime was set to
"no" by earlier checks, there is no need to check selinux runtime either.

For example:

               AS_IF([test "x$with_secontexts$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])

> @@ -165,6 +179,7 @@ case "$arch" in
>  	*) # case "$enable_mpers"
>  	st_cv_runtime=no
>  	st_cv_mpers=no
> +	st_cv_selinux_runtime=no
>  	;;
>  	esac
>  
> @@ -187,6 +202,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 +217,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])

OK

> diff --git a/m4/st_selinux.m4 b/m4/st_selinux.m4
> new file mode 100644
> index 000000000..e9f1eda84
> --- /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=
> +with_secontexts=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"
> +		 with_secontexts=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"
> +		 with_secontexts=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$with_secontexts" = xyes],
> +      [AC_DEFINE([USE_SELINUX], [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([USE_SELINUX], [test "x$with_secontexts" = xyes])
> +AM_CONDITIONAL([HAVE_SELINUX_RUNTIME], [test "x$with_secontexts" = xyes])
> +
> +])

OK

> diff --git a/src/Makefile.am b/src/Makefile.am
> index ee9415ea5..e5553918a 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -186,6 +186,7 @@ libstrace_a_SOURCES =	\
>  	mmap_notify.c	\
>  	mmap_notify.h	\
>  	mmsghdr.c	\
> +	mntns.c		\
>  	mount.c		\
>  	move_mount.c	\
>  	mpers_type.h	\
> @@ -303,6 +304,7 @@ libstrace_a_SOURCES =	\
>  	sched_attr.h	\
>  	scsi.c		\
>  	seccomp.c	\
> +	selinux.h	\
>  	sendfile.c	\
>  	sg_io_v3.c	\
>  	sg_io_v4.c	\
> @@ -406,6 +408,13 @@ strace_LDADD += $(libiberty_LIBS)
>  endif
>  endif
>  
> +if USE_SELINUX
> +libstrace_a_SOURCES += selinux.c
> +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)

It's an interesting question whether you want to compile mntns.c when
selinux support is not enabled.  Maybe some day in the future mntns.c might
be used outside USE_SELINUX code, bit currently it looks like we would
better off without mntns.c when USE_SELINUX is not enabled.

In other words, let's move mntns.c and selinux.h into "if USE_SELINUX"
case.

> diff --git a/src/access.c b/src/access.c
> index 2936242f7..81b78889b 100644
> --- a/src/access.c
> +++ b/src/access.c
> @@ -34,8 +34,10 @@ decode_faccessat(struct tcb *tcp)
>  {
>  	/* dirfd */
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprint_arg_next();
> -
>  	decode_access(tcp, 1);
>  }
>  
> diff --git a/src/chmod.c b/src/chmod.c
> index 6935fbfec..1e634722d 100644
> --- a/src/chmod.c
> +++ b/src/chmod.c
> @@ -29,6 +29,9 @@ SYS_FUNC(fchmodat)
>  {
>  	/* dirfd */
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprint_arg_next();
>  
>  	decode_chmod(tcp, 1);
> diff --git a/src/execve.c b/src/execve.c
> index a9224543b..22820b564 100644
> --- a/src/execve.c
> +++ b/src/execve.c
> @@ -119,6 +119,9 @@ SYS_FUNC(execveat)
>  {
>  	/* dirfd */
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprint_arg_next();
>  
>  	/* pathname, argv, envp */
> diff --git a/src/fanotify.c b/src/fanotify.c
> index 9e8071009..a87233418 100644
> --- a/src/fanotify.c
> +++ b/src/fanotify.c
> @@ -57,8 +57,12 @@ SYS_FUNC(fanotify_mark)
>  	tprints(", ");
>  	if ((int) tcp->u_arg[argn] == FAN_NOFD)
>  		print_xlat_d(FAN_NOFD);
> -	else
> +	else {
>  		print_dirfd(tcp, tcp->u_arg[argn]);
> +#ifdef USE_SELINUX
> +		tcp->dirfd = (int)(tcp->u_arg[argn]);
> +#endif
> +	}
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[argn + 1]);
>  
> diff --git a/src/fchownat.c b/src/fchownat.c
> index 25602a48e..99e911abb 100644
> --- a/src/fchownat.c
> +++ b/src/fchownat.c
> @@ -11,6 +11,9 @@ SYS_FUNC(fchownat)
>  {
>  	/* dirfd */
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprint_arg_next();
>  
>  	/* pathname */
> diff --git a/src/file_handle.c b/src/file_handle.c
> index 7a6ef1022..4da3013c2 100644
> --- a/src/file_handle.c
> +++ b/src/file_handle.c
> @@ -43,6 +43,9 @@ SYS_FUNC(name_to_handle_at)
>  	if (entering(tcp)) {
>  		/* dirfd */
>  		print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +		tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  		tprint_arg_next();
>  
>  		/* pathname */
> diff --git a/src/fspick.c b/src/fspick.c
> index 2db30f768..c5d244596 100644
> --- a/src/fspick.c
> +++ b/src/fspick.c
> @@ -13,6 +13,9 @@ SYS_FUNC(fspick)
>  {
>  	/* dirfd */
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprint_arg_next();
>  
>  	/* pathname */
> diff --git a/src/link.c b/src/link.c
> index bad2302c9..60ad2958e 100644
> --- a/src/link.c
> +++ b/src/link.c
> @@ -27,10 +27,16 @@ SYS_FUNC(link)
>  SYS_FUNC(linkat)
>  {
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[1]);
>  	tprints(", ");
>  	print_dirfd(tcp, tcp->u_arg[2]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[2]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[3]);
>  	tprints(", ");
> @@ -42,6 +48,9 @@ SYS_FUNC(linkat)
>  SYS_FUNC(unlinkat)
>  {
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[1]);
>  	tprints(", ");
> @@ -55,6 +64,9 @@ SYS_FUNC(symlinkat)
>  	printpath(tcp, tcp->u_arg[0]);
>  	tprints(", ");
>  	print_dirfd(tcp, tcp->u_arg[1]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[1]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[2]);
>  
> diff --git a/src/mknod.c b/src/mknod.c
> index e1950621a..e2f97c655 100644
> --- a/src/mknod.c
> +++ b/src/mknod.c
> @@ -46,6 +46,9 @@ SYS_FUNC(mknod)
>  SYS_FUNC(mknodat)
>  {
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprints(", ");
>  	decode_mknod(tcp, 1);
>  
> diff --git a/src/move_mount.c b/src/move_mount.c
> index 2fb571713..f8b1e387d 100644
> --- a/src/move_mount.c
> +++ b/src/move_mount.c
> @@ -12,10 +12,16 @@
>  SYS_FUNC(move_mount)
>  {
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[1]);
>  	tprints(", ");
>  	print_dirfd(tcp, tcp->u_arg[2]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[2]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[3]);
>  	tprints(", ");
> diff --git a/src/open.c b/src/open.c
> index 365693b6b..d563b3da2 100644
> --- a/src/open.c
> +++ b/src/open.c
> @@ -137,6 +137,9 @@ print_open_how(struct tcb *tcp, kernel_ulong_t addr, kernel_ulong_t size)
>  SYS_FUNC(openat)
>  {
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprints(", ");
>  	return decode_open(tcp, 1);
>  }
> @@ -144,6 +147,9 @@ SYS_FUNC(openat)
>  SYS_FUNC(openat2)
>  {
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[1]);
>  	tprints(", ");
> diff --git a/src/open_tree.c b/src/open_tree.c
> index 75a20cd9f..8dbe80d1d 100644
> --- a/src/open_tree.c
> +++ b/src/open_tree.c
> @@ -14,6 +14,9 @@
>  SYS_FUNC(open_tree)
>  {
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[1]);
>  	tprints(", ");
> diff --git a/src/readlink.c b/src/readlink.c
> index a602f6c26..8c055315f 100644
> --- a/src/readlink.c
> +++ b/src/readlink.c
> @@ -46,6 +46,9 @@ SYS_FUNC(readlinkat)
>  {
>  	if (entering(tcp)) {
>  		print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +		tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  		tprints(", ");
>  	}
>  	return decode_readlink(tcp, 1);
> diff --git a/src/renameat.c b/src/renameat.c
> index a854117df..264c564fd 100644
> --- a/src/renameat.c
> +++ b/src/renameat.c
> @@ -11,10 +11,16 @@ static void
>  decode_renameat(struct tcb *tcp)
>  {
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[1]);
>  	tprints(", ");
>  	print_dirfd(tcp, tcp->u_arg[2]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[2]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[3]);
>  }
> diff --git a/src/stat.c b/src/stat.c
> index 903750ded..33396785a 100644
> --- a/src/stat.c
> +++ b/src/stat.c
> @@ -44,6 +44,9 @@ SYS_FUNC(newfstatat)
>  {
>  	if (entering(tcp)) {
>  		print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +		tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  		tprints(", ");
>  		printpath(tcp, tcp->u_arg[1]);
>  		tprints(", ");
> diff --git a/src/stat64.c b/src/stat64.c
> index 33d6ca366..75440b1e7 100644
> --- a/src/stat64.c
> +++ b/src/stat64.c
> @@ -44,6 +44,9 @@ SYS_FUNC(fstatat64)
>  {
>  	if (entering(tcp)) {
>  		print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +		tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  		tprints(", ");
>  		printpath(tcp, tcp->u_arg[1]);
>  		tprints(", ");
> diff --git a/src/statx.c b/src/statx.c
> index a0e040f17..4a2d6909d 100644
> --- a/src/statx.c
> +++ b/src/statx.c
> @@ -31,6 +31,9 @@ SYS_FUNC(statx)
>  {
>  	if (entering(tcp)) {
>  		print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +		tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  		tprints(", ");
>  		printpath(tcp, tcp->u_arg[1]);
>  		tprints(", ");
> diff --git a/src/utimes.c b/src/utimes.c
> index 5bcd82e3a..5d4de6d47 100644
> --- a/src/utimes.c
> +++ b/src/utimes.c
> @@ -26,6 +26,9 @@ SYS_FUNC(utimes)
>  SYS_FUNC(futimesat)
>  {
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[1]);
>  	tprints(", ");
> @@ -38,6 +41,9 @@ static int
>  do_utimensat(struct tcb *const tcp, const print_obj_by_addr_fn print_ts)
>  {
>  	print_dirfd(tcp, tcp->u_arg[0]);
> +#ifdef USE_SELINUX
> +	tcp->dirfd = (int)(tcp->u_arg[0]);
> +#endif
>  	tprints(", ");
>  	printpath(tcp, tcp->u_arg[1]);
>  	tprints(", ");

You've added a lot of such tcp->dirfd assignments.  Apparently,
they are added after every print_dirfd invocation except one (and that one
seems to be omitted by mistake).  If you want to cache dirfd processed by
print_dirfd, it would be much easier if you just moved this assignment
inside print_dirfd.

> diff --git a/src/defs.h b/src/defs.h
> index 08a293130..673e86539 100644
> --- a/src/defs.h
> +++ b/src/defs.h
> @@ -293,6 +293,17 @@ struct tcb {
>  	 */
>  	unsigned int pid_ns;
>  
> +	/*
> +	 * The ID of the MOUNT namespace of this process
> +	 * (inode number of /proc/<pid>/ns/mnt)
> +	 * (0: not initialized)
> +	 */
> +	unsigned int mnt_ns;
> +
> +#ifdef USE_SELINUX
> +	int dirfd; /* Use AT_FDCWD for 'not set' */
> +#endif
> +
>  	struct mmap_cache_t *mmap_cache;
>  
>  	/*

Since mnt_ns shouldn't be used outside USE_SELINUX yet, let's move it
inside USE_SELINUX.

Also, dirfd seems to be too short, I'd like to rename it to something more
descriptive, e.g. last_dirfd.

> @@ -1046,8 +1057,13 @@ print_local_array_ex(struct tcb *tcp,
>  extern kernel_ulong_t *
>  fetch_indirect_syscall_args(struct tcb *, kernel_ulong_t addr, unsigned int n_args);
>  
> +extern unsigned int get_mnt_ns(struct tcb *tcp);
> +extern unsigned int get_our_mnt_ns(void);
> +
>  extern void pidns_init(void);
>  
> +extern const char *pid_to_str(pid_t pid);
> +
>  /**
>   * Returns the pid of the tracee as present in /proc of the tracer (can be
>   * different from tcp->pid if /proc and the tracer process are in different PID

You can move these declarations inside USE_SELINUX, but it's not
necessary.

> diff --git a/src/mntns.c b/src/mntns.c
> new file mode 100644
> index 000000000..ac6cddbf6
> --- /dev/null
> +++ b/src/mntns.c
> @@ -0,0 +1,72 @@
> +/*
> + * Copyright (c) 2021 The strace developers.
> + * All rights reserved.
> + *
> + * SPDX-License-Identifier: LGPL-2.1-or-later
> + */
> +
> +#include "defs.h"
> +
> +#include <fcntl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +
> +#include "largefile_wrappers.h"
> +#include "xstring.h"
> +
> +static unsigned int
> +get_mnt_ns_of_pid(int pid)
> +{
> +	unsigned int ns = 0;
> +	char path[PATH_MAX + 1];
> +	xsprintf(path, "/proc/%s/ns/mnt", pid_to_str(pid));
> +
> +	int fd = open_file(path, O_RDONLY);
> +	if (fd < 0)
> +		return 0;
> +	strace_stat_t st;
> +	if (fstat_fd(fd, &st))
> +		goto out;
> +	ns = st.st_ino;
> +out:
> +	close(fd);

Wouldn't it be easier to read if the last 5 lines were written this way:

	if (fstat_fd(fd, &st) == 0)
		ns = st.st_ino;
	close(fd);

I'd go even further:

	if (fd >= 0) {
		strace_stat_t st;
		if (fstat_fd(fd, &st) == 0)
			ns = st.st_ino;
		close(fd);
	}

> +
> +	return ns;
> +}
> +
> +/**
> + * Returns the MOUNT namespace of the tracee
> + */
> +unsigned int
> +get_mnt_ns(struct tcb *tcp)
> +{
> +	if (tcp->mnt_ns)
> +		return tcp->mnt_ns;
> +
> +	int proc_pid = 0;
> +	translate_pid(NULL, tcp->pid, PT_TID, &proc_pid);
> +
> +	if (!proc_pid)
> +		return 0;
> +
> +	tcp->mnt_ns = get_mnt_ns_of_pid(proc_pid);

Wouldn't it be easier to read if the last 4 lines were written this way:

	if (proc_pid)
		tcp->mnt_ns = get_mnt_ns_of_pid(proc_pid);

> +
> +	return tcp->mnt_ns;
> +}
> +
> +/**
> + * Returns the MOUNT namespace of strace
> + */
> +unsigned int
> +get_our_mnt_ns(void)
> +{
> +	static unsigned int our_ns = 0;
> +	static bool our_ns_initialised = false;
> +
> +	if (!our_ns_initialised) {
> +		our_ns = get_mnt_ns_of_pid((int)getpid());

I don't think this explicit cast is really needed here.

> +		our_ns_initialised = true;
> +	}
> +
> +	return our_ns;
> +}

The rest of this file is OK

> diff --git a/src/pidns.c b/src/pidns.c
> index dbcf52b91..6221f902b 100644
> --- a/src/pidns.c
> +++ b/src/pidns.c
> @@ -142,7 +142,7 @@ get_cached_proc_pid(unsigned int ns, int ns_pid, enum pid_type type)
>   * Helper function, converts pid to string, or to "self" for pid == 0.
>   * Uses static buffer for operation.
>   */
> -static const char *
> +const char *
>  pid_to_str(pid_t pid)
>  {
>  	if (!pid)

OK

> diff --git a/src/selinux.c b/src/selinux.c
> new file mode 100644
> index 000000000..0ea9e46ee
> --- /dev/null
> +++ b/src/selinux.c
> @@ -0,0 +1,179 @@
> +/*
> + * Copyright (c) 2020-2021 The strace developers.
> + * All rights reserved.
> + *
> + * SPDX-License-Identifier: LGPL-2.1-or-later
> + */
> +
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <selinux/selinux.h>
> +#include <stdlib.h>
> +
> +#include "defs.h"

"defs.h" must be included first.

Also, I prefer to have <stdlib.h> included before <selinux/selinux.h>.

> +#include "number_set.h"
> +#include "selinux.h"
> +#include "xstring.h"
> +
> +#ifndef AT_FDCWD
> +# define AT_FDCWD	-100
> +#endif
> +
> +bool selinux_context = false;
> +bool selinux_context_full = false;
> +
> +enum selinux_objtype {
> +	SELINUX_PID,
> +	SELINUX_PATH
> +};
> +
> +typedef struct {
> +	enum selinux_objtype type;
> +	union {
> +		pid_t pid;
> +		char *path;
> +	} obj;
> +} selinux_obj_t;
> +
> +static int getcontext(selinux_obj_t *obj, char **context);
> +
> +/*
> + * 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 **context)
> +{
> +	int proc_pid = 0;
> +	translate_pid(NULL, tcp->pid, PT_TID, &proc_pid);
> +	if (!proc_pid)
> +		return -1;

Let's check selinux_context first and return from this function
if selinux_context is not enabled.

> +
> +	selinux_obj_t obj;
> +	obj.type = SELINUX_PID;
> +	obj.obj.pid = (pid_t)proc_pid;
> +
> +	return getcontext(&obj, context);
> +}
> +
> +/*
> + * 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, char *path, char **context)

Let's change "char *path" to "const char *path".

> +{
> +	/*
> +	 * Current limitation: we cannot query the path if we are in different
> +	 * mount namespaces.
> +	 */
> +	if (get_mnt_ns(tcp) != get_our_mnt_ns())
> +		return -1;

Let's check selinux_context first and return from this function
if selinux_context is not enabled.

> +
> +	selinux_obj_t obj;
> +	obj.type = SELINUX_PATH;
> +	obj.obj.path = path;
> +
> +	if (path[0] == '/')
> +		return getcontext(&obj, context);
> +
> +	char resolved[PATH_MAX + 1];
> +	char pathtoresolve[2 * PATH_MAX + 2];
> +	int proc_pid = 0;
> +	translate_pid(NULL, tcp->pid, PT_TID, &proc_pid);
> +	if (!proc_pid)
> +		return -1;
> +
> +	/*
> +	 * If we have a relative pathname and 'dirfd' == AT_FDCWD, we need to
> +	 * prepend by the CWD.
> +	 */
> +	if (tcp->dirfd == AT_FDCWD) {
> +		char linkpath[sizeof("/proc/%u/cwd") + sizeof(int)*3];
> +		ssize_t n;
> +
> +		xsprintf(linkpath, "/proc/%u/cwd", proc_pid);
> +		n = readlink(linkpath, resolved, sizeof(resolved) - 1);
> +		/*
> +		 * NB: if buffer is too small, readlink doesn't fail,
> +		 * it returns truncated result.
> +		 */
> +		if (n == sizeof(resolved) - 1)
> +			return -1;
> +		resolved[n] = '\0';
> +	} else {
> +		if (number_set_array_is_empty(decode_fd_set, 0) ||

Interesting.  This means that --decode-fds should have effect on
selinux_getfilecon.  I wonder why.

> +		    getfdpath_pid(proc_pid, tcp->dirfd, resolved, sizeof(resolved)) < 0)
> +			return -1;

getfdpath_pid itself uses translate_pid to translate it's first argument.

> +	}
> +	xsprintf(pathtoresolve, "%s/%s", resolved, path);
> +	if (realpath(pathtoresolve, resolved) == NULL) {

Interesting.  Why realpath?  Would stat_file be enough?

> +		/*
> +		 * This can happen in multiple cases:
> +		 * - there was an error different than ENOENT
> +		 * - if path doesn't exist
> +		 * - path is below root directory, e.g. root dir and cwd are
> +		 *   '/home/<user>/chroot' and path is below root directory,
> +		 *   e.g. '../../bin/ls'
> +		 */
> +		return -1;
> +	}
> +	obj.obj.path = resolved;
> +
> +	return getcontext(&obj, context);
> +}
> +
> +static int
> +getcontext(selinux_obj_t *obj, char **context)
> +{
> +	int res;
> +	char *secontext;
> +
> +	if (!selinux_context)
> +		goto fail;
> +
> +	switch (obj->type) {
> +	case SELINUX_PID:
> +		res = getpidcon(obj->obj.pid, &secontext);
> +		break;
> +	case SELINUX_PATH:
> +		res = getfilecon(obj->obj.path, &secontext);
> +		break;
> +	default:
> +		/* XXX Assert instead */
> +		goto fail;

This is the reason why I don't like this enum/case approach:
it creates unreachable code.

> +	}
> +
> +	if (res == -1)
> +		goto fail;
> +
> +	if (selinux_context_full) {
> +		*context = xstrdup(secontext);
> +	} else {
> +		char *saveptr = NULL;
> +		char *secontext_copy = xstrdup(secontext);
> +		const char *token;
> +		int i;
> +
> +		/*
> +		 * We only want to keep the type (3rd field, ':' separator).
> +		 */
> +		*context = NULL;
> +		for (token = strtok_r(secontext_copy, ":", &saveptr), i = 0;
> +		     token; token = strtok_r(NULL, ":", &saveptr), i++) {
> +			if (i == 2) {
> +				*context = xstrdup(token);
> +				break;
> +			}
> +		}
> +		if (*context == NULL)
> +			*context = xstrdup(secontext);
> +		free(secontext_copy);
> +	}
> +	freecon(secontext);
> +	return 0;
> +fail:
> +	return -1;
> +}

I suggest some rewriting, for example:

#include "defs.h"

#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <selinux/selinux.h>

#include "number_set.h"
#include "selinux.h"
#include "xstring.h"

#ifndef AT_FDCWD
# define AT_FDCWD	-100
#endif

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)
		*result = xstrdup(*secontext);
	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 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;

	/*
	 * Current limitation: we cannot query the path if we are in different
	 * mount namespaces.
	 */
	if (get_mnt_ns(tcp) != get_our_mnt_ns())
		return -1;

	char *secontext;

	if (path[0] == '/')
		return getcontext(getfilecon(path, &secontext), &secontext, result);

	char resolved[PATH_MAX + 1];

	/*
	 * If we have a relative pathname and 'dirfd' == AT_FDCWD, we need to
	 * prepend by the CWD.
	 */
	if (tcp->last_dirfd == AT_FDCWD) {
		int proc_pid = 0;
		translate_pid(NULL, tcp->pid, PT_TID, &proc_pid);
		if (!proc_pid)
			return -1;

		char linkpath[sizeof("/proc/%u/cwd") + sizeof(int)*3];
		xsprintf(linkpath, "/proc/%u/cwd", proc_pid);
		ssize_t n = readlink(linkpath, resolved, sizeof(resolved) - 1);
		/*
		 * NB: if buffer is too small, readlink doesn't fail,
		 * it returns truncated result.
		 */
		if (n == sizeof(resolved) - 1)
			return -1;
		resolved[n] = '\0';
	} else {
		if (getfdpath_pid(tcp->pid, tcp->last_dirfd,
				  resolved, sizeof(resolved)) < 0)
			return -1;
	}

	char pathtoresolve[2 * PATH_MAX + 2];
	xsprintf(pathtoresolve, "%s/%s", resolved, path);
	/* XXX Why realpath?  Would stat_file be enough?  */
	if (realpath(pathtoresolve, resolved) == NULL) {
		/*
		 * This can happen in multiple cases:
		 * - there was an error different than ENOENT
		 * - if path doesn't exist
		 * - path is below root directory, e.g. root dir and cwd are
		 *   '/home/<user>/chroot' and path is below root directory,
		 *   e.g. '../../bin/ls'
		 */
		return -1;
	}

	return getcontext(getfilecon(resolved, &secontext), &secontext, result);
}

> diff --git a/src/selinux.h b/src/selinux.h
> new file mode 100644
> index 000000000..028e87617
> --- /dev/null
> +++ b/src/selinux.h
> @@ -0,0 +1,24 @@
> +/*
> + * SELinux interface.
> + *
> + * Copyright (c) 2020 The strace developers.

2020-2021

> + *
> + * SPDX-License-Identifier: LGPL-2.1-or-later
> + */
> +
> +#ifndef STRACE_SELINUX_H
> +#define STRACE_SELINUX_H
> +
> +#include "defs.h"
> +
> +#ifdef USE_SELINUX
> +
> +extern bool selinux_context;
> +extern bool selinux_context_full;
> +
> +int selinux_getpidcon(struct tcb *tcp, char **context);
> +int selinux_getfilecon(struct tcb *tcp, char *path, char **context);

Let's change "char *path" to "const char *path".

> +
> +#endif
> +
> +#endif /* !STRACE_SELINUX_H */

The rest of this file is OK.

> diff --git a/src/strace.c b/src/strace.c
> index 7e7920d31..9035c6de4 100644
> --- a/src/strace.c
> +++ b/src/strace.c
> @@ -40,6 +40,7 @@
>  #include "xstring.h"
>  #include "delay.h"
>  #include "wait.h"
> +#include "selinux.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 USE_SELINUX
> +		" secontext"
> +#endif
>  		"";
>  
>  	printf("%s -- version %s\n"
> @@ -258,12 +262,18 @@ usage(void)
>  # define K_OPT "k"
>  #else
>  # define K_OPT ""
> +#endif
> +#ifdef USE_SELINUX
> +# define SELINUX_OPT "[--secontext[=full]]\n"
> +#else
> +# define SELINUX_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"\
> +              SELINUX_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\
> @@ -445,6 +455,14 @@ Miscellaneous:\n\
>    -d, --debug    enable debug output to stderr\n\
>    -h, --help     print help message\n\
>    --seccomp-bpf  enable seccomp-bpf filtering\n\
> +"
> +#ifdef USE_SELINUX
> +"\
> +  --secontext[=full]\n\
> +                 print SELinux contexts (type only unless 'full' is specified)\n\
> +"
> +#endif
> +"\
>    -V, --version  print version\n\
>  "
>  /* ancient, no one should use it
> @@ -783,6 +801,14 @@ printleader(struct tcb *tcp)
>  	else if (nprocs > 1 && !outfname)
>  		tprintf("[pid %5u] ", tcp->pid);
>  
> +#ifdef USE_SELINUX
> +	char *context;
> +	if (!selinux_getpidcon(tcp, &context)) {
> +		tprintf("[%s] ", context);
> +		free(context);
> +	}
> +#endif
> +
>  	if (tflag_format) {
>  		struct timespec ts;
>  		clock_gettime(CLOCK_REALTIME, &ts);

OK

> @@ -896,6 +922,13 @@ alloctcb(int pid)
>  			tcp->pid = pid;
>  #if SUPPORTED_PERSONALITIES > 1
>  			tcp->currpers = current_personality;
> +#endif
> +#ifdef USE_SELINUX
> +#ifndef AT_FDCWD
> +# define AT_FDCWD>------100
> +#endif

What is this? :)

> +
> +			tcp->dirfd = AT_FDCWD;
>  #endif
>  			nprocs++;
>  			debug_msg("new tcb for pid %d, active tcbs:%d",
> @@ -2037,6 +2070,9 @@ init(int argc, char *argv[])
>  		GETOPT_OUTPUT_SEPARATELY,
>  		GETOPT_TS,
>  		GETOPT_PIDNS_TRANSLATION,
> +#ifdef USE_SELINUX
> +		GETOPT_SELINUX_CONTEXT,
> +#endif
>  
>  		GETOPT_QUAL_TRACE,
>  		GETOPT_QUAL_ABBREV,
> @@ -2093,6 +2129,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 USE_SELINUX
> +		{ "secontext",		optional_argument, 0, GETOPT_SELINUX_CONTEXT },
> +#endif
>  
>  		{ "trace",	required_argument, 0, GETOPT_QUAL_TRACE },
>  		{ "abbrev",	required_argument, 0, GETOPT_QUAL_ABBREV },
> @@ -2321,6 +2360,17 @@ init(int argc, char *argv[])
>  		case GETOPT_SECCOMP:
>  			seccomp_filtering = true;
>  			break;
> +#ifdef USE_SELINUX
> +		case GETOPT_SELINUX_CONTEXT:
> +			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 +2553,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 USE_SELINUX
> +		if (selinux_context)
> +			error_msg("--secontext has no effect with "
> +				  "-c/--summary-only");
> +#endif
>  	}
>  
>  	if (!outfname) {

OK

> @@ -3220,6 +3275,9 @@ next_event(void)
>  			if (!tcp)
>  				goto next_event_wait_next;
>  		}
> +#ifdef USE_SELINUX
> +		tcp->dirfd = AT_FDCWD;
> +#endif
>  
>  		if (cflag) {
>  			tcp->stime.tv_sec = ru.ru_stime.tv_sec;

I'm not sure this is the most optimal place to reset tcp->last_dirfd.
For example, if you want to assign it on entering syscall and use it on
exiting (e.g. in case of getdents below), this is not the right place
to reset it.

> diff --git a/src/util.c b/src/util.c
> index 9cb555ecb..509b12f7f 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 "selinux.h"
>  #include "static_assert.h"
>  #include "string_to_uint.h"
>  #include "xlat.h"
> @@ -664,6 +665,13 @@ printfd_pid(struct tcb *tcp, pid_t pid, int fd)
>  
>  printed:
>  		tprints(">");
> +#ifdef USE_SELINUX
> +		char *context;
> +		if (!selinux_getfilecon(tcp, path, &context)) {
> +			tprintf(" [%s]", context);
> +			free(context);
> +		}
> +#endif
>  	} else {
>  		tprintf("%d", fd);
>  	}
> @@ -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 USE_SELINUX
> +		char *context;
> +		if (nul_seen && !selinux_getfilecon(tcp, path, &context)) {
> +			tprintf(" [%s]", context);
> +			free(context);
> +		}
> +#endif
>  	}
>  
>  	return nul_seen;

This is OK, but there are few places in the code where printpathn is used
in different contexts where this wouldn't be appropriate:
- all readdir/getdents contexts, printpathn is used there relative to the
  corresponding directory, a solution is to assign tcp->last_dirfd inside
  SYS_FUNC(readdir) and xgetdents;
- memfd_create and sock_ioctl use printpathn to print something that's not
  a filesystem object at all, probably they should use printstrn instead.

> diff --git a/strace.spec.in b/strace.spec.in
> index c8f281f18..b3a2895d4 100644
> --- a/strace.spec.in
> +++ b/strace.spec.in
> @@ -29,11 +29,13 @@ 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
>  %endif
>  %{?buildrequires_stacktrace}
> +%{?buildrequires_selinux}
>  
>  # OBS compatibility
>  %{?!buildroot:BuildRoot: %_tmppath/buildroot-%name-%version-%release}

Maybe opensuse also provides libselinux-devel that could be used here.

> diff --git a/tests/.gitignore b/tests/.gitignore
> index a2f3419b0..b9a13bcdf 100644
> --- a/tests/.gitignore
> +++ b/tests/.gitignore
> @@ -3,6 +3,8 @@
>  *.log
>  *.o
>  *.trs
> +*--secontext
> +*--secontext_full
>  _newselect
>  _newselect-P
>  accept

OK

I haven't reviewed the tests yet, just tried to build and run them.
I needed to apply the following change to make them pass:

diff --git a/tests/gen_tests.in b/tests/gen_tests.in
index 3f41959a9..c674c9891 100644
--- a/tests/gen_tests.in
+++ b/tests/gen_tests.in
@@ -10,8 +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	--secontext --trace-path=access_sample -e trace=access
-access--secontext_full	--secontext=full --trace-path=access_sample -e trace=access
+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
@@ -27,8 +27,8 @@ bpf-v	-a20 -v -e trace=bpf
 btrfs	+ioctl.test
 chdir	-a10
 chmod	-a28
-chmod--secontext	--secontext -e trace=chmod
-chmod--secontext_full	--secontext=full -e trace=chmod
+chmod--secontext	-a28 --secontext -e trace=chmod
+chmod--secontext_full	-a28 --secontext=full -e trace=chmod
 chown	-a28
 chown32	-a31
 chroot	-a13
@@ -103,15 +103,15 @@ fadvise64_64	+fadvise64.test
 fallocate	-a18
 fanotify_init
 fanotify_mark	-a32
-fanotify_mark--secontext	--secontext -y -e trace=fanotify_mark
-fanotify_mark--secontext_full	--secontext=full -y -e trace=fanotify_mark
+fanotify_mark--secontext	-a32 --secontext -y -e trace=fanotify_mark
+fanotify_mark--secontext_full	-a32 --secontext=full -y -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	--secontext -y -e trace=fchmod
-fchmod--secontext_full	--secontext=full -y -e trace=fchmod
+fchmod--secontext	-a15 --secontext -y -e trace=fchmod
+fchmod--secontext_full	-a15 --secontext=full -y -e trace=fchmod
 fchmodat
 fchmodat--secontext	--secontext -y -e trace=fchmodat
 fchmodat--secontext_full	--secontext=full -y -e trace=fchmodat
@@ -516,8 +516,8 @@ open	-a30 -P $NAME.sample
 open_tree -a30 -y
 open_tree-P -a30 --decode-fds -P /dev/full -e trace=open_tree
 openat	-a36 -P $NAME.sample
-openat--secontext	-P openat.sample -P $PWD/openat.sample --secontext -y -e trace=openat
-openat--secontext_full	-P openat.sample -P $PWD/openat.sample --secontext=full -y -e trace=openat
+openat--secontext	-a36 -P openat.sample -P $PWD/openat.sample --secontext -y -e trace=openat
+openat--secontext_full	-a36 -P openat.sample -P $PWD/openat.sample --secontext=full -y -e trace=openat
 openat2	-a35
 openat2-Xabbrev	--trace=openat2 -a35 -Xabbrev
 openat2-Xraw	--trace=openat2 -a32 -Xraw

Also please note that you can use asprintf and functions from xmalloc.h
in tests, not need to use complicated malloc's followed by asserts.


-- 
ldv


More information about the Strace-devel mailing list