1bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines/* 2bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines * The majority of this code is from Android's 3bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines * external/libselinux/src/android.c and upstream 4f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * selinux/policycoreutils/setfiles/restore.c 5bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines * 6bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines * See selinux_restorecon(3) for details. 7bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines */ 8bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 9bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <unistd.h> 10bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <string.h> 11bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <stdio.h> 12bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <stdlib.h> 13bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <stdbool.h> 14bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <ctype.h> 15bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <errno.h> 16bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <fcntl.h> 17bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <fts.h> 18bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <limits.h> 19f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines#include <stdint.h> 20bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <sys/types.h> 21bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <sys/stat.h> 22bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <sys/xattr.h> 23bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <sys/vfs.h> 24f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines#include <sys/statvfs.h> 25f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines#include <sys/utsname.h> 26bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <linux/magic.h> 27bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <libgen.h> 28f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines#include <syslog.h> 29f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines#include <assert.h> 30f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 31bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <selinux/selinux.h> 32bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <selinux/context.h> 33bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <selinux/label.h> 34bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include <selinux/restorecon.h> 35bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 36bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include "callbacks.h" 37bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#include "selinux_internal.h" 38bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 39bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#define RESTORECON_LAST "security.restorecon_last" 40bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 41bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#define SYS_PATH "/sys" 42bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines#define SYS_PREFIX SYS_PATH "/" 43bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 44454768f56d7a941657d800e303994bca086b7546Richard Haines#define STAR_COUNT 1024 45f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 46bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesstatic struct selabel_handle *fc_sehandle = NULL; 47bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesstatic unsigned char *fc_digest = NULL; 48bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesstatic size_t fc_digest_len = 0; 49f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic char *rootpath = NULL; 50f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic int rootpathlen; 51f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 52f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines/* Information on excluded fs and directories. */ 53f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstruct edir { 54f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines char *directory; 55f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines size_t size; 56f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* True if excluded by selinux_restorecon_set_exclude_list(3). */ 57f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines bool caller_excluded; 58f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines}; 59f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines#define CALLER_EXCLUDED true 60f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic bool ignore_mounts; 61f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic int exclude_non_seclabel_mounts(void); 62f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic int exclude_count = 0; 63f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic struct edir *exclude_lst = NULL; 64f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic uint64_t fc_count = 0; /* Number of files processed so far */ 65f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic uint64_t efile_count; /* Estimated total number of files */ 66f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 672d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines/* Store information on directories with xattr's. */ 682d814ff4c7798a26d29e1dd091e75043f1628561Richard Hainesstruct dir_xattr *dir_xattr_list; 692d814ff4c7798a26d29e1dd091e75043f1628561Richard Hainesstatic struct dir_xattr *dir_xattr_last; 702d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 71d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines/* restorecon_flags for passing to restorecon_sb() */ 72d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Hainesstruct rest_flags { 73d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines bool nochange; 74d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines bool verbose; 75d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines bool progress; 76454768f56d7a941657d800e303994bca086b7546Richard Haines bool mass_relabel; 77d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines bool set_specctx; 78d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines bool add_assoc; 79d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines bool ignore_digest; 80d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines bool recurse; 81d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines bool userealpath; 82d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines bool set_xdev; 83f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines bool abort_on_error; 84f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines bool syslog_changes; 85f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines bool log_matches; 86f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines bool ignore_noent; 871cd972fc81757d6157afa192da99473243dfce8bStephen Smalley bool warnonnomatch; 88d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines}; 89d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 90bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesstatic void restorecon_init(void) 91bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines{ 92bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines struct selabel_handle *sehandle = NULL; 93bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 94bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (!fc_sehandle) { 95bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines sehandle = selinux_restorecon_default_handle(); 96bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_restorecon_set_sehandle(sehandle); 97bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 98f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 99f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines efile_count = 0; 100f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (!ignore_mounts) 101f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines efile_count = exclude_non_seclabel_mounts(); 102bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines} 103bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 104bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesstatic pthread_once_t fc_once = PTHREAD_ONCE_INIT; 105bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 106f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines/* 107f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * Manage excluded directories: 108f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * remove_exclude() - This removes any conflicting entries as there could be 109f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * a case where a non-seclabel fs is mounted on /foo and 110f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * then a seclabel fs is mounted on top of it. 111f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * However if an entry has been added via 112f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * selinux_restorecon_set_exclude_list(3) do not remove. 113f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * 114f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * add_exclude() - Add a directory/fs to be excluded from labeling. If it 115f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * has already been added, then ignore. 116f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * 117f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * check_excluded() - Check if directory/fs is to be excluded when relabeling. 118f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * 119f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * file_system_count() - Calculates the the number of files to be processed. 120f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * The count is only used if SELINUX_RESTORECON_PROGRESS 121f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * is set and a mass relabel is requested. 122f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * 123f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * exclude_non_seclabel_mounts() - Reads /proc/mounts to determine what 124f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * non-seclabel mounts to exclude from 125f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * relabeling. restorecon_init() will not 126f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * call this function if the 127f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * SELINUX_RESTORECON_IGNORE_MOUNTS 128f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * flag is set. 129f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * Setting SELINUX_RESTORECON_IGNORE_MOUNTS 130f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * is useful where there is a non-seclabel fs 131f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * mounted on /foo and then a seclabel fs is 132f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * mounted on a directory below this. 133f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines */ 134f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic void remove_exclude(const char *directory) 135f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines{ 136f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines int i; 137f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 138f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines for (i = 0; i < exclude_count; i++) { 139f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (strcmp(directory, exclude_lst[i].directory) == 0 && 140f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines !exclude_lst[i].caller_excluded) { 141f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines free(exclude_lst[i].directory); 142f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (i != exclude_count - 1) 143f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines exclude_lst[i] = exclude_lst[exclude_count - 1]; 144f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines exclude_count--; 145f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return; 146f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 147f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 148f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines} 149f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 150f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic int add_exclude(const char *directory, bool who) 151f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines{ 152f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines struct edir *tmp_list, *current; 153f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines size_t len = 0; 154f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines int i; 155f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 156f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* Check if already present. */ 157f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines for (i = 0; i < exclude_count; i++) { 158f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (strcmp(directory, exclude_lst[i].directory) == 0) 159f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return 0; 160f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 161f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 162f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (directory == NULL || directory[0] != '/') { 163f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines selinux_log(SELINUX_ERROR, 164f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines "Full path required for exclude: %s.\n", 165f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines directory); 166f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines errno = EINVAL; 167f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return -1; 168f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 169f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 170f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines tmp_list = realloc(exclude_lst, 171f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines sizeof(struct edir) * (exclude_count + 1)); 172f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (!tmp_list) 173f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines goto oom; 174f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 175f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines exclude_lst = tmp_list; 176f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 177f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines len = strlen(directory); 178f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines while (len > 1 && directory[len - 1] == '/') 179f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines len--; 180f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 181f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines current = (exclude_lst + exclude_count); 182f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 183f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines current->directory = strndup(directory, len); 184f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (!current->directory) 185f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines goto oom; 186f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 187f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines current->size = len; 188f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines current->caller_excluded = who; 189f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines exclude_count++; 190f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return 0; 191f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 192f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesoom: 193f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); 194f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return -1; 195f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines} 196bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 197bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesstatic int check_excluded(const char *file) 198bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines{ 199bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines int i; 200bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 201f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines for (i = 0; i < exclude_count; i++) { 202f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (strncmp(file, exclude_lst[i].directory, 203f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines exclude_lst[i].size) == 0) { 204f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (file[exclude_lst[i].size] == 0 || 205f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines file[exclude_lst[i].size] == '/') 206bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines return 1; 207f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 208bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 209bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines return 0; 210bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines} 211bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 212f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic int file_system_count(char *name) 213f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines{ 214f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines struct statvfs statvfs_buf; 215f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines int nfile = 0; 216f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 217f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines memset(&statvfs_buf, 0, sizeof(statvfs_buf)); 218f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (!statvfs(name, &statvfs_buf)) 219f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines nfile = statvfs_buf.f_files - statvfs_buf.f_ffree; 220f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 221f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return nfile; 222f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines} 223f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 224d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines/* 225f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * This is called once when selinux_restorecon() is first called. 226f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * Searches /proc/mounts for all file systems that do not support extended 227f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * attributes and adds them to the exclude directory table. File systems 228f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * that support security labels have the seclabel option, return 229f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * approximate total file count. 230f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines */ 231f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesstatic int exclude_non_seclabel_mounts(void) 232f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines{ 233f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines struct utsname uts; 234f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines FILE *fp; 235f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines size_t len; 236f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines ssize_t num; 237f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines int index = 0, found = 0, nfile = 0; 238f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines char *mount_info[4]; 239f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines char *buf = NULL, *item; 240f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 241f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* Check to see if the kernel supports seclabel */ 242f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0) 243f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return 0; 244f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 24564afa1aff1cd610d2493f780e2a44b551f668b84Nick Kralevich fp = fopen("/proc/mounts", "re"); 246f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (!fp) 247f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return 0; 248f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 249f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines while ((num = getline(&buf, &len, fp)) != -1) { 250f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines found = 0; 251f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines index = 0; 252f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines item = strtok(buf, " "); 253f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines while (item != NULL) { 254f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines mount_info[index] = item; 255f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines index++; 2569d3091a6d3f1c4e40b67716aca740031699150a2Nicolas Iooss if (index == 4) 2579d3091a6d3f1c4e40b67716aca740031699150a2Nicolas Iooss break; 258f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines item = strtok(NULL, " "); 259f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 2609d3091a6d3f1c4e40b67716aca740031699150a2Nicolas Iooss if (index < 4) { 261f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines selinux_log(SELINUX_ERROR, 262f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines "/proc/mounts record \"%s\" has incorrect format.\n", 263f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines buf); 264f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines continue; 265f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 266f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 267f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* Remove pre-existing entry */ 268f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines remove_exclude(mount_info[1]); 269f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 270f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines item = strtok(mount_info[3], ","); 271f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines while (item != NULL) { 272f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (strcmp(item, "seclabel") == 0) { 273f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines found = 1; 274f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines nfile += file_system_count(mount_info[1]); 275f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines break; 276f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 277f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines item = strtok(NULL, ","); 278f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 279f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 280f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* Exclude mount points without the seclabel option */ 281f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (!found) { 282f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (add_exclude(mount_info[1], !CALLER_EXCLUDED) && 283f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines errno == ENOMEM) 284f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines assert(0); 285f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 286f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 287f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 288f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines free(buf); 289f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines fclose(fp); 290f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* return estimated #Files + 5% for directories and hard links */ 291f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return nfile * 1.05; 292f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines} 293f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 2942d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines/* Called by selinux_restorecon_xattr(3) to build a linked list of entries. */ 2952d814ff4c7798a26d29e1dd091e75043f1628561Richard Hainesstatic int add_xattr_entry(const char *directory, bool delete_nonmatch, 2962d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines bool delete_all) 2972d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines{ 2982d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines char *sha1_buf = NULL; 2992d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines unsigned char *xattr_value = NULL; 3002d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines ssize_t xattr_size; 3012d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines size_t i; 3022d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines int rc, digest_result; 3032d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines struct dir_xattr *new_entry; 3042d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3052d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (!directory) { 3062d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines errno = EINVAL; 3072d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return -1; 3082d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 3092d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3102d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines xattr_value = malloc(fc_digest_len); 3112d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (!xattr_value) 3122d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines goto oom; 3132d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3142d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines xattr_size = getxattr(directory, RESTORECON_LAST, xattr_value, 3152d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines fc_digest_len); 3162d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (xattr_size < 0) { 3172d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines free(xattr_value); 3182d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return 1; 3192d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 3202d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3212d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines /* Convert entry to a hex encoded string. */ 3222d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines sha1_buf = malloc(xattr_size * 2 + 1); 3232d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (!sha1_buf) { 3242d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines free(xattr_value); 3252d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines goto oom; 3262d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 3272d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3282d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines for (i = 0; i < (size_t)xattr_size; i++) 3292d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines sprintf((&sha1_buf[i * 2]), "%02x", xattr_value[i]); 3302d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3312d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines rc = memcmp(fc_digest, xattr_value, fc_digest_len); 3322d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines digest_result = rc ? NOMATCH : MATCH; 3332d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3342d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if ((delete_nonmatch && rc != 0) || delete_all) { 3352d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines digest_result = rc ? DELETED_NOMATCH : DELETED_MATCH; 3362d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines rc = removexattr(directory, RESTORECON_LAST); 3372d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (rc) { 3382d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines selinux_log(SELINUX_ERROR, 3392d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines "Error: %s removing xattr \"%s\" from: %s\n", 3402d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines strerror(errno), RESTORECON_LAST, directory); 3412d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines digest_result = ERROR; 3422d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 3432d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 3442d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines free(xattr_value); 3452d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3462d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines /* Now add entries to link list. */ 3472d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines new_entry = malloc(sizeof(struct dir_xattr)); 3482d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (!new_entry) 3492d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines goto oom; 3502d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines new_entry->next = NULL; 3512d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3522d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines new_entry->directory = strdup(directory); 3532d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (!new_entry->directory) 3542d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines goto oom; 3552d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3562d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines new_entry->digest = strdup(sha1_buf); 3572d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (!new_entry->digest) 3582d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines goto oom; 3592d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3602d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines new_entry->result = digest_result; 3612d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3622d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (!dir_xattr_list) { 3632d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines dir_xattr_list = new_entry; 3642d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines dir_xattr_last = new_entry; 3652d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } else { 3662d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines dir_xattr_last->next = new_entry; 3672d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines dir_xattr_last = new_entry; 3682d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 3692d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3702d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines free(sha1_buf); 3712d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return 0; 3722d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 3732d814ff4c7798a26d29e1dd091e75043f1628561Richard Hainesoom: 3742d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); 3752d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return -1; 3762d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines} 3772d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 378f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines/* 379f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * Support filespec services filespec_add(), filespec_eval() and 380f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * filespec_destroy(). 381f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * 382f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * selinux_restorecon(3) uses filespec services when the 383f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * SELINUX_RESTORECON_ADD_ASSOC flag is set for adding associations between 384f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * an inode and a specification. 385d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines */ 386d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 387d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines/* 388d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * The hash table of associations, hashed by inode number. Chaining is used 389d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * for collisions, with elements ordered by inode number in each bucket. 390d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * Each hash bucket has a dummy header. 391d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines */ 392d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines#define HASH_BITS 16 393d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines#define HASH_BUCKETS (1 << HASH_BITS) 394d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines#define HASH_MASK (HASH_BUCKETS-1) 395d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 396d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines/* 397d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * An association between an inode and a context. 398d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines */ 399d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Hainestypedef struct file_spec { 400d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines ino_t ino; /* inode number */ 401d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines char *con; /* matched context */ 402d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines char *file; /* full pathname */ 403d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines struct file_spec *next; /* next association in hash bucket chain */ 404d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines} file_spec_t; 405d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 406d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Hainesstatic file_spec_t *fl_head; 407d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 408d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines/* 409d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * Try to add an association between an inode and a context. If there is a 410d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * different context that matched the inode, then use the first context 411d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * that matched. 412d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines */ 413d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Hainesstatic int filespec_add(ino_t ino, const char *con, const char *file) 414d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines{ 415d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines file_spec_t *prevfl, *fl; 416d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines int h, ret; 417d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines struct stat64 sb; 418d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 419d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!fl_head) { 420d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS); 421d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!fl_head) 422d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines goto oom; 423d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS); 424d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines } 425d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 426d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines h = (ino + (ino >> HASH_BITS)) & HASH_MASK; 427d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines for (prevfl = &fl_head[h], fl = fl_head[h].next; fl; 428d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines prevfl = fl, fl = fl->next) { 429d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (ino == fl->ino) { 430d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines ret = lstat64(fl->file, &sb); 431d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (ret < 0 || sb.st_ino != ino) { 432d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines freecon(fl->con); 433d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines free(fl->file); 434d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl->file = strdup(file); 435d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!fl->file) 436d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines goto oom; 437d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl->con = strdup(con); 438d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!fl->con) 439d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines goto oom; 440d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines return 1; 441d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines } 442d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 443d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (strcmp(fl->con, con) == 0) 444d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines return 1; 445d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 446d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines selinux_log(SELINUX_ERROR, 447d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines "conflicting specifications for %s and %s, using %s.\n", 448d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines file, fl->file, fl->con); 449d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines free(fl->file); 450d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl->file = strdup(file); 451d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!fl->file) 452d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines goto oom; 453d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines return 1; 454d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines } 455d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 456d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (ino > fl->ino) 457d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines break; 458d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines } 459d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 460d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl = malloc(sizeof(file_spec_t)); 461d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!fl) 462d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines goto oom; 463d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl->ino = ino; 464d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl->con = strdup(con); 465d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!fl->con) 466d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines goto oom_freefl; 467d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl->file = strdup(file); 468d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!fl->file) 469d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines goto oom_freefl; 470d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl->next = prevfl->next; 471d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines prevfl->next = fl; 472d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines return 0; 473d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 474d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Hainesoom_freefl: 475d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines free(fl); 476d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Hainesoom: 477d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); 478d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines return -1; 479d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines} 480d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 481d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines/* 482d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * Evaluate the association hash table distribution. 483d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines */ 484b88c4a4707c942028d7d0035bba9057fa031e83bStephen Smalley#ifdef DEBUG 485d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Hainesstatic void filespec_eval(void) 486d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines{ 487d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines file_spec_t *fl; 488d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines int h, used, nel, len, longest; 489d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 490d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!fl_head) 491d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines return; 492d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 493d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines used = 0; 494d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines longest = 0; 495d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines nel = 0; 496d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines for (h = 0; h < HASH_BUCKETS; h++) { 497d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines len = 0; 498d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines for (fl = fl_head[h].next; fl; fl = fl->next) 499d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines len++; 500d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (len) 501d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines used++; 502d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (len > longest) 503d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines longest = len; 504d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines nel += len; 505d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines } 506d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 507d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines selinux_log(SELINUX_INFO, 508d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines "filespec hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n", 509d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines nel, used, HASH_BUCKETS, longest); 510d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines} 511b88c4a4707c942028d7d0035bba9057fa031e83bStephen Smalley#else 512b88c4a4707c942028d7d0035bba9057fa031e83bStephen Smalleystatic void filespec_eval(void) 513b88c4a4707c942028d7d0035bba9057fa031e83bStephen Smalley{ 514b88c4a4707c942028d7d0035bba9057fa031e83bStephen Smalley} 515b88c4a4707c942028d7d0035bba9057fa031e83bStephen Smalley#endif 516d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 517d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines/* 518d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * Destroy the association hash table. 519d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines */ 520d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Hainesstatic void filespec_destroy(void) 521d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines{ 522d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines file_spec_t *fl, *tmp; 523d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines int h; 524d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 525d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!fl_head) 526d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines return; 527d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 528d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines for (h = 0; h < HASH_BUCKETS; h++) { 529d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl = fl_head[h].next; 530d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines while (fl) { 531d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines tmp = fl; 532d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl = fl->next; 533d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines freecon(tmp->con); 534d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines free(tmp->file); 535d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines free(tmp); 536d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines } 537d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl_head[h].next = NULL; 538d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines } 539d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines free(fl_head); 540d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines fl_head = NULL; 541d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines} 542d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 543d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines/* 544d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * Called if SELINUX_RESTORECON_SET_SPECFILE_CTX is not set to check if 545d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * the type components differ, updating newtypecon if so. 546d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines */ 547bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesstatic int compare_types(char *curcon, char *newcon, char **newtypecon) 548bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines{ 549bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines int types_differ = 0; 550bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines context_t cona; 551bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines context_t conb; 552bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines int rc = 0; 553bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 554bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines cona = context_new(curcon); 555bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (!cona) { 556bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines rc = -1; 557bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto out; 558bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 559bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines conb = context_new(newcon); 560bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (!conb) { 561bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines context_free(cona); 562bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines rc = -1; 563bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto out; 564bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 565bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 566bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines types_differ = strcmp(context_type_get(cona), context_type_get(conb)); 567bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (types_differ) { 568bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines rc |= context_user_set(conb, context_user_get(cona)); 569bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines rc |= context_role_set(conb, context_role_get(cona)); 570bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines rc |= context_range_set(conb, context_range_get(cona)); 571bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (!rc) { 572bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines *newtypecon = strdup(context_str(conb)); 573bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (!*newtypecon) { 574bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines rc = -1; 575bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto err; 576bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 577bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 578bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 579bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 580bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haineserr: 581bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines context_free(cona); 582bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines context_free(conb); 583bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesout: 584bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines return rc; 585bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines} 586bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 587bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesstatic int restorecon_sb(const char *pathname, const struct stat *sb, 588d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines struct rest_flags *flags) 589bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines{ 590bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines char *newcon = NULL; 591bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines char *curcon = NULL; 592bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines char *newtypecon = NULL; 593f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines int rc; 594bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines bool updated = false; 595f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines const char *lookup_path = pathname; 596f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines float pc; 597f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 598f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (rootpath) { 599f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (strncmp(rootpath, lookup_path, rootpathlen) != 0) { 600f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines selinux_log(SELINUX_ERROR, 601f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines "%s is not located in alt_rootpath %s\n", 602f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines lookup_path, rootpath); 603f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return -1; 604f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 605f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines lookup_path += rootpathlen; 606f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 607f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 608f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (rootpath != NULL && lookup_path[0] == '\0') 609f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* this is actually the root dir of the alt root. */ 610f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines rc = selabel_lookup_raw(fc_sehandle, &newcon, "/", 611f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines sb->st_mode); 612f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines else 613f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path, 614f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines sb->st_mode); 615f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 616f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (rc < 0) { 6171cd972fc81757d6157afa192da99473243dfce8bStephen Smalley if (errno == ENOENT && flags->warnonnomatch) 618f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines selinux_log(SELINUX_INFO, 619f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines "Warning no default label for %s\n", 620f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines lookup_path); 621bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 622bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines return 0; /* no match, but not an error */ 623f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 624f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 625f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (flags->progress) { 626f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines fc_count++; 627f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (fc_count % STAR_COUNT == 0) { 628454768f56d7a941657d800e303994bca086b7546Richard Haines if (flags->mass_relabel && efile_count > 0) { 629f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines pc = (fc_count < efile_count) ? (100.0 * 630f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines fc_count / efile_count) : 100; 631f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines fprintf(stdout, "\r%-.1f%%", (double)pc); 632f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } else { 633454768f56d7a941657d800e303994bca086b7546Richard Haines fprintf(stdout, "\r%luk", fc_count / STAR_COUNT); 634f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 635454768f56d7a941657d800e303994bca086b7546Richard Haines fflush(stdout); 636f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 637f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 638bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 639d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (flags->add_assoc) { 640d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines rc = filespec_add(sb->st_ino, newcon, pathname); 641d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 642d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (rc < 0) { 643d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines selinux_log(SELINUX_ERROR, 644d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines "filespec_add error: %s\n", pathname); 645d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines freecon(newcon); 646d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines return -1; 647d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines } 648d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 649d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (rc > 0) { 650d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines /* Already an association and it took precedence. */ 651d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines freecon(newcon); 652d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines return 0; 653d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines } 654d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines } 655d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 656f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (flags->log_matches) 657f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines selinux_log(SELINUX_INFO, "%s matched by %s\n", 658f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines pathname, newcon); 659f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 660bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (lgetfilecon_raw(pathname, &curcon) < 0) { 661bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (errno != ENODATA) 662bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto err; 663bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 664bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines curcon = NULL; 665bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 666bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 667a9094fae2c7bcd14af7263f9bb7fbacff5bc761cNicolas Iooss if (curcon == NULL || strcmp(curcon, newcon) != 0) { 668d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!flags->set_specctx && curcon && 669bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines (is_context_customizable(curcon) > 0)) { 670d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (flags->verbose) { 671bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_INFO, 672bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines "%s not reset as customized by admin to %s\n", 673bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines pathname, curcon); 674bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto out; 675bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 676bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 677bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 678d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!flags->set_specctx && curcon) { 679bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines /* If types different then update newcon. */ 680bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines rc = compare_types(curcon, newcon, &newtypecon); 681bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (rc) 682bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto err; 683bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 684bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (newtypecon) { 685bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines freecon(newcon); 686bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines newcon = newtypecon; 687bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } else { 688bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto out; 689bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 690bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 691bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 692d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!flags->nochange) { 693bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (lsetfilecon(pathname, newcon) < 0) 694bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto err; 695bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines updated = true; 696bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 697bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 698d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (flags->verbose) 699bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_INFO, 700bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines "%s %s from %s to %s\n", 701bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines updated ? "Relabeled" : "Would relabel", 702bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines pathname, curcon, newcon); 703f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 704f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (flags->syslog_changes && !flags->nochange) { 705f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (curcon) 706f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines syslog(LOG_INFO, 707f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines "relabeling %s from %s to %s\n", 708f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines pathname, curcon, newcon); 709f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines else 710f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines syslog(LOG_INFO, "labeling %s to %s\n", 711f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines pathname, newcon); 712f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 713bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 714bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 715bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesout: 716bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines rc = 0; 717bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesout1: 718bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines freecon(curcon); 719bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines freecon(newcon); 720bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines return rc; 721bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haineserr: 722bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_ERROR, 723bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines "Could not set context for %s: %s\n", 724bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines pathname, strerror(errno)); 725bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines rc = -1; 726bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto out1; 727bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines} 728bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 729bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines/* 730bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines * Public API 731bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines */ 732bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 733bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines/* selinux_restorecon(3) - Main function that is responsible for labeling */ 734bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesint selinux_restorecon(const char *pathname_orig, 735bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines unsigned int restorecon_flags) 736bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines{ 737d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines struct rest_flags flags; 738d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 739d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines flags.ignore_digest = (restorecon_flags & 740bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines SELINUX_RESTORECON_IGNORE_DIGEST) ? true : false; 741d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines flags.nochange = (restorecon_flags & 742bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines SELINUX_RESTORECON_NOCHANGE) ? true : false; 743d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines flags.verbose = (restorecon_flags & 744bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines SELINUX_RESTORECON_VERBOSE) ? true : false; 745d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines flags.progress = (restorecon_flags & 746bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines SELINUX_RESTORECON_PROGRESS) ? true : false; 747454768f56d7a941657d800e303994bca086b7546Richard Haines flags.mass_relabel = (restorecon_flags & 748454768f56d7a941657d800e303994bca086b7546Richard Haines SELINUX_RESTORECON_MASS_RELABEL) ? true : false; 749d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines flags.recurse = (restorecon_flags & 750bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines SELINUX_RESTORECON_RECURSE) ? true : false; 751d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines flags.set_specctx = (restorecon_flags & 752bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false; 753d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines flags.userealpath = (restorecon_flags & 754bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines SELINUX_RESTORECON_REALPATH) ? true : false; 755d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines flags.set_xdev = (restorecon_flags & 756bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines SELINUX_RESTORECON_XDEV) ? true : false; 757d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines flags.add_assoc = (restorecon_flags & 758d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines SELINUX_RESTORECON_ADD_ASSOC) ? true : false; 759f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines flags.abort_on_error = (restorecon_flags & 760f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines SELINUX_RESTORECON_ABORT_ON_ERROR) ? true : false; 761f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines flags.syslog_changes = (restorecon_flags & 762f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines SELINUX_RESTORECON_SYSLOG_CHANGES) ? true : false; 763f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines flags.log_matches = (restorecon_flags & 764f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines SELINUX_RESTORECON_LOG_MATCHES) ? true : false; 765f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines flags.ignore_noent = (restorecon_flags & 766f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines SELINUX_RESTORECON_IGNORE_NOENTRY) ? true : false; 7671cd972fc81757d6157afa192da99473243dfce8bStephen Smalley flags.warnonnomatch = true; 768f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines ignore_mounts = (restorecon_flags & 769f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines SELINUX_RESTORECON_IGNORE_MOUNTS) ? true : false; 770d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 771bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines bool issys; 772bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines bool setrestoreconlast = true; /* TRUE = set xattr RESTORECON_LAST 773bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines * FALSE = don't use xattr */ 774bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines struct stat sb; 775bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines struct statfs sfsb; 776bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines FTS *fts; 777bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines FTSENT *ftsent; 778bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname; 779f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines char *paths[2] = { NULL, NULL }; 780f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines int fts_flags, error, sverrno; 781bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines char *xattr_value = NULL; 782bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines ssize_t size; 783f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines dev_t dev_num = 0; 784bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 785d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (flags.verbose && flags.progress) 786d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines flags.verbose = false; 787bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 788bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines __selinux_once(fc_once, restorecon_init); 789bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 790bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (!fc_sehandle) 791bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines return -1; 792bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 793bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (fc_digest_len) { 794bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines xattr_value = malloc(fc_digest_len); 795bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (!xattr_value) 796bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines return -1; 797bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 798bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 799bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines /* 800bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines * Convert passed-in pathname to canonical pathname by resolving 801bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines * realpath of containing dir, then appending last component name. 802bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines */ 803d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (flags.userealpath) { 804aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley char *basename_cpy = strdup(pathname_orig); 805aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley if (!basename_cpy) 806aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley goto realpatherr; 807aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley pathbname = basename(basename_cpy); 808bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") || 809bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines !strcmp(pathbname, "..")) { 810bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines pathname = realpath(pathname_orig, NULL); 811aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley if (!pathname) { 812aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley free(basename_cpy); 813bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto realpatherr; 814aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley } 815bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } else { 816aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley char *dirname_cpy = strdup(pathname_orig); 817aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley if (!dirname_cpy) { 818aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley free(basename_cpy); 819aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley goto realpatherr; 820aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley } 821aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley pathdname = dirname(dirname_cpy); 822bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines pathdnamer = realpath(pathdname, NULL); 823aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley free(dirname_cpy); 824aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley if (!pathdnamer) { 825aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley free(basename_cpy); 826bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto realpatherr; 827aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley } 828bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (!strcmp(pathdnamer, "/")) 829bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines error = asprintf(&pathname, "/%s", pathbname); 830bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines else 831bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines error = asprintf(&pathname, "%s/%s", 832bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines pathdnamer, pathbname); 833aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley if (error < 0) { 834aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley free(basename_cpy); 835bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto oom; 836aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley } 837bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 838aa0c824bb2eeb8960ba02133faade72c837ea951Stephen Smalley free(basename_cpy); 839bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } else { 840bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines pathname = strdup(pathname_orig); 841bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (!pathname) 842bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto oom; 843bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 844bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 845bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines paths[0] = pathname; 846bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines issys = (!strcmp(pathname, SYS_PATH) || 847bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines !strncmp(pathname, SYS_PREFIX, 848bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines sizeof(SYS_PREFIX) - 1)) ? true : false; 849bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 850bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (lstat(pathname, &sb) < 0) { 851f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (flags.ignore_noent && errno == ENOENT) { 852f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines free(pathdnamer); 853f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines free(pathname); 854f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return 0; 855f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } else { 856f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines selinux_log(SELINUX_ERROR, 857f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines "lstat(%s) failed: %s\n", 858f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines pathname, strerror(errno)); 859f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines error = -1; 860f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines goto cleanup; 861f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 862bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 863bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 864bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines /* Ignore restoreconlast if not a directory */ 865bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if ((sb.st_mode & S_IFDIR) != S_IFDIR) 866bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines setrestoreconlast = false; 867bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 868d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!flags.recurse) { 869f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (check_excluded(pathname)) { 870f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines error = 0; 871f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines goto cleanup; 872f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 873f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 874d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines error = restorecon_sb(pathname, &sb, &flags); 875bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto cleanup; 876bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 877bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 878bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines /* Ignore restoreconlast on /sys */ 879bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (issys) 880bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines setrestoreconlast = false; 881bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 882bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines /* Ignore restoreconlast on in-memory filesystems */ 883bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (statfs(pathname, &sfsb) == 0) { 884bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC) 885bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines setrestoreconlast = false; 886bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 887bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 888bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (setrestoreconlast) { 889bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines size = getxattr(pathname, RESTORECON_LAST, xattr_value, 890bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fc_digest_len); 891bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 8928647a6c6214be2e6b87526c5755480b5bb3452fdNicolas Iooss if (!flags.ignore_digest && (size_t)size == fc_digest_len && 893bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines memcmp(fc_digest, xattr_value, fc_digest_len) 894bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines == 0) { 895bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_INFO, 896bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines "Skipping restorecon as matching digest on: %s\n", 897bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines pathname); 898bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines error = 0; 899bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto cleanup; 900bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 901bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 902bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 903d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (flags.set_xdev) 904bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fts_flags = FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV; 905bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines else 906bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fts_flags = FTS_PHYSICAL | FTS_NOCHDIR; 907bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 908bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fts = fts_open(paths, fts_flags, NULL); 909f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (!fts) 910f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines goto fts_err; 911f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 912f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines ftsent = fts_read(fts); 913f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (!ftsent) 914f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines goto fts_err; 915f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 916f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* 917f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * Keep the inode of the first device. This is because the FTS_XDEV 918f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * flag tells fts not to descend into directories with different 919f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * device numbers, but fts will still give back the actual directory. 920f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * By saving the device number of the directory that was passed to 921f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * selinux_restorecon() and then skipping all actions on any 922f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * directories with a different device number when the FTS_XDEV flag 923f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * is set (from http://marc.info/?l=selinux&m=124688830500777&w=2). 924f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines */ 925f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines dev_num = ftsent->fts_statp->st_dev; 926bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 927bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines error = 0; 928f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines do { 929f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* If the FTS_XDEV flag is set and the device is different */ 930f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (flags.set_xdev && ftsent->fts_statp->st_dev != dev_num) 931f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines continue; 932f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 933bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines switch (ftsent->fts_info) { 934bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines case FTS_DC: 935bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_ERROR, 936bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines "Directory cycle on %s.\n", 937bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines ftsent->fts_path); 938bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines errno = ELOOP; 939bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines error = -1; 940bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto out; 941bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines case FTS_DP: 942bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines continue; 943bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines case FTS_DNR: 944bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_ERROR, 945bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines "Could not read %s: %s.\n", 946bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines ftsent->fts_path, 947bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines strerror(ftsent->fts_errno)); 948bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fts_set(fts, ftsent, FTS_SKIP); 949bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines continue; 950bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines case FTS_NS: 951bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_ERROR, 952bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines "Could not stat %s: %s.\n", 953bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines ftsent->fts_path, 954bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines strerror(ftsent->fts_errno)); 955bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fts_set(fts, ftsent, FTS_SKIP); 956bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines continue; 957bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines case FTS_ERR: 958bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_ERROR, 959bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines "Error on %s: %s.\n", 960bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines ftsent->fts_path, 961bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines strerror(ftsent->fts_errno)); 962bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fts_set(fts, ftsent, FTS_SKIP); 963bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines continue; 964bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines case FTS_D: 965bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (issys && !selabel_partial_match(fc_sehandle, 966bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines ftsent->fts_path)) { 967bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fts_set(fts, ftsent, FTS_SKIP); 968bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines continue; 969bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 970f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 971f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (check_excluded(ftsent->fts_path)) { 972f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines fts_set(fts, ftsent, FTS_SKIP); 973f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines continue; 974f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 975bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines /* fall through */ 976bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines default: 977bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines error |= restorecon_sb(ftsent->fts_path, 978d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines ftsent->fts_statp, &flags); 9791cd972fc81757d6157afa192da99473243dfce8bStephen Smalley if (flags.warnonnomatch) 9801cd972fc81757d6157afa192da99473243dfce8bStephen Smalley flags.warnonnomatch = false; 981f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (error && flags.abort_on_error) 982f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines goto out; 983bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines break; 984bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 985f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } while ((ftsent = fts_read(fts)) != NULL); 986bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 987bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines /* Labeling successful. Mark the top level directory as completed. */ 988f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (setrestoreconlast && !flags.nochange && !error && fc_digest) { 989bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines error = setxattr(pathname, RESTORECON_LAST, fc_digest, 990bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fc_digest_len, 0); 991d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (!error && flags.verbose) 992bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_INFO, 993bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines "Updated digest for: %s\n", pathname); 994bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 995bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 996bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesout: 997454768f56d7a941657d800e303994bca086b7546Richard Haines if (flags.progress && flags.mass_relabel) 998454768f56d7a941657d800e303994bca086b7546Richard Haines fprintf(stdout, "\r%s 100.0%%\n", pathname); 999f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 1000bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines sverrno = errno; 1001bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines (void) fts_close(fts); 1002bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines errno = sverrno; 1003bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainescleanup: 1004d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (flags.add_assoc) { 1005d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines if (flags.verbose) 1006d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines filespec_eval(); 1007d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines filespec_destroy(); 1008d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines } 1009bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines free(pathdnamer); 1010bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines free(pathname); 1011bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines free(xattr_value); 1012bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines return error; 1013d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 1014bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesoom: 1015bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines sverrno = errno; 1016bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); 1017bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines errno = sverrno; 1018bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines error = -1; 1019bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto cleanup; 1020d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines 1021bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesrealpatherr: 1022bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines sverrno = errno; 1023bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_ERROR, 1024bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines "SELinux: Could not get canonical path for %s restorecon: %s.\n", 1025bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines pathname_orig, strerror(errno)); 1026bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines errno = sverrno; 1027bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines error = -1; 1028bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines goto cleanup; 1029f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 1030f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesfts_err: 1031f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines selinux_log(SELINUX_ERROR, 1032f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines "fts error while labeling %s: %s\n", 1033f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines paths[0], strerror(errno)); 1034f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines error = -1; 1035f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines goto cleanup; 1036bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines} 1037bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 1038bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines/* selinux_restorecon_set_sehandle(3) is called to set the global fc handle */ 1039bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesvoid selinux_restorecon_set_sehandle(struct selabel_handle *hndl) 1040bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines{ 1041f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines char **specfiles; 1042f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines size_t num_specfiles; 1043bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 1044bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fc_sehandle = (struct selabel_handle *) hndl; 1045bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 1046f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* 1047f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * Read digest if requested in selabel_open(3) and set global params. 1048f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines */ 1049f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (selabel_digest(fc_sehandle, &fc_digest, &fc_digest_len, 1050bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines &specfiles, &num_specfiles) < 0) { 1051bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fc_digest = NULL; 1052bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines fc_digest_len = 0; 1053bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 1054bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines} 1055bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 1056d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines/* 1057d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * selinux_restorecon_default_handle(3) is called to set the global restorecon 1058d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines * handle by a process if the default params are required. 1059d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines */ 1060bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesstruct selabel_handle *selinux_restorecon_default_handle(void) 1061bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines{ 1062bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines struct selabel_handle *sehandle; 1063bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 1064bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines struct selinux_opt fc_opts[] = { 1065bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines { SELABEL_OPT_DIGEST, (char *)1 } 1066bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines }; 1067bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 1068bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines sehandle = selabel_open(SELABEL_CTX_FILE, fc_opts, 1); 1069bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 1070bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines if (!sehandle) { 1071bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines selinux_log(SELINUX_ERROR, 1072bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines "Error obtaining file context handle: %s\n", 1073bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines strerror(errno)); 1074bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines return NULL; 1075bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines } 1076bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 1077bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines return sehandle; 1078bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines} 1079bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines 1080d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines/* 1081f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * selinux_restorecon_set_exclude_list(3) is called to add additional entries 1082f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines * to be excluded from labeling checks. 1083d4a46eec3fb271ccb442b876617361f5885d8d7aRichard Haines */ 1084bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Hainesvoid selinux_restorecon_set_exclude_list(const char **exclude_list) 1085bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines{ 1086f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines int i; 1087f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines struct stat sb; 1088f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 1089f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines for (i = 0; exclude_list[i]; i++) { 1090f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (lstat(exclude_list[i], &sb) < 0 && errno != EACCES) { 1091f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines selinux_log(SELINUX_ERROR, 1092f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines "lstat error on exclude path \"%s\", %s - ignoring.\n", 1093f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines exclude_list[i], strerror(errno)); 1094f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines break; 1095f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 1096f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (add_exclude(exclude_list[i], CALLER_EXCLUDED) && 1097f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines errno == ENOMEM) 1098f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines assert(0); 1099f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 1100f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines} 1101f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 1102f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines/* selinux_restorecon_set_alt_rootpath(3) sets an alternate rootpath. */ 1103f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Hainesint selinux_restorecon_set_alt_rootpath(const char *alt_rootpath) 1104f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines{ 1105f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines int len; 1106f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 1107f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* This should be NULL on first use */ 1108f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (rootpath) 1109f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines free(rootpath); 1110f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 1111f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines rootpath = strdup(alt_rootpath); 1112f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines if (!rootpath) { 1113f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__); 1114f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return -1; 1115f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines } 1116f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 1117f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines /* trim trailing /, if present */ 1118f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines len = strlen(rootpath); 1119f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines while (len && (rootpath[len - 1] == '/')) 1120f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines rootpath[--len] = '\0'; 1121f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines rootpathlen = len; 1122f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines 1123f2e77865e144ab2e1313aa78d99b969f8f48695eRichard Haines return 0; 1124bdd4e6d2b1bf8b7897be87056326f0dca18c1b94Richard Haines} 11252d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11262d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines/* selinux_restorecon_xattr(3) - Find RESTORECON_LAST entries. */ 11272d814ff4c7798a26d29e1dd091e75043f1628561Richard Hainesint selinux_restorecon_xattr(const char *pathname, unsigned int xattr_flags, 11282d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines struct dir_xattr ***xattr_list) 11292d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines{ 11302d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines bool recurse = (xattr_flags & 11312d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines SELINUX_RESTORECON_XATTR_RECURSE) ? true : false; 11322d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines bool delete_nonmatch = (xattr_flags & 11332d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines SELINUX_RESTORECON_XATTR_DELETE_NONMATCH_DIGESTS) ? true : false; 11342d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines bool delete_all = (xattr_flags & 11352d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines SELINUX_RESTORECON_XATTR_DELETE_ALL_DIGESTS) ? true : false; 11362d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines ignore_mounts = (xattr_flags & 11372d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS) ? true : false; 11382d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11392d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines int rc, fts_flags; 11402d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines struct stat sb; 11412d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines struct statfs sfsb; 11422d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines struct dir_xattr *current, *next; 11432d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines FTS *fts; 11442d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines FTSENT *ftsent; 11452d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines char *paths[2] = { NULL, NULL }; 11462d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11472d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines __selinux_once(fc_once, restorecon_init); 11482d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11492d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (!fc_sehandle || !fc_digest_len) 11502d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return -1; 11512d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11522d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (lstat(pathname, &sb) < 0) { 11532d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (errno == ENOENT) 11542d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return 0; 11552d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11562d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines selinux_log(SELINUX_ERROR, 11572d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines "lstat(%s) failed: %s\n", 11582d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines pathname, strerror(errno)); 11592d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return -1; 11602d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 11612d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11622d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (!recurse) { 11632d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (statfs(pathname, &sfsb) == 0) { 11642d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (sfsb.f_type == RAMFS_MAGIC || 11652d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines sfsb.f_type == TMPFS_MAGIC) 11662d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return 0; 11672d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 11682d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11692d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (check_excluded(pathname)) 11702d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return 0; 11712d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11722d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines rc = add_xattr_entry(pathname, delete_nonmatch, delete_all); 11732d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11742d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (!rc && dir_xattr_list) 11752d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines *xattr_list = &dir_xattr_list; 11762d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines else if (rc == -1) 11772d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return rc; 11782d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11792d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return 0; 11802d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 11812d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11822d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines paths[0] = (char *)pathname; 11832d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines fts_flags = FTS_PHYSICAL | FTS_NOCHDIR; 11842d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11852d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines fts = fts_open(paths, fts_flags, NULL); 11862d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (!fts) { 11872d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines selinux_log(SELINUX_ERROR, 11882d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines "fts error on %s: %s\n", 11892d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines paths[0], strerror(errno)); 11902d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return -1; 11912d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 11922d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 11932d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines while ((ftsent = fts_read(fts)) != NULL) { 11942d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines switch (ftsent->fts_info) { 11952d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines case FTS_DP: 11962d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines continue; 11972d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines case FTS_D: 11982d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (statfs(ftsent->fts_path, &sfsb) == 0) { 11992d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (sfsb.f_type == RAMFS_MAGIC || 12002d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines sfsb.f_type == TMPFS_MAGIC) 12012d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines continue; 12022d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 12032d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (check_excluded(ftsent->fts_path)) { 12042d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines fts_set(fts, ftsent, FTS_SKIP); 12052d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines continue; 12062d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 12072d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 12082d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines rc = add_xattr_entry(ftsent->fts_path, 12092d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines delete_nonmatch, delete_all); 12102d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (rc == 1) 12112d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines continue; 12122d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines else if (rc == -1) 12132d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines goto cleanup; 12142d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines break; 12152d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines default: 12162d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines break; 12172d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 12182d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 12192d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 12202d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (dir_xattr_list) 12212d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines *xattr_list = &dir_xattr_list; 12222d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 12232d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines (void) fts_close(fts); 12242d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return 0; 12252d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 12262d814ff4c7798a26d29e1dd091e75043f1628561Richard Hainescleanup: 12272d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines rc = errno; 12282d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines (void) fts_close(fts); 12292d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines errno = rc; 12302d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines 12312d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines if (dir_xattr_list) { 12322d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines /* Free any used memory */ 12332d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines current = dir_xattr_list; 12342d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines while (current) { 12352d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines next = current->next; 12362d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines free(current->directory); 12372d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines free(current->digest); 12382d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines free(current); 12392d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines current = next; 12402d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 12412d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines } 12422d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines return -1; 12432d814ff4c7798a26d29e1dd091e75043f1628561Richard Haines} 1244