Commit b07e3c3a1db0ce399d2a1d04860e1b901927c05e
Exists in
master
and in
4 other branches
Merge branch 'for-2.6.20' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6
* 'for-2.6.20' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6: SELinux: validate kernel object classes and permissions SELinux: ensure keys constant in hashtab_search SELinux: export object class and permission definitions SELinux: remove current object class and permission validation mechanism
Showing 6 changed files Side-by-side Diff
security/selinux/avc.c
... | ... | @@ -32,12 +32,7 @@ |
32 | 32 | #include "avc.h" |
33 | 33 | #include "avc_ss.h" |
34 | 34 | |
35 | -static const struct av_perm_to_string | |
36 | -{ | |
37 | - u16 tclass; | |
38 | - u32 value; | |
39 | - const char *name; | |
40 | -} av_perm_to_string[] = { | |
35 | +static const struct av_perm_to_string av_perm_to_string[] = { | |
41 | 36 | #define S_(c, v, s) { c, v, s }, |
42 | 37 | #include "av_perm_to_string.h" |
43 | 38 | #undef S_ |
44 | 39 | |
... | ... | @@ -57,15 +52,19 @@ |
57 | 52 | #undef TE_ |
58 | 53 | #undef S_ |
59 | 54 | |
60 | -static const struct av_inherit | |
61 | -{ | |
62 | - u16 tclass; | |
63 | - const char **common_pts; | |
64 | - u32 common_base; | |
65 | -} av_inherit[] = { | |
55 | +static const struct av_inherit av_inherit[] = { | |
66 | 56 | #define S_(c, i, b) { c, common_##i##_perm_to_string, b }, |
67 | 57 | #include "av_inherit.h" |
68 | 58 | #undef S_ |
59 | +}; | |
60 | + | |
61 | +const struct selinux_class_perm selinux_class_perm = { | |
62 | + av_perm_to_string, | |
63 | + ARRAY_SIZE(av_perm_to_string), | |
64 | + class_to_string, | |
65 | + ARRAY_SIZE(class_to_string), | |
66 | + av_inherit, | |
67 | + ARRAY_SIZE(av_inherit) | |
69 | 68 | }; |
70 | 69 | |
71 | 70 | #define AVC_CACHE_SLOTS 512 |
security/selinux/include/avc_ss.h
... | ... | @@ -10,5 +10,29 @@ |
10 | 10 | |
11 | 11 | int avc_ss_reset(u32 seqno); |
12 | 12 | |
13 | +struct av_perm_to_string | |
14 | +{ | |
15 | + u16 tclass; | |
16 | + u32 value; | |
17 | + const char *name; | |
18 | +}; | |
19 | + | |
20 | +struct av_inherit | |
21 | +{ | |
22 | + u16 tclass; | |
23 | + const char **common_pts; | |
24 | + u32 common_base; | |
25 | +}; | |
26 | + | |
27 | +struct selinux_class_perm | |
28 | +{ | |
29 | + const struct av_perm_to_string *av_perm_to_string; | |
30 | + u32 av_pts_len; | |
31 | + const char **class_to_string; | |
32 | + u32 cts_len; | |
33 | + const struct av_inherit *av_inherit; | |
34 | + u32 av_inherit_len; | |
35 | +}; | |
36 | + | |
13 | 37 | #endif /* _SELINUX_AVC_SS_H_ */ |
security/selinux/ss/hashtab.c
... | ... | @@ -8,8 +8,8 @@ |
8 | 8 | #include <linux/errno.h> |
9 | 9 | #include "hashtab.h" |
10 | 10 | |
11 | -struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key), | |
12 | - int (*keycmp)(struct hashtab *h, void *key1, void *key2), | |
11 | +struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), | |
12 | + int (*keycmp)(struct hashtab *h, const void *key1, const void *key2), | |
13 | 13 | u32 size) |
14 | 14 | { |
15 | 15 | struct hashtab *p; |
... | ... | @@ -71,7 +71,7 @@ |
71 | 71 | return 0; |
72 | 72 | } |
73 | 73 | |
74 | -void *hashtab_search(struct hashtab *h, void *key) | |
74 | +void *hashtab_search(struct hashtab *h, const void *key) | |
75 | 75 | { |
76 | 76 | u32 hvalue; |
77 | 77 | struct hashtab_node *cur; |
security/selinux/ss/hashtab.h
... | ... | @@ -22,9 +22,9 @@ |
22 | 22 | struct hashtab_node **htable; /* hash table */ |
23 | 23 | u32 size; /* number of slots in hash table */ |
24 | 24 | u32 nel; /* number of elements in hash table */ |
25 | - u32 (*hash_value)(struct hashtab *h, void *key); | |
25 | + u32 (*hash_value)(struct hashtab *h, const void *key); | |
26 | 26 | /* hash function */ |
27 | - int (*keycmp)(struct hashtab *h, void *key1, void *key2); | |
27 | + int (*keycmp)(struct hashtab *h, const void *key1, const void *key2); | |
28 | 28 | /* key comparison function */ |
29 | 29 | }; |
30 | 30 | |
... | ... | @@ -39,8 +39,8 @@ |
39 | 39 | * Returns NULL if insufficent space is available or |
40 | 40 | * the new hash table otherwise. |
41 | 41 | */ |
42 | -struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key), | |
43 | - int (*keycmp)(struct hashtab *h, void *key1, void *key2), | |
42 | +struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), | |
43 | + int (*keycmp)(struct hashtab *h, const void *key1, const void *key2), | |
44 | 44 | u32 size); |
45 | 45 | |
46 | 46 | /* |
... | ... | @@ -59,7 +59,7 @@ |
59 | 59 | * Returns NULL if no entry has the specified key or |
60 | 60 | * the datum of the entry otherwise. |
61 | 61 | */ |
62 | -void *hashtab_search(struct hashtab *h, void *k); | |
62 | +void *hashtab_search(struct hashtab *h, const void *k); | |
63 | 63 | |
64 | 64 | /* |
65 | 65 | * Destroys the specified hash table. |
security/selinux/ss/services.c
... | ... | @@ -17,9 +17,13 @@ |
17 | 17 | * |
18 | 18 | * Added support for NetLabel |
19 | 19 | * |
20 | + * Updated: Chad Sellers <csellers@tresys.com> | |
21 | + * | |
22 | + * Added validation of kernel classes and permissions | |
23 | + * | |
20 | 24 | * Copyright (C) 2006 Hewlett-Packard Development Company, L.P. |
21 | 25 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. |
22 | - * Copyright (C) 2003 - 2004 Tresys Technology, LLC | |
26 | + * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC | |
23 | 27 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> |
24 | 28 | * This program is free software; you can redistribute it and/or modify |
25 | 29 | * it under the terms of the GNU General Public License as published by |
... | ... | @@ -53,6 +57,11 @@ |
53 | 57 | extern void selnl_notify_policyload(u32 seqno); |
54 | 58 | unsigned int policydb_loaded_version; |
55 | 59 | |
60 | +/* | |
61 | + * This is declared in avc.c | |
62 | + */ | |
63 | +extern const struct selinux_class_perm selinux_class_perm; | |
64 | + | |
56 | 65 | static DEFINE_RWLOCK(policy_rwlock); |
57 | 66 | #define POLICY_RDLOCK read_lock(&policy_rwlock) |
58 | 67 | #define POLICY_WRLOCK write_lock_irq(&policy_rwlock) |
59 | 68 | |
60 | 69 | |
61 | 70 | |
62 | 71 | |
63 | 72 | |
64 | 73 | |
65 | 74 | |
... | ... | @@ -1019,86 +1028,112 @@ |
1019 | 1028 | } |
1020 | 1029 | |
1021 | 1030 | /* |
1022 | - * Verify that each permission that is defined under the | |
1023 | - * existing policy is still defined with the same value | |
1024 | - * in the new policy. | |
1031 | + * Verify that each kernel class that is defined in the | |
1032 | + * policy is correct | |
1025 | 1033 | */ |
1026 | -static int validate_perm(void *key, void *datum, void *p) | |
1034 | +static int validate_classes(struct policydb *p) | |
1027 | 1035 | { |
1028 | - struct hashtab *h; | |
1029 | - struct perm_datum *perdatum, *perdatum2; | |
1030 | - int rc = 0; | |
1036 | + int i, j; | |
1037 | + struct class_datum *cladatum; | |
1038 | + struct perm_datum *perdatum; | |
1039 | + u32 nprim, tmp, common_pts_len, perm_val, pol_val; | |
1040 | + u16 class_val; | |
1041 | + const struct selinux_class_perm *kdefs = &selinux_class_perm; | |
1042 | + const char *def_class, *def_perm, *pol_class; | |
1043 | + struct symtab *perms; | |
1031 | 1044 | |
1032 | - | |
1033 | - h = p; | |
1034 | - perdatum = datum; | |
1035 | - | |
1036 | - perdatum2 = hashtab_search(h, key); | |
1037 | - if (!perdatum2) { | |
1038 | - printk(KERN_ERR "security: permission %s disappeared", | |
1039 | - (char *)key); | |
1040 | - rc = -ENOENT; | |
1041 | - goto out; | |
1045 | + for (i = 1; i < kdefs->cts_len; i++) { | |
1046 | + def_class = kdefs->class_to_string[i]; | |
1047 | + if (i > p->p_classes.nprim) { | |
1048 | + printk(KERN_INFO | |
1049 | + "security: class %s not defined in policy\n", | |
1050 | + def_class); | |
1051 | + continue; | |
1052 | + } | |
1053 | + pol_class = p->p_class_val_to_name[i-1]; | |
1054 | + if (strcmp(pol_class, def_class)) { | |
1055 | + printk(KERN_ERR | |
1056 | + "security: class %d is incorrect, found %s but should be %s\n", | |
1057 | + i, pol_class, def_class); | |
1058 | + return -EINVAL; | |
1059 | + } | |
1042 | 1060 | } |
1043 | - if (perdatum->value != perdatum2->value) { | |
1044 | - printk(KERN_ERR "security: the value of permission %s changed", | |
1045 | - (char *)key); | |
1046 | - rc = -EINVAL; | |
1061 | + for (i = 0; i < kdefs->av_pts_len; i++) { | |
1062 | + class_val = kdefs->av_perm_to_string[i].tclass; | |
1063 | + perm_val = kdefs->av_perm_to_string[i].value; | |
1064 | + def_perm = kdefs->av_perm_to_string[i].name; | |
1065 | + if (class_val > p->p_classes.nprim) | |
1066 | + continue; | |
1067 | + pol_class = p->p_class_val_to_name[class_val-1]; | |
1068 | + cladatum = hashtab_search(p->p_classes.table, pol_class); | |
1069 | + BUG_ON(!cladatum); | |
1070 | + perms = &cladatum->permissions; | |
1071 | + nprim = 1 << (perms->nprim - 1); | |
1072 | + if (perm_val > nprim) { | |
1073 | + printk(KERN_INFO | |
1074 | + "security: permission %s in class %s not defined in policy\n", | |
1075 | + def_perm, pol_class); | |
1076 | + continue; | |
1077 | + } | |
1078 | + perdatum = hashtab_search(perms->table, def_perm); | |
1079 | + if (perdatum == NULL) { | |
1080 | + printk(KERN_ERR | |
1081 | + "security: permission %s in class %s not found in policy\n", | |
1082 | + def_perm, pol_class); | |
1083 | + return -EINVAL; | |
1084 | + } | |
1085 | + pol_val = 1 << (perdatum->value - 1); | |
1086 | + if (pol_val != perm_val) { | |
1087 | + printk(KERN_ERR | |
1088 | + "security: permission %s in class %s has incorrect value\n", | |
1089 | + def_perm, pol_class); | |
1090 | + return -EINVAL; | |
1091 | + } | |
1047 | 1092 | } |
1048 | -out: | |
1049 | - return rc; | |
1050 | -} | |
1051 | - | |
1052 | -/* | |
1053 | - * Verify that each class that is defined under the | |
1054 | - * existing policy is still defined with the same | |
1055 | - * attributes in the new policy. | |
1056 | - */ | |
1057 | -static int validate_class(void *key, void *datum, void *p) | |
1058 | -{ | |
1059 | - struct policydb *newp; | |
1060 | - struct class_datum *cladatum, *cladatum2; | |
1061 | - int rc; | |
1062 | - | |
1063 | - newp = p; | |
1064 | - cladatum = datum; | |
1065 | - | |
1066 | - cladatum2 = hashtab_search(newp->p_classes.table, key); | |
1067 | - if (!cladatum2) { | |
1068 | - printk(KERN_ERR "security: class %s disappeared\n", | |
1069 | - (char *)key); | |
1070 | - rc = -ENOENT; | |
1071 | - goto out; | |
1072 | - } | |
1073 | - if (cladatum->value != cladatum2->value) { | |
1074 | - printk(KERN_ERR "security: the value of class %s changed\n", | |
1075 | - (char *)key); | |
1076 | - rc = -EINVAL; | |
1077 | - goto out; | |
1078 | - } | |
1079 | - if ((cladatum->comdatum && !cladatum2->comdatum) || | |
1080 | - (!cladatum->comdatum && cladatum2->comdatum)) { | |
1081 | - printk(KERN_ERR "security: the inherits clause for the access " | |
1082 | - "vector definition for class %s changed\n", (char *)key); | |
1083 | - rc = -EINVAL; | |
1084 | - goto out; | |
1085 | - } | |
1086 | - if (cladatum->comdatum) { | |
1087 | - rc = hashtab_map(cladatum->comdatum->permissions.table, validate_perm, | |
1088 | - cladatum2->comdatum->permissions.table); | |
1089 | - if (rc) { | |
1090 | - printk(" in the access vector definition for class " | |
1091 | - "%s\n", (char *)key); | |
1092 | - goto out; | |
1093 | + for (i = 0; i < kdefs->av_inherit_len; i++) { | |
1094 | + class_val = kdefs->av_inherit[i].tclass; | |
1095 | + if (class_val > p->p_classes.nprim) | |
1096 | + continue; | |
1097 | + pol_class = p->p_class_val_to_name[class_val-1]; | |
1098 | + cladatum = hashtab_search(p->p_classes.table, pol_class); | |
1099 | + BUG_ON(!cladatum); | |
1100 | + if (!cladatum->comdatum) { | |
1101 | + printk(KERN_ERR | |
1102 | + "security: class %s should have an inherits clause but does not\n", | |
1103 | + pol_class); | |
1104 | + return -EINVAL; | |
1093 | 1105 | } |
1106 | + tmp = kdefs->av_inherit[i].common_base; | |
1107 | + common_pts_len = 0; | |
1108 | + while (!(tmp & 0x01)) { | |
1109 | + common_pts_len++; | |
1110 | + tmp >>= 1; | |
1111 | + } | |
1112 | + perms = &cladatum->comdatum->permissions; | |
1113 | + for (j = 0; j < common_pts_len; j++) { | |
1114 | + def_perm = kdefs->av_inherit[i].common_pts[j]; | |
1115 | + if (j >= perms->nprim) { | |
1116 | + printk(KERN_INFO | |
1117 | + "security: permission %s in class %s not defined in policy\n", | |
1118 | + def_perm, pol_class); | |
1119 | + continue; | |
1120 | + } | |
1121 | + perdatum = hashtab_search(perms->table, def_perm); | |
1122 | + if (perdatum == NULL) { | |
1123 | + printk(KERN_ERR | |
1124 | + "security: permission %s in class %s not found in policy\n", | |
1125 | + def_perm, pol_class); | |
1126 | + return -EINVAL; | |
1127 | + } | |
1128 | + if (perdatum->value != j + 1) { | |
1129 | + printk(KERN_ERR | |
1130 | + "security: permission %s in class %s has incorrect value\n", | |
1131 | + def_perm, pol_class); | |
1132 | + return -EINVAL; | |
1133 | + } | |
1134 | + } | |
1094 | 1135 | } |
1095 | - rc = hashtab_map(cladatum->permissions.table, validate_perm, | |
1096 | - cladatum2->permissions.table); | |
1097 | - if (rc) | |
1098 | - printk(" in access vector definition for class %s\n", | |
1099 | - (char *)key); | |
1100 | -out: | |
1101 | - return rc; | |
1136 | + return 0; | |
1102 | 1137 | } |
1103 | 1138 | |
1104 | 1139 | /* Clone the SID into the new SID table. */ |
... | ... | @@ -1243,6 +1278,16 @@ |
1243 | 1278 | avtab_cache_destroy(); |
1244 | 1279 | return -EINVAL; |
1245 | 1280 | } |
1281 | + /* Verify that the kernel defined classes are correct. */ | |
1282 | + if (validate_classes(&policydb)) { | |
1283 | + printk(KERN_ERR | |
1284 | + "security: the definition of a class is incorrect\n"); | |
1285 | + LOAD_UNLOCK; | |
1286 | + sidtab_destroy(&sidtab); | |
1287 | + policydb_destroy(&policydb); | |
1288 | + avtab_cache_destroy(); | |
1289 | + return -EINVAL; | |
1290 | + } | |
1246 | 1291 | policydb_loaded_version = policydb.policyvers; |
1247 | 1292 | ss_initialized = 1; |
1248 | 1293 | seqno = ++latest_granting; |
... | ... | @@ -1265,10 +1310,10 @@ |
1265 | 1310 | |
1266 | 1311 | sidtab_init(&newsidtab); |
1267 | 1312 | |
1268 | - /* Verify that the existing classes did not change. */ | |
1269 | - if (hashtab_map(policydb.p_classes.table, validate_class, &newpolicydb)) { | |
1270 | - printk(KERN_ERR "security: the definition of an existing " | |
1271 | - "class changed\n"); | |
1313 | + /* Verify that the kernel defined classes are correct. */ | |
1314 | + if (validate_classes(&newpolicydb)) { | |
1315 | + printk(KERN_ERR | |
1316 | + "security: the definition of a class is incorrect\n"); | |
1272 | 1317 | rc = -EINVAL; |
1273 | 1318 | goto err; |
1274 | 1319 | } |
security/selinux/ss/symtab.c
... | ... | @@ -9,9 +9,9 @@ |
9 | 9 | #include <linux/errno.h> |
10 | 10 | #include "symtab.h" |
11 | 11 | |
12 | -static unsigned int symhash(struct hashtab *h, void *key) | |
12 | +static unsigned int symhash(struct hashtab *h, const void *key) | |
13 | 13 | { |
14 | - char *p, *keyp; | |
14 | + const char *p, *keyp; | |
15 | 15 | unsigned int size; |
16 | 16 | unsigned int val; |
17 | 17 | |
18 | 18 | |
... | ... | @@ -23,9 +23,9 @@ |
23 | 23 | return val & (h->size - 1); |
24 | 24 | } |
25 | 25 | |
26 | -static int symcmp(struct hashtab *h, void *key1, void *key2) | |
26 | +static int symcmp(struct hashtab *h, const void *key1, const void *key2) | |
27 | 27 | { |
28 | - char *keyp1, *keyp2; | |
28 | + const char *keyp1, *keyp2; | |
29 | 29 | |
30 | 30 | keyp1 = key1; |
31 | 31 | keyp2 = key2; |