diff options
author | Paul Jensen <pauljensen@google.com> | 2015-05-06 07:29:56 -0400 |
---|---|---|
committer | Paul Jensen <pauljensen@google.com> | 2015-05-06 07:29:56 -0400 |
commit | d1df597001aadd5d83c9a3d1fe8bbde2bc9256ca (patch) | |
tree | 1a4dca47a641a10b41c282b04edadcce9acd5bd1 | |
parent | 390e4ea8106f9e741bc80fb962aaee94d5b28cbb (diff) | |
download | netd-d1df597001aadd5d83c9a3d1fe8bbde2bc9256ca.tar.gz |
Add FwmarkServer support for querying whether a UID can access a NetID
This new FwmarkServer API is only accessible from system apps.
Bug:20470604
Change-Id: Ie2376cdddc10f658fcc5802ef3e8dc9f1948d5c0
-rw-r--r-- | client/FwmarkClient.cpp | 36 | ||||
-rw-r--r-- | client/FwmarkClient.h | 4 | ||||
-rw-r--r-- | client/NetdClient.cpp | 15 | ||||
-rw-r--r-- | include/FwmarkCommand.h | 4 | ||||
-rw-r--r-- | include/NetdClient.h | 2 | ||||
-rw-r--r-- | server/FwmarkServer.cpp | 11 |
6 files changed, 47 insertions, 25 deletions
diff --git a/client/FwmarkClient.cpp b/client/FwmarkClient.cpp index 0ac1fbbc..5074a786 100644 --- a/client/FwmarkClient.cpp +++ b/client/FwmarkClient.cpp @@ -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; diff --git a/client/FwmarkClient.h b/client/FwmarkClient.h index 620275e5..df7686d9 100644 --- a/client/FwmarkClient.h +++ b/client/FwmarkClient.h @@ -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; diff --git a/client/NetdClient.cpp b/client/NetdClient.cpp index 3157d3a9..392b0af6 100644 --- a/client/NetdClient.cpp +++ b/client/NetdClient.cpp @@ -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); } diff --git a/include/FwmarkCommand.h b/include/FwmarkCommand.h index 57464b41..be068991 100644 --- a/include/FwmarkCommand.h +++ b/include/FwmarkCommand.h @@ -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 diff --git a/include/NetdClient.h b/include/NetdClient.h index 71529a34..7db09068 100644 --- a/include/NetdClient.h +++ b/include/NetdClient.h @@ -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 diff --git a/server/FwmarkServer.cpp b/server/FwmarkServer.cpp index b11e0757..530e96a2 100644 --- a/server/FwmarkServer.cpp +++ b/server/FwmarkServer.cpp @@ -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 |