summaryrefslogtreecommitdiff
path: root/security/selinux
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/.gitignore1
-rw-r--r--security/selinux/Makefile14
-rw-r--r--security/selinux/avc.c89
-rw-r--r--security/selinux/genheaders.c154
-rw-r--r--security/selinux/hooks.c535
-rw-r--r--security/selinux/include/audit.h51
-rw-r--r--security/selinux/include/avc.h5
-rw-r--r--security/selinux/include/classmap.h21
-rw-r--r--security/selinux/include/conditional.h2
-rw-r--r--security/selinux/include/initial_sid_to_string.h4
-rw-r--r--security/selinux/include/objsec.h28
-rw-r--r--security/selinux/include/policycap.h1
-rw-r--r--security/selinux/include/policycap_names.h1
-rw-r--r--security/selinux/include/security.h16
-rw-r--r--security/selinux/netlabel.c48
-rw-r--r--security/selinux/nlmsgtab.c297
-rw-r--r--security/selinux/selinuxfs.c58
-rw-r--r--security/selinux/ss/avtab.c121
-rw-r--r--security/selinux/ss/avtab.h82
-rw-r--r--security/selinux/ss/conditional.c100
-rw-r--r--security/selinux/ss/conditional.h31
-rw-r--r--security/selinux/ss/constraint.h67
-rw-r--r--security/selinux/ss/context.c4
-rw-r--r--security/selinux/ss/context.h45
-rw-r--r--security/selinux/ss/ebitmap.c116
-rw-r--r--security/selinux/ss/ebitmap.h87
-rw-r--r--security/selinux/ss/hashtab.c29
-rw-r--r--security/selinux/ss/hashtab.h37
-rw-r--r--security/selinux/ss/mls.c89
-rw-r--r--security/selinux/ss/mls.h58
-rw-r--r--security/selinux/ss/mls_types.h32
-rw-r--r--security/selinux/ss/policydb.c546
-rw-r--r--security/selinux/ss/policydb.h210
-rw-r--r--security/selinux/ss/services.c186
-rw-r--r--security/selinux/ss/services.h3
-rw-r--r--security/selinux/ss/sidtab.c75
-rw-r--r--security/selinux/ss/sidtab.h36
-rw-r--r--security/selinux/ss/symtab.c22
-rw-r--r--security/selinux/ss/symtab.h9
-rw-r--r--security/selinux/xfrm.c7
40 files changed, 1826 insertions, 1491 deletions
diff --git a/security/selinux/.gitignore b/security/selinux/.gitignore
index 168fae13ca5a..01c0df8ab009 100644
--- a/security/selinux/.gitignore
+++ b/security/selinux/.gitignore
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
av_permissions.h
flask.h
+/genheaders
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index c47519ed8156..66e56e9011df 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -33,10 +33,12 @@ $(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h
quiet_cmd_genhdrs = GEN $(addprefix $(obj)/,$(genhdrs))
cmd_genhdrs = $< $(addprefix $(obj)/,$(genhdrs))
-# see the note above, replace the $targets and 'flask.h' rule with the lines
-# below:
-# targets += $(genhdrs)
-# $(addprefix $(obj)/,$(genhdrs)) &: scripts/selinux/...
-targets += flask.h
-$(obj)/flask.h: scripts/selinux/genheaders/genheaders FORCE
+targets += $(genhdrs)
+
+# see the note above, replace the 'flask.h' rule with the line below:
+# $(addprefix $(obj)/,$(genhdrs)) &: $(obj)/genheaders FORCE
+$(obj)/flask.h: $(obj)/genheaders FORCE
$(call if_changed,genhdrs)
+
+hostprogs := genheaders
+HOST_EXTRACFLAGS += -I$(srctree)/security/selinux/include
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 32eb67fb3e42..1f2680bcc43a 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -134,18 +134,10 @@ static inline u32 avc_hash(u32 ssid, u32 tsid, u16 tclass)
*/
void __init avc_init(void)
{
- avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node),
- 0, SLAB_PANIC, NULL);
- avc_xperms_cachep = kmem_cache_create("avc_xperms_node",
- sizeof(struct avc_xperms_node),
- 0, SLAB_PANIC, NULL);
- avc_xperms_decision_cachep = kmem_cache_create(
- "avc_xperms_decision_node",
- sizeof(struct avc_xperms_decision_node),
- 0, SLAB_PANIC, NULL);
- avc_xperms_data_cachep = kmem_cache_create("avc_xperms_data",
- sizeof(struct extended_perms_data),
- 0, SLAB_PANIC, NULL);
+ avc_node_cachep = KMEM_CACHE(avc_node, SLAB_PANIC);
+ avc_xperms_cachep = KMEM_CACHE(avc_xperms_node, SLAB_PANIC);
+ avc_xperms_decision_cachep = KMEM_CACHE(avc_xperms_decision_node, SLAB_PANIC);
+ avc_xperms_data_cachep = KMEM_CACHE(extended_perms_data, SLAB_PANIC);
}
int avc_get_hash_stats(char *page)
@@ -182,13 +174,15 @@ int avc_get_hash_stats(char *page)
* using a linked list for extended_perms_decision lookup because the list is
* always small. i.e. less than 5, typically 1
*/
-static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver,
- struct avc_xperms_node *xp_node)
+static struct extended_perms_decision *
+avc_xperms_decision_lookup(u8 driver, u8 base_perm,
+ struct avc_xperms_node *xp_node)
{
struct avc_xperms_decision_node *xpd_node;
list_for_each_entry(xpd_node, &xp_node->xpd_head, xpd_list) {
- if (xpd_node->xpd.driver == driver)
+ if (xpd_node->xpd.driver == driver &&
+ xpd_node->xpd.base_perm == base_perm)
return &xpd_node->xpd;
}
return NULL;
@@ -213,11 +207,12 @@ avc_xperms_has_perm(struct extended_perms_decision *xpd,
}
static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node,
- u8 driver, u8 perm)
+ u8 driver, u8 base_perm, u8 perm)
{
struct extended_perms_decision *xpd;
security_xperm_set(xp_node->xp.drivers.p, driver);
- xpd = avc_xperms_decision_lookup(driver, xp_node);
+ xp_node->xp.base_perms |= base_perm;
+ xpd = avc_xperms_decision_lookup(driver, base_perm, xp_node);
if (xpd && xpd->allowed)
security_xperm_set(xpd->allowed->p, perm);
}
@@ -253,6 +248,7 @@ static void avc_xperms_free(struct avc_xperms_node *xp_node)
static void avc_copy_xperms_decision(struct extended_perms_decision *dest,
struct extended_perms_decision *src)
{
+ dest->base_perm = src->base_perm;
dest->driver = src->driver;
dest->used = src->used;
if (dest->used & XPERMS_ALLOWED)
@@ -280,6 +276,7 @@ static inline void avc_quick_copy_xperms_decision(u8 perm,
*/
u8 i = perm >> 5;
+ dest->base_perm = src->base_perm;
dest->used = src->used;
if (dest->used & XPERMS_ALLOWED)
dest->allowed->p[i] = src->allowed->p[i];
@@ -330,12 +327,12 @@ static int avc_add_xperms_decision(struct avc_node *node,
{
struct avc_xperms_decision_node *dest_xpd;
- node->ae.xp_node->xp.len++;
dest_xpd = avc_xperms_decision_alloc(src->used);
if (!dest_xpd)
return -ENOMEM;
avc_copy_xperms_decision(&dest_xpd->xpd, src);
list_add(&dest_xpd->xpd_list, &node->ae.xp_node->xpd_head);
+ node->ae.xp_node->xp.len++;
return 0;
}
@@ -365,6 +362,7 @@ static int avc_xperms_populate(struct avc_node *node,
memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p));
dest->xp.len = src->xp.len;
+ dest->xp.base_perms = src->xp.base_perms;
/* for each source xpd allocate a destination xpd and copy */
list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) {
@@ -396,7 +394,7 @@ static inline u32 avc_xperms_audit_required(u32 requested,
audited = denied & avd->auditdeny;
if (audited && xpd) {
if (avc_xperms_has_perm(xpd, perm, XPERMS_DONTAUDIT))
- audited &= ~requested;
+ audited = 0;
}
} else if (result) {
audited = denied = requested;
@@ -404,7 +402,7 @@ static inline u32 avc_xperms_audit_required(u32 requested,
audited = requested & avd->auditallow;
if (audited && xpd) {
if (!avc_xperms_has_perm(xpd, perm, XPERMS_AUDITALLOW))
- audited &= ~requested;
+ audited = 0;
}
}
@@ -815,6 +813,7 @@ out:
* @event : Updating event
* @perms : Permission mask bits
* @driver: xperm driver information
+ * @base_perm: the base permission associated with the extended permission
* @xperm: xperm permissions
* @ssid: AVC entry source sid
* @tsid: AVC entry target sid
@@ -828,10 +827,9 @@ out:
* otherwise, this function updates the AVC entry. The original AVC-entry object
* will release later by RCU.
*/
-static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
- u32 tsid, u16 tclass, u32 seqno,
- struct extended_perms_decision *xpd,
- u32 flags)
+static int avc_update_node(u32 event, u32 perms, u8 driver, u8 base_perm,
+ u8 xperm, u32 ssid, u32 tsid, u16 tclass, u32 seqno,
+ struct extended_perms_decision *xpd, u32 flags)
{
u32 hvalue;
int rc = 0;
@@ -888,7 +886,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
case AVC_CALLBACK_GRANT:
node->ae.avd.allowed |= perms;
if (node->ae.xp_node && (flags & AVC_EXTENDED_PERMS))
- avc_xperms_allow_perm(node->ae.xp_node, driver, xperm);
+ avc_xperms_allow_perm(node->ae.xp_node, driver, base_perm, xperm);
break;
case AVC_CALLBACK_TRY_REVOKE:
case AVC_CALLBACK_REVOKE:
@@ -907,7 +905,11 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
node->ae.avd.auditdeny &= ~perms;
break;
case AVC_CALLBACK_ADD_XPERMS:
- avc_add_xperms_decision(node, xpd);
+ rc = avc_add_xperms_decision(node, xpd);
+ if (rc) {
+ avc_node_kill(node);
+ goto out_unlock;
+ }
break;
}
avc_node_replace(node, orig);
@@ -991,10 +993,9 @@ static noinline void avc_compute_av(u32 ssid, u32 tsid, u16 tclass,
avc_insert(ssid, tsid, tclass, avd, xp_node);
}
-static noinline int avc_denied(u32 ssid, u32 tsid,
- u16 tclass, u32 requested,
- u8 driver, u8 xperm, unsigned int flags,
- struct av_decision *avd)
+static noinline int avc_denied(u32 ssid, u32 tsid, u16 tclass, u32 requested,
+ u8 driver, u8 base_perm, u8 xperm,
+ unsigned int flags, struct av_decision *avd)
{
if (flags & AVC_STRICT)
return -EACCES;
@@ -1003,7 +1004,7 @@ static noinline int avc_denied(u32 ssid, u32 tsid,
!(avd->flags & AVD_FLAGS_PERMISSIVE))
return -EACCES;
- avc_update_node(AVC_CALLBACK_GRANT, requested, driver,
+ avc_update_node(AVC_CALLBACK_GRANT, requested, driver, base_perm,
xperm, ssid, tsid, tclass, avd->seqno, NULL, flags);
return 0;
}
@@ -1016,7 +1017,8 @@ static noinline int avc_denied(u32 ssid, u32 tsid,
* driver field is used to specify which set contains the permission.
*/
int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
- u8 driver, u8 xperm, struct common_audit_data *ad)
+ u8 driver, u8 base_perm, u8 xperm,
+ struct common_audit_data *ad)
{
struct avc_node *node;
struct av_decision avd;
@@ -1051,22 +1053,23 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
local_xpd.auditallow = &auditallow;
local_xpd.dontaudit = &dontaudit;
- xpd = avc_xperms_decision_lookup(driver, xp_node);
+ xpd = avc_xperms_decision_lookup(driver, base_perm, xp_node);
if (unlikely(!xpd)) {
/*
* Compute the extended_perms_decision only if the driver
- * is flagged
+ * is flagged and the base permission is known.
*/
- if (!security_xperm_test(xp_node->xp.drivers.p, driver)) {
+ if (!security_xperm_test(xp_node->xp.drivers.p, driver) ||
+ !(xp_node->xp.base_perms & base_perm)) {
avd.allowed &= ~requested;
goto decision;
}
rcu_read_unlock();
- security_compute_xperms_decision(ssid, tsid, tclass,
- driver, &local_xpd);
+ security_compute_xperms_decision(ssid, tsid, tclass, driver,
+ base_perm, &local_xpd);
rcu_read_lock();
- avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested,
- driver, xperm, ssid, tsid, tclass, avd.seqno,
+ avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver,
+ base_perm, xperm, ssid, tsid, tclass, avd.seqno,
&local_xpd, 0);
} else {
avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd);
@@ -1079,8 +1082,8 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
decision:
denied = requested & ~(avd.allowed);
if (unlikely(denied))
- rc = avc_denied(ssid, tsid, tclass, requested,
- driver, xperm, AVC_EXTENDED_PERMS, &avd);
+ rc = avc_denied(ssid, tsid, tclass, requested, driver,
+ base_perm, xperm, AVC_EXTENDED_PERMS, &avd);
rcu_read_unlock();
@@ -1114,7 +1117,7 @@ static noinline int avc_perm_nonode(u32 ssid, u32 tsid, u16 tclass,
avc_compute_av(ssid, tsid, tclass, avd, &xp_node);
denied = requested & ~(avd->allowed);
if (unlikely(denied))
- return avc_denied(ssid, tsid, tclass, requested, 0, 0,
+ return avc_denied(ssid, tsid, tclass, requested, 0, 0, 0,
flags, avd);
return 0;
}
@@ -1162,7 +1165,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
rcu_read_unlock();
if (unlikely(denied))
- return avc_denied(ssid, tsid, tclass, requested, 0, 0,
+ return avc_denied(ssid, tsid, tclass, requested, 0, 0, 0,
flags, avd);
return 0;
}
diff --git a/security/selinux/genheaders.c b/security/selinux/genheaders.c
new file mode 100644
index 000000000000..3834d7eb0af6
--- /dev/null
+++ b/security/selinux/genheaders.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+struct security_class_mapping {
+ const char *name;
+ const char *perms[sizeof(unsigned) * 8 + 1];
+};
+
+#include "classmap.h"
+#include "initial_sid_to_string.h"
+
+const char *progname;
+
+static void usage(void)
+{
+ printf("usage: %s flask.h av_permissions.h\n", progname);
+ exit(1);
+}
+
+static char *stoupperx(const char *s)
+{
+ char *s2 = strdup(s);
+ char *p;
+
+ if (!s2) {
+ fprintf(stderr, "%s: out of memory\n", progname);
+ exit(3);
+ }
+
+ for (p = s2; *p; p++)
+ *p = toupper(*p);
+ return s2;
+}
+
+int main(int argc, char *argv[])
+{
+ int i, j;
+ int isids_len;
+ FILE *fout;
+
+ progname = argv[0];
+
+ if (argc < 3)
+ usage();
+
+ fout = fopen(argv[1], "w");
+ if (!fout) {
+ fprintf(stderr, "Could not open %s for writing: %s\n",
+ argv[1], strerror(errno));
+ exit(2);
+ }
+
+ fprintf(fout, "/* This file is automatically generated. Do not edit. */\n");
+ fprintf(fout, "#ifndef _SELINUX_FLASK_H_\n#define _SELINUX_FLASK_H_\n\n");
+
+ for (i = 0; secclass_map[i].name; i++) {
+ char *name = stoupperx(secclass_map[i].name);
+
+ fprintf(fout, "#define SECCLASS_%-39s %2d\n", name, i+1);
+ free(name);
+ }
+
+ fprintf(fout, "\n");
+
+ isids_len = sizeof(initial_sid_to_string) / sizeof(char *);
+ for (i = 1; i < isids_len; i++) {
+ const char *s = initial_sid_to_string[i];
+ if (s) {
+ char *sidname = stoupperx(s);
+
+ fprintf(fout, "#define SECINITSID_%-39s %2d\n", sidname, i);
+ free(sidname);
+ }
+ }
+ fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1);
+ fprintf(fout, "\nstatic inline bool security_is_socket_class(u16 kern_tclass)\n");
+ fprintf(fout, "{\n");
+ fprintf(fout, "\tbool sock = false;\n\n");
+ fprintf(fout, "\tswitch (kern_tclass) {\n");
+ for (i = 0; secclass_map[i].name; i++) {
+ static char s[] = "SOCKET";
+ int len, l;
+ char *name = stoupperx(secclass_map[i].name);
+
+ len = strlen(name);
+ l = sizeof(s) - 1;
+ if (len >= l && memcmp(name + len - l, s, l) == 0)
+ fprintf(fout, "\tcase SECCLASS_%s:\n", name);
+ free(name);
+ }
+ fprintf(fout, "\t\tsock = true;\n");
+ fprintf(fout, "\t\tbreak;\n");
+ fprintf(fout, "\tdefault:\n");
+ fprintf(fout, "\t\tbreak;\n");
+ fprintf(fout, "\t}\n\n");
+ fprintf(fout, "\treturn sock;\n");
+ fprintf(fout, "}\n");
+
+ fprintf(fout, "\n#endif\n");
+
+ if (fclose(fout) != 0) {
+ fprintf(stderr, "Could not successfully close %s: %s\n",
+ argv[1], strerror(errno));
+ exit(4);
+ }
+
+ fout = fopen(argv[2], "w");
+ if (!fout) {
+ fprintf(stderr, "Could not open %s for writing: %s\n",
+ argv[2], strerror(errno));
+ exit(5);
+ }
+
+ fprintf(fout, "/* This file is automatically generated. Do not edit. */\n");
+ fprintf(fout, "#ifndef _SELINUX_AV_PERMISSIONS_H_\n#define _SELINUX_AV_PERMISSIONS_H_\n\n");
+
+ for (i = 0; secclass_map[i].name; i++) {
+ const struct security_class_mapping *map = &secclass_map[i];
+ int len;
+ char *name = stoupperx(map->name);
+
+ len = strlen(name);
+ for (j = 0; map->perms[j]; j++) {
+ char *permname;
+
+ if (j >= 32) {
+ fprintf(stderr, "Too many permissions to fit into an access vector at (%s, %s).\n",
+ map->name, map->perms[j]);
+ exit(5);
+ }
+ permname = stoupperx(map->perms[j]);
+ fprintf(fout, "#define %s__%-*s 0x%08xU\n", name,
+ 39-len, permname, 1U<<j);
+ free(permname);
+ }
+ free(name);
+ }
+
+ fprintf(fout, "\n#endif\n");
+
+ if (fclose(fout) != 0) {
+ fprintf(stderr, "Could not successfully close %s: %s\n",
+ argv[2], strerror(errno));
+ exit(6);
+ }
+
+ exit(0);
+}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 338b023a8c3e..7b867dfec88b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -282,8 +282,13 @@ static int __inode_security_revalidate(struct inode *inode,
might_sleep_if(may_sleep);
+ /*
+ * The check of isec->initialized below is racy but
+ * inode_doinit_with_dentry() will recheck with
+ * isec->lock held.
+ */
if (selinux_initialized() &&
- isec->initialized != LABEL_INITIALIZED) {
+ data_race(isec->initialized != LABEL_INITIALIZED)) {
if (!may_sleep)
return -ECHILD;
@@ -402,7 +407,7 @@ static const struct {
static int match_opt_prefix(char *s, int l, char **arg)
{
- int i;
+ unsigned int i;
for (i = 0; i < ARRAY_SIZE(tokens); i++) {
size_t len = tokens[i].len;
@@ -2202,23 +2207,16 @@ static int selinux_syslog(int type)
}
/*
- * Check that a process has enough memory to allocate a new virtual
- * mapping. 0 means there is enough memory for the allocation to
- * succeed and -ENOMEM implies there is not.
+ * Check permission for allocating a new virtual mapping. Returns
+ * 0 if permission is granted, negative error code if not.
*
* Do not audit the selinux permission check, as this is applied to all
* processes that allocate mappings.
*/
static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
{
- int rc, cap_sys_admin = 0;
-
- rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
- CAP_OPT_NOAUDIT, true);
- if (rc == 0)
- cap_sys_admin = 1;
-
- return cap_sys_admin;
+ return cred_has_capability(current_cred(), CAP_SYS_ADMIN,
+ CAP_OPT_NOAUDIT, true);
}
/* binprm security operations */
@@ -2871,8 +2869,8 @@ static void selinux_inode_free_security(struct inode *inode)
static int selinux_dentry_init_security(struct dentry *dentry, int mode,
const struct qstr *name,
- const char **xattr_name, void **ctx,
- u32 *ctxlen)
+ const char **xattr_name,
+ struct lsm_context *cp)
{
u32 newsid;
int rc;
@@ -2887,8 +2885,8 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
if (xattr_name)
*xattr_name = XATTR_NAME_SELINUX;
- return security_sid_to_context(newsid, (char **)ctx,
- ctxlen);
+ cp->id = LSM_ID_SELINUX;
+ return security_sid_to_context(newsid, &cp->context, &cp->len);
}
static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
@@ -2920,23 +2918,22 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
struct superblock_security_struct *sbsec;
struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);
u32 newsid, clen;
+ u16 newsclass;
int rc;
char *context;
sbsec = selinux_superblock(dir->i_sb);
newsid = tsec->create_sid;
-
- rc = selinux_determine_inode_label(tsec, dir, qstr,
- inode_mode_to_security_class(inode->i_mode),
- &newsid);
+ newsclass = inode_mode_to_security_class(inode->i_mode);
+ rc = selinux_determine_inode_label(tsec, dir, qstr, newsclass, &newsid);
if (rc)
return rc;
/* Possibly defer initialization to selinux_complete_init. */
if (sbsec->flags & SE_SBINITIALIZED) {
struct inode_security_struct *isec = selinux_inode(inode);
- isec->sclass = inode_mode_to_security_class(inode->i_mode);
+ isec->sclass = newsclass;
isec->sid = newsid;
isec->initialized = LABEL_INITIALIZED;
}
@@ -2962,7 +2959,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
const struct qstr *name,
const struct inode *context_inode)
{
- const struct task_security_struct *tsec = selinux_cred(current_cred());
+ u32 sid = current_sid();
struct common_audit_data ad;
struct inode_security_struct *isec;
int rc;
@@ -2991,7 +2988,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
} else {
isec->sclass = SECCLASS_ANON_INODE;
rc = security_transition_sid(
- tsec->sid, tsec->sid,
+ sid, sid,
isec->sclass, name, &isec->sid);
if (rc)
return rc;
@@ -3006,7 +3003,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
ad.type = LSM_AUDIT_DATA_ANONINODE;
ad.u.anonclass = name ? (const char *)name->name : "?";
- return avc_has_perm(tsec->sid,
+ return avc_has_perm(sid,
isec->sid,
isec->sclass,
FILE__CREATE,
@@ -3064,14 +3061,12 @@ static int selinux_inode_readlink(struct dentry *dentry)
static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
bool rcu)
{
- const struct cred *cred = current_cred();
struct common_audit_data ad;
struct inode_security_struct *isec;
- u32 sid;
+ u32 sid = current_sid();
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
- sid = cred_sid(cred);
isec = inode_security_rcu(inode, rcu);
if (IS_ERR(isec))
return PTR_ERR(isec);
@@ -3095,12 +3090,11 @@ static noinline int audit_inode_permission(struct inode *inode,
static int selinux_inode_permission(struct inode *inode, int mask)
{
- const struct cred *cred = current_cred();
u32 perms;
bool from_access;
bool no_block = mask & MAY_NOT_BLOCK;
struct inode_security_struct *isec;
- u32 sid;
+ u32 sid = current_sid();
struct av_decision avd;
int rc, rc2;
u32 audited, denied;
@@ -3117,7 +3111,6 @@ static int selinux_inode_permission(struct inode *inode, int mask)
perms = file_mask_to_av(inode->i_mode, mask);
- sid = cred_sid(cred);
isec = inode_security_rcu(inode, no_block);
if (IS_ERR(isec))
return PTR_ERR(isec);
@@ -3136,12 +3129,13 @@ static int selinux_inode_permission(struct inode *inode, int mask)
return rc;
}
-static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+ struct iattr *iattr)
{
const struct cred *cred = current_cred();
struct inode *inode = d_backing_inode(dentry);
unsigned int ia_valid = iattr->ia_valid;
- __u32 av = FILE__WRITE;
+ u32 av = FILE__WRITE;
/* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
if (ia_valid & ATTR_FORCE) {
@@ -3181,6 +3175,23 @@ static bool has_cap_mac_admin(bool audit)
return true;
}
+/**
+ * selinux_inode_xattr_skipcap - Skip the xattr capability checks?
+ * @name: name of the xattr
+ *
+ * Returns 1 to indicate that SELinux "owns" the access control rights to xattrs
+ * named @name; the LSM layer should avoid enforcing any traditional
+ * capability based access controls on this xattr. Returns 0 to indicate that
+ * SELinux does not "own" the access control rights to xattrs named @name and is
+ * deferring to the LSM layer for further access controls, including capability
+ * based controls.
+ */
+static int selinux_inode_xattr_skipcap(const char *name)
+{
+ /* require capability check if not a selinux xattr */
+ return !strcmp(name, XATTR_NAME_SELINUX);
+}
+
static int selinux_inode_setxattr(struct mnt_idmap *idmap,
struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
@@ -3192,15 +3203,9 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
u32 newsid, sid = current_sid();
int rc = 0;
- if (strcmp(name, XATTR_NAME_SELINUX)) {
- rc = cap_inode_setxattr(dentry, name, value, size, flags);
- if (rc)
- return rc;
-
- /* Not an attribute we recognize, so just check the
- ordinary setattr permission. */
+ /* if not a selinux xattr, only check the ordinary setattr perm */
+ if (strcmp(name, XATTR_NAME_SELINUX))
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
- }
if (!selinux_initialized())
return (inode_owner_or_capable(idmap, inode) ? 0 : -EPERM);
@@ -3349,15 +3354,9 @@ static int selinux_inode_listxattr(struct dentry *dentry)
static int selinux_inode_removexattr(struct mnt_idmap *idmap,
struct dentry *dentry, const char *name)
{
- if (strcmp(name, XATTR_NAME_SELINUX)) {
- int rc = cap_inode_removexattr(idmap, dentry, name);
- if (rc)
- return rc;
-
- /* Not an attribute we recognize, so just check the
- ordinary setattr permission. */
+ /* if not a selinux xattr, only check the ordinary setattr perm */
+ if (strcmp(name, XATTR_NAME_SELINUX))
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
- }
if (!selinux_initialized())
return 0;
@@ -3405,7 +3404,8 @@ static int selinux_path_notify(const struct path *path, u64 mask,
perm |= FILE__WATCH_WITH_PERM;
/* watches on read-like events need the file:watch_reads permission */
- if (mask & (FS_ACCESS | FS_ACCESS_PERM | FS_CLOSE_NOWRITE))
+ if (mask & (FS_ACCESS | FS_ACCESS_PERM | FS_PRE_ACCESS |
+ FS_CLOSE_NOWRITE))
perm |= FILE__WATCH_READS;
return path_has_perm(current_cred(), path, perm);
@@ -3504,15 +3504,16 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
return len;
}
-static void selinux_inode_getsecid(struct inode *inode, u32 *secid)
+static void selinux_inode_getlsmprop(struct inode *inode, struct lsm_prop *prop)
{
struct inode_security_struct *isec = inode_security_novalidate(inode);
- *secid = isec->sid;
+
+ prop->selinux.secid = isec->sid;
}
static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
{
- u32 sid;
+ struct lsm_prop prop;
struct task_security_struct *tsec;
struct cred *new_creds = *new;
@@ -3524,20 +3525,21 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
tsec = selinux_cred(new_creds);
/* Get label from overlay inode and set it in create_sid */
- selinux_inode_getsecid(d_inode(src), &sid);
- tsec->create_sid = sid;
+ selinux_inode_getlsmprop(d_inode(src), &prop);
+ tsec->create_sid = prop.selinux.secid;
*new = new_creds;
return 0;
}
-static int selinux_inode_copy_up_xattr(const char *name)
+static int selinux_inode_copy_up_xattr(struct dentry *dentry, const char *name)
{
/* The copy_up hook above sets the initial context on an inode, but we
* don't then want to overwrite it by blindly copying all the lower
- * xattrs up. Instead, we have to filter out SELinux-related xattrs.
+ * xattrs up. Instead, filter out SELinux-related xattrs following
+ * policy load.
*/
- if (strcmp(name, XATTR_NAME_SELINUX) == 0)
- return 1; /* Discard */
+ if (selinux_initialized() && !strcmp(name, XATTR_NAME_SELINUX))
+ return -ECANCELED; /* Discard */
/*
* Any other attribute apart from SELINUX is not claimed, supported
* by selinux.
@@ -3687,8 +3689,8 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
return 0;
isec = inode_security(inode);
- rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass,
- requested, driver, xperm, &ad);
+ rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, requested,
+ driver, AVC_EXT_IOCTL, xperm, &ad);
out:
return rc;
}
@@ -3850,7 +3852,17 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
if (default_noexec &&
(prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
int rc = 0;
- if (vma_is_initial_heap(vma)) {
+ /*
+ * We don't use the vma_is_initial_heap() helper as it has
+ * a history of problems and is currently broken on systems
+ * where there is no heap, e.g. brk == start_brk. Before
+ * replacing the conditional below with vma_is_initial_heap(),
+ * or something similar, please ensure that the logic is the
+ * same as what we have below or you have tested every possible
+ * corner case you can think to test.
+ */
+ if (vma->vm_start >= vma->vm_mm->start_brk &&
+ vma->vm_end <= vma->vm_mm->brk) {
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
PROCESS__EXECHEAP, NULL);
} else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
@@ -3938,7 +3950,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
struct file_security_struct *fsec;
/* struct fown_struct is never outside the context of a struct file */
- file = container_of(fown, struct file, f_owner);
+ file = fown->file;
fsec = selinux_file(file);
@@ -4024,6 +4036,11 @@ static void selinux_cred_getsecid(const struct cred *c, u32 *secid)
*secid = cred_sid(c);
}
+static void selinux_cred_getlsmprop(const struct cred *c, struct lsm_prop *prop)
+{
+ prop->selinux.secid = cred_sid(c);
+}
+
/*
* set the security data for a kernel service
* - all the creation contexts are set to unlabelled
@@ -4159,14 +4176,15 @@ static int selinux_task_getsid(struct task_struct *p)
PROCESS__GETSESSION, NULL);
}
-static void selinux_current_getsecid_subj(u32 *secid)
+static void selinux_current_getlsmprop_subj(struct lsm_prop *prop)
{
- *secid = current_sid();
+ prop->selinux.secid = current_sid();
}
-static void selinux_task_getsecid_obj(struct task_struct *p, u32 *secid)
+static void selinux_task_getlsmprop_obj(struct task_struct *p,
+ struct lsm_prop *prop)
{
- *secid = task_sid_obj(p);
+ prop->selinux.secid = task_sid_obj(p);
}
static int selinux_task_setnice(struct task_struct *p, int nice)
@@ -4580,14 +4598,10 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
secclass, NULL, socksid);
}
-static int sock_has_perm(struct sock *sk, u32 perms)
+static bool sock_skip_has_perm(u32 sid)
{
- struct sk_security_struct *sksec = sk->sk_security;
- struct common_audit_data ad;
- struct lsm_network_audit net;
-
- if (sksec->sid == SECINITSID_KERNEL)
- return 0;
+ if (sid == SECINITSID_KERNEL)
+ return true;
/*
* Before POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT, sockets that
@@ -4601,7 +4615,19 @@ static int sock_has_perm(struct sock *sk, u32 perms)
* setting.
*/
if (!selinux_policycap_userspace_initial_context() &&
- sksec->sid == SECINITSID_INIT)
+ sid == SECINITSID_INIT)
+ return true;
+ return false;
+}
+
+
+static int sock_has_perm(struct sock *sk, u32 perms)
+{
+ struct sk_security_struct *sksec = sk->sk_security;
+ struct common_audit_data ad;
+ struct lsm_network_audit net;
+
+ if (sock_skip_has_perm(sksec->sid))
return 0;
ad_net_init_from_sk(&ad, &net, sk);
@@ -4650,7 +4676,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
isec->initialized = LABEL_INITIALIZED;
if (sock->sk) {
- sksec = sock->sk->sk_security;
+ sksec = selinux_sock(sock->sk);
sksec->sclass = sclass;
sksec->sid = sid;
/* Allows detection of the first association on this socket */
@@ -4666,8 +4692,8 @@ static int selinux_socket_post_create(struct socket *sock, int family,
static int selinux_socket_socketpair(struct socket *socka,
struct socket *sockb)
{
- struct sk_security_struct *sksec_a = socka->sk->sk_security;
- struct sk_security_struct *sksec_b = sockb->sk->sk_security;
+ struct sk_security_struct *sksec_a = selinux_sock(socka->sk);
+ struct sk_security_struct *sksec_b = selinux_sock(sockb->sk);
sksec_a->peer_sid = sksec_b->sid;
sksec_b->peer_sid = sksec_a->sid;
@@ -4682,7 +4708,7 @@ static int selinux_socket_socketpair(struct socket *socka,
static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
{
struct sock *sk = sock->sk;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
u16 family;
int err;
@@ -4810,7 +4836,7 @@ out:
return err;
err_af:
/* Note that SCTP services expect -EINVAL, others -EAFNOSUPPORT. */
- if (sksec->sclass == SECCLASS_SCTP_SOCKET)
+ if (sk->sk_protocol == IPPROTO_SCTP)
return -EINVAL;
return -EAFNOSUPPORT;
}
@@ -4822,7 +4848,7 @@ static int selinux_socket_connect_helper(struct socket *sock,
struct sockaddr *address, int addrlen)
{
struct sock *sk = sock->sk;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
int err;
err = sock_has_perm(sk, SOCKET__CONNECT);
@@ -5000,9 +5026,9 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
struct sock *other,
struct sock *newsk)
{
- struct sk_security_struct *sksec_sock = sock->sk_security;
- struct sk_security_struct *sksec_other = other->sk_security;
- struct sk_security_struct *sksec_new = newsk->sk_security;
+ struct sk_security_struct *sksec_sock = selinux_sock(sock);
+ struct sk_security_struct *sksec_other = selinux_sock(other);
+ struct sk_security_struct *sksec_new = selinux_sock(newsk);
struct common_audit_data ad;
struct lsm_network_audit net;
int err;
@@ -5031,8 +5057,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
static int selinux_socket_unix_may_send(struct socket *sock,
struct socket *other)
{
- struct sk_security_struct *ssec = sock->sk->sk_security;
- struct sk_security_struct *osec = other->sk->sk_security;
+ struct sk_security_struct *ssec = selinux_sock(sock->sk);
+ struct sk_security_struct *osec = selinux_sock(other->sk);
struct common_audit_data ad;
struct lsm_network_audit net;
@@ -5069,7 +5095,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
u16 family)
{
int err = 0;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
u32 sk_sid = sksec->sid;
struct common_audit_data ad;
struct lsm_network_audit net;
@@ -5098,7 +5124,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
int err, peerlbl_active, secmark_active;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
u16 family = sk->sk_family;
u32 sk_sid = sksec->sid;
struct common_audit_data ad;
@@ -5166,7 +5192,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock,
int err = 0;
char *scontext = NULL;
u32 scontext_len;
- struct sk_security_struct *sksec = sock->sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sock->sk);
u32 peer_sid = SECSID_NULL;
if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
@@ -5194,11 +5220,11 @@ out_len:
return err;
}
-static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
+static int selinux_socket_getpeersec_dgram(struct socket *sock,
+ struct sk_buff *skb, u32 *secid)
{
u32 peer_secid = SECSID_NULL;
u16 family;
- struct inode_security_struct *isec;
if (skb && skb->protocol == htons(ETH_P_IP))
family = PF_INET;
@@ -5206,52 +5232,47 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
family = PF_INET6;
else if (sock)
family = sock->sk->sk_family;
- else
- goto out;
+ else {
+ *secid = SECSID_NULL;
+ return -EINVAL;
+ }
if (sock && family == PF_UNIX) {
+ struct inode_security_struct *isec;
isec = inode_security_novalidate(SOCK_INODE(sock));
peer_secid = isec->sid;
} else if (skb)
selinux_skb_peerlbl_sid(skb, family, &peer_secid);
-out:
*secid = peer_secid;
if (peer_secid == SECSID_NULL)
- return -EINVAL;
+ return -ENOPROTOOPT;
return 0;
}
static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
{
- struct sk_security_struct *sksec;
-
- sksec = kzalloc(sizeof(*sksec), priority);
- if (!sksec)
- return -ENOMEM;
+ struct sk_security_struct *sksec = selinux_sock(sk);
sksec->peer_sid = SECINITSID_UNLABELED;
sksec->sid = SECINITSID_UNLABELED;
sksec->sclass = SECCLASS_SOCKET;
selinux_netlbl_sk_security_reset(sksec);
- sk->sk_security = sksec;
return 0;
}
static void selinux_sk_free_security(struct sock *sk)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
- sk->sk_security = NULL;
selinux_netlbl_sk_security_free(sksec);
- kfree(sksec);
}
static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
{
- struct sk_security_struct *sksec = sk->sk_security;
- struct sk_security_struct *newsksec = newsk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
+ struct sk_security_struct *newsksec = selinux_sock(newsk);
newsksec->sid = sksec->sid;
newsksec->peer_sid = sksec->peer_sid;
@@ -5265,7 +5286,7 @@ static void selinux_sk_getsecid(const struct sock *sk, u32 *secid)
if (!sk)
*secid = SECINITSID_ANY_SOCKET;
else {
- const struct sk_security_struct *sksec = sk->sk_security;
+ const struct sk_security_struct *sksec = selinux_sock(sk);
*secid = sksec->sid;
}
@@ -5275,7 +5296,7 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
{
struct inode_security_struct *isec =
inode_security_novalidate(SOCK_INODE(parent));
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
sk->sk_family == PF_UNIX)
@@ -5292,7 +5313,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
{
struct sock *sk = asoc->base.sk;
u16 family = sk->sk_family;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct common_audit_data ad;
struct lsm_network_audit net;
int err;
@@ -5347,7 +5368,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
static int selinux_sctp_assoc_request(struct sctp_association *asoc,
struct sk_buff *skb)
{
- struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
u32 conn_sid;
int err;
@@ -5380,7 +5401,7 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
static int selinux_sctp_assoc_established(struct sctp_association *asoc,
struct sk_buff *skb)
{
- struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
if (!selinux_policycap_extsockclass())
return 0;
@@ -5479,8 +5500,8 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
static void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk,
struct sock *newsk)
{
- struct sk_security_struct *sksec = sk->sk_security;
- struct sk_security_struct *newsksec = newsk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
+ struct sk_security_struct *newsksec = selinux_sock(newsk);
/* If policy does not support SECCLASS_SCTP_SOCKET then call
* the non-sctp clone version.
@@ -5496,8 +5517,8 @@ static void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk
static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
{
- struct sk_security_struct *ssksec = ssk->sk_security;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *ssksec = selinux_sock(ssk);
+ struct sk_security_struct *sksec = selinux_sock(sk);
ssksec->sclass = sksec->sclass;
ssksec->sid = sksec->sid;
@@ -5512,7 +5533,7 @@ static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
struct request_sock *req)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
int err;
u16 family = req->rsk_ops->family;
u32 connsid;
@@ -5533,7 +5554,7 @@ static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
static void selinux_inet_csk_clone(struct sock *newsk,
const struct request_sock *req)
{
- struct sk_security_struct *newsksec = newsk->sk_security;
+ struct sk_security_struct *newsksec = selinux_sock(newsk);
newsksec->sid = req->secid;
newsksec->peer_sid = req->peer_secid;
@@ -5550,7 +5571,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
{
u16 family = sk->sk_family;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
/* handle mapped IPv4 packets arriving via IPv6 sockets */
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
@@ -5561,13 +5582,7 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
static int selinux_secmark_relabel_packet(u32 sid)
{
- const struct task_security_struct *tsec;
- u32 tsid;
-
- tsec = selinux_cred(current_cred());
- tsid = tsec->sid;
-
- return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
+ return avc_has_perm(current_sid(), sid, SECCLASS_PACKET, PACKET__RELABELTO,
NULL);
}
@@ -5587,24 +5602,14 @@ static void selinux_req_classify_flow(const struct request_sock *req,
flic->flowic_secid = req->secid;
}
-static int selinux_tun_dev_alloc_security(void **security)
+static int selinux_tun_dev_alloc_security(void *security)
{
- struct tun_security_struct *tunsec;
+ struct tun_security_struct *tunsec = selinux_tun_dev(security);
- tunsec = kzalloc(sizeof(*tunsec), GFP_KERNEL);
- if (!tunsec)
- return -ENOMEM;
tunsec->sid = current_sid();
-
- *security = tunsec;
return 0;
}
-static void selinux_tun_dev_free_security(void *security)
-{
- kfree(security);
-}
-
static int selinux_tun_dev_create(void)
{
u32 sid = current_sid();
@@ -5622,7 +5627,7 @@ static int selinux_tun_dev_create(void)
static int selinux_tun_dev_attach_queue(void *security)
{
- struct tun_security_struct *tunsec = security;
+ struct tun_security_struct *tunsec = selinux_tun_dev(security);
return avc_has_perm(current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__ATTACH_QUEUE, NULL);
@@ -5630,8 +5635,8 @@ static int selinux_tun_dev_attach_queue(void *security)
static int selinux_tun_dev_attach(struct sock *sk, void *security)
{
- struct tun_security_struct *tunsec = security;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct tun_security_struct *tunsec = selinux_tun_dev(security);
+ struct sk_security_struct *sksec = selinux_sock(sk);
/* we don't currently perform any NetLabel based labeling here and it
* isn't clear that we would want to do so anyway; while we could apply
@@ -5648,7 +5653,7 @@ static int selinux_tun_dev_attach(struct sock *sk, void *security)
static int selinux_tun_dev_open(void *security)
{
- struct tun_security_struct *tunsec = security;
+ struct tun_security_struct *tunsec = selinux_tun_dev(security);
u32 sid = current_sid();
int err;
@@ -5734,7 +5739,7 @@ static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb,
/* we do this in the LOCAL_OUT path and not the POST_ROUTING path
* because we want to make sure we apply the necessary labeling
* before IPsec is applied so we can leverage AH protection */
- sk = skb->sk;
+ sk = sk_to_full_sk(skb->sk);
if (sk) {
struct sk_security_struct *sksec;
@@ -5754,7 +5759,7 @@ static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb,
return NF_ACCEPT;
/* standard practice, label using the parent socket */
- sksec = sk->sk_security;
+ sksec = selinux_sock(sk);
sid = sksec->sid;
} else
sid = SECINITSID_KERNEL;
@@ -5777,7 +5782,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
sk = skb_to_full_sk(skb);
if (sk == NULL)
return NF_ACCEPT;
- sksec = sk->sk_security;
+ sksec = selinux_sock(sk);
ad_net_init_from_iif(&ad, &net, state->out->ifindex, state->pf);
if (selinux_parse_skb(skb, &ad, NULL, 0, &proto))
@@ -5866,7 +5871,7 @@ static unsigned int selinux_ip_postroute(void *priv,
u32 skb_sid;
struct sk_security_struct *sksec;
- sksec = sk->sk_security;
+ sksec = selinux_sock(sk);
if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
return NF_DROP;
/* At this point, if the returned skb peerlbl is SECSID_NULL
@@ -5895,7 +5900,7 @@ static unsigned int selinux_ip_postroute(void *priv,
} else {
/* Locally generated packet, fetch the security label from the
* associated socket. */
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
peer_sid = sksec->sid;
secmark_perm = PACKET__SEND;
}
@@ -5931,6 +5936,26 @@ static unsigned int selinux_ip_postroute(void *priv,
}
#endif /* CONFIG_NETFILTER */
+static int nlmsg_sock_has_extended_perms(struct sock *sk, u32 perms, u16 nlmsg_type)
+{
+ struct sk_security_struct *sksec = sk->sk_security;
+ struct common_audit_data ad;
+ u8 driver;
+ u8 xperm;
+
+ if (sock_skip_has_perm(sksec->sid))
+ return 0;
+
+ ad.type = LSM_AUDIT_DATA_NLMSGTYPE;
+ ad.u.nlmsg_type = nlmsg_type;
+
+ driver = nlmsg_type >> 8;
+ xperm = nlmsg_type & 0xff;
+
+ return avc_has_extended_perms(current_sid(), sksec->sid, sksec->sclass,
+ perms, driver, AVC_EXT_NLMSG, xperm, &ad);
+}
+
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
{
int rc = 0;
@@ -5938,7 +5963,7 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
unsigned int data_len = skb->len;
unsigned char *data = skb->data;
struct nlmsghdr *nlh;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
u16 sclass = sksec->sclass;
u32 perm;
@@ -5956,7 +5981,12 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
rc = selinux_nlmsg_lookup(sclass, nlh->nlmsg_type, &perm);
if (rc == 0) {
- rc = sock_has_perm(sk, perm);
+ if (selinux_policycap_netlink_xperm()) {
+ rc = nlmsg_sock_has_extended_perms(
+ sk, perm, nlh->nlmsg_type);
+ } else {
+ rc = sock_has_perm(sk, perm);
+ }
if (rc)
return rc;
} else if (rc == -EINVAL) {
@@ -6330,10 +6360,11 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
return ipc_has_perm(ipcp, av);
}
-static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+static void selinux_ipc_getlsmprop(struct kern_ipc_perm *ipcp,
+ struct lsm_prop *prop)
{
struct ipc_security_struct *isec = selinux_ipc(ipcp);
- *secid = isec->sid;
+ prop->selinux.secid = isec->sid;
}
static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
@@ -6345,55 +6376,55 @@ static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
char **value)
{
- const struct task_security_struct *__tsec;
- u32 sid;
+ const struct task_security_struct *tsec;
int error;
- unsigned len;
+ u32 sid;
+ u32 len;
rcu_read_lock();
- __tsec = selinux_cred(__task_cred(p));
-
- if (current != p) {
- error = avc_has_perm(current_sid(), __tsec->sid,
+ tsec = selinux_cred(__task_cred(p));
+ if (p != current) {
+ error = avc_has_perm(current_sid(), tsec->sid,
SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
if (error)
- goto bad;
+ goto err_unlock;
}
-
switch (attr) {
case LSM_ATTR_CURRENT:
- sid = __tsec->sid;
+ sid = tsec->sid;
break;
case LSM_ATTR_PREV:
- sid = __tsec->osid;
+ sid = tsec->osid;
break;
case LSM_ATTR_EXEC:
- sid = __tsec->exec_sid;
+ sid = tsec->exec_sid;
break;
case LSM_ATTR_FSCREATE:
- sid = __tsec->create_sid;
+ sid = tsec->create_sid;
break;
case LSM_ATTR_KEYCREATE:
- sid = __tsec->keycreate_sid;
+ sid = tsec->keycreate_sid;
break;
case LSM_ATTR_SOCKCREATE:
- sid = __tsec->sockcreate_sid;
+ sid = tsec->sockcreate_sid;
break;
default:
error = -EOPNOTSUPP;
- goto bad;
+ goto err_unlock;
}
rcu_read_unlock();
- if (!sid)
+ if (sid == SECSID_NULL) {
+ *value = NULL;
return 0;
+ }
error = security_sid_to_context(sid, value, &len);
if (error)
return error;
return len;
-bad:
+err_unlock:
rcu_read_unlock();
return error;
}
@@ -6556,7 +6587,7 @@ abort_change:
* There will only ever be one attribute.
*/
static int selinux_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
- size_t *size, u32 flags)
+ u32 *size, u32 flags)
{
int rc;
char *val = NULL;
@@ -6571,7 +6602,7 @@ static int selinux_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx,
}
static int selinux_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
- size_t size, u32 flags)
+ u32 size, u32 flags)
{
int rc;
@@ -6610,10 +6641,28 @@ static int selinux_ismaclabel(const char *name)
return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
}
-static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+static int selinux_secid_to_secctx(u32 secid, struct lsm_context *cp)
{
- return security_sid_to_context(secid,
- secdata, seclen);
+ u32 seclen;
+ int ret;
+
+ if (cp) {
+ cp->id = LSM_ID_SELINUX;
+ ret = security_sid_to_context(secid, &cp->context, &cp->len);
+ if (ret < 0)
+ return ret;
+ return cp->len;
+ }
+ ret = security_sid_to_context(secid, NULL, &seclen);
+ if (ret < 0)
+ return ret;
+ return seclen;
+}
+
+static int selinux_lsmprop_to_secctx(struct lsm_prop *prop,
+ struct lsm_context *cp)
+{
+ return selinux_secid_to_secctx(prop->selinux.secid, cp);
}
static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
@@ -6622,9 +6671,13 @@ static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
secid, GFP_KERNEL);
}
-static void selinux_release_secctx(char *secdata, u32 seclen)
+static void selinux_release_secctx(struct lsm_context *cp)
{
- kfree(secdata);
+ if (cp->id == LSM_ID_SELINUX) {
+ kfree(cp->context);
+ cp->context = NULL;
+ cp->id = LSM_ID_UNDEF;
+ }
}
static void selinux_inode_invalidate_secctx(struct inode *inode)
@@ -6652,18 +6705,20 @@ static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen
*/
static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
{
- return __vfs_setxattr_noperm(&nop_mnt_idmap, dentry, XATTR_NAME_SELINUX,
- ctx, ctxlen, 0);
+ return __vfs_setxattr_locked(&nop_mnt_idmap, dentry, XATTR_NAME_SELINUX,
+ ctx, ctxlen, 0, NULL);
}
-static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+static int selinux_inode_getsecctx(struct inode *inode, struct lsm_context *cp)
{
- int len = 0;
+ int len;
len = selinux_inode_getsecurity(&nop_mnt_idmap, inode,
- XATTR_SELINUX_SUFFIX, ctx, true);
+ XATTR_SELINUX_SUFFIX,
+ (void **)&cp->context, true);
if (len < 0)
return len;
- *ctxlen = len;
+ cp->len = len;
+ cp->id = LSM_ID_SELINUX;
return 0;
}
#ifdef CONFIG_KEYS
@@ -6672,11 +6727,7 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred,
unsigned long flags)
{
const struct task_security_struct *tsec;
- struct key_security_struct *ksec;
-
- ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
- if (!ksec)
- return -ENOMEM;
+ struct key_security_struct *ksec = selinux_key(k);
tsec = selinux_cred(cred);
if (tsec->keycreate_sid)
@@ -6684,18 +6735,9 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred,
else
ksec->sid = tsec->sid;
- k->security = ksec;
return 0;
}
-static void selinux_key_free(struct key *k)
-{
- struct key_security_struct *ksec = k->security;
-
- k->security = NULL;
- kfree(ksec);
-}
-
static int selinux_key_permission(key_ref_t key_ref,
const struct cred *cred,
enum key_need_perm need_perm)
@@ -6736,14 +6778,14 @@ static int selinux_key_permission(key_ref_t key_ref,
sid = cred_sid(cred);
key = key_ref_to_ptr(key_ref);
- ksec = key->security;
+ ksec = selinux_key(key);
return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
}
static int selinux_key_getsecurity(struct key *key, char **_buffer)
{
- struct key_security_struct *ksec = key->security;
+ struct key_security_struct *ksec = selinux_key(key);
char *context = NULL;
unsigned len;
int rc;
@@ -6759,7 +6801,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
#ifdef CONFIG_KEY_NOTIFICATIONS
static int selinux_watch_key(struct key *key)
{
- struct key_security_struct *ksec = key->security;
+ struct key_security_struct *ksec = selinux_key(key);
u32 sid = current_sid();
return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, KEY__VIEW, NULL);
@@ -6813,23 +6855,13 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
}
-static int selinux_ib_alloc_security(void **ib_sec)
+static int selinux_ib_alloc_security(void *ib_sec)
{
- struct ib_security_struct *sec;
+ struct ib_security_struct *sec = selinux_ib(ib_sec);
- sec = kzalloc(sizeof(*sec), GFP_KERNEL);
- if (!sec)
- return -ENOMEM;
sec->sid = current_sid();
-
- *ib_sec = sec;
return 0;
}
-
-static void selinux_ib_free_security(void *ib_sec)
-{
- kfree(ib_sec);
-}
#endif
#ifdef CONFIG_BPF_SYSCALL
@@ -6920,7 +6952,8 @@ static int selinux_bpf_prog(struct bpf_prog *prog)
BPF__PROG_RUN, NULL);
}
-static int selinux_bpf_map_alloc(struct bpf_map *map)
+static int selinux_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
+ struct bpf_token *token)
{
struct bpf_security_struct *bpfsec;
@@ -6942,7 +6975,31 @@ static void selinux_bpf_map_free(struct bpf_map *map)
kfree(bpfsec);
}
-static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
+static int selinux_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
+ struct bpf_token *token)
+{
+ struct bpf_security_struct *bpfsec;
+
+ bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
+ if (!bpfsec)
+ return -ENOMEM;
+
+ bpfsec->sid = current_sid();
+ prog->aux->security = bpfsec;
+
+ return 0;
+}
+
+static void selinux_bpf_prog_free(struct bpf_prog *prog)
+{
+ struct bpf_security_struct *bpfsec = prog->aux->security;
+
+ prog->aux->security = NULL;
+ kfree(bpfsec);
+}
+
+static int selinux_bpf_token_create(struct bpf_token *token, union bpf_attr *attr,
+ const struct path *path)
{
struct bpf_security_struct *bpfsec;
@@ -6951,16 +7008,16 @@ static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
return -ENOMEM;
bpfsec->sid = current_sid();
- aux->security = bpfsec;
+ token->security = bpfsec;
return 0;
}
-static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
+static void selinux_bpf_token_free(struct bpf_token *token)
{
- struct bpf_security_struct *bpfsec = aux->security;
+ struct bpf_security_struct *bpfsec = token->security;
- aux->security = NULL;
+ token->security = NULL;
kfree(bpfsec);
}
#endif
@@ -6970,9 +7027,16 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
.lbs_file = sizeof(struct file_security_struct),
.lbs_inode = sizeof(struct inode_security_struct),
.lbs_ipc = sizeof(struct ipc_security_struct),
+ .lbs_key = sizeof(struct key_security_struct),
.lbs_msg_msg = sizeof(struct msg_security_struct),
+#ifdef CONFIG_PERF_EVENTS
+ .lbs_perf_event = sizeof(struct perf_event_security_struct),
+#endif
+ .lbs_sock = sizeof(struct sk_security_struct),
.lbs_superblock = sizeof(struct superblock_security_struct),
.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
+ .lbs_tun_dev = sizeof(struct tun_security_struct),
+ .lbs_ib = sizeof(struct ib_security_struct),
};
#ifdef CONFIG_PERF_EVENTS
@@ -6999,24 +7063,12 @@ static int selinux_perf_event_alloc(struct perf_event *event)
{
struct perf_event_security_struct *perfsec;
- perfsec = kzalloc(sizeof(*perfsec), GFP_KERNEL);
- if (!perfsec)
- return -ENOMEM;
-
+ perfsec = selinux_perf_event(event->security);
perfsec->sid = current_sid();
- event->security = perfsec;
return 0;
}
-static void selinux_perf_event_free(struct perf_event *event)
-{
- struct perf_event_security_struct *perfsec = event->security;
-
- event->security = NULL;
- kfree(perfsec);
-}
-
static int selinux_perf_event_read(struct perf_event *event)
{
struct perf_event_security_struct *perfsec = event->security;
@@ -7157,6 +7209,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(inode_permission, selinux_inode_permission),
LSM_HOOK_INIT(inode_setattr, selinux_inode_setattr),
LSM_HOOK_INIT(inode_getattr, selinux_inode_getattr),
+ LSM_HOOK_INIT(inode_xattr_skipcap, selinux_inode_xattr_skipcap),
LSM_HOOK_INIT(inode_setxattr, selinux_inode_setxattr),
LSM_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr),
LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
@@ -7168,7 +7221,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
- LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
+ LSM_HOOK_INIT(inode_getlsmprop, selinux_inode_getlsmprop),
LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
LSM_HOOK_INIT(path_notify, selinux_path_notify),
@@ -7194,6 +7247,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
+ LSM_HOOK_INIT(cred_getlsmprop, selinux_cred_getlsmprop),
LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
@@ -7202,8 +7256,8 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
- LSM_HOOK_INIT(current_getsecid_subj, selinux_current_getsecid_subj),
- LSM_HOOK_INIT(task_getsecid_obj, selinux_task_getsecid_obj),
+ LSM_HOOK_INIT(current_getlsmprop_subj, selinux_current_getlsmprop_subj),
+ LSM_HOOK_INIT(task_getlsmprop_obj, selinux_task_getlsmprop_obj),
LSM_HOOK_INIT(task_setnice, selinux_task_setnice),
LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio),
LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio),
@@ -7217,7 +7271,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(userns_create, selinux_userns_create),
LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission),
- LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
+ LSM_HOOK_INIT(ipc_getlsmprop, selinux_ipc_getlsmprop),
LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
@@ -7283,7 +7337,6 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(secmark_refcount_inc, selinux_secmark_refcount_inc),
LSM_HOOK_INIT(secmark_refcount_dec, selinux_secmark_refcount_dec),
LSM_HOOK_INIT(req_classify_flow, selinux_req_classify_flow),
- LSM_HOOK_INIT(tun_dev_free_security, selinux_tun_dev_free_security),
LSM_HOOK_INIT(tun_dev_create, selinux_tun_dev_create),
LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue),
LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach),
@@ -7292,7 +7345,6 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access),
LSM_HOOK_INIT(ib_endport_manage_subnet,
selinux_ib_endport_manage_subnet),
- LSM_HOOK_INIT(ib_free_security, selinux_ib_free_security),
#endif
#ifdef CONFIG_SECURITY_NETWORK_XFRM
LSM_HOOK_INIT(xfrm_policy_free_security, selinux_xfrm_policy_free),
@@ -7306,7 +7358,6 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
#endif
#ifdef CONFIG_KEYS
- LSM_HOOK_INIT(key_free, selinux_key_free),
LSM_HOOK_INIT(key_permission, selinux_key_permission),
LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity),
#ifdef CONFIG_KEY_NOTIFICATIONS
@@ -7324,13 +7375,13 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(bpf, selinux_bpf),
LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
- LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
- LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
+ LSM_HOOK_INIT(bpf_map_free, selinux_bpf_map_free),
+ LSM_HOOK_INIT(bpf_prog_free, selinux_bpf_prog_free),
+ LSM_HOOK_INIT(bpf_token_free, selinux_bpf_token_free),
#endif
#ifdef CONFIG_PERF_EVENTS
LSM_HOOK_INIT(perf_event_open, selinux_perf_event_open),
- LSM_HOOK_INIT(perf_event_free, selinux_perf_event_free),
LSM_HOOK_INIT(perf_event_read, selinux_perf_event_read),
LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write),
#endif
@@ -7363,6 +7414,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security),
LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
+ LSM_HOOK_INIT(lsmprop_to_secctx, selinux_lsmprop_to_secctx),
LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security),
@@ -7382,8 +7434,9 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init),
#endif
#ifdef CONFIG_BPF_SYSCALL
- LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
- LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
+ LSM_HOOK_INIT(bpf_map_create, selinux_bpf_map_create),
+ LSM_HOOK_INIT(bpf_prog_load, selinux_bpf_prog_load),
+ LSM_HOOK_INIT(bpf_token_create, selinux_bpf_token_create),
#endif
#ifdef CONFIG_PERF_EVENTS
LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc),
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index 52aca71210b4..d5b0425055e4 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -16,43 +16,46 @@
#include <linux/types.h>
/**
- * selinux_audit_rule_init - alloc/init an selinux audit rule structure.
- * @field: the field this rule refers to
- * @op: the operator the rule uses
- * @rulestr: the text "target" of the rule
- * @rule: pointer to the new rule structure returned via this
+ * selinux_audit_rule_init - alloc/init an selinux audit rule structure.
+ * @field: the field this rule refers to
+ * @op: the operator the rule uses
+ * @rulestr: the text "target" of the rule
+ * @rule: pointer to the new rule structure returned via this
+ * @gfp: GFP flag used for kmalloc
*
- * Returns 0 if successful, -errno if not. On success, the rule structure
- * will be allocated internally. The caller must free this structure with
- * selinux_audit_rule_free() after use.
+ * Returns 0 if successful, -errno if not. On success, the rule structure
+ * will be allocated internally. The caller must free this structure with
+ * selinux_audit_rule_free() after use.
*/
-int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule);
+int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **rule,
+ gfp_t gfp);
/**
- * selinux_audit_rule_free - free an selinux audit rule structure.
- * @rule: pointer to the audit rule to be freed
+ * selinux_audit_rule_free - free an selinux audit rule structure.
+ * @rule: pointer to the audit rule to be freed
*
- * This will free all memory associated with the given rule.
- * If @rule is NULL, no operation is performed.
+ * This will free all memory associated with the given rule.
+ * If @rule is NULL, no operation is performed.
*/
void selinux_audit_rule_free(void *rule);
/**
- * selinux_audit_rule_match - determine if a context ID matches a rule.
- * @sid: the context ID to check
- * @field: the field this rule refers to
- * @op: the operator the rule uses
- * @rule: pointer to the audit rule to check against
+ * selinux_audit_rule_match - determine if a context ID matches a rule.
+ * @prop: includes the context ID to check
+ * @field: the field this rule refers to
+ * @op: the operator the rule uses
+ * @rule: pointer to the audit rule to check against
*
- * Returns 1 if the context id matches the rule, 0 if it does not, and
- * -errno on failure.
+ * Returns 1 if the context id matches the rule, 0 if it does not, and
+ * -errno on failure.
*/
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
+int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op,
+ void *rule);
/**
- * selinux_audit_rule_known - check to see if rule contains selinux fields.
- * @rule: rule to be checked
- * Returns 1 if there are selinux fields specified in the rule, 0 otherwise.
+ * selinux_audit_rule_known - check to see if rule contains selinux fields.
+ * @rule: rule to be checked
+ * Returns 1 if there are selinux fields specified in the rule, 0 otherwise.
*/
int selinux_audit_rule_known(struct audit_krule *rule);
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 96a614d47df8..281f40103663 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -136,8 +136,11 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct common_audit_data *auditdata);
+#define AVC_EXT_IOCTL (1 << 0) /* Cache entry for an ioctl extended permission */
+#define AVC_EXT_NLMSG (1 << 1) /* Cache entry for an nlmsg extended permission */
int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
- u8 driver, u8 perm, struct common_audit_data *ad);
+ u8 driver, u8 base_perm, u8 perm,
+ struct common_audit_data *ad);
u32 avc_policy_seqno(void);
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 7229c9bf6c27..03e82477dce9 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -1,8 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
-#include <linux/capability.h>
-#include <linux/socket.h>
-
#define COMMON_FILE_SOCK_PERMS \
"ioctl", "read", "write", "create", "getattr", "setattr", "lock", \
"relabelfrom", "relabelto", "append", "map"
@@ -36,9 +33,13 @@
"mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend", \
"audit_read", "perfmon", "bpf", "checkpoint_restore"
+#ifdef __KERNEL__ /* avoid this check when building host programs */
+#include <linux/capability.h>
+
#if CAP_LAST_CAP > CAP_CHECKPOINT_RESTORE
#error New capability defined, please update COMMON_CAP2_PERMS.
#endif
+#endif
/*
* Note: The name for any socket class should be suffixed by "socket",
@@ -96,17 +97,17 @@ const struct security_class_mapping secclass_map[] = {
{ "shm", { COMMON_IPC_PERMS, "lock", NULL } },
{ "ipc", { COMMON_IPC_PERMS, NULL } },
{ "netlink_route_socket",
- { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", NULL } },
+ { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", "nlmsg", NULL } },
{ "netlink_tcpdiag_socket",
- { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", NULL } },
+ { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", "nlmsg", NULL } },
{ "netlink_nflog_socket", { COMMON_SOCK_PERMS, NULL } },
{ "netlink_xfrm_socket",
- { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", NULL } },
+ { COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", "nlmsg", NULL } },
{ "netlink_selinux_socket", { COMMON_SOCK_PERMS, NULL } },
{ "netlink_iscsi_socket", { COMMON_SOCK_PERMS, NULL } },
{ "netlink_audit_socket",
{ COMMON_SOCK_PERMS, "nlmsg_read", "nlmsg_write", "nlmsg_relay",
- "nlmsg_readpriv", "nlmsg_tty_audit", NULL } },
+ "nlmsg_readpriv", "nlmsg_tty_audit", "nlmsg", NULL } },
{ "netlink_fib_lookup_socket", { COMMON_SOCK_PERMS, NULL } },
{ "netlink_connector_socket", { COMMON_SOCK_PERMS, NULL } },
{ "netlink_netfilter_socket", { COMMON_SOCK_PERMS, NULL } },
@@ -178,9 +179,13 @@ const struct security_class_mapping secclass_map[] = {
{ "anon_inode", { COMMON_FILE_PERMS, NULL } },
{ "io_uring", { "override_creds", "sqpoll", "cmd", NULL } },
{ "user_namespace", { "create", NULL } },
- { NULL }
+ /* last one */ { NULL, {} }
};
+#ifdef __KERNEL__ /* avoid this check when building host programs */
+#include <linux/socket.h>
+
#if PF_MAX > 46
#error New address family defined, please update secclass_map.
#endif
+#endif
diff --git a/security/selinux/include/conditional.h b/security/selinux/include/conditional.h
index 5910bb7c2eca..060833e2dba2 100644
--- a/security/selinux/include/conditional.h
+++ b/security/selinux/include/conditional.h
@@ -16,7 +16,7 @@
int security_get_bools(struct selinux_policy *policy, u32 *len, char ***names,
int **values);
-int security_set_bools(u32 len, int *values);
+int security_set_bools(u32 len, const int *values);
int security_get_bool_value(u32 index);
diff --git a/security/selinux/include/initial_sid_to_string.h b/security/selinux/include/initial_sid_to_string.h
index 99b353b2abb4..d7ba60b62491 100644
--- a/security/selinux/include/initial_sid_to_string.h
+++ b/security/selinux/include/initial_sid_to_string.h
@@ -1,6 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
+#ifdef __KERNEL__
#include <linux/stddef.h>
+#else
+#include <stddef.h>
+#endif
static const char *const initial_sid_to_string[] = {
NULL, /* zero placeholder, not used */
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index dea1d6f3ed2d..c88cae81ee4c 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -195,4 +195,32 @@ selinux_superblock(const struct super_block *superblock)
return superblock->s_security + selinux_blob_sizes.lbs_superblock;
}
+#ifdef CONFIG_KEYS
+static inline struct key_security_struct *selinux_key(const struct key *key)
+{
+ return key->security + selinux_blob_sizes.lbs_key;
+}
+#endif /* CONFIG_KEYS */
+
+static inline struct sk_security_struct *selinux_sock(const struct sock *sock)
+{
+ return sock->sk_security + selinux_blob_sizes.lbs_sock;
+}
+
+static inline struct tun_security_struct *selinux_tun_dev(void *security)
+{
+ return security + selinux_blob_sizes.lbs_tun_dev;
+}
+
+static inline struct ib_security_struct *selinux_ib(void *ib_sec)
+{
+ return ib_sec + selinux_blob_sizes.lbs_ib;
+}
+
+static inline struct perf_event_security_struct *
+selinux_perf_event(void *perf_event)
+{
+ return perf_event + selinux_blob_sizes.lbs_perf_event;
+}
+
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/include/policycap.h b/security/selinux/include/policycap.h
index dc3674eb29c1..079679fe7254 100644
--- a/security/selinux/include/policycap.h
+++ b/security/selinux/include/policycap.h
@@ -14,6 +14,7 @@ enum {
POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS,
POLICYDB_CAP_IOCTL_SKIP_CLOEXEC,
POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT,
+ POLICYDB_CAP_NETLINK_XPERM,
__POLICYDB_CAP_MAX
};
#define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1)
diff --git a/security/selinux/include/policycap_names.h b/security/selinux/include/policycap_names.h
index 2cffcc1ce851..e080827408c4 100644
--- a/security/selinux/include/policycap_names.h
+++ b/security/selinux/include/policycap_names.h
@@ -17,6 +17,7 @@ const char *const selinux_policycap_names[__POLICYDB_CAP_MAX] = {
"genfs_seclabel_symlinks",
"ioctl_skip_cloexec",
"userspace_initial_context",
+ "netlink_xperm",
};
/* clang-format on */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 289bf9233f71..8b4c2aa35839 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -46,10 +46,11 @@
#define POLICYDB_VERSION_INFINIBAND 31
#define POLICYDB_VERSION_GLBLUB 32
#define POLICYDB_VERSION_COMP_FTRANS 33 /* compressed filename transitions */
+#define POLICYDB_VERSION_COND_XPERMS 34 /* extended permissions in conditional policies */
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX POLICYDB_VERSION_COMP_FTRANS
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_COND_XPERMS
/* Mask for just the mount related flags */
#define SE_MNTMASK 0x0f
@@ -195,6 +196,12 @@ static inline bool selinux_policycap_userspace_initial_context(void)
selinux_state.policycap[POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT]);
}
+static inline bool selinux_policycap_netlink_xperm(void)
+{
+ return READ_ONCE(
+ selinux_state.policycap[POLICYDB_CAP_NETLINK_XPERM]);
+}
+
struct selinux_policy_convert_data;
struct selinux_load_state {
@@ -233,6 +240,7 @@ struct extended_perms_data {
struct extended_perms_decision {
u8 used;
u8 driver;
+ u8 base_perm;
struct extended_perms_data *allowed;
struct extended_perms_data *auditallow;
struct extended_perms_data *dontaudit;
@@ -240,6 +248,7 @@ struct extended_perms_decision {
struct extended_perms {
u16 len; /* length associated decision chain */
+ u8 base_perms; /* which base permissions are covered */
struct extended_perms_data drivers; /* flag drivers that are used */
};
@@ -251,6 +260,7 @@ void security_compute_av(u32 ssid, u32 tsid, u16 tclass,
struct extended_perms *xperms);
void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, u8 driver,
+ u8 base_perm,
struct extended_perms_decision *xpermd);
void security_compute_av_user(u32 ssid, u32 tsid, u16 tclass,
@@ -283,7 +293,7 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len,
int security_context_to_sid_force(const char *scontext, u32 scontext_len,
u32 *sid);
-int security_get_user_sids(u32 callsid, char *username, u32 **sids, u32 *nel);
+int security_get_user_sids(u32 fromsid, const char *username, u32 **sids, u32 *nel);
int security_port_sid(u8 protocol, u16 port, u32 *out_sid);
@@ -301,7 +311,7 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass);
-int security_bounded_transition(u32 oldsid, u32 newsid);
+int security_bounded_transition(u32 old_sid, u32 new_sid);
int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 8f182800e412..d51dfe892312 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -17,6 +17,7 @@
#include <linux/gfp.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
+#include <linux/lsm_hooks.h>
#include <net/sock.h>
#include <net/netlabel.h>
#include <net/ip.h>
@@ -62,13 +63,13 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
* Description:
* Generate the NetLabel security attributes for a socket, making full use of
* the socket's attribute cache. Returns a pointer to the security attributes
- * on success, NULL on failure.
+ * on success, or an ERR_PTR on failure.
*
*/
static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
{
int rc;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct netlbl_lsm_secattr *secattr;
if (sksec->nlbl_secattr != NULL)
@@ -76,11 +77,12 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
secattr = netlbl_secattr_alloc(GFP_ATOMIC);
if (secattr == NULL)
- return NULL;
+ return ERR_PTR(-ENOMEM);
+
rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
if (rc != 0) {
netlbl_secattr_free(secattr);
- return NULL;
+ return ERR_PTR(rc);
}
sksec->nlbl_secattr = secattr;
@@ -100,7 +102,7 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
const struct sock *sk,
u32 sid)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
if (secattr == NULL)
@@ -240,7 +242,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
* being labeled by it's parent socket, if it is just exit */
sk = skb_to_full_sk(skb);
if (sk != NULL) {
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
if (sksec->nlbl_state != NLBL_REQSKB)
return 0;
@@ -277,7 +279,7 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
{
int rc;
struct netlbl_lsm_secattr secattr;
- struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
struct sockaddr_in addr4;
struct sockaddr_in6 addr6;
@@ -356,9 +358,9 @@ inet_conn_request_return:
*/
void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
- if (family == PF_INET)
+ if (family == PF_INET || family == PF_INET6)
sksec->nlbl_state = NLBL_LABELED;
else
sksec->nlbl_state = NLBL_UNSET;
@@ -374,8 +376,8 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
*/
void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
{
- struct sk_security_struct *sksec = sk->sk_security;
- struct sk_security_struct *newsksec = newsk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
+ struct sk_security_struct *newsksec = selinux_sock(newsk);
newsksec->nlbl_state = sksec->nlbl_state;
}
@@ -393,16 +395,19 @@ void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
{
int rc;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct netlbl_lsm_secattr *secattr;
if (family != PF_INET && family != PF_INET6)
return 0;
secattr = selinux_netlbl_sock_genattr(sk);
- if (secattr == NULL)
- return -ENOMEM;
- rc = netlbl_sock_setattr(sk, family, secattr);
+ if (IS_ERR(secattr))
+ return PTR_ERR(secattr);
+ /* On socket creation, replacement of IP options is safe even if
+ * the caller does not hold the socket lock.
+ */
+ rc = netlbl_sock_setattr(sk, family, secattr, true);
switch (rc) {
case 0:
sksec->nlbl_state = NLBL_LABELED;
@@ -507,7 +512,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
{
int rc = 0;
struct sock *sk = sock->sk;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct netlbl_lsm_secattr secattr;
if (selinux_netlbl_option(level, optname) &&
@@ -545,7 +550,7 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
struct sockaddr *addr)
{
int rc;
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
struct netlbl_lsm_secattr *secattr;
/* connected sockets are allowed to disconnect when the address family
@@ -558,10 +563,9 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
return rc;
}
secattr = selinux_netlbl_sock_genattr(sk);
- if (secattr == NULL) {
- rc = -ENOMEM;
- return rc;
- }
+ if (IS_ERR(secattr))
+ return PTR_ERR(secattr);
+
rc = netlbl_conn_setattr(sk, addr, secattr);
if (rc == 0)
sksec->nlbl_state = NLBL_CONNLABELED;
@@ -584,7 +588,7 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
int selinux_netlbl_socket_connect_locked(struct sock *sk,
struct sockaddr *addr)
{
- struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *sksec = selinux_sock(sk);
if (sksec->nlbl_state != NLBL_REQSKB &&
sksec->nlbl_state != NLBL_CONNLABELED)
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 8ff670cf1ee5..3a95986b134f 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -21,142 +21,142 @@
#include "security.h"
struct nlmsg_perm {
- u16 nlmsg_type;
- u32 perm;
+ u16 nlmsg_type;
+ u32 perm;
};
static const struct nlmsg_perm nlmsg_route_perms[] = {
- { RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETLINK, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_SETLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_NEWADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETADDR, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETROUTE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETRULE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETQDISC, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETACTION, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_GETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_SETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_NEWADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_GETDCB, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_NEWNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETMDB, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWNSID, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_GETNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_GETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_SETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_NEWCACHEREPORT, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_NEWVLAN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELVLAN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETVLAN, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETLINK, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_SETLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_NEWADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETADDR, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETROUTE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETRULE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETQDISC, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETACTION, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_GETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_SETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_NEWADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETADDRLABEL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_GETDCB, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_NEWNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETNETCONF, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETMDB, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWNSID, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_GETNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_GETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_SETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_NEWCACHEREPORT, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETNEXTHOP, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELLINKPROP, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_NEWVLAN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELVLAN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETVLAN, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
};
static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = {
- { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
- { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
- { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
- { SOCK_DESTROY, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE },
+ { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
+ { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
+ { SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
+ { SOCK_DESTROY, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE },
};
static const struct nlmsg_perm nlmsg_xfrm_perms[] = {
- { XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_GETSA, NETLINK_XFRM_SOCKET__NLMSG_READ },
- { XFRM_MSG_NEWPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_DELPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_GETPOLICY, NETLINK_XFRM_SOCKET__NLMSG_READ },
- { XFRM_MSG_ALLOCSPI, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_ACQUIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_EXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_UPDPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_UPDSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_POLEXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_FLUSHSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ },
- { XFRM_MSG_REPORT, NETLINK_XFRM_SOCKET__NLMSG_READ },
- { XFRM_MSG_MIGRATE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_NEWSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ },
- { XFRM_MSG_GETSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ },
- { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_GETSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_READ },
- { XFRM_MSG_MAPPING, NETLINK_XFRM_SOCKET__NLMSG_READ },
- { XFRM_MSG_SETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_GETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_GETSA, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_NEWPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_DELPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_GETPOLICY, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_ALLOCSPI, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_ACQUIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_EXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_UPDPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_UPDSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_POLEXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_FLUSHSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_REPORT, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_MIGRATE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_NEWSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_GETSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_GETSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_MAPPING, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_SETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_GETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_READ },
};
static const struct nlmsg_perm nlmsg_audit_perms[] = {
- { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
- { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
- { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_LIST_RULES, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
- { AUDIT_ADD_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY },
- { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ },
- { AUDIT_TRIM, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_MAKE_EQUIV, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
- { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT },
- { AUDIT_GET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_READ },
- { AUDIT_SET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
+ { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+ { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_LIST_RULES, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+ { AUDIT_ADD_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY },
+ { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ },
+ { AUDIT_TRIM, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_MAKE_EQUIV, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
+ { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT },
+ { AUDIT_GET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_READ },
+ { AUDIT_SET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
};
-
-static int nlmsg_perm(u16 nlmsg_type, u32 *perm, const struct nlmsg_perm *tab, size_t tabsize)
+static int nlmsg_perm(u16 nlmsg_type, u32 *perm, const struct nlmsg_perm *tab,
+ size_t tabsize)
{
unsigned int i;
int err = -EINVAL;
- for (i = 0; i < tabsize/sizeof(struct nlmsg_perm); i++)
+ for (i = 0; i < tabsize / sizeof(struct nlmsg_perm); i++)
if (nlmsg_type == tab[i].nlmsg_type) {
*perm = tab[i].perm;
err = 0;
@@ -168,7 +168,12 @@ static int nlmsg_perm(u16 nlmsg_type, u32 *perm, const struct nlmsg_perm *tab, s
int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
{
- int err = 0;
+ /* While it is possible to add a similar permission to other netlink
+ * classes, note that the extended permission value is matched against
+ * the nlmsg_type field. Notably, SECCLASS_NETLINK_GENERIC_SOCKET uses
+ * dynamic values for this field, which means that it cannot be added
+ * as-is.
+ */
switch (sclass) {
case SECCLASS_NETLINK_ROUTE_SOCKET:
@@ -178,42 +183,52 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
* before updating the BUILD_BUG_ON() macro!
*/
BUILD_BUG_ON(RTM_MAX != (RTM_NEWTUNNEL + 3));
- err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
- sizeof(nlmsg_route_perms));
- break;
+ if (selinux_policycap_netlink_xperm()) {
+ *perm = NETLINK_ROUTE_SOCKET__NLMSG;
+ return 0;
+ }
+ return nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
+ sizeof(nlmsg_route_perms));
+ break;
case SECCLASS_NETLINK_TCPDIAG_SOCKET:
- err = nlmsg_perm(nlmsg_type, perm, nlmsg_tcpdiag_perms,
- sizeof(nlmsg_tcpdiag_perms));
+ if (selinux_policycap_netlink_xperm()) {
+ *perm = NETLINK_TCPDIAG_SOCKET__NLMSG;
+ return 0;
+ }
+ return nlmsg_perm(nlmsg_type, perm, nlmsg_tcpdiag_perms,
+ sizeof(nlmsg_tcpdiag_perms));
break;
-
case SECCLASS_NETLINK_XFRM_SOCKET:
/* If the BUILD_BUG_ON() below fails you must update the
* structures at the top of this file with the new mappings
* before updating the BUILD_BUG_ON() macro!
*/
BUILD_BUG_ON(XFRM_MSG_MAX != XFRM_MSG_GETDEFAULT);
- err = nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms,
- sizeof(nlmsg_xfrm_perms));
- break;
+ if (selinux_policycap_netlink_xperm()) {
+ *perm = NETLINK_XFRM_SOCKET__NLMSG;
+ return 0;
+ }
+ return nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms,
+ sizeof(nlmsg_xfrm_perms));
+ break;
case SECCLASS_NETLINK_AUDIT_SOCKET:
- if ((nlmsg_type >= AUDIT_FIRST_USER_MSG &&
- nlmsg_type <= AUDIT_LAST_USER_MSG) ||
- (nlmsg_type >= AUDIT_FIRST_USER_MSG2 &&
- nlmsg_type <= AUDIT_LAST_USER_MSG2)) {
+ if (selinux_policycap_netlink_xperm()) {
+ *perm = NETLINK_AUDIT_SOCKET__NLMSG;
+ return 0;
+ } else if ((nlmsg_type >= AUDIT_FIRST_USER_MSG &&
+ nlmsg_type <= AUDIT_LAST_USER_MSG) ||
+ (nlmsg_type >= AUDIT_FIRST_USER_MSG2 &&
+ nlmsg_type <= AUDIT_LAST_USER_MSG2)) {
*perm = NETLINK_AUDIT_SOCKET__NLMSG_RELAY;
- } else {
- err = nlmsg_perm(nlmsg_type, perm, nlmsg_audit_perms,
- sizeof(nlmsg_audit_perms));
+ return 0;
}
- break;
-
- /* No messaging from userspace, or class unknown/unhandled */
- default:
- err = -ENOENT;
+ return nlmsg_perm(nlmsg_type, perm, nlmsg_audit_perms,
+ sizeof(nlmsg_audit_perms));
break;
}
- return err;
+ /* No messaging from userspace, or class unknown/unhandled */
+ return -ENOENT;
}
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 0619a1cbbfbe..47480eb2189b 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -571,11 +571,18 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+ struct selinux_fs_info *fsi;
struct selinux_load_state load_state;
ssize_t length;
void *data = NULL;
+ /* no partial writes */
+ if (*ppos)
+ return -EINVAL;
+ /* no empty policies */
+ if (!count)
+ return -EINVAL;
+
mutex_lock(&selinux_state.policy_mutex);
length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
@@ -583,26 +590,22 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
if (length)
goto out;
- /* No partial writes. */
- length = -EINVAL;
- if (*ppos != 0)
- goto out;
-
- length = -ENOMEM;
data = vmalloc(count);
- if (!data)
+ if (!data) {
+ length = -ENOMEM;
goto out;
-
- length = -EFAULT;
- if (copy_from_user(data, buf, count) != 0)
+ }
+ if (copy_from_user(data, buf, count) != 0) {
+ length = -EFAULT;
goto out;
+ }
length = security_load_policy(data, count, &load_state);
if (length) {
pr_warn_ratelimited("SELinux: failed to load policy\n");
goto out;
}
-
+ fsi = file_inode(file)->i_sb->s_fs_info;
length = sel_make_policy_nodes(fsi, load_state.policy);
if (length) {
pr_warn_ratelimited("SELinux: failed to initialize selinuxfs\n");
@@ -611,13 +614,12 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
}
selinux_policy_commit(&load_state);
-
length = count;
-
audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
"auid=%u ses=%u lsm=selinux res=1",
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current));
+
out:
mutex_unlock(&selinux_state.policy_mutex);
vfree(data);
@@ -706,7 +708,7 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
if (new_value) {
char comm[sizeof(current->comm)];
- memcpy(comm, current->comm, sizeof(comm));
+ strscpy(comm, current->comm);
pr_err("SELinux: %s (%d) set checkreqprot to 1. This is no longer supported.\n",
comm, current->pid);
}
@@ -1067,6 +1069,10 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
int rc;
u32 i, len, nsids;
+ pr_warn_ratelimited("SELinux: %s (%d) wrote to /sys/fs/selinux/user!"
+ " This will not be supported in the future; please update your"
+ " userspace.\n", current->comm, current->pid);
+
length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
NULL);
@@ -1509,7 +1515,7 @@ static const struct file_operations sel_avc_hash_stats_ops = {
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
static struct avc_cache_stats *sel_avc_get_stat_idx(loff_t *idx)
{
- int cpu;
+ loff_t cpu;
for (cpu = *idx; cpu < nr_cpu_ids; ++cpu) {
if (!cpu_possible(cpu))
@@ -1995,7 +2001,7 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
[SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
S_IWUGO},
- /* last one */ {""}
+ /* last one */ {"", NULL, 0}
};
ret = selinux_fs_info_create(sb);
@@ -2123,7 +2129,6 @@ static struct file_system_type sel_fs_type = {
.kill_sb = sel_kill_sb,
};
-static struct vfsmount *selinuxfs_mount __ro_after_init;
struct path selinux_null __ro_after_init;
static int __init init_sel_fs(void)
@@ -2145,20 +2150,29 @@ static int __init init_sel_fs(void)
return err;
}
- selinux_null.mnt = selinuxfs_mount = kern_mount(&sel_fs_type);
- if (IS_ERR(selinuxfs_mount)) {
+ selinux_null.mnt = kern_mount(&sel_fs_type);
+ if (IS_ERR(selinux_null.mnt)) {
pr_err("selinuxfs: could not mount!\n");
- err = PTR_ERR(selinuxfs_mount);
- selinuxfs_mount = NULL;
+ err = PTR_ERR(selinux_null.mnt);
+ selinux_null.mnt = NULL;
+ return err;
}
+
selinux_null.dentry = d_hash_and_lookup(selinux_null.mnt->mnt_root,
&null_name);
if (IS_ERR(selinux_null.dentry)) {
pr_err("selinuxfs: could not lookup null!\n");
err = PTR_ERR(selinux_null.dentry);
selinux_null.dentry = NULL;
+ return err;
}
+ /*
+ * Try to pre-allocate the status page, so the sequence number of the
+ * initial policy load can be stored.
+ */
+ (void) selinux_kernel_status_page();
+
return err;
}
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 697eb4352439..c2c31521cace 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -1,20 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Implementation of the access vector table type.
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
-/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
- *
- * Added conditional policy language extensions
- *
- * Copyright (C) 2003 Tresys Technology, LLC
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 2.
+/* Updated: Frank Mayer <mayerf@tresys.com> and
+ * Karl MacMillan <kmacmillan@tresys.com>
+ * Added conditional policy language extensions
+ * Copyright (C) 2003 Tresys Technology, LLC
*
* Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
- * Tuned number of hash slots for avtab to reduce memory usage
+ * Tuned number of hash slots for avtab to reduce memory usage
*/
#include <linux/bitops.h>
@@ -36,19 +33,20 @@ static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask)
static const u32 c2 = 0x1b873593;
static const u32 r1 = 15;
static const u32 r2 = 13;
- static const u32 m = 5;
- static const u32 n = 0xe6546b64;
+ static const u32 m = 5;
+ static const u32 n = 0xe6546b64;
u32 hash = 0;
-#define mix(input) do { \
- u32 v = input; \
- v *= c1; \
- v = (v << r1) | (v >> (32 - r1)); \
- v *= c2; \
- hash ^= v; \
+#define mix(input) \
+ do { \
+ u32 v = input; \
+ v *= c1; \
+ v = (v << r1) | (v >> (32 - r1)); \
+ v *= c2; \
+ hash ^= v; \
hash = (hash << r2) | (hash >> (32 - r2)); \
- hash = hash * m + n; \
+ hash = hash * m + n; \
} while (0)
mix(keyp->target_class);
@@ -66,9 +64,10 @@ static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask)
return hash & mask;
}
-static struct avtab_node*
-avtab_insert_node(struct avtab *h, struct avtab_node **dst,
- const struct avtab_key *key, const struct avtab_datum *datum)
+static struct avtab_node *avtab_insert_node(struct avtab *h,
+ struct avtab_node **dst,
+ const struct avtab_key *key,
+ const struct avtab_datum *datum)
{
struct avtab_node *newnode;
struct avtab_extended_perms *xperms;
@@ -99,7 +98,7 @@ avtab_insert_node(struct avtab *h, struct avtab_node **dst,
static int avtab_node_cmp(const struct avtab_key *key1,
const struct avtab_key *key2)
{
- u16 specified = key1->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
+ u16 specified = key1->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
if (key1->source_type == key2->source_type &&
key1->target_type == key2->target_type &&
@@ -129,8 +128,7 @@ static int avtab_insert(struct avtab *h, const struct avtab_key *key,
return -EINVAL;
hvalue = avtab_hash(key, h->mask);
- for (prev = NULL, cur = h->htable[hvalue];
- cur;
+ for (prev = NULL, cur = h->htable[hvalue]; cur;
prev = cur, cur = cur->next) {
cmp = avtab_node_cmp(key, &cur->key);
/* extended perms may not be unique */
@@ -163,8 +161,7 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h,
if (!h || !h->nslot || h->nel == U32_MAX)
return NULL;
hvalue = avtab_hash(key, h->mask);
- for (prev = NULL, cur = h->htable[hvalue];
- cur;
+ for (prev = NULL, cur = h->htable[hvalue]; cur;
prev = cur, cur = cur->next) {
cmp = avtab_node_cmp(key, &cur->key);
if (cmp <= 0)
@@ -188,8 +185,7 @@ struct avtab_node *avtab_search_node(struct avtab *h,
return NULL;
hvalue = avtab_hash(key, h->mask);
- for (cur = h->htable[hvalue]; cur;
- cur = cur->next) {
+ for (cur = h->htable[hvalue]; cur; cur = cur->next) {
cmp = avtab_node_cmp(key, &cur->key);
if (cmp == 0)
return cur;
@@ -199,8 +195,8 @@ struct avtab_node *avtab_search_node(struct avtab *h,
return NULL;
}
-struct avtab_node*
-avtab_search_node_next(struct avtab_node *node, u16 specified)
+struct avtab_node *avtab_search_node_next(struct avtab_node *node,
+ u16 specified)
{
struct avtab_key tmp_key;
struct avtab_node *cur;
@@ -314,17 +310,19 @@ void avtab_hash_eval(struct avtab *h, const char *tag)
if (chain_len > max_chain_len)
max_chain_len = chain_len;
- chain2_len_sum += (unsigned long long)chain_len * chain_len;
+ chain2_len_sum +=
+ (unsigned long long)chain_len * chain_len;
}
}
pr_debug("SELinux: %s: %d entries and %d/%d buckets used, "
- "longest chain length %d, sum of chain length^2 %llu\n",
- tag, h->nel, slots_used, h->nslot, max_chain_len,
- chain2_len_sum);
+ "longest chain length %d, sum of chain length^2 %llu\n",
+ tag, h->nel, slots_used, h->nslot, max_chain_len,
+ chain2_len_sum);
}
#endif /* CONFIG_SECURITY_SELINUX_DEBUG */
+/* clang-format off */
static const uint16_t spec_order[] = {
AVTAB_ALLOWED,
AVTAB_AUDITDENY,
@@ -336,11 +334,12 @@ static const uint16_t spec_order[] = {
AVTAB_XPERMS_AUDITALLOW,
AVTAB_XPERMS_DONTAUDIT
};
+/* clang-format on */
-int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
+int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *pol,
int (*insertf)(struct avtab *a, const struct avtab_key *k,
const struct avtab_datum *d, void *p),
- void *p)
+ void *p, bool conditional)
{
__le16 buf16[4];
u16 enabled;
@@ -365,9 +364,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
if (items2 > ARRAY_SIZE(buf32)) {
pr_err("SELinux: avtab: entry overflow\n");
return -EINVAL;
-
}
- rc = next_entry(buf32, fp, sizeof(u32)*items2);
+ rc = next_entry(buf32, fp, sizeof(u32) * items2);
if (rc) {
pr_err("SELinux: avtab: truncated entry\n");
return rc;
@@ -400,8 +398,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
pr_err("SELinux: avtab: null entry\n");
return -EINVAL;
}
- if ((val & AVTAB_AV) &&
- (val & AVTAB_TYPE)) {
+ if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) {
pr_err("SELinux: avtab: entry has both access vectors and types\n");
return -EINVAL;
}
@@ -428,7 +425,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
return 0;
}
- rc = next_entry(buf16, fp, sizeof(u16)*4);
+ rc = next_entry(buf16, fp, sizeof(u16) * 4);
if (rc) {
pr_err("SELinux: avtab: truncated entry\n");
return rc;
@@ -454,10 +451,18 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
}
if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) &&
- (key.specified & AVTAB_XPERMS)) {
+ (key.specified & AVTAB_XPERMS)) {
pr_err("SELinux: avtab: policy version %u does not "
- "support extended permissions rules and one "
- "was specified\n", vers);
+ "support extended permissions rules and one "
+ "was specified\n",
+ vers);
+ return -EINVAL;
+ } else if ((vers < POLICYDB_VERSION_COND_XPERMS) &&
+ (key.specified & AVTAB_XPERMS) && conditional) {
+ pr_err("SELinux: avtab: policy version %u does not "
+ "support extended permissions rules in conditional "
+ "policies and one was specified\n",
+ vers);
return -EINVAL;
} else if (key.specified & AVTAB_XPERMS) {
memset(&xperms, 0, sizeof(struct avtab_extended_perms));
@@ -471,7 +476,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
pr_err("SELinux: avtab: truncated entry\n");
return rc;
}
- rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p));
+ rc = next_entry(buf32, fp,
+ sizeof(u32) * ARRAY_SIZE(xperms.perms.p));
if (rc) {
pr_err("SELinux: avtab: truncated entry\n");
return rc;
@@ -501,13 +507,12 @@ static int avtab_insertf(struct avtab *a, const struct avtab_key *k,
return avtab_insert(a, k, d);
}
-int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
+int avtab_read(struct avtab *a, struct policy_file *fp, struct policydb *pol)
{
int rc;
__le32 buf[1];
u32 nel, i;
-
rc = next_entry(buf, fp, sizeof(u32));
if (rc < 0) {
pr_err("SELinux: avtab: truncated table\n");
@@ -525,7 +530,7 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
goto bad;
for (i = 0; i < nel; i++) {
- rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL);
+ rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL, false);
if (rc) {
if (rc == -ENOMEM)
pr_err("SELinux: avtab: out of memory\n");
@@ -545,7 +550,7 @@ bad:
goto out;
}
-int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp)
+int avtab_write_item(struct policydb *p, const struct avtab_node *cur, struct policy_file *fp)
{
__le16 buf16[4];
__le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)];
@@ -561,7 +566,8 @@ int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp)
return rc;
if (cur->key.specified & AVTAB_XPERMS) {
- rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, fp);
+ rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1,
+ fp);
if (rc)
return rc;
rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp);
@@ -570,7 +576,7 @@ int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp)
for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++)
buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]);
rc = put_entry(buf32, sizeof(u32),
- ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp);
+ ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp);
} else {
buf32[0] = cpu_to_le32(cur->datum.u.data);
rc = put_entry(buf32, sizeof(u32), 1, fp);
@@ -580,7 +586,7 @@ int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp)
return 0;
}
-int avtab_write(struct policydb *p, struct avtab *a, void *fp)
+int avtab_write(struct policydb *p, struct avtab *a, struct policy_file *fp)
{
u32 i;
int rc = 0;
@@ -593,8 +599,7 @@ int avtab_write(struct policydb *p, struct avtab *a, void *fp)
return rc;
for (i = 0; i < a->nslot; i++) {
- for (cur = a->htable[i]; cur;
- cur = cur->next) {
+ for (cur = a->htable[i]; cur; cur = cur->next) {
rc = avtab_write_item(p, cur, fp);
if (rc)
return rc;
@@ -606,10 +611,6 @@ int avtab_write(struct policydb *p, struct avtab *a, void *fp)
void __init avtab_cache_init(void)
{
- avtab_node_cachep = kmem_cache_create("avtab_node",
- sizeof(struct avtab_node),
- 0, SLAB_PANIC, NULL);
- avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms",
- sizeof(struct avtab_extended_perms),
- 0, SLAB_PANIC, NULL);
+ avtab_node_cachep = KMEM_CACHE(avtab_node, SLAB_PANIC);
+ avtab_xperms_cachep = KMEM_CACHE(avtab_extended_perms, SLAB_PANIC);
}
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
index 3c3904bf02b0..850b3453f259 100644
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -9,42 +9,42 @@
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
-/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
- *
- * Added conditional policy language extensions
- *
- * Copyright (C) 2003 Tresys Technology, LLC
+/* Updated: Frank Mayer <mayerf@tresys.com> and
+ * Karl MacMillan <kmacmillan@tresys.com>
+ * Added conditional policy language extensions
+ * Copyright (C) 2003 Tresys Technology, LLC
*
* Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
- * Tuned number of hash slots for avtab to reduce memory usage
+ * Tuned number of hash slots for avtab to reduce memory usage
*/
+
#ifndef _SS_AVTAB_H_
#define _SS_AVTAB_H_
#include "security.h"
struct avtab_key {
- u16 source_type; /* source type */
- u16 target_type; /* target type */
- u16 target_class; /* target object class */
-#define AVTAB_ALLOWED 0x0001
-#define AVTAB_AUDITALLOW 0x0002
-#define AVTAB_AUDITDENY 0x0004
-#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
-#define AVTAB_TRANSITION 0x0010
-#define AVTAB_MEMBER 0x0020
-#define AVTAB_CHANGE 0x0040
-#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
+ u16 source_type; /* source type */
+ u16 target_type; /* target type */
+ u16 target_class; /* target object class */
+#define AVTAB_ALLOWED 0x0001
+#define AVTAB_AUDITALLOW 0x0002
+#define AVTAB_AUDITDENY 0x0004
+#define AVTAB_AV (AVTAB_ALLOWED | AVTAB_AUDITALLOW | AVTAB_AUDITDENY)
+#define AVTAB_TRANSITION 0x0010
+#define AVTAB_MEMBER 0x0020
+#define AVTAB_CHANGE 0x0040
+#define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE)
/* extended permissions */
#define AVTAB_XPERMS_ALLOWED 0x0100
-#define AVTAB_XPERMS_AUDITALLOW 0x0200
+#define AVTAB_XPERMS_AUDITALLOW 0x0200
#define AVTAB_XPERMS_DONTAUDIT 0x0400
-#define AVTAB_XPERMS (AVTAB_XPERMS_ALLOWED | \
- AVTAB_XPERMS_AUDITALLOW | \
- AVTAB_XPERMS_DONTAUDIT)
-#define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */
-#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */
- u16 specified; /* what field is specified */
+#define AVTAB_XPERMS \
+ (AVTAB_XPERMS_ALLOWED | AVTAB_XPERMS_AUDITALLOW | \
+ AVTAB_XPERMS_DONTAUDIT)
+#define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */
+#define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */
+ u16 specified; /* what field is specified */
};
/*
@@ -55,6 +55,7 @@ struct avtab_extended_perms {
/* These are not flags. All 256 values may be used */
#define AVTAB_XPERMS_IOCTLFUNCTION 0x01
#define AVTAB_XPERMS_IOCTLDRIVER 0x02
+#define AVTAB_XPERMS_NLMSG 0x03
/* extension of the avtab_key specified */
u8 specified; /* ioctl, netfilter, ... */
/*
@@ -82,16 +83,19 @@ struct avtab_node {
struct avtab {
struct avtab_node **htable;
- u32 nel; /* number of elements */
- u32 nslot; /* number of hash slots */
- u32 mask; /* mask to compute hash func */
+ u32 nel; /* number of elements */
+ u32 nslot; /* number of hash slots */
+ u32 mask; /* mask to compute hash func */
};
void avtab_init(struct avtab *h);
-int avtab_alloc(struct avtab *, u32);
+int avtab_alloc(struct avtab *h, u32 nrules);
int avtab_alloc_dup(struct avtab *new, const struct avtab *orig);
void avtab_destroy(struct avtab *h);
+#define MAX_AVTAB_HASH_BITS 16
+#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
+
#ifdef CONFIG_SECURITY_SELINUX_DEBUG
void avtab_hash_eval(struct avtab *h, const char *tag);
#else
@@ -101,14 +105,16 @@ static inline void avtab_hash_eval(struct avtab *h, const char *tag)
#endif
struct policydb;
-int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
+struct policy_file;
+int avtab_read_item(struct avtab *a, struct policy_file *fp, struct policydb *pol,
int (*insert)(struct avtab *a, const struct avtab_key *k,
const struct avtab_datum *d, void *p),
- void *p);
+ void *p, bool conditional);
-int avtab_read(struct avtab *a, void *fp, struct policydb *pol);
-int avtab_write_item(struct policydb *p, const struct avtab_node *cur, void *fp);
-int avtab_write(struct policydb *p, struct avtab *a, void *fp);
+int avtab_read(struct avtab *a, struct policy_file *fp, struct policydb *pol);
+int avtab_write_item(struct policydb *p, const struct avtab_node *cur,
+ struct policy_file *fp);
+int avtab_write(struct policydb *p, struct avtab *a, struct policy_file *fp);
struct avtab_node *avtab_insert_nonunique(struct avtab *h,
const struct avtab_key *key,
@@ -116,11 +122,7 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h,
struct avtab_node *avtab_search_node(struct avtab *h,
const struct avtab_key *key);
+struct avtab_node *avtab_search_node_next(struct avtab_node *node,
+ u16 specified);
-struct avtab_node *avtab_search_node_next(struct avtab_node *node, u16 specified);
-
-#define MAX_AVTAB_HASH_BITS 16
-#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
-
-#endif /* _SS_AVTAB_H_ */
-
+#endif /* _SS_AVTAB_H_ */
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 81ff676f209a..1bebfcb9c6a1 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -1,8 +1,7 @@
-// SPDX-License-Identifier: GPL-2.0-only
+/* SPDX-License-Identifier: GPL-2.0-only */
/* Authors: Karl MacMillan <kmacmillan@tresys.com>
* Frank Mayer <mayerf@tresys.com>
- *
- * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
*/
#include <linux/kernel.h>
@@ -166,11 +165,13 @@ void cond_policydb_destroy(struct policydb *p)
int cond_init_bool_indexes(struct policydb *p)
{
kfree(p->bool_val_to_struct);
- p->bool_val_to_struct = kmalloc_array(p->p_bools.nprim,
- sizeof(*p->bool_val_to_struct),
- GFP_KERNEL);
+ p->bool_val_to_struct = kmalloc_array(
+ p->p_bools.nprim, sizeof(*p->bool_val_to_struct), GFP_KERNEL);
if (!p->bool_val_to_struct)
return -ENOMEM;
+
+ avtab_hash_eval(&p->te_cond_avtab, "conditional_rules");
+
return 0;
}
@@ -205,7 +206,7 @@ static int bool_isvalid(struct cond_bool_datum *b)
return 1;
}
-int cond_read_bool(struct policydb *p, struct symtab *s, void *fp)
+int cond_read_bool(struct policydb *p, struct symtab *s, struct policy_file *fp)
{
char *key = NULL;
struct cond_bool_datum *booldatum;
@@ -229,17 +230,11 @@ int cond_read_bool(struct policydb *p, struct symtab *s, void *fp)
goto err;
len = le32_to_cpu(buf[2]);
- if (((len == 0) || (len == (u32)-1)))
- goto err;
- rc = -ENOMEM;
- key = kmalloc(len + 1, GFP_KERNEL);
- if (!key)
- goto err;
- rc = next_entry(key, fp, len);
+ rc = str_read(&key, GFP_KERNEL, fp, len);
if (rc)
goto err;
- key[len] = '\0';
+
rc = symtab_insert(s, key, booldatum);
if (rc)
goto err;
@@ -287,7 +282,8 @@ static int cond_insertf(struct avtab *a, const struct avtab_key *k,
if (other) {
node_ptr = avtab_search_node(&p->te_cond_avtab, k);
if (node_ptr) {
- if (avtab_search_node_next(node_ptr, k->specified)) {
+ if (avtab_search_node_next(node_ptr,
+ k->specified)) {
pr_err("SELinux: too many conflicting type rules.\n");
return -EINVAL;
}
@@ -321,7 +317,7 @@ static int cond_insertf(struct avtab *a, const struct avtab_key *k,
return 0;
}
-static int cond_read_av_list(struct policydb *p, void *fp,
+static int cond_read_av_list(struct policydb *p, struct policy_file *fp,
struct cond_av_list *list,
struct cond_av_list *other)
{
@@ -347,7 +343,7 @@ static int cond_read_av_list(struct policydb *p, void *fp,
for (i = 0; i < len; i++) {
data.dst = &list->nodes[i];
rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
- &data);
+ &data, true);
if (rc) {
kfree(list->nodes);
list->nodes = NULL;
@@ -373,7 +369,7 @@ static int expr_node_isvalid(struct policydb *p, struct cond_expr_node *expr)
return 1;
}
-static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
+static int cond_read_node(struct policydb *p, struct cond_node *node, struct policy_file *fp)
{
__le32 buf[2];
u32 i, len;
@@ -413,7 +409,7 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
return cond_read_av_list(p, fp, &node->false_list, &node->true_list);
}
-int cond_read_list(struct policydb *p, void *fp)
+int cond_read_list(struct policydb *p, struct policy_file *fp)
{
__le32 buf[1];
u32 i, len;
@@ -451,7 +447,7 @@ int cond_write_bool(void *vkey, void *datum, void *ptr)
char *key = vkey;
struct cond_bool_datum *booldatum = datum;
struct policy_data *pd = ptr;
- void *fp = pd->fp;
+ struct policy_file *fp = pd->fp;
__le32 buf[3];
u32 len;
int rc;
@@ -478,8 +474,8 @@ int cond_write_bool(void *vkey, void *datum, void *ptr)
* the conditional. This means that the avtab with the conditional
* rules will not be saved but will be rebuilt on policy load.
*/
-static int cond_write_av_list(struct policydb *p,
- struct cond_av_list *list, struct policy_file *fp)
+static int cond_write_av_list(struct policydb *p, struct cond_av_list *list,
+ struct policy_file *fp)
{
__le32 buf[1];
u32 i;
@@ -500,7 +496,7 @@ static int cond_write_av_list(struct policydb *p,
}
static int cond_write_node(struct policydb *p, struct cond_node *node,
- struct policy_file *fp)
+ struct policy_file *fp)
{
__le32 buf[2];
int rc;
@@ -534,7 +530,7 @@ static int cond_write_node(struct policydb *p, struct cond_node *node,
return 0;
}
-int cond_write_list(struct policydb *p, void *fp)
+int cond_write_list(struct policydb *p, struct policy_file *fp)
{
u32 i;
__le32 buf[1];
@@ -555,7 +551,7 @@ int cond_write_list(struct policydb *p, void *fp)
}
void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
- struct extended_perms_decision *xpermd)
+ struct extended_perms_decision *xpermd)
{
struct avtab_node *node;
@@ -563,7 +559,7 @@ void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
return;
for (node = avtab_search_node(ctab, key); node;
- node = avtab_search_node_next(node, key->specified)) {
+ node = avtab_search_node_next(node, key->specified)) {
if (node->key.specified & AVTAB_ENABLED)
services_compute_xperms_decision(xpermd, node);
}
@@ -572,7 +568,7 @@ void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
* av table, and if so, add them to the result
*/
void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
- struct av_decision *avd, struct extended_perms *xperms)
+ struct av_decision *avd, struct extended_perms *xperms)
{
struct avtab_node *node;
@@ -580,30 +576,30 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
return;
for (node = avtab_search_node(ctab, key); node;
- node = avtab_search_node_next(node, key->specified)) {
- if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
- (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
+ node = avtab_search_node_next(node, key->specified)) {
+ if ((u16)(AVTAB_ALLOWED | AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_ALLOWED | AVTAB_ENABLED)))
avd->allowed |= node->datum.u.data;
- if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) ==
- (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
+ if ((u16)(AVTAB_AUDITDENY | AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_AUDITDENY | AVTAB_ENABLED)))
/* Since a '0' in an auditdeny mask represents a
* permission we do NOT want to audit (dontaudit), we use
* the '&' operand to ensure that all '0's in the mask
* are retained (much unlike the allow and auditallow cases).
*/
avd->auditdeny &= node->datum.u.data;
- if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
- (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
+ if ((u16)(AVTAB_AUDITALLOW | AVTAB_ENABLED) ==
+ (node->key.specified & (AVTAB_AUDITALLOW | AVTAB_ENABLED)))
avd->auditallow |= node->datum.u.data;
if (xperms && (node->key.specified & AVTAB_ENABLED) &&
- (node->key.specified & AVTAB_XPERMS))
+ (node->key.specified & AVTAB_XPERMS))
services_compute_xperms_drivers(xperms, node);
}
}
static int cond_dup_av_list(struct cond_av_list *new,
- struct cond_av_list *orig,
- struct avtab *avtab)
+ const struct cond_av_list *orig,
+ struct avtab *avtab)
{
u32 i;
@@ -614,9 +610,8 @@ static int cond_dup_av_list(struct cond_av_list *new,
return -ENOMEM;
for (i = 0; i < orig->len; i++) {
- new->nodes[i] = avtab_insert_nonunique(avtab,
- &orig->nodes[i]->key,
- &orig->nodes[i]->datum);
+ new->nodes[i] = avtab_insert_nonunique(
+ avtab, &orig->nodes[i]->key, &orig->nodes[i]->datum);
if (!new->nodes[i])
return -ENOMEM;
new->len++;
@@ -626,7 +621,7 @@ static int cond_dup_av_list(struct cond_av_list *new,
}
static int duplicate_policydb_cond_list(struct policydb *newp,
- struct policydb *origp)
+ const struct policydb *origp)
{
int rc;
u32 i;
@@ -637,19 +632,19 @@ static int duplicate_policydb_cond_list(struct policydb *newp,
newp->cond_list_len = 0;
newp->cond_list = kcalloc(origp->cond_list_len,
- sizeof(*newp->cond_list),
- GFP_KERNEL);
+ sizeof(*newp->cond_list), GFP_KERNEL);
if (!newp->cond_list)
goto error;
for (i = 0; i < origp->cond_list_len; i++) {
struct cond_node *newn = &newp->cond_list[i];
- struct cond_node *orign = &origp->cond_list[i];
+ const struct cond_node *orign = &origp->cond_list[i];
newp->cond_list_len++;
newn->cur_state = orign->cur_state;
- newn->expr.nodes = kmemdup(orign->expr.nodes,
+ newn->expr.nodes =
+ kmemdup(orign->expr.nodes,
orign->expr.len * sizeof(*orign->expr.nodes),
GFP_KERNEL);
if (!newn->expr.nodes)
@@ -658,12 +653,12 @@ static int duplicate_policydb_cond_list(struct policydb *newp,
newn->expr.len = orign->expr.len;
rc = cond_dup_av_list(&newn->true_list, &orign->true_list,
- &newp->te_cond_avtab);
+ &newp->te_cond_avtab);
if (rc)
goto error;
rc = cond_dup_av_list(&newn->false_list, &orign->false_list,
- &newp->te_cond_avtab);
+ &newp->te_cond_avtab);
if (rc)
goto error;
}
@@ -683,7 +678,8 @@ static int cond_bools_destroy(void *key, void *datum, void *args)
return 0;
}
-static int cond_bools_copy(struct hashtab_node *new, struct hashtab_node *orig, void *args)
+static int cond_bools_copy(struct hashtab_node *new,
+ const struct hashtab_node *orig, void *args)
{
struct cond_bool_datum *datum;
@@ -709,7 +705,7 @@ static int cond_bools_index(void *key, void *datum, void *args)
}
static int duplicate_policydb_bools(struct policydb *newdb,
- struct policydb *orig)
+ const struct policydb *orig)
{
struct cond_bool_datum **cond_bool_array;
int rc;
@@ -721,7 +717,7 @@ static int duplicate_policydb_bools(struct policydb *newdb,
return -ENOMEM;
rc = hashtab_duplicate(&newdb->p_bools.table, &orig->p_bools.table,
- cond_bools_copy, cond_bools_destroy, NULL);
+ cond_bools_copy, cond_bools_destroy, NULL);
if (rc) {
kfree(cond_bool_array);
return -ENOMEM;
@@ -742,7 +738,7 @@ void cond_policydb_destroy_dup(struct policydb *p)
cond_policydb_destroy(p);
}
-int cond_policydb_dup(struct policydb *new, struct policydb *orig)
+int cond_policydb_dup(struct policydb *new, const struct policydb *orig)
{
cond_policydb_init(new);
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h
index 5a7b51278dc6..468e98ad3ea1 100644
--- a/security/selinux/ss/conditional.h
+++ b/security/selinux/ss/conditional.h
@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Authors: Karl MacMillan <kmacmillan@tresys.com>
* Frank Mayer <mayerf@tresys.com>
- *
- * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Copyright (C) 2003 - 2004 Tresys Technology, LLC
*/
#ifndef _CONDITIONAL_H_
@@ -20,14 +19,14 @@
* in reverse polish notation.
*/
struct cond_expr_node {
-#define COND_BOOL 1 /* plain bool */
-#define COND_NOT 2 /* !bool */
-#define COND_OR 3 /* bool || bool */
-#define COND_AND 4 /* bool && bool */
-#define COND_XOR 5 /* bool ^ bool */
-#define COND_EQ 6 /* bool == bool */
-#define COND_NEQ 7 /* bool != bool */
-#define COND_LAST COND_NEQ
+#define COND_BOOL 1 /* plain bool */
+#define COND_NOT 2 /* !bool */
+#define COND_OR 3 /* bool || bool */
+#define COND_AND 4 /* bool && bool */
+#define COND_XOR 5 /* bool ^ bool */
+#define COND_EQ 6 /* bool == bool */
+#define COND_NEQ 7 /* bool != bool */
+#define COND_LAST COND_NEQ
u32 expr_type;
u32 boolean;
};
@@ -69,17 +68,17 @@ int cond_destroy_bool(void *key, void *datum, void *p);
int cond_index_bool(void *key, void *datum, void *datap);
-int cond_read_bool(struct policydb *p, struct symtab *s, void *fp);
-int cond_read_list(struct policydb *p, void *fp);
+int cond_read_bool(struct policydb *p, struct symtab *s, struct policy_file *fp);
+int cond_read_list(struct policydb *p, struct policy_file *fp);
int cond_write_bool(void *key, void *datum, void *ptr);
-int cond_write_list(struct policydb *p, void *fp);
+int cond_write_list(struct policydb *p, struct policy_file *fp);
void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
- struct av_decision *avd, struct extended_perms *xperms);
+ struct av_decision *avd, struct extended_perms *xperms);
void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
- struct extended_perms_decision *xpermd);
+ struct extended_perms_decision *xpermd);
void evaluate_cond_nodes(struct policydb *p);
void cond_policydb_destroy_dup(struct policydb *p);
-int cond_policydb_dup(struct policydb *new, struct policydb *orig);
+int cond_policydb_dup(struct policydb *new, const struct policydb *orig);
#endif /* _CONDITIONAL_H_ */
diff --git a/security/selinux/ss/constraint.h b/security/selinux/ss/constraint.h
index f76eb3128ad5..203033cfad67 100644
--- a/security/selinux/ss/constraint.h
+++ b/security/selinux/ss/constraint.h
@@ -13,6 +13,7 @@
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
+
#ifndef _SS_CONSTRAINT_H_
#define _SS_CONSTRAINT_H_
@@ -21,43 +22,43 @@
#define CEXPR_MAXDEPTH 5
struct constraint_expr {
-#define CEXPR_NOT 1 /* not expr */
-#define CEXPR_AND 2 /* expr and expr */
-#define CEXPR_OR 3 /* expr or expr */
-#define CEXPR_ATTR 4 /* attr op attr */
-#define CEXPR_NAMES 5 /* attr op names */
- u32 expr_type; /* expression type */
-
-#define CEXPR_USER 1 /* user */
-#define CEXPR_ROLE 2 /* role */
-#define CEXPR_TYPE 4 /* type */
-#define CEXPR_TARGET 8 /* target if set, source otherwise */
-#define CEXPR_XTARGET 16 /* special 3rd target for validatetrans rule */
-#define CEXPR_L1L2 32 /* low level 1 vs. low level 2 */
-#define CEXPR_L1H2 64 /* low level 1 vs. high level 2 */
-#define CEXPR_H1L2 128 /* high level 1 vs. low level 2 */
-#define CEXPR_H1H2 256 /* high level 1 vs. high level 2 */
-#define CEXPR_L1H1 512 /* low level 1 vs. high level 1 */
-#define CEXPR_L2H2 1024 /* low level 2 vs. high level 2 */
- u32 attr; /* attribute */
-
-#define CEXPR_EQ 1 /* == or eq */
-#define CEXPR_NEQ 2 /* != */
-#define CEXPR_DOM 3 /* dom */
-#define CEXPR_DOMBY 4 /* domby */
-#define CEXPR_INCOMP 5 /* incomp */
- u32 op; /* operator */
-
- struct ebitmap names; /* names */
+#define CEXPR_NOT 1 /* not expr */
+#define CEXPR_AND 2 /* expr and expr */
+#define CEXPR_OR 3 /* expr or expr */
+#define CEXPR_ATTR 4 /* attr op attr */
+#define CEXPR_NAMES 5 /* attr op names */
+ u32 expr_type; /* expression type */
+
+#define CEXPR_USER 1 /* user */
+#define CEXPR_ROLE 2 /* role */
+#define CEXPR_TYPE 4 /* type */
+#define CEXPR_TARGET 8 /* target if set, source otherwise */
+#define CEXPR_XTARGET 16 /* special 3rd target for validatetrans rule */
+#define CEXPR_L1L2 32 /* low level 1 vs. low level 2 */
+#define CEXPR_L1H2 64 /* low level 1 vs. high level 2 */
+#define CEXPR_H1L2 128 /* high level 1 vs. low level 2 */
+#define CEXPR_H1H2 256 /* high level 1 vs. high level 2 */
+#define CEXPR_L1H1 512 /* low level 1 vs. high level 1 */
+#define CEXPR_L2H2 1024 /* low level 2 vs. high level 2 */
+ u32 attr; /* attribute */
+
+#define CEXPR_EQ 1 /* == or eq */
+#define CEXPR_NEQ 2 /* != */
+#define CEXPR_DOM 3 /* dom */
+#define CEXPR_DOMBY 4 /* domby */
+#define CEXPR_INCOMP 5 /* incomp */
+ u32 op; /* operator */
+
+ struct ebitmap names; /* names */
struct type_set *type_names;
- struct constraint_expr *next; /* next expression */
+ struct constraint_expr *next; /* next expression */
};
struct constraint_node {
- u32 permissions; /* constrained permissions */
- struct constraint_expr *expr; /* constraint on permissions */
- struct constraint_node *next; /* next constraint */
+ u32 permissions; /* constrained permissions */
+ struct constraint_expr *expr; /* constraint on permissions */
+ struct constraint_node *next; /* next constraint */
};
-#endif /* _SS_CONSTRAINT_H_ */
+#endif /* _SS_CONSTRAINT_H_ */
diff --git a/security/selinux/ss/context.c b/security/selinux/ss/context.c
index 38bc0aa524a6..a528b7f76280 100644
--- a/security/selinux/ss/context.c
+++ b/security/selinux/ss/context.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Implementations of the security context functions.
*
@@ -20,7 +20,7 @@ u32 context_compute_hash(const struct context *c)
* context struct with only the len & str set (and vice versa)
* under a given policy. Since context structs from different
* policies should never meet, it is safe to hash valid and
- * invalid contexts differently. The context_cmp() function
+ * invalid contexts differently. The context_equal() function
* already operates under the same assumption.
*/
if (c->len)
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
index 1f59468c0759..dd3b9b5b588e 100644
--- a/security/selinux/ss/context.h
+++ b/security/selinux/ss/context.h
@@ -13,6 +13,7 @@
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
+
#ifndef _SS_CONTEXT_H_
#define _SS_CONTEXT_H_
@@ -28,9 +29,9 @@ struct context {
u32 user;
u32 role;
u32 type;
- u32 len; /* length of string in bytes */
+ u32 len; /* length of string in bytes */
struct mls_range range;
- char *str; /* string representation if context cannot be mapped. */
+ char *str; /* string representation if context cannot be mapped. */
};
static inline void mls_context_init(struct context *c)
@@ -38,7 +39,8 @@ static inline void mls_context_init(struct context *c)
memset(&c->range, 0, sizeof(c->range));
}
-static inline int mls_context_cpy(struct context *dst, const struct context *src)
+static inline int mls_context_cpy(struct context *dst,
+ const struct context *src)
{
int rc;
@@ -58,7 +60,8 @@ out:
/*
* Sets both levels in the MLS range of 'dst' to the low level of 'src'.
*/
-static inline int mls_context_cpy_low(struct context *dst, const struct context *src)
+static inline int mls_context_cpy_low(struct context *dst,
+ const struct context *src)
{
int rc;
@@ -78,7 +81,8 @@ out:
/*
* Sets both levels in the MLS range of 'dst' to the high level of 'src'.
*/
-static inline int mls_context_cpy_high(struct context *dst, const struct context *src)
+static inline int mls_context_cpy_high(struct context *dst,
+ const struct context *src)
{
int rc;
@@ -95,9 +99,9 @@ out:
return rc;
}
-
static inline int mls_context_glblub(struct context *dst,
- const struct context *c1, const struct context *c2)
+ const struct context *c1,
+ const struct context *c2)
{
struct mls_range *dr = &dst->range;
const struct mls_range *r1 = &c1->range, *r2 = &c2->range;
@@ -114,13 +118,13 @@ static inline int mls_context_glblub(struct context *dst,
/* Take the least of the high */
dr->level[1].sens = min(r1->level[1].sens, r2->level[1].sens);
- rc = ebitmap_and(&dr->level[0].cat,
- &r1->level[0].cat, &r2->level[0].cat);
+ rc = ebitmap_and(&dr->level[0].cat, &r1->level[0].cat,
+ &r2->level[0].cat);
if (rc)
goto out;
- rc = ebitmap_and(&dr->level[1].cat,
- &r1->level[1].cat, &r2->level[1].cat);
+ rc = ebitmap_and(&dr->level[1].cat, &r1->level[1].cat,
+ &r2->level[1].cat);
if (rc)
goto out;
@@ -128,12 +132,13 @@ out:
return rc;
}
-static inline int mls_context_cmp(const struct context *c1, const struct context *c2)
+static inline bool mls_context_equal(const struct context *c1,
+ const struct context *c2)
{
return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
- ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) &&
+ ebitmap_equal(&c1->range.level[0].cat, &c2->range.level[0].cat) &&
(c1->range.level[1].sens == c2->range.level[1].sens) &&
- ebitmap_cmp(&c1->range.level[1].cat, &c2->range.level[1].cat));
+ ebitmap_equal(&c1->range.level[1].cat, &c2->range.level[1].cat));
}
static inline void mls_context_destroy(struct context *c)
@@ -183,19 +188,17 @@ static inline void context_destroy(struct context *c)
mls_context_destroy(c);
}
-static inline int context_cmp(const struct context *c1, const struct context *c2)
+static inline bool context_equal(const struct context *c1,
+ const struct context *c2)
{
if (c1->len && c2->len)
return (c1->len == c2->len && !strcmp(c1->str, c2->str));
if (c1->len || c2->len)
return 0;
- return ((c1->user == c2->user) &&
- (c1->role == c2->role) &&
- (c1->type == c2->type) &&
- mls_context_cmp(c1, c2));
+ return ((c1->user == c2->user) && (c1->role == c2->role) &&
+ (c1->type == c2->type) && mls_context_equal(c1, c2));
}
u32 context_compute_hash(const struct context *c);
-#endif /* _SS_CONTEXT_H_ */
-
+#endif /* _SS_CONTEXT_H_ */
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index 77875ad355f7..43bc19e21960 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Implementation of the extensible bitmap type.
*
@@ -6,14 +6,11 @@
*/
/*
* Updated: Hewlett-Packard <paul@paul-moore.com>
+ * Added support to import/export the NetLabel category bitmap
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
*
- * Added support to import/export the NetLabel category bitmap
- *
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
- */
-/*
* Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
- * Applied standard bit operations to improve bitmap scanning.
+ * Applied standard bit operations to improve bitmap scanning.
*/
#include <linux/kernel.h>
@@ -24,30 +21,29 @@
#include "ebitmap.h"
#include "policydb.h"
-#define BITS_PER_U64 (sizeof(u64) * 8)
+#define BITS_PER_U64 ((u32)(sizeof(u64) * 8))
static struct kmem_cache *ebitmap_node_cachep __ro_after_init;
-int ebitmap_cmp(const struct ebitmap *e1, const struct ebitmap *e2)
+bool ebitmap_equal(const struct ebitmap *e1, const struct ebitmap *e2)
{
const struct ebitmap_node *n1, *n2;
if (e1->highbit != e2->highbit)
- return 0;
+ return false;
n1 = e1->node;
n2 = e2->node;
- while (n1 && n2 &&
- (n1->startbit == n2->startbit) &&
+ while (n1 && n2 && (n1->startbit == n2->startbit) &&
!memcmp(n1->maps, n2->maps, EBITMAP_SIZE / 8)) {
n1 = n1->next;
n2 = n2->next;
}
if (n1 || n2)
- return 0;
+ return false;
- return 1;
+ return true;
}
int ebitmap_cpy(struct ebitmap *dst, const struct ebitmap *src)
@@ -79,14 +75,17 @@ int ebitmap_cpy(struct ebitmap *dst, const struct ebitmap *src)
return 0;
}
-int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, const struct ebitmap *e2)
+int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1,
+ const struct ebitmap *e2)
{
struct ebitmap_node *n;
- int bit, rc;
+ u32 bit;
+ int rc;
ebitmap_init(dst);
- ebitmap_for_each_positive_bit(e1, n, bit) {
+ ebitmap_for_each_positive_bit(e1, n, bit)
+ {
if (ebitmap_get_bit(e2, bit)) {
rc = ebitmap_set_bit(dst, bit, 1);
if (rc < 0)
@@ -96,7 +95,6 @@ int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, const struct ebit
return 0;
}
-
#ifdef CONFIG_NETLABEL
/**
* ebitmap_netlbl_export - Export an ebitmap into a NetLabel category bitmap
@@ -131,10 +129,8 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
for (iter = 0; iter < EBITMAP_UNIT_NUMS; iter++) {
e_map = e_iter->maps[iter];
if (e_map != 0) {
- rc = netlbl_catmap_setlong(catmap,
- offset,
- e_map,
- GFP_ATOMIC);
+ rc = netlbl_catmap_setlong(catmap, offset,
+ e_map, GFP_ATOMIC);
if (rc != 0)
goto netlbl_export_failure;
}
@@ -185,7 +181,8 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
if (e_iter == NULL ||
offset >= e_iter->startbit + EBITMAP_SIZE) {
e_prev = e_iter;
- e_iter = kmem_cache_zalloc(ebitmap_node_cachep, GFP_ATOMIC);
+ e_iter = kmem_cache_zalloc(ebitmap_node_cachep,
+ GFP_ATOMIC);
if (e_iter == NULL)
goto netlbl_import_failure;
e_iter->startbit = offset - (offset % EBITMAP_SIZE);
@@ -218,7 +215,8 @@ netlbl_import_failure:
* if last_e2bit is non-zero, the highest set bit in e2 cannot exceed
* last_e2bit.
*/
-int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, u32 last_e2bit)
+int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2,
+ u32 last_e2bit)
{
const struct ebitmap_node *n1, *n2;
int i;
@@ -234,8 +232,8 @@ int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, u32 las
n1 = n1->next;
continue;
}
- for (i = EBITMAP_UNIT_NUMS - 1; (i >= 0) && !n2->maps[i]; )
- i--; /* Skip trailing NULL map entries */
+ for (i = EBITMAP_UNIT_NUMS - 1; (i >= 0) && !n2->maps[i];)
+ i--; /* Skip trailing NULL map entries */
if (last_e2bit && (i >= 0)) {
u32 lastsetbit = n2->startbit + i * EBITMAP_UNIT_SIZE +
__fls(n2->maps[i]);
@@ -259,7 +257,7 @@ int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, u32 las
return 1;
}
-int ebitmap_get_bit(const struct ebitmap *e, unsigned long bit)
+int ebitmap_get_bit(const struct ebitmap *e, u32 bit)
{
const struct ebitmap_node *n;
@@ -276,7 +274,7 @@ int ebitmap_get_bit(const struct ebitmap *e, unsigned long bit)
return 0;
}
-int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
+int ebitmap_set_bit(struct ebitmap *e, u32 bit, int value)
{
struct ebitmap_node *n, *prev, *new;
@@ -287,7 +285,7 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
if (value) {
ebitmap_node_set_bit(n, bit);
} else {
- unsigned int s;
+ u32 s;
ebitmap_node_clr_bit(n, bit);
@@ -302,8 +300,8 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
* within the bitmap
*/
if (prev)
- e->highbit = prev->startbit
- + EBITMAP_SIZE;
+ e->highbit = prev->startbit +
+ EBITMAP_SIZE;
else
e->highbit = 0;
}
@@ -362,15 +360,15 @@ void ebitmap_destroy(struct ebitmap *e)
e->node = NULL;
}
-int ebitmap_read(struct ebitmap *e, void *fp)
+int ebitmap_read(struct ebitmap *e, struct policy_file *fp)
{
struct ebitmap_node *n = NULL;
- u32 mapunit, count, startbit, index;
+ u32 mapunit, count, startbit, index, i;
__le32 ebitmap_start;
u64 map;
__le64 mapbits;
__le32 buf[3];
- int rc, i;
+ int rc;
ebitmap_init(e);
@@ -384,7 +382,7 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (mapunit != BITS_PER_U64) {
pr_err("SELinux: ebitmap: map size %u does not "
- "match my size %zd (high bit was %d)\n",
+ "match my size %u (high bit was %u)\n",
mapunit, BITS_PER_U64, e->highbit);
goto bad;
}
@@ -410,13 +408,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)
startbit = le32_to_cpu(ebitmap_start);
if (startbit & (mapunit - 1)) {
- pr_err("SELinux: ebitmap start bit (%d) is "
+ pr_err("SELinux: ebitmap start bit (%u) is "
"not a multiple of the map unit size (%u)\n",
startbit, mapunit);
goto bad;
}
if (startbit > e->highbit - mapunit) {
- pr_err("SELinux: ebitmap start bit (%d) is "
+ pr_err("SELinux: ebitmap start bit (%u) is "
"beyond the end of the bitmap (%u)\n",
startbit, (e->highbit - mapunit));
goto bad;
@@ -424,7 +422,8 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (!n || startbit >= n->startbit + EBITMAP_SIZE) {
struct ebitmap_node *tmp;
- tmp = kmem_cache_zalloc(ebitmap_node_cachep, GFP_KERNEL);
+ tmp = kmem_cache_zalloc(ebitmap_node_cachep,
+ GFP_KERNEL);
if (!tmp) {
pr_err("SELinux: ebitmap: out of memory\n");
rc = -ENOMEM;
@@ -438,8 +437,8 @@ int ebitmap_read(struct ebitmap *e, void *fp)
e->node = tmp;
n = tmp;
} else if (startbit <= n->startbit) {
- pr_err("SELinux: ebitmap: start bit %d"
- " comes after start bit %d\n",
+ pr_err("SELinux: ebitmap: start bit %u"
+ " comes after start bit %u\n",
startbit, n->startbit);
goto bad;
}
@@ -450,6 +449,10 @@ int ebitmap_read(struct ebitmap *e, void *fp)
goto bad;
}
map = le64_to_cpu(mapbits);
+ if (!map) {
+ pr_err("SELinux: ebitmap: empty map\n");
+ goto bad;
+ }
index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
while (map) {
@@ -457,6 +460,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)
map = EBITMAP_SHIFT_UNIT_SIZE(map);
}
}
+
+ if (n && n->startbit + EBITMAP_SIZE != e->highbit) {
+ pr_err("SELinux: ebitmap: high bit %u is not equal to the expected value %zu\n",
+ e->highbit, n->startbit + EBITMAP_SIZE);
+ goto bad;
+ }
+
ok:
rc = 0;
out:
@@ -468,21 +478,23 @@ bad:
goto out;
}
-int ebitmap_write(const struct ebitmap *e, void *fp)
+int ebitmap_write(const struct ebitmap *e, struct policy_file *fp)
{
struct ebitmap_node *n;
- u32 count;
+ u32 bit, count, last_bit, last_startbit;
__le32 buf[3];
u64 map;
- int bit, last_bit, last_startbit, rc;
+ int rc;
buf[0] = cpu_to_le32(BITS_PER_U64);
count = 0;
last_bit = 0;
- last_startbit = -1;
- ebitmap_for_each_positive_bit(e, n, bit) {
- if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) {
+ last_startbit = U32_MAX;
+ ebitmap_for_each_positive_bit(e, n, bit)
+ {
+ if (last_startbit == U32_MAX ||
+ rounddown(bit, BITS_PER_U64) > last_startbit) {
count++;
last_startbit = rounddown(bit, BITS_PER_U64);
}
@@ -496,9 +508,11 @@ int ebitmap_write(const struct ebitmap *e, void *fp)
return rc;
map = 0;
- last_startbit = INT_MIN;
- ebitmap_for_each_positive_bit(e, n, bit) {
- if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) {
+ last_startbit = U32_MAX;
+ ebitmap_for_each_positive_bit(e, n, bit)
+ {
+ if (last_startbit == U32_MAX ||
+ rounddown(bit, BITS_PER_U64) > last_startbit) {
__le64 buf64[1];
/* this is the very first bit */
@@ -558,7 +572,5 @@ u32 ebitmap_hash(const struct ebitmap *e, u32 hash)
void __init ebitmap_cache_init(void)
{
- ebitmap_node_cachep = kmem_cache_create("ebitmap_node",
- sizeof(struct ebitmap_node),
- 0, SLAB_PANIC, NULL);
+ ebitmap_node_cachep = KMEM_CACHE(ebitmap_node, SLAB_PANIC);
}
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index e3c807cfad90..c9569998f287 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -12,23 +12,25 @@
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
+
#ifndef _SS_EBITMAP_H_
#define _SS_EBITMAP_H_
#include <net/netlabel.h>
#ifdef CONFIG_64BIT
-#define EBITMAP_NODE_SIZE 64
+#define EBITMAP_NODE_SIZE 64
#else
-#define EBITMAP_NODE_SIZE 32
+#define EBITMAP_NODE_SIZE 32
#endif
-#define EBITMAP_UNIT_NUMS ((EBITMAP_NODE_SIZE-sizeof(void *)-sizeof(u32))\
- / sizeof(unsigned long))
-#define EBITMAP_UNIT_SIZE BITS_PER_LONG
-#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
-#define EBITMAP_BIT 1ULL
-#define EBITMAP_SHIFT_UNIT_SIZE(x) \
+#define EBITMAP_UNIT_NUMS \
+ ((EBITMAP_NODE_SIZE - sizeof(void *) - sizeof(u32)) / \
+ sizeof(unsigned long))
+#define EBITMAP_UNIT_SIZE BITS_PER_LONG
+#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
+#define EBITMAP_BIT 1UL
+#define EBITMAP_SHIFT_UNIT_SIZE(x) \
(((x) >> EBITMAP_UNIT_SIZE / 2) >> EBITMAP_UNIT_SIZE / 2)
struct ebitmap_node {
@@ -38,16 +40,16 @@ struct ebitmap_node {
};
struct ebitmap {
- struct ebitmap_node *node; /* first node in the bitmap */
- u32 highbit; /* highest position in the total bitmap */
+ struct ebitmap_node *node; /* first node in the bitmap */
+ u32 highbit; /* highest position in the total bitmap */
};
#define ebitmap_length(e) ((e)->highbit)
-static inline unsigned int ebitmap_start_positive(const struct ebitmap *e,
- struct ebitmap_node **n)
+static inline u32 ebitmap_start_positive(const struct ebitmap *e,
+ struct ebitmap_node **n)
{
- unsigned int ofs;
+ u32 ofs;
for (*n = e->node; *n; *n = (*n)->next) {
ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
@@ -62,11 +64,10 @@ static inline void ebitmap_init(struct ebitmap *e)
memset(e, 0, sizeof(*e));
}
-static inline unsigned int ebitmap_next_positive(const struct ebitmap *e,
- struct ebitmap_node **n,
- unsigned int bit)
+static inline u32 ebitmap_next_positive(const struct ebitmap *e,
+ struct ebitmap_node **n, u32 bit)
{
- unsigned int ofs;
+ u32 ofs;
ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
if (ofs < EBITMAP_SIZE)
@@ -80,16 +81,15 @@ static inline unsigned int ebitmap_next_positive(const struct ebitmap *e,
return ebitmap_length(e);
}
-#define EBITMAP_NODE_INDEX(node, bit) \
+#define EBITMAP_NODE_INDEX(node, bit) \
(((bit) - (node)->startbit) / EBITMAP_UNIT_SIZE)
-#define EBITMAP_NODE_OFFSET(node, bit) \
+#define EBITMAP_NODE_OFFSET(node, bit) \
(((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
-static inline int ebitmap_node_get_bit(const struct ebitmap_node *n,
- unsigned int bit)
+static inline int ebitmap_node_get_bit(const struct ebitmap_node *n, u32 bit)
{
- unsigned int index = EBITMAP_NODE_INDEX(n, bit);
- unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+ u32 index = EBITMAP_NODE_INDEX(n, bit);
+ u32 ofs = EBITMAP_NODE_OFFSET(n, bit);
BUG_ON(index >= EBITMAP_UNIT_NUMS);
if ((n->maps[index] & (EBITMAP_BIT << ofs)))
@@ -97,40 +97,41 @@ static inline int ebitmap_node_get_bit(const struct ebitmap_node *n,
return 0;
}
-static inline void ebitmap_node_set_bit(struct ebitmap_node *n,
- unsigned int bit)
+static inline void ebitmap_node_set_bit(struct ebitmap_node *n, u32 bit)
{
- unsigned int index = EBITMAP_NODE_INDEX(n, bit);
- unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+ u32 index = EBITMAP_NODE_INDEX(n, bit);
+ u32 ofs = EBITMAP_NODE_OFFSET(n, bit);
BUG_ON(index >= EBITMAP_UNIT_NUMS);
n->maps[index] |= (EBITMAP_BIT << ofs);
}
-static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
- unsigned int bit)
+static inline void ebitmap_node_clr_bit(struct ebitmap_node *n, u32 bit)
{
- unsigned int index = EBITMAP_NODE_INDEX(n, bit);
- unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit);
+ u32 index = EBITMAP_NODE_INDEX(n, bit);
+ u32 ofs = EBITMAP_NODE_OFFSET(n, bit);
BUG_ON(index >= EBITMAP_UNIT_NUMS);
n->maps[index] &= ~(EBITMAP_BIT << ofs);
}
-#define ebitmap_for_each_positive_bit(e, n, bit) \
- for ((bit) = ebitmap_start_positive(e, &(n)); \
- (bit) < ebitmap_length(e); \
- (bit) = ebitmap_next_positive(e, &(n), bit)) \
+#define ebitmap_for_each_positive_bit(e, n, bit) \
+ for ((bit) = ebitmap_start_positive(e, &(n)); \
+ (bit) < ebitmap_length(e); \
+ (bit) = ebitmap_next_positive(e, &(n), bit))
-int ebitmap_cmp(const struct ebitmap *e1, const struct ebitmap *e2);
+bool ebitmap_equal(const struct ebitmap *e1, const struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, const struct ebitmap *src);
-int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, const struct ebitmap *e2);
-int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, u32 last_e2bit);
-int ebitmap_get_bit(const struct ebitmap *e, unsigned long bit);
-int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
+int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1,
+ const struct ebitmap *e2);
+int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2,
+ u32 last_e2bit);
+int ebitmap_get_bit(const struct ebitmap *e, u32 bit);
+int ebitmap_set_bit(struct ebitmap *e, u32 bit, int value);
void ebitmap_destroy(struct ebitmap *e);
-int ebitmap_read(struct ebitmap *e, void *fp);
-int ebitmap_write(const struct ebitmap *e, void *fp);
+struct policy_file;
+int ebitmap_read(struct ebitmap *e, struct policy_file *fp);
+int ebitmap_write(const struct ebitmap *e, struct policy_file *fp);
u32 ebitmap_hash(const struct ebitmap *e, u32 hash);
#ifdef CONFIG_NETLABEL
@@ -151,4 +152,4 @@ static inline int ebitmap_netlbl_import(struct ebitmap *ebmap,
}
#endif
-#endif /* _SS_EBITMAP_H_ */
+#endif /* _SS_EBITMAP_H_ */
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c
index c05d8346a94a..383fd2d70878 100644
--- a/security/selinux/ss/hashtab.c
+++ b/security/selinux/ss/hashtab.c
@@ -4,6 +4,7 @@
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
+
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
@@ -47,8 +48,8 @@ int hashtab_init(struct hashtab *h, u32 nel_hint)
return 0;
}
-int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst,
- void *key, void *datum)
+int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst, void *key,
+ void *datum)
{
struct hashtab_node *newnode;
@@ -83,8 +84,7 @@ void hashtab_destroy(struct hashtab *h)
h->htable = NULL;
}
-int hashtab_map(struct hashtab *h,
- int (*apply)(void *k, void *d, void *args),
+int hashtab_map(struct hashtab *h, int (*apply)(void *k, void *d, void *args),
void *args)
{
u32 i;
@@ -136,12 +136,12 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
}
#endif /* CONFIG_SECURITY_SELINUX_DEBUG */
-int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
- int (*copy)(struct hashtab_node *new,
- struct hashtab_node *orig, void *args),
- int (*destroy)(void *k, void *d, void *args),
- void *args)
+int hashtab_duplicate(struct hashtab *new, const struct hashtab *orig,
+ int (*copy)(struct hashtab_node *new,
+ const struct hashtab_node *orig, void *args),
+ int (*destroy)(void *k, void *d, void *args), void *args)
{
+ const struct hashtab_node *orig_cur;
struct hashtab_node *cur, *tmp, *tail;
u32 i;
int rc;
@@ -156,12 +156,13 @@ int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
for (i = 0; i < orig->size; i++) {
tail = NULL;
- for (cur = orig->htable[i]; cur; cur = cur->next) {
+ for (orig_cur = orig->htable[i]; orig_cur;
+ orig_cur = orig_cur->next) {
tmp = kmem_cache_zalloc(hashtab_node_cachep,
GFP_KERNEL);
if (!tmp)
goto error;
- rc = copy(tmp, cur, args);
+ rc = copy(tmp, orig_cur, args);
if (rc) {
kmem_cache_free(hashtab_node_cachep, tmp);
goto error;
@@ -178,7 +179,7 @@ int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
return 0;
- error:
+error:
for (i = 0; i < new->size; i++) {
for (cur = new->htable[i]; cur; cur = tmp) {
tmp = cur->next;
@@ -193,7 +194,5 @@ int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
void __init hashtab_cache_init(void)
{
- hashtab_node_cachep = kmem_cache_create("hashtab_node",
- sizeof(struct hashtab_node),
- 0, SLAB_PANIC, NULL);
+ hashtab_node_cachep = KMEM_CACHE(hashtab_node, SLAB_PANIC);
}
diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h
index 09b0a3744937..deba82d78c3a 100644
--- a/security/selinux/ss/hashtab.h
+++ b/security/selinux/ss/hashtab.h
@@ -8,6 +8,7 @@
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
+
#ifndef _SS_HASHTAB_H_
#define _SS_HASHTAB_H_
@@ -15,12 +16,11 @@
#include <linux/errno.h>
#include <linux/sched.h>
-#define HASHTAB_MAX_NODES U32_MAX
+#define HASHTAB_MAX_NODES U32_MAX
struct hashtab_key_params {
- u32 (*hash)(const void *key); /* hash function */
- int (*cmp)(const void *key1, const void *key2);
- /* key comparison function */
+ u32 (*hash)(const void *key); /* hash func */
+ int (*cmp)(const void *key1, const void *key2); /* comparison func */
};
struct hashtab_node {
@@ -30,9 +30,9 @@ struct hashtab_node {
};
struct hashtab {
- struct hashtab_node **htable; /* hash table */
- u32 size; /* number of slots in hash table */
- u32 nel; /* number of elements in hash table */
+ struct hashtab_node **htable; /* hash table */
+ u32 size; /* number of slots in hash table */
+ u32 nel; /* number of elements in hash table */
};
struct hashtab_info {
@@ -48,8 +48,8 @@ struct hashtab_info {
*/
int hashtab_init(struct hashtab *h, u32 nel_hint);
-int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst,
- void *key, void *datum);
+int __hashtab_insert(struct hashtab *h, struct hashtab_node **dst, void *key,
+ void *datum);
/*
* Inserts the specified (key, datum) pair into the specified hash table.
@@ -84,8 +84,8 @@ static inline int hashtab_insert(struct hashtab *h, void *key, void *datum,
cur = cur->next;
}
- return __hashtab_insert(h, prev ? &prev->next : &h->htable[hvalue],
- key, datum);
+ return __hashtab_insert(h, prev ? &prev->next : &h->htable[hvalue], key,
+ datum);
}
/*
@@ -133,15 +133,13 @@ void hashtab_destroy(struct hashtab *h);
* iterating through the hash table and will propagate the error
* return to its caller.
*/
-int hashtab_map(struct hashtab *h,
- int (*apply)(void *k, void *d, void *args),
+int hashtab_map(struct hashtab *h, int (*apply)(void *k, void *d, void *args),
void *args);
-int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
- int (*copy)(struct hashtab_node *new,
- struct hashtab_node *orig, void *args),
- int (*destroy)(void *k, void *d, void *args),
- void *args);
+int hashtab_duplicate(struct hashtab *new, const struct hashtab *orig,
+ int (*copy)(struct hashtab_node *new,
+ const struct hashtab_node *orig, void *args),
+ int (*destroy)(void *k, void *d, void *args), void *args);
#ifdef CONFIG_SECURITY_SELINUX_DEBUG
/* Fill info with some hash table statistics */
@@ -149,7 +147,8 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info);
#else
static inline void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
{
+ return;
}
#endif
-#endif /* _SS_HASHTAB_H */
+#endif /* _SS_HASHTAB_H */
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index cd38f5913b63..a6e49269f535 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -4,19 +4,15 @@
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
+
/*
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ * Support for enhanced MLS infrastructure.
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
*
- * Support for enhanced MLS infrastructure.
- *
- * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
- */
-/*
* Updated: Hewlett-Packard <paul@paul-moore.com>
- *
- * Added support to import/export the MLS label from NetLabel
- *
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * Added support to import/export the MLS label from NetLabel
+ * Copyright (C) Hewlett-Packard Development Company, L.P., 2006
*/
#include <linux/kernel.h>
@@ -52,7 +48,8 @@ int mls_compute_context_len(struct policydb *p, struct context *context)
head = -2;
prev = -2;
e = &context->range.level[l].cat;
- ebitmap_for_each_positive_bit(e, node, i) {
+ ebitmap_for_each_positive_bit(e, node, i)
+ {
if (i - prev > 1) {
/* one or more negative bits are skipped */
if (head != prev) {
@@ -86,8 +83,7 @@ int mls_compute_context_len(struct policydb *p, struct context *context)
* the MLS fields of `context' into the string `*scontext'.
* Update `*scontext' to point to the end of the MLS fields.
*/
-void mls_sid_to_context(struct policydb *p,
- struct context *context,
+void mls_sid_to_context(struct policydb *p, struct context *context,
char **scontext)
{
char *scontextp, *nm;
@@ -112,7 +108,8 @@ void mls_sid_to_context(struct policydb *p,
head = -2;
prev = -2;
e = &context->range.level[l].cat;
- ebitmap_for_each_positive_bit(e, node, i) {
+ ebitmap_for_each_positive_bit(e, node, i)
+ {
if (i - prev > 1) {
/* one or more negative bits are skipped */
if (prev != head) {
@@ -174,7 +171,7 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l)
* levdatum->level->cat and no bit in l->cat is larger than
* p->p_cats.nprim.
*/
- return ebitmap_contains(&levdatum->level->cat, &l->cat,
+ return ebitmap_contains(&levdatum->level.cat, &l->cat,
p->p_cats.nprim);
}
@@ -230,12 +227,8 @@ int mls_context_isvalid(struct policydb *p, struct context *c)
* Policy read-lock must be held for sidtab lookup.
*
*/
-int mls_context_to_sid(struct policydb *pol,
- char oldc,
- char *scontext,
- struct context *context,
- struct sidtab *s,
- u32 def_sid)
+int mls_context_to_sid(struct policydb *pol, char oldc, char *scontext,
+ struct context *context, struct sidtab *s, u32 def_sid)
{
char *sensitivity, *cur_cat, *next_cat, *rngptr;
struct level_datum *levdatum;
@@ -296,7 +289,7 @@ int mls_context_to_sid(struct policydb *pol,
levdatum = symtab_search(&pol->p_levels, sensitivity);
if (!levdatum)
return -EINVAL;
- context->range.level[l].sens = levdatum->level->sens;
+ context->range.level[l].sens = levdatum->level.sens;
/* Extract category set. */
while (next_cat != NULL) {
@@ -333,7 +326,8 @@ int mls_context_to_sid(struct policydb *pol,
return -EINVAL;
for (i = catdatum->value; i < rngdatum->value; i++) {
- rc = ebitmap_set_bit(&context->range.level[l].cat, i, 1);
+ rc = ebitmap_set_bit(
+ &context->range.level[l].cat, i, 1);
if (rc)
return rc;
}
@@ -371,8 +365,8 @@ int mls_from_string(struct policydb *p, char *str, struct context *context,
if (!tmpstr) {
rc = -ENOMEM;
} else {
- rc = mls_context_to_sid(p, ':', tmpstr, context,
- NULL, SECSID_NULL);
+ rc = mls_context_to_sid(p, ':', tmpstr, context, NULL,
+ SECSID_NULL);
kfree(tmpstr);
}
@@ -382,8 +376,7 @@ int mls_from_string(struct policydb *p, char *str, struct context *context,
/*
* Copies the MLS range `range' into `context'.
*/
-int mls_range_set(struct context *context,
- struct mls_range *range)
+int mls_range_set(struct context *context, struct mls_range *range)
{
int l, rc = 0;
@@ -399,9 +392,8 @@ int mls_range_set(struct context *context,
return rc;
}
-int mls_setup_user_range(struct policydb *p,
- struct context *fromcon, struct user_datum *user,
- struct context *usercon)
+int mls_setup_user_range(struct policydb *p, struct context *fromcon,
+ struct user_datum *user, struct context *usercon)
{
if (p->mls_enabled) {
struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
@@ -444,10 +436,8 @@ int mls_setup_user_range(struct policydb *p,
* policy `oldp' to the values specified in the policy `newp',
* storing the resulting context in `newc'.
*/
-int mls_convert_context(struct policydb *oldp,
- struct policydb *newp,
- struct context *oldc,
- struct context *newc)
+int mls_convert_context(struct policydb *oldp, struct policydb *newp,
+ struct context *oldc, struct context *newc)
{
struct level_datum *levdatum;
struct cat_datum *catdatum;
@@ -466,10 +456,11 @@ int mls_convert_context(struct policydb *oldp,
if (!levdatum)
return -EINVAL;
- newc->range.level[l].sens = levdatum->level->sens;
+ newc->range.level[l].sens = levdatum->level.sens;
- ebitmap_for_each_positive_bit(&oldc->range.level[l].cat,
- node, i) {
+ ebitmap_for_each_positive_bit(&oldc->range.level[l].cat, node,
+ i)
+ {
int rc;
catdatum = symtab_search(&newp->p_cats,
@@ -486,13 +477,9 @@ int mls_convert_context(struct policydb *oldp,
return 0;
}
-int mls_compute_sid(struct policydb *p,
- struct context *scontext,
- struct context *tcontext,
- u16 tclass,
- u32 specified,
- struct context *newcontext,
- bool sock)
+int mls_compute_sid(struct policydb *p, struct context *scontext,
+ struct context *tcontext, u16 tclass, u32 specified,
+ struct context *newcontext, bool sock)
{
struct range_trans rtr;
struct mls_range *r;
@@ -532,8 +519,8 @@ int mls_compute_sid(struct policydb *p,
case DEFAULT_TARGET_LOW_HIGH:
return mls_context_cpy(newcontext, tcontext);
case DEFAULT_GLBLUB:
- return mls_context_glblub(newcontext,
- scontext, tcontext);
+ return mls_context_glblub(newcontext, scontext,
+ tcontext);
}
fallthrough;
@@ -563,8 +550,7 @@ int mls_compute_sid(struct policydb *p,
* NetLabel MLS sensitivity level field.
*
*/
-void mls_export_netlbl_lvl(struct policydb *p,
- struct context *context,
+void mls_export_netlbl_lvl(struct policydb *p, struct context *context,
struct netlbl_lsm_secattr *secattr)
{
if (!p->mls_enabled)
@@ -585,8 +571,7 @@ void mls_export_netlbl_lvl(struct policydb *p,
* NetLabel MLS sensitivity level into the context.
*
*/
-void mls_import_netlbl_lvl(struct policydb *p,
- struct context *context,
+void mls_import_netlbl_lvl(struct policydb *p, struct context *context,
struct netlbl_lsm_secattr *secattr)
{
if (!p->mls_enabled)
@@ -607,8 +592,7 @@ void mls_import_netlbl_lvl(struct policydb *p,
* MLS category field. Returns zero on success, negative values on failure.
*
*/
-int mls_export_netlbl_cat(struct policydb *p,
- struct context *context,
+int mls_export_netlbl_cat(struct policydb *p, struct context *context,
struct netlbl_lsm_secattr *secattr)
{
int rc;
@@ -637,8 +621,7 @@ int mls_export_netlbl_cat(struct policydb *p,
* negative values on failure.
*
*/
-int mls_import_netlbl_cat(struct policydb *p,
- struct context *context,
+int mls_import_netlbl_cat(struct policydb *p, struct context *context,
struct netlbl_lsm_secattr *secattr)
{
int rc;
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
index 107681dd1824..07980636751f 100644
--- a/security/selinux/ss/mls.h
+++ b/security/selinux/ss/mls.h
@@ -4,19 +4,15 @@
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
+
/*
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ * Support for enhanced MLS infrastructure.
+ * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
*
- * Support for enhanced MLS infrastructure.
- *
- * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
- */
-/*
* Updated: Hewlett-Packard <paul@paul-moore.com>
- *
- * Added support to import/export the MLS label from NetLabel
- *
- * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ * Added support to import/export the MLS label from NetLabel
+ * Copyright (X) Hewlett-Packard Development Company, L.P., 2006
*/
#ifndef _SS_MLS_H_
@@ -35,47 +31,32 @@ int mls_context_isvalid(struct policydb *p, struct context *c);
int mls_range_isvalid(struct policydb *p, struct mls_range *r);
int mls_level_isvalid(struct policydb *p, struct mls_level *l);
-int mls_context_to_sid(struct policydb *p,
- char oldc,
- char *scontext,
- struct context *context,
- struct sidtab *s,
- u32 def_sid);
+int mls_context_to_sid(struct policydb *p, char oldc, char *scontext,
+ struct context *context, struct sidtab *s, u32 def_sid);
int mls_from_string(struct policydb *p, char *str, struct context *context,
gfp_t gfp_mask);
int mls_range_set(struct context *context, struct mls_range *range);
-int mls_convert_context(struct policydb *oldp,
- struct policydb *newp,
- struct context *oldc,
- struct context *newc);
+int mls_convert_context(struct policydb *oldp, struct policydb *newp,
+ struct context *oldc, struct context *newc);
-int mls_compute_sid(struct policydb *p,
- struct context *scontext,
- struct context *tcontext,
- u16 tclass,
- u32 specified,
- struct context *newcontext,
- bool sock);
+int mls_compute_sid(struct policydb *p, struct context *scontext,
+ struct context *tcontext, u16 tclass, u32 specified,
+ struct context *newcontext, bool sock);
-int mls_setup_user_range(struct policydb *p,
- struct context *fromcon, struct user_datum *user,
- struct context *usercon);
+int mls_setup_user_range(struct policydb *p, struct context *fromcon,
+ struct user_datum *user, struct context *usercon);
#ifdef CONFIG_NETLABEL
-void mls_export_netlbl_lvl(struct policydb *p,
- struct context *context,
+void mls_export_netlbl_lvl(struct policydb *p, struct context *context,
struct netlbl_lsm_secattr *secattr);
-void mls_import_netlbl_lvl(struct policydb *p,
- struct context *context,
+void mls_import_netlbl_lvl(struct policydb *p, struct context *context,
struct netlbl_lsm_secattr *secattr);
-int mls_export_netlbl_cat(struct policydb *p,
- struct context *context,
+int mls_export_netlbl_cat(struct policydb *p, struct context *context,
struct netlbl_lsm_secattr *secattr);
-int mls_import_netlbl_cat(struct policydb *p,
- struct context *context,
+int mls_import_netlbl_cat(struct policydb *p, struct context *context,
struct netlbl_lsm_secattr *secattr);
#else
static inline void mls_export_netlbl_lvl(struct policydb *p,
@@ -112,5 +93,4 @@ static inline u32 mls_range_hash(const struct mls_range *r, u32 hash)
return hash;
}
-#endif /* _SS_MLS_H */
-
+#endif /* _SS_MLS_H */
diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h
index f492cf148891..51df2ebd1211 100644
--- a/security/selinux/ss/mls_types.h
+++ b/security/selinux/ss/mls_types.h
@@ -4,12 +4,11 @@
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
+
/*
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
- *
- * Support for enhanced MLS infrastructure.
- *
- * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
+ * Support for enhanced MLS infrastructure.
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
*/
#ifndef _SS_MLS_TYPES_H_
@@ -19,34 +18,35 @@
#include "ebitmap.h"
struct mls_level {
- u32 sens; /* sensitivity */
- struct ebitmap cat; /* category set */
+ u32 sens; /* sensitivity */
+ struct ebitmap cat; /* category set */
};
struct mls_range {
struct mls_level level[2]; /* low == level[0], high == level[1] */
};
-static inline int mls_level_eq(const struct mls_level *l1, const struct mls_level *l2)
+static inline int mls_level_eq(const struct mls_level *l1,
+ const struct mls_level *l2)
{
- return ((l1->sens == l2->sens) &&
- ebitmap_cmp(&l1->cat, &l2->cat));
+ return ((l1->sens == l2->sens) && ebitmap_equal(&l1->cat, &l2->cat));
}
-static inline int mls_level_dom(const struct mls_level *l1, const struct mls_level *l2)
+static inline int mls_level_dom(const struct mls_level *l1,
+ const struct mls_level *l2)
{
return ((l1->sens >= l2->sens) &&
ebitmap_contains(&l1->cat, &l2->cat, 0));
}
#define mls_level_incomp(l1, l2) \
-(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1)))
+ (!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1)))
#define mls_level_between(l1, l2, l3) \
-(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1)))
+ (mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1)))
-#define mls_range_contains(r1, r2) \
-(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \
- mls_level_dom(&(r1).level[1], &(r2).level[1]))
+#define mls_range_contains(r1, r2) \
+ (mls_level_dom(&(r2).level[0], &(r1).level[0]) && \
+ mls_level_dom(&(r1).level[1], &(r2).level[1]))
-#endif /* _SS_MLS_TYPES_H_ */
+#endif /* _SS_MLS_TYPES_H_ */
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 3b19ad28c922..9ea971943713 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -7,25 +7,21 @@
/*
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ * Support for enhanced MLS infrastructure.
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
*
- * Support for enhanced MLS infrastructure.
- *
- * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
- *
- * Added conditional policy language extensions
+ * Updated: Frank Mayer <mayerf@tresys.com> and
+ * Karl MacMillan <kmacmillan@tresys.com>
+ * Added conditional policy language extensions
+ * Copyright (C) 2003-2004 Tresys Technology, LLC
*
* Updated: Hewlett-Packard <paul@paul-moore.com>
- *
- * Added support for the policy capability bitmap
+ * Added support for the policy capability bitmap
+ * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
*
* Update: Mellanox Techonologies
- *
- * Added Infiniband support
- *
- * Copyright (C) 2016 Mellanox Techonologies
- * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
- * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
- * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Added Infiniband support
+ * Copyright (C) 2016 Mellanox Techonologies
*/
#include <linux/kernel.h>
@@ -42,6 +38,7 @@
#include "services.h"
#ifdef CONFIG_SECURITY_SELINUX_DEBUG
+/* clang-format off */
static const char *const symtab_name[SYM_NUM] = {
"common prefixes",
"classes",
@@ -52,6 +49,7 @@ static const char *const symtab_name[SYM_NUM] = {
"levels",
"categories",
};
+/* clang-format off */
#endif
struct policydb_compat_info {
@@ -63,103 +61,109 @@ struct policydb_compat_info {
/* These need to be updated if SYM_NUM or OCON_NUM changes */
static const struct policydb_compat_info policydb_compat[] = {
{
- .version = POLICYDB_VERSION_BASE,
- .sym_num = SYM_NUM - 3,
- .ocon_num = OCON_NUM - 3,
+ .version = POLICYDB_VERSION_BASE,
+ .sym_num = SYM_NUM - 3,
+ .ocon_num = OCON_NUM - 3,
},
{
- .version = POLICYDB_VERSION_BOOL,
- .sym_num = SYM_NUM - 2,
- .ocon_num = OCON_NUM - 3,
+ .version = POLICYDB_VERSION_BOOL,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_NUM - 3,
},
{
- .version = POLICYDB_VERSION_IPV6,
- .sym_num = SYM_NUM - 2,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_IPV6,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_NLCLASS,
- .sym_num = SYM_NUM - 2,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_NLCLASS,
+ .sym_num = SYM_NUM - 2,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_MLS,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_MLS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_AVTAB,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_AVTAB,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_RANGETRANS,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_RANGETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_POLCAP,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_POLCAP,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_PERMISSIVE,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_PERMISSIVE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_BOUNDARY,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_BOUNDARY,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_FILENAME_TRANS,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_FILENAME_TRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_ROLETRANS,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_ROLETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_DEFAULT_TYPE,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_DEFAULT_TYPE,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_CONSTRAINT_NAMES,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_CONSTRAINT_NAMES,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_XPERMS_IOCTL,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM - 2,
+ .version = POLICYDB_VERSION_XPERMS_IOCTL,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM - 2,
},
{
- .version = POLICYDB_VERSION_INFINIBAND,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM,
+ .version = POLICYDB_VERSION_INFINIBAND,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
},
{
- .version = POLICYDB_VERSION_GLBLUB,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM,
+ .version = POLICYDB_VERSION_GLBLUB,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
},
{
- .version = POLICYDB_VERSION_COMP_FTRANS,
- .sym_num = SYM_NUM,
- .ocon_num = OCON_NUM,
+ .version = POLICYDB_VERSION_COMP_FTRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
+ {
+ .version = POLICYDB_VERSION_COND_XPERMS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
},
};
-static const struct policydb_compat_info *policydb_lookup_compat(unsigned int version)
+static const struct policydb_compat_info *
+policydb_lookup_compat(unsigned int version)
{
unsigned int i;
@@ -297,9 +301,7 @@ static int sens_destroy(void *key, void *datum, void *p)
kfree(key);
if (datum) {
levdatum = datum;
- if (levdatum->level)
- ebitmap_destroy(&levdatum->level->cat);
- kfree(levdatum->level);
+ ebitmap_destroy(&levdatum->level.cat);
}
kfree(datum);
return 0;
@@ -312,7 +314,8 @@ static int cat_destroy(void *key, void *datum, void *p)
return 0;
}
-static int (*const destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
+/* clang-format off */
+static int (*const destroy_f[SYM_NUM])(void *key, void *datum, void *datap) = {
common_destroy,
cls_destroy,
role_destroy,
@@ -322,6 +325,7 @@ static int (*const destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
sens_destroy,
cat_destroy,
};
+/* clang-format on */
static int filenametr_destroy(void *key, void *datum, void *p)
{
@@ -366,8 +370,8 @@ static void ocontext_destroy(struct ocontext *c, unsigned int i)
context_destroy(&c->context[0]);
context_destroy(&c->context[1]);
- if (i == OCON_ISID || i == OCON_FS ||
- i == OCON_NETIF || i == OCON_FSUSE)
+ if (i == OCON_ISID || i == OCON_FS || i == OCON_NETIF ||
+ i == OCON_FSUSE)
kfree(c->u.name);
kfree(c);
}
@@ -429,7 +433,6 @@ static int filenametr_cmp(const void *k1, const void *k2)
return v;
return strcmp(ft1->name, ft2->name);
-
}
static const struct hashtab_key_params filenametr_key_params = {
@@ -437,8 +440,8 @@ static const struct hashtab_key_params filenametr_key_params = {
.cmp = filenametr_cmp,
};
-struct filename_trans_datum *policydb_filenametr_search(
- struct policydb *p, struct filename_trans_key *key)
+struct filename_trans_datum *
+policydb_filenametr_search(struct policydb *p, struct filename_trans_key *key)
{
return hashtab_search(&p->filename_trans, key, filenametr_key_params);
}
@@ -448,7 +451,7 @@ static u32 rangetr_hash(const void *k)
const struct range_trans *key = k;
return key->source_type + (key->target_type << 3) +
- (key->target_class << 5);
+ (key->target_class << 5);
}
static int rangetr_cmp(const void *k1, const void *k2)
@@ -484,7 +487,8 @@ static u32 role_trans_hash(const void *k)
{
const struct role_trans_key *key = k;
- return jhash_3words(key->role, key->type, (u32)key->tclass << 16 | key->tclass, 0);
+ return jhash_3words(key->role, key->type,
+ (u32)key->tclass << 16 | key->tclass, 0);
}
static int role_trans_cmp(const void *k1, const void *k2)
@@ -576,9 +580,8 @@ static int role_index(void *key, void *datum, void *datap)
role = datum;
p = datap;
- if (!role->value
- || role->value > p->p_roles.nprim
- || role->bounds > p->p_roles.nprim)
+ if (!role->value || role->value > p->p_roles.nprim ||
+ role->bounds > p->p_roles.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_ROLES][role->value - 1] = key;
@@ -595,9 +598,8 @@ static int type_index(void *key, void *datum, void *datap)
p = datap;
if (typdatum->primary) {
- if (!typdatum->value
- || typdatum->value > p->p_types.nprim
- || typdatum->bounds > p->p_types.nprim)
+ if (!typdatum->value || typdatum->value > p->p_types.nprim ||
+ typdatum->bounds > p->p_types.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key;
p->type_val_to_struct[typdatum->value - 1] = typdatum;
@@ -613,9 +615,8 @@ static int user_index(void *key, void *datum, void *datap)
usrdatum = datum;
p = datap;
- if (!usrdatum->value
- || usrdatum->value > p->p_users.nprim
- || usrdatum->bounds > p->p_users.nprim)
+ if (!usrdatum->value || usrdatum->value > p->p_users.nprim ||
+ usrdatum->bounds > p->p_users.nprim)
return -EINVAL;
p->sym_val_to_name[SYM_USERS][usrdatum->value - 1] = key;
@@ -632,11 +633,11 @@ static int sens_index(void *key, void *datum, void *datap)
p = datap;
if (!levdatum->isalias) {
- if (!levdatum->level->sens ||
- levdatum->level->sens > p->p_levels.nprim)
+ if (!levdatum->level.sens ||
+ levdatum->level.sens > p->p_levels.nprim)
return -EINVAL;
- p->sym_val_to_name[SYM_LEVELS][levdatum->level->sens - 1] = key;
+ p->sym_val_to_name[SYM_LEVELS][levdatum->level.sens - 1] = key;
}
return 0;
@@ -660,7 +661,8 @@ static int cat_index(void *key, void *datum, void *datap)
return 0;
}
-static int (*const index_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
+/* clang-format off */
+static int (*const index_f[SYM_NUM])(void *key, void *datum, void *datap) = {
common_index,
class_index,
role_index,
@@ -670,16 +672,20 @@ static int (*const index_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
sens_index,
cat_index,
};
+/* clang-format on */
#ifdef CONFIG_SECURITY_SELINUX_DEBUG
-static void hash_eval(struct hashtab *h, const char *hash_name)
+static void hash_eval(struct hashtab *h, const char *hash_name,
+ const char *hash_details)
{
struct hashtab_info info;
hashtab_stat(h, &info);
- pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d, sum of chain length^2 %llu\n",
- hash_name, h->nel, info.slots_used, h->size,
- info.max_chain_len, info.chain2_len_sum);
+ pr_debug(
+ "SELinux: %s%s%s: %d entries and %d/%d buckets used, longest chain length %d, sum of chain length^2 %llu\n",
+ hash_name, hash_details ? "@" : "", hash_details ?: "", h->nel,
+ info.slots_used, h->size, info.max_chain_len,
+ info.chain2_len_sum);
}
static void symtab_hash_eval(struct symtab *s)
@@ -687,11 +693,12 @@ static void symtab_hash_eval(struct symtab *s)
int i;
for (i = 0; i < SYM_NUM; i++)
- hash_eval(&s[i].table, symtab_name[i]);
+ hash_eval(&s[i].table, symtab_name[i], NULL);
}
#else
-static inline void hash_eval(struct hashtab *h, const char *hash_name)
+static inline void hash_eval(struct hashtab *h, const char *hash_name,
+ const char *hash_details)
{
}
static inline void symtab_hash_eval(struct symtab *s)
@@ -710,16 +717,17 @@ static int policydb_index(struct policydb *p)
int i, rc;
if (p->mls_enabled)
- pr_debug("SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n",
- p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
- p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim);
+ pr_debug(
+ "SELinux: %d users, %d roles, %d types, %d bools, %d sens, %d cats\n",
+ p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
+ p->p_bools.nprim, p->p_levels.nprim, p->p_cats.nprim);
else
pr_debug("SELinux: %d users, %d roles, %d types, %d bools\n",
p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim,
p->p_bools.nprim);
- pr_debug("SELinux: %d classes, %d rules\n",
- p->p_classes.nprim, p->te_avtab.nel);
+ pr_debug("SELinux: %d classes, %d rules\n", p->p_classes.nprim,
+ p->te_avtab.nel);
avtab_hash_eval(&p->te_avtab, "rules");
symtab_hash_eval(p->symtab);
@@ -730,21 +738,18 @@ static int policydb_index(struct policydb *p)
if (!p->class_val_to_struct)
return -ENOMEM;
- p->role_val_to_struct = kcalloc(p->p_roles.nprim,
- sizeof(*p->role_val_to_struct),
- GFP_KERNEL);
+ p->role_val_to_struct = kcalloc(
+ p->p_roles.nprim, sizeof(*p->role_val_to_struct), GFP_KERNEL);
if (!p->role_val_to_struct)
return -ENOMEM;
- p->user_val_to_struct = kcalloc(p->p_users.nprim,
- sizeof(*p->user_val_to_struct),
- GFP_KERNEL);
+ p->user_val_to_struct = kcalloc(
+ p->p_users.nprim, sizeof(*p->user_val_to_struct), GFP_KERNEL);
if (!p->user_val_to_struct)
return -ENOMEM;
- p->type_val_to_struct = kvcalloc(p->p_types.nprim,
- sizeof(*p->type_val_to_struct),
- GFP_KERNEL);
+ p->type_val_to_struct = kvcalloc(
+ p->p_types.nprim, sizeof(*p->type_val_to_struct), GFP_KERNEL);
if (!p->type_val_to_struct)
return -ENOMEM;
@@ -754,8 +759,7 @@ static int policydb_index(struct policydb *p)
for (i = 0; i < SYM_NUM; i++) {
p->sym_val_to_name[i] = kvcalloc(p->symtab[i].nprim,
- sizeof(char *),
- GFP_KERNEL);
+ sizeof(char *), GFP_KERNEL);
if (!p->sym_val_to_name[i])
return -ENOMEM;
@@ -857,8 +861,7 @@ void policydb_destroy(struct policydb *p)
int policydb_load_isids(struct policydb *p, struct sidtab *s)
{
struct ocontext *head, *c;
- bool isid_init_supported = ebitmap_get_bit(&p->policycaps,
- POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT);
+ bool isid_init;
int rc;
rc = sidtab_init(s);
@@ -867,6 +870,9 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)
return rc;
}
+ isid_init = ebitmap_get_bit(&p->policycaps,
+ POLICYDB_CAP_USERSPACE_INITIAL_CONTEXT);
+
head = p->ocontexts[OCON_ISID];
for (c = head; c; c = c->next) {
u32 sid = c->sid[0];
@@ -886,7 +892,7 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)
* Also ignore SECINITSID_INIT if the policy doesn't declare
* support for it
*/
- if (sid == SECINITSID_INIT && !isid_init_supported)
+ if (sid == SECINITSID_INIT && !isid_init)
continue;
rc = sidtab_set_initial(s, sid, &c->context[0]);
@@ -905,8 +911,9 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)
* started before policy load would initially get the context
* corresponding to SECINITSID_KERNEL.
*/
- if (sid == SECINITSID_KERNEL && !isid_init_supported) {
- rc = sidtab_set_initial(s, SECINITSID_INIT, &c->context[0]);
+ if (sid == SECINITSID_KERNEL && !isid_init) {
+ rc = sidtab_set_initial(s, SECINITSID_INIT,
+ &c->context[0]);
if (rc) {
pr_err("SELinux: unable to load initial SID %s.\n",
name);
@@ -988,7 +995,7 @@ int policydb_context_isvalid(struct policydb *p, struct context *c)
* Read a MLS range structure from a policydb binary
* representation file.
*/
-static int mls_read_range_helper(struct mls_range *r, void *fp)
+static int mls_read_range_helper(struct mls_range *r, struct policy_file *fp)
{
__le32 buf[2];
u32 items;
@@ -1047,9 +1054,8 @@ out:
* Read and validate a security context structure
* from a policydb binary representation file.
*/
-static int context_read_and_validate(struct context *c,
- struct policydb *p,
- void *fp)
+static int context_read_and_validate(struct context *c, struct policydb *p,
+ struct policy_file *fp)
{
__le32 buf[3];
int rc;
@@ -1087,7 +1093,7 @@ out:
* binary representation file.
*/
-static int str_read(char **strp, gfp_t flags, void *fp, u32 len)
+int str_read(char **strp, gfp_t flags, struct policy_file *fp, u32 len)
{
int rc;
char *str;
@@ -1110,7 +1116,7 @@ static int str_read(char **strp, gfp_t flags, void *fp, u32 len)
return 0;
}
-static int perm_read(struct policydb *p, struct symtab *s, void *fp)
+static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *fp)
{
char *key = NULL;
struct perm_datum *perdatum;
@@ -1143,7 +1149,7 @@ bad:
return rc;
}
-static int common_read(struct policydb *p, struct symtab *s, void *fp)
+static int common_read(struct policydb *p, struct symtab *s, struct policy_file *fp)
{
char *key = NULL;
struct common_datum *comdatum;
@@ -1178,6 +1184,8 @@ static int common_read(struct policydb *p, struct symtab *s, void *fp)
goto bad;
}
+ hash_eval(&comdatum->permissions.table, "common_permissions", key);
+
rc = symtab_insert(s, key, comdatum);
if (rc)
goto bad;
@@ -1193,7 +1201,7 @@ static void type_set_init(struct type_set *t)
ebitmap_init(&t->negset);
}
-static int type_set_read(struct type_set *t, void *fp)
+static int type_set_read(struct type_set *t, struct policy_file *fp)
{
__le32 buf[1];
int rc;
@@ -1211,10 +1219,8 @@ static int type_set_read(struct type_set *t, void *fp)
return 0;
}
-
-static int read_cons_helper(struct policydb *p,
- struct constraint_node **nodep,
- u32 ncons, int allowxtarget, void *fp)
+static int read_cons_helper(struct policydb *p, struct constraint_node **nodep,
+ u32 ncons, int allowxtarget, struct policy_file *fp)
{
struct constraint_node *c, *lc;
struct constraint_expr *e, *le;
@@ -1284,8 +1290,9 @@ static int read_cons_helper(struct policydb *p,
return rc;
if (p->policyvers >=
POLICYDB_VERSION_CONSTRAINT_NAMES) {
- e->type_names = kzalloc(sizeof
- (*e->type_names), GFP_KERNEL);
+ e->type_names =
+ kzalloc(sizeof(*e->type_names),
+ GFP_KERNEL);
if (!e->type_names)
return -ENOMEM;
type_set_init(e->type_names);
@@ -1307,7 +1314,7 @@ static int read_cons_helper(struct policydb *p,
return 0;
}
-static int class_read(struct policydb *p, struct symtab *s, void *fp)
+static int class_read(struct policydb *p, struct symtab *s, struct policy_file *fp)
{
char *key = NULL;
struct class_datum *cladatum;
@@ -1319,7 +1326,7 @@ static int class_read(struct policydb *p, struct symtab *s, void *fp)
if (!cladatum)
return -ENOMEM;
- rc = next_entry(buf, fp, sizeof(u32)*6);
+ rc = next_entry(buf, fp, sizeof(u32) * 6);
if (rc)
goto bad;
@@ -1345,8 +1352,8 @@ static int class_read(struct policydb *p, struct symtab *s, void *fp)
goto bad;
rc = -EINVAL;
- cladatum->comdatum = symtab_search(&p->p_commons,
- cladatum->comkey);
+ cladatum->comdatum =
+ symtab_search(&p->p_commons, cladatum->comkey);
if (!cladatum->comdatum) {
pr_err("SELinux: unknown common %s\n",
cladatum->comkey);
@@ -1359,6 +1366,8 @@ static int class_read(struct policydb *p, struct symtab *s, void *fp)
goto bad;
}
+ hash_eval(&cladatum->permissions.table, "class_permissions", key);
+
rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);
if (rc)
goto bad;
@@ -1369,8 +1378,8 @@ static int class_read(struct policydb *p, struct symtab *s, void *fp)
if (rc)
goto bad;
ncons = le32_to_cpu(buf[0]);
- rc = read_cons_helper(p, &cladatum->validatetrans,
- ncons, 1, fp);
+ rc = read_cons_helper(p, &cladatum->validatetrans, ncons, 1,
+ fp);
if (rc)
goto bad;
}
@@ -1402,7 +1411,7 @@ bad:
return rc;
}
-static int role_read(struct policydb *p, struct symtab *s, void *fp)
+static int role_read(struct policydb *p, struct symtab *s, struct policy_file *fp)
{
char *key = NULL;
struct role_datum *role;
@@ -1459,7 +1468,7 @@ bad:
return rc;
}
-static int type_read(struct policydb *p, struct symtab *s, void *fp)
+static int type_read(struct policydb *p, struct symtab *s, struct policy_file *fp)
{
char *key = NULL;
struct type_datum *typdatum;
@@ -1507,12 +1516,11 @@ bad:
return rc;
}
-
/*
* Read a MLS level structure from a policydb binary
* representation file.
*/
-static int mls_read_level(struct mls_level *lp, void *fp)
+static int mls_read_level(struct mls_level *lp, struct policy_file *fp)
{
__le32 buf[1];
int rc;
@@ -1534,7 +1542,7 @@ static int mls_read_level(struct mls_level *lp, void *fp)
return 0;
}
-static int user_read(struct policydb *p, struct symtab *s, void *fp)
+static int user_read(struct policydb *p, struct symtab *s, struct policy_file *fp)
{
char *key = NULL;
struct user_datum *usrdatum;
@@ -1585,7 +1593,7 @@ bad:
return rc;
}
-static int sens_read(struct policydb *p, struct symtab *s, void *fp)
+static int sens_read(struct policydb *p, struct symtab *s, struct policy_file *fp)
{
char *key = NULL;
struct level_datum *levdatum;
@@ -1608,12 +1616,7 @@ static int sens_read(struct policydb *p, struct symtab *s, void *fp)
if (rc)
goto bad;
- rc = -ENOMEM;
- levdatum->level = kmalloc(sizeof(*levdatum->level), GFP_KERNEL);
- if (!levdatum->level)
- goto bad;
-
- rc = mls_read_level(levdatum->level, fp);
+ rc = mls_read_level(&levdatum->level, fp);
if (rc)
goto bad;
@@ -1626,7 +1629,7 @@ bad:
return rc;
}
-static int cat_read(struct policydb *p, struct symtab *s, void *fp)
+static int cat_read(struct policydb *p, struct symtab *s, struct policy_file *fp)
{
char *key = NULL;
struct cat_datum *catdatum;
@@ -1659,8 +1662,9 @@ bad:
return rc;
}
-static int (*const read_f[SYM_NUM]) (struct policydb *p,
- struct symtab *s, void *fp) = {
+/* clang-format off */
+static int (*const read_f[SYM_NUM])(struct policydb *p, struct symtab *s,
+ struct policy_file *fp) = {
common_read,
class_read,
role_read,
@@ -1670,6 +1674,7 @@ static int (*const read_f[SYM_NUM]) (struct policydb *p,
sens_read,
cat_read,
};
+/* clang-format on */
static int user_bounds_sanity_check(void *key, void *datum, void *datap)
{
@@ -1685,12 +1690,13 @@ static int user_bounds_sanity_check(void *key, void *datum, void *datap)
if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
pr_err("SELinux: user %s: "
"too deep or looped boundary\n",
- (char *) key);
+ (char *)key);
return -EINVAL;
}
upper = p->user_val_to_struct[upper->bounds - 1];
- ebitmap_for_each_positive_bit(&user->roles, node, bit) {
+ ebitmap_for_each_positive_bit(&user->roles, node, bit)
+ {
if (ebitmap_get_bit(&upper->roles, bit))
continue;
@@ -1721,12 +1727,13 @@ static int role_bounds_sanity_check(void *key, void *datum, void *datap)
if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
pr_err("SELinux: role %s: "
"too deep or looped bounds\n",
- (char *) key);
+ (char *)key);
return -EINVAL;
}
upper = p->role_val_to_struct[upper->bounds - 1];
- ebitmap_for_each_positive_bit(&role->types, node, bit) {
+ ebitmap_for_each_positive_bit(&role->types, node, bit)
+ {
if (ebitmap_get_bit(&upper->types, bit))
continue;
@@ -1754,7 +1761,7 @@ static int type_bounds_sanity_check(void *key, void *datum, void *datap)
if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
pr_err("SELinux: type %s: "
"too deep or looped boundary\n",
- (char *) key);
+ (char *)key);
return -EINVAL;
}
@@ -1764,7 +1771,7 @@ static int type_bounds_sanity_check(void *key, void *datum, void *datap)
if (upper->attribute) {
pr_err("SELinux: type %s: "
"bounded by attribute %s\n",
- (char *) key,
+ (char *)key,
sym_name(p, SYM_TYPES, upper->value - 1));
return -EINVAL;
}
@@ -1815,7 +1822,7 @@ u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name)
if (!tclass || tclass > p->p_classes.nprim)
return 0;
- cladatum = p->class_val_to_struct[tclass-1];
+ cladatum = p->class_val_to_struct[tclass - 1];
comdatum = cladatum->comdatum;
if (comdatum)
perdatum = symtab_search(&comdatum->permissions, name);
@@ -1824,10 +1831,10 @@ u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name)
if (!perdatum)
return 0;
- return 1U << (perdatum->value-1);
+ return 1U << (perdatum->value - 1);
}
-static int range_read(struct policydb *p, void *fp)
+static int range_read(struct policydb *p, struct policy_file *fp)
{
struct range_trans *rt = NULL;
struct mls_range *r = NULL;
@@ -1896,7 +1903,7 @@ static int range_read(struct policydb *p, void *fp)
rt = NULL;
r = NULL;
}
- hash_eval(&p->range_tr, "rangetr");
+ hash_eval(&p->range_tr, "rangetr", NULL);
rc = 0;
out:
kfree(rt);
@@ -1904,7 +1911,7 @@ out:
return rc;
}
-static int filename_trans_read_helper_compat(struct policydb *p, void *fp)
+static int filename_trans_read_helper_compat(struct policydb *p, struct policy_file *fp)
{
struct filename_trans_key key, *ft = NULL;
struct filename_trans_datum *last, *datum = NULL;
@@ -1941,6 +1948,7 @@ static int filename_trans_read_helper_compat(struct policydb *p, void *fp)
if (unlikely(ebitmap_get_bit(&datum->stypes, stype - 1))) {
/* conflicting/duplicate rules are ignored */
datum = NULL;
+ rc = 0;
goto out;
}
if (likely(datum->otype == otype))
@@ -1988,7 +1996,7 @@ out:
return rc;
}
-static int filename_trans_read_helper(struct policydb *p, void *fp)
+static int filename_trans_read_helper(struct policydb *p, struct policy_file *fp)
{
struct filename_trans_key *ft = NULL;
struct filename_trans_datum **dst, *datum, *first = NULL;
@@ -2077,7 +2085,7 @@ out:
return rc;
}
-static int filename_trans_read(struct policydb *p, void *fp)
+static int filename_trans_read(struct policydb *p, struct policy_file *fp)
{
u32 nel, i;
__le32 buf[1];
@@ -2114,11 +2122,11 @@ static int filename_trans_read(struct policydb *p, void *fp)
return rc;
}
}
- hash_eval(&p->filename_trans, "filenametr");
+ hash_eval(&p->filename_trans, "filenametr", NULL);
return 0;
}
-static int genfs_read(struct policydb *p, void *fp)
+static int genfs_read(struct policydb *p, struct policy_file *fp)
{
int rc;
u32 i, j, nel, nel2, len, len2;
@@ -2192,12 +2200,12 @@ static int genfs_read(struct policydb *p, void *fp)
goto out;
newc->v.sclass = le32_to_cpu(buf[0]);
- rc = context_read_and_validate(&newc->context[0], p, fp);
+ rc = context_read_and_validate(&newc->context[0], p,
+ fp);
if (rc)
goto out;
- for (l = NULL, c = genfs->head; c;
- l = c, c = c->next) {
+ for (l = NULL, c = genfs->head; c; l = c, c = c->next) {
rc = -EINVAL;
if (!strcmp(newc->u.name, c->u.name) &&
(!c->v.sclass || !newc->v.sclass ||
@@ -2231,8 +2239,8 @@ out:
return rc;
}
-static int ocontext_read(struct policydb *p, const struct policydb_compat_info *info,
- void *fp)
+static int ocontext_read(struct policydb *p,
+ const struct policydb_compat_info *info, struct policy_file *fp)
{
int rc;
unsigned int i;
@@ -2267,7 +2275,8 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info *
goto out;
c->sid[0] = le32_to_cpu(buf[0]);
- rc = context_read_and_validate(&c->context[0], p, fp);
+ rc = context_read_and_validate(&c->context[0],
+ p, fp);
if (rc)
goto out;
break;
@@ -2286,21 +2295,24 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info *
pr_warn("SELinux: void and deprecated fs ocon %s\n",
c->u.name);
- rc = context_read_and_validate(&c->context[0], p, fp);
+ rc = context_read_and_validate(&c->context[0],
+ p, fp);
if (rc)
goto out;
- rc = context_read_and_validate(&c->context[1], p, fp);
+ rc = context_read_and_validate(&c->context[1],
+ p, fp);
if (rc)
goto out;
break;
case OCON_PORT:
- rc = next_entry(buf, fp, sizeof(u32)*3);
+ rc = next_entry(buf, fp, sizeof(u32) * 3);
if (rc)
goto out;
c->u.port.protocol = le32_to_cpu(buf[0]);
c->u.port.low_port = le32_to_cpu(buf[1]);
c->u.port.high_port = le32_to_cpu(buf[2]);
- rc = context_read_and_validate(&c->context[0], p, fp);
+ rc = context_read_and_validate(&c->context[0],
+ p, fp);
if (rc)
goto out;
break;
@@ -2310,12 +2322,13 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info *
goto out;
c->u.node.addr = nodebuf[0]; /* network order */
c->u.node.mask = nodebuf[1]; /* network order */
- rc = context_read_and_validate(&c->context[0], p, fp);
+ rc = context_read_and_validate(&c->context[0],
+ p, fp);
if (rc)
goto out;
break;
case OCON_FSUSE:
- rc = next_entry(buf, fp, sizeof(u32)*2);
+ rc = next_entry(buf, fp, sizeof(u32) * 2);
if (rc)
goto out;
@@ -2332,7 +2345,8 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info *
if (rc)
goto out;
- rc = context_read_and_validate(&c->context[0], p, fp);
+ rc = context_read_and_validate(&c->context[0],
+ p, fp);
if (rc)
goto out;
break;
@@ -2345,8 +2359,9 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info *
for (k = 0; k < 4; k++)
c->u.node6.addr[k] = nodebuf[k];
for (k = 0; k < 4; k++)
- c->u.node6.mask[k] = nodebuf[k+4];
- rc = context_read_and_validate(&c->context[0], p, fp);
+ c->u.node6.mask[k] = nodebuf[k + 4];
+ rc = context_read_and_validate(&c->context[0],
+ p, fp);
if (rc)
goto out;
break;
@@ -2359,7 +2374,8 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info *
goto out;
/* we need to have subnet_prefix in CPU order */
- c->u.ibpkey.subnet_prefix = be64_to_cpu(prefixbuf[0]);
+ c->u.ibpkey.subnet_prefix =
+ be64_to_cpu(prefixbuf[0]);
rc = next_entry(buf, fp, sizeof(u32) * 2);
if (rc)
@@ -2373,12 +2389,11 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info *
goto out;
}
- c->u.ibpkey.low_pkey = pkey_lo;
+ c->u.ibpkey.low_pkey = pkey_lo;
c->u.ibpkey.high_pkey = pkey_hi;
rc = context_read_and_validate(&c->context[0],
- p,
- fp);
+ p, fp);
if (rc)
goto out;
break;
@@ -2391,7 +2406,8 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info *
goto out;
len = le32_to_cpu(buf[0]);
- rc = str_read(&c->u.ibendport.dev_name, GFP_KERNEL, fp, len);
+ rc = str_read(&c->u.ibendport.dev_name,
+ GFP_KERNEL, fp, len);
if (rc)
goto out;
@@ -2404,8 +2420,7 @@ static int ocontext_read(struct policydb *p, const struct policydb_compat_info *
c->u.ibendport.port = port;
rc = context_read_and_validate(&c->context[0],
- p,
- fp);
+ p, fp);
if (rc)
goto out;
break;
@@ -2422,7 +2437,7 @@ out:
* Read the configuration data from a policy database binary
* representation file into a policy database structure.
*/
-int policydb_read(struct policydb *p, void *fp)
+int policydb_read(struct policydb *p, struct policy_file *fp)
{
struct role_allow *ra, *lra;
struct role_trans_key *rtk = NULL;
@@ -2458,26 +2473,22 @@ int policydb_read(struct policydb *p, void *fp)
goto bad;
}
- rc = -ENOMEM;
- policydb_str = kmalloc(len + 1, GFP_KERNEL);
- if (!policydb_str) {
- pr_err("SELinux: unable to allocate memory for policydb "
- "string of length %d\n", len);
- goto bad;
- }
-
- rc = next_entry(policydb_str, fp, len);
+ rc = str_read(&policydb_str, GFP_KERNEL, fp, len);
if (rc) {
- pr_err("SELinux: truncated policydb string identifier\n");
- kfree(policydb_str);
+ if (rc == -ENOMEM) {
+ pr_err("SELinux: unable to allocate memory for policydb string of length %d\n",
+ len);
+ } else {
+ pr_err("SELinux: truncated policydb string identifier\n");
+ }
goto bad;
}
rc = -EINVAL;
- policydb_str[len] = '\0';
if (strcmp(policydb_str, POLICYDB_STRING)) {
pr_err("SELinux: policydb string %s does not match "
- "my string %s\n", policydb_str, POLICYDB_STRING);
+ "my string %s\n",
+ policydb_str, POLICYDB_STRING);
kfree(policydb_str);
goto bad;
}
@@ -2486,7 +2497,7 @@ int policydb_read(struct policydb *p, void *fp)
policydb_str = NULL;
/* Read the version and table sizes. */
- rc = next_entry(buf, fp, sizeof(u32)*4);
+ rc = next_entry(buf, fp, sizeof(u32) * 4);
if (rc)
goto bad;
@@ -2496,7 +2507,8 @@ int policydb_read(struct policydb *p, void *fp)
p->policyvers > POLICYDB_VERSION_MAX) {
pr_err("SELinux: policydb version %d does not match "
"my version range %d-%d\n",
- le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
+ le32_to_cpu(buf[0]), POLICYDB_VERSION_MIN,
+ POLICYDB_VERSION_MAX);
goto bad;
}
@@ -2506,8 +2518,8 @@ int policydb_read(struct policydb *p, void *fp)
rc = -EINVAL;
if (p->policyvers < POLICYDB_VERSION_MLS) {
pr_err("SELinux: security policydb version %d "
- "(MLS) not backwards compatible\n",
- p->policyvers);
+ "(MLS) not backwards compatible\n",
+ p->policyvers);
goto bad;
}
}
@@ -2530,22 +2542,23 @@ int policydb_read(struct policydb *p, void *fp)
info = policydb_lookup_compat(p->policyvers);
if (!info) {
pr_err("SELinux: unable to find policy compat info "
- "for version %d\n", p->policyvers);
+ "for version %d\n",
+ p->policyvers);
goto bad;
}
rc = -EINVAL;
if (le32_to_cpu(buf[2]) != info->sym_num ||
- le32_to_cpu(buf[3]) != info->ocon_num) {
+ le32_to_cpu(buf[3]) != info->ocon_num) {
pr_err("SELinux: policydb table sizes (%d,%d) do "
- "not match mine (%d,%d)\n", le32_to_cpu(buf[2]),
- le32_to_cpu(buf[3]),
- info->sym_num, info->ocon_num);
+ "not match mine (%d,%d)\n",
+ le32_to_cpu(buf[2]), le32_to_cpu(buf[3]), info->sym_num,
+ info->ocon_num);
goto bad;
}
for (i = 0; i < info->sym_num; i++) {
- rc = next_entry(buf, fp, sizeof(u32)*2);
+ rc = next_entry(buf, fp, sizeof(u32) * 2);
if (rc)
goto bad;
nprim = le32_to_cpu(buf[0]);
@@ -2606,7 +2619,7 @@ int policydb_read(struct policydb *p, void *fp)
if (!rtd)
goto bad;
- rc = next_entry(buf, fp, sizeof(u32)*3);
+ rc = next_entry(buf, fp, sizeof(u32) * 3);
if (rc)
goto bad;
@@ -2636,6 +2649,8 @@ int policydb_read(struct policydb *p, void *fp)
rtd = NULL;
}
+ hash_eval(&p->role_tr, "roletr", NULL);
+
rc = next_entry(buf, fp, sizeof(u32));
if (rc)
goto bad;
@@ -2650,7 +2665,7 @@ int policydb_read(struct policydb *p, void *fp)
lra->next = ra;
else
p->role_allow = ra;
- rc = next_entry(buf, fp, sizeof(u32)*2);
+ rc = next_entry(buf, fp, sizeof(u32) * 2);
if (rc)
goto bad;
@@ -2698,9 +2713,8 @@ int policydb_read(struct policydb *p, void *fp)
goto bad;
rc = -ENOMEM;
- p->type_attr_map_array = kvcalloc(p->p_types.nprim,
- sizeof(*p->type_attr_map_array),
- GFP_KERNEL);
+ p->type_attr_map_array = kvcalloc(
+ p->p_types.nprim, sizeof(*p->type_attr_map_array), GFP_KERNEL);
if (!p->type_attr_map_array)
goto bad;
@@ -2740,7 +2754,7 @@ bad:
* Write a MLS level structure to a policydb binary
* representation file.
*/
-static int mls_write_level(struct mls_level *l, void *fp)
+static int mls_write_level(struct mls_level *l, struct policy_file *fp)
{
__le32 buf[1];
int rc;
@@ -2761,7 +2775,7 @@ static int mls_write_level(struct mls_level *l, void *fp)
* Write a MLS range structure to a policydb binary
* representation file.
*/
-static int mls_write_range_helper(struct mls_range *r, void *fp)
+static int mls_write_range_helper(struct mls_range *r, struct policy_file *fp)
{
__le32 buf[3];
size_t items;
@@ -2773,7 +2787,7 @@ static int mls_write_range_helper(struct mls_range *r, void *fp)
items = 2;
else
items = 3;
- buf[0] = cpu_to_le32(items-1);
+ buf[0] = cpu_to_le32(items - 1);
buf[1] = cpu_to_le32(r->level[0].sens);
if (!eq)
buf[2] = cpu_to_le32(r->level[1].sens);
@@ -2801,7 +2815,7 @@ static int sens_write(void *vkey, void *datum, void *ptr)
char *key = vkey;
struct level_datum *levdatum = datum;
struct policy_data *pd = ptr;
- void *fp = pd->fp;
+ struct policy_file *fp = pd->fp;
__le32 buf[2];
size_t len;
int rc;
@@ -2817,7 +2831,7 @@ static int sens_write(void *vkey, void *datum, void *ptr)
if (rc)
return rc;
- rc = mls_write_level(levdatum->level, fp);
+ rc = mls_write_level(&levdatum->level, fp);
if (rc)
return rc;
@@ -2829,7 +2843,7 @@ static int cat_write(void *vkey, void *datum, void *ptr)
char *key = vkey;
struct cat_datum *catdatum = datum;
struct policy_data *pd = ptr;
- void *fp = pd->fp;
+ struct policy_file *fp = pd->fp;
__le32 buf[3];
size_t len;
int rc;
@@ -2854,7 +2868,7 @@ static int role_trans_write_one(void *key, void *datum, void *ptr)
struct role_trans_key *rtk = key;
struct role_trans_datum *rtd = datum;
struct policy_data *pd = ptr;
- void *fp = pd->fp;
+ struct policy_file *fp = pd->fp;
struct policydb *p = pd->p;
__le32 buf[3];
int rc;
@@ -2874,7 +2888,7 @@ static int role_trans_write_one(void *key, void *datum, void *ptr)
return 0;
}
-static int role_trans_write(struct policydb *p, void *fp)
+static int role_trans_write(struct policydb *p, struct policy_file *fp)
{
struct policy_data pd = { .p = p, .fp = fp };
__le32 buf[1];
@@ -2888,7 +2902,7 @@ static int role_trans_write(struct policydb *p, void *fp)
return hashtab_map(&p->role_tr, role_trans_write_one, &pd);
}
-static int role_allow_write(struct role_allow *r, void *fp)
+static int role_allow_write(struct role_allow *r, struct policy_file *fp)
{
struct role_allow *ra;
__le32 buf[2];
@@ -2916,8 +2930,7 @@ static int role_allow_write(struct role_allow *r, void *fp)
* Write a security context structure
* to a policydb binary representation file.
*/
-static int context_write(struct policydb *p, struct context *c,
- void *fp)
+static int context_write(struct policydb *p, struct context *c, struct policy_file *fp)
{
int rc;
__le32 buf[3];
@@ -2970,7 +2983,7 @@ static int common_write(void *vkey, void *datum, void *ptr)
char *key = vkey;
struct common_datum *comdatum = datum;
struct policy_data *pd = ptr;
- void *fp = pd->fp;
+ struct policy_file *fp = pd->fp;
__le32 buf[4];
size_t len;
int rc;
@@ -2995,7 +3008,7 @@ static int common_write(void *vkey, void *datum, void *ptr)
return 0;
}
-static int type_set_write(struct type_set *t, void *fp)
+static int type_set_write(struct type_set *t, struct policy_file *fp)
{
int rc;
__le32 buf[1];
@@ -3014,7 +3027,7 @@ static int type_set_write(struct type_set *t, void *fp)
}
static int write_cons_helper(struct policydb *p, struct constraint_node *node,
- void *fp)
+ struct policy_file *fp)
{
struct constraint_node *c;
struct constraint_expr *e;
@@ -3045,7 +3058,7 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node,
if (rc)
return rc;
if (p->policyvers >=
- POLICYDB_VERSION_CONSTRAINT_NAMES) {
+ POLICYDB_VERSION_CONSTRAINT_NAMES) {
rc = type_set_write(e->type_names, fp);
if (rc)
return rc;
@@ -3065,7 +3078,7 @@ static int class_write(void *vkey, void *datum, void *ptr)
char *key = vkey;
struct class_datum *cladatum = datum;
struct policy_data *pd = ptr;
- void *fp = pd->fp;
+ struct policy_file *fp = pd->fp;
struct policydb *p = pd->p;
struct constraint_node *c;
__le32 buf[6];
@@ -3150,7 +3163,7 @@ static int role_write(void *vkey, void *datum, void *ptr)
char *key = vkey;
struct role_datum *role = datum;
struct policy_data *pd = ptr;
- void *fp = pd->fp;
+ struct policy_file *fp = pd->fp;
struct policydb *p = pd->p;
__le32 buf[3];
size_t items, len;
@@ -3190,7 +3203,7 @@ static int type_write(void *vkey, void *datum, void *ptr)
struct type_datum *typdatum = datum;
struct policy_data *pd = ptr;
struct policydb *p = pd->p;
- void *fp = pd->fp;
+ struct policy_file *fp = pd->fp;
__le32 buf[4];
int rc;
size_t items, len;
@@ -3231,7 +3244,7 @@ static int user_write(void *vkey, void *datum, void *ptr)
struct user_datum *usrdatum = datum;
struct policy_data *pd = ptr;
struct policydb *p = pd->p;
- void *fp = pd->fp;
+ struct policy_file *fp = pd->fp;
__le32 buf[3];
size_t items, len;
int rc;
@@ -3266,7 +3279,8 @@ static int user_write(void *vkey, void *datum, void *ptr)
return 0;
}
-static int (*const write_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
+/* clang-format off */
+static int (*const write_f[SYM_NUM])(void *key, void *datum, void *datap) = {
common_write,
class_write,
role_write,
@@ -3276,9 +3290,11 @@ static int (*const write_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
sens_write,
cat_write,
};
+/* clang-format on */
-static int ocontext_write(struct policydb *p, const struct policydb_compat_info *info,
- void *fp)
+static int ocontext_write(struct policydb *p,
+ const struct policydb_compat_info *info,
+ struct policy_file *fp)
{
unsigned int i, j;
int rc;
@@ -3360,9 +3376,13 @@ static int ocontext_write(struct policydb *p, const struct policydb_compat_info
break;
case OCON_NODE6:
for (j = 0; j < 4; j++)
- nodebuf[j] = c->u.node6.addr[j]; /* network order */
+ nodebuf[j] =
+ c->u.node6.addr
+ [j]; /* network order */
for (j = 0; j < 4; j++)
- nodebuf[j + 4] = c->u.node6.mask[j]; /* network order */
+ nodebuf[j + 4] =
+ c->u.node6.mask
+ [j]; /* network order */
rc = put_entry(nodebuf, sizeof(u32), 8, fp);
if (rc)
return rc;
@@ -3372,7 +3392,8 @@ static int ocontext_write(struct policydb *p, const struct policydb_compat_info
break;
case OCON_IBPKEY:
/* subnet_prefix is in CPU order */
- prefixbuf[0] = cpu_to_be64(c->u.ibpkey.subnet_prefix);
+ prefixbuf[0] =
+ cpu_to_be64(c->u.ibpkey.subnet_prefix);
rc = put_entry(prefixbuf, sizeof(u64), 1, fp);
if (rc)
@@ -3395,7 +3416,8 @@ static int ocontext_write(struct policydb *p, const struct policydb_compat_info
rc = put_entry(buf, sizeof(u32), 2, fp);
if (rc)
return rc;
- rc = put_entry(c->u.ibendport.dev_name, 1, len, fp);
+ rc = put_entry(c->u.ibendport.dev_name, 1, len,
+ fp);
if (rc)
return rc;
rc = context_write(p, &c->context[0], fp);
@@ -3408,7 +3430,7 @@ static int ocontext_write(struct policydb *p, const struct policydb_compat_info
return 0;
}
-static int genfs_write(struct policydb *p, void *fp)
+static int genfs_write(struct policydb *p, struct policy_file *fp)
{
struct genfs *genfs;
struct ocontext *c;
@@ -3466,7 +3488,7 @@ static int range_write_helper(void *key, void *data, void *ptr)
struct range_trans *rt = key;
struct mls_range *r = data;
struct policy_data *pd = ptr;
- void *fp = pd->fp;
+ struct policy_file *fp = pd->fp;
struct policydb *p = pd->p;
int rc;
@@ -3488,7 +3510,7 @@ static int range_write_helper(void *key, void *data, void *ptr)
return 0;
}
-static int range_write(struct policydb *p, void *fp)
+static int range_write(struct policydb *p, struct policy_file *fp)
{
__le32 buf[1];
int rc;
@@ -3515,13 +3537,14 @@ static int filename_write_helper_compat(void *key, void *data, void *ptr)
struct filename_trans_key *ft = key;
struct filename_trans_datum *datum = data;
struct ebitmap_node *node;
- void *fp = ptr;
+ struct policy_file *fp = ptr;
__le32 buf[4];
int rc;
u32 bit, len = strlen(ft->name);
do {
- ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
+ ebitmap_for_each_positive_bit(&datum->stypes, node, bit)
+ {
buf[0] = cpu_to_le32(len);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
@@ -3551,7 +3574,7 @@ static int filename_write_helper(void *key, void *data, void *ptr)
{
struct filename_trans_key *ft = key;
struct filename_trans_datum *datum;
- void *fp = ptr;
+ struct policy_file *fp = ptr;
__le32 buf[3];
int rc;
u32 ndatum, len = strlen(ft->name);
@@ -3596,7 +3619,7 @@ static int filename_write_helper(void *key, void *data, void *ptr)
return 0;
}
-static int filename_trans_write(struct policydb *p, void *fp)
+static int filename_trans_write(struct policydb *p, struct policy_file *fp)
{
__le32 buf[1];
int rc;
@@ -3628,7 +3651,7 @@ static int filename_trans_write(struct policydb *p, void *fp)
* structure to a policy database binary representation
* file.
*/
-int policydb_write(struct policydb *p, void *fp)
+int policydb_write(struct policydb *p, struct policy_file *fp)
{
unsigned int num_syms;
int rc;
@@ -3645,8 +3668,8 @@ int policydb_write(struct policydb *p, void *fp)
*/
if (p->policyvers < POLICYDB_VERSION_AVTAB) {
pr_err("SELinux: refusing to write policy version %d."
- " Because it is less than version %d\n", p->policyvers,
- POLICYDB_VERSION_AVTAB);
+ " Because it is less than version %d\n",
+ p->policyvers, POLICYDB_VERSION_AVTAB);
return -EINVAL;
}
@@ -3674,7 +3697,8 @@ int policydb_write(struct policydb *p, void *fp)
info = policydb_lookup_compat(p->policyvers);
if (!info) {
pr_err("SELinux: compatibility lookup failed for policy "
- "version %d\n", p->policyvers);
+ "version %d\n",
+ p->policyvers);
return -EINVAL;
}
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index b97cda489753..25650224b6e7 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -8,15 +8,13 @@
/*
* Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
+ * Support for enhanced MLS infrastructure.
+ * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
*
- * Support for enhanced MLS infrastructure.
- *
- * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
- *
- * Added conditional policy language extensions
- *
- * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
- * Copyright (C) 2003 - 2004 Tresys Technology, LLC
+ * Updated: Frank Mayer <mayerf@tresys.com> and
+ * Karl MacMillan <kmacmillan@tresys.com>
+ * Added conditional policy language extensions
+ * Copyright (C) 2003-2004 Tresys Technology, LLC
*/
#ifndef _SS_POLICYDB_H_
@@ -39,104 +37,103 @@
/* Permission attributes */
struct perm_datum {
- u32 value; /* permission bit + 1 */
+ u32 value; /* permission bit + 1 */
};
/* Attributes of a common prefix for access vectors */
struct common_datum {
- u32 value; /* internal common value */
- struct symtab permissions; /* common permissions */
+ u32 value; /* internal common value */
+ struct symtab permissions; /* common permissions */
};
/* Class attributes */
struct class_datum {
- u32 value; /* class value */
- char *comkey; /* common name */
- struct common_datum *comdatum; /* common datum */
- struct symtab permissions; /* class-specific permission symbol table */
- struct constraint_node *constraints; /* constraints on class permissions */
- struct constraint_node *validatetrans; /* special transition rules */
+ u32 value; /* class value */
+ char *comkey; /* common name */
+ struct common_datum *comdatum; /* common datum */
+ struct symtab permissions; /* class-specific permission symbol table */
+ struct constraint_node *constraints; /* constraints on class perms */
+ struct constraint_node *validatetrans; /* special transition rules */
/* Options how a new object user, role, and type should be decided */
-#define DEFAULT_SOURCE 1
-#define DEFAULT_TARGET 2
+#define DEFAULT_SOURCE 1
+#define DEFAULT_TARGET 2
char default_user;
char default_role;
char default_type;
/* Options how a new object range should be decided */
-#define DEFAULT_SOURCE_LOW 1
-#define DEFAULT_SOURCE_HIGH 2
-#define DEFAULT_SOURCE_LOW_HIGH 3
-#define DEFAULT_TARGET_LOW 4
-#define DEFAULT_TARGET_HIGH 5
-#define DEFAULT_TARGET_LOW_HIGH 6
+#define DEFAULT_SOURCE_LOW 1
+#define DEFAULT_SOURCE_HIGH 2
+#define DEFAULT_SOURCE_LOW_HIGH 3
+#define DEFAULT_TARGET_LOW 4
+#define DEFAULT_TARGET_HIGH 5
+#define DEFAULT_TARGET_LOW_HIGH 6
#define DEFAULT_GLBLUB 7
char default_range;
};
/* Role attributes */
struct role_datum {
- u32 value; /* internal role value */
- u32 bounds; /* boundary of role */
- struct ebitmap dominates; /* set of roles dominated by this role */
- struct ebitmap types; /* set of authorized types for role */
+ u32 value; /* internal role value */
+ u32 bounds; /* boundary of role */
+ struct ebitmap dominates; /* set of roles dominated by this role */
+ struct ebitmap types; /* set of authorized types for role */
};
struct role_trans_key {
- u32 role; /* current role */
- u32 type; /* program executable type, or new object type */
- u32 tclass; /* process class, or new object class */
+ u32 role; /* current role */
+ u32 type; /* program executable type, or new object type */
+ u32 tclass; /* process class, or new object class */
};
struct role_trans_datum {
- u32 new_role; /* new role */
+ u32 new_role; /* new role */
};
struct filename_trans_key {
- u32 ttype; /* parent dir context */
- u16 tclass; /* class of new object */
- const char *name; /* last path component */
+ u32 ttype; /* parent dir context */
+ u16 tclass; /* class of new object */
+ const char *name; /* last path component */
};
struct filename_trans_datum {
- struct ebitmap stypes; /* bitmap of source types for this otype */
- u32 otype; /* resulting type of new object */
- struct filename_trans_datum *next; /* record for next otype*/
+ struct ebitmap stypes; /* bitmap of source types for this otype */
+ u32 otype; /* resulting type of new object */
+ struct filename_trans_datum *next; /* record for next otype*/
};
struct role_allow {
- u32 role; /* current role */
- u32 new_role; /* new role */
+ u32 role; /* current role */
+ u32 new_role; /* new role */
struct role_allow *next;
};
/* Type attributes */
struct type_datum {
- u32 value; /* internal type value */
- u32 bounds; /* boundary of type */
- unsigned char primary; /* primary name? */
- unsigned char attribute;/* attribute ?*/
+ u32 value; /* internal type value */
+ u32 bounds; /* boundary of type */
+ unsigned char primary; /* primary name? */
+ unsigned char attribute; /* attribute ?*/
};
/* User attributes */
struct user_datum {
- u32 value; /* internal user value */
- u32 bounds; /* bounds of user */
- struct ebitmap roles; /* set of authorized roles for user */
- struct mls_range range; /* MLS range (min - max) for user */
- struct mls_level dfltlevel; /* default login MLS level for user */
+ u32 value; /* internal user value */
+ u32 bounds; /* bounds of user */
+ struct ebitmap roles; /* set of authorized roles for user */
+ struct mls_range range; /* MLS range (min - max) for user */
+ struct mls_level dfltlevel; /* default login MLS level for user */
};
-
/* Sensitivity attributes */
struct level_datum {
- struct mls_level *level; /* sensitivity and associated categories */
- unsigned char isalias; /* is this sensitivity an alias for another? */
+ struct mls_level level; /* sensitivity and associated categories */
+ unsigned char isalias; /* is this sensitivity an alias for another? */
};
/* Category attributes */
struct cat_datum {
- u32 value; /* internal category bit + 1 */
- unsigned char isalias; /* is this category an alias for another? */
+ u32 value; /* internal category bit + 1 */
+ unsigned char isalias; /* is this category an alias for another? */
};
struct range_trans {
@@ -147,7 +144,7 @@ struct range_trans {
/* Boolean data type */
struct cond_bool_datum {
- __u32 value; /* internal type value */
+ u32 value; /* internal type value */
int state;
};
@@ -173,20 +170,20 @@ struct type_set {
*/
struct ocontext {
union {
- char *name; /* name of initial SID, fs, netif, fstype, path */
+ char *name; /* name of initial SID, fs, netif, fstype, path */
struct {
u8 protocol;
u16 low_port;
u16 high_port;
- } port; /* TCP or UDP port information */
+ } port; /* TCP or UDP port information */
struct {
u32 addr;
u32 mask;
- } node; /* node information */
+ } node; /* node information */
struct {
u32 addr[4];
u32 mask[4];
- } node6; /* IPv6 node information */
+ } node6; /* IPv6 node information */
struct {
u64 subnet_prefix;
u16 low_pkey;
@@ -198,11 +195,11 @@ struct ocontext {
} ibendport;
} u;
union {
- u32 sclass; /* security class for genfs */
- u32 behavior; /* labeling behavior for fs_use */
+ u32 sclass; /* security class for genfs */
+ u32 behavior; /* labeling behavior for fs_use */
} v;
- struct context context[2]; /* security context(s) */
- u32 sid[2]; /* SID(s) */
+ struct context context[2]; /* security context(s) */
+ u32 sid[2]; /* SID(s) */
struct ocontext *next;
};
@@ -221,19 +218,19 @@ struct genfs {
#define SYM_BOOLS 5
#define SYM_LEVELS 6
#define SYM_CATS 7
-#define SYM_NUM 8
+#define SYM_NUM 8
/* object context array indices */
-#define OCON_ISID 0 /* initial SIDs */
-#define OCON_FS 1 /* unlabeled file systems (deprecated) */
-#define OCON_PORT 2 /* TCP and UDP port numbers */
-#define OCON_NETIF 3 /* network interfaces */
-#define OCON_NODE 4 /* nodes */
-#define OCON_FSUSE 5 /* fs_use */
-#define OCON_NODE6 6 /* IPv6 nodes */
-#define OCON_IBPKEY 7 /* Infiniband PKeys */
-#define OCON_IBENDPORT 8 /* Infiniband end ports */
-#define OCON_NUM 9
+#define OCON_ISID 0 /* initial SIDs */
+#define OCON_FS 1 /* unlabeled file systems (deprecated) */
+#define OCON_PORT 2 /* TCP and UDP port numbers */
+#define OCON_NETIF 3 /* network interfaces */
+#define OCON_NODE 4 /* nodes */
+#define OCON_FSUSE 5 /* fs_use */
+#define OCON_NODE6 6 /* IPv6 nodes */
+#define OCON_IBPKEY 7 /* Infiniband PKeys */
+#define OCON_IBENDPORT 8 /* Infiniband end ports */
+#define OCON_NUM 9
/* The policy database */
struct policydb {
@@ -243,15 +240,15 @@ struct policydb {
struct symtab symtab[SYM_NUM];
#define p_commons symtab[SYM_COMMONS]
#define p_classes symtab[SYM_CLASSES]
-#define p_roles symtab[SYM_ROLES]
-#define p_types symtab[SYM_TYPES]
-#define p_users symtab[SYM_USERS]
-#define p_bools symtab[SYM_BOOLS]
-#define p_levels symtab[SYM_LEVELS]
-#define p_cats symtab[SYM_CATS]
+#define p_roles symtab[SYM_ROLES]
+#define p_types symtab[SYM_TYPES]
+#define p_users symtab[SYM_USERS]
+#define p_bools symtab[SYM_BOOLS]
+#define p_levels symtab[SYM_LEVELS]
+#define p_cats symtab[SYM_CATS]
/* symbol names indexed by (value - 1) */
- char **sym_val_to_name[SYM_NUM];
+ char **sym_val_to_name[SYM_NUM];
/* class, role, and user attributes indexed by (value - 1) */
struct class_datum **class_val_to_struct;
@@ -315,44 +312,44 @@ struct policydb {
u32 process_trans_perms;
} __randomize_layout;
+struct policy_file {
+ char *data;
+ size_t len;
+};
+
extern void policydb_destroy(struct policydb *p);
extern int policydb_load_isids(struct policydb *p, struct sidtab *s);
extern int policydb_context_isvalid(struct policydb *p, struct context *c);
extern int policydb_class_isvalid(struct policydb *p, unsigned int class);
extern int policydb_type_isvalid(struct policydb *p, unsigned int type);
extern int policydb_role_isvalid(struct policydb *p, unsigned int role);
-extern int policydb_read(struct policydb *p, void *fp);
-extern int policydb_write(struct policydb *p, void *fp);
+extern int policydb_read(struct policydb *p, struct policy_file *fp);
+extern int policydb_write(struct policydb *p, struct policy_file *fp);
-extern struct filename_trans_datum *policydb_filenametr_search(
- struct policydb *p, struct filename_trans_key *key);
+extern struct filename_trans_datum *
+policydb_filenametr_search(struct policydb *p, struct filename_trans_key *key);
-extern struct mls_range *policydb_rangetr_search(
- struct policydb *p, struct range_trans *key);
+extern struct mls_range *policydb_rangetr_search(struct policydb *p,
+ struct range_trans *key);
-extern struct role_trans_datum *policydb_roletr_search(
- struct policydb *p, struct role_trans_key *key);
+extern struct role_trans_datum *
+policydb_roletr_search(struct policydb *p, struct role_trans_key *key);
-#define POLICYDB_CONFIG_MLS 1
+#define POLICYDB_CONFIG_MLS 1
/* the config flags related to unknown classes/perms are bits 2 and 3 */
-#define REJECT_UNKNOWN 0x00000002
-#define ALLOW_UNKNOWN 0x00000004
+#define REJECT_UNKNOWN 0x00000002
+#define ALLOW_UNKNOWN 0x00000004
-#define OBJECT_R "object_r"
+#define OBJECT_R "object_r"
#define OBJECT_R_VAL 1
-#define POLICYDB_MAGIC SELINUX_MAGIC
+#define POLICYDB_MAGIC SELINUX_MAGIC
#define POLICYDB_STRING "SE Linux"
-struct policy_file {
- char *data;
- size_t len;
-};
-
struct policy_data {
struct policydb *p;
- void *fp;
+ struct policy_file *fp;
};
static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
@@ -366,7 +363,8 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
return 0;
}
-static inline int put_entry(const void *buf, size_t bytes, size_t num, struct policy_file *fp)
+static inline int put_entry(const void *buf, size_t bytes, size_t num,
+ struct policy_file *fp)
{
size_t len;
@@ -382,13 +380,15 @@ static inline int put_entry(const void *buf, size_t bytes, size_t num, struct po
return 0;
}
-static inline char *sym_name(struct policydb *p, unsigned int sym_num, unsigned int element_nr)
+static inline char *sym_name(struct policydb *p, unsigned int sym_num,
+ unsigned int element_nr)
{
return p->sym_val_to_name[sym_num][element_nr];
}
+extern int str_read(char **strp, gfp_t flags, struct policy_file *fp, u32 len);
+
extern u16 string_to_security_class(struct policydb *p, const char *name);
extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name);
-#endif /* _SS_POLICYDB_H_ */
-
+#endif /* _SS_POLICYDB_H_ */
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index e88b1b6c4adb..8478842fbf9e 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -582,8 +582,7 @@ static void type_attribute_bounds_av(struct policydb *policydb,
}
/*
- * flag which drivers have permissions
- * only looking for ioctl based extended permissions
+ * Flag which drivers have permissions and which base permissions are covered.
*/
void services_compute_xperms_drivers(
struct extended_perms *xperms,
@@ -591,14 +590,25 @@ void services_compute_xperms_drivers(
{
unsigned int i;
- if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
+ switch (node->datum.u.xperms->specified) {
+ case AVTAB_XPERMS_IOCTLDRIVER:
+ xperms->base_perms |= AVC_EXT_IOCTL;
/* if one or more driver has all permissions allowed */
for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
- } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
+ break;
+ case AVTAB_XPERMS_IOCTLFUNCTION:
+ xperms->base_perms |= AVC_EXT_IOCTL;
+ /* if allowing permissions within a driver */
+ security_xperm_set(xperms->drivers.p,
+ node->datum.u.xperms->driver);
+ break;
+ case AVTAB_XPERMS_NLMSG:
+ xperms->base_perms |= AVC_EXT_NLMSG;
/* if allowing permissions within a driver */
security_xperm_set(xperms->drivers.p,
node->datum.u.xperms->driver);
+ break;
}
xperms->len = 1;
@@ -628,13 +638,11 @@ static void context_struct_compute_av(struct policydb *policydb,
avd->auditallow = 0;
avd->auditdeny = 0xffffffff;
if (xperms) {
- memset(&xperms->drivers, 0, sizeof(xperms->drivers));
- xperms->len = 0;
+ memset(xperms, 0, sizeof(*xperms));
}
if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
- if (printk_ratelimit())
- pr_warn("SELinux: Invalid class %hu\n", tclass);
+ pr_warn_ratelimited("SELinux: Invalid class %u\n", tclass);
return;
}
@@ -943,57 +951,74 @@ static void avd_init(struct selinux_policy *policy, struct av_decision *avd)
avd->flags = 0;
}
+static void update_xperms_extended_data(u8 specified,
+ const struct extended_perms_data *from,
+ struct extended_perms_data *xp_data)
+{
+ unsigned int i;
+
+ switch (specified) {
+ case AVTAB_XPERMS_IOCTLDRIVER:
+ memset(xp_data->p, 0xff, sizeof(xp_data->p));
+ break;
+ case AVTAB_XPERMS_IOCTLFUNCTION:
+ case AVTAB_XPERMS_NLMSG:
+ for (i = 0; i < ARRAY_SIZE(xp_data->p); i++)
+ xp_data->p[i] |= from->p[i];
+ break;
+ }
+
+}
+
void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
struct avtab_node *node)
{
- unsigned int i;
+ u16 specified;
- if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
- if (xpermd->driver != node->datum.u.xperms->driver)
+ switch (node->datum.u.xperms->specified) {
+ case AVTAB_XPERMS_IOCTLFUNCTION:
+ if (xpermd->base_perm != AVC_EXT_IOCTL ||
+ xpermd->driver != node->datum.u.xperms->driver)
return;
- } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
- if (!security_xperm_test(node->datum.u.xperms->perms.p,
- xpermd->driver))
+ break;
+ case AVTAB_XPERMS_IOCTLDRIVER:
+ if (xpermd->base_perm != AVC_EXT_IOCTL ||
+ !security_xperm_test(node->datum.u.xperms->perms.p,
+ xpermd->driver))
return;
- } else {
- BUG();
+ break;
+ case AVTAB_XPERMS_NLMSG:
+ if (xpermd->base_perm != AVC_EXT_NLMSG ||
+ xpermd->driver != node->datum.u.xperms->driver)
+ return;
+ break;
+ default:
+ pr_warn_once(
+ "SELinux: unknown extended permission (%u) will be ignored\n",
+ node->datum.u.xperms->specified);
+ return;
}
- if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
+ specified = node->key.specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
+
+ if (specified == AVTAB_XPERMS_ALLOWED) {
xpermd->used |= XPERMS_ALLOWED;
- if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
- memset(xpermd->allowed->p, 0xff,
- sizeof(xpermd->allowed->p));
- }
- if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
- for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
- xpermd->allowed->p[i] |=
- node->datum.u.xperms->perms.p[i];
- }
- } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
+ update_xperms_extended_data(node->datum.u.xperms->specified,
+ &node->datum.u.xperms->perms,
+ xpermd->allowed);
+ } else if (specified == AVTAB_XPERMS_AUDITALLOW) {
xpermd->used |= XPERMS_AUDITALLOW;
- if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
- memset(xpermd->auditallow->p, 0xff,
- sizeof(xpermd->auditallow->p));
- }
- if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
- for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
- xpermd->auditallow->p[i] |=
- node->datum.u.xperms->perms.p[i];
- }
- } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
+ update_xperms_extended_data(node->datum.u.xperms->specified,
+ &node->datum.u.xperms->perms,
+ xpermd->auditallow);
+ } else if (specified == AVTAB_XPERMS_DONTAUDIT) {
xpermd->used |= XPERMS_DONTAUDIT;
- if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
- memset(xpermd->dontaudit->p, 0xff,
- sizeof(xpermd->dontaudit->p));
- }
- if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
- for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
- xpermd->dontaudit->p[i] |=
- node->datum.u.xperms->perms.p[i];
- }
+ update_xperms_extended_data(node->datum.u.xperms->specified,
+ &node->datum.u.xperms->perms,
+ xpermd->dontaudit);
} else {
- BUG();
+ pr_warn_once("SELinux: unknown specified key (%u)\n",
+ node->key.specified);
}
}
@@ -1001,6 +1026,7 @@ void security_compute_xperms_decision(u32 ssid,
u32 tsid,
u16 orig_tclass,
u8 driver,
+ u8 base_perm,
struct extended_perms_decision *xpermd)
{
struct selinux_policy *policy;
@@ -1014,6 +1040,7 @@ void security_compute_xperms_decision(u32 ssid,
struct ebitmap_node *snode, *tnode;
unsigned int i, j;
+ xpermd->base_perm = base_perm;
xpermd->driver = driver;
xpermd->used = 0;
memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
@@ -1805,22 +1832,9 @@ retry:
newcontext.role = OBJECT_R_VAL;
}
- /* Set the type to default values. */
- if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
- newcontext.type = scontext->type;
- } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
- newcontext.type = tcontext->type;
- } else {
- if ((tclass == policydb->process_class) || sock) {
- /* Use the type of process. */
- newcontext.type = scontext->type;
- } else {
- /* Use the type of the related object. */
- newcontext.type = tcontext->type;
- }
- }
-
- /* Look for a type transition/member/change rule. */
+ /* Set the type.
+ * Look for a type transition/member/change rule.
+ */
avkey.source_type = scontext->type;
avkey.target_type = tcontext->type;
avkey.target_class = tclass;
@@ -1838,9 +1852,24 @@ retry:
}
}
+ /* If a permanent rule is found, use the type from
+ * the type transition/member/change rule. Otherwise,
+ * set the type to its default values.
+ */
if (avnode) {
- /* Use the type from the type transition/member/change rule. */
newcontext.type = avnode->datum.u.data;
+ } else if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
+ newcontext.type = scontext->type;
+ } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
+ newcontext.type = tcontext->type;
+ } else {
+ if ((tclass == policydb->process_class) || sock) {
+ /* Use the type of process. */
+ newcontext.type = scontext->type;
+ } else {
+ /* Use the type of the related object. */
+ newcontext.type = tcontext->type;
+ }
}
/* if we have a objname this is a file trans check so check those rules */
@@ -2586,17 +2615,15 @@ out:
return rc;
}
-static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
+static bool match_ipv6_addrmask(const u32 input[4], const u32 addr[4], const u32 mask[4])
{
- int i, fail = 0;
+ int i;
for (i = 0; i < 4; i++)
- if (addr[i] != (input[i] & mask[i])) {
- fail = 1;
- break;
- }
+ if (addr[i] != (input[i] & mask[i]))
+ return false;
- return !fail;
+ return true;
}
/**
@@ -2701,7 +2728,7 @@ out:
*/
int security_get_user_sids(u32 fromsid,
- char *username,
+ const char *username,
u32 **sids,
u32 *nel)
{
@@ -3023,7 +3050,7 @@ err:
}
-int security_set_bools(u32 len, int *values)
+int security_set_bools(u32 len, const int *values)
{
struct selinux_state *state = &selinux_state;
struct selinux_policy *newpolicy, *oldpolicy;
@@ -3322,7 +3349,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
__func__, xfrm_sid);
goto out;
}
- rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
+ rc = (mls_context_equal(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
if (rc)
goto out;
@@ -3508,7 +3535,8 @@ void selinux_audit_rule_free(void *vrule)
}
}
-int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
+int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
+ gfp_t gfp)
{
struct selinux_state *state = &selinux_state;
struct selinux_policy *policy;
@@ -3549,7 +3577,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
return -EINVAL;
}
- tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
+ tmprule = kzalloc(sizeof(struct selinux_audit_rule), gfp);
if (!tmprule)
return -ENOMEM;
context_init(&tmprule->au_ctxt);
@@ -3633,7 +3661,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
return 0;
}
-int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
+int selinux_audit_rule_match(struct lsm_prop *prop, u32 field, u32 op, void *vrule)
{
struct selinux_state *state = &selinux_state;
struct selinux_policy *policy;
@@ -3659,10 +3687,10 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
goto out;
}
- ctxt = sidtab_search(policy->sidtab, sid);
+ ctxt = sidtab_search(policy->sidtab, prop->selinux.secid);
if (unlikely(!ctxt)) {
WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
- sid);
+ prop->selinux.secid);
match = -ENOENT;
goto out;
}
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h
index d24b0a3d198e..93358e7a649c 100644
--- a/security/selinux/ss/services.h
+++ b/security/selinux/ss/services.h
@@ -4,6 +4,7 @@
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
+
#ifndef _SS_SERVICES_H_
#define _SS_SERVICES_H_
@@ -43,4 +44,4 @@ int services_convert_context(struct convert_context_args *args,
struct context *oldc, struct context *newc,
gfp_t gfp_flags);
-#endif /* _SS_SERVICES_H_ */
+#endif /* _SS_SERVICES_H_ */
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 732fd8e22a12..59f8c09158ef 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -7,6 +7,7 @@
*
* Copyright (C) 2018 Red Hat, Inc.
*/
+
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -29,7 +30,7 @@ struct sidtab_str_cache {
};
#define index_to_sid(index) ((index) + SECINITSID_NUM + 1)
-#define sid_to_index(sid) ((sid) - (SECINITSID_NUM + 1))
+#define sid_to_index(sid) ((sid) - (SECINITSID_NUM + 1))
int sidtab_init(struct sidtab *s)
{
@@ -65,7 +66,7 @@ static u32 context_to_sid(struct sidtab *s, struct context *context, u32 hash)
hash_for_each_possible_rcu(s->context_to_sid, entry, list, hash) {
if (entry->hash != hash)
continue;
- if (context_cmp(&entry->context, context)) {
+ if (context_equal(&entry->context, context)) {
sid = entry->sid;
break;
}
@@ -113,12 +114,12 @@ int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context)
int sidtab_hash_stats(struct sidtab *sidtab, char *page)
{
- int i;
+ unsigned int i;
int chain_len = 0;
int slots_used = 0;
int entries = 0;
int max_chain_len = 0;
- int cur_bucket = 0;
+ unsigned int cur_bucket = 0;
struct sidtab_entry *entry;
rcu_read_lock();
@@ -140,9 +141,11 @@ int sidtab_hash_stats(struct sidtab *sidtab, char *page)
if (chain_len > max_chain_len)
max_chain_len = chain_len;
- return scnprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
- "longest chain: %d\n", entries,
- slots_used, SIDTAB_HASH_BUCKETS, max_chain_len);
+ return scnprintf(page, PAGE_SIZE,
+ "entries: %d\nbuckets used: %d/%d\n"
+ "longest chain: %d\n",
+ entries, slots_used, SIDTAB_HASH_BUCKETS,
+ max_chain_len);
}
static u32 sidtab_level_from_count(u32 count)
@@ -162,15 +165,15 @@ static int sidtab_alloc_roots(struct sidtab *s, u32 level)
u32 l;
if (!s->roots[0].ptr_leaf) {
- s->roots[0].ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
- GFP_ATOMIC);
+ s->roots[0].ptr_leaf =
+ kzalloc(SIDTAB_NODE_ALLOC_SIZE, GFP_ATOMIC);
if (!s->roots[0].ptr_leaf)
return -ENOMEM;
}
for (l = 1; l <= level; ++l)
if (!s->roots[l].ptr_inner) {
- s->roots[l].ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
- GFP_ATOMIC);
+ s->roots[l].ptr_inner =
+ kzalloc(SIDTAB_NODE_ALLOC_SIZE, GFP_ATOMIC);
if (!s->roots[l].ptr_inner)
return -ENOMEM;
s->roots[l].ptr_inner->entries[0] = s->roots[l - 1];
@@ -203,16 +206,16 @@ static struct sidtab_entry *sidtab_do_lookup(struct sidtab *s, u32 index,
if (!entry->ptr_inner) {
if (alloc)
- entry->ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
- GFP_ATOMIC);
+ entry->ptr_inner = kzalloc(
+ SIDTAB_NODE_ALLOC_SIZE, GFP_ATOMIC);
if (!entry->ptr_inner)
return NULL;
}
}
if (!entry->ptr_leaf) {
if (alloc)
- entry->ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
- GFP_ATOMIC);
+ entry->ptr_leaf =
+ kzalloc(SIDTAB_NODE_ALLOC_SIZE, GFP_ATOMIC);
if (!entry->ptr_leaf)
return NULL;
}
@@ -262,8 +265,7 @@ struct sidtab_entry *sidtab_search_entry_force(struct sidtab *s, u32 sid)
return sidtab_search_core(s, sid, 1);
}
-int sidtab_context_to_sid(struct sidtab *s, struct context *context,
- u32 *sid)
+int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid)
{
unsigned long flags;
u32 count, hash = context_compute_hash(context);
@@ -327,8 +329,8 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context,
goto out_unlock;
}
- rc = services_convert_context(convert->args,
- context, &dst_convert->context,
+ rc = services_convert_context(convert->args, context,
+ &dst_convert->context,
GFP_ATOMIC);
if (rc) {
context_destroy(&dst->context);
@@ -338,8 +340,8 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context,
dst_convert->hash = context_compute_hash(&dst_convert->context);
target->count = count + 1;
- hash_add_rcu(target->context_to_sid,
- &dst_convert->list, dst_convert->hash);
+ hash_add_rcu(target->context_to_sid, &dst_convert->list,
+ dst_convert->hash);
}
if (context->len)
@@ -373,8 +375,8 @@ static void sidtab_convert_hashtable(struct sidtab *s, u32 count)
}
static int sidtab_convert_tree(union sidtab_entry_inner *edst,
- union sidtab_entry_inner *esrc,
- u32 *pos, u32 count, u32 level,
+ union sidtab_entry_inner *esrc, u32 *pos,
+ u32 count, u32 level,
struct sidtab_convert_params *convert)
{
int rc;
@@ -382,8 +384,8 @@ static int sidtab_convert_tree(union sidtab_entry_inner *edst,
if (level != 0) {
if (!edst->ptr_inner) {
- edst->ptr_inner = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
- GFP_KERNEL);
+ edst->ptr_inner =
+ kzalloc(SIDTAB_NODE_ALLOC_SIZE, GFP_KERNEL);
if (!edst->ptr_inner)
return -ENOMEM;
}
@@ -399,17 +401,18 @@ static int sidtab_convert_tree(union sidtab_entry_inner *edst,
}
} else {
if (!edst->ptr_leaf) {
- edst->ptr_leaf = kzalloc(SIDTAB_NODE_ALLOC_SIZE,
- GFP_KERNEL);
+ edst->ptr_leaf =
+ kzalloc(SIDTAB_NODE_ALLOC_SIZE, GFP_KERNEL);
if (!edst->ptr_leaf)
return -ENOMEM;
}
i = 0;
while (i < SIDTAB_LEAF_ENTRIES && *pos < count) {
- rc = services_convert_context(convert->args,
- &esrc->ptr_leaf->entries[i].context,
- &edst->ptr_leaf->entries[i].context,
- GFP_KERNEL);
+ rc = services_convert_context(
+ convert->args,
+ &esrc->ptr_leaf->entries[i].context,
+ &edst->ptr_leaf->entries[i].context,
+ GFP_KERNEL);
if (rc)
return rc;
(*pos)++;
@@ -489,13 +492,15 @@ void sidtab_cancel_convert(struct sidtab *s)
spin_unlock_irqrestore(&s->lock, flags);
}
-void sidtab_freeze_begin(struct sidtab *s, unsigned long *flags) __acquires(&s->lock)
+void sidtab_freeze_begin(struct sidtab *s, unsigned long *flags)
+ __acquires(&s->lock)
{
spin_lock_irqsave(&s->lock, *flags);
s->frozen = true;
s->convert = NULL;
}
-void sidtab_freeze_end(struct sidtab *s, unsigned long *flags) __releases(&s->lock)
+void sidtab_freeze_end(struct sidtab *s, unsigned long *flags)
+ __releases(&s->lock)
{
spin_unlock_irqrestore(&s->lock, *flags);
}
@@ -600,8 +605,8 @@ out_unlock:
kfree_rcu(victim, rcu_member);
}
-int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry,
- char **out, u32 *out_len)
+int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry, char **out,
+ u32 *out_len)
{
struct sidtab_str_cache *cache;
int rc = 0;
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
index 22258201cd14..832c85c70d83 100644
--- a/security/selinux/ss/sidtab.h
+++ b/security/selinux/ss/sidtab.h
@@ -8,6 +8,7 @@
*
* Copyright (C) 2018 Red Hat, Inc.
*/
+
#ifndef _SS_SIDTAB_H_
#define _SS_SIDTAB_H_
@@ -29,25 +30,26 @@ struct sidtab_entry {
union sidtab_entry_inner {
struct sidtab_node_inner *ptr_inner;
- struct sidtab_node_leaf *ptr_leaf;
+ struct sidtab_node_leaf *ptr_leaf;
};
/* align node size to page boundary */
#define SIDTAB_NODE_ALLOC_SHIFT PAGE_SHIFT
-#define SIDTAB_NODE_ALLOC_SIZE PAGE_SIZE
+#define SIDTAB_NODE_ALLOC_SIZE PAGE_SIZE
-#define size_to_shift(size) ((size) == 1 ? 1 : (const_ilog2((size) - 1) + 1))
+#define size_to_shift(size) ((size) == 1 ? 1 : (const_ilog2((size)-1) + 1))
-#define SIDTAB_INNER_SHIFT \
- (SIDTAB_NODE_ALLOC_SHIFT - size_to_shift(sizeof(union sidtab_entry_inner)))
+#define SIDTAB_INNER_SHIFT \
+ (SIDTAB_NODE_ALLOC_SHIFT - \
+ size_to_shift(sizeof(union sidtab_entry_inner)))
#define SIDTAB_INNER_ENTRIES ((size_t)1 << SIDTAB_INNER_SHIFT)
#define SIDTAB_LEAF_ENTRIES \
(SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry))
#define SIDTAB_MAX_BITS 32
-#define SIDTAB_MAX U32_MAX
+#define SIDTAB_MAX U32_MAX
/* ensure enough tree levels for SIDTAB_MAX entries */
-#define SIDTAB_MAX_LEVEL \
+#define SIDTAB_MAX_LEVEL \
DIV_ROUND_UP(SIDTAB_MAX_BITS - size_to_shift(SIDTAB_LEAF_ENTRIES), \
SIDTAB_INNER_SHIFT)
@@ -69,7 +71,7 @@ struct sidtab_convert_params {
struct sidtab *target;
};
-#define SIDTAB_HASH_BITS CONFIG_SECURITY_SELINUX_SIDTAB_HASH_BITS
+#define SIDTAB_HASH_BITS CONFIG_SECURITY_SELINUX_SIDTAB_HASH_BITS
#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
struct sidtab {
@@ -125,8 +127,10 @@ int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params);
void sidtab_cancel_convert(struct sidtab *s);
-void sidtab_freeze_begin(struct sidtab *s, unsigned long *flags) __acquires(&s->lock);
-void sidtab_freeze_end(struct sidtab *s, unsigned long *flags) __releases(&s->lock);
+void sidtab_freeze_begin(struct sidtab *s, unsigned long *flags)
+ __acquires(&s->lock);
+void sidtab_freeze_end(struct sidtab *s, unsigned long *flags)
+ __releases(&s->lock);
int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
@@ -137,8 +141,8 @@ int sidtab_hash_stats(struct sidtab *sidtab, char *page);
#if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0
void sidtab_sid2str_put(struct sidtab *s, struct sidtab_entry *entry,
const char *str, u32 str_len);
-int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry,
- char **out, u32 *out_len);
+int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry, char **out,
+ u32 *out_len);
#else
static inline void sidtab_sid2str_put(struct sidtab *s,
struct sidtab_entry *entry,
@@ -146,13 +150,11 @@ static inline void sidtab_sid2str_put(struct sidtab *s,
{
}
static inline int sidtab_sid2str_get(struct sidtab *s,
- struct sidtab_entry *entry,
- char **out, u32 *out_len)
+ struct sidtab_entry *entry, char **out,
+ u32 *out_len)
{
return -ENOENT;
}
#endif /* CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 */
-#endif /* _SS_SIDTAB_H_ */
-
-
+#endif /* _SS_SIDTAB_H_ */
diff --git a/security/selinux/ss/symtab.c b/security/selinux/ss/symtab.c
index 43d7f0319ccd..832660fd84a9 100644
--- a/security/selinux/ss/symtab.c
+++ b/security/selinux/ss/symtab.c
@@ -4,6 +4,7 @@
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
+
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
@@ -11,16 +12,17 @@
static unsigned int symhash(const void *key)
{
- const char *p, *keyp;
- unsigned int size;
- unsigned int val;
-
- val = 0;
- keyp = key;
- size = strlen(keyp);
- for (p = keyp; (p - keyp) < size; p++)
- val = (val << 4 | (val >> (8*sizeof(unsigned int)-4))) ^ (*p);
- return val;
+ /*
+ * djb2a
+ * Public domain from cdb v0.75
+ */
+ unsigned int hash = 5381;
+ unsigned char c;
+
+ while ((c = *(const unsigned char *)key++))
+ hash = ((hash << 5) + hash) ^ c;
+
+ return hash;
}
static int symcmp(const void *key1, const void *key2)
diff --git a/security/selinux/ss/symtab.h b/security/selinux/ss/symtab.h
index 0a3b5de79a0f..8e667cdbf38f 100644
--- a/security/selinux/ss/symtab.h
+++ b/security/selinux/ss/symtab.h
@@ -7,14 +7,15 @@
*
* Author : Stephen Smalley, <stephen.smalley.work@gmail.com>
*/
+
#ifndef _SS_SYMTAB_H_
#define _SS_SYMTAB_H_
#include "hashtab.h"
struct symtab {
- struct hashtab table; /* hash table (keyed on a string) */
- u32 nprim; /* number of primary names in table */
+ struct hashtab table; /* hash table (keyed on a string) */
+ u32 nprim; /* number of primary names in table */
};
int symtab_init(struct symtab *s, u32 size);
@@ -22,6 +23,4 @@ int symtab_init(struct symtab *s, u32 size);
int symtab_insert(struct symtab *s, char *name, void *datum);
void *symtab_search(struct symtab *s, const char *name);
-#endif /* _SS_SYMTAB_H_ */
-
-
+#endif /* _SS_SYMTAB_H_ */
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 95fcd2d3433e..90ec4ef1b082 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -76,7 +76,6 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
gfp_t gfp)
{
int rc;
- const struct task_security_struct *tsec = selinux_cred(current_cred());
struct xfrm_sec_ctx *ctx = NULL;
u32 str_len;
@@ -103,7 +102,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
if (rc)
goto err;
- rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
+ rc = avc_has_perm(current_sid(), ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL);
if (rc)
goto err;
@@ -134,12 +133,10 @@ static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx)
*/
static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
{
- const struct task_security_struct *tsec = selinux_cred(current_cred());
-
if (!ctx)
return 0;
- return avc_has_perm(tsec->sid, ctx->ctx_sid,
+ return avc_has_perm(current_sid(), ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
NULL);
}