aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/ss/mls.c
diff options
context:
space:
mode:
authorJann Horn <jannh@google.com>2018-08-06 17:19:32 -0400
committerPaul Moore <paul@paul-moore.com>2018-09-05 17:47:09 -0400
commit95ffe194204ae3cef88d0b59be209204bbe9b3be (patch)
treea31906d241c0bc898d412423cf97ce8905f0347c /security/selinux/ss/mls.c
parent7bb185edb0306bb90029a5fa6b9cff900ffdbf4b (diff)
selinux: refactor mls_context_to_sid() and make it stricter
The intended behavior change for this patch is to reject any MLS strings that contain (trailing) garbage if p->mls_enabled is true. As suggested by Paul Moore, change mls_context_to_sid() so that the two parts of the range are extracted before the rest of the parsing. Because now we don't have to scan for two different separators simultaneously everywhere, we can actually switch to strchr() everywhere instead of the open-coded loops that scan for two separators at once. mls_context_to_sid() used to signal how much of the input string was parsed by updating `*scontext`. However, there is actually no case in which mls_context_to_sid() only parses a subset of the input and still returns a success (other than the buggy case with a second '-' in which it incorrectly claims to have consumed the entire string). Turn `scontext` into a simple pointer argument and stop redundantly checking whether the entire input was consumed in string_to_context_struct(). This also lets us remove the `scontext_len` argument from `string_to_context_struct()`. Signed-off-by: Jann Horn <jannh@google.com> [PM: minor merge fuzz in convert_context()] Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'security/selinux/ss/mls.c')
-rw-r--r--security/selinux/ss/mls.c178
1 files changed, 77 insertions, 101 deletions
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 39475fb455bc..2fe459df3c85 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -218,9 +218,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
218/* 218/*
219 * Set the MLS fields in the security context structure 219 * Set the MLS fields in the security context structure
220 * `context' based on the string representation in 220 * `context' based on the string representation in
221 * the string `*scontext'. Update `*scontext' to 221 * the string `scontext'.
222 * point to the end of the string representation of
223 * the MLS fields.
224 * 222 *
225 * This function modifies the string in place, inserting 223 * This function modifies the string in place, inserting
226 * NULL characters to terminate the MLS fields. 224 * NULL characters to terminate the MLS fields.
@@ -235,22 +233,21 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
235 */ 233 */
236int mls_context_to_sid(struct policydb *pol, 234int mls_context_to_sid(struct policydb *pol,
237 char oldc, 235 char oldc,
238 char **scontext, 236 char *scontext,
239 struct context *context, 237 struct context *context,
240 struct sidtab *s, 238 struct sidtab *s,
241 u32 def_sid) 239 u32 def_sid)
242{ 240{
243 241 char *sensitivity, *cur_cat, *next_cat, *rngptr;
244 char delim;
245 char *scontextp, *p, *rngptr;
246 struct level_datum *levdatum; 242 struct level_datum *levdatum;
247 struct cat_datum *catdatum, *rngdatum; 243 struct cat_datum *catdatum, *rngdatum;
248 int l, rc = -EINVAL; 244 int l, rc, i;
245 char *rangep[2];
249 246
250 if (!pol->mls_enabled) { 247 if (!pol->mls_enabled) {
251 if (def_sid != SECSID_NULL && oldc) 248 if ((def_sid != SECSID_NULL && oldc) || (*scontext) == '\0')
252 *scontext += strlen(*scontext) + 1; 249 return 0;
253 return 0; 250 return -EINVAL;
254 } 251 }
255 252
256 /* 253 /*
@@ -261,113 +258,94 @@ int mls_context_to_sid(struct policydb *pol,
261 struct context *defcon; 258 struct context *defcon;
262 259
263 if (def_sid == SECSID_NULL) 260 if (def_sid == SECSID_NULL)
264 goto out; 261 return -EINVAL;
265 262
266 defcon = sidtab_search(s, def_sid); 263 defcon = sidtab_search(s, def_sid);
267 if (!defcon) 264 if (!defcon)
268 goto out; 265 return -EINVAL;
269 266
270 rc = mls_context_cpy(context, defcon); 267 return mls_context_cpy(context, defcon);
271 goto out;
272 } 268 }
273 269
274 /* Extract low sensitivity. */ 270 /*
275 scontextp = p = *scontext; 271 * If we're dealing with a range, figure out where the two parts
276 while (*p && *p != ':' && *p != '-') 272 * of the range begin.
277 p++; 273 */
278 274 rangep[0] = scontext;
279 delim = *p; 275 rangep[1] = strchr(scontext, '-');
280 if (delim != '\0') 276 if (rangep[1]) {
281 *p++ = '\0'; 277 rangep[1][0] = '\0';
278 rangep[1]++;
279 }
282 280
281 /* For each part of the range: */
283 for (l = 0; l < 2; l++) { 282 for (l = 0; l < 2; l++) {
284 levdatum = hashtab_search(pol->p_levels.table, scontextp); 283 /* Split sensitivity and category set. */
285 if (!levdatum) { 284 sensitivity = rangep[l];
286 rc = -EINVAL; 285 if (sensitivity == NULL)
287 goto out; 286 break;
288 } 287 next_cat = strchr(sensitivity, ':');
288 if (next_cat)
289 *(next_cat++) = '\0';
289 290
291 /* Parse sensitivity. */
292 levdatum = hashtab_search(pol->p_levels.table, sensitivity);
293 if (!levdatum)
294 return -EINVAL;
290 context->range.level[l].sens = levdatum->level->sens; 295 context->range.level[l].sens = levdatum->level->sens;
291 296
292 if (delim == ':') { 297 /* Extract category set. */
293 /* Extract category set. */ 298 while (next_cat != NULL) {
294 while (1) { 299 cur_cat = next_cat;
295 scontextp = p; 300 next_cat = strchr(next_cat, ',');
296 while (*p && *p != ',' && *p != '-') 301 if (next_cat != NULL)
297 p++; 302 *(next_cat++) = '\0';
298 delim = *p; 303
299 if (delim != '\0') 304 /* Separate into range if exists */
300 *p++ = '\0'; 305 rngptr = strchr(cur_cat, '.');
301 306 if (rngptr != NULL) {
302 /* Separate into range if exists */ 307 /* Remove '.' */
303 rngptr = strchr(scontextp, '.'); 308 *rngptr++ = '\0';
304 if (rngptr != NULL) { 309 }
305 /* Remove '.' */
306 *rngptr++ = '\0';
307 }
308 310
309 catdatum = hashtab_search(pol->p_cats.table, 311 catdatum = hashtab_search(pol->p_cats.table, cur_cat);
310 scontextp); 312 if (!catdatum)
311 if (!catdatum) { 313 return -EINVAL;
312 rc = -EINVAL;
313 goto out;
314 }
315 314
316 rc = ebitmap_set_bit(&context->range.level[l].cat, 315 rc = ebitmap_set_bit(&context->range.level[l].cat,
317 catdatum->value - 1, 1); 316 catdatum->value - 1, 1);
318 if (rc) 317 if (rc)
319 goto out; 318 return rc;
320 319
321 /* If range, set all categories in range */ 320 /* If range, set all categories in range */
322 if (rngptr) { 321 if (rngptr == NULL)
323 int i; 322 continue;
324 323
325 rngdatum = hashtab_search(pol->p_cats.table, rngptr); 324 rngdatum = hashtab_search(pol->p_cats.table, rngptr);
326 if (!rngdatum) { 325 if (!rngdatum)
327 rc = -EINVAL; 326 return -EINVAL;
328 goto out; 327
329 } 328 if (catdatum->value >= rngdatum->value)
330 329 return -EINVAL;
331 if (catdatum->value >= rngdatum->value) {
332 rc = -EINVAL;
333 goto out;
334 }
335
336 for (i = catdatum->value; i < rngdatum->value; i++) {
337 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
338 if (rc)
339 goto out;
340 }
341 }
342 330
343 if (delim != ',') 331 for (i = catdatum->value; i < rngdatum->value; i++) {
344 break; 332 rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
333 if (rc)
334 return rc;
345 } 335 }
346 } 336 }
347 if (delim == '-') {
348 /* Extract high sensitivity. */
349 scontextp = p;
350 while (*p && *p != ':')
351 p++;
352
353 delim = *p;
354 if (delim != '\0')
355 *p++ = '\0';
356 } else
357 break;
358 } 337 }
359 338
360 if (l == 0) { 339 /* If we didn't see a '-', the range start is also the range end. */
340 if (rangep[1] == NULL) {
361 context->range.level[1].sens = context->range.level[0].sens; 341 context->range.level[1].sens = context->range.level[0].sens;
362 rc = ebitmap_cpy(&context->range.level[1].cat, 342 rc = ebitmap_cpy(&context->range.level[1].cat,
363 &context->range.level[0].cat); 343 &context->range.level[0].cat);
364 if (rc) 344 if (rc)
365 goto out; 345 return rc;
366 } 346 }
367 *scontext = ++p; 347
368 rc = 0; 348 return 0;
369out:
370 return rc;
371} 349}
372 350
373/* 351/*
@@ -379,21 +357,19 @@ out:
379int mls_from_string(struct policydb *p, char *str, struct context *context, 357int mls_from_string(struct policydb *p, char *str, struct context *context,
380 gfp_t gfp_mask) 358 gfp_t gfp_mask)
381{ 359{
382 char *tmpstr, *freestr; 360 char *tmpstr;
383 int rc; 361 int rc;
384 362
385 if (!p->mls_enabled) 363 if (!p->mls_enabled)
386 return -EINVAL; 364 return -EINVAL;
387 365
388 /* we need freestr because mls_context_to_sid will change 366 tmpstr = kstrdup(str, gfp_mask);
389 the value of tmpstr */
390 tmpstr = freestr = kstrdup(str, gfp_mask);
391 if (!tmpstr) { 367 if (!tmpstr) {
392 rc = -ENOMEM; 368 rc = -ENOMEM;
393 } else { 369 } else {
394 rc = mls_context_to_sid(p, ':', &tmpstr, context, 370 rc = mls_context_to_sid(p, ':', tmpstr, context,
395 NULL, SECSID_NULL); 371 NULL, SECSID_NULL);
396 kfree(freestr); 372 kfree(tmpstr);
397 } 373 }
398 374
399 return rc; 375 return rc;