From 30eecfb38d370d3aaa43fba7a1668dbc89a99fe4 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 21 Nov 2020 16:59:25 -0800 Subject: [PATCH 3/3] maint: port from matchpathcon to selabel_lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ubuntu 20.10 is using a newer version of libselinux that complains that matchpathcon is obsolete. Rewrite the code that it uses the recommended selabel_lookup instead. * m4/jm-macros.m4 (coreutils_MACROS): Do not check for matchpathcon_init_prefix, as it is no longer used. * src/copy.c (set_file_security_ctx): Omit process_local arg, as it is equivalent to !x->set_security_context. All callers changed. * src/copy.h (struct cp_options): set_security_context is now of type struct selabel_handle *, not bool. All uses changed. * src/cp.c, src/install.c, src/mkdir.c, src/mkfifo.c, src/mknod.c: * src/mv.c: Include selinux/label.h. (main): Use selabel_open for set_security context. * src/install.c (matchpathcon_init_prefix): Remove; now unused. (get_labeling_handle): New static function. (setdefaultfilecon, main): Use it. (setdefaultfilecon): Do something regardless of ENABLE_MATCHPATHCON, which seems to be a revenant macro. (setdefaultfilecon): Use selabel_lookup instead of the obsolescent matchpathcon. Report an error unless it fails due to ENOENT. * src/local.mk (src_ginstall_CPPFLAGS): Remove. * src/selinux.c: Include selinux/label.h Do not include die.h, error.h, canonicalize.h. (defaultcon, restorecon_private, restorecon): New arg HANDLE. All callers changed. Use selabel_lookup rather than matchpathcon. (restorecon_private, restorecon): Don’t lose track of errno. * src/selinux.c, src/selinux.h: (restorecon): Don’t call ‘error’; that’s the caller’s job. Use HAVE_SELINUX_LABEL_H, not HAVE_SELINUX_SELINUX_H, in case there is some weird system with the former but not the latter. * src/selinux.h (struct selinux_handle): Add forward decl. --- m4/jm-macros.m4 | 17 +------ src/copy.c | 23 ++++------ src/copy.h | 8 ++-- src/cp.c | 20 ++++---- src/install.c | 95 ++++++++++++-------------------------- src/local.mk | 2 - src/mkdir.c | 23 ++++++---- src/mkfifo.c | 13 ++++-- src/mknod.c | 15 ++++-- src/mv.c | 9 ++-- src/selinux.c | 119 ++++++++++++++---------------------------------- src/selinux.h | 16 +++++-- 12 files changed, 144 insertions(+), 216 deletions(-) diff --git a/m4/jm-macros.m4 b/m4/jm-macros.m4 index 266235113..bce7ae7fc 100644 --- a/m4/jm-macros.m4 +++ b/m4/jm-macros.m4 @@ -1,4 +1,4 @@ -#serial 111 -*- autoconf -*- +#serial 112 -*- autoconf -*- dnl Misc type-related macros for coreutils. @@ -52,21 +52,6 @@ AC_DEFUN([coreutils_MACROS], LIBS="$LIBS $LIB_SELINUX" # Used by selinux.c. AC_CHECK_FUNCS([mode_to_security_class], [], []) - # Used by install.c. - AC_CHECK_FUNCS([matchpathcon_init_prefix], [], - [ - if test "$with_selinux" != no; then - case "$ac_cv_search_setfilecon:$ac_cv_header_selinux_selinux_h" in - no:*) # SELinux disabled - ;; - *:no) # SELinux disabled - ;; - *) - AC_MSG_WARN([SELinux enabled, but matchpathcon_init_prefix not found]) - AC_MSG_WARN([The install utility may run slowly]) - esac - fi - ]) LIBS=$coreutils_saved_libs # Used by sort.c. diff --git a/src/copy.c b/src/copy.c index 4050f6953..93f3c6db4 100644 --- a/src/copy.c +++ b/src/copy.c @@ -1141,7 +1141,7 @@ set_process_security_ctx (char const *src_name, char const *dst_name, { /* With -Z, adjust the default context for the process to have the type component adjusted as per the destination path. */ - if (new_dst && defaultcon (dst_name, mode) < 0 + if (new_dst && defaultcon (x->set_security_context, dst_name, mode) < 0 && ! ignorable_ctx_err (errno)) { error (0, errno, @@ -1154,21 +1154,21 @@ set_process_security_ctx (char const *src_name, char const *dst_name, } /* Reset the security context of DST_NAME, to that already set - as the process default if PROCESS_LOCAL is true. Otherwise + as the process default if !X->set_security_context. Otherwise adjust the type component of DST_NAME's security context as per the system default for that path. Issue warnings upon - failure, when allowed by various settings in CP_OPTIONS. - Return FALSE on failure, TRUE on success. */ + failure, when allowed by various settings in X. + Return false on failure, true on success. */ bool -set_file_security_ctx (char const *dst_name, bool process_local, +set_file_security_ctx (char const *dst_name, bool recurse, const struct cp_options *x) { bool all_errors = (!x->data_copy_required || x->require_preserve_context); bool some_errors = !all_errors && !x->reduce_diagnostics; - if (! restorecon (dst_name, recurse, process_local)) + if (! restorecon (x->set_security_context, dst_name, recurse)) { if (all_errors || (some_errors && !errno_unsupported (errno))) error (0, errno, _("failed to set the security context of %s"), @@ -1330,8 +1330,7 @@ copy_reg (char const *src_name, char const *dst_name, if ((x->set_security_context || x->preserve_security_context) && 0 <= dest_desc) { - if (! set_file_security_ctx (dst_name, x->preserve_security_context, - false, x)) + if (! set_file_security_ctx (dst_name, false, x)) { if (x->require_preserve_context) { @@ -2609,7 +2608,7 @@ copy_internal (char const *src_name, char const *dst_name, if (x->set_security_context) { /* -Z failures are only warnings currently. */ - (void) set_file_security_ctx (dst_name, false, true, x); + (void) set_file_security_ctx (dst_name, true, x); } if (rename_succeeded) @@ -2819,8 +2818,7 @@ copy_internal (char const *src_name, char const *dst_name, descendents, so use it to set the context for existing dirs here. This will also give earlier indication of failure to set ctx. */ if (x->set_security_context || x->preserve_security_context) - if (! set_file_security_ctx (dst_name, x->preserve_security_context, - false, x)) + if (! set_file_security_ctx (dst_name, false, x)) { if (x->require_preserve_context) goto un_backup; @@ -3020,8 +3018,7 @@ copy_internal (char const *src_name, char const *dst_name, if (!new_dst && !x->copy_as_regular && !S_ISDIR (src_mode) && (x->set_security_context || x->preserve_security_context)) { - if (! set_file_security_ctx (dst_name, x->preserve_security_context, - false, x)) + if (! set_file_security_ctx (dst_name, false, x)) { if (x->require_preserve_context) goto un_backup; diff --git a/src/copy.h b/src/copy.h index a0ad494b9..344d91bfb 100644 --- a/src/copy.h +++ b/src/copy.h @@ -22,6 +22,8 @@ # include # include "hash.h" +struct selabel_handle; + /* Control creation of sparse files (files with holes). */ enum Sparse_type { @@ -162,8 +164,8 @@ struct cp_options bool preserve_timestamps; bool explicit_no_preserve_mode; - /* If true, attempt to set specified security context */ - bool set_security_context; + /* If non-null, attempt to set specified security context */ + struct selabel_handle *set_security_context; /* Enabled for mv, and for cp by the --preserve=links option. If true, attempt to preserve in the destination files any @@ -294,7 +296,7 @@ extern bool set_process_security_ctx (char const *src_name, mode_t mode, bool new_dst, const struct cp_options *x); -extern bool set_file_security_ctx (char const *dst_name, bool process_local, +extern bool set_file_security_ctx (char const *dst_name, bool recurse, const struct cp_options *x); void dest_info_init (struct cp_options *); diff --git a/src/cp.c b/src/cp.c index a4ecbbc9f..3a451eb99 100644 --- a/src/cp.c +++ b/src/cp.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include "system.h" #include "argmatch.h" @@ -531,10 +531,9 @@ make_dir_parents_private (char const *const_dir, size_t src_offset, if (! *new_dst && (x->set_security_context || x->preserve_security_context)) { - if (! set_file_security_ctx (dir, x->preserve_security_context, - false, x) + if (! set_file_security_ctx (dir, false, x) && x->require_preserve_context) - return false; + return false; } *slash++ = '/'; @@ -802,7 +801,7 @@ cp_option_init (struct cp_options *x) x->explicit_no_preserve_mode = false; x->preserve_security_context = false; /* -a or --preserve=context. */ x->require_preserve_context = false; /* --preserve=context. */ - x->set_security_context = false; /* -Z, set sys default context. */ + x->set_security_context = NULL; /* -Z, set sys default context. */ x->preserve_xattr = false; x->reduce_diagnostics = false; x->require_preserve_xattr = false; @@ -1116,7 +1115,12 @@ main (int argc, char **argv) if (optarg) scontext = optarg; else - x.set_security_context = true; + { + x.set_security_context = selabel_open (SELABEL_CTX_FILE, + NULL, 0); + if (! x.set_security_context) + error (0, errno, _("warning: ignoring --context")); + } } else if (optarg) { @@ -1197,8 +1201,8 @@ main (int argc, char **argv) /* FIXME: This handles new files. But what about existing files? I.e., if updating a tree, new files would have the specified context, but shouldn't existing files be updated for consistency like this? - if (scontext) - restorecon (dst_path, 0, true); + if (scontext && !restorecon (NULL, dst_path, 0)) + error (...); */ if (scontext && setfscreatecon (se_const (scontext)) < 0) die (EXIT_FAILURE, errno, diff --git a/src/install.c b/src/install.c index a94053f4d..eb6e403e7 100644 --- a/src/install.c +++ b/src/install.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include "system.h" @@ -65,10 +65,6 @@ static bool use_default_selinux_context = true; # define lchown(name, uid, gid) chown (name, uid, gid) #endif -#if ! HAVE_MATCHPATHCON_INIT_PREFIX -# define matchpathcon_init_prefix(a, p) /* empty */ -#endif - /* The user name that will own the files, or NULL to make the owner the current user ID. */ static char *owner_name; @@ -298,24 +294,37 @@ cp_option_init (struct cp_options *x) x->update = false; x->require_preserve_context = false; /* Not used by install currently. */ x->preserve_security_context = false; /* Whether to copy context from src. */ - x->set_security_context = false; /* Whether to set sys default context. */ + x->set_security_context = NULL; /* Whether to set sys default context. */ x->preserve_xattr = false; x->verbose = false; x->dest_info = NULL; x->src_info = NULL; } -#ifdef ENABLE_MATCHPATHCON +static struct selabel_handle * +get_labeling_handle (void) +{ + static bool initialized; + static struct selabel_handle *hnd; + if (!initialized) + { + initialized = true; + hnd = selabel_open (SELABEL_CTX_FILE, NULL, 0); + if (!hnd) + error (0, errno, _("warning: security labeling handle failed")); + } + return hnd; +} + /* Modify file context to match the specified policy. If an error occurs the file will remain with the default directory - context. Note this sets the context to that returned by matchpathcon, + context. Note this sets the context to that returned by selabel_lookup and thus discards MLS levels and user identity of the FILE. */ static void setdefaultfilecon (char const *file) { struct stat st; char *scontext = NULL; - static bool first_call = true; if (selinux_enabled != 1) { @@ -325,51 +334,14 @@ setdefaultfilecon (char const *file) if (lstat (file, &st) != 0) return; - if (first_call && IS_ABSOLUTE_FILE_NAME (file)) - { - /* Calling matchpathcon_init_prefix (NULL, "/first_component/") - is an optimization to minimize the expense of the following - matchpathcon call. Do it only once, just before the first - matchpathcon call. We *could* call matchpathcon_fini after - the final matchpathcon call, but that's not necessary, since - by then we're about to exit, and besides, the buffers it - would free are still reachable. */ - char const *p0; - char const *p = file + 1; - while (ISSLASH (*p)) - ++p; - - /* Record final leading slash, for when FILE starts with two or more. */ - p0 = p - 1; - - if (*p) - { - char *prefix; - do - { - ++p; - } - while (*p && !ISSLASH (*p)); - - prefix = malloc (p - p0 + 2); - if (prefix) - { - stpcpy (stpncpy (prefix, p0, p - p0), "/"); - matchpathcon_init_prefix (NULL, prefix); - free (prefix); - } - } - } - first_call = false; - - /* If there's an error determining the context, or it has none, - return to allow default context. Note the "<>" check - is only needed for libselinux < 1.20 (2005-01-04). */ - if ((matchpathcon (file, st.st_mode, &scontext) != 0) - || STREQ (scontext, "<>")) + struct selabel_handle *hnd = get_labeling_handle (); + if (!hnd) + return; + if (selabel_lookup (hnd, &scontext, file, st.st_mode) != 0) { - if (scontext != NULL) - freecon (scontext); + if (errno != ENOENT) + error (0, errno, _("warning: %s: context lookup failed"), + quotef (file)); return; } @@ -379,15 +351,7 @@ setdefaultfilecon (char const *file) quotef_n (0, file), quote_n (1, scontext)); freecon (scontext); - return; } -#else -static void -setdefaultfilecon (char const *file) -{ - (void) file; -} -#endif /* FILE is the last operand of this command. Return true if FILE is a directory. But report an error there is a problem accessing FILE, @@ -427,7 +391,8 @@ static int make_ancestor (char const *dir, char const *component, void *options) { struct cp_options const *x = options; - if (x->set_security_context && defaultcon (component, S_IFDIR) < 0 + if (x->set_security_context + && defaultcon (x->set_security_context, component, S_IFDIR) < 0 && ! ignorable_ctx_err (errno)) error (0, errno, _("failed to set default creation context for %s"), quoteaf (dir)); @@ -457,7 +422,7 @@ process_dir (char *dir, struct savewd *wd, void *options) and here we set the context for the final component. */ if (ret == EXIT_SUCCESS && x->set_security_context) { - if (! restorecon (last_component (dir), false, false) + if (! restorecon (x->set_security_context, last_component (dir), false) && ! ignorable_ctx_err (errno)) error (0, errno, _("failed to restore context for %s"), quoteaf (dir)); @@ -902,7 +867,7 @@ main (int argc, char **argv) /* Disable use of the install(1) specific setdefaultfilecon(). Note setdefaultfilecon() is different from the newer and more generic restorecon() in that the former sets the context of - the dest files to that returned by matchpathcon directly, + the dest files to that returned by selabel_lookup directly, thus discarding MLS level and user identity of the file. TODO: consider removing setdefaultfilecon() in future. */ use_default_selinux_context = false; @@ -910,7 +875,7 @@ main (int argc, char **argv) if (optarg) scontext = optarg; else - x.set_security_context = true; + x.set_security_context = get_labeling_handle (); } else if (optarg) { diff --git a/src/local.mk b/src/local.mk index 03150bff3..04e3c30e4 100644 --- a/src/local.mk +++ b/src/local.mk @@ -416,8 +416,6 @@ src_base32_CPPFLAGS = -DBASE_TYPE=32 $(AM_CPPFLAGS) src_basenc_SOURCES = src/basenc.c src_basenc_CPPFLAGS = -DBASE_TYPE=42 $(AM_CPPFLAGS) -src_ginstall_CPPFLAGS = -DENABLE_MATCHPATHCON=1 $(AM_CPPFLAGS) - src_expand_SOURCES = src/expand.c src/expand-common.c src_unexpand_SOURCES = src/unexpand.c src/expand-common.c diff --git a/src/mkdir.c b/src/mkdir.c index 5afc0aa0f..988e53624 100644 --- a/src/mkdir.c +++ b/src/mkdir.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include "system.h" #include "die.h" @@ -98,7 +98,7 @@ struct mkdir_options mode_t mode_bits; /* Set the SELinux File Context. */ - bool set_security_context; + struct selabel_handle *set_security_context; /* If not null, format to use when reporting newly made directories. */ char const *created_directory_format; @@ -123,7 +123,8 @@ make_ancestor (char const *dir, char const *component, void *options) { struct mkdir_options const *o = options; - if (o->set_security_context && defaultcon (component, S_IFDIR) < 0 + if (o->set_security_context + && defaultcon (o->set_security_context, component, S_IFDIR) < 0 && ! ignorable_ctx_err (errno)) error (0, errno, _("failed to set default creation context for %s"), quoteaf (dir)); @@ -156,7 +157,8 @@ process_dir (char *dir, struct savewd *wd, void *options) /* If possible set context before DIR created. */ if (o->set_security_context) { - if (! o->make_ancestor_function && defaultcon (dir, S_IFDIR) < 0 + if (! o->make_ancestor_function + && defaultcon (o->set_security_context, dir, S_IFDIR) < 0 && ! ignorable_ctx_err (errno)) error (0, errno, _("failed to set default creation context for %s"), quoteaf (dir)); @@ -176,7 +178,7 @@ process_dir (char *dir, struct savewd *wd, void *options) if (ret == EXIT_SUCCESS && o->set_security_context && o->make_ancestor_function) { - if (! restorecon (last_component (dir), false, false) + if (! restorecon (o->set_security_context, last_component (dir), false) && ! ignorable_ctx_err (errno)) error (0, errno, _("failed to restore context for %s"), quoteaf (dir)); @@ -197,7 +199,7 @@ main (int argc, char **argv) options.mode = S_IRWXUGO; options.mode_bits = 0; options.created_directory_format = NULL; - options.set_security_context = false; + options.set_security_context = NULL; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -231,7 +233,12 @@ main (int argc, char **argv) if (optarg) scontext = optarg; else - options.set_security_context = true; + { + options.set_security_context = selabel_open (SELABEL_CTX_FILE, + NULL, 0); + if (! options.set_security_context) + error (0, errno, _("warning: ignoring --context")); + } } else if (optarg) { @@ -255,7 +262,7 @@ main (int argc, char **argv) /* FIXME: This assumes mkdir() is done in the same process. If that's not always the case we would need to call this - like we do when options.set_security_context == true. */ + like we do when options.set_security_context. */ if (scontext) { int ret = 0; diff --git a/src/mkfifo.c b/src/mkfifo.c index 9ec42144b..a28a9b84a 100644 --- a/src/mkfifo.c +++ b/src/mkfifo.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include "system.h" #include "die.h" @@ -81,7 +81,7 @@ main (int argc, char **argv) int exit_status = EXIT_SUCCESS; int optc; char const *scontext = NULL; - bool set_security_context = false; + struct selabel_handle *set_security_context = NULL; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -109,7 +109,12 @@ main (int argc, char **argv) if (optarg) scontext = optarg; else - set_security_context = true; + { + set_security_context = selabel_open (SELABEL_CTX_FILE, + NULL, 0); + if (! set_security_context) + error (0, errno, _("warning: ignoring --context")); + } } else if (optarg) { @@ -164,7 +169,7 @@ main (int argc, char **argv) for (; optind < argc; ++optind) { if (set_security_context) - defaultcon (argv[optind], S_IFIFO); + defaultcon (set_security_context, argv[optind], S_IFIFO); if (mkfifo (argv[optind], newmode) != 0) { error (0, errno, _("cannot create fifo %s"), quoteaf (argv[optind])); diff --git a/src/mknod.c b/src/mknod.c index 3f3f79acf..334a39769 100644 --- a/src/mknod.c +++ b/src/mknod.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include "system.h" #include "die.h" @@ -98,7 +98,7 @@ main (int argc, char **argv) size_t expected_operands; mode_t node_type; char const *scontext = NULL; - bool set_security_context = false; + struct selabel_handle *set_security_context = NULL; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -126,7 +126,12 @@ main (int argc, char **argv) if (optarg) scontext = optarg; else - set_security_context = true; + { + set_security_context = selabel_open (SELABEL_CTX_FILE, + NULL, 0); + if (! set_security_context) + error (0, errno, _("warning: ignoring --context")); + } } else if (optarg) { @@ -248,7 +253,7 @@ main (int argc, char **argv) #endif if (set_security_context) - defaultcon (argv[optind], node_type); + defaultcon (set_security_context, argv[optind], node_type); if (mknod (argv[optind], newmode | node_type, device) != 0) die (EXIT_FAILURE, errno, "%s", quotef (argv[optind])); @@ -257,7 +262,7 @@ main (int argc, char **argv) case 'p': /* 'pipe' */ if (set_security_context) - defaultcon (argv[optind], S_IFIFO); + defaultcon (set_security_context, argv[optind], S_IFIFO); if (mkfifo (argv[optind], newmode) != 0) die (EXIT_FAILURE, errno, "%s", quotef (argv[optind])); break; diff --git a/src/mv.c b/src/mv.c index b284dccca..21621af21 100644 --- a/src/mv.c +++ b/src/mv.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "system.h" #include "backupfile.h" @@ -125,7 +125,7 @@ cp_option_init (struct cp_options *x) x->preserve_timestamps = true; x->explicit_no_preserve_mode= false; x->preserve_security_context = selinux_enabled; - x->set_security_context = false; + x->set_security_context = NULL; x->reduce_diagnostics = false; x->data_copy_required = true; x->require_preserve = false; /* FIXME: maybe make this an option */ @@ -417,7 +417,10 @@ main (int argc, char **argv) if (selinux_enabled) { x.preserve_security_context = false; - x.set_security_context = true; + x.set_security_context = selabel_open (SELABEL_CTX_FILE, + NULL, 0); + if (! x.set_security_context) + error (0, errno, _("warning: ignoring --context")); } break; case_GETOPT_HELP_CHAR; diff --git a/src/selinux.c b/src/selinux.c index 874ad5b6d..10fa9d8c6 100644 --- a/src/selinux.c +++ b/src/selinux.c @@ -17,18 +17,15 @@ /* Written by Daniel Walsh */ #include -#include +#include #include #include -#include "die.h" -#include "error.h" #include "system.h" -#include "canonicalize.h" #include "xfts.h" #include "selinux.h" -#if HAVE_SELINUX_SELINUX_H +#if HAVE_SELINUX_LABEL_H # if ! HAVE_MODE_TO_SECURITY_CLASS /* @@ -98,16 +95,17 @@ quit: } /* - This function takes a path and a mode, it calls computecon to get the + This function takes a handle, path and mode, it calls computecon to get the label of the path object if the current process created it, then it calls - matchpathcon to get the default type for the object. It substitutes the + selabel_lookup to get the default type for the object. It substitutes the default type into label. It tells the SELinux Kernel to label all new file system objects created by the current process with this label. Returns -1 on failure. errno will be set appropriately. */ int -defaultcon (char const *path, mode_t mode) +defaultcon (struct selabel_handle *selabel_handle, + char const *path, mode_t mode) { int rc = -1; char *scon = NULL; @@ -115,20 +113,8 @@ defaultcon (char const *path, mode_t mode) context_t scontext = 0, tcontext = 0; const char *contype; char *constr; - char *newpath = NULL; - if (! IS_ABSOLUTE_FILE_NAME (path)) - { - /* Generate absolute path as required by subsequent matchpathcon(), - with libselinux < 2.1.5 2011-0826. */ - newpath = canonicalize_filename_mode (path, CAN_MISSING); - if (! newpath) - die (EXIT_FAILURE, errno, _("error canonicalizing %s"), - quoteaf (path)); - path = newpath; - } - - if (matchpathcon (path, mode, &scon) < 0) + if (selabel_lookup (selabel_handle, &scon, path, mode) < 0) { /* "No such file or directory" is a confusing error, when processing files, when in fact it was the @@ -160,25 +146,20 @@ quit: context_free (tcontext); freecon (scon); freecon (tcon); - free (newpath); return rc; } /* - This function takes a PATH of an existing file system object, and a LOCAL - boolean that indicates whether the function should set the object's label - to the default for the local process, or one using system wide settings. - If LOCAL == true, it will ask the SELinux Kernel what the default label - for all objects created should be and then sets the label on the object. - Otherwise it calls matchpathcon on the object to ask the system what the - default label should be, extracts the type field and then modifies the file + If SELABEL_HANDLE is null, set PATH's label to the default to the + local process. Otherwise use selabel_lookup to determine the + default label, extract the type field and then modify the file system object. Note only the type field is updated, thus preserving MLS levels and user identity etc. of the PATH. Returns -1 on failure. errno will be set appropriately. */ static int -restorecon_private (char const *path, bool local) +restorecon_private (struct selabel_handle *selabel_handle, char const *path) { int rc = -1; struct stat sb; @@ -189,7 +170,7 @@ restorecon_private (char const *path, bool local) char *constr; int fd; - if (local) + if (!selabel_handle) { if (getfscreatecon (&tcon) < 0) return rc; @@ -199,7 +180,9 @@ restorecon_private (char const *path, bool local) return rc; } rc = lsetfilecon (path, tcon); + int err = errno; freecon (tcon); + errno = err; return rc; } @@ -218,13 +201,13 @@ restorecon_private (char const *path, bool local) goto quit; } - if (matchpathcon (path, sb.st_mode, &scon) < 0) + if (selabel_lookup (selabel_handle, &scon, path, sb.st_mode) < 0) { /* "No such file or directory" is a confusing error, when processing files, when in fact it was the associated default context that was not found. Therefore map the error to something more appropriate - to the context in which we're using matchpathcon(). */ + to the context in which we're using selabel_lookup. */ if (errno == ENOENT) errno = ENODATA; goto quit; @@ -258,83 +241,51 @@ restorecon_private (char const *path, bool local) else rc = lsetfilecon (path, constr); -quit: + quit:; + int err = errno; if (fd != -1) close (fd); context_free (scontext); context_free (tcontext); freecon (scon); freecon (tcon); + errno = err; return rc; } /* This function takes three parameters: + SELABEL_HANDLE for selabel_lookup, or null to preserve. + PATH of an existing file system object. A RECURSE boolean which if the file system object is a directory, will call restorecon_private on every file system object in the directory. - A LOCAL boolean that indicates whether the function should set object labels - to the default for the local process, or use system wide settings. - - Returns false on failure. errno will be set appropriately. + Return false on failure. errno will be set appropriately. */ bool -restorecon (char const *path, bool recurse, bool local) +restorecon (struct selabel_handle *selabel_handle, + char const *path, bool recurse) { - char *newpath = NULL; - FTS *fts; - bool ok = true; - - if (! IS_ABSOLUTE_FILE_NAME (path) && ! local) - { - /* Generate absolute path as required by subsequent matchpathcon(), - with libselinux < 2.1.5 2011-0826. Also generating the absolute - path before the fts walk, will generate absolute paths in the - fts entries, which may be quicker to process in any case. */ - newpath = canonicalize_filename_mode (path, CAN_MISSING); - if (! newpath) - die (EXIT_FAILURE, errno, _("error canonicalizing %s"), - quoteaf (path)); - } - - const char *ftspath[2] = { newpath ? newpath : path, NULL }; - if (! recurse) - { - ok = restorecon_private (*ftspath, local) != -1; - free (newpath); - return ok; - } + return restorecon_private (selabel_handle, path) == 0; - fts = xfts_open ((char *const *) ftspath, FTS_PHYSICAL, NULL); - while (1) - { - FTSENT *ent; + char const *ftspath[2] = { path, NULL }; + FTS *fts = xfts_open ((char *const *) ftspath, FTS_PHYSICAL, NULL); - ent = fts_read (fts); - if (ent == NULL) - { - if (errno != 0) - { - error (0, errno, _("fts_read failed")); - ok = false; - } - break; - } + int err = 0; + for (FTSENT *ent; (ent = fts_read (fts)); ) + if (restorecon_private (selabel_handle, fts->fts_path) < 0) + err = errno; - ok &= restorecon_private (fts->fts_path, local) != -1; - } + if (errno != 0) + err = errno; if (fts_close (fts) != 0) - { - error (0, errno, _("fts_close failed")); - ok = false; - } + err = errno; - free (newpath); - return ok; + return !err; } #endif diff --git a/src/selinux.h b/src/selinux.h index c191c36da..e1c6b3a54 100644 --- a/src/selinux.h +++ b/src/selinux.h @@ -19,6 +19,8 @@ #ifndef COREUTILS_SELINUX_H # define COREUTILS_SELINUX_H +struct selabel_handle; + /* Return true if ERR corresponds to an unsupported request, or if there is no context or it's inaccessible. */ static inline bool @@ -27,21 +29,25 @@ ignorable_ctx_err (int err) return err == ENOTSUP || err == ENODATA; } -# if HAVE_SELINUX_SELINUX_H +# if HAVE_SELINUX_LABEL_H extern bool -restorecon (char const *path, bool recurse, bool preserve); +restorecon (struct selabel_handle *selabel_handle, + char const *path, bool recurse); extern int -defaultcon (char const *path, mode_t mode); +defaultcon (struct selabel_handle *selabel_handle, + char const *path, mode_t mode); # else static inline bool -restorecon (char const *path, bool recurse, bool preserve) +restorecon (struct selabel_handle *selabel_handle, + char const *path, bool recurse) { errno = ENOTSUP; return false; } static inline int -defaultcon (char const *path, mode_t mode) +defaultcon (struct selabel_handle *selabel_handle, + char const *path, mode_t mode) { errno = ENOTSUP; return -1; } # endif -- 2.27.0