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