@@ -20,6 +20,7 @@ selabel_digest
selabel_get_digests_all_partial_matches
selabel_lookup
selabel_lookup_best_match
+selabel_nuke
selabel_partial_match
selinux_check_securetty_context
selinuxenabled
new file mode 100644
@@ -0,0 +1,134 @@
+#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/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 [-nrv] <path>\n", progname);
+}
+
+static void nuke(int atfd, const char *path, const char *fullpath, bool dry_run, bool recursive, bool verbose)
+{
+ 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;
+ }
+
+ 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;
+ }
+
+ nuke(dirfd(dir), entry->d_name, nextfullpath, dry_run, recursive, verbose);
+
+ free(nextfullpath);
+ }
+
+ closedir(dir);
+}
+
+
+int main(int argc, char *argv[])
+{
+ bool dry_run = false, recursive = false, verbose = false;
+ int c;
+
+ while ((c = getopt(argc, argv, "nrv")) != -1) {
+ switch (c) {
+ case 'n':
+ dry_run = true;
+ break;
+ case 'r':
+ recursive = true;
+ break;
+ case 'v':
+ verbose = 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++)
+ nuke(AT_FDCWD, argv[index], argv[index], dry_run, recursive, verbose);
+
+ return EXIT_SUCCESS;
+}
Introduce a helper to remove SELinux file 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> --- libselinux/utils/.gitignore | 1 + libselinux/utils/selabel_nuke.c | 134 ++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 libselinux/utils/selabel_nuke.c