OSDN Git Service

Add FwmarkServer support for querying whether a UID can access a NetID
authorPaul Jensen <pauljensen@google.com>
Wed, 6 May 2015 11:29:56 +0000 (07:29 -0400)
committerPaul Jensen <pauljensen@google.com>
Wed, 6 May 2015 11:29:56 +0000 (07:29 -0400)
This new FwmarkServer API is only accessible from system apps.

Bug:20470604
Change-Id: Ie2376cdddc10f658fcc5802ef3e8dc9f1948d5c0

client/FwmarkClient.cpp
client/FwmarkClient.h
client/NetdClient.cpp
include/FwmarkCommand.h
include/NetdClient.h
server/FwmarkServer.cpp

index 0ac1fbb..5074a78 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "FwmarkClient.h"
 
+#include "FwmarkCommand.h"
+
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
@@ -42,7 +44,7 @@ FwmarkClient::~FwmarkClient() {
     }
 }
 
-int FwmarkClient::send(void* data, size_t len, int fd) {
+int FwmarkClient::send(FwmarkCommand* data, int fd) {
     mChannel = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
     if (mChannel == -1) {
         return -errno;
@@ -57,27 +59,29 @@ int FwmarkClient::send(void* data, size_t len, int fd) {
 
     iovec iov;
     iov.iov_base = data;
-    iov.iov_len = len;
+    iov.iov_len = sizeof(*data);
 
     msghdr message;
     memset(&message, 0, sizeof(message));
     message.msg_iov = &iov;
     message.msg_iovlen = 1;
 
-    union {
-        cmsghdr cmh;
-        char cmsg[CMSG_SPACE(sizeof(fd))];
-    } cmsgu;
-
-    memset(cmsgu.cmsg, 0, sizeof(cmsgu.cmsg));
-    message.msg_control = cmsgu.cmsg;
-    message.msg_controllen = sizeof(cmsgu.cmsg);
-
-    cmsghdr* const cmsgh = CMSG_FIRSTHDR(&message);
-    cmsgh->cmsg_len = CMSG_LEN(sizeof(fd));
-    cmsgh->cmsg_level = SOL_SOCKET;
-    cmsgh->cmsg_type = SCM_RIGHTS;
-    memcpy(CMSG_DATA(cmsgh), &fd, sizeof(fd));
+    if (data->cmdId != FwmarkCommand::QUERY_USER_ACCESS) {
+        union {
+            cmsghdr cmh;
+            char cmsg[CMSG_SPACE(sizeof(fd))];
+        } cmsgu;
+
+        memset(cmsgu.cmsg, 0, sizeof(cmsgu.cmsg));
+        message.msg_control = cmsgu.cmsg;
+        message.msg_controllen = sizeof(cmsgu.cmsg);
+
+        cmsghdr* const cmsgh = CMSG_FIRSTHDR(&message);
+        cmsgh->cmsg_len = CMSG_LEN(sizeof(fd));
+        cmsgh->cmsg_level = SOL_SOCKET;
+        cmsgh->cmsg_type = SCM_RIGHTS;
+        memcpy(CMSG_DATA(cmsgh), &fd, sizeof(fd));
+    }
 
     if (TEMP_FAILURE_RETRY(sendmsg(mChannel, &message, 0)) == -1) {
         return -errno;
index 620275e..df7686d 100644 (file)
@@ -19,6 +19,8 @@
 
 #include <sys/socket.h>
 
+struct FwmarkCommand;
+
 class FwmarkClient {
 public:
     // Returns true if a socket of the given |family| should be sent to the fwmark server to have
@@ -30,7 +32,7 @@ public:
 
     // Sends |data| to the fwmark server, along with |fd| as ancillary data using cmsg(3).
     // Returns 0 on success or a negative errno value on failure.
-    int send(void* data, size_t len, int fd);
+    int send(FwmarkCommand* data, int fd);
 
 private:
     int mChannel;
index 3157d3a..392b0af 100644 (file)
@@ -65,7 +65,7 @@ int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags)
     }
     if (FwmarkClient::shouldSetFwmark(family)) {
         FwmarkCommand command = {FwmarkCommand::ON_ACCEPT, 0, 0};
-        if (int error = FwmarkClient().send(&command, sizeof(command), acceptedSocket)) {
+        if (int error = FwmarkClient().send(&command, acceptedSocket)) {
             return closeFdAndSetErrno(acceptedSocket, error);
         }
     }
@@ -75,7 +75,7 @@ int netdClientAccept4(int sockfd, sockaddr* addr, socklen_t* addrlen, int flags)
 int netdClientConnect(int sockfd, const sockaddr* addr, socklen_t addrlen) {
     if (sockfd >= 0 && addr && FwmarkClient::shouldSetFwmark(addr->sa_family)) {
         FwmarkCommand command = {FwmarkCommand::ON_CONNECT, 0, 0};
-        if (int error = FwmarkClient().send(&command, sizeof(command), sockfd)) {
+        if (int error = FwmarkClient().send(&command, sockfd)) {
             errno = -error;
             return -1;
         }
@@ -185,7 +185,7 @@ extern "C" int setNetworkForSocket(unsigned netId, int socketFd) {
         return -EBADF;
     }
     FwmarkCommand command = {FwmarkCommand::SELECT_NETWORK, netId, 0};
-    return FwmarkClient().send(&command, sizeof(command), socketFd);
+    return FwmarkClient().send(&command, socketFd);
 }
 
 extern "C" int setNetworkForProcess(unsigned netId) {
@@ -201,7 +201,7 @@ extern "C" int protectFromVpn(int socketFd) {
         return -EBADF;
     }
     FwmarkCommand command = {FwmarkCommand::PROTECT_FROM_VPN, 0, 0};
-    return FwmarkClient().send(&command, sizeof(command), socketFd);
+    return FwmarkClient().send(&command, socketFd);
 }
 
 extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
@@ -209,5 +209,10 @@ extern "C" int setNetworkForUser(uid_t uid, int socketFd) {
         return -EBADF;
     }
     FwmarkCommand command = {FwmarkCommand::SELECT_FOR_USER, 0, uid};
-    return FwmarkClient().send(&command, sizeof(command), socketFd);
+    return FwmarkClient().send(&command, socketFd);
+}
+
+extern "C" int queryUserAccess(uid_t uid, unsigned netId) {
+    FwmarkCommand command = {FwmarkCommand::QUERY_USER_ACCESS, netId, uid};
+    return FwmarkClient().send(&command, -1);
 }
index 57464b4..be06899 100644 (file)
@@ -27,9 +27,11 @@ struct FwmarkCommand {
         SELECT_NETWORK,
         PROTECT_FROM_VPN,
         SELECT_FOR_USER,
+        QUERY_USER_ACCESS,
     } cmdId;
     unsigned netId;  // used only in the SELECT_NETWORK command; ignored otherwise.
-    uid_t uid;  // used only in the SELECT_FOR_USER command; ignored otherwise.
+    uid_t uid;  // used only in the SELECT_FOR_USER and QUERY_USER_ACCESS commands;
+                // ignored otherwise.
 };
 
 #endif  // NETD_INCLUDE_FWMARK_COMMAND_H
index 71529a3..7db0906 100644 (file)
@@ -37,6 +37,8 @@ int protectFromVpn(int socketFd);
 
 int setNetworkForUser(uid_t uid, int socketFd);
 
+int queryUserAccess(uid_t uid, unsigned netId);
+
 __END_DECLS
 
 #endif  // NETD_INCLUDE_NETD_CLIENT_H
index b11e075..530e96a 100644 (file)
@@ -75,6 +75,15 @@ int FwmarkServer::processClient(SocketClient* client, int* socketFd) {
         return -EBADMSG;
     }
 
+    Permission permission = mNetworkController->getPermissionForUser(client->getUid());
+
+    if (command.cmdId == FwmarkCommand::QUERY_USER_ACCESS) {
+        if ((permission & PERMISSION_SYSTEM) != PERMISSION_SYSTEM) {
+            return -EPERM;
+        }
+        return mNetworkController->checkUserNetworkAccess(command.uid, command.netId);
+    }
+
     cmsghdr* const cmsgh = CMSG_FIRSTHDR(&message);
     if (cmsgh && cmsgh->cmsg_level == SOL_SOCKET && cmsgh->cmsg_type == SCM_RIGHTS &&
         cmsgh->cmsg_len == CMSG_LEN(sizeof(*socketFd))) {
@@ -91,8 +100,6 @@ int FwmarkServer::processClient(SocketClient* client, int* socketFd) {
         return -errno;
     }
 
-    Permission permission = mNetworkController->getPermissionForUser(client->getUid());
-
     switch (command.cmdId) {
         case FwmarkCommand::ON_ACCEPT: {
             // Called after a socket accept(). The kernel would've marked the NetId and necessary