xref: /aosp_15_r20/external/selinux/libselinux/src/label_media.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /*
2*2d543d20SAndroid Build Coastguard Worker  * Media contexts backend for labeling system
3*2d543d20SAndroid Build Coastguard Worker  *
4*2d543d20SAndroid Build Coastguard Worker  * Author : Eamon Walsh <[email protected]>
5*2d543d20SAndroid Build Coastguard Worker  */
6*2d543d20SAndroid Build Coastguard Worker 
7*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
8*2d543d20SAndroid Build Coastguard Worker #include <string.h>
9*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
10*2d543d20SAndroid Build Coastguard Worker #include <stdio_ext.h>
11*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
12*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
13*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
14*2d543d20SAndroid Build Coastguard Worker #include "callbacks.h"
15*2d543d20SAndroid Build Coastguard Worker #include "label_internal.h"
16*2d543d20SAndroid Build Coastguard Worker 
17*2d543d20SAndroid Build Coastguard Worker /*
18*2d543d20SAndroid Build Coastguard Worker  * Internals
19*2d543d20SAndroid Build Coastguard Worker  */
20*2d543d20SAndroid Build Coastguard Worker 
21*2d543d20SAndroid Build Coastguard Worker /* A context specification. */
22*2d543d20SAndroid Build Coastguard Worker typedef struct spec {
23*2d543d20SAndroid Build Coastguard Worker 	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
24*2d543d20SAndroid Build Coastguard Worker 	char *key;		/* key string */
25*2d543d20SAndroid Build Coastguard Worker 	int matches;		/* number of matches made during operation */
26*2d543d20SAndroid Build Coastguard Worker } spec_t;
27*2d543d20SAndroid Build Coastguard Worker 
28*2d543d20SAndroid Build Coastguard Worker struct saved_data {
29*2d543d20SAndroid Build Coastguard Worker 	unsigned int nspec;
30*2d543d20SAndroid Build Coastguard Worker 	spec_t *spec_arr;
31*2d543d20SAndroid Build Coastguard Worker };
32*2d543d20SAndroid Build Coastguard Worker 
process_line(const char * path,const char * line_buf,int pass,unsigned lineno,struct selabel_handle * rec)33*2d543d20SAndroid Build Coastguard Worker static int process_line(const char *path, const char *line_buf, int pass,
34*2d543d20SAndroid Build Coastguard Worker 			unsigned lineno, struct selabel_handle *rec)
35*2d543d20SAndroid Build Coastguard Worker {
36*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
37*2d543d20SAndroid Build Coastguard Worker 	int items;
38*2d543d20SAndroid Build Coastguard Worker 	const char *buf_p;
39*2d543d20SAndroid Build Coastguard Worker 	char *key, *context;
40*2d543d20SAndroid Build Coastguard Worker 
41*2d543d20SAndroid Build Coastguard Worker 	buf_p = line_buf;
42*2d543d20SAndroid Build Coastguard Worker 	while (isspace((unsigned char)*buf_p))
43*2d543d20SAndroid Build Coastguard Worker 		buf_p++;
44*2d543d20SAndroid Build Coastguard Worker 	/* Skip comment lines and empty lines. */
45*2d543d20SAndroid Build Coastguard Worker 	if (*buf_p == '#' || *buf_p == 0)
46*2d543d20SAndroid Build Coastguard Worker 		return 0;
47*2d543d20SAndroid Build Coastguard Worker 	items = sscanf(line_buf, "%ms %ms ", &key, &context);
48*2d543d20SAndroid Build Coastguard Worker 	if (items < 2) {
49*2d543d20SAndroid Build Coastguard Worker 		selinux_log(SELINUX_WARNING,
50*2d543d20SAndroid Build Coastguard Worker 			  "%s:  line %u is missing fields, skipping\n", path,
51*2d543d20SAndroid Build Coastguard Worker 			  lineno);
52*2d543d20SAndroid Build Coastguard Worker 		if (items == 1)
53*2d543d20SAndroid Build Coastguard Worker 			free(key);
54*2d543d20SAndroid Build Coastguard Worker 		return 0;
55*2d543d20SAndroid Build Coastguard Worker 	}
56*2d543d20SAndroid Build Coastguard Worker 
57*2d543d20SAndroid Build Coastguard Worker 	if (pass == 1) {
58*2d543d20SAndroid Build Coastguard Worker 		data->spec_arr[data->nspec].key = key;
59*2d543d20SAndroid Build Coastguard Worker 		data->spec_arr[data->nspec].lr.ctx_raw = context;
60*2d543d20SAndroid Build Coastguard Worker 	}
61*2d543d20SAndroid Build Coastguard Worker 
62*2d543d20SAndroid Build Coastguard Worker 	data->nspec++;
63*2d543d20SAndroid Build Coastguard Worker 	if (pass == 0) {
64*2d543d20SAndroid Build Coastguard Worker 		free(key);
65*2d543d20SAndroid Build Coastguard Worker 		free(context);
66*2d543d20SAndroid Build Coastguard Worker 	}
67*2d543d20SAndroid Build Coastguard Worker 	return 0;
68*2d543d20SAndroid Build Coastguard Worker }
69*2d543d20SAndroid Build Coastguard Worker 
init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned n)70*2d543d20SAndroid Build Coastguard Worker static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
71*2d543d20SAndroid Build Coastguard Worker 		unsigned n)
72*2d543d20SAndroid Build Coastguard Worker {
73*2d543d20SAndroid Build Coastguard Worker 	FILE *fp;
74*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
75*2d543d20SAndroid Build Coastguard Worker 	const char *path = NULL;
76*2d543d20SAndroid Build Coastguard Worker 	char *line_buf = NULL;
77*2d543d20SAndroid Build Coastguard Worker 	size_t line_len = 0;
78*2d543d20SAndroid Build Coastguard Worker 	int status = -1;
79*2d543d20SAndroid Build Coastguard Worker 	unsigned int lineno, pass, maxnspec;
80*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
81*2d543d20SAndroid Build Coastguard Worker 
82*2d543d20SAndroid Build Coastguard Worker 	/* Process arguments */
83*2d543d20SAndroid Build Coastguard Worker 	while (n) {
84*2d543d20SAndroid Build Coastguard Worker 		n--;
85*2d543d20SAndroid Build Coastguard Worker 		switch(opts[n].type) {
86*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_PATH:
87*2d543d20SAndroid Build Coastguard Worker 			path = opts[n].value;
88*2d543d20SAndroid Build Coastguard Worker 			break;
89*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_UNUSED:
90*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_VALIDATE:
91*2d543d20SAndroid Build Coastguard Worker 		case SELABEL_OPT_DIGEST:
92*2d543d20SAndroid Build Coastguard Worker 			break;
93*2d543d20SAndroid Build Coastguard Worker 		default:
94*2d543d20SAndroid Build Coastguard Worker 			errno = EINVAL;
95*2d543d20SAndroid Build Coastguard Worker 			return -1;
96*2d543d20SAndroid Build Coastguard Worker 		}
97*2d543d20SAndroid Build Coastguard Worker }
98*2d543d20SAndroid Build Coastguard Worker 
99*2d543d20SAndroid Build Coastguard Worker 	/* Open the specification file. */
100*2d543d20SAndroid Build Coastguard Worker 	if (!path)
101*2d543d20SAndroid Build Coastguard Worker 		path = selinux_media_context_path();
102*2d543d20SAndroid Build Coastguard Worker 	if ((fp = fopen(path, "re")) == NULL)
103*2d543d20SAndroid Build Coastguard Worker 		return -1;
104*2d543d20SAndroid Build Coastguard Worker 	__fsetlocking(fp, FSETLOCKING_BYCALLER);
105*2d543d20SAndroid Build Coastguard Worker 
106*2d543d20SAndroid Build Coastguard Worker 	if (fstat(fileno(fp), &sb) < 0)
107*2d543d20SAndroid Build Coastguard Worker 		goto finish;
108*2d543d20SAndroid Build Coastguard Worker 	if (!S_ISREG(sb.st_mode)) {
109*2d543d20SAndroid Build Coastguard Worker 		errno = EINVAL;
110*2d543d20SAndroid Build Coastguard Worker 		goto finish;
111*2d543d20SAndroid Build Coastguard Worker 	}
112*2d543d20SAndroid Build Coastguard Worker 	rec->spec_file = strdup(path);
113*2d543d20SAndroid Build Coastguard Worker 
114*2d543d20SAndroid Build Coastguard Worker 	/*
115*2d543d20SAndroid Build Coastguard Worker 	 * Perform two passes over the specification file.
116*2d543d20SAndroid Build Coastguard Worker 	 * The first pass counts the number of specifications and
117*2d543d20SAndroid Build Coastguard Worker 	 * performs simple validation of the input.  At the end
118*2d543d20SAndroid Build Coastguard Worker 	 * of the first pass, the spec array is allocated.
119*2d543d20SAndroid Build Coastguard Worker 	 * The second pass performs detailed validation of the input
120*2d543d20SAndroid Build Coastguard Worker 	 * and fills in the spec array.
121*2d543d20SAndroid Build Coastguard Worker 	 */
122*2d543d20SAndroid Build Coastguard Worker 	maxnspec = UINT_MAX / sizeof(spec_t);
123*2d543d20SAndroid Build Coastguard Worker 	for (pass = 0; pass < 2; pass++) {
124*2d543d20SAndroid Build Coastguard Worker 		lineno = 0;
125*2d543d20SAndroid Build Coastguard Worker 		data->nspec = 0;
126*2d543d20SAndroid Build Coastguard Worker 		while (getline(&line_buf, &line_len, fp) > 0 &&
127*2d543d20SAndroid Build Coastguard Worker 		       data->nspec < maxnspec) {
128*2d543d20SAndroid Build Coastguard Worker 			if (process_line(path, line_buf, pass, ++lineno, rec))
129*2d543d20SAndroid Build Coastguard Worker 				goto finish;
130*2d543d20SAndroid Build Coastguard Worker 		}
131*2d543d20SAndroid Build Coastguard Worker 
132*2d543d20SAndroid Build Coastguard Worker 		if (pass == 0) {
133*2d543d20SAndroid Build Coastguard Worker 			if (data->nspec == 0) {
134*2d543d20SAndroid Build Coastguard Worker 				status = 0;
135*2d543d20SAndroid Build Coastguard Worker 				goto finish;
136*2d543d20SAndroid Build Coastguard Worker 			}
137*2d543d20SAndroid Build Coastguard Worker 			data->spec_arr = malloc(sizeof(spec_t)*data->nspec);
138*2d543d20SAndroid Build Coastguard Worker 			if (data->spec_arr == NULL)
139*2d543d20SAndroid Build Coastguard Worker 				goto finish;
140*2d543d20SAndroid Build Coastguard Worker 			memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
141*2d543d20SAndroid Build Coastguard Worker 			maxnspec = data->nspec;
142*2d543d20SAndroid Build Coastguard Worker 
143*2d543d20SAndroid Build Coastguard Worker 			status = fseek(fp, 0L, SEEK_SET);
144*2d543d20SAndroid Build Coastguard Worker 			if (status == -1)
145*2d543d20SAndroid Build Coastguard Worker 				goto finish;
146*2d543d20SAndroid Build Coastguard Worker 		}
147*2d543d20SAndroid Build Coastguard Worker 	}
148*2d543d20SAndroid Build Coastguard Worker 
149*2d543d20SAndroid Build Coastguard Worker 	status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path);
150*2d543d20SAndroid Build Coastguard Worker 	if (status)
151*2d543d20SAndroid Build Coastguard Worker 		goto finish;
152*2d543d20SAndroid Build Coastguard Worker 
153*2d543d20SAndroid Build Coastguard Worker 	digest_gen_hash(rec->digest);
154*2d543d20SAndroid Build Coastguard Worker 
155*2d543d20SAndroid Build Coastguard Worker finish:
156*2d543d20SAndroid Build Coastguard Worker 	free(line_buf);
157*2d543d20SAndroid Build Coastguard Worker 	fclose(fp);
158*2d543d20SAndroid Build Coastguard Worker 	return status;
159*2d543d20SAndroid Build Coastguard Worker }
160*2d543d20SAndroid Build Coastguard Worker 
161*2d543d20SAndroid Build Coastguard Worker /*
162*2d543d20SAndroid Build Coastguard Worker  * Backend interface routines
163*2d543d20SAndroid Build Coastguard Worker  */
close(struct selabel_handle * rec)164*2d543d20SAndroid Build Coastguard Worker static void close(struct selabel_handle *rec)
165*2d543d20SAndroid Build Coastguard Worker {
166*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
167*2d543d20SAndroid Build Coastguard Worker 	struct spec *spec, *spec_arr;
168*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
169*2d543d20SAndroid Build Coastguard Worker 
170*2d543d20SAndroid Build Coastguard Worker 	if (!data)
171*2d543d20SAndroid Build Coastguard Worker 		return;
172*2d543d20SAndroid Build Coastguard Worker 
173*2d543d20SAndroid Build Coastguard Worker 	spec_arr = data->spec_arr;
174*2d543d20SAndroid Build Coastguard Worker 
175*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < data->nspec; i++) {
176*2d543d20SAndroid Build Coastguard Worker 		spec = &spec_arr[i];
177*2d543d20SAndroid Build Coastguard Worker 		free(spec->key);
178*2d543d20SAndroid Build Coastguard Worker 		free(spec->lr.ctx_raw);
179*2d543d20SAndroid Build Coastguard Worker 		free(spec->lr.ctx_trans);
180*2d543d20SAndroid Build Coastguard Worker 	}
181*2d543d20SAndroid Build Coastguard Worker 
182*2d543d20SAndroid Build Coastguard Worker 	if (spec_arr)
183*2d543d20SAndroid Build Coastguard Worker 	    free(spec_arr);
184*2d543d20SAndroid Build Coastguard Worker 
185*2d543d20SAndroid Build Coastguard Worker 	free(data);
186*2d543d20SAndroid Build Coastguard Worker 	rec->data = NULL;
187*2d543d20SAndroid Build Coastguard Worker }
188*2d543d20SAndroid Build Coastguard Worker 
lookup(struct selabel_handle * rec,const char * key,int type)189*2d543d20SAndroid Build Coastguard Worker static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
190*2d543d20SAndroid Build Coastguard Worker 					 const char *key,
191*2d543d20SAndroid Build Coastguard Worker 					 int type __attribute__((unused)))
192*2d543d20SAndroid Build Coastguard Worker {
193*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
194*2d543d20SAndroid Build Coastguard Worker 	spec_t *spec_arr = data->spec_arr;
195*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
196*2d543d20SAndroid Build Coastguard Worker 
197*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < data->nspec; i++) {
198*2d543d20SAndroid Build Coastguard Worker 		if (!strncmp(spec_arr[i].key, key, strlen(key) + 1))
199*2d543d20SAndroid Build Coastguard Worker 			break;
200*2d543d20SAndroid Build Coastguard Worker 		if (!strncmp(spec_arr[i].key, "*", 2))
201*2d543d20SAndroid Build Coastguard Worker 			break;
202*2d543d20SAndroid Build Coastguard Worker 	}
203*2d543d20SAndroid Build Coastguard Worker 
204*2d543d20SAndroid Build Coastguard Worker 	if (i >= data->nspec) {
205*2d543d20SAndroid Build Coastguard Worker 		/* No matching specification. */
206*2d543d20SAndroid Build Coastguard Worker 		errno = ENOENT;
207*2d543d20SAndroid Build Coastguard Worker 		return NULL;
208*2d543d20SAndroid Build Coastguard Worker 	}
209*2d543d20SAndroid Build Coastguard Worker 
210*2d543d20SAndroid Build Coastguard Worker 	spec_arr[i].matches++;
211*2d543d20SAndroid Build Coastguard Worker 	return &spec_arr[i].lr;
212*2d543d20SAndroid Build Coastguard Worker }
213*2d543d20SAndroid Build Coastguard Worker 
stats(struct selabel_handle * rec)214*2d543d20SAndroid Build Coastguard Worker static void stats(struct selabel_handle *rec)
215*2d543d20SAndroid Build Coastguard Worker {
216*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data = (struct saved_data *)rec->data;
217*2d543d20SAndroid Build Coastguard Worker 	unsigned int i, total = 0;
218*2d543d20SAndroid Build Coastguard Worker 
219*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < data->nspec; i++)
220*2d543d20SAndroid Build Coastguard Worker 		total += data->spec_arr[i].matches;
221*2d543d20SAndroid Build Coastguard Worker 
222*2d543d20SAndroid Build Coastguard Worker 	selinux_log(SELINUX_INFO, "%u entries, %u matches made\n",
223*2d543d20SAndroid Build Coastguard Worker 		  data->nspec, total);
224*2d543d20SAndroid Build Coastguard Worker }
225*2d543d20SAndroid Build Coastguard Worker 
selabel_media_init(struct selabel_handle * rec,const struct selinux_opt * opts,unsigned nopts)226*2d543d20SAndroid Build Coastguard Worker int selabel_media_init(struct selabel_handle *rec,
227*2d543d20SAndroid Build Coastguard Worker 				    const struct selinux_opt *opts,
228*2d543d20SAndroid Build Coastguard Worker 				    unsigned nopts)
229*2d543d20SAndroid Build Coastguard Worker {
230*2d543d20SAndroid Build Coastguard Worker 	struct saved_data *data;
231*2d543d20SAndroid Build Coastguard Worker 
232*2d543d20SAndroid Build Coastguard Worker 	data = (struct saved_data *)malloc(sizeof(*data));
233*2d543d20SAndroid Build Coastguard Worker 	if (!data)
234*2d543d20SAndroid Build Coastguard Worker 		return -1;
235*2d543d20SAndroid Build Coastguard Worker 	memset(data, 0, sizeof(*data));
236*2d543d20SAndroid Build Coastguard Worker 
237*2d543d20SAndroid Build Coastguard Worker 	rec->data = data;
238*2d543d20SAndroid Build Coastguard Worker 	rec->func_close = &close;
239*2d543d20SAndroid Build Coastguard Worker 	rec->func_lookup = &lookup;
240*2d543d20SAndroid Build Coastguard Worker 	rec->func_stats = &stats;
241*2d543d20SAndroid Build Coastguard Worker 
242*2d543d20SAndroid Build Coastguard Worker 	return init(rec, opts, nopts);
243*2d543d20SAndroid Build Coastguard Worker }
244