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