1 /*
2  * Copyright (C) 2007-2016 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 <errno.h>
18 #include <fcntl.h>
19 #include <inttypes.h>
20 #include <poll.h>
21 #include <stdarg.h>
22 #include <stdatomic.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <sys/un.h>
30 #include <time.h>
31 #include <unistd.h>
32 
33 #include <cutils/sockets.h>
34 #include <private/android_filesystem_config.h>
35 #include <private/android_logger.h>
36 
37 #include "log_portability.h"
38 #include "logger.h"
39 #include "uio.h"
40 
41 static int logdAvailable(log_id_t LogId);
42 static int logdOpen();
43 static void logdClose();
44 static int logdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
45 
46 struct android_log_transport_write logdLoggerWrite = {
47     .name = "logd",
48     .logMask = 0,
49     .context.sock = -EBADF,
50     .available = logdAvailable,
51     .open = logdOpen,
52     .close = logdClose,
53     .write = logdWrite,
54 };
55 
56 /* log_init_lock assumed */
logdOpen()57 static int logdOpen() {
58   int i, ret = 0;
59 
60   i = atomic_load(&logdLoggerWrite.context.sock);
61   if (i < 0) {
62     int sock = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
63     if (sock < 0) {
64       ret = -errno;
65     } else {
66       struct sockaddr_un un;
67       memset(&un, 0, sizeof(struct sockaddr_un));
68       un.sun_family = AF_UNIX;
69       strcpy(un.sun_path, "/dev/socket/logdw");
70 
71       if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr*)&un, sizeof(struct sockaddr_un))) <
72           0) {
73         ret = -errno;
74         switch (ret) {
75           case -ENOTCONN:
76           case -ECONNREFUSED:
77           case -ENOENT:
78             i = atomic_exchange(&logdLoggerWrite.context.sock, ret);
79             [[fallthrough]];
80           default:
81             break;
82         }
83         close(sock);
84       } else {
85         ret = atomic_exchange(&logdLoggerWrite.context.sock, sock);
86         if ((ret >= 0) && (ret != sock)) {
87           close(ret);
88         }
89         ret = 0;
90       }
91     }
92   }
93 
94   return ret;
95 }
96 
__logdClose(int negative_errno)97 static void __logdClose(int negative_errno) {
98   int sock = atomic_exchange(&logdLoggerWrite.context.sock, negative_errno);
99   if (sock >= 0) {
100     close(sock);
101   }
102 }
103 
logdClose()104 static void logdClose() {
105   __logdClose(-EBADF);
106 }
107 
logdAvailable(log_id_t logId)108 static int logdAvailable(log_id_t logId) {
109   if (logId >= LOG_ID_MAX || logId == LOG_ID_KERNEL) {
110     return -EINVAL;
111   }
112   if (atomic_load(&logdLoggerWrite.context.sock) < 0) {
113     if (access("/dev/socket/logdw", W_OK) == 0) {
114       return 0;
115     }
116     return -EBADF;
117   }
118   return 1;
119 }
120 
logdWrite(log_id_t logId,struct timespec * ts,struct iovec * vec,size_t nr)121 static int logdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
122   ssize_t ret;
123   int sock;
124   static const unsigned headerLength = 1;
125   struct iovec newVec[nr + headerLength];
126   android_log_header_t header;
127   size_t i, payloadSize;
128   static atomic_int dropped;
129   static atomic_int droppedSecurity;
130 
131   sock = atomic_load(&logdLoggerWrite.context.sock);
132   if (sock < 0) switch (sock) {
133       case -ENOTCONN:
134       case -ECONNREFUSED:
135       case -ENOENT:
136         break;
137       default:
138         return -EBADF;
139     }
140 
141   /* logd, after initialization and priv drop */
142   if (__android_log_uid() == AID_LOGD) {
143     /*
144      * ignore log messages we send to ourself (logd).
145      * Such log messages are often generated by libraries we depend on
146      * which use standard Android logging.
147      */
148     return 0;
149   }
150 
151   /*
152    *  struct {
153    *      // what we provide to socket
154    *      android_log_header_t header;
155    *      // caller provides
156    *      union {
157    *          struct {
158    *              char     prio;
159    *              char     payload[];
160    *          } string;
161    *          struct {
162    *              uint32_t tag
163    *              char     payload[];
164    *          } binary;
165    *      };
166    *  };
167    */
168 
169   header.tid = gettid();
170   header.realtime.tv_sec = ts->tv_sec;
171   header.realtime.tv_nsec = ts->tv_nsec;
172 
173   newVec[0].iov_base = (unsigned char*)&header;
174   newVec[0].iov_len = sizeof(header);
175 
176   if (sock >= 0) {
177     int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0, memory_order_relaxed);
178     if (snapshot) {
179       android_log_event_int_t buffer;
180 
181       header.id = LOG_ID_SECURITY;
182       buffer.header.tag = LIBLOG_LOG_TAG;
183       buffer.payload.type = EVENT_TYPE_INT;
184       buffer.payload.data = snapshot;
185 
186       newVec[headerLength].iov_base = &buffer;
187       newVec[headerLength].iov_len = sizeof(buffer);
188 
189       ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
190       if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
191         atomic_fetch_add_explicit(&droppedSecurity, snapshot, memory_order_relaxed);
192       }
193     }
194     snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
195     if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO, "liblog", strlen("liblog"),
196                                                   ANDROID_LOG_VERBOSE)) {
197       android_log_event_int_t buffer;
198 
199       header.id = LOG_ID_EVENTS;
200       buffer.header.tag = LIBLOG_LOG_TAG;
201       buffer.payload.type = EVENT_TYPE_INT;
202       buffer.payload.data = snapshot;
203 
204       newVec[headerLength].iov_base = &buffer;
205       newVec[headerLength].iov_len = sizeof(buffer);
206 
207       ret = TEMP_FAILURE_RETRY(writev(sock, newVec, 2));
208       if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
209         atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
210       }
211     }
212   }
213 
214   header.id = logId;
215 
216   for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
217     newVec[i].iov_base = vec[i - headerLength].iov_base;
218     payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
219 
220     if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
221       newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
222       if (newVec[i].iov_len) {
223         ++i;
224       }
225       break;
226     }
227   }
228 
229   /*
230    * The write below could be lost, but will never block.
231    *
232    * ENOTCONN occurs if logd has died.
233    * ENOENT occurs if logd is not running and socket is missing.
234    * ECONNREFUSED occurs if we can not reconnect to logd.
235    * EAGAIN occurs if logd is overloaded.
236    */
237   if (sock < 0) {
238     ret = sock;
239   } else {
240     ret = TEMP_FAILURE_RETRY(writev(sock, newVec, i));
241     if (ret < 0) {
242       ret = -errno;
243     }
244   }
245   switch (ret) {
246     case -ENOTCONN:
247     case -ECONNREFUSED:
248     case -ENOENT:
249       if (__android_log_trylock()) {
250         return ret; /* in a signal handler? try again when less stressed */
251       }
252       __logdClose(ret);
253       ret = logdOpen();
254       __android_log_unlock();
255 
256       if (ret < 0) {
257         return ret;
258       }
259 
260       ret = TEMP_FAILURE_RETRY(writev(atomic_load(&logdLoggerWrite.context.sock), newVec, i));
261       if (ret < 0) {
262         ret = -errno;
263       }
264       [[fallthrough]];
265     default:
266       break;
267   }
268 
269   if (ret > (ssize_t)sizeof(header)) {
270     ret -= sizeof(header);
271   } else if (ret == -EAGAIN) {
272     atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
273     if (logId == LOG_ID_SECURITY) {
274       atomic_fetch_add_explicit(&droppedSecurity, 1, memory_order_relaxed);
275     }
276   }
277 
278   return ret;
279 }
280