Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get an Android Process running with the CAP_NET_ADMIN capability

I have an Android activity utilizing a JNI library that uses netlink commands to configure a network interface (in this case a socketcan interface). If I run the activity, the network interface configuration fails with an EPERM error from RTNETLINK. The commands that are failing require the CAP_NET_ADMIN capability in order to successfully complete. As such running the code as root succeeds, and also running as root and then limiting the capabilities to only CAP_NET_ADMIN using capset.

I added the following permissions to the applications manifest that gave me the impression that my process would be given the NET_ADMIN capabilities:

<uses-permission android:name="android.permission.INTERNET" />    
<uses-permission android:name="android.permission.NET_ADMIN" />

This put the process in the inet and net_admin groups, but the process did not receive the CAP_NET_ADMIN capability resulting in the netlink commands failing with EPERM.

In various searches I have made on this topic I have found hints that the capability should be applied. eg, from http://elinux.org/Android_Security

#define             GID     Capability
AID_NET_BT_ADMIN    3001    Can create an RFCOMM, SCO, or L2CAPP Bluetooth socket
AID_NET_BT          3002    Can create a Bluetooth socket
AID_INET            3003    Can create IPv4 or IPv6 socket
AID_NET_RAW         3004    Can create certain kinds of IPv4 sockets??
AID_NET_ADMIN*      3005    Allow CAP_NET_ADMIN permissions for process 

Unfortunately, this doesn't seem to apply to my system.

NOTE: I am running with a system and kernel modified by a chipset vendor, so it is possible that something has been modified that stops this from working.

Does anyone know

  • If this should just work?
  • What other steps are required to add the capability to a process?
  • Whether it is even possible?
like image 965
Piklor Avatar asked Oct 24 '12 02:10

Piklor


2 Answers

It turns out that Android modifies the kernel capability system to allow verification of specific capabilities based on group-id. Unfortunately the modifications made don't seem to cover all cases. To resolve the problem I was having, I modified the cap_netlink_recv check to use the Android modified cap_capability call. This allows users in the net_link group to obtain CAP_NET_LINK capabilities.

This change seems to be within the spirit of the modifications made to the Android kernel, and works for my situation.

diff --git a/security/commoncap.c b/security/commoncap.c
        index ccfe568..f069f8d 100644
        --- a/security/commoncap.c
        +++ b/security/commoncap.c
        @@ -56,21 +56,23 @@
    }
}

int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
{
» return 0;
}

int cap_netlink_recv(struct sk_buff *skb, int cap)
{
-» if (!cap_raised(current_cap(), cap))
+» if (cap_capable(current, current_cred(),
+» » » current_cred()->user->user_ns, cap,
+» » » SECURITY_CAP_NOAUDIT) != 0)
» » return -EPERM;
» return 0;
}
EXPORT_SYMBOL(cap_netlink_recv);

/**
 * cap_capable - Determine whether a task has a particular effective capability
 * @tsk: The task to query
 * @cred: The credentials to use
 * @ns:  The user namespace in which we need the capability
like image 90
Piklor Avatar answered Sep 28 '22 16:09

Piklor


Indeed, in the netlink path, there is no check for additional permissions for kernel versions before v3.1-18-gfd77846.

Originally it did not seem to be a good idea to replace cap_raised completely, so here I chose to prepend a similar check as the one in cap_capable. Other possible caps are CAP_SYS_ADMIN, CAP_AUDIT_CONTROL and CAP_AUDIT_WRITE, but these are not relevant to networking. Note that since the above commit, it ultimately ends up calling cap_capable (via capable).

The patch:

diff --git a/security/commoncap.c b/security/commoncap.c
index 8bfbd13..485245a 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -63,6 +63,10 @@ int cap_netlink_send(struct sock *sk, struct sk_buff *skb)

 int cap_netlink_recv(struct sk_buff *skb, int cap)
 {
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+   if (cap == CAP_NET_ADMIN && in_egroup_p(AID_NET_ADMIN))
+       return 0;
+#endif
    if (!cap_raised(current_cap(), cap))
        return -EPERM;
    return 0;

For those looking at CAP_NET_RAW, for that you need to be in the net_raw group. Either add that group to the existing android.permission.NET_ADMIN permission or apply the following framework patch:

diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1e7dcf7..07f5d94 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -927,6 +927,12 @@
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature" />

+    <!-- Allows access to raw sockets, allowing full network access and spoofing.
+         @hide -->
+    <permission android:name="android.permission.NET_RAW"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature" />
+
     <!-- Allows registration for remote audio playback. @hide -->
     <permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 47cb7ab..9c209c3 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -82,6 +82,10 @@
         <group gid="net_admin" />
     </permission>

+    <permission name="android.permission.NET_RAW" >
+        <group gid="net_raw" />
+    </permission>
+
     <!-- The group that /cache belongs to, linked to the permission
          set on the applications that can access /cache -->
     <permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
like image 43
Lekensteyn Avatar answered Sep 28 '22 16:09

Lekensteyn