@@ -116,7 +116,7 @@ struct security_class_mapping secclass_map[] = {
{ COMMON_IPC_PERMS, NULL } },
{ "netlink_route_socket",
{ COMMON_SOCK_PERMS,
- "nlmsg_read", "nlmsg_write", NULL } },
+ "nlmsg_read", "nlmsg_write", "nlmsg_readpriv", NULL } },
{ "netlink_tcpdiag_socket",
{ COMMON_SOCK_PERMS,
"nlmsg_read", "nlmsg_write", NULL } },
@@ -79,6 +79,7 @@ enum {
POLICYDB_CAPABILITY_ALWAYSNETWORK,
POLICYDB_CAPABILITY_CGROUPSECLABEL,
POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION,
+ POLICYDB_CAPABILITY_NETLINK_ROUTE_GETLINK,
__POLICYDB_CAPABILITY_MAX
};
#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
@@ -209,6 +210,13 @@ static inline bool selinux_policycap_nnp_nosuid_transition(void)
return state->policycap[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION];
}
+static inline bool selinux_policycap_nlroute_getlink(void)
+{
+ struct selinux_state *state = &selinux_state;
+
+ return state->policycap[POLICYDB_CAPABILITY_NETLINK_ROUTE_GETLINK];
+}
+
int security_mls_enabled(struct selinux_state *state);
int security_load_policy(struct selinux_state *state,
void *data, size_t len);
@@ -422,6 +430,7 @@ extern struct vfsmount *selinuxfs_mount;
extern void selnl_notify_setenforce(int val);
extern void selnl_notify_policyload(u32 seqno);
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
+extern void selinux_nlmsg_init(void);
extern void avtab_cache_init(void);
extern void ebitmap_cache_init(void);
@@ -25,7 +25,7 @@ struct nlmsg_perm {
u32 perm;
};
-static const struct nlmsg_perm nlmsg_route_perms[] =
+static struct nlmsg_perm nlmsg_route_perms[] =
{
{ RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
@@ -208,3 +208,27 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
return err;
}
+
+static void nlmsg_set_getlink_perm(u32 perm)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nlmsg_route_perms); i++) {
+ if (nlmsg_route_perms[i].nlmsg_type == RTM_GETLINK) {
+ nlmsg_route_perms[i].perm = perm;
+ break;
+ }
+ }
+}
+
+/**
+ * Use nlmsg_readpriv as the permission for RTM_GETLINK messages if the
+ * netlink_route_getlink policy capability is set. Otherwise use nlmsg_read.
+ */
+void selinux_nlmsg_init(void)
+{
+ if (selinux_policycap_nlroute_getlink())
+ nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READPRIV);
+ else
+ nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READ);
+}
@@ -73,7 +73,8 @@ const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
"extended_socket_class",
"always_check_network",
"cgroup_seclabel",
- "nnp_nosuid_transition"
+ "nnp_nosuid_transition",
+ "netlink_route_getlink"
};
static struct selinux_ss selinux_ss;
@@ -2157,6 +2158,12 @@ static void security_load_policycaps(struct selinux_state *state)
}
}
+static void security_policycaps_init(struct selinux_state *state)
+{
+ security_load_policycaps(state);
+ selinux_nlmsg_init();
+}
+
static int security_preserve_bools(struct selinux_state *state,
struct policydb *newpolicydb);
@@ -2222,7 +2229,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
}
state->ss->sidtab = newsidtab;
- security_load_policycaps(state);
+ security_policycaps_init(state);
selinux_mark_initialized(state);
seqno = ++state->ss->latest_granting;
selinux_complete_init();
@@ -2294,7 +2301,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len)
write_lock_irq(&state->ss->policy_rwlock);
memcpy(policydb, newpolicydb, sizeof(*policydb));
state->ss->sidtab = newsidtab;
- security_load_policycaps(state);
+ security_policycaps_init(state);
oldmapping = state->ss->map.mapping;
state->ss->map.mapping = newmap.mapping;
state->ss->map.size = newmap.size;
Persistent device identifiers like MAC addresses are sensitive because they are (usually) unique and can be used to identify/track a device or user [1]. The MAC address is accessible via the RTM_GETLINK request message type of a netlink route socket[2] which returns the RTM_NEWLINK message. Mapping RTM_GETLINK to a separate permission enables restricting access to the MAC address without changing the behavior for other RTM_GET* message types. [1] https://adamdrake.com/mac-addresses-udids-and-privacy.html [2] Other access vectors like ioctl(SIOCGIFHWADDR) are already covered by existing LSM hooks. v3: -Add security_policycaps_init() to handle loading of policycaps, selinux_nlmsg_init(), and future initializations resulting from policy capabilities. v2: -Fix comment. -Use ARRAY_SIZE instead of sizeof/sizeof. -Call selinux_nlmsg_init() after both instances of selinux_load_policycaps(). Signed-off-by: Jeff Vander Stoep <jeffv@google.com> --- security/selinux/include/classmap.h | 2 +- security/selinux/include/security.h | 9 +++++++++ security/selinux/nlmsgtab.c | 26 +++++++++++++++++++++++++- security/selinux/ss/services.c | 13 ++++++++++--- 4 files changed, 45 insertions(+), 5 deletions(-)