Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

Commit

Permalink
Add FwmarkServer support for querying whether a UID can access a NetID
Browse files Browse the repository at this point in the history
This new FwmarkServer API is only accessible from system apps.

Bug:20470604
Change-Id: Ie2376cdddc10f658fcc5802ef3e8dc9f1948d5c0
  • Loading branch information
JensenPaul committed May 6, 2015
1 parent 390e4ea commit d1df597
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 25 deletions.
36 changes: 20 additions & 16 deletions client/FwmarkClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include "FwmarkClient.h"

#include "FwmarkCommand.h"

#include <errno.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -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;
Expand All @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion client/FwmarkClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -30,7 +32,7 @@ class FwmarkClient {

// 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;
Expand Down
15 changes: 10 additions & 5 deletions client/NetdClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand All @@ -201,13 +201,18 @@ 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) {
if (socketFd < 0) {
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);
}
4 changes: 3 additions & 1 deletion include/FwmarkCommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions include/NetdClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 9 additions & 2 deletions server/FwmarkServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))) {
Expand All @@ -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
Expand Down

0 comments on commit d1df597

Please sign in to comment.