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)) { |
