ANDROID: selinux: modify RTM_GETLINK permission
authorJeff Vander Stoep <jeffv@google.com>
Wed, 22 Jan 2020 10:19:58 +0000 (11:19 +0100)
committerJeffrey Vander Stoep <jeffv@google.com>
Thu, 23 Jan 2020 21:44:44 +0000 (21:44 +0000)
Map the permission gating RTM_GETLINK messages to a new permission so
that it can be distinguished from the other netlink route permissions
in selinux policy.

This is a temporary Android-only patch that will be deprecated in
newer kernels once the long-term solution lands as discusssed on the
mailing list [1]. The maintainer's recommended solution is more
general, much more complex, and likely not suitable for backporting.
This patch provides the minimal change needed for Android including
the userspace settable trigger which ensures that the permission
change is only applied to the newest version of Android which
contains the changes needed for userpace compatibility.

[1]: https://lore.kernel.org/selinux/20200116142653.61738-1-jeffv@google.com/

Bug: 141455849
Bug: 148218425

Test: CtsSelinuxTargetSdkCurrentTestCases
Test: atest bionic-unit-tests-static
Test: atest NetworkInterfaceTest
Test: Connect to Wi-Fi network
Test: Set up hotspot
Test: Cast from device
Test: Pair Bluetooth device
Test: Call getifaddrs() directly from within an app.
Test: Call NetworkInterface#getNetworkInterfaces() from within an app.

Change-Id: I7b44ce60ad98f858c412722d41b9842f8577151f
Signed-off-by: Jeff Vander Stoep <jeffv@google.com>
security/selinux/include/classmap.h
security/selinux/include/security.h
security/selinux/nlmsgtab.c
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c

index 5ae315ab060be09fac474ef71f18c33463391ba6..702bdaf07252dd63482316136797b510542c38ff 100644 (file)
@@ -115,7 +115,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 } },
index 02f0412d42f24d485ed98bc7ff0c70fd5c7b8f47..45cc615fddaedd9852256e8e524a7da080572aba 100644 (file)
@@ -81,6 +81,7 @@ enum {
 
 extern char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX];
 
+extern int selinux_android_netlink_route;
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 extern int selinux_policycap_extsockclass;
@@ -276,6 +277,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);
 
 #endif /* _SELINUX_SECURITY_H_ */
 
index 7b7433a1a34c6257d1a93f2f976e5b71cce9c60a..963930b4e2f8cd5c7126157074f1dd542367c053 100644 (file)
@@ -28,7 +28,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 },
@@ -195,3 +195,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_android_netlink_route)
+               nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READPRIV);
+       else
+               nlmsg_set_getlink_perm(NETLINK_ROUTE_SOCKET__NLMSG_READ);
+}
index 9d9f6bb1e56efa05135eda2937b17309bbe6462b..51564b2aba9e18374d6846fccea77b8f83cc0684 100644 (file)
@@ -2386,6 +2386,10 @@ int policydb_read(struct policydb *p, void *fp)
        p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
        p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
 
+       if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_ANDROID_NETLINK_ROUTE)) {
+               p->android_netlink_route = 1;
+       }
+
        if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
                rc = ebitmap_read(&p->policycaps, fp);
                if (rc)
index 215f8f30ac5a5dcfa5126c8357da7cebf9639a1b..dbb0ed57ed8b164d1001b5cb761358bbb553f9ac 100644 (file)
@@ -238,6 +238,7 @@ struct genfs {
 /* The policy database */
 struct policydb {
        int mls_enabled;
+       int android_netlink_route;
 
        /* symbol tables */
        struct symtab symtab[SYM_NUM];
@@ -324,6 +325,7 @@ extern int policydb_write(struct policydb *p, void *fp);
 #define PERM_SYMTAB_SIZE 32
 
 #define POLICYDB_CONFIG_MLS    1
+#define POLICYDB_CONFIG_ANDROID_NETLINK_ROUTE    (1 << 31)
 
 /* the config flags related to unknown classes/perms are bits 2 and 3 */
 #define REJECT_UNKNOWN 0x00000002
index b275743e23cc1d919d1049f873d8d92319f9d2a2..f91bcb90825c44a3c4204b317655c44e536a3674 100644 (file)
@@ -80,6 +80,7 @@ char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
        "nnp_nosuid_transition"
 };
 
+int selinux_android_netlink_route;
 int selinux_policycap_netpeer;
 int selinux_policycap_openperm;
 int selinux_policycap_extsockclass;
@@ -2026,6 +2027,9 @@ static void security_load_policycaps(void)
                        pr_info("SELinux:  unknown policy capability %u\n",
                                i);
        }
+
+       selinux_android_netlink_route = policydb.android_netlink_route;
+       selinux_nlmsg_init();
 }
 
 static int security_preserve_bools(struct policydb *p);