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 67 static int drop_privs() { 68 struct sched_param param; 69 memset(¶m, 0, sizeof(param)); 70 71 if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 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 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. 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 char property[PROPERTY_VALUE_MAX]; 157 property_get("ro.build.type", property, ""); 158 if (property_get_bool("logd.statistics", 159 !!strcmp(property, "user") 160 && !property_get_bool("ro.config.low_ram", false))) { 161 logBuf->enableStatistics(); 162 } 163 } 164 165 // LogReader listens on /dev/socket/logdr. When a client 166 // connects, log entries in the LogBuffer are written to the client. 167 168 LogReader *reader = new LogReader(logBuf); 169 if (reader->startListener()) { 170 exit(1); 171 } 172 173 // LogListener listens on /dev/socket/logdw for client 174 // initiated log messages. New log entries are added to LogBuffer 175 // and LogReader is notified to send updates to connected clients. 176 177 LogListener *swl = new LogListener(logBuf, reader); 178 // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value 179 if (swl->startListener(300)) { 180 exit(1); 181 } 182 183 // Command listener listens on /dev/socket/logd for incoming logd 184 // administrative commands. 185 186 CommandListener *cl = new CommandListener(logBuf, reader, swl); 187 if (cl->startListener()) { 188 exit(1); 189 } 190 191 // LogAudit listens on NETLINK_AUDIT socket for selinux 192 // initiated log messages. New log entries are added to LogBuffer 193 // and LogReader is notified to send updates to connected clients. 194 195 if (auditd) { 196 // failure is an option ... messages are in dmesg (required by standard) 197 LogAudit *al = new LogAudit(logBuf, reader, fdDmesg); 198 if (al->startListener()) { 199 delete al; 200 close(fdDmesg); 201 } 202 } 203 204 pause(); 205 exit(0); 206 } 207 208