aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2007-09-21 14:37:10 -0400
committerJames Morris <jmorris@namei.org>2007-10-16 18:59:33 -0400
commit3f12070e27b4a213d62607d2bff139793089a77d (patch)
treeb6b614737f916c7c3102f66e6ad9e682b9c9bf04 /security
parent788e7dd4c22e6f41b3a118fd8c291f831f6fddbb (diff)
SELinux: policy selectable handling of unknown classes and perms
Allow policy to select, in much the same way as it selects MLS support, how the kernel should handle access decisions which contain either unknown classes or unknown permissions in known classes. The three choices for the policy flags are 0 - Deny unknown security access. (default) 2 - reject loading policy if it does not contain all definitions 4 - allow unknown security access The policy's choice is exported through 2 booleans in selinuxfs. /selinux/deny_unknown and /selinux/reject_unknown. Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: Stephen Smalley <sds@tycho.nsa.gov> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-rw-r--r--security/selinux/include/security.h2
-rw-r--r--security/selinux/selinuxfs.c26
-rw-r--r--security/selinux/ss/policydb.c4
-rw-r--r--security/selinux/ss/policydb.h8
-rw-r--r--security/selinux/ss/services.c75
5 files changed, 106 insertions, 9 deletions
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 83bdd4d2a29e..39337afffec2 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -90,6 +90,8 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
90 90
91int security_get_classes(char ***classes, int *nclasses); 91int security_get_classes(char ***classes, int *nclasses);
92int security_get_permissions(char *class, char ***perms, int *nperms); 92int security_get_permissions(char *class, char ***perms, int *nperms);
93int security_get_reject_unknown(void);
94int security_get_allow_unknown(void);
93 95
94#define SECURITY_FS_USE_XATTR 1 /* use xattr */ 96#define SECURITY_FS_USE_XATTR 1 /* use xattr */
95#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */ 97#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index c9e92daedee2..f5f3e6da5da7 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -103,6 +103,8 @@ enum sel_inos {
103 SEL_MEMBER, /* compute polyinstantiation membership decision */ 103 SEL_MEMBER, /* compute polyinstantiation membership decision */
104 SEL_CHECKREQPROT, /* check requested protection, not kernel-applied one */ 104 SEL_CHECKREQPROT, /* check requested protection, not kernel-applied one */
105 SEL_COMPAT_NET, /* whether to use old compat network packet controls */ 105 SEL_COMPAT_NET, /* whether to use old compat network packet controls */
106 SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
107 SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
106 SEL_INO_NEXT, /* The next inode number to use */ 108 SEL_INO_NEXT, /* The next inode number to use */
107}; 109};
108 110
@@ -177,6 +179,23 @@ static const struct file_operations sel_enforce_ops = {
177 .write = sel_write_enforce, 179 .write = sel_write_enforce,
178}; 180};
179 181
182static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
183 size_t count, loff_t *ppos)
184{
185 char tmpbuf[TMPBUFLEN];
186 ssize_t length;
187 ino_t ino = filp->f_path.dentry->d_inode->i_ino;
188 int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?
189 security_get_reject_unknown() : !security_get_allow_unknown();
190
191 length = scnprintf(tmpbuf, TMPBUFLEN, "%d", handle_unknown);
192 return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
193}
194
195static const struct file_operations sel_handle_unknown_ops = {
196 .read = sel_read_handle_unknown,
197};
198
180#ifdef CONFIG_SECURITY_SELINUX_DISABLE 199#ifdef CONFIG_SECURITY_SELINUX_DISABLE
181static ssize_t sel_write_disable(struct file * file, const char __user * buf, 200static ssize_t sel_write_disable(struct file * file, const char __user * buf,
182 size_t count, loff_t *ppos) 201 size_t count, loff_t *ppos)
@@ -309,6 +328,11 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf,
309 length = count; 328 length = count;
310 329
311out1: 330out1:
331
332 printk(KERN_INFO "SELinux: policy loaded with handle_unknown=%s\n",
333 (security_get_reject_unknown() ? "reject" :
334 (security_get_allow_unknown() ? "allow" : "deny")));
335
312 audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, 336 audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
313 "policy loaded auid=%u", 337 "policy loaded auid=%u",
314 audit_get_loginuid(current->audit_context)); 338 audit_get_loginuid(current->audit_context));
@@ -1575,6 +1599,8 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
1575 [SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO}, 1599 [SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
1576 [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, 1600 [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
1577 [SEL_COMPAT_NET] = {"compat_net", &sel_compat_net_ops, S_IRUGO|S_IWUSR}, 1601 [SEL_COMPAT_NET] = {"compat_net", &sel_compat_net_ops, S_IRUGO|S_IWUSR},
1602 [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
1603 [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
1578 /* last one */ {""} 1604 /* last one */ {""}
1579 }; 1605 };
1580 ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); 1606 ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 5ecbad7d8b9f..539828b229b2 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -674,6 +674,8 @@ void policydb_destroy(struct policydb *p)
674 } 674 }
675 kfree(p->type_attr_map); 675 kfree(p->type_attr_map);
676 676
677 kfree(p->undefined_perms);
678
677 return; 679 return;
678} 680}
679 681
@@ -1527,6 +1529,8 @@ int policydb_read(struct policydb *p, void *fp)
1527 goto bad; 1529 goto bad;
1528 } 1530 }
1529 } 1531 }
1532 p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
1533 p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
1530 1534
1531 info = policydb_lookup_compat(p->policyvers); 1535 info = policydb_lookup_compat(p->policyvers);
1532 if (!info) { 1536 if (!info) {
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 8319d5ff5944..844d310f4f1b 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -242,6 +242,10 @@ struct policydb {
242 struct ebitmap *type_attr_map; 242 struct ebitmap *type_attr_map;
243 243
244 unsigned int policyvers; 244 unsigned int policyvers;
245
246 unsigned int reject_unknown : 1;
247 unsigned int allow_unknown : 1;
248 u32 *undefined_perms;
245}; 249};
246 250
247extern void policydb_destroy(struct policydb *p); 251extern void policydb_destroy(struct policydb *p);
@@ -253,6 +257,10 @@ extern int policydb_read(struct policydb *p, void *fp);
253 257
254#define POLICYDB_CONFIG_MLS 1 258#define POLICYDB_CONFIG_MLS 1
255 259
260/* the config flags related to unknown classes/perms are bits 2 and 3 */
261#define REJECT_UNKNOWN 0x00000002
262#define ALLOW_UNKNOWN 0x00000004
263
256#define OBJECT_R "object_r" 264#define OBJECT_R "object_r"
257#define OBJECT_R_VAL 1 265#define OBJECT_R_VAL 1
258 266
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 6100fc023055..03140edf97a3 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -292,6 +292,7 @@ static int context_struct_compute_av(struct context *scontext,
292 struct class_datum *tclass_datum; 292 struct class_datum *tclass_datum;
293 struct ebitmap *sattr, *tattr; 293 struct ebitmap *sattr, *tattr;
294 struct ebitmap_node *snode, *tnode; 294 struct ebitmap_node *snode, *tnode;
295 const struct selinux_class_perm *kdefs = &selinux_class_perm;
295 unsigned int i, j; 296 unsigned int i, j;
296 297
297 /* 298 /*
@@ -305,13 +306,6 @@ static int context_struct_compute_av(struct context *scontext,
305 tclass <= SECCLASS_NETLINK_DNRT_SOCKET) 306 tclass <= SECCLASS_NETLINK_DNRT_SOCKET)
306 tclass = SECCLASS_NETLINK_SOCKET; 307 tclass = SECCLASS_NETLINK_SOCKET;
307 308
308 if (!tclass || tclass > policydb.p_classes.nprim) {
309 printk(KERN_ERR "security_compute_av: unrecognized class %d\n",
310 tclass);
311 return -EINVAL;
312 }
313 tclass_datum = policydb.class_val_to_struct[tclass - 1];
314
315 /* 309 /*
316 * Initialize the access vectors to the default values. 310 * Initialize the access vectors to the default values.
317 */ 311 */
@@ -322,6 +316,36 @@ static int context_struct_compute_av(struct context *scontext,
322 avd->seqno = latest_granting; 316 avd->seqno = latest_granting;
323 317
324 /* 318 /*
319 * Check for all the invalid cases.
320 * - tclass 0
321 * - tclass > policy and > kernel
322 * - tclass > policy but is a userspace class
323 * - tclass > policy but we do not allow unknowns
324 */
325 if (unlikely(!tclass))
326 goto inval_class;
327 if (unlikely(tclass > policydb.p_classes.nprim))
328 if (tclass > kdefs->cts_len ||
329 !kdefs->class_to_string[tclass - 1] ||
330 !policydb.allow_unknown)
331 goto inval_class;
332
333 /*
334 * Kernel class and we allow unknown so pad the allow decision
335 * the pad will be all 1 for unknown classes.
336 */
337 if (tclass <= kdefs->cts_len && policydb.allow_unknown)
338 avd->allowed = policydb.undefined_perms[tclass - 1];
339
340 /*
341 * Not in policy. Since decision is completed (all 1 or all 0) return.
342 */
343 if (unlikely(tclass > policydb.p_classes.nprim))
344 return 0;
345
346 tclass_datum = policydb.class_val_to_struct[tclass - 1];
347
348 /*
325 * If a specific type enforcement rule was defined for 349 * If a specific type enforcement rule was defined for
326 * this permission check, then use it. 350 * this permission check, then use it.
327 */ 351 */
@@ -387,6 +411,10 @@ static int context_struct_compute_av(struct context *scontext,
387 } 411 }
388 412
389 return 0; 413 return 0;
414
415inval_class:
416 printk(KERN_ERR "%s: unrecognized class %d\n", __FUNCTION__, tclass);
417 return -EINVAL;
390} 418}
391 419
392static int security_validtrans_handle_fail(struct context *ocontext, 420static int security_validtrans_handle_fail(struct context *ocontext,
@@ -1054,6 +1082,13 @@ static int validate_classes(struct policydb *p)
1054 const char *def_class, *def_perm, *pol_class; 1082 const char *def_class, *def_perm, *pol_class;
1055 struct symtab *perms; 1083 struct symtab *perms;
1056 1084
1085 if (p->allow_unknown) {
1086 u32 num_classes = kdefs->cts_len;
1087 p->undefined_perms = kcalloc(num_classes, sizeof(u32), GFP_KERNEL);
1088 if (!p->undefined_perms)
1089 return -ENOMEM;
1090 }
1091
1057 for (i = 1; i < kdefs->cts_len; i++) { 1092 for (i = 1; i < kdefs->cts_len; i++) {
1058 def_class = kdefs->class_to_string[i]; 1093 def_class = kdefs->class_to_string[i];
1059 if (!def_class) 1094 if (!def_class)
@@ -1062,6 +1097,10 @@ static int validate_classes(struct policydb *p)
1062 printk(KERN_INFO 1097 printk(KERN_INFO
1063 "security: class %s not defined in policy\n", 1098 "security: class %s not defined in policy\n",
1064 def_class); 1099 def_class);
1100 if (p->reject_unknown)
1101 return -EINVAL;
1102 if (p->allow_unknown)
1103 p->undefined_perms[i-1] = ~0U;
1065 continue; 1104 continue;
1066 } 1105 }
1067 pol_class = p->p_class_val_to_name[i-1]; 1106 pol_class = p->p_class_val_to_name[i-1];
@@ -1087,12 +1126,16 @@ static int validate_classes(struct policydb *p)
1087 printk(KERN_INFO 1126 printk(KERN_INFO
1088 "security: permission %s in class %s not defined in policy\n", 1127 "security: permission %s in class %s not defined in policy\n",
1089 def_perm, pol_class); 1128 def_perm, pol_class);
1129 if (p->reject_unknown)
1130 return -EINVAL;
1131 if (p->allow_unknown)
1132 p->undefined_perms[class_val-1] |= perm_val;
1090 continue; 1133 continue;
1091 } 1134 }
1092 perdatum = hashtab_search(perms->table, def_perm); 1135 perdatum = hashtab_search(perms->table, def_perm);
1093 if (perdatum == NULL) { 1136 if (perdatum == NULL) {
1094 printk(KERN_ERR 1137 printk(KERN_ERR
1095 "security: permission %s in class %s not found in policy\n", 1138 "security: permission %s in class %s not found in policy, bad policy\n",
1096 def_perm, pol_class); 1139 def_perm, pol_class);
1097 return -EINVAL; 1140 return -EINVAL;
1098 } 1141 }
@@ -1130,12 +1173,16 @@ static int validate_classes(struct policydb *p)
1130 printk(KERN_INFO 1173 printk(KERN_INFO
1131 "security: permission %s in class %s not defined in policy\n", 1174 "security: permission %s in class %s not defined in policy\n",
1132 def_perm, pol_class); 1175 def_perm, pol_class);
1176 if (p->reject_unknown)
1177 return -EINVAL;
1178 if (p->allow_unknown)
1179 p->undefined_perms[class_val-1] |= (1 << j);
1133 continue; 1180 continue;
1134 } 1181 }
1135 perdatum = hashtab_search(perms->table, def_perm); 1182 perdatum = hashtab_search(perms->table, def_perm);
1136 if (perdatum == NULL) { 1183 if (perdatum == NULL) {
1137 printk(KERN_ERR 1184 printk(KERN_ERR
1138 "security: permission %s in class %s not found in policy\n", 1185 "security: permission %s in class %s not found in policy, bad policy\n",
1139 def_perm, pol_class); 1186 def_perm, pol_class);
1140 return -EINVAL; 1187 return -EINVAL;
1141 } 1188 }
@@ -2102,6 +2149,16 @@ err:
2102 return rc; 2149 return rc;
2103} 2150}
2104 2151
2152int security_get_reject_unknown(void)
2153{
2154 return policydb.reject_unknown;
2155}
2156
2157int security_get_allow_unknown(void)
2158{
2159 return policydb.allow_unknown;
2160}
2161
2105struct selinux_audit_rule { 2162struct selinux_audit_rule {
2106 u32 au_seqno; 2163 u32 au_seqno;
2107 struct context au_ctxt; 2164 struct context au_ctxt;