diff mbox series

[1/2] libselinux: Add selinux_restorecon option to treat conflicting specifications as an error.

Message ID 20200402154509.3640-1-chpebeni@linux.microsoft.com (mailing list archive)
State Accepted
Headers show
Series [1/2] libselinux: Add selinux_restorecon option to treat conflicting specifications as an error. | expand

Commit Message

Chris PeBenito April 2, 2020, 3:45 p.m. UTC
Signed-off-by: Chris PeBenito <chpebeni@linux.microsoft.com>
---
 libselinux/include/selinux/restorecon.h  | 37 ++++++++++++++----------
 libselinux/man/man3/selinux_restorecon.3 |  4 +++
 libselinux/src/selinux_restorecon.c      | 13 +++++++--
 3 files changed, 36 insertions(+), 18 deletions(-)
diff mbox series

Patch

diff --git a/libselinux/include/selinux/restorecon.h b/libselinux/include/selinux/restorecon.h
index 754b8645..466de39a 100644
--- a/libselinux/include/selinux/restorecon.h
+++ b/libselinux/include/selinux/restorecon.h
@@ -30,77 +30,82 @@  extern int selinux_restorecon(const char *pathname,
  * Force the checking of labels even if the stored SHA1 digest
  * matches the specfiles SHA1 digest (requires CAP_SYS_ADMIN).
  */
-#define SELINUX_RESTORECON_IGNORE_DIGEST		0x0001
+#define SELINUX_RESTORECON_IGNORE_DIGEST		0x00001
 /*
  * Do not change file labels.
  */
-#define SELINUX_RESTORECON_NOCHANGE			0x0002
+#define SELINUX_RESTORECON_NOCHANGE			0x00002
 /*
  * If set, change file label to that in spec file.
  * If not, only change type component to that in spec file.
  */
-#define SELINUX_RESTORECON_SET_SPECFILE_CTX		0x0004
+#define SELINUX_RESTORECON_SET_SPECFILE_CTX		0x00004
 /*
  * Recursively descend directories.
  */
-#define SELINUX_RESTORECON_RECURSE			0x0008
+#define SELINUX_RESTORECON_RECURSE			0x00008
 /*
  * Log changes to selinux log. Note that if VERBOSE and
  * PROGRESS are set, then PROGRESS will take precedence.
  */
-#define SELINUX_RESTORECON_VERBOSE			0x0010
+#define SELINUX_RESTORECON_VERBOSE			0x00010
 /*
  * If SELINUX_RESTORECON_PROGRESS is true and
  * SELINUX_RESTORECON_MASS_RELABEL is true, then output approx % complete,
  * else output the number of files in 1k blocks processed to stdout.
  */
-#define SELINUX_RESTORECON_PROGRESS			0x0020
+#define SELINUX_RESTORECON_PROGRESS			0x00020
 /*
  * Convert passed-in pathname to canonical pathname.
  */
-#define SELINUX_RESTORECON_REALPATH			0x0040
+#define SELINUX_RESTORECON_REALPATH			0x00040
 /*
  * Prevent descending into directories that have a different
  * device number than the pathname from which the descent began.
  */
-#define SELINUX_RESTORECON_XDEV				0x0080
+#define SELINUX_RESTORECON_XDEV				0x00080
 /*
  * Attempt to add an association between an inode and a specification.
  * If there is already an association for the inode and it conflicts
  * with the specification, then use the last matching specification.
  */
-#define SELINUX_RESTORECON_ADD_ASSOC			0x0100
+#define SELINUX_RESTORECON_ADD_ASSOC			0x00100
 /*
  * Abort on errors during the file tree walk.
  */
-#define SELINUX_RESTORECON_ABORT_ON_ERROR		0x0200
+#define SELINUX_RESTORECON_ABORT_ON_ERROR		0x00200
 /*
  * Log any label changes to syslog.
  */
-#define SELINUX_RESTORECON_SYSLOG_CHANGES		0x0400
+#define SELINUX_RESTORECON_SYSLOG_CHANGES		0x00400
 /*
  * Log what spec matched each file.
  */
-#define SELINUX_RESTORECON_LOG_MATCHES			0x0800
+#define SELINUX_RESTORECON_LOG_MATCHES			0x00800
 /*
  * Ignore files that do not exist.
  */
-#define SELINUX_RESTORECON_IGNORE_NOENTRY		0x1000
+#define SELINUX_RESTORECON_IGNORE_NOENTRY		0x01000
 /*
  * Do not read /proc/mounts to obtain a list of non-seclabel
  * mounts to be excluded from relabeling checks.
  */
-#define SELINUX_RESTORECON_IGNORE_MOUNTS		0x2000
+#define SELINUX_RESTORECON_IGNORE_MOUNTS		0x02000
 /*
  * Set if there is a mass relabel required.
  * See SELINUX_RESTORECON_PROGRESS flag for details.
  */
-#define SELINUX_RESTORECON_MASS_RELABEL			0x4000
+#define SELINUX_RESTORECON_MASS_RELABEL			0x04000
 /*
  * Set if no digest is to be read or written (as only processes
  * running with CAP_SYS_ADMIN can read/write digests).
  */
-#define SELINUX_RESTORECON_SKIP_DIGEST			0x8000
+#define SELINUX_RESTORECON_SKIP_DIGEST			0x08000
+
+/*
+ * Set to treat conflicting specifications as errors.
+ */
+#define SELINUX_RESTORECON_CONFLICT_ERROR		0x10000
 
 /**
  * selinux_restorecon_set_sehandle - Set the global fc handle.
diff --git a/libselinux/man/man3/selinux_restorecon.3 b/libselinux/man/man3/selinux_restorecon.3
index f6e5f2d7..ad637406 100644
--- a/libselinux/man/man3/selinux_restorecon.3
+++ b/libselinux/man/man3/selinux_restorecon.3
@@ -152,6 +152,10 @@  Setting
 .B SELINUX_RESTORECON_IGNORE_MOUNTS
 is useful where there is a non-seclabel fs mounted with a seclabel fs mounted
 on a directory below this.
+.sp
+.B SELINUX_RESTORECON_CONFLICT_ERROR
+to treat conflicting specifications, such as where two hardlinks for the
+same inode have different contexts, as errors.
 .RE
 .sp
 The behavior regarding the checking and updating of the SHA1 digest described
diff --git a/libselinux/src/selinux_restorecon.c b/libselinux/src/selinux_restorecon.c
index 028d8924..91dfeb66 100644
--- a/libselinux/src/selinux_restorecon.c
+++ b/libselinux/src/selinux_restorecon.c
@@ -81,6 +81,7 @@  struct rest_flags {
 	bool log_matches;
 	bool ignore_noent;
 	bool warnonnomatch;
+	bool conflicterror;
 };
 
 static void restorecon_init(void)
@@ -418,7 +419,8 @@  static file_spec_t *fl_head;
  * different context that matched the inode, then use the first context
  * that matched.
  */
-static int filespec_add(ino_t ino, const char *con, const char *file)
+static int filespec_add(ino_t ino, const char *con, const char *file,
+			struct rest_flags *flags)
 {
 	file_spec_t *prevfl, *fl;
 	int h, ret;
@@ -458,6 +460,11 @@  static int filespec_add(ino_t ino, const char *con, const char *file)
 			fl->file = strdup(file);
 			if (!fl->file)
 				goto oom;
+			if (flags->conflicterror) {
+				selinux_log(SELINUX_ERROR,
+				"treating conflicting specifications as an error.\n");
+				return -1;
+			}
 			return 1;
 		}
 
@@ -645,7 +652,7 @@  static int restorecon_sb(const char *pathname, const struct stat *sb,
 	}
 
 	if (flags->add_assoc) {
-		rc = filespec_add(sb->st_ino, newcon, pathname);
+		rc = filespec_add(sb->st_ino, newcon, pathname, flags);
 
 		if (rc < 0) {
 			selinux_log(SELINUX_ERROR,
@@ -833,6 +840,8 @@  int selinux_restorecon(const char *pathname_orig,
 	flags.ignore_noent = (restorecon_flags &
 		   SELINUX_RESTORECON_IGNORE_NOENTRY) ? true : false;
 	flags.warnonnomatch = true;
+	flags.conflicterror = (restorecon_flags &
+		   SELINUX_RESTORECON_CONFLICT_ERROR) ? true : false;
 	ignore_mounts = (restorecon_flags &
 		   SELINUX_RESTORECON_IGNORE_MOUNTS) ? true : false;
 	bool ignore_digest = (restorecon_flags &