Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac3ca99b authored by Nick Kralevich's avatar Nick Kralevich
Browse files

introduce auditctl and use it to configure SELinux throttling

In an effort to ensure that our development community does not
introduce new code without corresponding SELinux changes, Android
closely monitors the number of SELinux denials which occur during
boot. This monitoring occurs both in treehugger, as well as various
dashboards. If SELinux denials are dropped during early boot, this
could result in non-determinism for the various SELinux treehugger
tests.

Introduce /system/bin/auditctl. This tool, model after
https://linux.die.net/man/8/auditctl , allows for configuring the
throttling rate for the kernel auditing system.

Remove any throttling from early boot. This will hopefully reduce
treehugger flakiness by making denial generation more predictible
during early boot.

Reapply the throttling at boot complete, to avoid denial of service
attacks against the auditing subsystem.

Delete pre-existing unittests for logd / SELinux integration. It's
intended that all throttling decisions be made in the kernel, and
shouldn't be a concern of logd.

Bug: 118815957
Test: Perform an operation which generates lots of SELinux denials,
      and count how many occur before and after the time period.

(cherry picked from commit be5e4467)

Change-Id: I283cd56151d199cd66f0d217b49115460c4a01e5
parent 83e52ce9
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -80,6 +80,24 @@ cc_binary {
    cflags: ["-Werror"],
}

cc_binary {
    name: "auditctl",

    srcs: ["auditctl.cpp"],

    static_libs: [
        "liblogd",
    ],

    shared_libs: ["libbase"],

    cflags: [
        "-Wall",
        "-Wextra",
        "-Werror",
        "-Wconversion"
    ],
}

prebuilt_etc {
    name: "logtagd.rc",

logd/auditctl.cpp

0 → 100644
+74 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <android-base/parseint.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "libaudit.h"

static void usage(const char* cmdline) {
    fprintf(stderr, "Usage: %s [-r rate]\n", cmdline);
}

static void do_update_rate(uint32_t rate) {
    int fd = audit_open();
    if (fd == -1) {
        error(EXIT_FAILURE, errno, "Unable to open audit socket");
    }
    int result = audit_rate_limit(fd, rate);
    close(fd);
    if (result < 0) {
        fprintf(stderr, "Can't update audit rate limit: %d\n", result);
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char* argv[]) {
    uint32_t rate = 0;
    bool update_rate = false;
    int opt;

    while ((opt = getopt(argc, argv, "r:")) != -1) {
        switch (opt) {
            case 'r':
                if (!android::base::ParseUint<uint32_t>(optarg, &rate)) {
                    error(EXIT_FAILURE, errno, "Invalid Rate");
                }
                update_rate = true;
                break;
            default: /* '?' */
                usage(argv[0]);
                exit(EXIT_FAILURE);
        }
    }

    // In the future, we may add other options to auditctl
    // so this if statement will expand.
    // if (!update_rate && !update_backlog && !update_whatever) ...
    if (!update_rate) {
        fprintf(stderr, "Nothing to do\n");
        usage(argv[0]);
        exit(EXIT_FAILURE);
    }

    if (update_rate) {
        do_update_rate(rate);
    }

    return 0;
}
+9 −2
Original line number Diff line number Diff line
@@ -160,8 +160,7 @@ int audit_setup(int fd, pid_t pid) {
     * and the the mask set to AUDIT_STATUS_PID
     */
    status.pid = pid;
    status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
    status.rate_limit = AUDIT_RATE_LIMIT; /* audit entries per second */
    status.mask = AUDIT_STATUS_PID;

    /* Let the kernel know this pid will be registering for audit events */
    rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
@@ -188,6 +187,14 @@ int audit_open() {
    return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
}

int audit_rate_limit(int fd, uint32_t limit) {
    struct audit_status status;
    memset(&status, 0, sizeof(status));
    status.mask = AUDIT_STATUS_RATE_LIMIT;
    status.rate_limit = limit; /* audit entries per second */
    return audit_send(fd, AUDIT_SET, &status, sizeof(status));
}

int audit_get_reply(int fd, struct audit_message* rep, reply_t block, int peek) {
    ssize_t len;
    int flags;
+11 −2
Original line number Diff line number Diff line
@@ -89,8 +89,17 @@ extern int audit_get_reply(int fd, struct audit_message* rep, reply_t block,
 */
extern int audit_setup(int fd, pid_t pid);

/* Max audit messages per second  */
#define AUDIT_RATE_LIMIT 5
/**
 * Throttle kernel messages at the provided rate
 * @param fd
 *  The fd returned by a call to audit_open()
 * @param rate
 *  The rate, in messages per second, above which the kernel
 *  should drop audit messages.
 * @return
 *  This function returns 0 on success, -errno on error.
 */
extern int audit_rate_limit(int fd, uint32_t limit);

__END_DECLS

+11 −0
Original line number Diff line number Diff line
@@ -16,8 +16,19 @@ service logd-reinit /system/bin/logd --reinit
    group logd
    writepid /dev/cpuset/system-background/tasks

# Limit SELinux denial generation to 5/second
service logd-auditctl /system/bin/auditctl -r 5
    oneshot
    disabled
    user logd
    group logd
    capabilities AUDIT_CONTROL

on fs
    write /dev/event-log-tags "# content owned by logd
"
    chown logd logd /dev/event-log-tags
    chmod 0644 /dev/event-log-tags

on property:sys.boot_completed=1
    start logd-auditctl
Loading