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