Пример #1
0
LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg)
    : SocketListener(getLogSocket(), false),
      logbuf(buf),
      reader(reader),
      fdDmesg(fdDmesg),
      main(__android_logger_property_get_bool("ro.logd.auditd.main",
                                              BOOL_DEFAULT_TRUE)),
      events(__android_logger_property_get_bool("ro.logd.auditd.events",
                                                BOOL_DEFAULT_TRUE)),
      initialized(false) {
    static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
                                           'l',
                                           'o',
                                           'g',
                                           'd',
                                           '.',
                                           'a',
                                           'u',
                                           'd',
                                           'i',
                                           't',
                                           'd',
                                           ':',
                                           ' ',
                                           's',
                                           't',
                                           'a',
                                           'r',
                                           't',
                                           '\n' };
    write(fdDmesg, auditd_message, sizeof(auditd_message));
}
Пример #2
0
TEST(liblog, android_logger_get_) {
#ifdef __ANDROID__
  // This test assumes the log buffers are filled with noise from
  // normal operations. It will fail if done immediately after a
  // logcat -c.
  struct logger_list* logger_list =
      android_logger_list_alloc(ANDROID_LOG_WRONLY, 0, 0);

  for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
    log_id_t id = static_cast<log_id_t>(i);
    const char* name = android_log_id_to_name(id);
    if (id != android_name_to_log_id(name)) {
      continue;
    }
    fprintf(stderr, "log buffer %s\r", name);
    struct logger* logger;
    EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
    EXPECT_EQ(id, android_logger_get_id(logger));
    ssize_t get_log_size = android_logger_get_log_size(logger);
    /* security buffer is allowed to be denied */
    if (strcmp("security", name)) {
      EXPECT_LT(0, get_log_size);
      // crash buffer is allowed to be empty, that is actually healthy!
      // kernel buffer is allowed to be empty on "user" builds
      // stats buffer is allowed to be empty TEMPORARILY.
      // TODO: remove stats buffer from here once we start to use it in
      // framework (b/68266385).
      EXPECT_LE(  // boolean 1 or 0 depending on expected content or empty
          !!((strcmp("crash", name) != 0) &&
             ((strcmp("kernel", name) != 0) ||
              __android_logger_property_get_bool(
                  "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG |
                                        BOOL_DEFAULT_FLAG_SVELTE)) &&
             (strcmp("stats", name) != 0)),
          android_logger_get_log_readable_size(logger));
    } else {
      EXPECT_NE(0, get_log_size);
      if (get_log_size < 0) {
        EXPECT_GT(0, android_logger_get_log_readable_size(logger));
      } else {
        EXPECT_LE(0, android_logger_get_log_readable_size(logger));
      }
    }
    EXPECT_LT(0, android_logger_get_log_version(logger));
  }

  android_logger_list_close(logger_list);
#else
  GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
}
Пример #3
0
LIBLOG_ABI_PRIVATE unsigned long __android_logger_get_buffer_size(log_id_t logId)
{
    static const char global_tunable[] = "persist.logd.size"; /* Settings App */
    static const char global_default[] = "ro.logd.size"; /* BoardConfig.mk */
    static struct cache2_property_size global = {
        PTHREAD_MUTEX_INITIALIZER,
        0,
        global_tunable,
        { { NULL, -1 }, {} },
        global_default,
        { { NULL, -1 }, {} },
        evaluate_property_get_size
    };
    char key_persist[PROP_NAME_MAX];
    char key_ro[PROP_NAME_MAX];
    struct cache2_property_size local = {
        PTHREAD_MUTEX_INITIALIZER,
        0,
        key_persist,
        { { NULL, -1 }, {} },
        key_ro,
        { { NULL, -1 }, {} },
        evaluate_property_get_size
    };
    unsigned long property_size, default_size;

    default_size =  do_cache2_property_size(&global);
    if (!default_size) {
        default_size = __android_logger_property_get_bool("ro.config.low_ram",
                                                          BOOL_DEFAULT_FALSE)
            ? LOG_BUFFER_MIN_SIZE /* 64K  */
            : LOG_BUFFER_SIZE;    /* 256K */
    }

    snprintf(key_persist, sizeof(key_persist), "%s.%s",
             global_tunable, android_log_id_to_name(logId));
    snprintf(key_ro, sizeof(key_ro), "%s.%s",
             global_default, android_log_id_to_name(logId));
    property_size = do_cache2_property_size(&local);

    if (!property_size) {
        property_size = default_size;
    }

    if (!property_size) {
        property_size = LOG_BUFFER_SIZE;
    }

    return property_size;
}
Пример #4
0
/* get boolean with the logger twist that supports eng adjustments */
LIBLOG_ABI_PRIVATE bool __android_logger_property_get_bool(const char* key,
                                                           int flag)
{
    struct cache_property property = { { NULL, -1 }, { 0 } };
    if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
        char newkey[PROP_NAME_MAX];
        snprintf(newkey, sizeof(newkey), "ro.%s", key);
        refresh_cache_property(&property, newkey);
        property.cache.pinfo = NULL;
        property.cache.serial = -1;
        snprintf(newkey, sizeof(newkey), "persist.%s", key);
        refresh_cache_property(&property, newkey);
        property.cache.pinfo = NULL;
        property.cache.serial = -1;
    }

    refresh_cache_property(&property, key);

    if (check_flag(property.property, "true")) {
        return true;
    }
    if (check_flag(property.property, "false")) {
        return false;
    }
    if (check_flag(property.property, "eng")) {
       flag |= BOOL_DEFAULT_FLAG_ENG;
    }
    /* this is really a "not" flag */
    if (check_flag(property.property, "svelte")) {
       flag |= BOOL_DEFAULT_FLAG_SVELTE;
    }

    /* Sanity Check */
    if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
        flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
        flag |= BOOL_DEFAULT_TRUE;
    }

    if ((flag & BOOL_DEFAULT_FLAG_SVELTE)
            && __android_logger_property_get_bool("ro.config.low_ram",
                                 BOOL_DEFAULT_FALSE)) {
        return false;
    }
    if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) {
        return false;
    }

    return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
}
Пример #5
0
static int drop_privs(bool klogd, bool auditd) {
    // Tricky, if ro.build.type is "eng" then this is true because of the
    // side effect that ro.debuggable == 1 as well, else it is false.
    bool eng =
        __android_logger_property_get_bool("ro.build.type", BOOL_DEFAULT_FALSE);

    struct sched_param param;
    memset(&param, 0, sizeof(param));

    if (set_sched_policy(0, SP_BACKGROUND) < 0) {
        android::prdebug("failed to set background scheduling policy");
        if (!eng) return -1;
    }

    if (sched_setscheduler((pid_t)0, SCHED_BATCH, &param) < 0) {
        android::prdebug("failed to set batch scheduler");
        if (!eng) return -1;
    }

    if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
        android::prdebug("failed to set background cgroup");
        if (!eng) return -1;
    }

    if (!eng && (prctl(PR_SET_DUMPABLE, 0) < 0)) {
        android::prdebug("failed to clear PR_SET_DUMPABLE");
        return -1;
    }

    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
        android::prdebug("failed to set PR_SET_KEEPCAPS");
        if (!eng) return -1;
    }

    std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(),
                                                             cap_free);
    if (cap_clear(caps.get()) < 0) return -1;
    cap_value_t cap_value[] = { CAP_SETGID,  // must be first for below
                                klogd ? CAP_SYSLOG : CAP_SETGID,
                                auditd ? CAP_AUDIT_CONTROL : CAP_SETGID };
    if (cap_set_flag(caps.get(), CAP_PERMITTED, arraysize(cap_value), cap_value,
                     CAP_SET) < 0) {
        return -1;
    }
    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, arraysize(cap_value), cap_value,
                     CAP_SET) < 0) {
        return -1;
    }
    if (cap_set_proc(caps.get()) < 0) {
        android::prdebug(
            "failed to set CAP_SETGID, CAP_SYSLOG or CAP_AUDIT_CONTROL (%d)",
            errno);
        if (!eng) return -1;
    }

    gid_t groups[] = { AID_READPROC };

    if (setgroups(arraysize(groups), groups) == -1) {
        android::prdebug("failed to set AID_READPROC groups");
        if (!eng) return -1;
    }

    if (setgid(AID_LOGD) != 0) {
        android::prdebug("failed to set AID_LOGD gid");
        if (!eng) return -1;
    }

    if (setuid(AID_LOGD) != 0) {
        android::prdebug("failed to set AID_LOGD uid");
        if (!eng) return -1;
    }

    if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, cap_value, CAP_CLEAR) < 0) {
        return -1;
    }
    if (cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR) < 0) {
        return -1;
    }
    if (cap_set_proc(caps.get()) < 0) {
        android::prdebug("failed to clear CAP_SETGID (%d)", errno);
        if (!eng) return -1;
    }

    return 0;
}
Пример #6
0
// Foreground waits for exit of the main persistent threads
// that are started here. The threads are created to manage
// UNIX domain client sockets for writing, reading and
// controlling the user space logger, and for any additional
// logging plugins like auditd and restart control. Additional
// transitory per-client threads are created for each reader.
int main(int argc, char* argv[]) {
    // logd is written under the assumption that the timezone is UTC.
    // If TZ is not set, persist.sys.timezone is looked up in some time utility
    // libc functions, including mktime. It confuses the logd time handling,
    // so here explicitly set TZ to UTC, which overrides the property.
    setenv("TZ", "UTC", 1);
    // issue reinit command. KISS argument parsing.
    if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
        return issueReinit();
    }

    static const char dev_kmsg[] = "/dev/kmsg";
    fdDmesg = android_get_control_file(dev_kmsg);
    if (fdDmesg < 0) {
        fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));
    }

    int fdPmesg = -1;
    bool klogd = __android_logger_property_get_bool(
        "logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
                           BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
    if (klogd) {
        static const char proc_kmsg[] = "/proc/kmsg";
        fdPmesg = android_get_control_file(proc_kmsg);
        if (fdPmesg < 0) {
            fdPmesg = TEMP_FAILURE_RETRY(
                open(proc_kmsg, O_RDONLY | O_NDELAY | O_CLOEXEC));
        }
        if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);
    }

    // Reinit Thread
    sem_init(&reinit, 0, 0);
    sem_init(&uidName, 0, 0);
    sem_init(&sem_name, 0, 1);
    pthread_attr_t attr;
    if (!pthread_attr_init(&attr)) {
        struct sched_param param;

        memset(&param, 0, sizeof(param));
        pthread_attr_setschedparam(&attr, &param);
        pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
        if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
            pthread_t thread;
            reinit_running = true;
            if (pthread_create(&thread, &attr, reinit_thread_start, nullptr)) {
                reinit_running = false;
            }
        }
        pthread_attr_destroy(&attr);
    }

    bool auditd =
        __android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE);
    if (drop_privs(klogd, auditd) != 0) {
        return -1;
    }

    // Serves the purpose of managing the last logs times read on a
    // socket connection, and as a reader lock on a range of log
    // entries.

    LastLogTimes* times = new LastLogTimes();

    // LogBuffer is the object which is responsible for holding all
    // log entries.

    logBuf = new LogBuffer(times);

    signal(SIGHUP, reinit_signal_handler);

    if (__android_logger_property_get_bool(
            "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
                                   BOOL_DEFAULT_FLAG_ENG |
                                   BOOL_DEFAULT_FLAG_SVELTE)) {
        logBuf->enableStatistics();
    }

    // LogReader listens on /dev/socket/logdr. When a client
    // connects, log entries in the LogBuffer are written to the client.

    LogReader* reader = new LogReader(logBuf);
    if (reader->startListener()) {
        exit(1);
    }

    // LogListener listens on /dev/socket/logdw for client
    // initiated log messages. New log entries are added to LogBuffer
    // and LogReader is notified to send updates to connected clients.

    LogListener* swl = new LogListener(logBuf, reader);
    // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
    if (swl->startListener(600)) {
        exit(1);
    }

    // Command listener listens on /dev/socket/logd for incoming logd
    // administrative commands.

    CommandListener* cl = new CommandListener(logBuf, reader, swl);
    if (cl->startListener()) {
        exit(1);
    }

    // LogAudit listens on NETLINK_AUDIT socket for selinux
    // initiated log messages. New log entries are added to LogBuffer
    // and LogReader is notified to send updates to connected clients.

    LogAudit* al = nullptr;
    if (auditd) {
        al = new LogAudit(logBuf, reader,
                          __android_logger_property_get_bool(
                              "ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
                              ? fdDmesg
                              : -1);
    }

    LogKlog* kl = nullptr;
    if (klogd) {
        kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != nullptr);
    }

    readDmesg(al, kl);

    // failure is an option ... messages are in dmesg (required by standard)

    if (kl && kl->startListener()) {
        delete kl;
    }

    if (al && al->startListener()) {
        delete al;
    }

    TEMP_FAILURE_RETRY(pause());

    exit(0);
}