Blame SOURCES/0181-secontext-fix-expected-SELinux-context-check-for-unl.patch

6fb5f2
From 3f0e5340b651da98251a58cc7923525d69f96032 Mon Sep 17 00:00:00 2001
6fb5f2
From: Eugene Syromyatnikov <evgsyr@gmail.com>
6fb5f2
Date: Fri, 1 Jul 2022 10:45:48 +0200
6fb5f2
Subject: [PATCH] secontext: fix expected SELinux context check for unlinked
6fb5f2
 FDs
6fb5f2
MIME-Version: 1.0
6fb5f2
Content-Type: text/plain; charset=UTF-8
6fb5f2
Content-Transfer-Encoding: 8bit
6fb5f2
6fb5f2
selinux_getfdcon open-coded a part of getfdpath_pid since it tries
6fb5f2
to do the same job, figure out a path associated with an FD, for slightly
6fb5f2
different purpose: to get the expected SELinux context for it.  As the previous
6fb5f2
commit shows, it's a bit more complicated in cases when the path ends
6fb5f2
with the " (deleted)" string, which is also used for designated unlinked paths
6fb5f2
in procfs.  Otherwise, it may manifest in test failures such as this:
6fb5f2
6fb5f2
     [unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023] fchmod(4</root/rpmbuild/BUILD/strace-5.13/tests/fchmod-y--secontext_full_mismatch.dir/fchmod_subdir/fchmod_sample_file> [unconfined_u:object_r:admin_home_t:s0!!system_u:object_r:admin_home_t:s0], 0600) = 0
6fb5f2
    -[unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023] fchmod(4</root/rpmbuild/BUILD/strace-5.13/tests/fchmod-y--secontext_full_mismatch.dir/fchmod_subdir/fchmod_sample_file (deleted)> [unconfined_u:object_r:admin_home_t:s0!!system_u:object_r:admin_home_t:s0], 051) = 0
6fb5f2
    -[unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023] fchmod(4</root/rpmbuild/BUILD/strace-5.13/tests/fchmod-y--secontext_full_mismatch.dir/fchmod_subdir/fchmod_sample_file (deleted)> [unconfined_u:object_r:admin_home_t:s0!!system_u:object_r:admin_home_t:s0], 004) = 0
6fb5f2
    +[unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023] fchmod(4</root/rpmbuild/BUILD/strace-5.13/tests/fchmod-y--secontext_full_mismatch.dir/fchmod_subdir/fchmod_sample_file (deleted)> [unconfined_u:object_r:admin_home_t:s0], 051) = 0
6fb5f2
    +[unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023] fchmod(4</root/rpmbuild/BUILD/strace-5.13/tests/fchmod-y--secontext_full_mismatch.dir/fchmod_subdir/fchmod_sample_file (deleted)> [unconfined_u:object_r:admin_home_t:s0], 004) = 0
6fb5f2
     +++ exited with 0 +++
6fb5f2
    + fail_ '../../src/strace -a15 -y --secontext=full,mismatch -e trace=fchmod ../fchmod-y--secontext_full_mismatch output mismatch'
6fb5f2
    + warn_ 'fchmod-y--secontext_full_mismatch.gen.test: failed test: ../../src/strace -a15 -y --secontext=full,mismatch -e trace=fchmod ../fchmod-y--secontext_full_mismatch output mismatch'
6fb5f2
    + printf '%s\n' 'fchmod-y--secontext_full_mismatch.gen.test: failed test: ../../src/strace -a15 -y --secontext=full,mismatch -e trace=fchmod ../fchmod-y--secontext_full_mismatch output mismatch'
6fb5f2
    fchmod-y--secontext_full_mismatch.gen.test: failed test: ../../src/strace -a15 -y --secontext=full,mismatch -e trace=fchmod ../fchmod-y--secontext_full_mismatch output mismatch
6fb5f2
    + exit 1
6fb5f2
    FAIL fchmod-y--secontext_full_mismatch.gen.test (exit status: 1)
6fb5f2
6fb5f2
that happens due to the fact that the get_expected_filecontext() call
6fb5f2
is made against the path with the " (deleted)" part, which is wrong (it
6fb5f2
is more wrong than shown above when a file with the path that ends with
6fb5f2
" (deleted)" exists).  Moreover, it would be incorrect to call stat()
6fb5f2
on that path.
6fb5f2
6fb5f2
Let's factor out the common part of the code and simply call it
6fb5f2
from selinux_getfdcon, then use the st_mode from the procfs link.
6fb5f2
6fb5f2
* src/defs.h (get_proc_pid_fd_path): New declaration.
6fb5f2
* src/pathtrace.c (get)proc_pid_fd_path): New function, part
6fb5f2
of getfdpath_pid that performs link resolution and processing
6fb5f2
of the result.
6fb5f2
(getfdpath_pid): Call get_proc_pid_fd_path after PID resolution.
6fb5f2
* src/secontext.c (get_expected_filecontext): Add mode parameter, use
6fb5f2
it in selabel_lookup call instead of retrieveing file mode using stat()
6fb5f2
if it is not -1.
6fb5f2
(selinux_getfdcon): Call get_proc_pid_fd_path instead
6fb5f2
of open-coding path resolution code, call stat() on the procfs link
6fb5f2
and pass the retrieved st_mode to the get_expected_filecontext call.
6fb5f2
(selinux_getfilecon): Pass -1 as mode in the get_expected_filecontext
6fb5f2
call.
6fb5f2
6fb5f2
Reported-by: Václav Kadlčík <vkadlcik@redhat.com>
6fb5f2
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2087693
6fb5f2
---
6fb5f2
 src/defs.h      | 15 +++++++++++++++
6fb5f2
 src/pathtrace.c | 26 ++++++++++++++++++--------
6fb5f2
 src/secontext.c | 35 +++++++++++++++++++++--------------
6fb5f2
 3 files changed, 54 insertions(+), 22 deletions(-)
6fb5f2
6fb5f2
Index: strace-5.18/src/defs.h
6fb5f2
===================================================================
6fb5f2
--- strace-5.18.orig/src/defs.h	2022-07-12 18:22:01.563254140 +0200
6fb5f2
+++ strace-5.18/src/defs.h	2022-07-12 18:22:06.202199392 +0200
6fb5f2
@@ -785,6 +785,21 @@
6fb5f2
 	return pathtrace_match_set(tcp, &global_path_set);
6fb5f2
 }
6fb5f2
 
6fb5f2
+/**
6fb5f2
+ * Resolves a path for a fd procfs PID proc_pid (the one got from
6fb5f2
+ * get_proc_pid()).
6fb5f2
+ *
6fb5f2
+ * @param proc_pid PID number in /proc, obtained with get_proc_pid().
6fb5f2
+ * @param fd       FD to resolve path for.
6fb5f2
+ * @param buf      Buffer to store the resolved path in.
6fb5f2
+ * @param bufsize  The size of buf.
6fb5f2
+ * @param deleted  If non-NULL, set to true if the path associated with the FD
6fb5f2
+ *                 seems to have been unlinked and to false otherwise.
6fb5f2
+ * @return         Number of bytes written including terminating '\0'.
6fb5f2
+ */
6fb5f2
+extern int get_proc_pid_fd_path(int proc_pid, int fd, char *buf,
6fb5f2
+				unsigned bufsize, bool *deleted);
6fb5f2
+
6fb5f2
 extern int getfdpath_pid(pid_t pid, int fd, char *buf, unsigned bufsize,
6fb5f2
 			 bool *deleted);
6fb5f2
 
6fb5f2
Index: strace-5.18/src/pathtrace.c
6fb5f2
===================================================================
6fb5f2
--- strace-5.18.orig/src/pathtrace.c	2022-07-12 18:22:01.532254506 +0200
6fb5f2
+++ strace-5.18/src/pathtrace.c	2022-07-12 18:22:06.202199392 +0200
6fb5f2
@@ -77,11 +77,9 @@
6fb5f2
 	set->paths_selected[set->num_selected++] = path;
6fb5f2
 }
6fb5f2
 
6fb5f2
-/*
6fb5f2
- * Get path associated with fd of a process with pid.
6fb5f2
- */
6fb5f2
 int
6fb5f2
-getfdpath_pid(pid_t pid, int fd, char *buf, unsigned bufsize, bool *deleted)
6fb5f2
+get_proc_pid_fd_path(int proc_pid, int fd, char *buf, unsigned bufsize,
6fb5f2
+		     bool *deleted)
6fb5f2
 {
6fb5f2
 	char linkpath[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3];
6fb5f2
 	ssize_t n;
6fb5f2
@@ -89,10 +87,6 @@
6fb5f2
 	if (fd < 0)
6fb5f2
 		return -1;
6fb5f2
 
6fb5f2
-	int proc_pid = get_proc_pid(pid);
6fb5f2
-	if (!proc_pid)
6fb5f2
-		return -1;
6fb5f2
-
6fb5f2
 	xsprintf(linkpath, "/proc/%u/fd/%u", proc_pid, fd);
6fb5f2
 	n = readlink(linkpath, buf, bufsize - 1);
6fb5f2
 	if (n < 0)
6fb5f2
@@ -143,6 +137,22 @@
6fb5f2
 }
6fb5f2
 
6fb5f2
 /*
6fb5f2
+ * Get path associated with fd of a process with pid.
6fb5f2
+ */
6fb5f2
+int
6fb5f2
+getfdpath_pid(pid_t pid, int fd, char *buf, unsigned bufsize, bool *deleted)
6fb5f2
+{
6fb5f2
+	if (fd < 0)
6fb5f2
+		return -1;
6fb5f2
+
6fb5f2
+	int proc_pid = get_proc_pid(pid);
6fb5f2
+	if (!proc_pid)
6fb5f2
+		return -1;
6fb5f2
+
6fb5f2
+	return get_proc_pid_fd_path(proc_pid, fd, buf, bufsize, deleted);
6fb5f2
+}
6fb5f2
+
6fb5f2
+/*
6fb5f2
  * Add a path to the set we're tracing.  Also add the canonicalized
6fb5f2
  * version of the path.  Specifying NULL will delete all paths.
6fb5f2
  */
6fb5f2
Index: strace-5.18/src/secontext.c
6fb5f2
===================================================================
6fb5f2
--- strace-5.18.orig/src/secontext.c	2022-07-12 18:22:01.564254128 +0200
6fb5f2
+++ strace-5.18/src/secontext.c	2022-07-12 18:22:06.203199380 +0200
6fb5f2
@@ -62,7 +62,7 @@
6fb5f2
 }
6fb5f2
 
6fb5f2
 static int
6fb5f2
-get_expected_filecontext(const char *path, char **secontext)
6fb5f2
+get_expected_filecontext(const char *path, char **secontext, int mode)
6fb5f2
 {
6fb5f2
 	static struct selabel_handle *hdl;
6fb5f2
 
6fb5f2
@@ -80,12 +80,7 @@
6fb5f2
 		}
6fb5f2
 	}
6fb5f2
 
6fb5f2
-	strace_stat_t stb;
6fb5f2
-	if (stat_file(path, &stb) < 0) {
6fb5f2
-		return -1;
6fb5f2
-	}
6fb5f2
-
6fb5f2
-	return selabel_lookup(hdl, secontext, path, stb.st_mode);
6fb5f2
+	return selabel_lookup(hdl, secontext, path, mode);
6fb5f2
 }
6fb5f2
 
6fb5f2
 /*
6fb5f2
@@ -130,16 +125,22 @@
6fb5f2
 
6fb5f2
 	/*
6fb5f2
 	 * We need to resolve the path, because selabel_lookup() doesn't
6fb5f2
-	 * resolve anything.  Using readlink() is sufficient here.
6fb5f2
+	 * resolve anything.
6fb5f2
 	 */
6fb5f2
+	char buf[PATH_MAX + 1];
6fb5f2
+	ssize_t n = get_proc_pid_fd_path(proc_pid, fd, buf, sizeof(buf), NULL);
6fb5f2
+	if ((size_t) n >= (sizeof(buf) - 1))
6fb5f2
+		return 0;
6fb5f2
 
6fb5f2
-	char buf[PATH_MAX];
6fb5f2
-	ssize_t n = readlink(linkpath, buf, sizeof(buf));
6fb5f2
-	if ((size_t) n >= sizeof(buf))
6fb5f2
+	/*
6fb5f2
+	 * We retrieve stat() here since the path the procfs link resolves into
6fb5f2
+	 * may be reused by a different file with different context.
6fb5f2
+	 */
6fb5f2
+	strace_stat_t st;
6fb5f2
+	if (stat_file(linkpath, &st))
6fb5f2
 		return 0;
6fb5f2
-	buf[n] = '\0';
6fb5f2
 
6fb5f2
-	get_expected_filecontext(buf, expected);
6fb5f2
+	get_expected_filecontext(buf, expected, st.st_mode);
6fb5f2
 
6fb5f2
 	return 0;
6fb5f2
 }
6fb5f2
@@ -190,7 +191,13 @@
6fb5f2
 	if (!resolved)
6fb5f2
 		return 0;
6fb5f2
 
6fb5f2
-	get_expected_filecontext(resolved, expected);
6fb5f2
+	strace_stat_t st;
6fb5f2
+	if (stat_file(resolved, &st) < 0)
6fb5f2
+		goto out;
6fb5f2
+
6fb5f2
+	get_expected_filecontext(resolved, expected, st.st_mode);
6fb5f2
+
6fb5f2
+out:
6fb5f2
 	free(resolved);
6fb5f2
 
6fb5f2
 	return 0;