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

Commit 9cf2124a authored by Stephen Smalley's avatar Stephen Smalley Committed by Steve Kondik
Browse files

Sync with master auditd.

parent dfa24649
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -3,9 +3,13 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

# Override this in the BoardConfig.mk
# to change the default size
# Note: The value is in Kilobytes
AUDITD_MAX_LOG_FILE_SIZEKB ?= 100

LOCAL_SRC_FILES:= \
	auditd.c \
	netlink.c \
	libaudit.c \
	audit_log.c

@@ -15,5 +19,5 @@ LOCAL_SHARED_LIBRARIES := \

LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := auditd

LOCAL_CFLAGS := -DAUDITD_MAX_LOG_FILE_SIZEKB=$(AUDITD_MAX_LOG_FILE_SIZEKB)
include $(BUILD_EXECUTABLE)

auditd/README

0 → 100644
+44 −0
Original line number Diff line number Diff line
Auditd Daemon

The audit daemon is a simplified version of its desktop
counterpart designed to gather the audit logs from the
audit kernel subsystem. The audit subsystem of the kernel
includes Linux Security Modules (LSM) messages as well.

To enable the audit subsystem, you must add this to your
kernel config:
CONFIG_AUDIT=y
CONFIG_AUDITSYSCALL=y

To enable a LSM, you must consult that LSM's documentation, the
example below is for SELinux:
CONFIG_SECURITY_SELINUX=y

This does not include possible dependencies that may need to be
satisfied for that particular LSM.

The daemon maintains two log files audit.log and audit.old
at /data/misc/audit/. On boot, if audit.log exists, and
the size is greater than 0, audit.log is renamed to
audit.old. The log file is also renamed, or rotated, when
a threshold is hit. This threshold is hard-coded to 100KB
but can be adjusted through the AUDITD_MAX_LOG_FILE_SIZEKB
Makefile file variable that can be overridden in the device.mk

The daemon is not included by default, and must explicitly be
added to PRODUCT_PACKAGES. This could be set in the device.mk

The daemon also has no external interfaces, but one could
use inotify to start and build a system from this. The log
files are owned by UID audit and readable by system. A
system UID application could conceivably be used to consume
these logs.

Example configuration in device.mk:

# 1MB Log file threshold
AUDITD_MAX_LOG_FILE_SIZEKB := 1000

PRODUCT_PACKAGES += auditd

+314 −212
Original line number Diff line number Diff line
/*
 * Copyright 2012, Samsung Telecommunications of America
 *
 * 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.
 *
 * Written by William Roberts <w.roberts@sta.samsung.com>
 */

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>

#include <stdarg.h>
#include <ctype.h>
#include <alloca.h>
#include <sys/klog.h>
#include <sys/types.h>
#include <sys/stat.h>

#define LOG_TAG "audit_log"
#include <cutils/log.h>

#include "libaudit.h"
#include "audit_log.h"
#include "auditd.h"

/*
 * Note that the flags passed to fcntl and the flags used
 * by fopen must be compatible. For instance, specifying
 * write only on one and read only on the other will yield
 * strange behavior.
 */
/* Mode for fopen */
#define AUDIT_LOG_FMODE "w+"
/* mode for fchmod*/
#define AUDIT_LOG_MODE  (S_IRUSR | S_IWUSR | S_IRGRP)
/* flags for fcntl */
#define AUDIT_LOG_FLAGS (O_RDWR | O_CREAT | O_SYNC)

struct audit_log {
	int fd;
#define AUDIT_TYPE    "type="
#define AUDIT_MSG     "msg="
#define AUDIT_KEYWORD "audit("

struct audit_log
{
    FILE *file;
    size_t total_bytes;
    size_t threshold;
    char *rotatefile;
@@ -25,210 +62,242 @@ struct audit_log {
};

/**
 * Writes data pointed by buf to audit log, appends a trailing newline.
 * @param l
 *  The log to write
 * @param buf
 *  The data to write
 * @param len
 *  The length of the data
 * Wraps open with a fchmod to prevent umask issues from arising in
 * permission setting as well as a fcntl to set the underlying
 * fds mode. However, the rest of the library relies on stdio file
 * access, so a FILE pointer is returned.
 *
 * You must make sure your mode and fmode are compatible
 *
 * @param file
 *  File stream output
 * @param path
 *  The path of the log file
 * @param flags
 *  The flags passed to fcntl
 * @param fmode
 *  The mode passed to fopen
 * @param mode
 *  The mode passed to open and fchmod
 * @return
 *  0 on success with *file set, or -errno on error
 */
static int write_log(audit_log *l, const void *buf, size_t len) {
static int open_log(FILE **file, const char *path, int flags, const char *fmode, mode_t mode)
{
    int fd;
    int rc;

	int rc = 0;
	ssize_t bytes = 0;
    if(!file) {
        return -EINVAL;
    }

	/*
	 * Ensure that the pointer offset and
	 * number of bytes written are the same
	 * size. Avoid char *, as on esoteric
	 * systems that are not byte addressable
	 * it could be defined as something else.
	 */
	const uint8_t *b = (uint8_t *)buf;
    *file = fopen(path, fmode);
    if(!*file) {
        rc = -errno;
        SLOGE("Could not open audit log file %s : %s", path, strerror(errno));
        return rc;
    }

	if(!l) {
		rc = EINVAL;
    rc = setvbuf(*file, NULL, _IONBF, 0);
    if (rc != 0) {
        rc = -errno;
        SLOGE("Could not setvbuf the log file");
        goto err;
    }

	do {
		bytes = write(l->fd, b, len);
		if(bytes < 0 && errno != EINTR) {
			rc = errno;
    fd = fileno(*file);
    rc = fchmod(fd, mode);
    if (rc < 0) {
        rc = -errno;
        SLOGE("Could not fchmod the log file");
        goto err;
    }
		b += bytes;
		len -= bytes;
		l->total_bytes += bytes;
	} while (len > 0);


out:
	/*
	 * Always attempt to write a newline, but ignore
	 * any errors as it could be a cascading effect
	 * from above.
	 */
	bytes = write(l->fd, "\n", 1);
	l->total_bytes += (bytes > 0) ? bytes : 0;

	/*
	 * Always attempt to rotate, even in the
	 * face of errors above
	 */
	if(l->total_bytes > l->threshold) {
		rc = audit_log_rotate(l);
    rc = fcntl(fd, F_SETFD, flags);
    if (rc < 0) {
        rc = -errno;
        SLOGE("Could not fcntl the log file");
        goto err;
    }

	return rc;
    return 0;

err:
	ERROR("Error in function: %s, line: %d, error: %s\n",
		__FUNCTION__, __LINE__, strerror(rc));
	goto out;
    fclose(*file);
    return rc;
}

audit_log *audit_log_open(const char *logfile, const char *rotatefile, size_t threshold) {

	int fd = -1;
audit_log *audit_log_open(const char *logfile, const char *rotatefile, size_t threshold)
{
    int rc;
    audit_log *l = NULL;
    struct stat log_file_stats;

	if (stat(logfile, &log_file_stats) < 0) {
    rc = stat(logfile, &log_file_stats);
    if (rc < 0) {
        if(errno != ENOENT) {
			ERROR("Could not stat %s: %s\n",
				logfile, strerror(errno));
			goto err;
            SLOGE("Could not stat audit logfile %s: %s", logfile, strerror(errno));
            return NULL;
        }
	}
	/* The existing log had data */
	else if (log_file_stats.st_size != 0){
		if (rename(logfile, rotatefile) < 0) {
			ERROR("Could not rename %s to %s: %s\n",
				logfile, rotatefile, strerror(errno));
			goto err;
        else {
            SLOGI("Previous audit logfile not detected");
        }
    }

	/* Open the output logfile */
	fd = open(logfile, AUDIT_LOG_FLAGS, AUDIT_LOG_MODE);
	if (fd < 0) {
		ERROR("Could not open %s: %s\n",
			logfile, strerror(errno));
		goto err;
    /* The existing log had data */
    if (rc == 0 && log_file_stats.st_size >= 0) {
        rc = rename(logfile, rotatefile);
        if (rc < 0) {
            SLOGE("Could not rename %s to %s: %s", logfile, rotatefile, strerror(errno));
            return NULL;
        }
        SLOGI("Previous audit logfile detected, rotating\n");
    }
	fchmod(fd, AUDIT_LOG_MODE);

    l = calloc(sizeof(struct audit_log), 1);
    if (!l) {
		goto err;
        SLOGE("Out of memory while allocating audit log");
        return NULL;
    }

    /* Open the output logfile */
    rc = open_log(&(l->file), logfile, AUDIT_LOG_FLAGS, AUDIT_LOG_FMODE, AUDIT_LOG_MODE);
    if (rc < 0) {
        /* Error message handled by open_log() */
        return NULL;
    }

    l->rotatefile = strdup(rotatefile);
    if (!l->rotatefile) {
        SLOGE("Out of memory while duplicating rotatefile string");
        goto err;
    }

    l->logfile = strdup(logfile);
    if (!l->logfile) {
        SLOGE("Out of memory while duplicating logfile string");
        goto err;
    }
	l->fd = fd;

    l->threshold = threshold;

out:
    return l;

err:
    audit_log_close(l);
	l = NULL;
    return NULL;
}

int audit_log_write(audit_log *l, const char *fmt, ...)
{
    int rc;
    va_list args;

    if (l == NULL || fmt == NULL) {
        return -EINVAL;
    }

    va_start(args, fmt);
    rc = vfprintf(l->file, fmt, args);
    va_end(args);

    if(rc < 0) {
        SLOGE("Error writing to log file");
        clearerr(l->file);
        rc = -EINVAL;
        goto out;
    }

int audit_log_write_str(audit_log *l, const char *str) {
	return write_log(l, str, strlen(str));
    l->total_bytes += rc;

out:
    if(l->total_bytes > l->threshold) {
        /* audit_log_rotate() handles error message */
        rc = audit_log_rotate(l);
    }

int audit_log_write(audit_log *l, const struct audit_reply *reply) {
	return write_log(l, reply->msg.data, reply->len);
    return rc;
}

int audit_log_rotate(audit_log *l) {
int audit_log_rotate(audit_log *l)
{
    FILE *file;
    int rc = 0;

    if (!l) {
		rc = EINVAL;
		goto err;
        return -EINVAL;
    }

    rc = rename(l->logfile, l->rotatefile);
    if (rc < 0) {
		rc = errno;
		goto err;
        rc = -errno;
        SLOGE("Could not rename audit log file \"%s\" to \"%s\", error: %s",
                l->logfile, l->rotatefile, strerror(errno));
        return rc;
    }

    rc = open_log(&file, l->logfile, AUDIT_LOG_FLAGS, AUDIT_LOG_FMODE, AUDIT_LOG_MODE);
    if (rc < 0) {
        /* Error message handled by open_log() */
        return rc;
    }

	close(l->fd);
    fclose(l->file);
    l->total_bytes = 0;
    l->file = file;

	l->fd = open(l->logfile, AUDIT_LOG_FLAGS, AUDIT_LOG_MODE);
	if(l->fd < 0) {
		rc = errno;
		goto err;
    return 0;
}
	fchmod(l->fd, AUDIT_LOG_MODE);

out:
	return rc;
err:
	goto out;
void audit_log_close(audit_log *l)
{
    if (!l) {
        return;
    }

void audit_log_close(audit_log *l) {
	if(l) {
		if(l->logfile) {
    free(l->logfile);
		}
		if(l->rotatefile) {
    free(l->rotatefile);
		}
		if(l->fd >= 0) {
			close(l->fd);
    if (l->file) {
        fclose(l->file);
    }
    free(l);
		l = NULL;
	}
    return;
}

int audit_log_put_kmsg(audit_log *l) {

int audit_log_put_kmsg(audit_log *l)
{
    char *tok;

    char *audit;
    char *type;
    int rc = 0;
    char *buf = NULL;
    int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);

	if (len > 0) {
    /* No data to read */
    if (len == 0) {
        SLOGI("Empty kmsg");
        return 0;
    }

    /* Error */
    if (len < 0) {
        rc = -errno;
        SLOGE("Could not read kernel log length: %s", strerror(errno));
        return rc;
    }

    /* Data to read */
    len++;
    buf = malloc(len * sizeof(*buf));
    if (!buf) {
			ERROR("Out of memory\n");
			rc = ENOMEM;
			goto err;
		}
	}
	else if(len < 0) {
		ERROR("Could not read logs: %s\n",
				strerror(errno));
		rc = errno;
		goto err;
        SLOGE("Out of memory wile allocating kmsg buffer");
        return -ENOMEM;
    }

    rc = klogctl(KLOG_READ_ALL, buf, len);
    if (rc < 0) {
		ERROR("Could not read logs: %s\n",
				strerror(errno));
		rc = errno;
        rc = -errno;
        SLOGE("Could not read kernel log data: %s", strerror(errno));
        goto err;
    }

@@ -236,16 +305,49 @@ int audit_log_put_kmsg(audit_log *l) {
    tok = buf;

    while ((tok = strtok(tok, "\r\n"))) {
		if(strstr(tok, " audit(")) {
			audit_log_write_str(l, tok);

        /* Only print audit messages The SPACE is important!! as we want the
         * audit pointer pointing to a space and not the beginning of the message.
         * This helps ensure that we don't erroneously going down the wrong path when
         * parsing this data.
         * XXX Should we include the space in the AUDIT_KEYWORD macro?
         */
        audit = strstr(tok, " "AUDIT_KEYWORD);
        if (audit) {

            /* Place a null terminator at the space, and advance the pointer past it */
            *audit++ = '\0';

            /* If it has type field, print that than msg=<rest> */
            type = strstr(tok, AUDIT_TYPE);
            if (type) {

                /*
                 * The type should be the the left of the space we replaced with a
                 * null terminator
                 *
                 * type is pointing to type=1400\0 and audit is pointing to audit(....\0
                 */
                rc = audit_log_write(l, "%s msg=%s\n", type, audit);
                if(rc < 0) {
                    /* audit_log_write handles error message */
                    goto err;
                }
            }
            /* It contined the AUDIT_KEWORD but was not formatted as expected, just dump it */
            else {
                SLOGW("Improperly formatted kernel audit message, dumping as is");
                rc = audit_log_write(l, "%s\n", audit);
                if(rc < 0) {
                    /* audit_log_write handles error message */
                    goto err;
                }
            }
        }
        tok = NULL;
    }

err:
	if (buf) {
    free(buf);
	}

	return 0;
    return rc;
}
+13 −26
Original line number Diff line number Diff line
@@ -34,58 +34,45 @@ typedef struct audit_log audit_log;
 *  The threshold, in bytes, the log file should grow to
 *  until rotation.
 * @return
 *  A valid handle to the audit_log.
 *  A valid handle to the audit_log or NULL on failure.
 */
extern audit_log *audit_log_open(const char *logfile, const char *rotatefile, size_t threshold);

/**
 * Appends an audit reposnse to the audit log, and rotates the log if threshold is
 * passed. Note, it always finishes a message even if it is past threshold. Also
 * always appends a newline to the end of the message.
 * Writes a formatted message to the audit log
 * @param l
 *  The audit log to use
 * @param reply
 *  The response to write
 *  The log to write too
 * @param fmt
 *  The fmt specifier as passed to fprintf/printf family of functions
 * @return
 *  0 on success
 */
extern int audit_log_write(audit_log *l, const struct audit_reply *reply);

/**
 * Appends a string to the audit log, appending a newline, and rotating
 * the logs if needed.
 * @param l
 *  The audit log to append too.
 * @param str
 *  The string to append to the log.
 * @return
 *  0 on success
 *  0 on success or -errno on error
 *
 */
extern int audit_log_write_str(audit_log *l, const char *str);
extern int audit_log_write(audit_log *l, const char *fmt, ...);

/**
 * Forces a rotation of the audit log.
 * @param l
 *  The log file to use
 * @return
 *  0 on success
 *  0 on success, -errno on failure.
 */
extern int audit_log_rotate(audit_log *l);

/**
 * Closes the audit log file.
 * @param l
 *  The log file to close, NULL's the pointer.
 *  The log file to close.
 */
extern void audit_log_close(audit_log *l);

/**
 * Searches once through kmesg for type=1400
 * Searches once through kmsg for type=1400
 * kernel messages and logs them to the audit log
 * @param l
 *  The log to append too
 * @return
 *  0 on success
 *  0 on success, -errno on failure.
 */
extern int audit_log_put_kmsg(audit_log *l);

+160 −151
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@
 * Written by William Roberts <w.roberts@sta.samsung.com>
 */

#define LOG_TAG "auditd"

#include <stdio.h>
#include <stdlib.h>

@@ -28,17 +30,20 @@
#include <syslog.h>
#include <unistd.h>

#include <sys/capability.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <cutils/log.h>
#include <cutils/klog.h>

#include <cutils/log.h>
#include <private/android_filesystem_config.h>

#include <linux/capability.h>
#include <linux/prctl.h>

#include "auditd.h"
#include "libaudit.h"
#include "audit_log.h"

@@ -48,49 +53,57 @@
 *   1. Add a socket interface for sending events
 */

#define LOG_DIR "/data/misc/audit"
#define LOG_FILE LOG_DIR "/audit.log"
#define OLD_LOG_FILE LOG_DIR "/audit.old"
#ifndef AUDITD_MAX_LOG_FILE_SIZEKB
#error "AUDITD_MAX_LOG_FILE_SIZEKB not defined by makefile!"
#endif

#define MAX_LOG_FILE_SIZE (1024 * 100)
#define AUDITD_LOG_DIR "/data/misc/audit"
#define AUDITD_LOG_FILE AUDITD_LOG_DIR "/audit.log"
#define AUDITD_OLD_LOG_FILE AUDITD_LOG_DIR "/audit.old"

#define AUDITD_MAX_LOG_FILE_SIZE (1024 * AUDITD_MAX_LOG_FILE_SIZEKB)

static volatile int quit = 0;

static void signal_handler(int sig) {
static void signal_handler(int sig)
{
    switch (sig) {
    case SIGINT:
    case SIGTERM:
        quit = 1;
        break;
    }
    return;
}

static void usage(char *cmd) {
static void usage(char *cmd)
{
    printf("%s - log audit events from the kernel\n"
            "OPTIONS\n"
            "-k - search dmesg on startup for audit events\n"
			"\n",
			cmd);
            "\n", cmd);
}

#define RAISE(ary, c) ary[CAP_TO_INDEX(c)].permitted |= CAP_TO_MASK(c);

static void drop_privileges_or_die(void) {
static void drop_privileges_or_die(void)
{

    struct __user_cap_header_struct capheader;
    struct __user_cap_data_struct capdata[2];

    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
		ERROR("Failed on prctl KEEPCAPS: %s\n", strerror(errno));
        SLOGE("Failed on prctl KEEPCAPS: %s", strerror(errno));
        exit(1);
    }

    if (setgid(AID_AUDIT) < 0) {
		ERROR("Failed on setgid: %s\n", strerror(errno));
        SLOGE("Failed on setgid: %s", strerror(errno));
        exit(1);
    }

    if (setuid(AID_AUDIT) < 0) {
		ERROR("Failed on setuid: %s\n", strerror(errno));
        SLOGE("Failed on setuid: %s", strerror(errno));
        exit(1);
    }

@@ -108,27 +121,24 @@ static void drop_privileges_or_die(void) {
    capdata[1].inheritable = 0;

    if (capset(&capheader, &capdata[0]) < 0) {
		ERROR("Failed on capset: %s\n", strerror(errno));
        SLOGE("Failed on capset: %s", strerror(errno));
        exit(1);
    }
}

int main(int argc, char *argv[]) {

int main(int argc, char *argv[])
{
    int c;

	struct audit_reply rep;
	struct sigaction action;

    int rc;
    int audit_fd = -1;
    int check_kernel_log = 0;

	audit_log *l = NULL;
	ssize_t total_bytes = 0;
    struct pollfd pfds;
    struct audit_reply rep;
    struct sigaction action;
    audit_log *l = NULL;

	INFO("auditd:  starting up\n");
    SLOGI("Starting up");

    drop_privileges_or_die();

@@ -139,7 +149,7 @@ int main(int argc, char *argv[]) {
    rc = sigaction(SIGINT, &action, NULL);
    if (rc < 0) {
        rc = errno;
		ERROR("Failed on set signal handler: %s\n", strerror(errno));
        SLOGE("Failed on set signal handler: %s", strerror(errno));
        goto err;
    }

@@ -158,19 +168,19 @@ int main(int argc, char *argv[]) {
    audit_fd = audit_open();
    if (audit_fd < 0) {
        rc = errno;
		ERROR("Failed on audit_set_pid with error: %s\n", strerror(errno));
        SLOGE("Failed on audit_set_pid with error: %s", strerror(errno));
        goto err;
    }

	l = audit_log_open(LOG_FILE, OLD_LOG_FILE, MAX_LOG_FILE_SIZE);
    l = audit_log_open(AUDITD_LOG_FILE, AUDITD_OLD_LOG_FILE, AUDITD_MAX_LOG_FILE_SIZE);
    if (!l) {
		ERROR("Failed on audit_log_open\n");
        SLOGE("Failed on audit_log_open");
        goto err;
    }

    if (audit_set_pid(audit_fd, getpid(), WAIT_YES) < 0) {
        rc = errno;
		ERROR("Failed on audit_set_pid with error: %s\n", strerror(errno));
        SLOGE("Failed on audit_set_pid with error: %s", strerror(errno));
        goto err;
    }

@@ -187,25 +197,24 @@ int main(int argc, char *argv[]) {
        rc = poll(&pfds, 1, -1);
        if (rc == 0) {
            continue;
		}
		else if(rc < 0) {
        } else if (rc < 0) {
            if (errno != EINTR) {
				ERROR("Failed to poll audit log socket: %d : %s\n", errno, strerror(errno));
                SLOGE("Failed to poll audit log socket: %d : %s", errno, strerror(errno));
            }
            continue;
        }

        if (audit_get_reply(audit_fd, &rep, GET_REPLY_BLOCKING, 0) < 0) {
			ERROR("Failed on audit_get_reply with error: %s\n", strerror(errno));
            SLOGE("Failed on audit_get_reply with error: %s", strerror(errno));
            continue;
        }

		audit_log_write(l, &rep);
        audit_log_write(l, "type=%d msg=%.*s\n", rep.type, rep.len, rep.msg.data);
        /* Keep reading for events */
    }

err:
	INFO("auditd:  exiting\n");
    SLOGI("Exiting");
    if (audit_fd >= 0) {
        audit_set_pid(audit_fd, 0, WAIT_NO);
        audit_close(audit_fd);
Loading