Home | History | Annotate | Download | only in logd
      1 /*
      2  * Copyright (C) 2014 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 <ctype.h>
     18 #include <errno.h>
     19 #include <limits.h>
     20 #include <stdarg.h>
     21 #include <stdlib.h>
     22 #include <sys/klog.h>
     23 #include <sys/prctl.h>
     24 #include <sys/uio.h>
     25 #include <syslog.h>
     26 
     27 #include "libaudit.h"
     28 #include "LogAudit.h"
     29 
     30 #define KMSG_PRIORITY(PRI)         \
     31     '<',                           \
     32     '0' + (LOG_AUTH | (PRI)) / 10, \
     33     '0' + (LOG_AUTH | (PRI)) % 10, \
     34     '>'
     35 
     36 LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmsg)
     37         : SocketListener(getLogSocket(), false)
     38         , logbuf(buf)
     39         , reader(reader)
     40         , fdDmesg(-1) {
     41     static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
     42         'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
     43         ' ', 's', 't', 'a', 'r', 't', '\n' };
     44     write(fdDmsg, auditd_message, sizeof(auditd_message));
     45     logDmesg();
     46     fdDmesg = fdDmsg;
     47 }
     48 
     49 bool LogAudit::onDataAvailable(SocketClient *cli) {
     50     prctl(PR_SET_NAME, "logd.auditd");
     51 
     52     struct audit_message rep;
     53 
     54     rep.nlh.nlmsg_type = 0;
     55     rep.nlh.nlmsg_len = 0;
     56     rep.data[0] = '\0';
     57 
     58     if (audit_get_reply(cli->getSocket(), &rep, GET_REPLY_BLOCKING, 0) < 0) {
     59         SLOGE("Failed on audit_get_reply with error: %s", strerror(errno));
     60         return false;
     61     }
     62 
     63     logPrint("type=%d %.*s", rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
     64 
     65     return true;
     66 }
     67 
     68 int LogAudit::logPrint(const char *fmt, ...) {
     69     if (fmt == NULL) {
     70         return -EINVAL;
     71     }
     72 
     73     va_list args;
     74 
     75     char *str = NULL;
     76     va_start(args, fmt);
     77     int rc = vasprintf(&str, fmt, args);
     78     va_end(args);
     79 
     80     if (rc < 0) {
     81         return rc;
     82     }
     83 
     84     char *cp;
     85     while ((cp = strstr(str, "  "))) {
     86         memmove(cp, cp + 1, strlen(cp + 1) + 1);
     87     }
     88 
     89     bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
     90     if (fdDmesg >= 0) {
     91         struct iovec iov[3];
     92         static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
     93         static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) };
     94 
     95         iov[0].iov_base = info ? const_cast<char *>(log_info)
     96                                : const_cast<char *>(log_warning);
     97         iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
     98         iov[1].iov_base = str;
     99         iov[1].iov_len = strlen(str);
    100         iov[2].iov_base = const_cast<char *>("\n");
    101         iov[2].iov_len = 1;
    102 
    103         writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
    104     }
    105 
    106     pid_t pid = getpid();
    107     pid_t tid = gettid();
    108     uid_t uid = getuid();
    109     log_time now;
    110 
    111     static const char audit_str[] = " audit(";
    112     char *timeptr = strstr(str, audit_str);
    113     if (timeptr
    114             && ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q")))
    115             && (*cp == ':')) {
    116         memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
    117         memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
    118     } else {
    119         now.strptime("", ""); // side effect of setting CLOCK_REALTIME
    120     }
    121 
    122     static const char pid_str[] = " pid=";
    123     char *pidptr = strstr(str, pid_str);
    124     if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
    125         cp = pidptr + sizeof(pid_str) - 1;
    126         pid = 0;
    127         while (isdigit(*cp)) {
    128             pid = (pid * 10) + (*cp - '0');
    129             ++cp;
    130         }
    131         tid = pid;
    132         uid = logbuf->pidToUid(pid);
    133         memmove(pidptr, cp, strlen(cp) + 1);
    134     }
    135 
    136     // log to events
    137 
    138     size_t l = strlen(str);
    139     size_t n = l + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
    140 
    141     bool notify = false;
    142 
    143     char *newstr = reinterpret_cast<char *>(malloc(n));
    144     if (!newstr) {
    145         rc = -ENOMEM;
    146     } else {
    147         cp = newstr;
    148         *cp++ = AUDITD_LOG_TAG & 0xFF;
    149         *cp++ = (AUDITD_LOG_TAG >> 8) & 0xFF;
    150         *cp++ = (AUDITD_LOG_TAG >> 16) & 0xFF;
    151         *cp++ = (AUDITD_LOG_TAG >> 24) & 0xFF;
    152         *cp++ = EVENT_TYPE_STRING;
    153         *cp++ = l & 0xFF;
    154         *cp++ = (l >> 8) & 0xFF;
    155         *cp++ = (l >> 16) & 0xFF;
    156         *cp++ = (l >> 24) & 0xFF;
    157         memcpy(cp, str, l);
    158 
    159         logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, newstr,
    160                     (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
    161         free(newstr);
    162 
    163         notify = true;
    164     }
    165 
    166     // log to main
    167 
    168     static const char comm_str[] = " comm=\"";
    169     const char *comm = strstr(str, comm_str);
    170     const char *estr = str + strlen(str);
    171     if (comm) {
    172         estr = comm;
    173         comm += sizeof(comm_str) - 1;
    174     } else if (pid == getpid()) {
    175         pid = tid;
    176         comm = "auditd";
    177     } else if (!(comm = logbuf->pidToName(pid))) {
    178         comm = "unknown";
    179     }
    180 
    181     const char *ecomm = strchr(comm, '"');
    182     if (ecomm) {
    183         ++ecomm;
    184         l = ecomm - comm;
    185     } else {
    186         l = strlen(comm) + 1;
    187         ecomm = "";
    188     }
    189     n = (estr - str) + strlen(ecomm) + l + 2;
    190 
    191     newstr = reinterpret_cast<char *>(malloc(n));
    192     if (!newstr) {
    193         rc = -ENOMEM;
    194     } else {
    195         *newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
    196         strlcpy(newstr + 1, comm, l);
    197         strncpy(newstr + 1 + l, str, estr - str);
    198         strcpy(newstr + 1 + l + (estr - str), ecomm);
    199 
    200         logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
    201                     (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
    202         free(newstr);
    203 
    204         notify = true;
    205     }
    206 
    207     free(str);
    208 
    209     if (notify) {
    210         reader->notifyNewLog();
    211     }
    212 
    213     return rc;
    214 }
    215 
    216 void LogAudit::logDmesg() {
    217     int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
    218     if (len <= 0) {
    219         return;
    220     }
    221 
    222     len++;
    223     char buf[len];
    224 
    225     int rc = klogctl(KLOG_READ_ALL, buf, len);
    226 
    227     buf[len - 1] = '\0';
    228 
    229     for(char *tok = buf; (rc >= 0) && ((tok = strtok(tok, "\r\n"))); tok = NULL) {
    230         char *audit = strstr(tok, " audit(");
    231         if (!audit) {
    232             continue;
    233         }
    234 
    235         *audit++ = '\0';
    236 
    237         char *type = strstr(tok, "type=");
    238         if (type) {
    239             rc = logPrint("%s %s", type, audit);
    240         } else {
    241             rc = logPrint("%s", audit);
    242         }
    243     }
    244 }
    245 
    246 int LogAudit::getLogSocket() {
    247     int fd = audit_open();
    248     if (fd < 0) {
    249         return fd;
    250     }
    251     if (audit_setup(fd, getpid()) < 0) {
    252         audit_close(fd);
    253         fd = -1;
    254     }
    255     return fd;
    256 }
    257