Proposing SELinux support in strace

Renaud Métrich rmetrich at redhat.com
Fri Mar 19 08:29:12 UTC 2021


Shame on me, definitely, your idea just works fine and is robust!

Tested on chroots, bind mounts and systemd-nspawns. We get even more 
contexts since Unix sockets are now displayed as well.

I was concentrating on how I could rebuild the fs tree from mountinfo 
instead of just following symlinks in /proc as you proposed ...

So what's next now? Since contexts always display now, there is no real 
need for dedicated *--secontext test suite, all this can be integrated 
into the standard test suite (we just need to add "%s" almost everywhere 
for tests that we want to re-run with "strace --secontext").

Shall I do this or just stick to the updated test suite?

Renaud.


On 3/19/21 2:41 AM, Dmitry V. Levin wrote:
> On Fri, Mar 19, 2021 at 02:18:35AM +0300, Dmitry V. Levin wrote:
>> On Thu, Mar 18, 2021 at 04:55:13PM +0100, Renaud Métrich wrote:
>>> Hello, I've just realized that the limitation on the mount namespace is
>>> a real blocker in real world:
>>>
>>> it appears that on systemd systems, all systemd services making use of
>>> PrivateTmp get their own namespace (due to having their own /var/tmp),
>>> which prevents the --secontext option from working for all files.
>> The very minimal fix that's readily available is for printing selinux
>> context associated with descriptors.  Since it can be obtained right from
>> procfs without falling back to path names, it should not be affected by
>> any differences in mountns or rootfs between strace and its tracee.
> Assuming this works, let's see what could be done with file names:
> - if the filename starts with "/", we can construct a new name as
>    /proc/pid/root/filename and getfilecon it;
> - otherwise, if last_dirfd == AT_FDCWD, we can construct a new name as
>    /proc/pid/cwd/filename and getfilecon it;
> - otherwise, we can construct a new name as
>    /proc/pid/fd/last_dirfd/filename and getfilecon it.
>
> Could you check whether this approach would work good enough, please?
>
> diff --git a/doc/strace.1.in b/doc/strace.1.in
> index e6ad7a9c0..15d8e2531 100644
> --- a/doc/strace.1.in
> +++ b/doc/strace.1.in
> @@ -1093,11 +1093,6 @@ strace's namespace, too.
>   .if '@USE_SELINUX_FALSE@'#' .B full
>   .if '@USE_SELINUX_FALSE@'#' is specified, print the complete context (user,
>   .if '@USE_SELINUX_FALSE@'#' role, type and category) instead of just the type.
> -.if '@USE_SELINUX_FALSE@'#' The current implementation has limitations, in
> -.if '@USE_SELINUX_FALSE@'#' particular, SELinux contexts cannot be printed for
> -.if '@USE_SELINUX_FALSE@'#' file names when
> -.if '@USE_SELINUX_FALSE@'#' .B strace
> -.if '@USE_SELINUX_FALSE@'#' and the tracee belong to different mount namespaces.
>   .SS Statistics
>   .TP 12
>   .B \-c
> diff --git a/src/selinux.c b/src/selinux.c
> index 0f1edfe28..b62d40324 100644
> --- a/src/selinux.c
> +++ b/src/selinux.c
> @@ -103,52 +103,27 @@ 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())
> +	int proc_pid = 0;
> +	translate_pid(NULL, tcp->pid, PT_TID, &proc_pid);
> +	if (!proc_pid)
>   		return -1;
>   
> -	char *secontext;
> +	int ret = -1;
> +	char fname[PATH_MAX];
>   
>   	if (path[0] == '/')
> -		return getcontext(getfilecon(path, &secontext), &secontext, result);
> -
> -	char resolved[PATH_MAX + 1];
> -
> -	/*
> -	 * If we have a relative pathname and 'last_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;
> -	}
> -
> -	if (resolved[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 pathtoresolve[2 * PATH_MAX + 2];
> -	xsprintf(pathtoresolve, "%s/%s", resolved, path);
> -
> -	return getcontext(getfilecon(pathtoresolve, &secontext), &secontext, result);
> +	char *secontext;
> +	return getcontext(getfilecon(fname, &secontext), &secontext, result);
>   }
> diff --git a/tests/fchmod--secontext.c b/tests/fchmod--secontext.c
> index 13434544c..3b6681153 100644
> --- a/tests/fchmod--secontext.c
> +++ b/tests/fchmod--secontext.c
> @@ -37,19 +37,20 @@ main(void)
>   	if (fname_realpath == NULL)
>   		perror_msg_and_fail("realpath");
>   
> +	const char *fname_context = SELINUX_FILECONTEXT(fname);
>   	long rc = syscall(__NR_fchmod, fd, 0600);
>   	printf("%sfchmod(%d<%s>%s, 0600) = %s\n",
>   	       SELINUX_MYCONTEXT(),
> -	       fd, fname_realpath, SELINUX_FILECONTEXT(fname),
> +	       fd, fname_realpath, fname_context,
>   	       sprintrc(rc));
>   
>   	if (unlink(fname))
>   		perror_msg_and_fail("unlink");
>   
>   	rc = syscall(__NR_fchmod, fd, 0600);
> -	printf("%sfchmod(%d<%s (deleted)>, 0600) = %s\n",
> +	printf("%sfchmod(%d<%s (deleted)>%s, 0600) = %s\n",
>   	       SELINUX_MYCONTEXT(),
> -	       fd, fname_realpath,
> +	       fd, fname_realpath, fname_context,
>   	       sprintrc(rc));
>   
>   	puts("+++ exited with 0 +++");
>

-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20210319/f4d70956/attachment.bin>


More information about the Strace-devel mailing list