diff --git a/libcutils/Android.bp b/libcutils/Android.bp index cfe8d2931..b30336ddd 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -110,7 +110,7 @@ cc_library { "klog.cpp", "partition_utils.c", "properties.cpp", - "qtaguid.c", + "qtaguid.cpp", "trace-dev.c", "uevent.c", ], diff --git a/libcutils/include/cutils/qtaguid.h b/libcutils/include/cutils/qtaguid.h new file mode 100644 index 000000000..3f5e41fd3 --- /dev/null +++ b/libcutils/include/cutils/qtaguid.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CUTILS_QTAGUID_H +#define __CUTILS_QTAGUID_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Set tags (and owning UIDs) for network sockets. + */ +extern int qtaguid_tagSocket(int sockfd, int tag, uid_t uid); + +/* + * Untag a network socket before closing. + */ +extern int qtaguid_untagSocket(int sockfd); + +/* + * For the given uid, switch counter sets. + * The kernel only keeps a limited number of sets. + * 2 for now. + */ +extern int qtaguid_setCounterSet(int counterSetNum, uid_t uid); + +/* + * Delete all tag info that relates to the given tag an uid. + * If the tag is 0, then ALL info about the uid is freed. + * The delete data also affects active tagged sockets, which are + * then untagged. + * The calling process can only operate on its own tags. + * Unless it is part of the happy AID_NET_BW_ACCT group. + * In which case it can clobber everything. + */ +extern int qtaguid_deleteTagData(int tag, uid_t uid); + +/* + * Enable/disable qtaguid functionnality at a lower level. + * When pacified, the kernel will accept commands but do nothing. + */ +extern int qtaguid_setPacifier(int on); + +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_QTAG_UID_H */ diff --git a/libcutils/qtaguid.cpp b/libcutils/qtaguid.cpp new file mode 100644 index 000000000..86a5dc4b3 --- /dev/null +++ b/libcutils/qtaguid.cpp @@ -0,0 +1,125 @@ +/* + * Copyright 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 + +#define LOG_TAG "qtaguid" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class netdHandler { + public: + int (*netdTagSocket)(int, uint32_t, uid_t); + int (*netdUntagSocket)(int); + int (*netdSetCounterSet)(uint32_t, uid_t); + int (*netdDeleteTagData)(uint32_t, uid_t); +}; + +int dummyTagSocket(int, uint32_t, uid_t) { + return -EREMOTEIO; +} + +int dummyUntagSocket(int) { + return -EREMOTEIO; +} + +int dummySetCounterSet(uint32_t, uid_t) { + return -EREMOTEIO; +} + +int dummyDeleteTagData(uint32_t, uid_t) { + return -EREMOTEIO; +} + +netdHandler initHandler(void) { + netdHandler handler = {dummyTagSocket, dummyUntagSocket, dummySetCounterSet, dummyDeleteTagData}; + + void* netdClientHandle = dlopen("libnetd_client.so", RTLD_NOW); + if (!netdClientHandle) { + ALOGE("Failed to open libnetd_client.so: %s", dlerror()); + return handler; + } + + handler.netdTagSocket = (int (*)(int, uint32_t, uid_t))dlsym(netdClientHandle, "tagSocket"); + if (!handler.netdTagSocket) { + ALOGE("load netdTagSocket handler failed: %s", dlerror()); + } + + handler.netdUntagSocket = (int (*)(int))dlsym(netdClientHandle, "untagSocket"); + if (!handler.netdUntagSocket) { + ALOGE("load netdUntagSocket handler failed: %s", dlerror()); + } + + handler.netdSetCounterSet = (int (*)(uint32_t, uid_t))dlsym(netdClientHandle, "setCounterSet"); + if (!handler.netdSetCounterSet) { + ALOGE("load netdSetCounterSet handler failed: %s", dlerror()); + } + + handler.netdDeleteTagData = (int (*)(uint32_t, uid_t))dlsym(netdClientHandle, "deleteTagData"); + if (!handler.netdDeleteTagData) { + ALOGE("load netdDeleteTagData handler failed: %s", dlerror()); + } + return handler; +} + +// The language guarantees that this object will be initialized in a thread-safe way. +static netdHandler& getHandler() { + static netdHandler instance = initHandler(); + return instance; +} + +int qtaguid_tagSocket(int sockfd, int tag, uid_t uid) { + // Check the socket fd passed to us is still valid before we load the netd + // client. Pass a already closed socket fd to netd client may let netd open + // the unix socket with the same fd number and pass it to server for + // tagging. + // TODO: move the check into netdTagSocket. + int res = fcntl(sockfd, F_GETFD); + if (res < 0) return res; + + ALOGV("Tagging socket %d with tag %u for uid %d", sockfd, tag, uid); + return getHandler().netdTagSocket(sockfd, tag, uid); +} + +int qtaguid_untagSocket(int sockfd) { + // Similiar to tag socket. We need a check before untag to make sure untag a closed socket fail + // as expected. + // TODO: move the check into netdTagSocket. + int res = fcntl(sockfd, F_GETFD); + if (res < 0) return res; + + ALOGV("Untagging socket %d", sockfd); + return getHandler().netdUntagSocket(sockfd); +} + +int qtaguid_setCounterSet(int counterSetNum, uid_t uid) { + ALOGV("Setting counters to set %d for uid %d", counterSetNum, uid); + return getHandler().netdSetCounterSet(counterSetNum, uid); +} + +int qtaguid_deleteTagData(int tag, uid_t uid) { + ALOGV("Deleting tag data with tag %u for uid %d", tag, uid); + return getHandler().netdDeleteTagData(tag, uid); +} diff --git a/libqtaguid/include/qtaguid/qtaguid.h b/libqtaguid/include/qtaguid/qtaguid.h index 803fe0d9a..72285e532 100644 --- a/libqtaguid/include/qtaguid/qtaguid.h +++ b/libqtaguid/include/qtaguid/qtaguid.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef __CUTILS_QTAGUID_H -#define __CUTILS_QTAGUID_H +#ifndef __LEGACY_QTAGUID_H +#define __LEGACY_QTAGUID_H #include #include @@ -30,19 +30,19 @@ extern "C" { * by calling qtaguid_untagSocket() before closing it, otherwise the qtaguid * module will keep a reference to it even after close. */ -extern int qtaguid_tagSocket(int sockfd, int tag, uid_t uid); +extern int legacy_tagSocket(int sockfd, int tag, uid_t uid); /* * Untag a network socket before closing. */ -extern int qtaguid_untagSocket(int sockfd); +extern int legacy_untagSocket(int sockfd); /* * For the given uid, switch counter sets. * The kernel only keeps a limited number of sets. * 2 for now. */ -extern int qtaguid_setCounterSet(int counterSetNum, uid_t uid); +extern int legacy_setCounterSet(int counterSetNum, uid_t uid); /* * Delete all tag info that relates to the given tag an uid. @@ -53,16 +53,10 @@ extern int qtaguid_setCounterSet(int counterSetNum, uid_t uid); * Unless it is part of the happy AID_NET_BW_ACCT group. * In which case it can clobber everything. */ -extern int qtaguid_deleteTagData(int tag, uid_t uid); - -/* - * Enable/disable qtaguid functionnality at a lower level. - * When pacified, the kernel will accept commands but do nothing. - */ -extern int qtaguid_setPacifier(int on); +extern int legacy_deleteTagData(int tag, uid_t uid); #ifdef __cplusplus } #endif -#endif /* __CUTILS_QTAG_UID_H */ +#endif /* __LEGACY_QTAGUID_H */ diff --git a/libqtaguid/qtaguid.c b/libqtaguid/qtaguid.c index af9fbfa7d..cd38bad77 100644 --- a/libqtaguid/qtaguid.c +++ b/libqtaguid/qtaguid.c @@ -26,13 +26,11 @@ #include #include -#include #include +#include static const char* CTRL_PROCPATH = "/proc/net/xt_qtaguid/ctrl"; static const int CTRL_MAX_INPUT_LEN = 128; -static const char* GLOBAL_PACIFIER_PARAM = "/sys/module/xt_qtaguid/parameters/passive"; -static const char* TAG_PACIFIER_PARAM = "/sys/module/xt_qtaguid/parameters/tag_tracking_passive"; /* * One per proccess. @@ -46,7 +44,7 @@ static int resTrackFd = -1; pthread_once_t resTrackInitDone = PTHREAD_ONCE_INIT; /* Only call once per process. */ -void qtaguid_resTrack(void) { +void legacy_resTrack(void) { resTrackFd = TEMP_FAILURE_RETRY(open("/dev/xt_qtaguid", O_RDONLY | O_CLOEXEC)); } @@ -79,28 +77,12 @@ static int write_ctrl(const char* cmd) { return -savedErrno; } -static int write_param(const char* param_path, const char* value) { - int param_fd; - int res; - - param_fd = TEMP_FAILURE_RETRY(open(param_path, O_WRONLY | O_CLOEXEC)); - if (param_fd < 0) { - return -errno; - } - res = TEMP_FAILURE_RETRY(write(param_fd, value, strlen(value))); - if (res < 0) { - return -errno; - } - close(param_fd); - return 0; -} - -int qtaguid_tagSocket(int sockfd, int tag, uid_t uid) { +int legacy_tagSocket(int sockfd, int tag, uid_t uid) { char lineBuf[CTRL_MAX_INPUT_LEN]; int res; uint64_t kTag = ((uint64_t)tag << 32); - pthread_once(&resTrackInitDone, qtaguid_resTrack); + pthread_once(&resTrackInitDone, legacy_resTrack); snprintf(lineBuf, sizeof(lineBuf), "t %d %" PRIu64 " %d", sockfd, kTag, uid); @@ -115,7 +97,7 @@ int qtaguid_tagSocket(int sockfd, int tag, uid_t uid) { return res; } -int qtaguid_untagSocket(int sockfd) { +int legacy_untagSocket(int sockfd) { char lineBuf[CTRL_MAX_INPUT_LEN]; int res; @@ -130,7 +112,7 @@ int qtaguid_untagSocket(int sockfd) { return res; } -int qtaguid_setCounterSet(int counterSetNum, uid_t uid) { +int legacy_setCounterSet(int counterSetNum, uid_t uid) { char lineBuf[CTRL_MAX_INPUT_LEN]; int res; @@ -141,14 +123,14 @@ int qtaguid_setCounterSet(int counterSetNum, uid_t uid) { return res; } -int qtaguid_deleteTagData(int tag, uid_t uid) { +int legacy_deleteTagData(int tag, uid_t uid) { char lineBuf[CTRL_MAX_INPUT_LEN]; int cnt = 0, res = 0; uint64_t kTag = (uint64_t)tag << 32; ALOGV("Deleting tag data with tag %" PRIx64 "{%d,0} for uid %d", kTag, tag, uid); - pthread_once(&resTrackInitDone, qtaguid_resTrack); + pthread_once(&resTrackInitDone, legacy_resTrack); snprintf(lineBuf, sizeof(lineBuf), "d %" PRIu64 " %d", kTag, uid); res = write_ctrl(lineBuf); @@ -159,16 +141,3 @@ int qtaguid_deleteTagData(int tag, uid_t uid) { return res; } - -int qtaguid_setPacifier(int on) { - const char* value; - - value = on ? "Y" : "N"; - if (write_param(GLOBAL_PACIFIER_PARAM, value) < 0) { - return -errno; - } - if (write_param(TAG_PACIFIER_PARAM, value) < 0) { - return -errno; - } - return 0; -}