diff options
-rw-r--r-- | security/selinux/ss/services.c | 138 |
1 files changed, 137 insertions, 1 deletions
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 33ae1020091e..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) |
@@ -1018,6 +1027,115 @@ int security_change_sid(u32 ssid, | |||
1018 | return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid); | 1027 | return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid); |
1019 | } | 1028 | } |
1020 | 1029 | ||
1030 | /* | ||
1031 | * Verify that each kernel class that is defined in the | ||
1032 | * policy is correct | ||
1033 | */ | ||
1034 | static int validate_classes(struct policydb *p) | ||
1035 | { | ||
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; | ||
1044 | |||
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 | } | ||
1060 | } | ||
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 | } | ||
1092 | } | ||
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; | ||
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 | } | ||
1135 | } | ||
1136 | return 0; | ||
1137 | } | ||
1138 | |||
1021 | /* Clone the SID into the new SID table. */ | 1139 | /* Clone the SID into the new SID table. */ |
1022 | static int clone_sid(u32 sid, | 1140 | static int clone_sid(u32 sid, |
1023 | struct context *context, | 1141 | struct context *context, |
@@ -1160,6 +1278,16 @@ int security_load_policy(void *data, size_t len) | |||
1160 | avtab_cache_destroy(); | 1278 | avtab_cache_destroy(); |
1161 | return -EINVAL; | 1279 | return -EINVAL; |
1162 | } | 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 | } | ||
1163 | policydb_loaded_version = policydb.policyvers; | 1291 | policydb_loaded_version = policydb.policyvers; |
1164 | ss_initialized = 1; | 1292 | ss_initialized = 1; |
1165 | seqno = ++latest_granting; | 1293 | seqno = ++latest_granting; |
@@ -1182,6 +1310,14 @@ int security_load_policy(void *data, size_t len) | |||
1182 | 1310 | ||
1183 | sidtab_init(&newsidtab); | 1311 | sidtab_init(&newsidtab); |
1184 | 1312 | ||
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"); | ||
1317 | rc = -EINVAL; | ||
1318 | goto err; | ||
1319 | } | ||
1320 | |||
1185 | /* Clone the SID table. */ | 1321 | /* Clone the SID table. */ |
1186 | sidtab_shutdown(&sidtab); | 1322 | sidtab_shutdown(&sidtab); |
1187 | if (sidtab_map(&sidtab, clone_sid, &newsidtab)) { | 1323 | if (sidtab_map(&sidtab, clone_sid, &newsidtab)) { |