diff options
-rw-r--r-- | security/selinux/include/security.h | 2 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 26 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 4 | ||||
-rw-r--r-- | security/selinux/ss/policydb.h | 8 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 75 |
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 | ||
91 | int security_get_classes(char ***classes, int *nclasses); | 91 | int security_get_classes(char ***classes, int *nclasses); |
92 | int security_get_permissions(char *class, char ***perms, int *nperms); | 92 | int security_get_permissions(char *class, char ***perms, int *nperms); |
93 | int security_get_reject_unknown(void); | ||
94 | int 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 | ||
182 | static 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 | |||
195 | static 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 |
181 | static ssize_t sel_write_disable(struct file * file, const char __user * buf, | 200 | static 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 | ||
311 | out1: | 330 | out1: |
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 | ||
247 | extern void policydb_destroy(struct policydb *p); | 251 | extern 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 | |||
415 | inval_class: | ||
416 | printk(KERN_ERR "%s: unrecognized class %d\n", __FUNCTION__, tclass); | ||
417 | return -EINVAL; | ||
390 | } | 418 | } |
391 | 419 | ||
392 | static int security_validtrans_handle_fail(struct context *ocontext, | 420 | static 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 | ||
2152 | int security_get_reject_unknown(void) | ||
2153 | { | ||
2154 | return policydb.reject_unknown; | ||
2155 | } | ||
2156 | |||
2157 | int security_get_allow_unknown(void) | ||
2158 | { | ||
2159 | return policydb.allow_unknown; | ||
2160 | } | ||
2161 | |||
2105 | struct selinux_audit_rule { | 2162 | struct selinux_audit_rule { |
2106 | u32 au_seqno; | 2163 | u32 au_seqno; |
2107 | struct context au_ctxt; | 2164 | struct context au_ctxt; |