1 /* 2 ** Copyright 2011, The Android Open Source Project 3 ** 4 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** you may not use this file except in compliance with the License. 6 ** You may obtain a copy of the License at 7 ** 8 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** 10 ** Unless required by applicable law or agreed to in writing, software 11 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** See the License for the specific language governing permissions and 14 ** limitations under the License. 15 */ 16 17 // #define LOG_NDEBUG 0 18 19 #define LOG_TAG "qtaguid" 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <inttypes.h> 24 #include <pthread.h> 25 #include <stdio.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 #include <log/log.h> 30 #include <qtaguid/qtaguid.h> 31 32 static const char* CTRL_PROCPATH = "/proc/net/xt_qtaguid/ctrl"; 33 static const int CTRL_MAX_INPUT_LEN = 128; 34 35 /* 36 * One per proccess. 37 * Once the device is open, this process will have its socket tags tracked. 38 * And on exit or untimely death, all socket tags will be removed. 39 * A process can only open /dev/xt_qtaguid once. 40 * It should not close it unless it is really done with all the socket tags. 41 * Failure to open it will be visible when socket tagging will be attempted. 42 */ 43 static int resTrackFd = -1; 44 pthread_once_t resTrackInitDone = PTHREAD_ONCE_INIT; 45 46 /* Only call once per process. */ 47 void legacy_resTrack(void) { 48 resTrackFd = TEMP_FAILURE_RETRY(open("/dev/xt_qtaguid", O_RDONLY | O_CLOEXEC)); 49 } 50 51 /* 52 * Returns: 53 * 0 on success. 54 * -errno on failure. 55 */ 56 static int write_ctrl(const char* cmd) { 57 int fd, res, savedErrno; 58 59 ALOGV("write_ctrl(%s)", cmd); 60 61 fd = TEMP_FAILURE_RETRY(open(CTRL_PROCPATH, O_WRONLY | O_CLOEXEC)); 62 if (fd < 0) { 63 return -errno; 64 } 65 66 res = TEMP_FAILURE_RETRY(write(fd, cmd, strlen(cmd))); 67 if (res < 0) { 68 savedErrno = errno; 69 } else { 70 savedErrno = 0; 71 } 72 if (res < 0) { 73 // ALOGV is enough because all the callers also log failures 74 ALOGV("Failed write_ctrl(%s) res=%d errno=%d", cmd, res, savedErrno); 75 } 76 close(fd); 77 return -savedErrno; 78 } 79 80 int legacy_tagSocket(int sockfd, int tag, uid_t uid) { 81 char lineBuf[CTRL_MAX_INPUT_LEN]; 82 int res; 83 uint64_t kTag = ((uint64_t)tag << 32); 84 85 pthread_once(&resTrackInitDone, legacy_resTrack); 86 87 snprintf(lineBuf, sizeof(lineBuf), "t %d %" PRIu64 " %d", sockfd, kTag, uid); 88 89 ALOGV("Tagging socket %d with tag %" PRIx64 "{%u,0} for uid %d", sockfd, kTag, tag, uid); 90 91 res = write_ctrl(lineBuf); 92 if (res < 0) { 93 ALOGI("Tagging socket %d with tag %" PRIx64 "(%d) for uid %d failed errno=%d", sockfd, kTag, 94 tag, uid, res); 95 } 96 97 return res; 98 } 99 100 int legacy_untagSocket(int sockfd) { 101 char lineBuf[CTRL_MAX_INPUT_LEN]; 102 int res; 103 104 ALOGV("Untagging socket %d", sockfd); 105 106 snprintf(lineBuf, sizeof(lineBuf), "u %d", sockfd); 107 res = write_ctrl(lineBuf); 108 if (res < 0) { 109 ALOGI("Untagging socket %d failed errno=%d", sockfd, res); 110 } 111 112 return res; 113 } 114 115 int legacy_setCounterSet(int counterSetNum, uid_t uid) { 116 char lineBuf[CTRL_MAX_INPUT_LEN]; 117 int res; 118 119 ALOGV("Setting counters to set %d for uid %d", counterSetNum, uid); 120 121 snprintf(lineBuf, sizeof(lineBuf), "s %d %d", counterSetNum, uid); 122 res = write_ctrl(lineBuf); 123 return res; 124 } 125 126 int legacy_deleteTagData(int tag, uid_t uid) { 127 char lineBuf[CTRL_MAX_INPUT_LEN]; 128 int cnt = 0, res = 0; 129 uint64_t kTag = (uint64_t)tag << 32; 130 131 ALOGV("Deleting tag data with tag %" PRIx64 "{%d,0} for uid %d", kTag, tag, uid); 132 133 pthread_once(&resTrackInitDone, legacy_resTrack); 134 135 snprintf(lineBuf, sizeof(lineBuf), "d %" PRIu64 " %d", kTag, uid); 136 res = write_ctrl(lineBuf); 137 if (res < 0) { 138 ALOGI("Deleting tag data with tag %" PRIx64 "/%d for uid %d failed with cnt=%d errno=%d", 139 kTag, tag, uid, cnt, errno); 140 } 141 142 return res; 143 } 144