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