blob: ece5a3a42204d24d6983f734d24e47a9808d8872 [file] [log] [blame]
Mark Salyzyn0175b072014-02-26 09:50:16 -08001/*
2 * Copyright (C) 2012-2013 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 <dirent.h>
18#include <errno.h>
19#include <fcntl.h>
Mark Salyzyn882f8562013-12-26 15:13:36 -080020#include <sched.h>
Mark Salyzyn0175b072014-02-26 09:50:16 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/capability.h>
25#include <sys/stat.h>
26#include <sys/types.h>
Mark Salyzyne457b742014-02-19 17:18:31 -080027#include <unistd.h>
Mark Salyzyn0175b072014-02-26 09:50:16 -080028
29#include <linux/prctl.h>
30
Mark Salyzyne457b742014-02-19 17:18:31 -080031#include <cutils/properties.h>
32
Mark Salyzyn0175b072014-02-26 09:50:16 -080033#include "private/android_filesystem_config.h"
34#include "CommandListener.h"
35#include "LogBuffer.h"
36#include "LogListener.h"
William Roberts29d238d2013-02-08 09:45:26 +090037#include "LogAudit.h"
Mark Salyzyn0175b072014-02-26 09:50:16 -080038
Mark Salyzyndfc47e82014-03-24 10:26:47 -070039//
40// The service is designed to be run by init, it does not respond well
41// to starting up manually. When starting up manually the sockets will
42// fail to open typically for one of the following reasons:
43// EADDRINUSE if logger is running.
44// EACCESS if started without precautions (below)
45//
46// Here is a cookbook procedure for starting up logd manually assuming
47// init is out of the way, pedantically all permissions and selinux
48// security is put back in place:
49//
50// setenforce 0
51// rm /dev/socket/logd*
52// chmod 777 /dev/socket
53// # here is where you would attach the debugger or valgrind for example
54// runcon u:r:logd:s0 /system/bin/logd </dev/null >/dev/null 2>&1 &
55// sleep 1
56// chmod 755 /dev/socket
57// chown logd.logd /dev/socket/logd*
58// restorecon /dev/socket/logd*
59// setenforce 1
60//
61// If minimalism prevails, typical for debugging and security is not a concern:
62//
63// setenforce 0
64// chmod 777 /dev/socket
65// logd
66//
67
Mark Salyzyn0175b072014-02-26 09:50:16 -080068static int drop_privs() {
Mark Salyzyn882f8562013-12-26 15:13:36 -080069 struct sched_param param;
70 memset(&param, 0, sizeof(param));
71
72 if (sched_setscheduler((pid_t) 0, SCHED_BATCH, &param) < 0) {
73 return -1;
74 }
75
Mark Salyzyn0175b072014-02-26 09:50:16 -080076 if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
77 return -1;
78 }
79
80 if (setgid(AID_LOGD) != 0) {
81 return -1;
82 }
83
84 if (setuid(AID_LOGD) != 0) {
85 return -1;
86 }
87
88 struct __user_cap_header_struct capheader;
89 struct __user_cap_data_struct capdata[2];
90 memset(&capheader, 0, sizeof(capheader));
91 memset(&capdata, 0, sizeof(capdata));
92 capheader.version = _LINUX_CAPABILITY_VERSION_3;
93 capheader.pid = 0;
94
95 capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
William Roberts29d238d2013-02-08 09:45:26 +090096 capdata[CAP_TO_INDEX(CAP_AUDIT_CONTROL)].permitted |= CAP_TO_MASK(CAP_AUDIT_CONTROL);
97
98 capdata[0].effective = capdata[0].permitted;
99 capdata[1].effective = capdata[1].permitted;
Mark Salyzyn0175b072014-02-26 09:50:16 -0800100 capdata[0].inheritable = 0;
101 capdata[1].inheritable = 0;
102
103 if (capset(&capheader, &capdata[0]) < 0) {
104 return -1;
105 }
106
107 return 0;
108}
109
Mark Salyzyne0fa2912014-04-28 16:39:04 -0700110// Property helper
111static bool property_get_bool(const char *key, bool def) {
112 char property[PROPERTY_VALUE_MAX];
113 property_get(key, property, "");
114
115 if (!strcasecmp(property, "true")) {
116 return true;
117 }
118 if (!strcasecmp(property, "false")) {
119 return false;
120 }
121
122 return def;
123}
124
Mark Salyzyn0175b072014-02-26 09:50:16 -0800125// Foreground waits for exit of the three main persistent threads that
126// are started here. The three threads are created to manage UNIX
127// domain client sockets for writing, reading and controlling the user
128// space logger. Additional transitory per-client threads are created
129// for each reader once they register.
130int main() {
Mark Salyzyne0fa2912014-04-28 16:39:04 -0700131 bool auditd = property_get_bool("logd.auditd", true);
132
Mark Salyzyne9bebd02014-04-03 09:55:26 -0700133 int fdDmesg = -1;
Mark Salyzyne0fa2912014-04-28 16:39:04 -0700134 if (auditd && property_get_bool("logd.auditd.dmesg", true)) {
Mark Salyzyne9bebd02014-04-03 09:55:26 -0700135 fdDmesg = open("/dev/kmsg", O_WRONLY);
136 }
137
Mark Salyzyn0175b072014-02-26 09:50:16 -0800138 if (drop_privs() != 0) {
139 return -1;
140 }
141
142 // Serves the purpose of managing the last logs times read on a
143 // socket connection, and as a reader lock on a range of log
144 // entries.
145
146 LastLogTimes *times = new LastLogTimes();
147
148 // LogBuffer is the object which is responsible for holding all
149 // log entries.
150
151 LogBuffer *logBuf = new LogBuffer(times);
152
Mark Salyzyne0fa2912014-04-28 16:39:04 -0700153 if (property_get_bool("logd.statistics.dgram_qlen", false)) {
Mark Salyzyne457b742014-02-19 17:18:31 -0800154 logBuf->enableDgramQlenStatistics();
155 }
156
Mark Salyzyn0175b072014-02-26 09:50:16 -0800157 // LogReader listens on /dev/socket/logdr. When a client
158 // connects, log entries in the LogBuffer are written to the client.
159
160 LogReader *reader = new LogReader(logBuf);
161 if (reader->startListener()) {
162 exit(1);
163 }
164
165 // LogListener listens on /dev/socket/logdw for client
166 // initiated log messages. New log entries are added to LogBuffer
167 // and LogReader is notified to send updates to connected clients.
168
169 LogListener *swl = new LogListener(logBuf, reader);
Mark Salyzyn581edc12013-11-20 13:38:52 -0800170 // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
171 if (swl->startListener(300)) {
Mark Salyzyn0175b072014-02-26 09:50:16 -0800172 exit(1);
173 }
174
175 // Command listener listens on /dev/socket/logd for incoming logd
176 // administrative commands.
177
178 CommandListener *cl = new CommandListener(logBuf, reader, swl);
179 if (cl->startListener()) {
180 exit(1);
181 }
182
William Roberts29d238d2013-02-08 09:45:26 +0900183 // LogAudit listens on NETLINK_AUDIT socket for selinux
184 // initiated log messages. New log entries are added to LogBuffer
185 // and LogReader is notified to send updates to connected clients.
186
Mark Salyzyne0fa2912014-04-28 16:39:04 -0700187 if (auditd) {
188 // failure is an option ... messages are in dmesg (required by standard)
189 LogAudit *al = new LogAudit(logBuf, reader, fdDmesg);
190 if (al->startListener()) {
191 delete al;
192 close(fdDmesg);
193 }
William Roberts29d238d2013-02-08 09:45:26 +0900194 }
195
Mark Salyzyn0175b072014-02-26 09:50:16 -0800196 pause();
197 exit(0);
198}
199