Home | History | Annotate | Download | only in logd
      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(&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
    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