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