/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
-#include <ftw.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <sys/statvfs.h>
#include "alloc-util.h"
#include "bus-util.h"
+#include "cgroup-setup.h"
#include "cgroup-util.h"
#include "conf-files.h"
-#include "cgroup-setup.h"
#include "dev-setup.h"
#include "dirent-util.h"
#include "efi-loader.h"
#include "mountpoint-util.h"
#include "nulstr-util.h"
#include "path-util.h"
+#include "recurse-dir.h"
#include "set.h"
#include "smack-util.h"
#include "strv.h"
}
#if HAVE_SELINUX || ENABLE_SMACK
-static int nftw_cb(
- const char *fpath,
- const struct stat *sb,
- int tflag,
- struct FTW *ftwbuf) {
-
- /* No need to label /dev twice in a row... */
- if (_unlikely_(ftwbuf->level == 0))
- return FTW_CONTINUE;
-
- (void) label_fix(fpath, 0);
-
- /* /run/initramfs is static data and big, no need to
- * dynamically relabel its contents at boot... */
- if (_unlikely_(ftwbuf->level == 1 &&
- tflag == FTW_D &&
- streq(fpath, "/run/initramfs")))
- return FTW_SKIP_SUBTREE;
-
- return FTW_CONTINUE;
-};
+static int relabel_cb(
+ RecurseDirEvent event,
+ const char *path,
+ int dir_fd,
+ int inode_fd,
+ const struct dirent *de,
+ const struct statx *sx,
+ void *userdata) {
+
+ switch (event) {
+
+ case RECURSE_DIR_LEAVE:
+ case RECURSE_DIR_SKIP_MOUNT:
+ /* If we already saw this dirent when entering it or this is a dirent that on a different
+ * mount, don't relabel it. */
+ return RECURSE_DIR_CONTINUE;
+
+ case RECURSE_DIR_ENTER:
+ /* /run/initramfs is static data and big, no need to dynamically relabel its contents at boot... */
+ if (path_equal(path, "/run/initramfs"))
+ return RECURSE_DIR_SKIP_ENTRY;
+
+ _fallthrough_;
+
+ default:
+ /* Otherwise, label it, even if we had trouble stat()ing it and similar. SELinux can figure this out */
+ (void) label_fix(path, 0);
+ return RECURSE_DIR_CONTINUE;
+ }
+}
+
+static int relabel_tree(const char *path) {
+ int r;
+
+ r = recurse_dir_at(AT_FDCWD, path, 0, UINT_MAX, RECURSE_DIR_ENSURE_TYPE|RECURSE_DIR_SAME_MOUNT, relabel_cb, NULL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to recursively relabel '%s': %m", path);
+
+ return r;
+}
static int relabel_cgroup_filesystems(void) {
int r;
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
(void) label_fix("/sys/fs/cgroup", 0);
- (void) nftw("/sys/fs/cgroup", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+ (void) relabel_tree("/sys/fs/cgroup");
if (st.f_flags & ST_RDONLY)
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
log_debug("Relabelling additional file/directory '%s'.", line);
(void) label_fix(line, 0);
- (void) nftw(line, nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+ (void) relabel_tree(line);
c++;
}
before_relabel = now(CLOCK_MONOTONIC);
FOREACH_STRING(i, "/dev", "/dev/shm", "/run")
- (void) nftw(i, nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+ (void) relabel_tree(i);
(void) relabel_cgroup_filesystems();