Commit b07e3c3a1db0ce399d2a1d04860e1b901927c05e

Authored by Linus Torvalds

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;