1*2d543d20SAndroid Build Coastguard Worker /*
2*2d543d20SAndroid Build Coastguard Worker * The majority of this code is from Android's
3*2d543d20SAndroid Build Coastguard Worker * external/libselinux/src/android.c and upstream
4*2d543d20SAndroid Build Coastguard Worker * selinux/policycoreutils/setfiles/restore.c
5*2d543d20SAndroid Build Coastguard Worker *
6*2d543d20SAndroid Build Coastguard Worker * See selinux_restorecon(3) for details.
7*2d543d20SAndroid Build Coastguard Worker */
8*2d543d20SAndroid Build Coastguard Worker
9*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
10*2d543d20SAndroid Build Coastguard Worker #include <string.h>
11*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
12*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
13*2d543d20SAndroid Build Coastguard Worker #include <stdbool.h>
14*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
15*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
16*2d543d20SAndroid Build Coastguard Worker #include <fcntl.h>
17*2d543d20SAndroid Build Coastguard Worker #include <fts.h>
18*2d543d20SAndroid Build Coastguard Worker #include <inttypes.h>
19*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
20*2d543d20SAndroid Build Coastguard Worker #include <stdint.h>
21*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
22*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
23*2d543d20SAndroid Build Coastguard Worker #include <sys/xattr.h>
24*2d543d20SAndroid Build Coastguard Worker #include <sys/vfs.h>
25*2d543d20SAndroid Build Coastguard Worker #include <sys/statvfs.h>
26*2d543d20SAndroid Build Coastguard Worker #include <sys/utsname.h>
27*2d543d20SAndroid Build Coastguard Worker #include <linux/magic.h>
28*2d543d20SAndroid Build Coastguard Worker #include <libgen.h>
29*2d543d20SAndroid Build Coastguard Worker #include <syslog.h>
30*2d543d20SAndroid Build Coastguard Worker #include <assert.h>
31*2d543d20SAndroid Build Coastguard Worker
32*2d543d20SAndroid Build Coastguard Worker #include <selinux/selinux.h>
33*2d543d20SAndroid Build Coastguard Worker #include <selinux/context.h>
34*2d543d20SAndroid Build Coastguard Worker #include <selinux/label.h>
35*2d543d20SAndroid Build Coastguard Worker #include <selinux/restorecon.h>
36*2d543d20SAndroid Build Coastguard Worker
37*2d543d20SAndroid Build Coastguard Worker #include "callbacks.h"
38*2d543d20SAndroid Build Coastguard Worker #include "selinux_internal.h"
39*2d543d20SAndroid Build Coastguard Worker #include "label_file.h"
40*2d543d20SAndroid Build Coastguard Worker #include "sha1.h"
41*2d543d20SAndroid Build Coastguard Worker
42*2d543d20SAndroid Build Coastguard Worker #define STAR_COUNT 1024
43*2d543d20SAndroid Build Coastguard Worker
44*2d543d20SAndroid Build Coastguard Worker static struct selabel_handle *fc_sehandle = NULL;
45*2d543d20SAndroid Build Coastguard Worker static bool selabel_no_digest;
46*2d543d20SAndroid Build Coastguard Worker static char *rootpath = NULL;
47*2d543d20SAndroid Build Coastguard Worker static size_t rootpathlen;
48*2d543d20SAndroid Build Coastguard Worker
49*2d543d20SAndroid Build Coastguard Worker /* Information on excluded fs and directories. */
50*2d543d20SAndroid Build Coastguard Worker struct edir {
51*2d543d20SAndroid Build Coastguard Worker char *directory;
52*2d543d20SAndroid Build Coastguard Worker size_t size;
53*2d543d20SAndroid Build Coastguard Worker /* True if excluded by selinux_restorecon_set_exclude_list(3). */
54*2d543d20SAndroid Build Coastguard Worker bool caller_excluded;
55*2d543d20SAndroid Build Coastguard Worker };
56*2d543d20SAndroid Build Coastguard Worker #define CALLER_EXCLUDED true
57*2d543d20SAndroid Build Coastguard Worker static bool ignore_mounts;
58*2d543d20SAndroid Build Coastguard Worker static uint64_t exclude_non_seclabel_mounts(void);
59*2d543d20SAndroid Build Coastguard Worker static int exclude_count = 0;
60*2d543d20SAndroid Build Coastguard Worker static struct edir *exclude_lst = NULL;
61*2d543d20SAndroid Build Coastguard Worker static uint64_t fc_count = 0; /* Number of files processed so far */
62*2d543d20SAndroid Build Coastguard Worker static uint64_t efile_count; /* Estimated total number of files */
63*2d543d20SAndroid Build Coastguard Worker static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER;
64*2d543d20SAndroid Build Coastguard Worker
65*2d543d20SAndroid Build Coastguard Worker /* Store information on directories with xattr's. */
66*2d543d20SAndroid Build Coastguard Worker static struct dir_xattr *dir_xattr_list;
67*2d543d20SAndroid Build Coastguard Worker static struct dir_xattr *dir_xattr_last;
68*2d543d20SAndroid Build Coastguard Worker
69*2d543d20SAndroid Build Coastguard Worker /* Number of errors ignored during the file tree walk. */
70*2d543d20SAndroid Build Coastguard Worker static long unsigned skipped_errors;
71*2d543d20SAndroid Build Coastguard Worker
72*2d543d20SAndroid Build Coastguard Worker /* restorecon_flags for passing to restorecon_sb() */
73*2d543d20SAndroid Build Coastguard Worker struct rest_flags {
74*2d543d20SAndroid Build Coastguard Worker bool nochange;
75*2d543d20SAndroid Build Coastguard Worker bool verbose;
76*2d543d20SAndroid Build Coastguard Worker bool progress;
77*2d543d20SAndroid Build Coastguard Worker bool mass_relabel;
78*2d543d20SAndroid Build Coastguard Worker bool set_specctx;
79*2d543d20SAndroid Build Coastguard Worker bool add_assoc;
80*2d543d20SAndroid Build Coastguard Worker bool recurse;
81*2d543d20SAndroid Build Coastguard Worker bool userealpath;
82*2d543d20SAndroid Build Coastguard Worker bool set_xdev;
83*2d543d20SAndroid Build Coastguard Worker bool abort_on_error;
84*2d543d20SAndroid Build Coastguard Worker bool syslog_changes;
85*2d543d20SAndroid Build Coastguard Worker bool log_matches;
86*2d543d20SAndroid Build Coastguard Worker bool ignore_noent;
87*2d543d20SAndroid Build Coastguard Worker bool warnonnomatch;
88*2d543d20SAndroid Build Coastguard Worker bool conflicterror;
89*2d543d20SAndroid Build Coastguard Worker bool count_errors;
90*2d543d20SAndroid Build Coastguard Worker };
91*2d543d20SAndroid Build Coastguard Worker
restorecon_init(void)92*2d543d20SAndroid Build Coastguard Worker static void restorecon_init(void)
93*2d543d20SAndroid Build Coastguard Worker {
94*2d543d20SAndroid Build Coastguard Worker struct selabel_handle *sehandle = NULL;
95*2d543d20SAndroid Build Coastguard Worker
96*2d543d20SAndroid Build Coastguard Worker if (!fc_sehandle) {
97*2d543d20SAndroid Build Coastguard Worker sehandle = selinux_restorecon_default_handle();
98*2d543d20SAndroid Build Coastguard Worker selinux_restorecon_set_sehandle(sehandle);
99*2d543d20SAndroid Build Coastguard Worker }
100*2d543d20SAndroid Build Coastguard Worker
101*2d543d20SAndroid Build Coastguard Worker efile_count = 0;
102*2d543d20SAndroid Build Coastguard Worker if (!ignore_mounts)
103*2d543d20SAndroid Build Coastguard Worker efile_count = exclude_non_seclabel_mounts();
104*2d543d20SAndroid Build Coastguard Worker }
105*2d543d20SAndroid Build Coastguard Worker
106*2d543d20SAndroid Build Coastguard Worker static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
107*2d543d20SAndroid Build Coastguard Worker
108*2d543d20SAndroid Build Coastguard Worker /*
109*2d543d20SAndroid Build Coastguard Worker * Manage excluded directories:
110*2d543d20SAndroid Build Coastguard Worker * remove_exclude() - This removes any conflicting entries as there could be
111*2d543d20SAndroid Build Coastguard Worker * a case where a non-seclabel fs is mounted on /foo and
112*2d543d20SAndroid Build Coastguard Worker * then a seclabel fs is mounted on top of it.
113*2d543d20SAndroid Build Coastguard Worker * However if an entry has been added via
114*2d543d20SAndroid Build Coastguard Worker * selinux_restorecon_set_exclude_list(3) do not remove.
115*2d543d20SAndroid Build Coastguard Worker *
116*2d543d20SAndroid Build Coastguard Worker * add_exclude() - Add a directory/fs to be excluded from labeling. If it
117*2d543d20SAndroid Build Coastguard Worker * has already been added, then ignore.
118*2d543d20SAndroid Build Coastguard Worker *
119*2d543d20SAndroid Build Coastguard Worker * check_excluded() - Check if directory/fs is to be excluded when relabeling.
120*2d543d20SAndroid Build Coastguard Worker *
121*2d543d20SAndroid Build Coastguard Worker * file_system_count() - Calculates the number of files to be processed.
122*2d543d20SAndroid Build Coastguard Worker * The count is only used if SELINUX_RESTORECON_PROGRESS
123*2d543d20SAndroid Build Coastguard Worker * is set and a mass relabel is requested.
124*2d543d20SAndroid Build Coastguard Worker *
125*2d543d20SAndroid Build Coastguard Worker * exclude_non_seclabel_mounts() - Reads /proc/mounts to determine what
126*2d543d20SAndroid Build Coastguard Worker * non-seclabel mounts to exclude from
127*2d543d20SAndroid Build Coastguard Worker * relabeling. restorecon_init() will not
128*2d543d20SAndroid Build Coastguard Worker * call this function if the
129*2d543d20SAndroid Build Coastguard Worker * SELINUX_RESTORECON_IGNORE_MOUNTS
130*2d543d20SAndroid Build Coastguard Worker * flag is set.
131*2d543d20SAndroid Build Coastguard Worker * Setting SELINUX_RESTORECON_IGNORE_MOUNTS
132*2d543d20SAndroid Build Coastguard Worker * is useful where there is a non-seclabel fs
133*2d543d20SAndroid Build Coastguard Worker * mounted on /foo and then a seclabel fs is
134*2d543d20SAndroid Build Coastguard Worker * mounted on a directory below this.
135*2d543d20SAndroid Build Coastguard Worker */
remove_exclude(const char * directory)136*2d543d20SAndroid Build Coastguard Worker static void remove_exclude(const char *directory)
137*2d543d20SAndroid Build Coastguard Worker {
138*2d543d20SAndroid Build Coastguard Worker int i;
139*2d543d20SAndroid Build Coastguard Worker
140*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < exclude_count; i++) {
141*2d543d20SAndroid Build Coastguard Worker if (strcmp(directory, exclude_lst[i].directory) == 0 &&
142*2d543d20SAndroid Build Coastguard Worker !exclude_lst[i].caller_excluded) {
143*2d543d20SAndroid Build Coastguard Worker free(exclude_lst[i].directory);
144*2d543d20SAndroid Build Coastguard Worker if (i != exclude_count - 1)
145*2d543d20SAndroid Build Coastguard Worker exclude_lst[i] = exclude_lst[exclude_count - 1];
146*2d543d20SAndroid Build Coastguard Worker exclude_count--;
147*2d543d20SAndroid Build Coastguard Worker return;
148*2d543d20SAndroid Build Coastguard Worker }
149*2d543d20SAndroid Build Coastguard Worker }
150*2d543d20SAndroid Build Coastguard Worker }
151*2d543d20SAndroid Build Coastguard Worker
add_exclude(const char * directory,bool who)152*2d543d20SAndroid Build Coastguard Worker static int add_exclude(const char *directory, bool who)
153*2d543d20SAndroid Build Coastguard Worker {
154*2d543d20SAndroid Build Coastguard Worker struct edir *tmp_list, *current;
155*2d543d20SAndroid Build Coastguard Worker size_t len = 0;
156*2d543d20SAndroid Build Coastguard Worker int i;
157*2d543d20SAndroid Build Coastguard Worker
158*2d543d20SAndroid Build Coastguard Worker /* Check if already present. */
159*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < exclude_count; i++) {
160*2d543d20SAndroid Build Coastguard Worker if (strcmp(directory, exclude_lst[i].directory) == 0)
161*2d543d20SAndroid Build Coastguard Worker return 0;
162*2d543d20SAndroid Build Coastguard Worker }
163*2d543d20SAndroid Build Coastguard Worker
164*2d543d20SAndroid Build Coastguard Worker if (directory == NULL || directory[0] != '/') {
165*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
166*2d543d20SAndroid Build Coastguard Worker "Full path required for exclude: %s.\n",
167*2d543d20SAndroid Build Coastguard Worker directory);
168*2d543d20SAndroid Build Coastguard Worker errno = EINVAL;
169*2d543d20SAndroid Build Coastguard Worker return -1;
170*2d543d20SAndroid Build Coastguard Worker }
171*2d543d20SAndroid Build Coastguard Worker
172*2d543d20SAndroid Build Coastguard Worker if (exclude_count >= INT_MAX - 1) {
173*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR, "Too many directory excludes: %d.\n", exclude_count);
174*2d543d20SAndroid Build Coastguard Worker errno = EOVERFLOW;
175*2d543d20SAndroid Build Coastguard Worker return -1;
176*2d543d20SAndroid Build Coastguard Worker }
177*2d543d20SAndroid Build Coastguard Worker
178*2d543d20SAndroid Build Coastguard Worker tmp_list = reallocarray(exclude_lst, exclude_count + 1, sizeof(struct edir));
179*2d543d20SAndroid Build Coastguard Worker if (!tmp_list)
180*2d543d20SAndroid Build Coastguard Worker goto oom;
181*2d543d20SAndroid Build Coastguard Worker
182*2d543d20SAndroid Build Coastguard Worker exclude_lst = tmp_list;
183*2d543d20SAndroid Build Coastguard Worker
184*2d543d20SAndroid Build Coastguard Worker len = strlen(directory);
185*2d543d20SAndroid Build Coastguard Worker while (len > 1 && directory[len - 1] == '/')
186*2d543d20SAndroid Build Coastguard Worker len--;
187*2d543d20SAndroid Build Coastguard Worker
188*2d543d20SAndroid Build Coastguard Worker current = (exclude_lst + exclude_count);
189*2d543d20SAndroid Build Coastguard Worker
190*2d543d20SAndroid Build Coastguard Worker current->directory = strndup(directory, len);
191*2d543d20SAndroid Build Coastguard Worker if (!current->directory)
192*2d543d20SAndroid Build Coastguard Worker goto oom;
193*2d543d20SAndroid Build Coastguard Worker
194*2d543d20SAndroid Build Coastguard Worker current->size = len;
195*2d543d20SAndroid Build Coastguard Worker current->caller_excluded = who;
196*2d543d20SAndroid Build Coastguard Worker exclude_count++;
197*2d543d20SAndroid Build Coastguard Worker return 0;
198*2d543d20SAndroid Build Coastguard Worker
199*2d543d20SAndroid Build Coastguard Worker oom:
200*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__);
201*2d543d20SAndroid Build Coastguard Worker return -1;
202*2d543d20SAndroid Build Coastguard Worker }
203*2d543d20SAndroid Build Coastguard Worker
check_excluded(const char * file)204*2d543d20SAndroid Build Coastguard Worker static int check_excluded(const char *file)
205*2d543d20SAndroid Build Coastguard Worker {
206*2d543d20SAndroid Build Coastguard Worker int i;
207*2d543d20SAndroid Build Coastguard Worker
208*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < exclude_count; i++) {
209*2d543d20SAndroid Build Coastguard Worker if (strncmp(file, exclude_lst[i].directory,
210*2d543d20SAndroid Build Coastguard Worker exclude_lst[i].size) == 0) {
211*2d543d20SAndroid Build Coastguard Worker if (file[exclude_lst[i].size] == 0 ||
212*2d543d20SAndroid Build Coastguard Worker file[exclude_lst[i].size] == '/')
213*2d543d20SAndroid Build Coastguard Worker return 1;
214*2d543d20SAndroid Build Coastguard Worker }
215*2d543d20SAndroid Build Coastguard Worker }
216*2d543d20SAndroid Build Coastguard Worker return 0;
217*2d543d20SAndroid Build Coastguard Worker }
218*2d543d20SAndroid Build Coastguard Worker
file_system_count(const char * name)219*2d543d20SAndroid Build Coastguard Worker static uint64_t file_system_count(const char *name)
220*2d543d20SAndroid Build Coastguard Worker {
221*2d543d20SAndroid Build Coastguard Worker struct statvfs statvfs_buf;
222*2d543d20SAndroid Build Coastguard Worker uint64_t nfile = 0;
223*2d543d20SAndroid Build Coastguard Worker
224*2d543d20SAndroid Build Coastguard Worker memset(&statvfs_buf, 0, sizeof(statvfs_buf));
225*2d543d20SAndroid Build Coastguard Worker if (!statvfs(name, &statvfs_buf))
226*2d543d20SAndroid Build Coastguard Worker nfile = statvfs_buf.f_files - statvfs_buf.f_ffree;
227*2d543d20SAndroid Build Coastguard Worker
228*2d543d20SAndroid Build Coastguard Worker return nfile;
229*2d543d20SAndroid Build Coastguard Worker }
230*2d543d20SAndroid Build Coastguard Worker
231*2d543d20SAndroid Build Coastguard Worker /*
232*2d543d20SAndroid Build Coastguard Worker * This is called once when selinux_restorecon() is first called.
233*2d543d20SAndroid Build Coastguard Worker * Searches /proc/mounts for all file systems that do not support extended
234*2d543d20SAndroid Build Coastguard Worker * attributes and adds them to the exclude directory table. File systems
235*2d543d20SAndroid Build Coastguard Worker * that support security labels have the seclabel option, return
236*2d543d20SAndroid Build Coastguard Worker * approximate total file count.
237*2d543d20SAndroid Build Coastguard Worker */
exclude_non_seclabel_mounts(void)238*2d543d20SAndroid Build Coastguard Worker static uint64_t exclude_non_seclabel_mounts(void)
239*2d543d20SAndroid Build Coastguard Worker {
240*2d543d20SAndroid Build Coastguard Worker struct utsname uts;
241*2d543d20SAndroid Build Coastguard Worker FILE *fp;
242*2d543d20SAndroid Build Coastguard Worker size_t len;
243*2d543d20SAndroid Build Coastguard Worker int index = 0, found = 0;
244*2d543d20SAndroid Build Coastguard Worker uint64_t nfile = 0;
245*2d543d20SAndroid Build Coastguard Worker char *mount_info[4];
246*2d543d20SAndroid Build Coastguard Worker char *buf = NULL, *item, *saveptr;
247*2d543d20SAndroid Build Coastguard Worker
248*2d543d20SAndroid Build Coastguard Worker /* Check to see if the kernel supports seclabel */
249*2d543d20SAndroid Build Coastguard Worker if (uname(&uts) == 0 && strverscmp(uts.release, "2.6.30") < 0)
250*2d543d20SAndroid Build Coastguard Worker return 0;
251*2d543d20SAndroid Build Coastguard Worker if (is_selinux_enabled() <= 0)
252*2d543d20SAndroid Build Coastguard Worker return 0;
253*2d543d20SAndroid Build Coastguard Worker
254*2d543d20SAndroid Build Coastguard Worker fp = fopen("/proc/mounts", "re");
255*2d543d20SAndroid Build Coastguard Worker if (!fp)
256*2d543d20SAndroid Build Coastguard Worker return 0;
257*2d543d20SAndroid Build Coastguard Worker
258*2d543d20SAndroid Build Coastguard Worker while (getline(&buf, &len, fp) != -1) {
259*2d543d20SAndroid Build Coastguard Worker found = 0;
260*2d543d20SAndroid Build Coastguard Worker index = 0;
261*2d543d20SAndroid Build Coastguard Worker saveptr = NULL;
262*2d543d20SAndroid Build Coastguard Worker item = strtok_r(buf, " ", &saveptr);
263*2d543d20SAndroid Build Coastguard Worker while (item != NULL) {
264*2d543d20SAndroid Build Coastguard Worker mount_info[index] = item;
265*2d543d20SAndroid Build Coastguard Worker index++;
266*2d543d20SAndroid Build Coastguard Worker if (index == 4)
267*2d543d20SAndroid Build Coastguard Worker break;
268*2d543d20SAndroid Build Coastguard Worker item = strtok_r(NULL, " ", &saveptr);
269*2d543d20SAndroid Build Coastguard Worker }
270*2d543d20SAndroid Build Coastguard Worker if (index < 4) {
271*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
272*2d543d20SAndroid Build Coastguard Worker "/proc/mounts record \"%s\" has incorrect format.\n",
273*2d543d20SAndroid Build Coastguard Worker buf);
274*2d543d20SAndroid Build Coastguard Worker continue;
275*2d543d20SAndroid Build Coastguard Worker }
276*2d543d20SAndroid Build Coastguard Worker
277*2d543d20SAndroid Build Coastguard Worker /* Remove pre-existing entry */
278*2d543d20SAndroid Build Coastguard Worker remove_exclude(mount_info[1]);
279*2d543d20SAndroid Build Coastguard Worker
280*2d543d20SAndroid Build Coastguard Worker saveptr = NULL;
281*2d543d20SAndroid Build Coastguard Worker item = strtok_r(mount_info[3], ",", &saveptr);
282*2d543d20SAndroid Build Coastguard Worker while (item != NULL) {
283*2d543d20SAndroid Build Coastguard Worker if (strcmp(item, "seclabel") == 0) {
284*2d543d20SAndroid Build Coastguard Worker found = 1;
285*2d543d20SAndroid Build Coastguard Worker nfile += file_system_count(mount_info[1]);
286*2d543d20SAndroid Build Coastguard Worker break;
287*2d543d20SAndroid Build Coastguard Worker }
288*2d543d20SAndroid Build Coastguard Worker item = strtok_r(NULL, ",", &saveptr);
289*2d543d20SAndroid Build Coastguard Worker }
290*2d543d20SAndroid Build Coastguard Worker
291*2d543d20SAndroid Build Coastguard Worker /* Exclude mount points without the seclabel option */
292*2d543d20SAndroid Build Coastguard Worker if (!found) {
293*2d543d20SAndroid Build Coastguard Worker if (add_exclude(mount_info[1], !CALLER_EXCLUDED) &&
294*2d543d20SAndroid Build Coastguard Worker errno == ENOMEM)
295*2d543d20SAndroid Build Coastguard Worker assert(0);
296*2d543d20SAndroid Build Coastguard Worker }
297*2d543d20SAndroid Build Coastguard Worker }
298*2d543d20SAndroid Build Coastguard Worker
299*2d543d20SAndroid Build Coastguard Worker free(buf);
300*2d543d20SAndroid Build Coastguard Worker fclose(fp);
301*2d543d20SAndroid Build Coastguard Worker /* return estimated #Files + 5% for directories and hard links */
302*2d543d20SAndroid Build Coastguard Worker return nfile * 1.05;
303*2d543d20SAndroid Build Coastguard Worker }
304*2d543d20SAndroid Build Coastguard Worker
305*2d543d20SAndroid Build Coastguard Worker /* Called by selinux_restorecon_xattr(3) to build a linked list of entries. */
add_xattr_entry(const char * directory,bool delete_nonmatch,bool delete_all)306*2d543d20SAndroid Build Coastguard Worker static int add_xattr_entry(const char *directory, bool delete_nonmatch,
307*2d543d20SAndroid Build Coastguard Worker bool delete_all)
308*2d543d20SAndroid Build Coastguard Worker {
309*2d543d20SAndroid Build Coastguard Worker char *sha1_buf = NULL;
310*2d543d20SAndroid Build Coastguard Worker size_t i, digest_len = 0;
311*2d543d20SAndroid Build Coastguard Worker int rc;
312*2d543d20SAndroid Build Coastguard Worker enum digest_result digest_result;
313*2d543d20SAndroid Build Coastguard Worker bool match;
314*2d543d20SAndroid Build Coastguard Worker struct dir_xattr *new_entry;
315*2d543d20SAndroid Build Coastguard Worker uint8_t *xattr_digest = NULL;
316*2d543d20SAndroid Build Coastguard Worker uint8_t *calculated_digest = NULL;
317*2d543d20SAndroid Build Coastguard Worker
318*2d543d20SAndroid Build Coastguard Worker if (!directory) {
319*2d543d20SAndroid Build Coastguard Worker errno = EINVAL;
320*2d543d20SAndroid Build Coastguard Worker return -1;
321*2d543d20SAndroid Build Coastguard Worker }
322*2d543d20SAndroid Build Coastguard Worker
323*2d543d20SAndroid Build Coastguard Worker match = selabel_get_digests_all_partial_matches(fc_sehandle, directory,
324*2d543d20SAndroid Build Coastguard Worker &calculated_digest, &xattr_digest,
325*2d543d20SAndroid Build Coastguard Worker &digest_len);
326*2d543d20SAndroid Build Coastguard Worker
327*2d543d20SAndroid Build Coastguard Worker if (!xattr_digest || !digest_len) {
328*2d543d20SAndroid Build Coastguard Worker free(calculated_digest);
329*2d543d20SAndroid Build Coastguard Worker return 1;
330*2d543d20SAndroid Build Coastguard Worker }
331*2d543d20SAndroid Build Coastguard Worker
332*2d543d20SAndroid Build Coastguard Worker /* Convert entry to a hex encoded string. */
333*2d543d20SAndroid Build Coastguard Worker sha1_buf = malloc(digest_len * 2 + 1);
334*2d543d20SAndroid Build Coastguard Worker if (!sha1_buf) {
335*2d543d20SAndroid Build Coastguard Worker free(xattr_digest);
336*2d543d20SAndroid Build Coastguard Worker free(calculated_digest);
337*2d543d20SAndroid Build Coastguard Worker goto oom;
338*2d543d20SAndroid Build Coastguard Worker }
339*2d543d20SAndroid Build Coastguard Worker
340*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < digest_len; i++)
341*2d543d20SAndroid Build Coastguard Worker sprintf((&sha1_buf[i * 2]), "%02x", xattr_digest[i]);
342*2d543d20SAndroid Build Coastguard Worker
343*2d543d20SAndroid Build Coastguard Worker digest_result = match ? MATCH : NOMATCH;
344*2d543d20SAndroid Build Coastguard Worker
345*2d543d20SAndroid Build Coastguard Worker if ((delete_nonmatch && !match) || delete_all) {
346*2d543d20SAndroid Build Coastguard Worker digest_result = match ? DELETED_MATCH : DELETED_NOMATCH;
347*2d543d20SAndroid Build Coastguard Worker rc = removexattr(directory, RESTORECON_PARTIAL_MATCH_DIGEST);
348*2d543d20SAndroid Build Coastguard Worker if (rc) {
349*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
350*2d543d20SAndroid Build Coastguard Worker "Error: %m removing xattr \"%s\" from: %s\n",
351*2d543d20SAndroid Build Coastguard Worker RESTORECON_PARTIAL_MATCH_DIGEST, directory);
352*2d543d20SAndroid Build Coastguard Worker digest_result = ERROR;
353*2d543d20SAndroid Build Coastguard Worker }
354*2d543d20SAndroid Build Coastguard Worker }
355*2d543d20SAndroid Build Coastguard Worker free(xattr_digest);
356*2d543d20SAndroid Build Coastguard Worker free(calculated_digest);
357*2d543d20SAndroid Build Coastguard Worker
358*2d543d20SAndroid Build Coastguard Worker /* Now add entries to link list. */
359*2d543d20SAndroid Build Coastguard Worker new_entry = malloc(sizeof(struct dir_xattr));
360*2d543d20SAndroid Build Coastguard Worker if (!new_entry) {
361*2d543d20SAndroid Build Coastguard Worker free(sha1_buf);
362*2d543d20SAndroid Build Coastguard Worker goto oom;
363*2d543d20SAndroid Build Coastguard Worker }
364*2d543d20SAndroid Build Coastguard Worker new_entry->next = NULL;
365*2d543d20SAndroid Build Coastguard Worker
366*2d543d20SAndroid Build Coastguard Worker new_entry->directory = strdup(directory);
367*2d543d20SAndroid Build Coastguard Worker if (!new_entry->directory) {
368*2d543d20SAndroid Build Coastguard Worker free(new_entry);
369*2d543d20SAndroid Build Coastguard Worker free(sha1_buf);
370*2d543d20SAndroid Build Coastguard Worker goto oom;
371*2d543d20SAndroid Build Coastguard Worker }
372*2d543d20SAndroid Build Coastguard Worker
373*2d543d20SAndroid Build Coastguard Worker new_entry->digest = strdup(sha1_buf);
374*2d543d20SAndroid Build Coastguard Worker if (!new_entry->digest) {
375*2d543d20SAndroid Build Coastguard Worker free(new_entry->directory);
376*2d543d20SAndroid Build Coastguard Worker free(new_entry);
377*2d543d20SAndroid Build Coastguard Worker free(sha1_buf);
378*2d543d20SAndroid Build Coastguard Worker goto oom;
379*2d543d20SAndroid Build Coastguard Worker }
380*2d543d20SAndroid Build Coastguard Worker
381*2d543d20SAndroid Build Coastguard Worker new_entry->result = digest_result;
382*2d543d20SAndroid Build Coastguard Worker
383*2d543d20SAndroid Build Coastguard Worker if (!dir_xattr_list) {
384*2d543d20SAndroid Build Coastguard Worker dir_xattr_list = new_entry;
385*2d543d20SAndroid Build Coastguard Worker dir_xattr_last = new_entry;
386*2d543d20SAndroid Build Coastguard Worker } else {
387*2d543d20SAndroid Build Coastguard Worker dir_xattr_last->next = new_entry;
388*2d543d20SAndroid Build Coastguard Worker dir_xattr_last = new_entry;
389*2d543d20SAndroid Build Coastguard Worker }
390*2d543d20SAndroid Build Coastguard Worker
391*2d543d20SAndroid Build Coastguard Worker free(sha1_buf);
392*2d543d20SAndroid Build Coastguard Worker return 0;
393*2d543d20SAndroid Build Coastguard Worker
394*2d543d20SAndroid Build Coastguard Worker oom:
395*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__);
396*2d543d20SAndroid Build Coastguard Worker return -1;
397*2d543d20SAndroid Build Coastguard Worker }
398*2d543d20SAndroid Build Coastguard Worker
399*2d543d20SAndroid Build Coastguard Worker /*
400*2d543d20SAndroid Build Coastguard Worker * Support filespec services filespec_add(), filespec_eval() and
401*2d543d20SAndroid Build Coastguard Worker * filespec_destroy().
402*2d543d20SAndroid Build Coastguard Worker *
403*2d543d20SAndroid Build Coastguard Worker * selinux_restorecon(3) uses filespec services when the
404*2d543d20SAndroid Build Coastguard Worker * SELINUX_RESTORECON_ADD_ASSOC flag is set for adding associations between
405*2d543d20SAndroid Build Coastguard Worker * an inode and a specification.
406*2d543d20SAndroid Build Coastguard Worker */
407*2d543d20SAndroid Build Coastguard Worker
408*2d543d20SAndroid Build Coastguard Worker /*
409*2d543d20SAndroid Build Coastguard Worker * The hash table of associations, hashed by inode number. Chaining is used
410*2d543d20SAndroid Build Coastguard Worker * for collisions, with elements ordered by inode number in each bucket.
411*2d543d20SAndroid Build Coastguard Worker * Each hash bucket has a dummy header.
412*2d543d20SAndroid Build Coastguard Worker */
413*2d543d20SAndroid Build Coastguard Worker #define HASH_BITS 16
414*2d543d20SAndroid Build Coastguard Worker #define HASH_BUCKETS (1 << HASH_BITS)
415*2d543d20SAndroid Build Coastguard Worker #define HASH_MASK (HASH_BUCKETS-1)
416*2d543d20SAndroid Build Coastguard Worker
417*2d543d20SAndroid Build Coastguard Worker /*
418*2d543d20SAndroid Build Coastguard Worker * An association between an inode and a context.
419*2d543d20SAndroid Build Coastguard Worker */
420*2d543d20SAndroid Build Coastguard Worker typedef struct file_spec {
421*2d543d20SAndroid Build Coastguard Worker ino_t ino; /* inode number */
422*2d543d20SAndroid Build Coastguard Worker char *con; /* matched context */
423*2d543d20SAndroid Build Coastguard Worker char *file; /* full pathname */
424*2d543d20SAndroid Build Coastguard Worker struct file_spec *next; /* next association in hash bucket chain */
425*2d543d20SAndroid Build Coastguard Worker } file_spec_t;
426*2d543d20SAndroid Build Coastguard Worker
427*2d543d20SAndroid Build Coastguard Worker static file_spec_t *fl_head;
428*2d543d20SAndroid Build Coastguard Worker static pthread_mutex_t fl_mutex = PTHREAD_MUTEX_INITIALIZER;
429*2d543d20SAndroid Build Coastguard Worker
430*2d543d20SAndroid Build Coastguard Worker /*
431*2d543d20SAndroid Build Coastguard Worker * Try to add an association between an inode and a context. If there is a
432*2d543d20SAndroid Build Coastguard Worker * different context that matched the inode, then use the first context
433*2d543d20SAndroid Build Coastguard Worker * that matched.
434*2d543d20SAndroid Build Coastguard Worker */
filespec_add(ino_t ino,const char * con,const char * file,const struct rest_flags * flags)435*2d543d20SAndroid Build Coastguard Worker static int filespec_add(ino_t ino, const char *con, const char *file,
436*2d543d20SAndroid Build Coastguard Worker const struct rest_flags *flags)
437*2d543d20SAndroid Build Coastguard Worker {
438*2d543d20SAndroid Build Coastguard Worker file_spec_t *prevfl, *fl;
439*2d543d20SAndroid Build Coastguard Worker uint32_t h;
440*2d543d20SAndroid Build Coastguard Worker int ret;
441*2d543d20SAndroid Build Coastguard Worker struct stat64 sb;
442*2d543d20SAndroid Build Coastguard Worker
443*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_lock(&fl_mutex);
444*2d543d20SAndroid Build Coastguard Worker
445*2d543d20SAndroid Build Coastguard Worker if (!fl_head) {
446*2d543d20SAndroid Build Coastguard Worker fl_head = calloc(HASH_BUCKETS, sizeof(file_spec_t));
447*2d543d20SAndroid Build Coastguard Worker if (!fl_head)
448*2d543d20SAndroid Build Coastguard Worker goto oom;
449*2d543d20SAndroid Build Coastguard Worker }
450*2d543d20SAndroid Build Coastguard Worker
451*2d543d20SAndroid Build Coastguard Worker h = (ino + (ino >> HASH_BITS)) & HASH_MASK;
452*2d543d20SAndroid Build Coastguard Worker for (prevfl = &fl_head[h], fl = fl_head[h].next; fl;
453*2d543d20SAndroid Build Coastguard Worker prevfl = fl, fl = fl->next) {
454*2d543d20SAndroid Build Coastguard Worker if (ino == fl->ino) {
455*2d543d20SAndroid Build Coastguard Worker ret = lstat64(fl->file, &sb);
456*2d543d20SAndroid Build Coastguard Worker if (ret < 0 || sb.st_ino != ino) {
457*2d543d20SAndroid Build Coastguard Worker freecon(fl->con);
458*2d543d20SAndroid Build Coastguard Worker free(fl->file);
459*2d543d20SAndroid Build Coastguard Worker fl->file = strdup(file);
460*2d543d20SAndroid Build Coastguard Worker if (!fl->file)
461*2d543d20SAndroid Build Coastguard Worker goto oom;
462*2d543d20SAndroid Build Coastguard Worker fl->con = strdup(con);
463*2d543d20SAndroid Build Coastguard Worker if (!fl->con)
464*2d543d20SAndroid Build Coastguard Worker goto oom;
465*2d543d20SAndroid Build Coastguard Worker goto unlock_1;
466*2d543d20SAndroid Build Coastguard Worker }
467*2d543d20SAndroid Build Coastguard Worker
468*2d543d20SAndroid Build Coastguard Worker if (strcmp(fl->con, con) == 0)
469*2d543d20SAndroid Build Coastguard Worker goto unlock_1;
470*2d543d20SAndroid Build Coastguard Worker
471*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
472*2d543d20SAndroid Build Coastguard Worker "conflicting specifications for %s and %s, using %s.\n",
473*2d543d20SAndroid Build Coastguard Worker file, fl->file, fl->con);
474*2d543d20SAndroid Build Coastguard Worker free(fl->file);
475*2d543d20SAndroid Build Coastguard Worker fl->file = strdup(file);
476*2d543d20SAndroid Build Coastguard Worker if (!fl->file)
477*2d543d20SAndroid Build Coastguard Worker goto oom;
478*2d543d20SAndroid Build Coastguard Worker
479*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_unlock(&fl_mutex);
480*2d543d20SAndroid Build Coastguard Worker
481*2d543d20SAndroid Build Coastguard Worker if (flags->conflicterror) {
482*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
483*2d543d20SAndroid Build Coastguard Worker "treating conflicting specifications as an error.\n");
484*2d543d20SAndroid Build Coastguard Worker return -1;
485*2d543d20SAndroid Build Coastguard Worker }
486*2d543d20SAndroid Build Coastguard Worker return 1;
487*2d543d20SAndroid Build Coastguard Worker }
488*2d543d20SAndroid Build Coastguard Worker
489*2d543d20SAndroid Build Coastguard Worker if (ino > fl->ino)
490*2d543d20SAndroid Build Coastguard Worker break;
491*2d543d20SAndroid Build Coastguard Worker }
492*2d543d20SAndroid Build Coastguard Worker
493*2d543d20SAndroid Build Coastguard Worker fl = malloc(sizeof(file_spec_t));
494*2d543d20SAndroid Build Coastguard Worker if (!fl)
495*2d543d20SAndroid Build Coastguard Worker goto oom;
496*2d543d20SAndroid Build Coastguard Worker fl->ino = ino;
497*2d543d20SAndroid Build Coastguard Worker fl->con = strdup(con);
498*2d543d20SAndroid Build Coastguard Worker if (!fl->con)
499*2d543d20SAndroid Build Coastguard Worker goto oom_freefl;
500*2d543d20SAndroid Build Coastguard Worker fl->file = strdup(file);
501*2d543d20SAndroid Build Coastguard Worker if (!fl->file)
502*2d543d20SAndroid Build Coastguard Worker goto oom_freeflcon;
503*2d543d20SAndroid Build Coastguard Worker fl->next = prevfl->next;
504*2d543d20SAndroid Build Coastguard Worker prevfl->next = fl;
505*2d543d20SAndroid Build Coastguard Worker
506*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_unlock(&fl_mutex);
507*2d543d20SAndroid Build Coastguard Worker return 0;
508*2d543d20SAndroid Build Coastguard Worker
509*2d543d20SAndroid Build Coastguard Worker oom_freeflcon:
510*2d543d20SAndroid Build Coastguard Worker free(fl->con);
511*2d543d20SAndroid Build Coastguard Worker oom_freefl:
512*2d543d20SAndroid Build Coastguard Worker free(fl);
513*2d543d20SAndroid Build Coastguard Worker oom:
514*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_unlock(&fl_mutex);
515*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__);
516*2d543d20SAndroid Build Coastguard Worker return -1;
517*2d543d20SAndroid Build Coastguard Worker unlock_1:
518*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_unlock(&fl_mutex);
519*2d543d20SAndroid Build Coastguard Worker return 1;
520*2d543d20SAndroid Build Coastguard Worker }
521*2d543d20SAndroid Build Coastguard Worker
522*2d543d20SAndroid Build Coastguard Worker /*
523*2d543d20SAndroid Build Coastguard Worker * Evaluate the association hash table distribution.
524*2d543d20SAndroid Build Coastguard Worker */
525*2d543d20SAndroid Build Coastguard Worker #ifdef DEBUG
filespec_eval(void)526*2d543d20SAndroid Build Coastguard Worker static void filespec_eval(void)
527*2d543d20SAndroid Build Coastguard Worker {
528*2d543d20SAndroid Build Coastguard Worker file_spec_t *fl;
529*2d543d20SAndroid Build Coastguard Worker uint32_t h;
530*2d543d20SAndroid Build Coastguard Worker size_t used, nel, len, longest;
531*2d543d20SAndroid Build Coastguard Worker
532*2d543d20SAndroid Build Coastguard Worker if (!fl_head)
533*2d543d20SAndroid Build Coastguard Worker return;
534*2d543d20SAndroid Build Coastguard Worker
535*2d543d20SAndroid Build Coastguard Worker used = 0;
536*2d543d20SAndroid Build Coastguard Worker longest = 0;
537*2d543d20SAndroid Build Coastguard Worker nel = 0;
538*2d543d20SAndroid Build Coastguard Worker for (h = 0; h < HASH_BUCKETS; h++) {
539*2d543d20SAndroid Build Coastguard Worker len = 0;
540*2d543d20SAndroid Build Coastguard Worker for (fl = fl_head[h].next; fl; fl = fl->next)
541*2d543d20SAndroid Build Coastguard Worker len++;
542*2d543d20SAndroid Build Coastguard Worker if (len)
543*2d543d20SAndroid Build Coastguard Worker used++;
544*2d543d20SAndroid Build Coastguard Worker if (len > longest)
545*2d543d20SAndroid Build Coastguard Worker longest = len;
546*2d543d20SAndroid Build Coastguard Worker nel += len;
547*2d543d20SAndroid Build Coastguard Worker }
548*2d543d20SAndroid Build Coastguard Worker
549*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_INFO,
550*2d543d20SAndroid Build Coastguard Worker "filespec hash table stats: %zu elements, %zu/%zu buckets used, longest chain length %zu\n",
551*2d543d20SAndroid Build Coastguard Worker nel, used, HASH_BUCKETS, longest);
552*2d543d20SAndroid Build Coastguard Worker }
553*2d543d20SAndroid Build Coastguard Worker #else
filespec_eval(void)554*2d543d20SAndroid Build Coastguard Worker static void filespec_eval(void)
555*2d543d20SAndroid Build Coastguard Worker {
556*2d543d20SAndroid Build Coastguard Worker }
557*2d543d20SAndroid Build Coastguard Worker #endif
558*2d543d20SAndroid Build Coastguard Worker
559*2d543d20SAndroid Build Coastguard Worker /*
560*2d543d20SAndroid Build Coastguard Worker * Destroy the association hash table.
561*2d543d20SAndroid Build Coastguard Worker */
filespec_destroy(void)562*2d543d20SAndroid Build Coastguard Worker static void filespec_destroy(void)
563*2d543d20SAndroid Build Coastguard Worker {
564*2d543d20SAndroid Build Coastguard Worker file_spec_t *fl, *tmp;
565*2d543d20SAndroid Build Coastguard Worker uint32_t h;
566*2d543d20SAndroid Build Coastguard Worker
567*2d543d20SAndroid Build Coastguard Worker if (!fl_head)
568*2d543d20SAndroid Build Coastguard Worker return;
569*2d543d20SAndroid Build Coastguard Worker
570*2d543d20SAndroid Build Coastguard Worker for (h = 0; h < HASH_BUCKETS; h++) {
571*2d543d20SAndroid Build Coastguard Worker fl = fl_head[h].next;
572*2d543d20SAndroid Build Coastguard Worker while (fl) {
573*2d543d20SAndroid Build Coastguard Worker tmp = fl;
574*2d543d20SAndroid Build Coastguard Worker fl = fl->next;
575*2d543d20SAndroid Build Coastguard Worker freecon(tmp->con);
576*2d543d20SAndroid Build Coastguard Worker free(tmp->file);
577*2d543d20SAndroid Build Coastguard Worker free(tmp);
578*2d543d20SAndroid Build Coastguard Worker }
579*2d543d20SAndroid Build Coastguard Worker fl_head[h].next = NULL;
580*2d543d20SAndroid Build Coastguard Worker }
581*2d543d20SAndroid Build Coastguard Worker free(fl_head);
582*2d543d20SAndroid Build Coastguard Worker fl_head = NULL;
583*2d543d20SAndroid Build Coastguard Worker }
584*2d543d20SAndroid Build Coastguard Worker
585*2d543d20SAndroid Build Coastguard Worker /*
586*2d543d20SAndroid Build Coastguard Worker * Called if SELINUX_RESTORECON_SET_SPECFILE_CTX is not set to check if
587*2d543d20SAndroid Build Coastguard Worker * the type components differ, updating newtypecon if so.
588*2d543d20SAndroid Build Coastguard Worker */
compare_types(const char * curcon,const char * newcon,char ** newtypecon)589*2d543d20SAndroid Build Coastguard Worker static int compare_types(const char *curcon, const char *newcon, char **newtypecon)
590*2d543d20SAndroid Build Coastguard Worker {
591*2d543d20SAndroid Build Coastguard Worker int types_differ = 0;
592*2d543d20SAndroid Build Coastguard Worker context_t cona;
593*2d543d20SAndroid Build Coastguard Worker context_t conb;
594*2d543d20SAndroid Build Coastguard Worker int rc = 0;
595*2d543d20SAndroid Build Coastguard Worker
596*2d543d20SAndroid Build Coastguard Worker cona = context_new(curcon);
597*2d543d20SAndroid Build Coastguard Worker if (!cona) {
598*2d543d20SAndroid Build Coastguard Worker rc = -1;
599*2d543d20SAndroid Build Coastguard Worker goto out;
600*2d543d20SAndroid Build Coastguard Worker }
601*2d543d20SAndroid Build Coastguard Worker conb = context_new(newcon);
602*2d543d20SAndroid Build Coastguard Worker if (!conb) {
603*2d543d20SAndroid Build Coastguard Worker context_free(cona);
604*2d543d20SAndroid Build Coastguard Worker rc = -1;
605*2d543d20SAndroid Build Coastguard Worker goto out;
606*2d543d20SAndroid Build Coastguard Worker }
607*2d543d20SAndroid Build Coastguard Worker
608*2d543d20SAndroid Build Coastguard Worker types_differ = strcmp(context_type_get(cona), context_type_get(conb));
609*2d543d20SAndroid Build Coastguard Worker if (types_differ) {
610*2d543d20SAndroid Build Coastguard Worker rc |= context_user_set(conb, context_user_get(cona));
611*2d543d20SAndroid Build Coastguard Worker rc |= context_role_set(conb, context_role_get(cona));
612*2d543d20SAndroid Build Coastguard Worker rc |= context_range_set(conb, context_range_get(cona));
613*2d543d20SAndroid Build Coastguard Worker if (!rc) {
614*2d543d20SAndroid Build Coastguard Worker *newtypecon = strdup(context_str(conb));
615*2d543d20SAndroid Build Coastguard Worker if (!*newtypecon) {
616*2d543d20SAndroid Build Coastguard Worker rc = -1;
617*2d543d20SAndroid Build Coastguard Worker goto err;
618*2d543d20SAndroid Build Coastguard Worker }
619*2d543d20SAndroid Build Coastguard Worker }
620*2d543d20SAndroid Build Coastguard Worker }
621*2d543d20SAndroid Build Coastguard Worker
622*2d543d20SAndroid Build Coastguard Worker err:
623*2d543d20SAndroid Build Coastguard Worker context_free(cona);
624*2d543d20SAndroid Build Coastguard Worker context_free(conb);
625*2d543d20SAndroid Build Coastguard Worker out:
626*2d543d20SAndroid Build Coastguard Worker return rc;
627*2d543d20SAndroid Build Coastguard Worker }
628*2d543d20SAndroid Build Coastguard Worker
restorecon_sb(const char * pathname,const struct stat * sb,const struct rest_flags * flags,bool first)629*2d543d20SAndroid Build Coastguard Worker static int restorecon_sb(const char *pathname, const struct stat *sb,
630*2d543d20SAndroid Build Coastguard Worker const struct rest_flags *flags, bool first)
631*2d543d20SAndroid Build Coastguard Worker {
632*2d543d20SAndroid Build Coastguard Worker char *newcon = NULL;
633*2d543d20SAndroid Build Coastguard Worker char *curcon = NULL;
634*2d543d20SAndroid Build Coastguard Worker char *newtypecon = NULL;
635*2d543d20SAndroid Build Coastguard Worker int rc;
636*2d543d20SAndroid Build Coastguard Worker const char *lookup_path = pathname;
637*2d543d20SAndroid Build Coastguard Worker
638*2d543d20SAndroid Build Coastguard Worker if (rootpath) {
639*2d543d20SAndroid Build Coastguard Worker if (strncmp(rootpath, lookup_path, rootpathlen) != 0) {
640*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
641*2d543d20SAndroid Build Coastguard Worker "%s is not located in alt_rootpath %s\n",
642*2d543d20SAndroid Build Coastguard Worker lookup_path, rootpath);
643*2d543d20SAndroid Build Coastguard Worker return -1;
644*2d543d20SAndroid Build Coastguard Worker }
645*2d543d20SAndroid Build Coastguard Worker lookup_path += rootpathlen;
646*2d543d20SAndroid Build Coastguard Worker }
647*2d543d20SAndroid Build Coastguard Worker
648*2d543d20SAndroid Build Coastguard Worker if (rootpath != NULL && lookup_path[0] == '\0')
649*2d543d20SAndroid Build Coastguard Worker /* this is actually the root dir of the alt root. */
650*2d543d20SAndroid Build Coastguard Worker rc = selabel_lookup_raw(fc_sehandle, &newcon, "/",
651*2d543d20SAndroid Build Coastguard Worker sb->st_mode & S_IFMT);
652*2d543d20SAndroid Build Coastguard Worker else
653*2d543d20SAndroid Build Coastguard Worker rc = selabel_lookup_raw(fc_sehandle, &newcon, lookup_path,
654*2d543d20SAndroid Build Coastguard Worker sb->st_mode & S_IFMT);
655*2d543d20SAndroid Build Coastguard Worker
656*2d543d20SAndroid Build Coastguard Worker if (rc < 0) {
657*2d543d20SAndroid Build Coastguard Worker if (errno == ENOENT) {
658*2d543d20SAndroid Build Coastguard Worker if (flags->warnonnomatch && first)
659*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_INFO,
660*2d543d20SAndroid Build Coastguard Worker "Warning no default label for %s\n",
661*2d543d20SAndroid Build Coastguard Worker lookup_path);
662*2d543d20SAndroid Build Coastguard Worker
663*2d543d20SAndroid Build Coastguard Worker return 0; /* no match, but not an error */
664*2d543d20SAndroid Build Coastguard Worker }
665*2d543d20SAndroid Build Coastguard Worker
666*2d543d20SAndroid Build Coastguard Worker return -1;
667*2d543d20SAndroid Build Coastguard Worker }
668*2d543d20SAndroid Build Coastguard Worker
669*2d543d20SAndroid Build Coastguard Worker if (flags->progress) {
670*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_lock(&progress_mutex);
671*2d543d20SAndroid Build Coastguard Worker fc_count++;
672*2d543d20SAndroid Build Coastguard Worker if (fc_count % STAR_COUNT == 0) {
673*2d543d20SAndroid Build Coastguard Worker if (flags->mass_relabel && efile_count > 0) {
674*2d543d20SAndroid Build Coastguard Worker float pc = (fc_count < efile_count) ? (100.0 *
675*2d543d20SAndroid Build Coastguard Worker fc_count / efile_count) : 100;
676*2d543d20SAndroid Build Coastguard Worker fprintf(stdout, "\r%-.1f%%", (double)pc);
677*2d543d20SAndroid Build Coastguard Worker } else {
678*2d543d20SAndroid Build Coastguard Worker fprintf(stdout, "\r%" PRIu64 "k", fc_count / STAR_COUNT);
679*2d543d20SAndroid Build Coastguard Worker }
680*2d543d20SAndroid Build Coastguard Worker fflush(stdout);
681*2d543d20SAndroid Build Coastguard Worker }
682*2d543d20SAndroid Build Coastguard Worker __pthread_mutex_unlock(&progress_mutex);
683*2d543d20SAndroid Build Coastguard Worker }
684*2d543d20SAndroid Build Coastguard Worker
685*2d543d20SAndroid Build Coastguard Worker if (flags->add_assoc) {
686*2d543d20SAndroid Build Coastguard Worker rc = filespec_add(sb->st_ino, newcon, pathname, flags);
687*2d543d20SAndroid Build Coastguard Worker
688*2d543d20SAndroid Build Coastguard Worker if (rc < 0) {
689*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
690*2d543d20SAndroid Build Coastguard Worker "filespec_add error: %s\n", pathname);
691*2d543d20SAndroid Build Coastguard Worker freecon(newcon);
692*2d543d20SAndroid Build Coastguard Worker return -1;
693*2d543d20SAndroid Build Coastguard Worker }
694*2d543d20SAndroid Build Coastguard Worker
695*2d543d20SAndroid Build Coastguard Worker if (rc > 0) {
696*2d543d20SAndroid Build Coastguard Worker /* Already an association and it took precedence. */
697*2d543d20SAndroid Build Coastguard Worker freecon(newcon);
698*2d543d20SAndroid Build Coastguard Worker return 0;
699*2d543d20SAndroid Build Coastguard Worker }
700*2d543d20SAndroid Build Coastguard Worker }
701*2d543d20SAndroid Build Coastguard Worker
702*2d543d20SAndroid Build Coastguard Worker if (flags->log_matches)
703*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_INFO, "%s matched by %s\n",
704*2d543d20SAndroid Build Coastguard Worker pathname, newcon);
705*2d543d20SAndroid Build Coastguard Worker
706*2d543d20SAndroid Build Coastguard Worker if (lgetfilecon_raw(pathname, &curcon) < 0) {
707*2d543d20SAndroid Build Coastguard Worker if (errno != ENODATA)
708*2d543d20SAndroid Build Coastguard Worker goto err;
709*2d543d20SAndroid Build Coastguard Worker
710*2d543d20SAndroid Build Coastguard Worker curcon = NULL;
711*2d543d20SAndroid Build Coastguard Worker }
712*2d543d20SAndroid Build Coastguard Worker
713*2d543d20SAndroid Build Coastguard Worker if (curcon == NULL || strcmp(curcon, newcon) != 0) {
714*2d543d20SAndroid Build Coastguard Worker bool updated = false;
715*2d543d20SAndroid Build Coastguard Worker
716*2d543d20SAndroid Build Coastguard Worker if (!flags->set_specctx && curcon &&
717*2d543d20SAndroid Build Coastguard Worker (is_context_customizable(curcon) > 0)) {
718*2d543d20SAndroid Build Coastguard Worker if (flags->verbose) {
719*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_INFO,
720*2d543d20SAndroid Build Coastguard Worker "%s not reset as customized by admin to %s\n",
721*2d543d20SAndroid Build Coastguard Worker pathname, curcon);
722*2d543d20SAndroid Build Coastguard Worker }
723*2d543d20SAndroid Build Coastguard Worker goto out;
724*2d543d20SAndroid Build Coastguard Worker }
725*2d543d20SAndroid Build Coastguard Worker
726*2d543d20SAndroid Build Coastguard Worker if (!flags->set_specctx && curcon) {
727*2d543d20SAndroid Build Coastguard Worker /* If types different then update newcon. */
728*2d543d20SAndroid Build Coastguard Worker rc = compare_types(curcon, newcon, &newtypecon);
729*2d543d20SAndroid Build Coastguard Worker if (rc)
730*2d543d20SAndroid Build Coastguard Worker goto err;
731*2d543d20SAndroid Build Coastguard Worker
732*2d543d20SAndroid Build Coastguard Worker if (newtypecon) {
733*2d543d20SAndroid Build Coastguard Worker freecon(newcon);
734*2d543d20SAndroid Build Coastguard Worker newcon = newtypecon;
735*2d543d20SAndroid Build Coastguard Worker } else {
736*2d543d20SAndroid Build Coastguard Worker goto out;
737*2d543d20SAndroid Build Coastguard Worker }
738*2d543d20SAndroid Build Coastguard Worker }
739*2d543d20SAndroid Build Coastguard Worker
740*2d543d20SAndroid Build Coastguard Worker if (!flags->nochange) {
741*2d543d20SAndroid Build Coastguard Worker if (lsetfilecon(pathname, newcon) < 0)
742*2d543d20SAndroid Build Coastguard Worker goto err;
743*2d543d20SAndroid Build Coastguard Worker updated = true;
744*2d543d20SAndroid Build Coastguard Worker }
745*2d543d20SAndroid Build Coastguard Worker
746*2d543d20SAndroid Build Coastguard Worker if (flags->verbose)
747*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_INFO,
748*2d543d20SAndroid Build Coastguard Worker "%s %s from %s to %s\n",
749*2d543d20SAndroid Build Coastguard Worker updated ? "Relabeled" : "Would relabel",
750*2d543d20SAndroid Build Coastguard Worker pathname,
751*2d543d20SAndroid Build Coastguard Worker curcon ? curcon : "<no context>",
752*2d543d20SAndroid Build Coastguard Worker newcon);
753*2d543d20SAndroid Build Coastguard Worker
754*2d543d20SAndroid Build Coastguard Worker if (flags->syslog_changes && !flags->nochange) {
755*2d543d20SAndroid Build Coastguard Worker if (curcon)
756*2d543d20SAndroid Build Coastguard Worker syslog(LOG_INFO,
757*2d543d20SAndroid Build Coastguard Worker "relabeling %s from %s to %s\n",
758*2d543d20SAndroid Build Coastguard Worker pathname, curcon, newcon);
759*2d543d20SAndroid Build Coastguard Worker else
760*2d543d20SAndroid Build Coastguard Worker syslog(LOG_INFO, "labeling %s to %s\n",
761*2d543d20SAndroid Build Coastguard Worker pathname, newcon);
762*2d543d20SAndroid Build Coastguard Worker }
763*2d543d20SAndroid Build Coastguard Worker }
764*2d543d20SAndroid Build Coastguard Worker
765*2d543d20SAndroid Build Coastguard Worker out:
766*2d543d20SAndroid Build Coastguard Worker rc = 0;
767*2d543d20SAndroid Build Coastguard Worker out1:
768*2d543d20SAndroid Build Coastguard Worker freecon(curcon);
769*2d543d20SAndroid Build Coastguard Worker freecon(newcon);
770*2d543d20SAndroid Build Coastguard Worker return rc;
771*2d543d20SAndroid Build Coastguard Worker err:
772*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
773*2d543d20SAndroid Build Coastguard Worker "Could not set context for %s: %m\n",
774*2d543d20SAndroid Build Coastguard Worker pathname);
775*2d543d20SAndroid Build Coastguard Worker rc = -1;
776*2d543d20SAndroid Build Coastguard Worker goto out1;
777*2d543d20SAndroid Build Coastguard Worker }
778*2d543d20SAndroid Build Coastguard Worker
779*2d543d20SAndroid Build Coastguard Worker struct dir_hash_node {
780*2d543d20SAndroid Build Coastguard Worker char *path;
781*2d543d20SAndroid Build Coastguard Worker uint8_t digest[SHA1_HASH_SIZE];
782*2d543d20SAndroid Build Coastguard Worker struct dir_hash_node *next;
783*2d543d20SAndroid Build Coastguard Worker };
784*2d543d20SAndroid Build Coastguard Worker /*
785*2d543d20SAndroid Build Coastguard Worker * Returns true if the digest of all partial matched contexts is the same as
786*2d543d20SAndroid Build Coastguard Worker * the one saved by setxattr. Otherwise returns false and constructs a
787*2d543d20SAndroid Build Coastguard Worker * dir_hash_node with the newly calculated digest.
788*2d543d20SAndroid Build Coastguard Worker */
check_context_match_for_dir(const char * pathname,struct dir_hash_node ** new_node,int error)789*2d543d20SAndroid Build Coastguard Worker static bool check_context_match_for_dir(const char *pathname,
790*2d543d20SAndroid Build Coastguard Worker struct dir_hash_node **new_node,
791*2d543d20SAndroid Build Coastguard Worker int error)
792*2d543d20SAndroid Build Coastguard Worker {
793*2d543d20SAndroid Build Coastguard Worker bool status;
794*2d543d20SAndroid Build Coastguard Worker size_t digest_len = 0;
795*2d543d20SAndroid Build Coastguard Worker uint8_t *read_digest = NULL;
796*2d543d20SAndroid Build Coastguard Worker uint8_t *calculated_digest = NULL;
797*2d543d20SAndroid Build Coastguard Worker
798*2d543d20SAndroid Build Coastguard Worker if (!new_node)
799*2d543d20SAndroid Build Coastguard Worker return false;
800*2d543d20SAndroid Build Coastguard Worker
801*2d543d20SAndroid Build Coastguard Worker *new_node = NULL;
802*2d543d20SAndroid Build Coastguard Worker
803*2d543d20SAndroid Build Coastguard Worker /* status = true if digests match, false otherwise. */
804*2d543d20SAndroid Build Coastguard Worker status = selabel_get_digests_all_partial_matches(fc_sehandle, pathname,
805*2d543d20SAndroid Build Coastguard Worker &calculated_digest,
806*2d543d20SAndroid Build Coastguard Worker &read_digest,
807*2d543d20SAndroid Build Coastguard Worker &digest_len);
808*2d543d20SAndroid Build Coastguard Worker
809*2d543d20SAndroid Build Coastguard Worker if (status)
810*2d543d20SAndroid Build Coastguard Worker goto free;
811*2d543d20SAndroid Build Coastguard Worker
812*2d543d20SAndroid Build Coastguard Worker /* Save digest of all matched contexts for the current directory. */
813*2d543d20SAndroid Build Coastguard Worker if (!error && calculated_digest) {
814*2d543d20SAndroid Build Coastguard Worker *new_node = calloc(1, sizeof(struct dir_hash_node));
815*2d543d20SAndroid Build Coastguard Worker
816*2d543d20SAndroid Build Coastguard Worker if (!*new_node)
817*2d543d20SAndroid Build Coastguard Worker goto oom;
818*2d543d20SAndroid Build Coastguard Worker
819*2d543d20SAndroid Build Coastguard Worker (*new_node)->path = strdup(pathname);
820*2d543d20SAndroid Build Coastguard Worker
821*2d543d20SAndroid Build Coastguard Worker if (!(*new_node)->path) {
822*2d543d20SAndroid Build Coastguard Worker free(*new_node);
823*2d543d20SAndroid Build Coastguard Worker *new_node = NULL;
824*2d543d20SAndroid Build Coastguard Worker goto oom;
825*2d543d20SAndroid Build Coastguard Worker }
826*2d543d20SAndroid Build Coastguard Worker memcpy((*new_node)->digest, calculated_digest, digest_len);
827*2d543d20SAndroid Build Coastguard Worker (*new_node)->next = NULL;
828*2d543d20SAndroid Build Coastguard Worker }
829*2d543d20SAndroid Build Coastguard Worker
830*2d543d20SAndroid Build Coastguard Worker free:
831*2d543d20SAndroid Build Coastguard Worker free(calculated_digest);
832*2d543d20SAndroid Build Coastguard Worker free(read_digest);
833*2d543d20SAndroid Build Coastguard Worker return status;
834*2d543d20SAndroid Build Coastguard Worker
835*2d543d20SAndroid Build Coastguard Worker oom:
836*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__);
837*2d543d20SAndroid Build Coastguard Worker goto free;
838*2d543d20SAndroid Build Coastguard Worker }
839*2d543d20SAndroid Build Coastguard Worker
840*2d543d20SAndroid Build Coastguard Worker struct rest_state {
841*2d543d20SAndroid Build Coastguard Worker struct rest_flags flags;
842*2d543d20SAndroid Build Coastguard Worker dev_t dev_num;
843*2d543d20SAndroid Build Coastguard Worker struct statfs sfsb;
844*2d543d20SAndroid Build Coastguard Worker bool ignore_digest;
845*2d543d20SAndroid Build Coastguard Worker bool setrestorecondigest;
846*2d543d20SAndroid Build Coastguard Worker bool parallel;
847*2d543d20SAndroid Build Coastguard Worker
848*2d543d20SAndroid Build Coastguard Worker FTS *fts;
849*2d543d20SAndroid Build Coastguard Worker FTSENT *ftsent_first;
850*2d543d20SAndroid Build Coastguard Worker struct dir_hash_node *head, *current;
851*2d543d20SAndroid Build Coastguard Worker bool abort;
852*2d543d20SAndroid Build Coastguard Worker int error;
853*2d543d20SAndroid Build Coastguard Worker long unsigned skipped_errors;
854*2d543d20SAndroid Build Coastguard Worker int saved_errno;
855*2d543d20SAndroid Build Coastguard Worker pthread_mutex_t mutex;
856*2d543d20SAndroid Build Coastguard Worker };
857*2d543d20SAndroid Build Coastguard Worker
selinux_restorecon_thread(void * arg)858*2d543d20SAndroid Build Coastguard Worker static void *selinux_restorecon_thread(void *arg)
859*2d543d20SAndroid Build Coastguard Worker {
860*2d543d20SAndroid Build Coastguard Worker struct rest_state *state = arg;
861*2d543d20SAndroid Build Coastguard Worker FTS *fts = state->fts;
862*2d543d20SAndroid Build Coastguard Worker FTSENT *ftsent;
863*2d543d20SAndroid Build Coastguard Worker int error;
864*2d543d20SAndroid Build Coastguard Worker char ent_path[PATH_MAX];
865*2d543d20SAndroid Build Coastguard Worker struct stat ent_st;
866*2d543d20SAndroid Build Coastguard Worker bool first = false;
867*2d543d20SAndroid Build Coastguard Worker
868*2d543d20SAndroid Build Coastguard Worker if (state->parallel)
869*2d543d20SAndroid Build Coastguard Worker pthread_mutex_lock(&state->mutex);
870*2d543d20SAndroid Build Coastguard Worker
871*2d543d20SAndroid Build Coastguard Worker if (state->ftsent_first) {
872*2d543d20SAndroid Build Coastguard Worker ftsent = state->ftsent_first;
873*2d543d20SAndroid Build Coastguard Worker state->ftsent_first = NULL;
874*2d543d20SAndroid Build Coastguard Worker first = true;
875*2d543d20SAndroid Build Coastguard Worker goto loop_body;
876*2d543d20SAndroid Build Coastguard Worker }
877*2d543d20SAndroid Build Coastguard Worker
878*2d543d20SAndroid Build Coastguard Worker while (((void)(errno = 0), ftsent = fts_read(fts)) != NULL) {
879*2d543d20SAndroid Build Coastguard Worker loop_body:
880*2d543d20SAndroid Build Coastguard Worker /* If the FTS_XDEV flag is set and the device is different */
881*2d543d20SAndroid Build Coastguard Worker if (state->flags.set_xdev &&
882*2d543d20SAndroid Build Coastguard Worker ftsent->fts_statp->st_dev != state->dev_num)
883*2d543d20SAndroid Build Coastguard Worker continue;
884*2d543d20SAndroid Build Coastguard Worker
885*2d543d20SAndroid Build Coastguard Worker switch (ftsent->fts_info) {
886*2d543d20SAndroid Build Coastguard Worker case FTS_DC:
887*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
888*2d543d20SAndroid Build Coastguard Worker "Directory cycle on %s.\n",
889*2d543d20SAndroid Build Coastguard Worker ftsent->fts_path);
890*2d543d20SAndroid Build Coastguard Worker errno = ELOOP;
891*2d543d20SAndroid Build Coastguard Worker state->error = -1;
892*2d543d20SAndroid Build Coastguard Worker state->abort = true;
893*2d543d20SAndroid Build Coastguard Worker goto finish;
894*2d543d20SAndroid Build Coastguard Worker case FTS_DP:
895*2d543d20SAndroid Build Coastguard Worker continue;
896*2d543d20SAndroid Build Coastguard Worker case FTS_DNR:
897*2d543d20SAndroid Build Coastguard Worker error = errno;
898*2d543d20SAndroid Build Coastguard Worker errno = ftsent->fts_errno;
899*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
900*2d543d20SAndroid Build Coastguard Worker "Could not read %s: %m.\n",
901*2d543d20SAndroid Build Coastguard Worker ftsent->fts_path);
902*2d543d20SAndroid Build Coastguard Worker errno = error;
903*2d543d20SAndroid Build Coastguard Worker fts_set(fts, ftsent, FTS_SKIP);
904*2d543d20SAndroid Build Coastguard Worker continue;
905*2d543d20SAndroid Build Coastguard Worker case FTS_NS:
906*2d543d20SAndroid Build Coastguard Worker error = errno;
907*2d543d20SAndroid Build Coastguard Worker errno = ftsent->fts_errno;
908*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
909*2d543d20SAndroid Build Coastguard Worker "Could not stat %s: %m.\n",
910*2d543d20SAndroid Build Coastguard Worker ftsent->fts_path);
911*2d543d20SAndroid Build Coastguard Worker errno = error;
912*2d543d20SAndroid Build Coastguard Worker fts_set(fts, ftsent, FTS_SKIP);
913*2d543d20SAndroid Build Coastguard Worker continue;
914*2d543d20SAndroid Build Coastguard Worker case FTS_ERR:
915*2d543d20SAndroid Build Coastguard Worker error = errno;
916*2d543d20SAndroid Build Coastguard Worker errno = ftsent->fts_errno;
917*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
918*2d543d20SAndroid Build Coastguard Worker "Error on %s: %m.\n",
919*2d543d20SAndroid Build Coastguard Worker ftsent->fts_path);
920*2d543d20SAndroid Build Coastguard Worker errno = error;
921*2d543d20SAndroid Build Coastguard Worker fts_set(fts, ftsent, FTS_SKIP);
922*2d543d20SAndroid Build Coastguard Worker continue;
923*2d543d20SAndroid Build Coastguard Worker case FTS_D:
924*2d543d20SAndroid Build Coastguard Worker if (state->sfsb.f_type == SYSFS_MAGIC &&
925*2d543d20SAndroid Build Coastguard Worker !selabel_partial_match(fc_sehandle,
926*2d543d20SAndroid Build Coastguard Worker ftsent->fts_path)) {
927*2d543d20SAndroid Build Coastguard Worker fts_set(fts, ftsent, FTS_SKIP);
928*2d543d20SAndroid Build Coastguard Worker continue;
929*2d543d20SAndroid Build Coastguard Worker }
930*2d543d20SAndroid Build Coastguard Worker
931*2d543d20SAndroid Build Coastguard Worker if (check_excluded(ftsent->fts_path)) {
932*2d543d20SAndroid Build Coastguard Worker fts_set(fts, ftsent, FTS_SKIP);
933*2d543d20SAndroid Build Coastguard Worker continue;
934*2d543d20SAndroid Build Coastguard Worker }
935*2d543d20SAndroid Build Coastguard Worker
936*2d543d20SAndroid Build Coastguard Worker if (state->setrestorecondigest) {
937*2d543d20SAndroid Build Coastguard Worker struct dir_hash_node *new_node = NULL;
938*2d543d20SAndroid Build Coastguard Worker
939*2d543d20SAndroid Build Coastguard Worker if (check_context_match_for_dir(ftsent->fts_path,
940*2d543d20SAndroid Build Coastguard Worker &new_node,
941*2d543d20SAndroid Build Coastguard Worker state->error) &&
942*2d543d20SAndroid Build Coastguard Worker !state->ignore_digest) {
943*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_INFO,
944*2d543d20SAndroid Build Coastguard Worker "Skipping restorecon on directory(%s)\n",
945*2d543d20SAndroid Build Coastguard Worker ftsent->fts_path);
946*2d543d20SAndroid Build Coastguard Worker fts_set(fts, ftsent, FTS_SKIP);
947*2d543d20SAndroid Build Coastguard Worker continue;
948*2d543d20SAndroid Build Coastguard Worker }
949*2d543d20SAndroid Build Coastguard Worker
950*2d543d20SAndroid Build Coastguard Worker if (new_node && !state->error) {
951*2d543d20SAndroid Build Coastguard Worker if (!state->current) {
952*2d543d20SAndroid Build Coastguard Worker state->current = new_node;
953*2d543d20SAndroid Build Coastguard Worker state->head = state->current;
954*2d543d20SAndroid Build Coastguard Worker } else {
955*2d543d20SAndroid Build Coastguard Worker state->current->next = new_node;
956*2d543d20SAndroid Build Coastguard Worker state->current = new_node;
957*2d543d20SAndroid Build Coastguard Worker }
958*2d543d20SAndroid Build Coastguard Worker }
959*2d543d20SAndroid Build Coastguard Worker }
960*2d543d20SAndroid Build Coastguard Worker /* fall through */
961*2d543d20SAndroid Build Coastguard Worker default:
962*2d543d20SAndroid Build Coastguard Worker if (strlcpy(ent_path, ftsent->fts_path, sizeof(ent_path)) >= sizeof(ent_path)) {
963*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
964*2d543d20SAndroid Build Coastguard Worker "Path name too long on %s.\n",
965*2d543d20SAndroid Build Coastguard Worker ftsent->fts_path);
966*2d543d20SAndroid Build Coastguard Worker errno = ENAMETOOLONG;
967*2d543d20SAndroid Build Coastguard Worker state->error = -1;
968*2d543d20SAndroid Build Coastguard Worker state->abort = true;
969*2d543d20SAndroid Build Coastguard Worker goto finish;
970*2d543d20SAndroid Build Coastguard Worker }
971*2d543d20SAndroid Build Coastguard Worker
972*2d543d20SAndroid Build Coastguard Worker ent_st = *ftsent->fts_statp;
973*2d543d20SAndroid Build Coastguard Worker if (state->parallel)
974*2d543d20SAndroid Build Coastguard Worker pthread_mutex_unlock(&state->mutex);
975*2d543d20SAndroid Build Coastguard Worker
976*2d543d20SAndroid Build Coastguard Worker error = restorecon_sb(ent_path, &ent_st, &state->flags,
977*2d543d20SAndroid Build Coastguard Worker first);
978*2d543d20SAndroid Build Coastguard Worker
979*2d543d20SAndroid Build Coastguard Worker if (state->parallel) {
980*2d543d20SAndroid Build Coastguard Worker pthread_mutex_lock(&state->mutex);
981*2d543d20SAndroid Build Coastguard Worker if (state->abort)
982*2d543d20SAndroid Build Coastguard Worker goto unlock;
983*2d543d20SAndroid Build Coastguard Worker }
984*2d543d20SAndroid Build Coastguard Worker
985*2d543d20SAndroid Build Coastguard Worker first = false;
986*2d543d20SAndroid Build Coastguard Worker if (error) {
987*2d543d20SAndroid Build Coastguard Worker if (state->flags.abort_on_error) {
988*2d543d20SAndroid Build Coastguard Worker state->error = error;
989*2d543d20SAndroid Build Coastguard Worker state->abort = true;
990*2d543d20SAndroid Build Coastguard Worker goto finish;
991*2d543d20SAndroid Build Coastguard Worker }
992*2d543d20SAndroid Build Coastguard Worker if (state->flags.count_errors)
993*2d543d20SAndroid Build Coastguard Worker state->skipped_errors++;
994*2d543d20SAndroid Build Coastguard Worker else
995*2d543d20SAndroid Build Coastguard Worker state->error = error;
996*2d543d20SAndroid Build Coastguard Worker }
997*2d543d20SAndroid Build Coastguard Worker break;
998*2d543d20SAndroid Build Coastguard Worker }
999*2d543d20SAndroid Build Coastguard Worker }
1000*2d543d20SAndroid Build Coastguard Worker
1001*2d543d20SAndroid Build Coastguard Worker finish:
1002*2d543d20SAndroid Build Coastguard Worker if (!state->saved_errno)
1003*2d543d20SAndroid Build Coastguard Worker state->saved_errno = errno;
1004*2d543d20SAndroid Build Coastguard Worker unlock:
1005*2d543d20SAndroid Build Coastguard Worker if (state->parallel)
1006*2d543d20SAndroid Build Coastguard Worker pthread_mutex_unlock(&state->mutex);
1007*2d543d20SAndroid Build Coastguard Worker return NULL;
1008*2d543d20SAndroid Build Coastguard Worker }
1009*2d543d20SAndroid Build Coastguard Worker
selinux_restorecon_common(const char * pathname_orig,unsigned int restorecon_flags,size_t nthreads)1010*2d543d20SAndroid Build Coastguard Worker static int selinux_restorecon_common(const char *pathname_orig,
1011*2d543d20SAndroid Build Coastguard Worker unsigned int restorecon_flags,
1012*2d543d20SAndroid Build Coastguard Worker size_t nthreads)
1013*2d543d20SAndroid Build Coastguard Worker {
1014*2d543d20SAndroid Build Coastguard Worker struct rest_state state;
1015*2d543d20SAndroid Build Coastguard Worker
1016*2d543d20SAndroid Build Coastguard Worker state.flags.nochange = (restorecon_flags &
1017*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_NOCHANGE) ? true : false;
1018*2d543d20SAndroid Build Coastguard Worker state.flags.verbose = (restorecon_flags &
1019*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_VERBOSE) ? true : false;
1020*2d543d20SAndroid Build Coastguard Worker state.flags.progress = (restorecon_flags &
1021*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_PROGRESS) ? true : false;
1022*2d543d20SAndroid Build Coastguard Worker state.flags.mass_relabel = (restorecon_flags &
1023*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_MASS_RELABEL) ? true : false;
1024*2d543d20SAndroid Build Coastguard Worker state.flags.recurse = (restorecon_flags &
1025*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_RECURSE) ? true : false;
1026*2d543d20SAndroid Build Coastguard Worker state.flags.set_specctx = (restorecon_flags &
1027*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_SET_SPECFILE_CTX) ? true : false;
1028*2d543d20SAndroid Build Coastguard Worker state.flags.userealpath = (restorecon_flags &
1029*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_REALPATH) ? true : false;
1030*2d543d20SAndroid Build Coastguard Worker state.flags.set_xdev = (restorecon_flags &
1031*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_XDEV) ? true : false;
1032*2d543d20SAndroid Build Coastguard Worker state.flags.add_assoc = (restorecon_flags &
1033*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_ADD_ASSOC) ? true : false;
1034*2d543d20SAndroid Build Coastguard Worker state.flags.abort_on_error = (restorecon_flags &
1035*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_ABORT_ON_ERROR) ? true : false;
1036*2d543d20SAndroid Build Coastguard Worker state.flags.syslog_changes = (restorecon_flags &
1037*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_SYSLOG_CHANGES) ? true : false;
1038*2d543d20SAndroid Build Coastguard Worker state.flags.log_matches = (restorecon_flags &
1039*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_LOG_MATCHES) ? true : false;
1040*2d543d20SAndroid Build Coastguard Worker state.flags.ignore_noent = (restorecon_flags &
1041*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_IGNORE_NOENTRY) ? true : false;
1042*2d543d20SAndroid Build Coastguard Worker state.flags.warnonnomatch = true;
1043*2d543d20SAndroid Build Coastguard Worker state.flags.conflicterror = (restorecon_flags &
1044*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_CONFLICT_ERROR) ? true : false;
1045*2d543d20SAndroid Build Coastguard Worker ignore_mounts = (restorecon_flags &
1046*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_IGNORE_MOUNTS) ? true : false;
1047*2d543d20SAndroid Build Coastguard Worker state.ignore_digest = (restorecon_flags &
1048*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_IGNORE_DIGEST) ? true : false;
1049*2d543d20SAndroid Build Coastguard Worker state.flags.count_errors = (restorecon_flags &
1050*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_COUNT_ERRORS) ? true : false;
1051*2d543d20SAndroid Build Coastguard Worker state.setrestorecondigest = true;
1052*2d543d20SAndroid Build Coastguard Worker
1053*2d543d20SAndroid Build Coastguard Worker state.head = NULL;
1054*2d543d20SAndroid Build Coastguard Worker state.current = NULL;
1055*2d543d20SAndroid Build Coastguard Worker state.abort = false;
1056*2d543d20SAndroid Build Coastguard Worker state.error = 0;
1057*2d543d20SAndroid Build Coastguard Worker state.skipped_errors = 0;
1058*2d543d20SAndroid Build Coastguard Worker state.saved_errno = 0;
1059*2d543d20SAndroid Build Coastguard Worker
1060*2d543d20SAndroid Build Coastguard Worker struct stat sb;
1061*2d543d20SAndroid Build Coastguard Worker char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname;
1062*2d543d20SAndroid Build Coastguard Worker char *paths[2] = { NULL, NULL };
1063*2d543d20SAndroid Build Coastguard Worker int fts_flags, error;
1064*2d543d20SAndroid Build Coastguard Worker struct dir_hash_node *current = NULL;
1065*2d543d20SAndroid Build Coastguard Worker
1066*2d543d20SAndroid Build Coastguard Worker if (state.flags.verbose && state.flags.progress)
1067*2d543d20SAndroid Build Coastguard Worker state.flags.verbose = false;
1068*2d543d20SAndroid Build Coastguard Worker
1069*2d543d20SAndroid Build Coastguard Worker __selinux_once(fc_once, restorecon_init);
1070*2d543d20SAndroid Build Coastguard Worker
1071*2d543d20SAndroid Build Coastguard Worker if (!fc_sehandle)
1072*2d543d20SAndroid Build Coastguard Worker return -1;
1073*2d543d20SAndroid Build Coastguard Worker
1074*2d543d20SAndroid Build Coastguard Worker /*
1075*2d543d20SAndroid Build Coastguard Worker * If selabel_no_digest = true then no digest has been requested by
1076*2d543d20SAndroid Build Coastguard Worker * an external selabel_open(3) call.
1077*2d543d20SAndroid Build Coastguard Worker */
1078*2d543d20SAndroid Build Coastguard Worker if (selabel_no_digest ||
1079*2d543d20SAndroid Build Coastguard Worker (restorecon_flags & SELINUX_RESTORECON_SKIP_DIGEST))
1080*2d543d20SAndroid Build Coastguard Worker state.setrestorecondigest = false;
1081*2d543d20SAndroid Build Coastguard Worker
1082*2d543d20SAndroid Build Coastguard Worker if (!__pthread_supported) {
1083*2d543d20SAndroid Build Coastguard Worker if (nthreads != 1) {
1084*2d543d20SAndroid Build Coastguard Worker nthreads = 1;
1085*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_WARNING,
1086*2d543d20SAndroid Build Coastguard Worker "Threading functionality not available, falling back to 1 thread.");
1087*2d543d20SAndroid Build Coastguard Worker }
1088*2d543d20SAndroid Build Coastguard Worker } else if (nthreads == 0) {
1089*2d543d20SAndroid Build Coastguard Worker long nproc = sysconf(_SC_NPROCESSORS_ONLN);
1090*2d543d20SAndroid Build Coastguard Worker
1091*2d543d20SAndroid Build Coastguard Worker if (nproc > 0) {
1092*2d543d20SAndroid Build Coastguard Worker nthreads = nproc;
1093*2d543d20SAndroid Build Coastguard Worker } else {
1094*2d543d20SAndroid Build Coastguard Worker nthreads = 1;
1095*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_WARNING,
1096*2d543d20SAndroid Build Coastguard Worker "Unable to detect CPU count, falling back to 1 thread.");
1097*2d543d20SAndroid Build Coastguard Worker }
1098*2d543d20SAndroid Build Coastguard Worker }
1099*2d543d20SAndroid Build Coastguard Worker
1100*2d543d20SAndroid Build Coastguard Worker /*
1101*2d543d20SAndroid Build Coastguard Worker * Convert passed-in pathname to canonical pathname by resolving
1102*2d543d20SAndroid Build Coastguard Worker * realpath of containing dir, then appending last component name.
1103*2d543d20SAndroid Build Coastguard Worker */
1104*2d543d20SAndroid Build Coastguard Worker if (state.flags.userealpath) {
1105*2d543d20SAndroid Build Coastguard Worker char *basename_cpy = strdup(pathname_orig);
1106*2d543d20SAndroid Build Coastguard Worker if (!basename_cpy)
1107*2d543d20SAndroid Build Coastguard Worker goto realpatherr;
1108*2d543d20SAndroid Build Coastguard Worker pathbname = basename(basename_cpy);
1109*2d543d20SAndroid Build Coastguard Worker if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") ||
1110*2d543d20SAndroid Build Coastguard Worker !strcmp(pathbname, "..")) {
1111*2d543d20SAndroid Build Coastguard Worker pathname = realpath(pathname_orig, NULL);
1112*2d543d20SAndroid Build Coastguard Worker if (!pathname) {
1113*2d543d20SAndroid Build Coastguard Worker free(basename_cpy);
1114*2d543d20SAndroid Build Coastguard Worker /* missing parent directory */
1115*2d543d20SAndroid Build Coastguard Worker if (state.flags.ignore_noent && errno == ENOENT) {
1116*2d543d20SAndroid Build Coastguard Worker return 0;
1117*2d543d20SAndroid Build Coastguard Worker }
1118*2d543d20SAndroid Build Coastguard Worker goto realpatherr;
1119*2d543d20SAndroid Build Coastguard Worker }
1120*2d543d20SAndroid Build Coastguard Worker } else {
1121*2d543d20SAndroid Build Coastguard Worker char *dirname_cpy = strdup(pathname_orig);
1122*2d543d20SAndroid Build Coastguard Worker if (!dirname_cpy) {
1123*2d543d20SAndroid Build Coastguard Worker free(basename_cpy);
1124*2d543d20SAndroid Build Coastguard Worker goto realpatherr;
1125*2d543d20SAndroid Build Coastguard Worker }
1126*2d543d20SAndroid Build Coastguard Worker pathdname = dirname(dirname_cpy);
1127*2d543d20SAndroid Build Coastguard Worker pathdnamer = realpath(pathdname, NULL);
1128*2d543d20SAndroid Build Coastguard Worker free(dirname_cpy);
1129*2d543d20SAndroid Build Coastguard Worker if (!pathdnamer) {
1130*2d543d20SAndroid Build Coastguard Worker free(basename_cpy);
1131*2d543d20SAndroid Build Coastguard Worker if (state.flags.ignore_noent && errno == ENOENT) {
1132*2d543d20SAndroid Build Coastguard Worker return 0;
1133*2d543d20SAndroid Build Coastguard Worker }
1134*2d543d20SAndroid Build Coastguard Worker goto realpatherr;
1135*2d543d20SAndroid Build Coastguard Worker }
1136*2d543d20SAndroid Build Coastguard Worker if (!strcmp(pathdnamer, "/"))
1137*2d543d20SAndroid Build Coastguard Worker error = asprintf(&pathname, "/%s", pathbname);
1138*2d543d20SAndroid Build Coastguard Worker else
1139*2d543d20SAndroid Build Coastguard Worker error = asprintf(&pathname, "%s/%s",
1140*2d543d20SAndroid Build Coastguard Worker pathdnamer, pathbname);
1141*2d543d20SAndroid Build Coastguard Worker if (error < 0) {
1142*2d543d20SAndroid Build Coastguard Worker free(basename_cpy);
1143*2d543d20SAndroid Build Coastguard Worker goto oom;
1144*2d543d20SAndroid Build Coastguard Worker }
1145*2d543d20SAndroid Build Coastguard Worker }
1146*2d543d20SAndroid Build Coastguard Worker free(basename_cpy);
1147*2d543d20SAndroid Build Coastguard Worker } else {
1148*2d543d20SAndroid Build Coastguard Worker pathname = strdup(pathname_orig);
1149*2d543d20SAndroid Build Coastguard Worker if (!pathname)
1150*2d543d20SAndroid Build Coastguard Worker goto oom;
1151*2d543d20SAndroid Build Coastguard Worker }
1152*2d543d20SAndroid Build Coastguard Worker
1153*2d543d20SAndroid Build Coastguard Worker paths[0] = pathname;
1154*2d543d20SAndroid Build Coastguard Worker
1155*2d543d20SAndroid Build Coastguard Worker if (lstat(pathname, &sb) < 0) {
1156*2d543d20SAndroid Build Coastguard Worker if (state.flags.ignore_noent && errno == ENOENT) {
1157*2d543d20SAndroid Build Coastguard Worker free(pathdnamer);
1158*2d543d20SAndroid Build Coastguard Worker free(pathname);
1159*2d543d20SAndroid Build Coastguard Worker return 0;
1160*2d543d20SAndroid Build Coastguard Worker } else {
1161*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
1162*2d543d20SAndroid Build Coastguard Worker "lstat(%s) failed: %m\n",
1163*2d543d20SAndroid Build Coastguard Worker pathname);
1164*2d543d20SAndroid Build Coastguard Worker error = -1;
1165*2d543d20SAndroid Build Coastguard Worker goto cleanup;
1166*2d543d20SAndroid Build Coastguard Worker }
1167*2d543d20SAndroid Build Coastguard Worker }
1168*2d543d20SAndroid Build Coastguard Worker
1169*2d543d20SAndroid Build Coastguard Worker /* Skip digest if not a directory */
1170*2d543d20SAndroid Build Coastguard Worker if (!S_ISDIR(sb.st_mode))
1171*2d543d20SAndroid Build Coastguard Worker state.setrestorecondigest = false;
1172*2d543d20SAndroid Build Coastguard Worker
1173*2d543d20SAndroid Build Coastguard Worker if (!state.flags.recurse) {
1174*2d543d20SAndroid Build Coastguard Worker if (check_excluded(pathname)) {
1175*2d543d20SAndroid Build Coastguard Worker error = 0;
1176*2d543d20SAndroid Build Coastguard Worker goto cleanup;
1177*2d543d20SAndroid Build Coastguard Worker }
1178*2d543d20SAndroid Build Coastguard Worker
1179*2d543d20SAndroid Build Coastguard Worker error = restorecon_sb(pathname, &sb, &state.flags, true);
1180*2d543d20SAndroid Build Coastguard Worker goto cleanup;
1181*2d543d20SAndroid Build Coastguard Worker }
1182*2d543d20SAndroid Build Coastguard Worker
1183*2d543d20SAndroid Build Coastguard Worker /* Obtain fs type */
1184*2d543d20SAndroid Build Coastguard Worker memset(&state.sfsb, 0, sizeof(state.sfsb));
1185*2d543d20SAndroid Build Coastguard Worker if (!S_ISLNK(sb.st_mode) && statfs(pathname, &state.sfsb) < 0) {
1186*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
1187*2d543d20SAndroid Build Coastguard Worker "statfs(%s) failed: %m\n",
1188*2d543d20SAndroid Build Coastguard Worker pathname);
1189*2d543d20SAndroid Build Coastguard Worker error = -1;
1190*2d543d20SAndroid Build Coastguard Worker goto cleanup;
1191*2d543d20SAndroid Build Coastguard Worker }
1192*2d543d20SAndroid Build Coastguard Worker
1193*2d543d20SAndroid Build Coastguard Worker /* Skip digest on in-memory filesystems and /sys */
1194*2d543d20SAndroid Build Coastguard Worker if ((uint32_t)state.sfsb.f_type == (uint32_t)RAMFS_MAGIC ||
1195*2d543d20SAndroid Build Coastguard Worker state.sfsb.f_type == TMPFS_MAGIC || state.sfsb.f_type == SYSFS_MAGIC)
1196*2d543d20SAndroid Build Coastguard Worker state.setrestorecondigest = false;
1197*2d543d20SAndroid Build Coastguard Worker
1198*2d543d20SAndroid Build Coastguard Worker if (state.flags.set_xdev)
1199*2d543d20SAndroid Build Coastguard Worker fts_flags = FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV;
1200*2d543d20SAndroid Build Coastguard Worker else
1201*2d543d20SAndroid Build Coastguard Worker fts_flags = FTS_PHYSICAL | FTS_NOCHDIR;
1202*2d543d20SAndroid Build Coastguard Worker
1203*2d543d20SAndroid Build Coastguard Worker state.fts = fts_open(paths, fts_flags, NULL);
1204*2d543d20SAndroid Build Coastguard Worker if (!state.fts)
1205*2d543d20SAndroid Build Coastguard Worker goto fts_err;
1206*2d543d20SAndroid Build Coastguard Worker
1207*2d543d20SAndroid Build Coastguard Worker state.ftsent_first = fts_read(state.fts);
1208*2d543d20SAndroid Build Coastguard Worker if (!state.ftsent_first)
1209*2d543d20SAndroid Build Coastguard Worker goto fts_err;
1210*2d543d20SAndroid Build Coastguard Worker
1211*2d543d20SAndroid Build Coastguard Worker /*
1212*2d543d20SAndroid Build Coastguard Worker * Keep the inode of the first device. This is because the FTS_XDEV
1213*2d543d20SAndroid Build Coastguard Worker * flag tells fts not to descend into directories with different
1214*2d543d20SAndroid Build Coastguard Worker * device numbers, but fts will still give back the actual directory.
1215*2d543d20SAndroid Build Coastguard Worker * By saving the device number of the directory that was passed to
1216*2d543d20SAndroid Build Coastguard Worker * selinux_restorecon() and then skipping all actions on any
1217*2d543d20SAndroid Build Coastguard Worker * directories with a different device number when the FTS_XDEV flag
1218*2d543d20SAndroid Build Coastguard Worker * is set (from http://marc.info/?l=selinux&m=124688830500777&w=2).
1219*2d543d20SAndroid Build Coastguard Worker */
1220*2d543d20SAndroid Build Coastguard Worker state.dev_num = state.ftsent_first->fts_statp->st_dev;
1221*2d543d20SAndroid Build Coastguard Worker
1222*2d543d20SAndroid Build Coastguard Worker if (nthreads == 1) {
1223*2d543d20SAndroid Build Coastguard Worker state.parallel = false;
1224*2d543d20SAndroid Build Coastguard Worker selinux_restorecon_thread(&state);
1225*2d543d20SAndroid Build Coastguard Worker } else {
1226*2d543d20SAndroid Build Coastguard Worker size_t i;
1227*2d543d20SAndroid Build Coastguard Worker pthread_t self = pthread_self();
1228*2d543d20SAndroid Build Coastguard Worker pthread_t *threads = NULL;
1229*2d543d20SAndroid Build Coastguard Worker
1230*2d543d20SAndroid Build Coastguard Worker pthread_mutex_init(&state.mutex, NULL);
1231*2d543d20SAndroid Build Coastguard Worker
1232*2d543d20SAndroid Build Coastguard Worker threads = calloc(nthreads - 1, sizeof(*threads));
1233*2d543d20SAndroid Build Coastguard Worker if (!threads)
1234*2d543d20SAndroid Build Coastguard Worker goto oom;
1235*2d543d20SAndroid Build Coastguard Worker
1236*2d543d20SAndroid Build Coastguard Worker state.parallel = true;
1237*2d543d20SAndroid Build Coastguard Worker /*
1238*2d543d20SAndroid Build Coastguard Worker * Start (nthreads - 1) threads - the main thread is going to
1239*2d543d20SAndroid Build Coastguard Worker * take part, too.
1240*2d543d20SAndroid Build Coastguard Worker */
1241*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < nthreads - 1; i++) {
1242*2d543d20SAndroid Build Coastguard Worker if (pthread_create(&threads[i], NULL,
1243*2d543d20SAndroid Build Coastguard Worker selinux_restorecon_thread, &state)) {
1244*2d543d20SAndroid Build Coastguard Worker /*
1245*2d543d20SAndroid Build Coastguard Worker * If any thread fails to be created, just mark
1246*2d543d20SAndroid Build Coastguard Worker * it as such and let the successfully created
1247*2d543d20SAndroid Build Coastguard Worker * threads do the job. In the worst case the
1248*2d543d20SAndroid Build Coastguard Worker * main thread will do everything, but that's
1249*2d543d20SAndroid Build Coastguard Worker * still better than to give up.
1250*2d543d20SAndroid Build Coastguard Worker */
1251*2d543d20SAndroid Build Coastguard Worker threads[i] = self;
1252*2d543d20SAndroid Build Coastguard Worker }
1253*2d543d20SAndroid Build Coastguard Worker }
1254*2d543d20SAndroid Build Coastguard Worker
1255*2d543d20SAndroid Build Coastguard Worker /* Let's join in on the fun! */
1256*2d543d20SAndroid Build Coastguard Worker selinux_restorecon_thread(&state);
1257*2d543d20SAndroid Build Coastguard Worker
1258*2d543d20SAndroid Build Coastguard Worker /* Now wait for all threads to finish. */
1259*2d543d20SAndroid Build Coastguard Worker for (i = 0; i < nthreads - 1; i++) {
1260*2d543d20SAndroid Build Coastguard Worker /* Skip threads that failed to be created. */
1261*2d543d20SAndroid Build Coastguard Worker if (pthread_equal(threads[i], self))
1262*2d543d20SAndroid Build Coastguard Worker continue;
1263*2d543d20SAndroid Build Coastguard Worker pthread_join(threads[i], NULL);
1264*2d543d20SAndroid Build Coastguard Worker }
1265*2d543d20SAndroid Build Coastguard Worker free(threads);
1266*2d543d20SAndroid Build Coastguard Worker
1267*2d543d20SAndroid Build Coastguard Worker pthread_mutex_destroy(&state.mutex);
1268*2d543d20SAndroid Build Coastguard Worker }
1269*2d543d20SAndroid Build Coastguard Worker
1270*2d543d20SAndroid Build Coastguard Worker error = state.error;
1271*2d543d20SAndroid Build Coastguard Worker if (state.saved_errno)
1272*2d543d20SAndroid Build Coastguard Worker goto out;
1273*2d543d20SAndroid Build Coastguard Worker
1274*2d543d20SAndroid Build Coastguard Worker /*
1275*2d543d20SAndroid Build Coastguard Worker * Labeling successful. Write partial match digests for subdirectories.
1276*2d543d20SAndroid Build Coastguard Worker * TODO: Write digest upon FTS_DP if no error occurs in its descents.
1277*2d543d20SAndroid Build Coastguard Worker * Note: we can't ignore errors here that we've masked due to
1278*2d543d20SAndroid Build Coastguard Worker * SELINUX_RESTORECON_COUNT_ERRORS.
1279*2d543d20SAndroid Build Coastguard Worker */
1280*2d543d20SAndroid Build Coastguard Worker if (state.setrestorecondigest && !state.flags.nochange && !error &&
1281*2d543d20SAndroid Build Coastguard Worker state.skipped_errors == 0) {
1282*2d543d20SAndroid Build Coastguard Worker current = state.head;
1283*2d543d20SAndroid Build Coastguard Worker while (current != NULL) {
1284*2d543d20SAndroid Build Coastguard Worker if (setxattr(current->path,
1285*2d543d20SAndroid Build Coastguard Worker RESTORECON_PARTIAL_MATCH_DIGEST,
1286*2d543d20SAndroid Build Coastguard Worker current->digest,
1287*2d543d20SAndroid Build Coastguard Worker SHA1_HASH_SIZE, 0) < 0) {
1288*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
1289*2d543d20SAndroid Build Coastguard Worker "setxattr failed: %s: %m\n",
1290*2d543d20SAndroid Build Coastguard Worker current->path);
1291*2d543d20SAndroid Build Coastguard Worker }
1292*2d543d20SAndroid Build Coastguard Worker current = current->next;
1293*2d543d20SAndroid Build Coastguard Worker }
1294*2d543d20SAndroid Build Coastguard Worker }
1295*2d543d20SAndroid Build Coastguard Worker
1296*2d543d20SAndroid Build Coastguard Worker skipped_errors = state.skipped_errors;
1297*2d543d20SAndroid Build Coastguard Worker
1298*2d543d20SAndroid Build Coastguard Worker out:
1299*2d543d20SAndroid Build Coastguard Worker if (state.flags.progress && state.flags.mass_relabel)
1300*2d543d20SAndroid Build Coastguard Worker fprintf(stdout, "\r%s 100.0%%\n", pathname);
1301*2d543d20SAndroid Build Coastguard Worker
1302*2d543d20SAndroid Build Coastguard Worker (void) fts_close(state.fts);
1303*2d543d20SAndroid Build Coastguard Worker errno = state.saved_errno;
1304*2d543d20SAndroid Build Coastguard Worker cleanup:
1305*2d543d20SAndroid Build Coastguard Worker if (state.flags.add_assoc) {
1306*2d543d20SAndroid Build Coastguard Worker if (state.flags.verbose)
1307*2d543d20SAndroid Build Coastguard Worker filespec_eval();
1308*2d543d20SAndroid Build Coastguard Worker filespec_destroy();
1309*2d543d20SAndroid Build Coastguard Worker }
1310*2d543d20SAndroid Build Coastguard Worker free(pathdnamer);
1311*2d543d20SAndroid Build Coastguard Worker free(pathname);
1312*2d543d20SAndroid Build Coastguard Worker
1313*2d543d20SAndroid Build Coastguard Worker current = state.head;
1314*2d543d20SAndroid Build Coastguard Worker while (current != NULL) {
1315*2d543d20SAndroid Build Coastguard Worker struct dir_hash_node *next = current->next;
1316*2d543d20SAndroid Build Coastguard Worker
1317*2d543d20SAndroid Build Coastguard Worker free(current->path);
1318*2d543d20SAndroid Build Coastguard Worker free(current);
1319*2d543d20SAndroid Build Coastguard Worker current = next;
1320*2d543d20SAndroid Build Coastguard Worker }
1321*2d543d20SAndroid Build Coastguard Worker return error;
1322*2d543d20SAndroid Build Coastguard Worker
1323*2d543d20SAndroid Build Coastguard Worker oom:
1324*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__);
1325*2d543d20SAndroid Build Coastguard Worker error = -1;
1326*2d543d20SAndroid Build Coastguard Worker goto cleanup;
1327*2d543d20SAndroid Build Coastguard Worker
1328*2d543d20SAndroid Build Coastguard Worker realpatherr:
1329*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
1330*2d543d20SAndroid Build Coastguard Worker "SELinux: Could not get canonical path for %s restorecon: %m.\n",
1331*2d543d20SAndroid Build Coastguard Worker pathname_orig);
1332*2d543d20SAndroid Build Coastguard Worker error = -1;
1333*2d543d20SAndroid Build Coastguard Worker goto cleanup;
1334*2d543d20SAndroid Build Coastguard Worker
1335*2d543d20SAndroid Build Coastguard Worker fts_err:
1336*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
1337*2d543d20SAndroid Build Coastguard Worker "fts error while labeling %s: %m\n",
1338*2d543d20SAndroid Build Coastguard Worker paths[0]);
1339*2d543d20SAndroid Build Coastguard Worker error = -1;
1340*2d543d20SAndroid Build Coastguard Worker goto cleanup;
1341*2d543d20SAndroid Build Coastguard Worker }
1342*2d543d20SAndroid Build Coastguard Worker
1343*2d543d20SAndroid Build Coastguard Worker
1344*2d543d20SAndroid Build Coastguard Worker /*
1345*2d543d20SAndroid Build Coastguard Worker * Public API
1346*2d543d20SAndroid Build Coastguard Worker */
1347*2d543d20SAndroid Build Coastguard Worker
1348*2d543d20SAndroid Build Coastguard Worker /* selinux_restorecon(3) - Main function that is responsible for labeling */
selinux_restorecon(const char * pathname_orig,unsigned int restorecon_flags)1349*2d543d20SAndroid Build Coastguard Worker int selinux_restorecon(const char *pathname_orig,
1350*2d543d20SAndroid Build Coastguard Worker unsigned int restorecon_flags)
1351*2d543d20SAndroid Build Coastguard Worker {
1352*2d543d20SAndroid Build Coastguard Worker return selinux_restorecon_common(pathname_orig, restorecon_flags, 1);
1353*2d543d20SAndroid Build Coastguard Worker }
1354*2d543d20SAndroid Build Coastguard Worker
1355*2d543d20SAndroid Build Coastguard Worker /* selinux_restorecon_parallel(3) - Parallel version of selinux_restorecon(3) */
selinux_restorecon_parallel(const char * pathname_orig,unsigned int restorecon_flags,size_t nthreads)1356*2d543d20SAndroid Build Coastguard Worker int selinux_restorecon_parallel(const char *pathname_orig,
1357*2d543d20SAndroid Build Coastguard Worker unsigned int restorecon_flags,
1358*2d543d20SAndroid Build Coastguard Worker size_t nthreads)
1359*2d543d20SAndroid Build Coastguard Worker {
1360*2d543d20SAndroid Build Coastguard Worker return selinux_restorecon_common(pathname_orig, restorecon_flags, nthreads);
1361*2d543d20SAndroid Build Coastguard Worker }
1362*2d543d20SAndroid Build Coastguard Worker
1363*2d543d20SAndroid Build Coastguard Worker /* selinux_restorecon_set_sehandle(3) is called to set the global fc handle */
selinux_restorecon_set_sehandle(struct selabel_handle * hndl)1364*2d543d20SAndroid Build Coastguard Worker void selinux_restorecon_set_sehandle(struct selabel_handle *hndl)
1365*2d543d20SAndroid Build Coastguard Worker {
1366*2d543d20SAndroid Build Coastguard Worker char **specfiles;
1367*2d543d20SAndroid Build Coastguard Worker unsigned char *fc_digest;
1368*2d543d20SAndroid Build Coastguard Worker size_t num_specfiles, fc_digest_len;
1369*2d543d20SAndroid Build Coastguard Worker
1370*2d543d20SAndroid Build Coastguard Worker fc_sehandle = hndl;
1371*2d543d20SAndroid Build Coastguard Worker if (!fc_sehandle)
1372*2d543d20SAndroid Build Coastguard Worker return;
1373*2d543d20SAndroid Build Coastguard Worker
1374*2d543d20SAndroid Build Coastguard Worker /* Check if digest requested in selabel_open(3), if so use it. */
1375*2d543d20SAndroid Build Coastguard Worker if (selabel_digest(fc_sehandle, &fc_digest, &fc_digest_len,
1376*2d543d20SAndroid Build Coastguard Worker &specfiles, &num_specfiles) < 0)
1377*2d543d20SAndroid Build Coastguard Worker selabel_no_digest = true;
1378*2d543d20SAndroid Build Coastguard Worker else
1379*2d543d20SAndroid Build Coastguard Worker selabel_no_digest = false;
1380*2d543d20SAndroid Build Coastguard Worker }
1381*2d543d20SAndroid Build Coastguard Worker
1382*2d543d20SAndroid Build Coastguard Worker
1383*2d543d20SAndroid Build Coastguard Worker /*
1384*2d543d20SAndroid Build Coastguard Worker * selinux_restorecon_default_handle(3) is called to set the global restorecon
1385*2d543d20SAndroid Build Coastguard Worker * handle by a process if the default params are required.
1386*2d543d20SAndroid Build Coastguard Worker */
selinux_restorecon_default_handle(void)1387*2d543d20SAndroid Build Coastguard Worker struct selabel_handle *selinux_restorecon_default_handle(void)
1388*2d543d20SAndroid Build Coastguard Worker {
1389*2d543d20SAndroid Build Coastguard Worker struct selabel_handle *sehandle;
1390*2d543d20SAndroid Build Coastguard Worker
1391*2d543d20SAndroid Build Coastguard Worker struct selinux_opt fc_opts[] = {
1392*2d543d20SAndroid Build Coastguard Worker { SELABEL_OPT_DIGEST, (char *)1 }
1393*2d543d20SAndroid Build Coastguard Worker };
1394*2d543d20SAndroid Build Coastguard Worker
1395*2d543d20SAndroid Build Coastguard Worker sehandle = selabel_open(SELABEL_CTX_FILE, fc_opts, 1);
1396*2d543d20SAndroid Build Coastguard Worker
1397*2d543d20SAndroid Build Coastguard Worker if (!sehandle) {
1398*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
1399*2d543d20SAndroid Build Coastguard Worker "Error obtaining file context handle: %m\n");
1400*2d543d20SAndroid Build Coastguard Worker return NULL;
1401*2d543d20SAndroid Build Coastguard Worker }
1402*2d543d20SAndroid Build Coastguard Worker
1403*2d543d20SAndroid Build Coastguard Worker selabel_no_digest = false;
1404*2d543d20SAndroid Build Coastguard Worker return sehandle;
1405*2d543d20SAndroid Build Coastguard Worker }
1406*2d543d20SAndroid Build Coastguard Worker
1407*2d543d20SAndroid Build Coastguard Worker /*
1408*2d543d20SAndroid Build Coastguard Worker * selinux_restorecon_set_exclude_list(3) is called to add additional entries
1409*2d543d20SAndroid Build Coastguard Worker * to be excluded from labeling checks.
1410*2d543d20SAndroid Build Coastguard Worker */
selinux_restorecon_set_exclude_list(const char ** exclude_list)1411*2d543d20SAndroid Build Coastguard Worker void selinux_restorecon_set_exclude_list(const char **exclude_list)
1412*2d543d20SAndroid Build Coastguard Worker {
1413*2d543d20SAndroid Build Coastguard Worker int i;
1414*2d543d20SAndroid Build Coastguard Worker struct stat sb;
1415*2d543d20SAndroid Build Coastguard Worker
1416*2d543d20SAndroid Build Coastguard Worker for (i = 0; exclude_list[i]; i++) {
1417*2d543d20SAndroid Build Coastguard Worker if (lstat(exclude_list[i], &sb) < 0 && errno != EACCES) {
1418*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
1419*2d543d20SAndroid Build Coastguard Worker "lstat error on exclude path \"%s\", %m - ignoring.\n",
1420*2d543d20SAndroid Build Coastguard Worker exclude_list[i]);
1421*2d543d20SAndroid Build Coastguard Worker break;
1422*2d543d20SAndroid Build Coastguard Worker }
1423*2d543d20SAndroid Build Coastguard Worker if (add_exclude(exclude_list[i], CALLER_EXCLUDED) &&
1424*2d543d20SAndroid Build Coastguard Worker errno == ENOMEM)
1425*2d543d20SAndroid Build Coastguard Worker assert(0);
1426*2d543d20SAndroid Build Coastguard Worker }
1427*2d543d20SAndroid Build Coastguard Worker }
1428*2d543d20SAndroid Build Coastguard Worker
1429*2d543d20SAndroid Build Coastguard Worker /* selinux_restorecon_set_alt_rootpath(3) sets an alternate rootpath. */
selinux_restorecon_set_alt_rootpath(const char * alt_rootpath)1430*2d543d20SAndroid Build Coastguard Worker int selinux_restorecon_set_alt_rootpath(const char *alt_rootpath)
1431*2d543d20SAndroid Build Coastguard Worker {
1432*2d543d20SAndroid Build Coastguard Worker size_t len;
1433*2d543d20SAndroid Build Coastguard Worker
1434*2d543d20SAndroid Build Coastguard Worker /* This should be NULL on first use */
1435*2d543d20SAndroid Build Coastguard Worker if (rootpath)
1436*2d543d20SAndroid Build Coastguard Worker free(rootpath);
1437*2d543d20SAndroid Build Coastguard Worker
1438*2d543d20SAndroid Build Coastguard Worker rootpath = strdup(alt_rootpath);
1439*2d543d20SAndroid Build Coastguard Worker if (!rootpath) {
1440*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __func__);
1441*2d543d20SAndroid Build Coastguard Worker return -1;
1442*2d543d20SAndroid Build Coastguard Worker }
1443*2d543d20SAndroid Build Coastguard Worker
1444*2d543d20SAndroid Build Coastguard Worker /* trim trailing /, if present */
1445*2d543d20SAndroid Build Coastguard Worker len = strlen(rootpath);
1446*2d543d20SAndroid Build Coastguard Worker while (len && (rootpath[len - 1] == '/'))
1447*2d543d20SAndroid Build Coastguard Worker rootpath[--len] = '\0';
1448*2d543d20SAndroid Build Coastguard Worker rootpathlen = len;
1449*2d543d20SAndroid Build Coastguard Worker
1450*2d543d20SAndroid Build Coastguard Worker return 0;
1451*2d543d20SAndroid Build Coastguard Worker }
1452*2d543d20SAndroid Build Coastguard Worker
1453*2d543d20SAndroid Build Coastguard Worker /* selinux_restorecon_xattr(3)
1454*2d543d20SAndroid Build Coastguard Worker * Find RESTORECON_PARTIAL_MATCH_DIGEST entries.
1455*2d543d20SAndroid Build Coastguard Worker */
selinux_restorecon_xattr(const char * pathname,unsigned int xattr_flags,struct dir_xattr *** xattr_list)1456*2d543d20SAndroid Build Coastguard Worker int selinux_restorecon_xattr(const char *pathname, unsigned int xattr_flags,
1457*2d543d20SAndroid Build Coastguard Worker struct dir_xattr ***xattr_list)
1458*2d543d20SAndroid Build Coastguard Worker {
1459*2d543d20SAndroid Build Coastguard Worker bool recurse = (xattr_flags &
1460*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_XATTR_RECURSE) ? true : false;
1461*2d543d20SAndroid Build Coastguard Worker bool delete_nonmatch = (xattr_flags &
1462*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_XATTR_DELETE_NONMATCH_DIGESTS) ? true : false;
1463*2d543d20SAndroid Build Coastguard Worker bool delete_all = (xattr_flags &
1464*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_XATTR_DELETE_ALL_DIGESTS) ? true : false;
1465*2d543d20SAndroid Build Coastguard Worker ignore_mounts = (xattr_flags &
1466*2d543d20SAndroid Build Coastguard Worker SELINUX_RESTORECON_XATTR_IGNORE_MOUNTS) ? true : false;
1467*2d543d20SAndroid Build Coastguard Worker
1468*2d543d20SAndroid Build Coastguard Worker int rc, fts_flags;
1469*2d543d20SAndroid Build Coastguard Worker struct stat sb;
1470*2d543d20SAndroid Build Coastguard Worker struct statfs sfsb;
1471*2d543d20SAndroid Build Coastguard Worker struct dir_xattr *current, *next;
1472*2d543d20SAndroid Build Coastguard Worker FTS *fts;
1473*2d543d20SAndroid Build Coastguard Worker FTSENT *ftsent;
1474*2d543d20SAndroid Build Coastguard Worker char *paths[2] = { NULL, NULL };
1475*2d543d20SAndroid Build Coastguard Worker
1476*2d543d20SAndroid Build Coastguard Worker __selinux_once(fc_once, restorecon_init);
1477*2d543d20SAndroid Build Coastguard Worker
1478*2d543d20SAndroid Build Coastguard Worker if (!fc_sehandle)
1479*2d543d20SAndroid Build Coastguard Worker return -1;
1480*2d543d20SAndroid Build Coastguard Worker
1481*2d543d20SAndroid Build Coastguard Worker if (lstat(pathname, &sb) < 0) {
1482*2d543d20SAndroid Build Coastguard Worker if (errno == ENOENT)
1483*2d543d20SAndroid Build Coastguard Worker return 0;
1484*2d543d20SAndroid Build Coastguard Worker
1485*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
1486*2d543d20SAndroid Build Coastguard Worker "lstat(%s) failed: %m\n",
1487*2d543d20SAndroid Build Coastguard Worker pathname);
1488*2d543d20SAndroid Build Coastguard Worker return -1;
1489*2d543d20SAndroid Build Coastguard Worker }
1490*2d543d20SAndroid Build Coastguard Worker
1491*2d543d20SAndroid Build Coastguard Worker if (!recurse) {
1492*2d543d20SAndroid Build Coastguard Worker if (statfs(pathname, &sfsb) == 0) {
1493*2d543d20SAndroid Build Coastguard Worker if ((uint32_t)sfsb.f_type == (uint32_t)RAMFS_MAGIC ||
1494*2d543d20SAndroid Build Coastguard Worker sfsb.f_type == TMPFS_MAGIC)
1495*2d543d20SAndroid Build Coastguard Worker return 0;
1496*2d543d20SAndroid Build Coastguard Worker }
1497*2d543d20SAndroid Build Coastguard Worker
1498*2d543d20SAndroid Build Coastguard Worker if (check_excluded(pathname))
1499*2d543d20SAndroid Build Coastguard Worker return 0;
1500*2d543d20SAndroid Build Coastguard Worker
1501*2d543d20SAndroid Build Coastguard Worker rc = add_xattr_entry(pathname, delete_nonmatch, delete_all);
1502*2d543d20SAndroid Build Coastguard Worker
1503*2d543d20SAndroid Build Coastguard Worker if (!rc && dir_xattr_list)
1504*2d543d20SAndroid Build Coastguard Worker *xattr_list = &dir_xattr_list;
1505*2d543d20SAndroid Build Coastguard Worker else if (rc == -1)
1506*2d543d20SAndroid Build Coastguard Worker return rc;
1507*2d543d20SAndroid Build Coastguard Worker
1508*2d543d20SAndroid Build Coastguard Worker return 0;
1509*2d543d20SAndroid Build Coastguard Worker }
1510*2d543d20SAndroid Build Coastguard Worker
1511*2d543d20SAndroid Build Coastguard Worker paths[0] = (char *)pathname;
1512*2d543d20SAndroid Build Coastguard Worker fts_flags = FTS_PHYSICAL | FTS_NOCHDIR;
1513*2d543d20SAndroid Build Coastguard Worker
1514*2d543d20SAndroid Build Coastguard Worker fts = fts_open(paths, fts_flags, NULL);
1515*2d543d20SAndroid Build Coastguard Worker if (!fts) {
1516*2d543d20SAndroid Build Coastguard Worker selinux_log(SELINUX_ERROR,
1517*2d543d20SAndroid Build Coastguard Worker "fts error on %s: %m\n",
1518*2d543d20SAndroid Build Coastguard Worker paths[0]);
1519*2d543d20SAndroid Build Coastguard Worker return -1;
1520*2d543d20SAndroid Build Coastguard Worker }
1521*2d543d20SAndroid Build Coastguard Worker
1522*2d543d20SAndroid Build Coastguard Worker while ((ftsent = fts_read(fts)) != NULL) {
1523*2d543d20SAndroid Build Coastguard Worker switch (ftsent->fts_info) {
1524*2d543d20SAndroid Build Coastguard Worker case FTS_DP:
1525*2d543d20SAndroid Build Coastguard Worker continue;
1526*2d543d20SAndroid Build Coastguard Worker case FTS_D:
1527*2d543d20SAndroid Build Coastguard Worker if (statfs(ftsent->fts_path, &sfsb) == 0) {
1528*2d543d20SAndroid Build Coastguard Worker if ((uint32_t)sfsb.f_type == (uint32_t)RAMFS_MAGIC ||
1529*2d543d20SAndroid Build Coastguard Worker sfsb.f_type == TMPFS_MAGIC)
1530*2d543d20SAndroid Build Coastguard Worker continue;
1531*2d543d20SAndroid Build Coastguard Worker }
1532*2d543d20SAndroid Build Coastguard Worker if (check_excluded(ftsent->fts_path)) {
1533*2d543d20SAndroid Build Coastguard Worker fts_set(fts, ftsent, FTS_SKIP);
1534*2d543d20SAndroid Build Coastguard Worker continue;
1535*2d543d20SAndroid Build Coastguard Worker }
1536*2d543d20SAndroid Build Coastguard Worker
1537*2d543d20SAndroid Build Coastguard Worker rc = add_xattr_entry(ftsent->fts_path,
1538*2d543d20SAndroid Build Coastguard Worker delete_nonmatch, delete_all);
1539*2d543d20SAndroid Build Coastguard Worker if (rc == 1)
1540*2d543d20SAndroid Build Coastguard Worker continue;
1541*2d543d20SAndroid Build Coastguard Worker else if (rc == -1)
1542*2d543d20SAndroid Build Coastguard Worker goto cleanup;
1543*2d543d20SAndroid Build Coastguard Worker break;
1544*2d543d20SAndroid Build Coastguard Worker default:
1545*2d543d20SAndroid Build Coastguard Worker break;
1546*2d543d20SAndroid Build Coastguard Worker }
1547*2d543d20SAndroid Build Coastguard Worker }
1548*2d543d20SAndroid Build Coastguard Worker
1549*2d543d20SAndroid Build Coastguard Worker if (dir_xattr_list)
1550*2d543d20SAndroid Build Coastguard Worker *xattr_list = &dir_xattr_list;
1551*2d543d20SAndroid Build Coastguard Worker
1552*2d543d20SAndroid Build Coastguard Worker (void) fts_close(fts);
1553*2d543d20SAndroid Build Coastguard Worker return 0;
1554*2d543d20SAndroid Build Coastguard Worker
1555*2d543d20SAndroid Build Coastguard Worker cleanup:
1556*2d543d20SAndroid Build Coastguard Worker rc = errno;
1557*2d543d20SAndroid Build Coastguard Worker (void) fts_close(fts);
1558*2d543d20SAndroid Build Coastguard Worker errno = rc;
1559*2d543d20SAndroid Build Coastguard Worker
1560*2d543d20SAndroid Build Coastguard Worker if (dir_xattr_list) {
1561*2d543d20SAndroid Build Coastguard Worker /* Free any used memory */
1562*2d543d20SAndroid Build Coastguard Worker current = dir_xattr_list;
1563*2d543d20SAndroid Build Coastguard Worker while (current) {
1564*2d543d20SAndroid Build Coastguard Worker next = current->next;
1565*2d543d20SAndroid Build Coastguard Worker free(current->directory);
1566*2d543d20SAndroid Build Coastguard Worker free(current->digest);
1567*2d543d20SAndroid Build Coastguard Worker free(current);
1568*2d543d20SAndroid Build Coastguard Worker current = next;
1569*2d543d20SAndroid Build Coastguard Worker }
1570*2d543d20SAndroid Build Coastguard Worker }
1571*2d543d20SAndroid Build Coastguard Worker return -1;
1572*2d543d20SAndroid Build Coastguard Worker }
1573*2d543d20SAndroid Build Coastguard Worker
selinux_restorecon_get_skipped_errors(void)1574*2d543d20SAndroid Build Coastguard Worker long unsigned selinux_restorecon_get_skipped_errors(void)
1575*2d543d20SAndroid Build Coastguard Worker {
1576*2d543d20SAndroid Build Coastguard Worker return skipped_errors;
1577*2d543d20SAndroid Build Coastguard Worker }
1578