Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

SELinux: add boundary support and thread context assignment

The purpose of this patch is to assign per-thread security context
under a constraint. It enables multi-threaded server application
to kick a request handler with its fair security context, and
helps some of userspace object managers to handle user's request.

When we assign a per-thread security context, it must not have wider
permissions than the original one. Because a multi-threaded process
shares a single local memory, an arbitary per-thread security context
also means another thread can easily refer violated information.

The constraint on a per-thread security context requires a new domain
has to be equal or weaker than its original one, when it tries to assign
a per-thread security context.

Bounds relationship between two types is a way to ensure a domain can
never have wider permission than its bounds. We can define it in two
explicit or implicit ways.

The first way is using new TYPEBOUNDS statement. It enables to define
a boundary of types explicitly. The other one expand the concept of
existing named based hierarchy. If we defines a type with "." separated
name like "httpd_t.php", toolchain implicitly set its bounds on "httpd_t".

This feature requires a new policy version.
The 24th version (POLICYDB_VERSION_BOUNDARY) enables to ship them into
kernel space, and the following patch enables to handle it.

Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: James Morris <jmorris@namei.org>

authored by

KaiGai Kohei and committed by
James Morris
d9250dea da31894e

+398 -20
+1 -1
security/selinux/avc.c
··· 136 136 * @tclass: target security class 137 137 * @av: access vector 138 138 */ 139 - static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) 139 + void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) 140 140 { 141 141 const char **common_pts = NULL; 142 142 u32 common_base = 0;
+12 -3
security/selinux/hooks.c
··· 5226 5226 5227 5227 if (sid == 0) 5228 5228 return -EINVAL; 5229 - 5230 - /* Only allow single threaded processes to change context */ 5229 + /* 5230 + * SELinux allows to change context in the following case only. 5231 + * - Single threaded processes. 5232 + * - Multi threaded processes intend to change its context into 5233 + * more restricted domain (defined by TYPEBOUNDS statement). 5234 + */ 5231 5235 if (atomic_read(&p->mm->mm_users) != 1) { 5232 5236 struct task_struct *g, *t; 5233 5237 struct mm_struct *mm = p->mm; ··· 5239 5235 do_each_thread(g, t) { 5240 5236 if (t->mm == mm && t != p) { 5241 5237 read_unlock(&tasklist_lock); 5242 - return -EPERM; 5238 + error = security_bounded_transition(tsec->sid, sid); 5239 + if (!error) 5240 + goto boundary_ok; 5241 + 5242 + return error; 5243 5243 } 5244 5244 } while_each_thread(g, t); 5245 5245 read_unlock(&tasklist_lock); 5246 5246 } 5247 + boundary_ok: 5247 5248 5248 5249 /* Check permissions for the transition. */ 5249 5250 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
+4
security/selinux/include/avc.h
··· 12 12 #include <linux/kdev_t.h> 13 13 #include <linux/spinlock.h> 14 14 #include <linux/init.h> 15 + #include <linux/audit.h> 15 16 #include <linux/in6.h> 16 17 #include <linux/path.h> 17 18 #include <asm/system.h> ··· 126 125 u32 *out_retained), 127 126 u32 events, u32 ssid, u32 tsid, 128 127 u16 tclass, u32 perms); 128 + 129 + /* Shows permission in human readable form */ 130 + void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av); 129 131 130 132 /* Exported to selinuxfs */ 131 133 int avc_get_hash_stats(char *page);
+14 -1
security/selinux/include/security.h
··· 27 27 #define POLICYDB_VERSION_RANGETRANS 21 28 28 #define POLICYDB_VERSION_POLCAP 22 29 29 #define POLICYDB_VERSION_PERMISSIVE 23 30 + #define POLICYDB_VERSION_BOUNDARY 24 30 31 31 32 /* Range of policy versions we understand*/ 32 33 #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE 33 34 #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX 34 35 #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE 35 36 #else 36 - #define POLICYDB_VERSION_MAX POLICYDB_VERSION_PERMISSIVE 37 + #define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY 37 38 #endif 38 39 39 40 #define CONTEXT_MNT 0x01 ··· 62 61 63 62 extern int selinux_policycap_netpeer; 64 63 extern int selinux_policycap_openperm; 64 + 65 + /* 66 + * type_datum properties 67 + * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY 68 + */ 69 + #define TYPEDATUM_PROPERTY_PRIMARY 0x0001 70 + #define TYPEDATUM_PROPERTY_ATTRIBUTE 0x0002 71 + 72 + /* limitation of boundary depth */ 73 + #define POLICYDB_BOUNDS_MAXDEPTH 4 65 74 66 75 int security_load_policy(void *data, size_t len); 67 76 ··· 127 116 128 117 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, 129 118 u16 tclass); 119 + 120 + int security_bounded_transition(u32 oldsid, u32 newsid); 130 121 131 122 int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); 132 123
+191 -14
security/selinux/ss/policydb.c
··· 30 30 #include <linux/slab.h> 31 31 #include <linux/string.h> 32 32 #include <linux/errno.h> 33 + #include <linux/audit.h> 33 34 #include "security.h" 34 35 35 36 #include "policydb.h" ··· 117 116 .version = POLICYDB_VERSION_PERMISSIVE, 118 117 .sym_num = SYM_NUM, 119 118 .ocon_num = OCON_NUM, 120 - } 119 + }, 120 + { 121 + .version = POLICYDB_VERSION_BOUNDARY, 122 + .sym_num = SYM_NUM, 123 + .ocon_num = OCON_NUM, 124 + }, 121 125 }; 122 126 123 127 static struct policydb_compat_info *policydb_lookup_compat(int version) ··· 260 254 261 255 role = datum; 262 256 p = datap; 263 - if (!role->value || role->value > p->p_roles.nprim) 257 + if (!role->value 258 + || role->value > p->p_roles.nprim 259 + || role->bounds > p->p_roles.nprim) 264 260 return -EINVAL; 265 261 p->p_role_val_to_name[role->value - 1] = key; 266 262 p->role_val_to_struct[role->value - 1] = role; ··· 278 270 p = datap; 279 271 280 272 if (typdatum->primary) { 281 - if (!typdatum->value || typdatum->value > p->p_types.nprim) 273 + if (!typdatum->value 274 + || typdatum->value > p->p_types.nprim 275 + || typdatum->bounds > p->p_types.nprim) 282 276 return -EINVAL; 283 277 p->p_type_val_to_name[typdatum->value - 1] = key; 278 + p->type_val_to_struct[typdatum->value - 1] = typdatum; 284 279 } 285 280 286 281 return 0; ··· 296 285 297 286 usrdatum = datum; 298 287 p = datap; 299 - if (!usrdatum->value || usrdatum->value > p->p_users.nprim) 288 + if (!usrdatum->value 289 + || usrdatum->value > p->p_users.nprim 290 + || usrdatum->bounds > p->p_users.nprim) 300 291 return -EINVAL; 301 292 p->p_user_val_to_name[usrdatum->value - 1] = key; 302 293 p->user_val_to_struct[usrdatum->value - 1] = usrdatum; ··· 447 434 kmalloc(p->p_users.nprim * sizeof(*(p->user_val_to_struct)), 448 435 GFP_KERNEL); 449 436 if (!p->user_val_to_struct) { 437 + rc = -ENOMEM; 438 + goto out; 439 + } 440 + 441 + p->type_val_to_struct = 442 + kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)), 443 + GFP_KERNEL); 444 + if (!p->type_val_to_struct) { 450 445 rc = -ENOMEM; 451 446 goto out; 452 447 } ··· 646 625 kfree(p->class_val_to_struct); 647 626 kfree(p->role_val_to_struct); 648 627 kfree(p->user_val_to_struct); 628 + kfree(p->type_val_to_struct); 649 629 650 630 avtab_destroy(&p->te_avtab); 651 631 ··· 1198 1176 { 1199 1177 char *key = NULL; 1200 1178 struct role_datum *role; 1201 - int rc; 1202 - __le32 buf[2]; 1179 + int rc, to_read = 2; 1180 + __le32 buf[3]; 1203 1181 u32 len; 1204 1182 1205 1183 role = kzalloc(sizeof(*role), GFP_KERNEL); ··· 1208 1186 goto out; 1209 1187 } 1210 1188 1211 - rc = next_entry(buf, fp, sizeof buf); 1189 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) 1190 + to_read = 3; 1191 + 1192 + rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); 1212 1193 if (rc < 0) 1213 1194 goto bad; 1214 1195 1215 1196 len = le32_to_cpu(buf[0]); 1216 1197 role->value = le32_to_cpu(buf[1]); 1198 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) 1199 + role->bounds = le32_to_cpu(buf[2]); 1217 1200 1218 1201 key = kmalloc(len + 1, GFP_KERNEL); 1219 1202 if (!key) { ··· 1263 1236 { 1264 1237 char *key = NULL; 1265 1238 struct type_datum *typdatum; 1266 - int rc; 1267 - __le32 buf[3]; 1239 + int rc, to_read = 3; 1240 + __le32 buf[4]; 1268 1241 u32 len; 1269 1242 1270 1243 typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); ··· 1273 1246 return rc; 1274 1247 } 1275 1248 1276 - rc = next_entry(buf, fp, sizeof buf); 1249 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) 1250 + to_read = 4; 1251 + 1252 + rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); 1277 1253 if (rc < 0) 1278 1254 goto bad; 1279 1255 1280 1256 len = le32_to_cpu(buf[0]); 1281 1257 typdatum->value = le32_to_cpu(buf[1]); 1282 - typdatum->primary = le32_to_cpu(buf[2]); 1258 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) { 1259 + u32 prop = le32_to_cpu(buf[2]); 1260 + 1261 + if (prop & TYPEDATUM_PROPERTY_PRIMARY) 1262 + typdatum->primary = 1; 1263 + if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE) 1264 + typdatum->attribute = 1; 1265 + 1266 + typdatum->bounds = le32_to_cpu(buf[3]); 1267 + } else { 1268 + typdatum->primary = le32_to_cpu(buf[2]); 1269 + } 1283 1270 1284 1271 key = kmalloc(len + 1, GFP_KERNEL); 1285 1272 if (!key) { ··· 1350 1309 { 1351 1310 char *key = NULL; 1352 1311 struct user_datum *usrdatum; 1353 - int rc; 1354 - __le32 buf[2]; 1312 + int rc, to_read = 2; 1313 + __le32 buf[3]; 1355 1314 u32 len; 1356 1315 1357 1316 usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL); ··· 1360 1319 goto out; 1361 1320 } 1362 1321 1363 - rc = next_entry(buf, fp, sizeof buf); 1322 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) 1323 + to_read = 3; 1324 + 1325 + rc = next_entry(buf, fp, sizeof(buf[0]) * to_read); 1364 1326 if (rc < 0) 1365 1327 goto bad; 1366 1328 1367 1329 len = le32_to_cpu(buf[0]); 1368 1330 usrdatum->value = le32_to_cpu(buf[1]); 1331 + if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) 1332 + usrdatum->bounds = le32_to_cpu(buf[2]); 1369 1333 1370 1334 key = kmalloc(len + 1, GFP_KERNEL); 1371 1335 if (!key) { ··· 1510 1464 sens_read, 1511 1465 cat_read, 1512 1466 }; 1467 + 1468 + static int user_bounds_sanity_check(void *key, void *datum, void *datap) 1469 + { 1470 + struct user_datum *upper, *user; 1471 + struct policydb *p = datap; 1472 + int depth = 0; 1473 + 1474 + upper = user = datum; 1475 + while (upper->bounds) { 1476 + struct ebitmap_node *node; 1477 + unsigned long bit; 1478 + 1479 + if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { 1480 + printk(KERN_ERR "SELinux: user %s: " 1481 + "too deep or looped boundary", 1482 + (char *) key); 1483 + return -EINVAL; 1484 + } 1485 + 1486 + upper = p->user_val_to_struct[upper->bounds - 1]; 1487 + ebitmap_for_each_positive_bit(&user->roles, node, bit) { 1488 + if (ebitmap_get_bit(&upper->roles, bit)) 1489 + continue; 1490 + 1491 + printk(KERN_ERR 1492 + "SELinux: boundary violated policy: " 1493 + "user=%s role=%s bounds=%s\n", 1494 + p->p_user_val_to_name[user->value - 1], 1495 + p->p_role_val_to_name[bit], 1496 + p->p_user_val_to_name[upper->value - 1]); 1497 + 1498 + return -EINVAL; 1499 + } 1500 + } 1501 + 1502 + return 0; 1503 + } 1504 + 1505 + static int role_bounds_sanity_check(void *key, void *datum, void *datap) 1506 + { 1507 + struct role_datum *upper, *role; 1508 + struct policydb *p = datap; 1509 + int depth = 0; 1510 + 1511 + upper = role = datum; 1512 + while (upper->bounds) { 1513 + struct ebitmap_node *node; 1514 + unsigned long bit; 1515 + 1516 + if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { 1517 + printk(KERN_ERR "SELinux: role %s: " 1518 + "too deep or looped bounds\n", 1519 + (char *) key); 1520 + return -EINVAL; 1521 + } 1522 + 1523 + upper = p->role_val_to_struct[upper->bounds - 1]; 1524 + ebitmap_for_each_positive_bit(&role->types, node, bit) { 1525 + if (ebitmap_get_bit(&upper->types, bit)) 1526 + continue; 1527 + 1528 + printk(KERN_ERR 1529 + "SELinux: boundary violated policy: " 1530 + "role=%s type=%s bounds=%s\n", 1531 + p->p_role_val_to_name[role->value - 1], 1532 + p->p_type_val_to_name[bit], 1533 + p->p_role_val_to_name[upper->value - 1]); 1534 + 1535 + return -EINVAL; 1536 + } 1537 + } 1538 + 1539 + return 0; 1540 + } 1541 + 1542 + static int type_bounds_sanity_check(void *key, void *datum, void *datap) 1543 + { 1544 + struct type_datum *upper, *type; 1545 + struct policydb *p = datap; 1546 + int depth = 0; 1547 + 1548 + upper = type = datum; 1549 + while (upper->bounds) { 1550 + if (++depth == POLICYDB_BOUNDS_MAXDEPTH) { 1551 + printk(KERN_ERR "SELinux: type %s: " 1552 + "too deep or looped boundary\n", 1553 + (char *) key); 1554 + return -EINVAL; 1555 + } 1556 + 1557 + upper = p->type_val_to_struct[upper->bounds - 1]; 1558 + if (upper->attribute) { 1559 + printk(KERN_ERR "SELinux: type %s: " 1560 + "bounded by attribute %s", 1561 + (char *) key, 1562 + p->p_type_val_to_name[upper->value - 1]); 1563 + return -EINVAL; 1564 + } 1565 + } 1566 + 1567 + return 0; 1568 + } 1569 + 1570 + static int policydb_bounds_sanity_check(struct policydb *p) 1571 + { 1572 + int rc; 1573 + 1574 + if (p->policyvers < POLICYDB_VERSION_BOUNDARY) 1575 + return 0; 1576 + 1577 + rc = hashtab_map(p->p_users.table, 1578 + user_bounds_sanity_check, p); 1579 + if (rc) 1580 + return rc; 1581 + 1582 + rc = hashtab_map(p->p_roles.table, 1583 + role_bounds_sanity_check, p); 1584 + if (rc) 1585 + return rc; 1586 + 1587 + rc = hashtab_map(p->p_types.table, 1588 + type_bounds_sanity_check, p); 1589 + if (rc) 1590 + return rc; 1591 + 1592 + return 0; 1593 + } 1513 1594 1514 1595 extern int ss_initialized; 1515 1596 ··· 2133 1960 if (ebitmap_set_bit(&p->type_attr_map[i], i, 1)) 2134 1961 goto bad; 2135 1962 } 1963 + 1964 + rc = policydb_bounds_sanity_check(p); 1965 + if (rc) 1966 + goto bad; 2136 1967 2137 1968 rc = 0; 2138 1969 out:
+5
security/selinux/ss/policydb.h
··· 61 61 /* Role attributes */ 62 62 struct role_datum { 63 63 u32 value; /* internal role value */ 64 + u32 bounds; /* boundary of role */ 64 65 struct ebitmap dominates; /* set of roles dominated by this role */ 65 66 struct ebitmap types; /* set of authorized types for role */ 66 67 }; ··· 82 81 /* Type attributes */ 83 82 struct type_datum { 84 83 u32 value; /* internal type value */ 84 + u32 bounds; /* boundary of type */ 85 85 unsigned char primary; /* primary name? */ 86 + unsigned char attribute;/* attribute ?*/ 86 87 }; 87 88 88 89 /* User attributes */ 89 90 struct user_datum { 90 91 u32 value; /* internal user value */ 92 + u32 bounds; /* bounds of user */ 91 93 struct ebitmap roles; /* set of authorized roles for user */ 92 94 struct mls_range range; /* MLS range (min - max) for user */ 93 95 struct mls_level dfltlevel; /* default login MLS level for user */ ··· 213 209 struct class_datum **class_val_to_struct; 214 210 struct role_datum **role_val_to_struct; 215 211 struct user_datum **user_val_to_struct; 212 + struct type_datum **type_val_to_struct; 216 213 217 214 /* type enforcement access vectors and transitions */ 218 215 struct avtab te_avtab;
+171 -1
security/selinux/ss/services.c
··· 88 88 static int context_struct_to_string(struct context *context, char **scontext, 89 89 u32 *scontext_len); 90 90 91 + static int context_struct_compute_av(struct context *scontext, 92 + struct context *tcontext, 93 + u16 tclass, 94 + u32 requested, 95 + struct av_decision *avd); 91 96 /* 92 97 * Return the boolean value of a constraint expression 93 98 * when it is applied to the specified source and target ··· 279 274 } 280 275 281 276 /* 277 + * security_boundary_permission - drops violated permissions 278 + * on boundary constraint. 279 + */ 280 + static void type_attribute_bounds_av(struct context *scontext, 281 + struct context *tcontext, 282 + u16 tclass, 283 + u32 requested, 284 + struct av_decision *avd) 285 + { 286 + struct context lo_scontext; 287 + struct context lo_tcontext; 288 + struct av_decision lo_avd; 289 + struct type_datum *source 290 + = policydb.type_val_to_struct[scontext->type - 1]; 291 + struct type_datum *target 292 + = policydb.type_val_to_struct[tcontext->type - 1]; 293 + u32 masked = 0; 294 + 295 + if (source->bounds) { 296 + memset(&lo_avd, 0, sizeof(lo_avd)); 297 + 298 + memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); 299 + lo_scontext.type = source->bounds; 300 + 301 + context_struct_compute_av(&lo_scontext, 302 + tcontext, 303 + tclass, 304 + requested, 305 + &lo_avd); 306 + if ((lo_avd.allowed & avd->allowed) == avd->allowed) 307 + return; /* no masked permission */ 308 + masked = ~lo_avd.allowed & avd->allowed; 309 + } 310 + 311 + if (target->bounds) { 312 + memset(&lo_avd, 0, sizeof(lo_avd)); 313 + 314 + memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); 315 + lo_tcontext.type = target->bounds; 316 + 317 + context_struct_compute_av(scontext, 318 + &lo_tcontext, 319 + tclass, 320 + requested, 321 + &lo_avd); 322 + if ((lo_avd.allowed & avd->allowed) == avd->allowed) 323 + return; /* no masked permission */ 324 + masked = ~lo_avd.allowed & avd->allowed; 325 + } 326 + 327 + if (source->bounds && target->bounds) { 328 + memset(&lo_avd, 0, sizeof(lo_avd)); 329 + /* 330 + * lo_scontext and lo_tcontext are already 331 + * set up. 332 + */ 333 + 334 + context_struct_compute_av(&lo_scontext, 335 + &lo_tcontext, 336 + tclass, 337 + requested, 338 + &lo_avd); 339 + if ((lo_avd.allowed & avd->allowed) == avd->allowed) 340 + return; /* no masked permission */ 341 + masked = ~lo_avd.allowed & avd->allowed; 342 + } 343 + 344 + if (masked) { 345 + struct audit_buffer *ab; 346 + char *stype_name 347 + = policydb.p_type_val_to_name[source->value - 1]; 348 + char *ttype_name 349 + = policydb.p_type_val_to_name[target->value - 1]; 350 + char *tclass_name 351 + = policydb.p_class_val_to_name[tclass - 1]; 352 + 353 + /* mask violated permissions */ 354 + avd->allowed &= ~masked; 355 + 356 + /* notice to userspace via audit message */ 357 + ab = audit_log_start(current->audit_context, 358 + GFP_ATOMIC, AUDIT_SELINUX_ERR); 359 + if (!ab) 360 + return; 361 + 362 + audit_log_format(ab, "av boundary violation: " 363 + "source=%s target=%s tclass=%s", 364 + stype_name, ttype_name, tclass_name); 365 + avc_dump_av(ab, tclass, masked); 366 + audit_log_end(ab); 367 + } 368 + } 369 + 370 + /* 282 371 * Compute access vectors based on a context structure pair for 283 372 * the permissions in a particular class. 284 373 */ ··· 502 403 avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION | 503 404 PROCESS__DYNTRANSITION); 504 405 } 406 + 407 + /* 408 + * If the given source and target types have boundary 409 + * constraint, lazy checks have to mask any violated 410 + * permission and notice it to userspace via audit. 411 + */ 412 + type_attribute_bounds_av(scontext, tcontext, 413 + tclass, requested, avd); 505 414 506 415 return 0; 507 416 ··· 655 548 read_unlock(&policy_rwlock); 656 549 return rc; 657 550 } 551 + 552 + /* 553 + * security_bounded_transition - check whether the given 554 + * transition is directed to bounded, or not. 555 + * It returns 0, if @newsid is bounded by @oldsid. 556 + * Otherwise, it returns error code. 557 + * 558 + * @oldsid : current security identifier 559 + * @newsid : destinated security identifier 560 + */ 561 + int security_bounded_transition(u32 old_sid, u32 new_sid) 562 + { 563 + struct context *old_context, *new_context; 564 + struct type_datum *type; 565 + int index; 566 + int rc = -EINVAL; 567 + 568 + read_lock(&policy_rwlock); 569 + 570 + old_context = sidtab_search(&sidtab, old_sid); 571 + if (!old_context) { 572 + printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", 573 + __func__, old_sid); 574 + goto out; 575 + } 576 + 577 + new_context = sidtab_search(&sidtab, new_sid); 578 + if (!new_context) { 579 + printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", 580 + __func__, new_sid); 581 + goto out; 582 + } 583 + 584 + /* type/domain unchaned */ 585 + if (old_context->type == new_context->type) { 586 + rc = 0; 587 + goto out; 588 + } 589 + 590 + index = new_context->type; 591 + while (true) { 592 + type = policydb.type_val_to_struct[index - 1]; 593 + BUG_ON(!type); 594 + 595 + /* not bounded anymore */ 596 + if (!type->bounds) { 597 + rc = -EPERM; 598 + break; 599 + } 600 + 601 + /* @newsid is bounded by @oldsid */ 602 + if (type->bounds == old_context->type) { 603 + rc = 0; 604 + break; 605 + } 606 + index = type->bounds; 607 + } 608 + out: 609 + read_unlock(&policy_rwlock); 610 + 611 + return rc; 612 + } 613 + 658 614 659 615 /** 660 616 * security_compute_av - Compute access vector decisions. ··· 964 794 *p++ = 0; 965 795 966 796 typdatum = hashtab_search(pol->p_types.table, scontextp); 967 - if (!typdatum) 797 + if (!typdatum || typdatum->attribute) 968 798 goto out; 969 799 970 800 ctx->type = typdatum->value;