aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Smalley <sds@tycho.nsa.gov>2007-11-07 10:08:00 -0500
committerJames Morris <jmorris@namei.org>2007-11-07 16:56:23 -0500
commit45e5421eb5bbcd9efa037d682dd357284e3ef982 (patch)
treeceb24143024fe335d08ac30fb4da9ca25fbeb6e6
parent6d2b685564ba417f4c6d80c3661f0dfee13fff85 (diff)
SELinux: add more validity checks on policy load
Add more validity checks at policy load time to reject malformed policies and prevent subsequent out-of-range indexing when in permissive mode. Resolves the NULL pointer dereference reported in https://bugzilla.redhat.com/show_bug.cgi?id=357541. Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--security/selinux/ss/avtab.c32
-rw-r--r--security/selinux/ss/avtab.h5
-rw-r--r--security/selinux/ss/conditional.c3
-rw-r--r--security/selinux/ss/mls.c66
-rw-r--r--security/selinux/ss/mls.h2
-rw-r--r--security/selinux/ss/policydb.c45
-rw-r--r--security/selinux/ss/policydb.h3
7 files changed, 118 insertions, 38 deletions
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 7551af1f7899..9e70a160d7da 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -325,7 +325,7 @@ static uint16_t spec_order[] = {
325 AVTAB_MEMBER 325 AVTAB_MEMBER
326}; 326};
327 327
328int avtab_read_item(void *fp, u32 vers, struct avtab *a, 328int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
329 int (*insertf)(struct avtab *a, struct avtab_key *k, 329 int (*insertf)(struct avtab *a, struct avtab_key *k,
330 struct avtab_datum *d, void *p), 330 struct avtab_datum *d, void *p),
331 void *p) 331 void *p)
@@ -333,10 +333,11 @@ int avtab_read_item(void *fp, u32 vers, struct avtab *a,
333 __le16 buf16[4]; 333 __le16 buf16[4];
334 u16 enabled; 334 u16 enabled;
335 __le32 buf32[7]; 335 __le32 buf32[7];
336 u32 items, items2, val; 336 u32 items, items2, val, vers = pol->policyvers;
337 struct avtab_key key; 337 struct avtab_key key;
338 struct avtab_datum datum; 338 struct avtab_datum datum;
339 int i, rc; 339 int i, rc;
340 unsigned set;
340 341
341 memset(&key, 0, sizeof(struct avtab_key)); 342 memset(&key, 0, sizeof(struct avtab_key));
342 memset(&datum, 0, sizeof(struct avtab_datum)); 343 memset(&datum, 0, sizeof(struct avtab_datum));
@@ -420,12 +421,35 @@ int avtab_read_item(void *fp, u32 vers, struct avtab *a,
420 key.target_class = le16_to_cpu(buf16[items++]); 421 key.target_class = le16_to_cpu(buf16[items++]);
421 key.specified = le16_to_cpu(buf16[items++]); 422 key.specified = le16_to_cpu(buf16[items++]);
422 423
424 if (!policydb_type_isvalid(pol, key.source_type) ||
425 !policydb_type_isvalid(pol, key.target_type) ||
426 !policydb_class_isvalid(pol, key.target_class)) {
427 printk(KERN_WARNING "security: avtab: invalid type or class\n");
428 return -1;
429 }
430
431 set = 0;
432 for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
433 if (key.specified & spec_order[i])
434 set++;
435 }
436 if (!set || set > 1) {
437 printk(KERN_WARNING
438 "security: avtab: more than one specifier\n");
439 return -1;
440 }
441
423 rc = next_entry(buf32, fp, sizeof(u32)); 442 rc = next_entry(buf32, fp, sizeof(u32));
424 if (rc < 0) { 443 if (rc < 0) {
425 printk("security: avtab: truncated entry\n"); 444 printk("security: avtab: truncated entry\n");
426 return -1; 445 return -1;
427 } 446 }
428 datum.data = le32_to_cpu(*buf32); 447 datum.data = le32_to_cpu(*buf32);
448 if ((key.specified & AVTAB_TYPE) &&
449 !policydb_type_isvalid(pol, datum.data)) {
450 printk(KERN_WARNING "security: avtab: invalid type\n");
451 return -1;
452 }
429 return insertf(a, &key, &datum, p); 453 return insertf(a, &key, &datum, p);
430} 454}
431 455
@@ -435,7 +459,7 @@ static int avtab_insertf(struct avtab *a, struct avtab_key *k,
435 return avtab_insert(a, k, d); 459 return avtab_insert(a, k, d);
436} 460}
437 461
438int avtab_read(struct avtab *a, void *fp, u32 vers) 462int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
439{ 463{
440 int rc; 464 int rc;
441 __le32 buf[1]; 465 __le32 buf[1];
@@ -459,7 +483,7 @@ int avtab_read(struct avtab *a, void *fp, u32 vers)
459 goto bad; 483 goto bad;
460 484
461 for (i = 0; i < nel; i++) { 485 for (i = 0; i < nel; i++) {
462 rc = avtab_read_item(fp,vers, a, avtab_insertf, NULL); 486 rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL);
463 if (rc) { 487 if (rc) {
464 if (rc == -ENOMEM) 488 if (rc == -ENOMEM)
465 printk(KERN_ERR "security: avtab: out of memory\n"); 489 printk(KERN_ERR "security: avtab: out of memory\n");
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
index d8edf8ca56d1..8da6a8428086 100644
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -64,12 +64,13 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
64void avtab_destroy(struct avtab *h); 64void avtab_destroy(struct avtab *h);
65void avtab_hash_eval(struct avtab *h, char *tag); 65void avtab_hash_eval(struct avtab *h, char *tag);
66 66
67int avtab_read_item(void *fp, uint32_t vers, struct avtab *a, 67struct policydb;
68int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
68 int (*insert)(struct avtab *a, struct avtab_key *k, 69 int (*insert)(struct avtab *a, struct avtab_key *k,
69 struct avtab_datum *d, void *p), 70 struct avtab_datum *d, void *p),
70 void *p); 71 void *p);
71 72
72int avtab_read(struct avtab *a, void *fp, u32 vers); 73int avtab_read(struct avtab *a, void *fp, struct policydb *pol);
73 74
74struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, 75struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
75 struct avtab_datum *datum); 76 struct avtab_datum *datum);
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 45b93a827c80..50ad85d4b77c 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -362,7 +362,8 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list *
362 data.head = NULL; 362 data.head = NULL;
363 data.tail = NULL; 363 data.tail = NULL;
364 for (i = 0; i < len; i++) { 364 for (i = 0; i < len; i++) {
365 rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, cond_insertf, &data); 365 rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
366 &data);
366 if (rc) 367 if (rc)
367 return rc; 368 return rc;
368 369
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 9a11deaaa9e7..fb5d70a6628d 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -157,49 +157,55 @@ void mls_sid_to_context(struct context *context,
157 return; 157 return;
158} 158}
159 159
160int mls_level_isvalid(struct policydb *p, struct mls_level *l)
161{
162 struct level_datum *levdatum;
163 struct ebitmap_node *node;
164 int i;
165
166 if (!l->sens || l->sens > p->p_levels.nprim)
167 return 0;
168 levdatum = hashtab_search(p->p_levels.table,
169 p->p_sens_val_to_name[l->sens - 1]);
170 if (!levdatum)
171 return 0;
172
173 ebitmap_for_each_positive_bit(&l->cat, node, i) {
174 if (i > p->p_cats.nprim)
175 return 0;
176 if (!ebitmap_get_bit(&levdatum->level->cat, i)) {
177 /*
178 * Category may not be associated with
179 * sensitivity.
180 */
181 return 0;
182 }
183 }
184
185 return 1;
186}
187
188int mls_range_isvalid(struct policydb *p, struct mls_range *r)
189{
190 return (mls_level_isvalid(p, &r->level[0]) &&
191 mls_level_isvalid(p, &r->level[1]) &&
192 mls_level_dom(&r->level[1], &r->level[0]));
193}
194
160/* 195/*
161 * Return 1 if the MLS fields in the security context 196 * Return 1 if the MLS fields in the security context
162 * structure `c' are valid. Return 0 otherwise. 197 * structure `c' are valid. Return 0 otherwise.
163 */ 198 */
164int mls_context_isvalid(struct policydb *p, struct context *c) 199int mls_context_isvalid(struct policydb *p, struct context *c)
165{ 200{
166 struct level_datum *levdatum;
167 struct user_datum *usrdatum; 201 struct user_datum *usrdatum;
168 struct ebitmap_node *node;
169 int i, l;
170 202
171 if (!selinux_mls_enabled) 203 if (!selinux_mls_enabled)
172 return 1; 204 return 1;
173 205
174 /* 206 if (!mls_range_isvalid(p, &c->range))
175 * MLS range validity checks: high must dominate low, low level must
176 * be valid (category set <-> sensitivity check), and high level must
177 * be valid (category set <-> sensitivity check)
178 */
179 if (!mls_level_dom(&c->range.level[1], &c->range.level[0]))
180 /* High does not dominate low. */
181 return 0; 207 return 0;
182 208
183 for (l = 0; l < 2; l++) {
184 if (!c->range.level[l].sens || c->range.level[l].sens > p->p_levels.nprim)
185 return 0;
186 levdatum = hashtab_search(p->p_levels.table,
187 p->p_sens_val_to_name[c->range.level[l].sens - 1]);
188 if (!levdatum)
189 return 0;
190
191 ebitmap_for_each_positive_bit(&c->range.level[l].cat, node, i) {
192 if (i > p->p_cats.nprim)
193 return 0;
194 if (!ebitmap_get_bit(&levdatum->level->cat, i))
195 /*
196 * Category may not be associated with
197 * sensitivity in low level.
198 */
199 return 0;
200 }
201 }
202
203 if (c->role == OBJECT_R_VAL) 209 if (c->role == OBJECT_R_VAL)
204 return 1; 210 return 1;
205 211
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 096d1b4ef7fb..ab53663d9f5f 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -27,6 +27,8 @@
27int mls_compute_context_len(struct context *context); 27int mls_compute_context_len(struct context *context);
28void mls_sid_to_context(struct context *context, char **scontext); 28void mls_sid_to_context(struct context *context, char **scontext);
29int mls_context_isvalid(struct policydb *p, struct context *c); 29int mls_context_isvalid(struct policydb *p, struct context *c);
30int mls_range_isvalid(struct policydb *p, struct mls_range *r);
31int mls_level_isvalid(struct policydb *p, struct mls_level *l);
30 32
31int mls_context_to_sid(char oldc, 33int mls_context_to_sid(char oldc,
32 char **scontext, 34 char **scontext,
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 539828b229b2..b582aae3c62c 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -713,6 +713,27 @@ out:
713 return rc; 713 return rc;
714} 714}
715 715
716int policydb_class_isvalid(struct policydb *p, unsigned int class)
717{
718 if (!class || class > p->p_classes.nprim)
719 return 0;
720 return 1;
721}
722
723int policydb_role_isvalid(struct policydb *p, unsigned int role)
724{
725 if (!role || role > p->p_roles.nprim)
726 return 0;
727 return 1;
728}
729
730int policydb_type_isvalid(struct policydb *p, unsigned int type)
731{
732 if (!type || type > p->p_types.nprim)
733 return 0;
734 return 1;
735}
736
716/* 737/*
717 * Return 1 if the fields in the security context 738 * Return 1 if the fields in the security context
718 * structure `c' are valid. Return 0 otherwise. 739 * structure `c' are valid. Return 0 otherwise.
@@ -1260,6 +1281,7 @@ static int mls_read_level(struct mls_level *lp, void *fp)
1260 "categories\n"); 1281 "categories\n");
1261 goto bad; 1282 goto bad;
1262 } 1283 }
1284
1263 return 0; 1285 return 0;
1264 1286
1265bad: 1287bad:
@@ -1563,7 +1585,7 @@ int policydb_read(struct policydb *p, void *fp)
1563 p->symtab[i].nprim = nprim; 1585 p->symtab[i].nprim = nprim;
1564 } 1586 }
1565 1587
1566 rc = avtab_read(&p->te_avtab, fp, p->policyvers); 1588 rc = avtab_read(&p->te_avtab, fp, p);
1567 if (rc) 1589 if (rc)
1568 goto bad; 1590 goto bad;
1569 1591
@@ -1595,6 +1617,12 @@ int policydb_read(struct policydb *p, void *fp)
1595 tr->role = le32_to_cpu(buf[0]); 1617 tr->role = le32_to_cpu(buf[0]);
1596 tr->type = le32_to_cpu(buf[1]); 1618 tr->type = le32_to_cpu(buf[1]);
1597 tr->new_role = le32_to_cpu(buf[2]); 1619 tr->new_role = le32_to_cpu(buf[2]);
1620 if (!policydb_role_isvalid(p, tr->role) ||
1621 !policydb_type_isvalid(p, tr->type) ||
1622 !policydb_role_isvalid(p, tr->new_role)) {
1623 rc = -EINVAL;
1624 goto bad;
1625 }
1598 ltr = tr; 1626 ltr = tr;
1599 } 1627 }
1600 1628
@@ -1619,6 +1647,11 @@ int policydb_read(struct policydb *p, void *fp)
1619 goto bad; 1647 goto bad;
1620 ra->role = le32_to_cpu(buf[0]); 1648 ra->role = le32_to_cpu(buf[0]);
1621 ra->new_role = le32_to_cpu(buf[1]); 1649 ra->new_role = le32_to_cpu(buf[1]);
1650 if (!policydb_role_isvalid(p, ra->role) ||
1651 !policydb_role_isvalid(p, ra->new_role)) {
1652 rc = -EINVAL;
1653 goto bad;
1654 }
1622 lra = ra; 1655 lra = ra;
1623 } 1656 }
1624 1657
@@ -1872,9 +1905,19 @@ int policydb_read(struct policydb *p, void *fp)
1872 rt->target_class = le32_to_cpu(buf[0]); 1905 rt->target_class = le32_to_cpu(buf[0]);
1873 } else 1906 } else
1874 rt->target_class = SECCLASS_PROCESS; 1907 rt->target_class = SECCLASS_PROCESS;
1908 if (!policydb_type_isvalid(p, rt->source_type) ||
1909 !policydb_type_isvalid(p, rt->target_type) ||
1910 !policydb_class_isvalid(p, rt->target_class)) {
1911 rc = -EINVAL;
1912 goto bad;
1913 }
1875 rc = mls_read_range_helper(&rt->target_range, fp); 1914 rc = mls_read_range_helper(&rt->target_range, fp);
1876 if (rc) 1915 if (rc)
1877 goto bad; 1916 goto bad;
1917 if (!mls_range_isvalid(p, &rt->target_range)) {
1918 printk(KERN_WARNING "security: rangetrans: invalid range\n");
1919 goto bad;
1920 }
1878 lrt = rt; 1921 lrt = rt;
1879 } 1922 }
1880 } 1923 }
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 844d310f4f1b..ed6fc687c66f 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -251,6 +251,9 @@ struct policydb {
251extern void policydb_destroy(struct policydb *p); 251extern void policydb_destroy(struct policydb *p);
252extern int policydb_load_isids(struct policydb *p, struct sidtab *s); 252extern int policydb_load_isids(struct policydb *p, struct sidtab *s);
253extern int policydb_context_isvalid(struct policydb *p, struct context *c); 253extern int policydb_context_isvalid(struct policydb *p, struct context *c);
254extern int policydb_class_isvalid(struct policydb *p, unsigned int class);
255extern int policydb_type_isvalid(struct policydb *p, unsigned int type);
256extern int policydb_role_isvalid(struct policydb *p, unsigned int role);
254extern int policydb_read(struct policydb *p, void *fp); 257extern int policydb_read(struct policydb *p, void *fp);
255 258
256#define PERM_SYMTAB_SIZE 32 259#define PERM_SYMTAB_SIZE 32