All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Christian Göttsche" <cgzones@googlemail.com>
To: selinux@vger.kernel.org
Subject: [RFC PATCH v2 1/9] policycoreutils: introduce unsetfiles
Date: Wed, 31 Jan 2024 14:08:27 +0100	[thread overview]
Message-ID: <20240131130840.48155-2-cgzones@googlemail.com> (raw)
In-Reply-To: <20240131130840.48155-1-cgzones@googlemail.com>

Introduce a helper to remove SELinux file security contexts.

Mainly for testing label operations, and only for SELinux disabled
systems, since removing file contexts is not supported by SELinux.

Signed-off-by: Christian Göttsche <cgzones@googlemail.com>
---
v2:
   move from libselinux/utils to policycoreutils and rename
---
 policycoreutils/.gitignore              |   1 +
 policycoreutils/Makefile                |   2 +-
 policycoreutils/unsetfiles/Makefile     |  26 ++++
 policycoreutils/unsetfiles/unsetfiles.1 |  46 ++++++
 policycoreutils/unsetfiles/unsetfiles.c | 183 ++++++++++++++++++++++++
 5 files changed, 257 insertions(+), 1 deletion(-)
 create mode 100644 policycoreutils/unsetfiles/Makefile
 create mode 100644 policycoreutils/unsetfiles/unsetfiles.1
 create mode 100644 policycoreutils/unsetfiles/unsetfiles.c

diff --git a/policycoreutils/.gitignore b/policycoreutils/.gitignore
index 47c9cc52..33e7414c 100644
--- a/policycoreutils/.gitignore
+++ b/policycoreutils/.gitignore
@@ -9,4 +9,5 @@ setfiles/restorecon
 setfiles/restorecon_xattr
 setfiles/setfiles
 setsebool/setsebool
+unsetfiles/unsetfiles
 hll/pp/pp
diff --git a/policycoreutils/Makefile b/policycoreutils/Makefile
index b930b297..32ad0201 100644
--- a/policycoreutils/Makefile
+++ b/policycoreutils/Makefile
@@ -1,4 +1,4 @@
-SUBDIRS = setfiles load_policy newrole run_init secon sestatus semodule setsebool scripts po man hll
+SUBDIRS = setfiles load_policy newrole run_init secon sestatus semodule setsebool scripts po man hll unsetfiles
 
 all install relabel clean indent:
 	@for subdir in $(SUBDIRS); do \
diff --git a/policycoreutils/unsetfiles/Makefile b/policycoreutils/unsetfiles/Makefile
new file mode 100644
index 00000000..9e5edc04
--- /dev/null
+++ b/policycoreutils/unsetfiles/Makefile
@@ -0,0 +1,26 @@
+PREFIX ?= /usr
+SBINDIR ?= $(PREFIX)/sbin
+MANDIR ?= $(PREFIX)/share/man
+
+override CFLAGS += -D_GNU_SOURCE
+override LDLIBS += -lselinux
+
+
+all: unsetfiles
+
+unsetfiles: unsetfiles.o
+
+install: all
+	test -d $(DESTDIR)$(SBINDIR)     || install -m 755 -d $(DESTDIR)$(SBINDIR)
+	test -d $(DESTDIR)$(MANDIR)/man1 || install -m 755 -d $(DESTDIR)$(MANDIR)/man1
+	install -m 755 unsetfiles $(DESTDIR)$(SBINDIR)
+	install -m 644 unsetfiles.1 $(DESTDIR)$(MANDIR)/man1/
+
+clean:
+	-rm -f unsetfiles *.o
+
+indent:
+	../../scripts/Lindent $(wildcard *.[ch])
+
+relabel: install
+	/sbin/restorecon $(DESTDIR)$(SBINDIR)/unsetfiles
diff --git a/policycoreutils/unsetfiles/unsetfiles.1 b/policycoreutils/unsetfiles/unsetfiles.1
new file mode 100644
index 00000000..49d0c821
--- /dev/null
+++ b/policycoreutils/unsetfiles/unsetfiles.1
@@ -0,0 +1,46 @@
+.TH UNSETFILES "1" "December 2023" "Security Enhanced Linux"
+.SH NAME
+unsetfiles \- Remove SELinux file security contexts.
+.SH SYNOPSIS
+.B unsetfiles
+.RB [ \-hnrvx ]
+.IR pathname \ ...
+
+.SH DESCRIPTION
+.P
+This program removes the SELinux file security contexts of files.  It can help
+cleaning extended file attributes after disabling SELinux.
+.P
+.B unsetfiles
+will only work on SELinux disabled systems, since removing file security
+contexts is not supported by SELinux.
+
+.SH OPTIONS
+.TP
+.B \-h
+Show usage information and exit.
+.TP
+.B \-n
+Do not actually remove any SELinux file security contexts.
+.TP
+.B \-r
+Remove SELinux file security contexts recursive.
+.TP
+.B \-v
+Be verbose about performed actions.
+.TP
+.B \-x
+Do not cross filesystem boundaries.
+
+.SH ARGUMENTS
+.TP
+.IR pathname \ ...
+One or more path names to operate on.
+
+.SH SEE ALSO
+.BR restorecon (8),
+.BR setfiles (8)
+
+.SH AUTHORS
+.nf
+Christian Göttsche (cgzones@googlemail.com)
diff --git a/policycoreutils/unsetfiles/unsetfiles.c b/policycoreutils/unsetfiles/unsetfiles.c
new file mode 100644
index 00000000..6293d00f
--- /dev/null
+++ b/policycoreutils/unsetfiles/unsetfiles.c
@@ -0,0 +1,183 @@
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <linux/magic.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include <selinux/selinux.h>
+
+
+#define XATTR_NAME_SELINUX "security.selinux"
+
+
+static void usage(const char *progname)
+{
+	fprintf(stderr, "usage: %s [-nrvx] <path>\n\n"
+	                "Options:\n"
+	                "\t-n\tdon't remove any file labels\n"
+	                "\t-r\tremove labels recursive\n"
+	                "\t-v\tbe verbose\n"
+	                "\t-x\tdo not cross filesystem boundaries\n",
+	                progname);
+}
+
+static void unset(int atfd, const char *path, const char *fullpath,
+                  bool dry_run, bool recursive, bool verbose,
+                  dev_t root_dev)
+{
+	ssize_t ret;
+	int fd, rc;
+	DIR *dir;
+
+	ret = lgetxattr(fullpath, XATTR_NAME_SELINUX, NULL, 0);
+	if (ret <= 0) {
+		if (errno != ENODATA && errno != ENOTSUP)
+			fprintf(stderr, "Failed to get SELinux label of %s:  %m\n", fullpath);
+		else if (verbose)
+			printf("Failed to get SELinux label of %s:  %m\n", fullpath);
+	} else {
+		if (dry_run) {
+			printf("Would remove SELinux label of %s\n", fullpath);
+		} else {
+			if (verbose)
+				printf("Removing label of %s\n", fullpath);
+
+			rc = lremovexattr(fullpath, XATTR_NAME_SELINUX);
+			if (rc < 0)
+				fprintf(stderr, "Failed to remove SELinux label of %s:  %m\n", fullpath);
+		}
+	}
+
+	if (!recursive)
+		return;
+
+	fd = openat(atfd, path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+	if (fd < 0) {
+		if (errno != ENOTDIR)
+			fprintf(stderr, "Failed to open %s:  %m\n", fullpath);
+		return;
+	}
+
+	if (root_dev != (dev_t)-1) {
+		struct stat sb;
+
+		rc = fstat(fd, &sb);
+		if (rc == -1) {
+			fprintf(stderr, "Failed to stat directory %s:  %m\n", fullpath);
+			close(fd);
+			return;
+		}
+
+		if (sb.st_dev != root_dev) {
+			if (verbose)
+				printf("Skipping directory %s due to filesystem boundary\n", fullpath);
+
+			close(fd);
+			return;
+		}
+	}
+
+	dir = fdopendir(fd);
+	if (!dir) {
+		fprintf(stderr, "Failed to open directory %s:  %m\n", fullpath);
+		close(fd);
+		return;
+	}
+
+	while (true) {
+		const struct dirent *entry;
+		char *nextfullpath;
+
+		errno = 0;
+		entry = readdir(dir);
+		if (!entry) {
+			if (errno)
+				fprintf(stderr, "Failed to iterate directory %s:  %m\n", fullpath);
+			break;
+		}
+
+		if (entry->d_name[0] == '.' && (entry->d_name[1] == '\0' || (entry->d_name[1] == '.' && entry->d_name[2] == '\0')))
+			continue;
+
+		rc = asprintf(&nextfullpath, "%s/%s", strcmp(fullpath, "/") == 0 ? "" : fullpath, entry->d_name);
+		if (rc < 0) {
+			fprintf(stderr, "Out of memory!\n");
+			closedir(dir);
+			return;
+		}
+
+		unset(dirfd(dir), entry->d_name, nextfullpath, dry_run, recursive, verbose, root_dev);
+
+		free(nextfullpath);
+	}
+
+	closedir(dir);
+}
+
+
+int main(int argc, char *argv[])
+{
+	bool dry_run = false, recursive = false, verbose = false, same_dev = false;
+	int c;
+
+	while ((c = getopt(argc, argv, "hnrvx")) != -1) {
+		switch (c) {
+		case 'h':
+			usage(argv[0]);
+			return EXIT_SUCCESS;
+		case 'n':
+			dry_run = true;
+			break;
+		case 'r':
+			recursive = true;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		case 'x':
+			same_dev = true;
+			break;
+		default:
+			usage(argv[0]);
+			return EXIT_FAILURE;
+		}
+	}
+
+	if (optind >= argc) {
+		usage(argv[0]);
+		return EXIT_FAILURE;
+	}
+
+	if (is_selinux_enabled()) {
+		fprintf(stderr, "Removing SELinux attributes on a SELinux enabled system is not supported!\n");
+		return EXIT_FAILURE;
+	}
+
+	for (int index = optind; index < argc; index++) {
+		dev_t root_dev = (dev_t)-1;
+
+		if (same_dev) {
+			struct stat sb;
+			int rc;
+
+			rc = stat(argv[index], &sb);
+			if (rc == -1) {
+				fprintf(stderr, "Failed to stat %s:  %m\n", argv[index]);
+				continue;
+			}
+
+			root_dev = sb.st_dev;
+		}
+		unset(AT_FDCWD, argv[index], argv[index], dry_run, recursive, verbose, root_dev);
+	}
+
+	return EXIT_SUCCESS;
+}
-- 
2.43.0


  reply	other threads:[~2024-01-31 13:08 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-31 13:08 [RFC PATCH v2 0/9] libselinux: rework selabel_file(5) database Christian Göttsche
2024-01-31 13:08 ` Christian Göttsche [this message]
2024-01-31 13:08 ` [RFC PATCH v2 2/9] libselinux/utils: introduce selabel_compare Christian Göttsche
2024-03-07 19:50   ` James Carter
2024-03-11 17:20     ` Christian Göttsche
2024-03-11 20:49       ` James Carter
2024-01-31 13:08 ` [RFC PATCH v2 3/9] libselinux: use more appropriate types in sidtab Christian Göttsche
2024-01-31 13:08 ` [RFC PATCH v2 4/9] libselinux: add unique id to sidtab entries Christian Göttsche
2024-01-31 13:08 ` [RFC PATCH v2 5/9] libselinux: sidtab updates Christian Göttsche
2024-03-07 20:53   ` James Carter
2024-03-11 16:32     ` Christian Göttsche
2024-01-31 13:08 ` [RFC PATCH v2 6/9] libselinux: rework selabel_file(5) database Christian Göttsche
2024-01-31 13:08 ` [RFC PATCH v2 7/9] libselinux: remove unused hashtab code Christian Göttsche
2024-01-31 13:08 ` [RFC PATCH v2 8/9] libselinux: add selabel_file(5) fuzzer Christian Göttsche
2024-01-31 13:08 ` [RFC PATCH v2 9/9] libselinux: support parallel selabel_lookup(3) Christian Göttsche

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240131130840.48155-2-cgzones@googlemail.com \
    --to=cgzones@googlemail.com \
    --cc=selinux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.