xref: /aosp_15_r20/external/selinux/mcstrans/src/mls_level.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1 #include <stdio.h>
2 #include "mls_level.h"
3 #include <sepol/policydb/ebitmap.h>
4 
mls_level_from_string(char * mls_context)5 mls_level_t *mls_level_from_string(char *mls_context)
6 {
7 	char delim;
8 	char *scontextp, *p, *lptr;
9 	mls_level_t *l;
10 
11 	if (!mls_context) {
12 		return NULL;
13 	}
14 
15 	l = (mls_level_t *) calloc(1, sizeof(mls_level_t));
16 	if (!l)
17 		return NULL;
18 
19 	/* Extract low sensitivity. */
20 	scontextp = p = mls_context;
21 	while (*p && *p != ':' && *p != '-')
22 		p++;
23 
24 	delim = *p;
25 	if (delim != 0)
26 		*p++ = 0;
27 
28 	if (*scontextp != 's')
29 		goto err;
30 	l->sens = atoi(scontextp + 1);
31 
32 	if (delim == ':') {
33 		/* Extract category set. */
34 		while (1) {
35 			scontextp = p;
36 			while (*p && *p != ',' && *p != '-')
37 				p++;
38 			delim = *p;
39 			if (delim != 0)
40 				*p++ = 0;
41 
42 			/* Separate into level if exists */
43 			if ((lptr = strchr(scontextp, '.')) != NULL) {
44 				/* Remove '.' */
45 				*lptr++ = 0;
46 			}
47 
48 			if (*scontextp != 'c')
49 				goto err;
50 			int bit = atoi(scontextp + 1);
51 			if (ebitmap_set_bit(&l->cat, bit, 1))
52 				goto err;
53 
54 			/* If level, set all categories in level */
55 			if (lptr) {
56 				if (*lptr != 'c')
57 					goto err;
58 				int ubit = atoi(lptr + 1);
59 				int i;
60 				for (i = bit + 1; i <= ubit; i++) {
61 					if (ebitmap_set_bit
62 					    (&l->cat, i, 1))
63 						goto err;
64 				}
65 			}
66 
67 			if (delim != ',')
68 				break;
69 		}
70 	}
71 
72 	return l;
73 
74       err:
75 	free(l);
76 	return NULL;
77 }
78 
79 /*
80  * Return the length in bytes for the MLS fields of the
81  * security context string representation of `context'.
82  */
mls_compute_string_len(mls_level_t * l)83 unsigned int mls_compute_string_len(mls_level_t *l)
84 {
85 	unsigned int len = 0;
86 	char temp[16];
87 	unsigned int i, level = 0;
88 	ebitmap_node_t *cnode;
89 
90 	if (!l)
91 		return 0;
92 
93 	len += snprintf(temp, sizeof(temp), "s%d", l->sens);
94 
95 	ebitmap_for_each_bit(&l->cat, cnode, i) {
96 		if (ebitmap_node_get_bit(cnode, i)) {
97 			if (level) {
98 				level++;
99 				continue;
100 			}
101 
102 			len++; /* : or ,` */
103 
104 			len += snprintf(temp, sizeof(temp), "c%d", i);
105 			level++;
106 		} else {
107 			if (level > 1)
108 				len += snprintf(temp, sizeof(temp), ".c%d", i-1);
109 			level = 0;
110 		}
111 	}
112 
113 	/* Handle case where last category is the end of level */
114 	if (level > 1)
115 		len += snprintf(temp, sizeof(temp), ".c%d", i-1);
116 	return len;
117 }
118 
mls_level_to_string(mls_level_t * l)119 char *mls_level_to_string(mls_level_t *l)
120 {
121 	unsigned int wrote_sep, len = mls_compute_string_len(l);
122 	unsigned int i, level = 0;
123 	ebitmap_node_t *cnode;
124 	wrote_sep = 0;
125 
126 	if (len == 0)
127 		return NULL;
128 	char *result = (char *)malloc(len + 1);
129 	if (!result)
130 		return NULL;
131 
132 	char *p = result;
133 
134 	p += sprintf(p, "s%d", l->sens);
135 
136 	/* categories */
137 	ebitmap_for_each_bit(&l->cat, cnode, i) {
138 		if (ebitmap_node_get_bit(cnode, i)) {
139 			if (level) {
140 				level++;
141 				continue;
142 			}
143 
144 			if (!wrote_sep) {
145 				*p++ = ':';
146 				wrote_sep = 1;
147 			} else
148 				*p++ = ',';
149 			p += sprintf(p, "c%d", i);
150 			level++;
151 		} else {
152 			if (level > 1) {
153 				if (level > 2)
154 					*p++ = '.';
155 				else
156 					*p++ = ',';
157 
158 				p += sprintf(p, "c%d", i-1);
159 			}
160 			level = 0;
161 		}
162 	}
163 	/* Handle case where last category is the end of level */
164 	if (level > 1) {
165 		if (level > 2)
166 			*p++ = '.';
167 		else
168 			*p++ = ',';
169 
170 		p += sprintf(p, "c%d", i-1);
171 	}
172 
173 	*(result + len) = 0;
174 	return result;
175 }
176