1 /* 2 * Copyright (C) 2012-2014 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 #include <ctype.h> 18 #include <limits.h> 19 #include <stdio.h> 20 #include <sys/cdefs.h> 21 #include <sys/prctl.h> 22 #include <sys/socket.h> 23 #include <sys/types.h> 24 #include <sys/un.h> 25 #include <unistd.h> 26 27 #include <cutils/sockets.h> 28 #include <private/android_filesystem_config.h> 29 #include <private/android_logger.h> 30 31 #include "LogBuffer.h" 32 #include "LogListener.h" 33 #include "LogUtils.h" 34 35 LogListener::LogListener(LogBufferInterface* buf, LogReader* reader) 36 : SocketListener(getLogSocket(), false), logbuf(buf), reader(reader) { 37 } 38 39 bool LogListener::onDataAvailable(SocketClient* cli) { 40 static bool name_set; 41 if (!name_set) { 42 prctl(PR_SET_NAME, "logd.writer"); 43 name_set = true; 44 } 45 46 char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time) + 47 LOGGER_ENTRY_MAX_PAYLOAD]; 48 struct iovec iov = { buffer, sizeof(buffer) }; 49 50 alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))]; 51 struct msghdr hdr = { 52 NULL, 0, &iov, 1, control, sizeof(control), 0, 53 }; 54 55 int socket = cli->getSocket(); 56 57 // To clear the entire buffer is secure/safe, but this contributes to 1.68% 58 // overhead under logging load. We are safe because we check counts. 59 // memset(buffer, 0, sizeof(buffer)); 60 ssize_t n = recvmsg(socket, &hdr, 0); 61 if (n <= (ssize_t)(sizeof(android_log_header_t))) { 62 return false; 63 } 64 65 struct ucred* cred = NULL; 66 67 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr); 68 while (cmsg != NULL) { 69 if (cmsg->cmsg_level == SOL_SOCKET && 70 cmsg->cmsg_type == SCM_CREDENTIALS) { 71 cred = (struct ucred*)CMSG_DATA(cmsg); 72 break; 73 } 74 cmsg = CMSG_NXTHDR(&hdr, cmsg); 75 } 76 77 struct ucred fake_cred; 78 if (cred == NULL) { 79 cred = &fake_cred; 80 cred->pid = 0; 81 cred->uid = DEFAULT_OVERFLOWUID; 82 } 83 84 if (cred->uid == AID_LOGD) { 85 // ignore log messages we send to ourself. 86 // Such log messages are often generated by libraries we depend on 87 // which use standard Android logging. 88 return false; 89 } 90 91 android_log_header_t* header = 92 reinterpret_cast<android_log_header_t*>(buffer); 93 if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX || 94 header->id == LOG_ID_KERNEL) { 95 return false; 96 } 97 98 if ((header->id == LOG_ID_SECURITY) && 99 (!__android_log_security() || 100 !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) { 101 return false; 102 } 103 104 // Check credential validity, acquire corrected details if not supplied. 105 if (cred->pid == 0) { 106 cred->pid = logbuf ? logbuf->tidToPid(header->tid) 107 : android::tidToPid(header->tid); 108 if (cred->pid == getpid()) { 109 // We expect that /proc/<tid>/ is accessible to self even without 110 // readproc group, so that we will always drop messages that come 111 // from any of our logd threads and their library calls. 112 return false; // ignore self 113 } 114 } 115 if (cred->uid == DEFAULT_OVERFLOWUID) { 116 uid_t uid = 117 logbuf ? logbuf->pidToUid(cred->pid) : android::pidToUid(cred->pid); 118 if (uid == AID_LOGD) { 119 uid = logbuf ? logbuf->pidToUid(header->tid) 120 : android::pidToUid(cred->pid); 121 } 122 if (uid != AID_LOGD) cred->uid = uid; 123 } 124 125 char* msg = ((char*)buffer) + sizeof(android_log_header_t); 126 n -= sizeof(android_log_header_t); 127 128 // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a 129 // truncated message to the logs. 130 131 if (logbuf != nullptr) { 132 int res = logbuf->log( 133 (log_id_t)header->id, header->realtime, cred->uid, cred->pid, 134 header->tid, msg, 135 ((size_t)n <= USHRT_MAX) ? (unsigned short)n : USHRT_MAX); 136 if (res > 0 && reader != nullptr) { 137 reader->notifyNewLog(); 138 } 139 } 140 141 return true; 142 } 143 144 int LogListener::getLogSocket() { 145 static const char socketName[] = "logdw"; 146 int sock = android_get_control_socket(socketName); 147 148 if (sock < 0) { // logd started up in init.sh 149 sock = socket_local_server( 150 socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM); 151 152 int on = 1; 153 if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) { 154 return -1; 155 } 156 } 157 return sock; 158 } 159