aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorKaiGai Kohei <kaigai@ak.jp.nec.com>2008-08-28 03:35:57 -0400
committerJames Morris <jmorris@namei.org>2008-08-28 10:33:33 -0400
commitd9250dea3f89fe808a525f08888016b495240ed4 (patch)
treec4b039ce0b29714e8f4c3bbc6d407adc361cc122 /security
parentda31894ed7b654e2e1741e7ac4ef6c15be0dd14b (diff)
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>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/avc.c2
-rw-r--r--security/selinux/hooks.c15
-rw-r--r--security/selinux/include/avc.h4
-rw-r--r--security/selinux/include/security.h15
-rw-r--r--security/selinux/ss/policydb.c205
-rw-r--r--security/selinux/ss/policydb.h5
-rw-r--r--security/selinux/ss/services.c172
7 files changed, 398 insertions, 20 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 114b4b4c97b2..cb30c7e350b3 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -136,7 +136,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
136 * @tclass: target security class 136 * @tclass: target security class
137 * @av: access vector 137 * @av: access vector
138 */ 138 */
139static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) 139void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
140{ 140{
141 const char **common_pts = NULL; 141 const char **common_pts = NULL;
142 u32 common_base = 0; 142 u32 common_base = 0;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6b5790bba8f9..89f446d86054 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5226,8 +5226,12 @@ static int selinux_setprocattr(struct task_struct *p,
5226 5226
5227 if (sid == 0) 5227 if (sid == 0)
5228 return -EINVAL; 5228 return -EINVAL;
5229 5229 /*
5230 /* Only allow single threaded processes to change context */ 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 if (atomic_read(&p->mm->mm_users) != 1) { 5235 if (atomic_read(&p->mm->mm_users) != 1) {
5232 struct task_struct *g, *t; 5236 struct task_struct *g, *t;
5233 struct mm_struct *mm = p->mm; 5237 struct mm_struct *mm = p->mm;
@@ -5235,11 +5239,16 @@ static int selinux_setprocattr(struct task_struct *p,
5235 do_each_thread(g, t) { 5239 do_each_thread(g, t) {
5236 if (t->mm == mm && t != p) { 5240 if (t->mm == mm && t != p) {
5237 read_unlock(&tasklist_lock); 5241 read_unlock(&tasklist_lock);
5238 return -EPERM; 5242 error = security_bounded_transition(tsec->sid, sid);
5243 if (!error)
5244 goto boundary_ok;
5245
5246 return error;
5239 } 5247 }
5240 } while_each_thread(g, t); 5248 } while_each_thread(g, t);
5241 read_unlock(&tasklist_lock); 5249 read_unlock(&tasklist_lock);
5242 } 5250 }
5251boundary_ok:
5243 5252
5244 /* Check permissions for the transition. */ 5253 /* Check permissions for the transition. */
5245 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, 5254 error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 7b9769f5e775..d12ff1a9c0aa 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -12,6 +12,7 @@
12#include <linux/kdev_t.h> 12#include <linux/kdev_t.h>
13#include <linux/spinlock.h> 13#include <linux/spinlock.h>
14#include <linux/init.h> 14#include <linux/init.h>
15#include <linux/audit.h>
15#include <linux/in6.h> 16#include <linux/in6.h>
16#include <linux/path.h> 17#include <linux/path.h>
17#include <asm/system.h> 18#include <asm/system.h>
@@ -126,6 +127,9 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
126 u32 events, u32 ssid, u32 tsid, 127 u32 events, u32 ssid, u32 tsid,
127 u16 tclass, u32 perms); 128 u16 tclass, u32 perms);
128 129
130/* Shows permission in human readable form */
131void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
132
129/* Exported to selinuxfs */ 133/* Exported to selinuxfs */
130int avc_get_hash_stats(char *page); 134int avc_get_hash_stats(char *page);
131extern unsigned int avc_cache_threshold; 135extern unsigned int avc_cache_threshold;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 7c543003d653..72447370bc95 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -27,13 +27,14 @@
27#define POLICYDB_VERSION_RANGETRANS 21 27#define POLICYDB_VERSION_RANGETRANS 21
28#define POLICYDB_VERSION_POLCAP 22 28#define POLICYDB_VERSION_POLCAP 22
29#define POLICYDB_VERSION_PERMISSIVE 23 29#define POLICYDB_VERSION_PERMISSIVE 23
30#define POLICYDB_VERSION_BOUNDARY 24
30 31
31/* Range of policy versions we understand*/ 32/* Range of policy versions we understand*/
32#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE 33#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
33#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX 34#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
34#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE 35#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
35#else 36#else
36#define POLICYDB_VERSION_MAX POLICYDB_VERSION_PERMISSIVE 37#define POLICYDB_VERSION_MAX POLICYDB_VERSION_BOUNDARY
37#endif 38#endif
38 39
39#define CONTEXT_MNT 0x01 40#define CONTEXT_MNT 0x01
@@ -62,6 +63,16 @@ enum {
62extern int selinux_policycap_netpeer; 63extern int selinux_policycap_netpeer;
63extern int selinux_policycap_openperm; 64extern int selinux_policycap_openperm;
64 65
66/*
67 * type_datum properties
68 * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
69 */
70#define TYPEDATUM_PROPERTY_PRIMARY 0x0001
71#define TYPEDATUM_PROPERTY_ATTRIBUTE 0x0002
72
73/* limitation of boundary depth */
74#define POLICYDB_BOUNDS_MAXDEPTH 4
75
65int security_load_policy(void *data, size_t len); 76int security_load_policy(void *data, size_t len);
66 77
67int security_policycap_supported(unsigned int req_cap); 78int security_policycap_supported(unsigned int req_cap);
@@ -117,6 +128,8 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
117int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, 128int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
118 u16 tclass); 129 u16 tclass);
119 130
131int security_bounded_transition(u32 oldsid, u32 newsid);
132
120int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); 133int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
121 134
122int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, 135int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 26646305dc0e..72e4a54973aa 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -30,6 +30,7 @@
30#include <linux/slab.h> 30#include <linux/slab.h>
31#include <linux/string.h> 31#include <linux/string.h>
32#include <linux/errno.h> 32#include <linux/errno.h>
33#include <linux/audit.h>
33#include "security.h" 34#include "security.h"
34 35
35#include "policydb.h" 36#include "policydb.h"
@@ -116,7 +117,12 @@ static struct policydb_compat_info policydb_compat[] = {
116 .version = POLICYDB_VERSION_PERMISSIVE, 117 .version = POLICYDB_VERSION_PERMISSIVE,
117 .sym_num = SYM_NUM, 118 .sym_num = SYM_NUM,
118 .ocon_num = OCON_NUM, 119 .ocon_num = OCON_NUM,
119 } 120 },
121 {
122 .version = POLICYDB_VERSION_BOUNDARY,
123 .sym_num = SYM_NUM,
124 .ocon_num = OCON_NUM,
125 },
120}; 126};
121 127
122static struct policydb_compat_info *policydb_lookup_compat(int version) 128static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -254,7 +260,9 @@ static int role_index(void *key, void *datum, void *datap)
254 260
255 role = datum; 261 role = datum;
256 p = datap; 262 p = datap;
257 if (!role->value || role->value > p->p_roles.nprim) 263 if (!role->value
264 || role->value > p->p_roles.nprim
265 || role->bounds > p->p_roles.nprim)
258 return -EINVAL; 266 return -EINVAL;
259 p->p_role_val_to_name[role->value - 1] = key; 267 p->p_role_val_to_name[role->value - 1] = key;
260 p->role_val_to_struct[role->value - 1] = role; 268 p->role_val_to_struct[role->value - 1] = role;
@@ -270,9 +278,12 @@ static int type_index(void *key, void *datum, void *datap)
270 p = datap; 278 p = datap;
271 279
272 if (typdatum->primary) { 280 if (typdatum->primary) {
273 if (!typdatum->value || typdatum->value > p->p_types.nprim) 281 if (!typdatum->value
282 || typdatum->value > p->p_types.nprim
283 || typdatum->bounds > p->p_types.nprim)
274 return -EINVAL; 284 return -EINVAL;
275 p->p_type_val_to_name[typdatum->value - 1] = key; 285 p->p_type_val_to_name[typdatum->value - 1] = key;
286 p->type_val_to_struct[typdatum->value - 1] = typdatum;
276 } 287 }
277 288
278 return 0; 289 return 0;
@@ -285,7 +296,9 @@ static int user_index(void *key, void *datum, void *datap)
285 296
286 usrdatum = datum; 297 usrdatum = datum;
287 p = datap; 298 p = datap;
288 if (!usrdatum->value || usrdatum->value > p->p_users.nprim) 299 if (!usrdatum->value
300 || usrdatum->value > p->p_users.nprim
301 || usrdatum->bounds > p->p_users.nprim)
289 return -EINVAL; 302 return -EINVAL;
290 p->p_user_val_to_name[usrdatum->value - 1] = key; 303 p->p_user_val_to_name[usrdatum->value - 1] = key;
291 p->user_val_to_struct[usrdatum->value - 1] = usrdatum; 304 p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
@@ -438,6 +451,14 @@ static int policydb_index_others(struct policydb *p)
438 goto out; 451 goto out;
439 } 452 }
440 453
454 p->type_val_to_struct =
455 kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)),
456 GFP_KERNEL);
457 if (!p->type_val_to_struct) {
458 rc = -ENOMEM;
459 goto out;
460 }
461
441 if (cond_init_bool_indexes(p)) { 462 if (cond_init_bool_indexes(p)) {
442 rc = -ENOMEM; 463 rc = -ENOMEM;
443 goto out; 464 goto out;
@@ -625,6 +646,7 @@ void policydb_destroy(struct policydb *p)
625 kfree(p->class_val_to_struct); 646 kfree(p->class_val_to_struct);
626 kfree(p->role_val_to_struct); 647 kfree(p->role_val_to_struct);
627 kfree(p->user_val_to_struct); 648 kfree(p->user_val_to_struct);
649 kfree(p->type_val_to_struct);
628 650
629 avtab_destroy(&p->te_avtab); 651 avtab_destroy(&p->te_avtab);
630 652
@@ -1176,8 +1198,8 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
1176{ 1198{
1177 char *key = NULL; 1199 char *key = NULL;
1178 struct role_datum *role; 1200 struct role_datum *role;
1179 int rc; 1201 int rc, to_read = 2;
1180 __le32 buf[2]; 1202 __le32 buf[3];
1181 u32 len; 1203 u32 len;
1182 1204
1183 role = kzalloc(sizeof(*role), GFP_KERNEL); 1205 role = kzalloc(sizeof(*role), GFP_KERNEL);
@@ -1186,12 +1208,17 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
1186 goto out; 1208 goto out;
1187 } 1209 }
1188 1210
1189 rc = next_entry(buf, fp, sizeof buf); 1211 if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
1212 to_read = 3;
1213
1214 rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
1190 if (rc < 0) 1215 if (rc < 0)
1191 goto bad; 1216 goto bad;
1192 1217
1193 len = le32_to_cpu(buf[0]); 1218 len = le32_to_cpu(buf[0]);
1194 role->value = le32_to_cpu(buf[1]); 1219 role->value = le32_to_cpu(buf[1]);
1220 if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
1221 role->bounds = le32_to_cpu(buf[2]);
1195 1222
1196 key = kmalloc(len + 1, GFP_KERNEL); 1223 key = kmalloc(len + 1, GFP_KERNEL);
1197 if (!key) { 1224 if (!key) {
@@ -1236,8 +1263,8 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
1236{ 1263{
1237 char *key = NULL; 1264 char *key = NULL;
1238 struct type_datum *typdatum; 1265 struct type_datum *typdatum;
1239 int rc; 1266 int rc, to_read = 3;
1240 __le32 buf[3]; 1267 __le32 buf[4];
1241 u32 len; 1268 u32 len;
1242 1269
1243 typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); 1270 typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
@@ -1246,13 +1273,27 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
1246 return rc; 1273 return rc;
1247 } 1274 }
1248 1275
1249 rc = next_entry(buf, fp, sizeof buf); 1276 if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
1277 to_read = 4;
1278
1279 rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
1250 if (rc < 0) 1280 if (rc < 0)
1251 goto bad; 1281 goto bad;
1252 1282
1253 len = le32_to_cpu(buf[0]); 1283 len = le32_to_cpu(buf[0]);
1254 typdatum->value = le32_to_cpu(buf[1]); 1284 typdatum->value = le32_to_cpu(buf[1]);
1255 typdatum->primary = le32_to_cpu(buf[2]); 1285 if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
1286 u32 prop = le32_to_cpu(buf[2]);
1287
1288 if (prop & TYPEDATUM_PROPERTY_PRIMARY)
1289 typdatum->primary = 1;
1290 if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE)
1291 typdatum->attribute = 1;
1292
1293 typdatum->bounds = le32_to_cpu(buf[3]);
1294 } else {
1295 typdatum->primary = le32_to_cpu(buf[2]);
1296 }
1256 1297
1257 key = kmalloc(len + 1, GFP_KERNEL); 1298 key = kmalloc(len + 1, GFP_KERNEL);
1258 if (!key) { 1299 if (!key) {
@@ -1309,8 +1350,8 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
1309{ 1350{
1310 char *key = NULL; 1351 char *key = NULL;
1311 struct user_datum *usrdatum; 1352 struct user_datum *usrdatum;
1312 int rc; 1353 int rc, to_read = 2;
1313 __le32 buf[2]; 1354 __le32 buf[3];
1314 u32 len; 1355 u32 len;
1315 1356
1316 usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL); 1357 usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
@@ -1319,12 +1360,17 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
1319 goto out; 1360 goto out;
1320 } 1361 }
1321 1362
1322 rc = next_entry(buf, fp, sizeof buf); 1363 if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
1364 to_read = 3;
1365
1366 rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
1323 if (rc < 0) 1367 if (rc < 0)
1324 goto bad; 1368 goto bad;
1325 1369
1326 len = le32_to_cpu(buf[0]); 1370 len = le32_to_cpu(buf[0]);
1327 usrdatum->value = le32_to_cpu(buf[1]); 1371 usrdatum->value = le32_to_cpu(buf[1]);
1372 if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
1373 usrdatum->bounds = le32_to_cpu(buf[2]);
1328 1374
1329 key = kmalloc(len + 1, GFP_KERNEL); 1375 key = kmalloc(len + 1, GFP_KERNEL);
1330 if (!key) { 1376 if (!key) {
@@ -1465,6 +1511,133 @@ static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp)
1465 cat_read, 1511 cat_read,
1466}; 1512};
1467 1513
1514static int user_bounds_sanity_check(void *key, void *datum, void *datap)
1515{
1516 struct user_datum *upper, *user;
1517 struct policydb *p = datap;
1518 int depth = 0;
1519
1520 upper = user = datum;
1521 while (upper->bounds) {
1522 struct ebitmap_node *node;
1523 unsigned long bit;
1524
1525 if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
1526 printk(KERN_ERR "SELinux: user %s: "
1527 "too deep or looped boundary",
1528 (char *) key);
1529 return -EINVAL;
1530 }
1531
1532 upper = p->user_val_to_struct[upper->bounds - 1];
1533 ebitmap_for_each_positive_bit(&user->roles, node, bit) {
1534 if (ebitmap_get_bit(&upper->roles, bit))
1535 continue;
1536
1537 printk(KERN_ERR
1538 "SELinux: boundary violated policy: "
1539 "user=%s role=%s bounds=%s\n",
1540 p->p_user_val_to_name[user->value - 1],
1541 p->p_role_val_to_name[bit],
1542 p->p_user_val_to_name[upper->value - 1]);
1543
1544 return -EINVAL;
1545 }
1546 }
1547
1548 return 0;
1549}
1550
1551static int role_bounds_sanity_check(void *key, void *datum, void *datap)
1552{
1553 struct role_datum *upper, *role;
1554 struct policydb *p = datap;
1555 int depth = 0;
1556
1557 upper = role = datum;
1558 while (upper->bounds) {
1559 struct ebitmap_node *node;
1560 unsigned long bit;
1561
1562 if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
1563 printk(KERN_ERR "SELinux: role %s: "
1564 "too deep or looped bounds\n",
1565 (char *) key);
1566 return -EINVAL;
1567 }
1568
1569 upper = p->role_val_to_struct[upper->bounds - 1];
1570 ebitmap_for_each_positive_bit(&role->types, node, bit) {
1571 if (ebitmap_get_bit(&upper->types, bit))
1572 continue;
1573
1574 printk(KERN_ERR
1575 "SELinux: boundary violated policy: "
1576 "role=%s type=%s bounds=%s\n",
1577 p->p_role_val_to_name[role->value - 1],
1578 p->p_type_val_to_name[bit],
1579 p->p_role_val_to_name[upper->value - 1]);
1580
1581 return -EINVAL;
1582 }
1583 }
1584
1585 return 0;
1586}
1587
1588static int type_bounds_sanity_check(void *key, void *datum, void *datap)
1589{
1590 struct type_datum *upper, *type;
1591 struct policydb *p = datap;
1592 int depth = 0;
1593
1594 upper = type = datum;
1595 while (upper->bounds) {
1596 if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
1597 printk(KERN_ERR "SELinux: type %s: "
1598 "too deep or looped boundary\n",
1599 (char *) key);
1600 return -EINVAL;
1601 }
1602
1603 upper = p->type_val_to_struct[upper->bounds - 1];
1604 if (upper->attribute) {
1605 printk(KERN_ERR "SELinux: type %s: "
1606 "bounded by attribute %s",
1607 (char *) key,
1608 p->p_type_val_to_name[upper->value - 1]);
1609 return -EINVAL;
1610 }
1611 }
1612
1613 return 0;
1614}
1615
1616static int policydb_bounds_sanity_check(struct policydb *p)
1617{
1618 int rc;
1619
1620 if (p->policyvers < POLICYDB_VERSION_BOUNDARY)
1621 return 0;
1622
1623 rc = hashtab_map(p->p_users.table,
1624 user_bounds_sanity_check, p);
1625 if (rc)
1626 return rc;
1627
1628 rc = hashtab_map(p->p_roles.table,
1629 role_bounds_sanity_check, p);
1630 if (rc)
1631 return rc;
1632
1633 rc = hashtab_map(p->p_types.table,
1634 type_bounds_sanity_check, p);
1635 if (rc)
1636 return rc;
1637
1638 return 0;
1639}
1640
1468extern int ss_initialized; 1641extern int ss_initialized;
1469 1642
1470/* 1643/*
@@ -1961,6 +2134,10 @@ int policydb_read(struct policydb *p, void *fp)
1961 goto bad; 2134 goto bad;
1962 } 2135 }
1963 2136
2137 rc = policydb_bounds_sanity_check(p);
2138 if (rc)
2139 goto bad;
2140
1964 rc = 0; 2141 rc = 0;
1965out: 2142out:
1966 return rc; 2143 return rc;
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 4253370fda6a..55152d498b53 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -61,6 +61,7 @@ struct class_datum {
61/* Role attributes */ 61/* Role attributes */
62struct role_datum { 62struct role_datum {
63 u32 value; /* internal role value */ 63 u32 value; /* internal role value */
64 u32 bounds; /* boundary of role */
64 struct ebitmap dominates; /* set of roles dominated by this role */ 65 struct ebitmap dominates; /* set of roles dominated by this role */
65 struct ebitmap types; /* set of authorized types for role */ 66 struct ebitmap types; /* set of authorized types for role */
66}; 67};
@@ -81,12 +82,15 @@ struct role_allow {
81/* Type attributes */ 82/* Type attributes */
82struct type_datum { 83struct type_datum {
83 u32 value; /* internal type value */ 84 u32 value; /* internal type value */
85 u32 bounds; /* boundary of type */
84 unsigned char primary; /* primary name? */ 86 unsigned char primary; /* primary name? */
87 unsigned char attribute;/* attribute ?*/
85}; 88};
86 89
87/* User attributes */ 90/* User attributes */
88struct user_datum { 91struct user_datum {
89 u32 value; /* internal user value */ 92 u32 value; /* internal user value */
93 u32 bounds; /* bounds of user */
90 struct ebitmap roles; /* set of authorized roles for user */ 94 struct ebitmap roles; /* set of authorized roles for user */
91 struct mls_range range; /* MLS range (min - max) for user */ 95 struct mls_range range; /* MLS range (min - max) for user */
92 struct mls_level dfltlevel; /* default login MLS level for user */ 96 struct mls_level dfltlevel; /* default login MLS level for user */
@@ -209,6 +213,7 @@ struct policydb {
209 struct class_datum **class_val_to_struct; 213 struct class_datum **class_val_to_struct;
210 struct role_datum **role_val_to_struct; 214 struct role_datum **role_val_to_struct;
211 struct user_datum **user_val_to_struct; 215 struct user_datum **user_val_to_struct;
216 struct type_datum **type_val_to_struct;
212 217
213 /* type enforcement access vectors and transitions */ 218 /* type enforcement access vectors and transitions */
214 struct avtab te_avtab; 219 struct avtab te_avtab;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 5a0536bddc63..4f233d9960e7 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -88,6 +88,11 @@ static u32 latest_granting;
88static int context_struct_to_string(struct context *context, char **scontext, 88static int context_struct_to_string(struct context *context, char **scontext,
89 u32 *scontext_len); 89 u32 *scontext_len);
90 90
91static 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 * Return the boolean value of a constraint expression 97 * Return the boolean value of a constraint expression
93 * when it is applied to the specified source and target 98 * when it is applied to the specified source and target
@@ -274,6 +279,100 @@ mls_ops:
274} 279}
275 280
276/* 281/*
282 * security_boundary_permission - drops violated permissions
283 * on boundary constraint.
284 */
285static void type_attribute_bounds_av(struct context *scontext,
286 struct context *tcontext,
287 u16 tclass,
288 u32 requested,
289 struct av_decision *avd)
290{
291 struct context lo_scontext;
292 struct context lo_tcontext;
293 struct av_decision lo_avd;
294 struct type_datum *source
295 = policydb.type_val_to_struct[scontext->type - 1];
296 struct type_datum *target
297 = policydb.type_val_to_struct[tcontext->type - 1];
298 u32 masked = 0;
299
300 if (source->bounds) {
301 memset(&lo_avd, 0, sizeof(lo_avd));
302
303 memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
304 lo_scontext.type = source->bounds;
305
306 context_struct_compute_av(&lo_scontext,
307 tcontext,
308 tclass,
309 requested,
310 &lo_avd);
311 if ((lo_avd.allowed & avd->allowed) == avd->allowed)
312 return; /* no masked permission */
313 masked = ~lo_avd.allowed & avd->allowed;
314 }
315
316 if (target->bounds) {
317 memset(&lo_avd, 0, sizeof(lo_avd));
318
319 memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
320 lo_tcontext.type = target->bounds;
321
322 context_struct_compute_av(scontext,
323 &lo_tcontext,
324 tclass,
325 requested,
326 &lo_avd);
327 if ((lo_avd.allowed & avd->allowed) == avd->allowed)
328 return; /* no masked permission */
329 masked = ~lo_avd.allowed & avd->allowed;
330 }
331
332 if (source->bounds && target->bounds) {
333 memset(&lo_avd, 0, sizeof(lo_avd));
334 /*
335 * lo_scontext and lo_tcontext are already
336 * set up.
337 */
338
339 context_struct_compute_av(&lo_scontext,
340 &lo_tcontext,
341 tclass,
342 requested,
343 &lo_avd);
344 if ((lo_avd.allowed & avd->allowed) == avd->allowed)
345 return; /* no masked permission */
346 masked = ~lo_avd.allowed & avd->allowed;
347 }
348
349 if (masked) {
350 struct audit_buffer *ab;
351 char *stype_name
352 = policydb.p_type_val_to_name[source->value - 1];
353 char *ttype_name
354 = policydb.p_type_val_to_name[target->value - 1];
355 char *tclass_name
356 = policydb.p_class_val_to_name[tclass - 1];
357
358 /* mask violated permissions */
359 avd->allowed &= ~masked;
360
361 /* notice to userspace via audit message */
362 ab = audit_log_start(current->audit_context,
363 GFP_ATOMIC, AUDIT_SELINUX_ERR);
364 if (!ab)
365 return;
366
367 audit_log_format(ab, "av boundary violation: "
368 "source=%s target=%s tclass=%s",
369 stype_name, ttype_name, tclass_name);
370 avc_dump_av(ab, tclass, masked);
371 audit_log_end(ab);
372 }
373}
374
375/*
277 * Compute access vectors based on a context structure pair for 376 * Compute access vectors based on a context structure pair for
278 * the permissions in a particular class. 377 * the permissions in a particular class.
279 */ 378 */
@@ -404,6 +503,14 @@ static int context_struct_compute_av(struct context *scontext,
404 PROCESS__DYNTRANSITION); 503 PROCESS__DYNTRANSITION);
405 } 504 }
406 505
506 /*
507 * If the given source and target types have boundary
508 * constraint, lazy checks have to mask any violated
509 * permission and notice it to userspace via audit.
510 */
511 type_attribute_bounds_av(scontext, tcontext,
512 tclass, requested, avd);
513
407 return 0; 514 return 0;
408 515
409inval_class: 516inval_class:
@@ -549,6 +656,69 @@ out:
549 return rc; 656 return rc;
550} 657}
551 658
659/*
660 * security_bounded_transition - check whether the given
661 * transition is directed to bounded, or not.
662 * It returns 0, if @newsid is bounded by @oldsid.
663 * Otherwise, it returns error code.
664 *
665 * @oldsid : current security identifier
666 * @newsid : destinated security identifier
667 */
668int security_bounded_transition(u32 old_sid, u32 new_sid)
669{
670 struct context *old_context, *new_context;
671 struct type_datum *type;
672 int index;
673 int rc = -EINVAL;
674
675 read_lock(&policy_rwlock);
676
677 old_context = sidtab_search(&sidtab, old_sid);
678 if (!old_context) {
679 printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
680 __func__, old_sid);
681 goto out;
682 }
683
684 new_context = sidtab_search(&sidtab, new_sid);
685 if (!new_context) {
686 printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
687 __func__, new_sid);
688 goto out;
689 }
690
691 /* type/domain unchaned */
692 if (old_context->type == new_context->type) {
693 rc = 0;
694 goto out;
695 }
696
697 index = new_context->type;
698 while (true) {
699 type = policydb.type_val_to_struct[index - 1];
700 BUG_ON(!type);
701
702 /* not bounded anymore */
703 if (!type->bounds) {
704 rc = -EPERM;
705 break;
706 }
707
708 /* @newsid is bounded by @oldsid */
709 if (type->bounds == old_context->type) {
710 rc = 0;
711 break;
712 }
713 index = type->bounds;
714 }
715out:
716 read_unlock(&policy_rwlock);
717
718 return rc;
719}
720
721
552/** 722/**
553 * security_compute_av - Compute access vector decisions. 723 * security_compute_av - Compute access vector decisions.
554 * @ssid: source security identifier 724 * @ssid: source security identifier
@@ -794,7 +964,7 @@ static int string_to_context_struct(struct policydb *pol,
794 *p++ = 0; 964 *p++ = 0;
795 965
796 typdatum = hashtab_search(pol->p_types.table, scontextp); 966 typdatum = hashtab_search(pol->p_types.table, scontextp);
797 if (!typdatum) 967 if (!typdatum || typdatum->attribute)
798 goto out; 968 goto out;
799 969
800 ctx->type = typdatum->value; 970 ctx->type = typdatum->value;