aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.osdl.org>2006-12-01 19:43:42 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-01 19:43:42 -0500
commitb07e3c3a1db0ce399d2a1d04860e1b901927c05e (patch)
tree474c17e969b5462a3702f0021249e1d78522ac35 /security
parent5f56bbdf1e35d41b4b3d4c92bdb3e70c63877e4d (diff)
parentb94c7e677b9d28bd3f9ba4a70df6bfa7942867ca (diff)
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
Diffstat (limited to 'security')
-rw-r--r--security/selinux/avc.c23
-rw-r--r--security/selinux/include/avc_ss.h24
-rw-r--r--security/selinux/ss/hashtab.c6
-rw-r--r--security/selinux/ss/hashtab.h10
-rw-r--r--security/selinux/ss/services.c203
-rw-r--r--security/selinux/ss/symtab.c8
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
35static const struct av_perm_to_string 35static 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
60static const struct av_inherit 55static 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
61const 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
11int avc_ss_reset(u32 seqno); 11int avc_ss_reset(u32 seqno);
12 12
13struct av_perm_to_string
14{
15 u16 tclass;
16 u32 value;
17 const char *name;
18};
19
20struct av_inherit
21{
22 u16 tclass;
23 const char **common_pts;
24 u32 common_base;
25};
26
27struct 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
11struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key), 11struct 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
74void *hashtab_search(struct hashtab *h, void *key) 74void *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 */
42struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, void *key), 42struct 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 */
62void *hashtab_search(struct hashtab *h, void *k); 62void *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 @@
53extern void selnl_notify_policyload(u32 seqno); 57extern void selnl_notify_policyload(u32 seqno);
54unsigned int policydb_loaded_version; 58unsigned int policydb_loaded_version;
55 59
60/*
61 * This is declared in avc.c
62 */
63extern const struct selinux_class_perm selinux_class_perm;
64
56static DEFINE_RWLOCK(policy_rwlock); 65static 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 */
1026static int validate_perm(void *key, void *datum, void *p) 1034static 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
1048out: 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 */
1057static 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);
1100out:
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
12static unsigned int symhash(struct hashtab *h, void *key) 12static 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
26static int symcmp(struct hashtab *h, void *key1, void *key2) 26static 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;