1/* 2 * Copyright (C) 2018 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#define DEBUG false // STOPSHIP if true 17#include "Log.h" 18 19#include <ctype.h> 20#include <limits.h> 21#include <stdio.h> 22#include <sys/cdefs.h> 23#include <sys/prctl.h> 24#include <sys/socket.h> 25#include <sys/types.h> 26#include <sys/un.h> 27#include <unistd.h> 28 29#include <cutils/sockets.h> 30#include <private/android_filesystem_config.h> 31#include <private/android_logger.h> 32#include <unordered_map> 33 34#include "StatsSocketListener.h" 35#include "guardrail/StatsdStats.h" 36#include "stats_log_util.h" 37 38namespace android { 39namespace os { 40namespace statsd { 41 42static const int kLogMsgHeaderSize = 28; 43 44StatsSocketListener::StatsSocketListener(const sp<LogListener>& listener) 45 : SocketListener(getLogSocket(), false /*start listen*/), mListener(listener) { 46} 47 48StatsSocketListener::~StatsSocketListener() { 49} 50 51bool StatsSocketListener::onDataAvailable(SocketClient* cli) { 52 static bool name_set; 53 if (!name_set) { 54 prctl(PR_SET_NAME, "statsd.writer"); 55 name_set = true; 56 } 57 58 // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received 59 char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time) + LOGGER_ENTRY_MAX_PAYLOAD + 60 1]; 61 struct iovec iov = {buffer, sizeof(buffer) - 1}; 62 63 alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))]; 64 struct msghdr hdr = { 65 NULL, 0, &iov, 1, control, sizeof(control), 0, 66 }; 67 68 int socket = cli->getSocket(); 69 70 // To clear the entire buffer is secure/safe, but this contributes to 1.68% 71 // overhead under logging load. We are safe because we check counts, but 72 // still need to clear null terminator 73 // memset(buffer, 0, sizeof(buffer)); 74 ssize_t n = recvmsg(socket, &hdr, 0); 75 if (n <= (ssize_t)(sizeof(android_log_header_t))) { 76 return false; 77 } 78 79 buffer[n] = 0; 80 81 struct ucred* cred = NULL; 82 83 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr); 84 while (cmsg != NULL) { 85 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) { 86 cred = (struct ucred*)CMSG_DATA(cmsg); 87 break; 88 } 89 cmsg = CMSG_NXTHDR(&hdr, cmsg); 90 } 91 92 struct ucred fake_cred; 93 if (cred == NULL) { 94 cred = &fake_cred; 95 cred->pid = 0; 96 cred->uid = DEFAULT_OVERFLOWUID; 97 } 98 99 char* ptr = ((char*)buffer) + sizeof(android_log_header_t); 100 n -= sizeof(android_log_header_t); 101 102 log_msg msg; 103 104 msg.entry.len = n; 105 msg.entry.hdr_size = kLogMsgHeaderSize; 106 msg.entry.sec = time(nullptr); 107 msg.entry.pid = cred->pid; 108 msg.entry.uid = cred->uid; 109 110 memcpy(msg.buf + kLogMsgHeaderSize, ptr, n + 1); 111 LogEvent event(msg); 112 113 // Call the listener 114 mListener->OnLogEvent(&event, false /*reconnected, N/A in statsd socket*/); 115 116 return true; 117} 118 119int StatsSocketListener::getLogSocket() { 120 static const char socketName[] = "statsdw"; 121 int sock = android_get_control_socket(socketName); 122 123 if (sock < 0) { // statsd started up in init.sh 124 sock = socket_local_server(socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM); 125 126 int on = 1; 127 if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) { 128 return -1; 129 } 130 } 131 return sock; 132} 133 134} // namespace statsd 135} // namespace os 136} // namespace android 137