diff options
-rw-r--r-- | security/selinux/avc.c | 23 | ||||
-rw-r--r-- | security/selinux/include/avc_ss.h | 24 | ||||
-rw-r--r-- | security/selinux/ss/hashtab.c | 6 | ||||
-rw-r--r-- | security/selinux/ss/hashtab.h | 10 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 203 | ||||
-rw-r--r-- | security/selinux/ss/symtab.c | 8 |
6 files changed, 171 insertions, 103 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index a300702da527..74c0319c417e 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -32,12 +32,7 @@ | |||
32 | #include "avc.h" | 32 | #include "avc.h" |
33 | #include "avc_ss.h" | 33 | #include "avc_ss.h" |
34 | 34 | ||
35 | static const struct av_perm_to_string | 35 | static const struct av_perm_to_string av_perm_to_string[] = { |
36 | { | ||
37 | u16 tclass; | ||
38 | u32 value; | ||
39 | const char *name; | ||
40 | } av_perm_to_string[] = { | ||
41 | #define S_(c, v, s) { c, v, s }, | 36 | #define S_(c, v, s) { c, v, s }, |
42 | #include "av_perm_to_string.h" | 37 | #include "av_perm_to_string.h" |
43 | #undef S_ | 38 | #undef S_ |
@@ -57,17 +52,21 @@ static const char *class_to_string[] = { | |||
57 | #undef TE_ | 52 | #undef TE_ |
58 | #undef S_ | 53 | #undef S_ |
59 | 54 | ||
60 | static const struct av_inherit | 55 | static const struct av_inherit av_inherit[] = { |
61 | { | ||
62 | u16 tclass; | ||
63 | const char **common_pts; | ||
64 | u32 common_base; | ||
65 | } av_inherit[] = { | ||
66 | #define S_(c, i, b) { c, common_##i##_perm_to_string, b }, | 56 | #define S_(c, i, b) { c, common_##i##_perm_to_string, b }, |
67 | #include "av_inherit.h" | 57 | #include "av_inherit.h" |
68 | #undef S_ | 58 | #undef S_ |
69 | }; | 59 | }; |
70 | 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) | ||
68 | }; | ||
69 | |||
71 | #define AVC_CACHE_SLOTS 512 | 70 | #define AVC_CACHE_SLOTS 512 |
72 | #define AVC_DEF_CACHE_THRESHOLD 512 | 71 | #define AVC_DEF_CACHE_THRESHOLD 512 |
73 | #define AVC_CACHE_RECLAIM 16 | 72 | #define AVC_CACHE_RECLAIM 16 |
diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h index 450a2831e2e3..ff869e8b6f4a 100644 --- a/security/selinux/include/avc_ss.h +++ b/security/selinux/include/avc_ss.h | |||
@@ -10,5 +10,29 @@ | |||
10 | 10 | ||
11 | int avc_ss_reset(u32 seqno); | 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 | #endif /* _SELINUX_AVC_SS_H_ */ | 37 | #endif /* _SELINUX_AVC_SS_H_ */ |
14 | 38 | ||
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 24e5ec957630..77b530c3bbce 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c | |||
@@ -8,8 +8,8 @@ | |||
8 | #include <linux/errno.h> | 8 | #include <linux/errno.h> |
9 | #include "hashtab.h" | 9 | #include "hashtab.h" |
10 | 10 | ||
11 | struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key), | 11 | struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), |
12 | int (*keycmp)(struct hashtab *h, void *key1, void *key2), | 12 | int (*keycmp)(struct hashtab *h, const void *key1, const void *key2), |
13 | u32 size) | 13 | u32 size) |
14 | { | 14 | { |
15 | struct hashtab *p; | 15 | struct hashtab *p; |
@@ -71,7 +71,7 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum) | |||
71 | return 0; | 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 | u32 hvalue; | 76 | u32 hvalue; |
77 | struct hashtab_node *cur; | 77 | struct hashtab_node *cur; |
diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h index 4cc85816a718..7e2ff3e3c6d2 100644 --- a/security/selinux/ss/hashtab.h +++ b/security/selinux/ss/hashtab.h | |||
@@ -22,9 +22,9 @@ struct hashtab { | |||
22 | struct hashtab_node **htable; /* hash table */ | 22 | struct hashtab_node **htable; /* hash table */ |
23 | u32 size; /* number of slots in hash table */ | 23 | u32 size; /* number of slots in hash table */ |
24 | u32 nel; /* number of elements in hash table */ | 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 | /* hash function */ | 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 | /* key comparison function */ | 28 | /* key comparison function */ |
29 | }; | 29 | }; |
30 | 30 | ||
@@ -39,8 +39,8 @@ struct hashtab_info { | |||
39 | * Returns NULL if insufficent space is available or | 39 | * Returns NULL if insufficent space is available or |
40 | * the new hash table otherwise. | 40 | * the new hash table otherwise. |
41 | */ | 41 | */ |
42 | struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key), | 42 | struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), |
43 | int (*keycmp)(struct hashtab *h, void *key1, void *key2), | 43 | int (*keycmp)(struct hashtab *h, const void *key1, const void *key2), |
44 | u32 size); | 44 | u32 size); |
45 | 45 | ||
46 | /* | 46 | /* |
@@ -59,7 +59,7 @@ int hashtab_insert(struct hashtab *h, void *k, void *d); | |||
59 | * Returns NULL if no entry has the specified key or | 59 | * Returns NULL if no entry has the specified key or |
60 | * the datum of the entry otherwise. | 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 | * Destroys the specified hash table. | 65 | * Destroys the specified hash table. |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index bfe122764c98..408820486af0 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -17,9 +17,13 @@ | |||
17 | * | 17 | * |
18 | * Added support for NetLabel | 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 | * Copyright (C) 2006 Hewlett-Packard Development Company, L.P. | 24 | * Copyright (C) 2006 Hewlett-Packard Development Company, L.P. |
21 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. | 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 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> | 27 | * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> |
24 | * This program is free software; you can redistribute it and/or modify | 28 | * This program is free software; you can redistribute it and/or modify |
25 | * it under the terms of the GNU General Public License as published by | 29 | * it under the terms of the GNU General Public License as published by |
@@ -53,6 +57,11 @@ | |||
53 | extern void selnl_notify_policyload(u32 seqno); | 57 | extern void selnl_notify_policyload(u32 seqno); |
54 | unsigned int policydb_loaded_version; | 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 | static DEFINE_RWLOCK(policy_rwlock); | 65 | static DEFINE_RWLOCK(policy_rwlock); |
57 | #define POLICY_RDLOCK read_lock(&policy_rwlock) | 66 | #define POLICY_RDLOCK read_lock(&policy_rwlock) |
58 | #define POLICY_WRLOCK write_lock_irq(&policy_rwlock) | 67 | #define POLICY_WRLOCK write_lock_irq(&policy_rwlock) |
@@ -1019,86 +1028,112 @@ int security_change_sid(u32 ssid, | |||
1019 | } | 1028 | } |
1020 | 1029 | ||
1021 | /* | 1030 | /* |
1022 | * Verify that each permission that is defined under the | 1031 | * Verify that each kernel class that is defined in the |
1023 | * existing policy is still defined with the same value | 1032 | * policy is correct |
1024 | * in the new policy. | ||
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; | 1036 | int i, j; |
1029 | struct perm_datum *perdatum, *perdatum2; | 1037 | struct class_datum *cladatum; |
1030 | int rc = 0; | 1038 | struct perm_datum *perdatum; |
1031 | 1039 | u32 nprim, tmp, common_pts_len, perm_val, pol_val; | |
1032 | 1040 | u16 class_val; | |
1033 | h = p; | 1041 | const struct selinux_class_perm *kdefs = &selinux_class_perm; |
1034 | perdatum = datum; | 1042 | const char *def_class, *def_perm, *pol_class; |
1035 | 1043 | struct symtab *perms; | |
1036 | perdatum2 = hashtab_search(h, key); | 1044 | |
1037 | if (!perdatum2) { | 1045 | for (i = 1; i < kdefs->cts_len; i++) { |
1038 | printk(KERN_ERR "security: permission %s disappeared", | 1046 | def_class = kdefs->class_to_string[i]; |
1039 | (char *)key); | 1047 | if (i > p->p_classes.nprim) { |
1040 | rc = -ENOENT; | 1048 | printk(KERN_INFO |
1041 | goto out; | 1049 | "security: class %s not defined in policy\n", |
1042 | } | 1050 | def_class); |
1043 | if (perdatum->value != perdatum2->value) { | 1051 | continue; |
1044 | printk(KERN_ERR "security: the value of permission %s changed", | 1052 | } |
1045 | (char *)key); | 1053 | pol_class = p->p_class_val_to_name[i-1]; |
1046 | rc = -EINVAL; | 1054 | if (strcmp(pol_class, def_class)) { |
1047 | } | 1055 | printk(KERN_ERR |
1048 | out: | 1056 | "security: class %d is incorrect, found %s but should be %s\n", |
1049 | return rc; | 1057 | i, pol_class, def_class); |
1050 | } | 1058 | return -EINVAL; |
1051 | 1059 | } | |
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 | } | 1060 | } |
1079 | if ((cladatum->comdatum && !cladatum2->comdatum) || | 1061 | for (i = 0; i < kdefs->av_pts_len; i++) { |
1080 | (!cladatum->comdatum && cladatum2->comdatum)) { | 1062 | class_val = kdefs->av_perm_to_string[i].tclass; |
1081 | printk(KERN_ERR "security: the inherits clause for the access " | 1063 | perm_val = kdefs->av_perm_to_string[i].value; |
1082 | "vector definition for class %s changed\n", (char *)key); | 1064 | def_perm = kdefs->av_perm_to_string[i].name; |
1083 | rc = -EINVAL; | 1065 | if (class_val > p->p_classes.nprim) |
1084 | goto out; | 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 | } | ||
1085 | } | 1092 | } |
1086 | if (cladatum->comdatum) { | 1093 | for (i = 0; i < kdefs->av_inherit_len; i++) { |
1087 | rc = hashtab_map(cladatum->comdatum->permissions.table, validate_perm, | 1094 | class_val = kdefs->av_inherit[i].tclass; |
1088 | cladatum2->comdatum->permissions.table); | 1095 | if (class_val > p->p_classes.nprim) |
1089 | if (rc) { | 1096 | continue; |
1090 | printk(" in the access vector definition for class " | 1097 | pol_class = p->p_class_val_to_name[class_val-1]; |
1091 | "%s\n", (char *)key); | 1098 | cladatum = hashtab_search(p->p_classes.table, pol_class); |
1092 | goto out; | 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; | ||
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 | } | ||
1093 | } | 1134 | } |
1094 | } | 1135 | } |
1095 | rc = hashtab_map(cladatum->permissions.table, validate_perm, | 1136 | return 0; |
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; | ||
1102 | } | 1137 | } |
1103 | 1138 | ||
1104 | /* Clone the SID into the new SID table. */ | 1139 | /* Clone the SID into the new SID table. */ |
@@ -1243,6 +1278,16 @@ int security_load_policy(void *data, size_t len) | |||
1243 | avtab_cache_destroy(); | 1278 | avtab_cache_destroy(); |
1244 | return -EINVAL; | 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 | policydb_loaded_version = policydb.policyvers; | 1291 | policydb_loaded_version = policydb.policyvers; |
1247 | ss_initialized = 1; | 1292 | ss_initialized = 1; |
1248 | seqno = ++latest_granting; | 1293 | seqno = ++latest_granting; |
@@ -1265,10 +1310,10 @@ int security_load_policy(void *data, size_t len) | |||
1265 | 1310 | ||
1266 | sidtab_init(&newsidtab); | 1311 | sidtab_init(&newsidtab); |
1267 | 1312 | ||
1268 | /* Verify that the existing classes did not change. */ | 1313 | /* Verify that the kernel defined classes are correct. */ |
1269 | if (hashtab_map(policydb.p_classes.table, validate_class, &newpolicydb)) { | 1314 | if (validate_classes(&newpolicydb)) { |
1270 | printk(KERN_ERR "security: the definition of an existing " | 1315 | printk(KERN_ERR |
1271 | "class changed\n"); | 1316 | "security: the definition of a class is incorrect\n"); |
1272 | rc = -EINVAL; | 1317 | rc = -EINVAL; |
1273 | goto err; | 1318 | goto err; |
1274 | } | 1319 | } |
diff --git a/security/selinux/ss/symtab.c b/security/selinux/ss/symtab.c index 24a10d36d3b6..837658a98a54 100644 --- a/security/selinux/ss/symtab.c +++ b/security/selinux/ss/symtab.c | |||
@@ -9,9 +9,9 @@ | |||
9 | #include <linux/errno.h> | 9 | #include <linux/errno.h> |
10 | #include "symtab.h" | 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 | unsigned int size; | 15 | unsigned int size; |
16 | unsigned int val; | 16 | unsigned int val; |
17 | 17 | ||
@@ -23,9 +23,9 @@ static unsigned int symhash(struct hashtab *h, void *key) | |||
23 | return val & (h->size - 1); | 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 | keyp1 = key1; | 30 | keyp1 = key1; |
31 | keyp2 = key2; | 31 | keyp2 = key2; |