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