aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Roberts <w.roberts@sta.samsung.com>2013-02-08 09:45:26 +0900
committerRicardo Cerqueira <cyanogenmod@cerqueira.org>2013-07-18 20:38:39 +0100
commit44677e46395555657a59a42a374c325135fc4beb (patch)
treee92ddd4e6f251ce4a382435f86c2bc384ee7a370
parent1f34e1cb563506ed0d9c27420a3bb2203ee8396e (diff)
downloadsystem_core-44677e46395555657a59a42a374c325135fc4beb.zip
system_core-44677e46395555657a59a42a374c325135fc4beb.tar.gz
system_core-44677e46395555657a59a42a374c325135fc4beb.tar.bz2
Auditd initial commit
Initial commit for an audit daemon that writes kernel audit messages to a log file. The daemon runs in uid "audit" or AID_AUDIT. The log files are located at /data/misc/audit/ The daemon maintains two files at this location: audit.log and optionally audit.old. On boot ( if the file is non-zero in size), or when a fixed threshold is hit, the daemon rotates audit.log to audit.old. Optionally, if passed the -k option, the daemon polls dmesg for all lines that contain "audit" and writes them into the log. After that it continues to operate as normal, receiving the messages from the netlink socket. Change-Id: I5b5037a5a8b39a054213848249afb7808f8b0ffa
-rw-r--r--auditd/Android.mk19
-rw-r--r--auditd/NOTICE190
-rw-r--r--auditd/audit_log.c251
-rw-r--r--auditd/audit_log.h92
-rw-r--r--auditd/auditd.c215
-rw-r--r--auditd/auditd.h44
-rw-r--r--auditd/libaudit.c78
-rw-r--r--auditd/libaudit.h46
-rw-r--r--auditd/netlink.c367
-rw-r--r--rootdir/init.rc4
10 files changed, 1306 insertions, 0 deletions
diff --git a/auditd/Android.mk b/auditd/Android.mk
new file mode 100644
index 0000000..582511b
--- /dev/null
+++ b/auditd/Android.mk
@@ -0,0 +1,19 @@
+# Copyright 2005 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ auditd.c \
+ netlink.c \
+ libaudit.c \
+ audit_log.c
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libc
+
+LOCAL_MODULE_TAGS:=optional
+LOCAL_MODULE:=auditd
+
+include $(BUILD_EXECUTABLE)
diff --git a/auditd/NOTICE b/auditd/NOTICE
new file mode 100644
index 0000000..8022096
--- /dev/null
+++ b/auditd/NOTICE
@@ -0,0 +1,190 @@
+
+ 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/auditd/audit_log.c b/auditd/audit_log.c
new file mode 100644
index 0000000..5a9ffd3
--- /dev/null
+++ b/auditd/audit_log.c
@@ -0,0 +1,251 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include <sys/klog.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "libaudit.h"
+#include "audit_log.h"
+#include "auditd.h"
+
+#define AUDIT_LOG_MODE (S_IRUSR | S_IWUSR | S_IRGRP)
+#define AUDIT_LOG_FLAGS (O_RDWR | O_CREAT | O_SYNC)
+
+struct audit_log {
+ int fd;
+ size_t total_bytes;
+ size_t threshold;
+ char *rotatefile;
+ char *logfile;
+};
+
+/**
+ * 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
+ * @return
+ */
+static int write_log(audit_log *l, const void *buf, size_t len) {
+
+ int rc = 0;
+ ssize_t bytes = 0;
+
+ /*
+ * 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;
+
+ if(!l) {
+ rc = EINVAL;
+ goto err;
+ }
+
+ do {
+ bytes = write(l->fd, b, len);
+ if(bytes < 0 && errno != EINTR) {
+ rc = errno;
+ 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);
+ }
+
+ return rc;
+
+err:
+ ERROR("Error in function: %s, line: %d, error: %s\n",
+ __FUNCTION__, __LINE__, strerror(rc));
+ goto out;
+}
+
+audit_log *audit_log_open(const char *logfile, const char *rotatefile, size_t threshold) {
+
+ int fd = -1;
+ audit_log *l = NULL;
+ struct stat log_file_stats;
+
+ if (stat(logfile, &log_file_stats) < 0) {
+ if (errno != ENOENT) {
+ ERROR("Could not stat %s: %s\n",
+ logfile, strerror(errno));
+ goto err;
+ }
+ }
+ /* 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;
+ }
+ }
+
+ /* 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;
+ }
+ fchmod(fd, AUDIT_LOG_MODE);
+
+ l = calloc(sizeof(struct audit_log), 1);
+ if (!l) {
+ goto err;
+ }
+ l->rotatefile = strdup(rotatefile);
+ if (!l->rotatefile) {
+ goto err;
+ }
+
+ l->logfile = strdup(logfile);
+ if (!l->logfile) {
+ goto err;
+ }
+ l->fd = fd;
+ l->threshold = threshold;
+
+out:
+ return l;
+
+err:
+ audit_log_close(l);
+ l = NULL;
+ goto out;
+}
+
+int audit_log_write_str(audit_log *l, const char *str) {
+ return write_log(l, str, strlen(str));
+}
+
+int audit_log_write(audit_log *l, const struct audit_reply *reply) {
+ return write_log(l, reply->msg.data, reply->len);
+}
+
+int audit_log_rotate(audit_log *l) {
+ int rc = 0;
+ if(!l) {
+ rc = EINVAL;
+ goto err;
+ }
+
+ rc = rename(l->logfile, l->rotatefile);
+ if (rc < 0) {
+ rc = errno;
+ goto err;
+ }
+
+ close(l->fd);
+ l->total_bytes = 0;
+
+ l->fd = open(l->logfile, AUDIT_LOG_FLAGS, AUDIT_LOG_MODE);
+ if(l->fd < 0) {
+ rc = errno;
+ goto err;
+ }
+ fchmod(l->fd, AUDIT_LOG_MODE);
+
+out:
+ return rc;
+err:
+ goto out;
+}
+
+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);
+ }
+ free(l);
+ l = NULL;
+ }
+ return;
+}
+
+int audit_log_put_kmsg(audit_log *l) {
+
+ char *tok;
+
+ int rc = 0;
+ char *buf = NULL;
+ int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
+
+ if (len > 0) {
+ 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;
+ }
+
+ rc = klogctl(KLOG_READ_ALL, buf, len);
+ if(rc < 0) {
+ ERROR("Could not read logs: %s\n",
+ strerror(errno));
+ rc = errno;
+ goto err;
+ }
+
+ buf[len-1] = '\0';
+ tok = buf;
+
+ while((tok = strtok(tok, "\r\n"))) {
+ if(strstr(tok, " audit(")) {
+ audit_log_write_str(l, tok);
+ }
+ tok = NULL;
+ }
+
+err:
+ if (buf) {
+ free(buf);
+ }
+
+ return 0;
+}
diff --git a/auditd/audit_log.h b/auditd/audit_log.h
new file mode 100644
index 0000000..454782d
--- /dev/null
+++ b/auditd/audit_log.h
@@ -0,0 +1,92 @@
+/*
+ * 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>
+ */
+
+#ifndef _AUDIT_LOG_H_
+#define _AUDIT_LOG_H_
+
+#include <unistd.h>
+#include "libaudit.h"
+
+typedef struct audit_log audit_log;
+
+/**
+ * Opens an audit logfile for writing
+ * @param logfile
+ * The logfile name to use
+ * @param rotatefile
+ * The logfile to rotate to when threshold is encountered
+ * @param threshold
+ * The threshold, in bytes, the log file should grow to
+ * until rotation.
+ * @return
+ * A valid handle to the audit_log.
+ */
+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.
+ * @param l
+ * The audit log to use
+ * @param reply
+ * The response to write
+ * @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
+ */
+extern int audit_log_write_str(audit_log *l, const char *str);
+
+/**
+ * Forces a rotation of the audit log.
+ * @param l
+ * The log file to use
+ * @return
+ * 0 on success
+ */
+extern int audit_log_rotate(audit_log *l);
+
+/**
+ * Closes the audit log file.
+ * @param l
+ * The log file to close, NULL's the pointer.
+ */
+extern void audit_log_close(audit_log *l);
+
+/**
+ * Searches once through kmesg for type=1400
+ * kernel messages and logs them to the audit log
+ * @param l
+ * The log to append too
+ * @return
+ * 0 on success
+ */
+extern int audit_log_put_kmsg(audit_log *l);
+
+#endif
diff --git a/auditd/auditd.c b/auditd/auditd.c
new file mode 100644
index 0000000..f56f659
--- /dev/null
+++ b/auditd/auditd.c
@@ -0,0 +1,215 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <cutils/klog.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"
+
+/*
+ * TODO:
+ * Just Ideas:
+ * 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"
+
+#define MAX_LOG_FILE_SIZE (1024 * 100)
+
+static volatile int quit = 0;
+
+static void signal_handler(int sig) {
+ switch (sig) {
+ case SIGINT:
+ quit = 1;
+ break;
+ }
+ return;
+}
+
+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);
+}
+
+#define RAISE(ary, c) ary[CAP_TO_INDEX(c)].permitted |= CAP_TO_MASK(c);
+
+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));
+ exit(1);
+ }
+
+ if (setgid(AID_AUDIT) < 0) {
+ ERROR("Failed on setgid: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (setuid(AID_AUDIT) < 0) {
+ ERROR("Failed on setuid: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ RAISE(capdata, CAP_AUDIT_CONTROL);
+ RAISE(capdata, CAP_SYSLOG);
+
+ capdata[0].effective = capdata[0].permitted;
+ capdata[1].effective = capdata[1].permitted;
+ capdata[0].inheritable = 0;
+ capdata[1].inheritable = 0;
+
+ if (capset(&capheader, &capdata[0]) < 0) {
+ ERROR("Failed on capset: %s\n", strerror(errno));
+ exit(1);
+ }
+}
+
+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;
+
+ INFO("auditd: starting up\n");
+
+ drop_privileges_or_die();
+
+ /* register the signal handler */
+ action.sa_handler = signal_handler;
+ sigemptyset (&action.sa_mask);
+ action.sa_flags = 0;
+ rc = sigaction (SIGINT, &action, NULL);
+ if (rc < 0) {
+ rc = errno;
+ ERROR("Failed on set signal handler: %s\n", strerror(errno));
+ goto err;
+ }
+
+ while((c = getopt(argc, argv, "k")) != -1) {
+ switch(c) {
+ case 'k':
+ check_kernel_log = 1;
+ break;
+ default:
+ usage(argv[0]);
+ goto err;
+ }
+ }
+
+ /* Open the netlink socket for audit events */
+ audit_fd = audit_open();
+ if (audit_fd < 0) {
+ rc = errno;
+ ERROR("Failed on audit_set_pid with error: %s\n", strerror(errno));
+ goto err;
+ }
+
+ l = audit_log_open(LOG_FILE, OLD_LOG_FILE, MAX_LOG_FILE_SIZE);
+ if(!l) {
+ ERROR("Failed on audit_log_open\n");
+ 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));
+ goto err;
+ }
+
+ pfds.fd = audit_fd;
+ pfds.events = POLLIN;
+
+ if(check_kernel_log) {
+ audit_log_put_kmsg(l);
+ }
+
+ while (!quit) {
+
+ /* Start reading for events */
+ rc = poll(&pfds, 1, -1);
+ if (rc == 0) {
+ continue;
+ }
+ else if(rc < 0) {
+ if (errno != EINTR) {
+ ERROR("Failed to poll audit log socket: %d : %s\n", 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));
+ continue;
+ }
+
+ audit_log_write(l, &rep);
+ /* Keep reading for events */
+ }
+
+err:
+ INFO("auditd: exiting\n");
+ if (audit_fd >= 0) {
+ audit_set_pid(audit_fd, 0, WAIT_NO);
+ audit_close(audit_fd);
+ }
+ audit_log_close(l);
+ return rc;
+}
diff --git a/auditd/auditd.h b/auditd/auditd.h
new file mode 100644
index 0000000..594b670
--- /dev/null
+++ b/auditd/auditd.h
@@ -0,0 +1,44 @@
+/*
+ * 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>
+ */
+
+#ifndef _AUDITD_H_
+#define _AUDITD_H_
+
+#define LOG_TAG "auditd"
+
+#include <cutils/log.h>
+
+/* Debugging statements that go to the system log
+ * aka logcat.
+ * The naming convention follows the severity of the
+ * message to print.
+ */
+#define INFO(...) SLOGI(__VA_ARGS__)
+#define ERROR(...) SLOGE(__VA_ARGS__)
+#define WARNING(...) SLOGW(__VA_ARGS__)
+
+/*
+ * Given an errno variable, returns the abs value of it
+ * Some of the existing interfaces return a -errno instead of -1
+ * with errno set. This is just a way of ensuring that the errno
+ * you are using, is a positive value.
+ */
+#define GETERRNO(x) ((x < 0) ? -x : x)
+
+#endif
+
diff --git a/auditd/libaudit.c b/auditd/libaudit.c
new file mode 100644
index 0000000..905e8af
--- /dev/null
+++ b/auditd/libaudit.c
@@ -0,0 +1,78 @@
+/*
+ * 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 <string.h>
+
+#include <cutils/klog.h>
+
+#include "auditd.h"
+#include "libaudit.h"
+
+/* Only should be used internally */
+extern int audit_send(int fd, int type, const void *data, unsigned int size);
+
+/* Depending on static to initialize this to 0 */
+static const struct audit_status _new_audit_status;
+
+int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode) {
+
+ int rc;
+ int line;
+ struct audit_reply rep;
+ struct audit_status status = _new_audit_status;
+
+ /*
+ * In order to set the auditd PID we send an audit message over the netlink socket
+ * with the pid field of the status struct set to our current pid, and the
+ * the mask set to AUDIT_STATUS_PID
+ */
+ status.pid = pid;
+ 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));
+ if (rc < 0) {
+ line = __LINE__;
+ goto err;
+ }
+
+ /*
+ * In a request where we need to wait for a response, wait for the message
+ * and discard it. This message confirms and sync's us with the kernel.
+ * This daemon is now registered as the audit logger. Only wait if the
+ * wmode is != WAIT_NO
+ */
+ if (wmode != WAIT_NO) {
+ /* TODO
+ * If the daemon dies and restarts the message didn't come back,
+ * so I went to non-blocking and it seemed to fix the bug.
+ * Need to investigate further.
+ */
+ (void)audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
+ }
+
+out:
+ return rc;
+
+err:
+ errno = GETERRNO(rc);
+ ERROR("%s Failed in %s around line %d with error: %s\n", __FILE__, __FUNCTION__, line, strerror(errno));
+ rc = -1;
+ goto out;
+}
diff --git a/auditd/libaudit.h b/auditd/libaudit.h
new file mode 100644
index 0000000..4d96059
--- /dev/null
+++ b/auditd/libaudit.h
@@ -0,0 +1,46 @@
+#ifndef _LIBAUDIT_H_
+#define _LIBAUDIT_H_
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <linux/netlink.h>
+#include <linux/audit.h>
+
+#define MAX_AUDIT_MESSAGE_LENGTH 8970
+
+typedef enum { GET_REPLY_BLOCKING=0, GET_REPLY_NONBLOCKING } reply_t;
+typedef enum { WAIT_NO, WAIT_YES } rep_wait_t;
+
+struct audit_sig_info {
+ uid_t uid;
+ pid_t pid;
+ char ctx[0];
+};
+
+struct audit_message {
+ struct nlmsghdr nlh;
+ char data[MAX_AUDIT_MESSAGE_LENGTH];
+};
+
+struct audit_reply {
+ int type;
+ int len;
+ struct nlmsghdr *nlh;
+ struct audit_message msg;
+
+ union {
+ struct audit_status *status;
+ struct audit_rule_data *ruledata;
+ const char *message;
+ struct nlmsgerr *error;
+ struct audit_sig_info *signal_info;
+ };
+};
+
+extern int audit_open(void);
+extern void audit_close(int fd);
+extern int audit_get_reply(int fd, struct audit_reply *rep, reply_t block,
+ int peek);
+extern int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode);
+
+#endif
diff --git a/auditd/netlink.c b/auditd/netlink.c
new file mode 100644
index 0000000..27cbfb9
--- /dev/null
+++ b/auditd/netlink.c
@@ -0,0 +1,367 @@
+/*
+ * 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 <string.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include <cutils/klog.h>
+
+#include "auditd.h"
+#include "libaudit.h"
+
+/* Relying on static to initialize to 0, these are used to initialize structs to 0 */
+static const struct audit_message _new_req;
+static const struct sockaddr_nl _new_addr;
+
+/**
+ * Copies the netlink message data to the reply structure.
+ *
+ * When the kernel sends a response back, we must adjust the response from the nlmsghdr.
+ * All the data is is rep->msg but belongs in type enforced fields in the struct.
+ *
+ * @param rep
+ * The response
+ * @param len
+ * The length of ther message, len must never be less than 0!
+ * @return
+ * This function returns 0 on success.
+ */
+static int set_internal_fields(struct audit_reply *rep, ssize_t len) {
+
+ int rc = 0;
+ int line = 0;
+
+ /*
+ * We end up setting a specific field in the union, but since it
+ * is a union and they are all of type pointer, we can just clear
+ * one.
+ */
+ rep->status = NULL;
+
+ /* Set the response from the netlink message */
+ rep->nlh = &rep->msg.nlh;
+ rep->len = rep->msg.nlh.nlmsg_len;
+ rep->type = rep->msg.nlh.nlmsg_type;
+
+ /* Check if the reply from the kernel was ok */
+ if (!NLMSG_OK(rep->nlh, (size_t)len)) {
+ rc = (len == sizeof(rep->msg)) ? EFBIG : EBADE;
+ line = __LINE__;
+ goto err;
+ }
+
+ /* Next we'll set the data structure to point to msg.data. This is
+ * to avoid having to use casts later. */
+ if (rep->type == NLMSG_ERROR) {
+ rep->error = NLMSG_DATA(rep->nlh);
+ }
+ else if (rep->type == AUDIT_GET) {
+ rep->status = NLMSG_DATA(rep->nlh);
+ }
+ else if (rep -> type == AUDIT_LIST_RULES) {
+ rep->ruledata = NLMSG_DATA(rep->nlh);
+ }
+ else if (rep->type == AUDIT_SIGNAL_INFO) {
+ rep->signal_info = NLMSG_DATA(rep->nlh);
+ }
+ /* If it is not any of the above specific events, it must be a generic message */
+ else {
+ rep->message = NLMSG_DATA(rep->nlh);
+ }
+out:
+ return rc;
+err:
+ errno = GETERRNO(rc);
+ ERROR("%s Failed in %s around line %d with error: %s\n", __FILE__, __FUNCTION__, line, strerror(errno));
+ rc = -1;
+ goto out;
+}
+
+/**
+ * Waits for an ack from the kernel
+ * @param fd
+ * The netlink socket fd
+ * @param seq
+ * The current sequence number were acking on
+ * @return
+ * 0 on success
+ */
+static int get_ack(int fd, int16_t seq) {
+
+ int rc = 0;
+ int line = 0;
+
+ struct audit_reply rep;
+
+ /* Sanity check the input, this is an internal interface this shouldn't happen */
+ if (fd < 0) {
+ rc = EINVAL;
+ line = __LINE__;
+ goto err;
+ }
+
+ rc = -audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, MSG_PEEK);
+ if(rc < 0) {
+ line = __LINE__;
+ goto err;
+ }
+ else if (rep.type == NLMSG_ERROR) {
+ (void)audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0);
+ if (rep.error->error) {
+ line = __LINE__;
+ rc = rep.error->error;
+ goto err;
+ }
+ }
+out:
+ return rc;
+err:
+ errno = GETERRNO(rc);
+ ERROR("%s Failed in %s around line %d with error: %s\n", __FILE__, __FUNCTION__, line, strerror(errno));
+ rc = -1;
+ goto out;
+}
+
+/**
+ * Opens a connection to the Audit netlink socket
+ * @return
+ * A valid fd on success or < 0 on error with errno set.
+ * Returns the same errors as man 2 socket.
+ */
+int audit_open() {
+ return socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
+}
+
+/**
+ *
+ * @param fd
+ * The fd returned by a call to audit_open()
+ * @param rep
+ * The response struct to store the response in.
+ * @param block
+ * Whether or not to block on IO
+ * @param peek
+ * Whether or not we are to remove the message from
+ * the queue when we do a read on the netlink socket.
+ * @return
+ * 0 on success, errno on error
+ */
+int audit_get_reply(int fd, struct audit_reply *rep, reply_t block, int peek) {
+
+ int rc;
+ ssize_t len;
+ int flags;
+ int line = 0;
+
+ struct sockaddr_nl nladdr;
+ socklen_t nladdrlen = sizeof(nladdr);
+
+ if (fd < 0) {
+ rc = EBADF;
+ line = __LINE__;
+ goto err;
+ }
+
+ /* Set up the flags for recv from */
+ flags = (block == GET_REPLY_NONBLOCKING) ? MSG_DONTWAIT : 0;
+ flags |= peek;
+
+ /*
+ * Get the data from the netlink socket but on error we need to be carefull,
+ * the interface shows that EINTR can never be returned, other errors, however,
+ * can be returned.
+ */
+ do {
+
+ len = recvfrom(fd, &rep->msg, sizeof(rep->msg), flags,
+ (struct sockaddr*)&nladdr, &nladdrlen);
+
+ /*
+ * EAGAIN and EINTR should be re-tried until success or
+ * another error manifests.
+ */
+ if (len < 0 && errno != EINTR) {
+ if (block == GET_REPLY_NONBLOCKING && errno == EAGAIN) {
+ rc = 0;
+ goto out;
+ }
+ rc = errno;
+ line = __LINE__;
+ goto err;
+ }
+
+ /* 0 or greater indicates success */
+ } while (len < 0);
+
+ if (nladdrlen != sizeof(nladdr)) {
+ rc = EPROTO;
+ line == __LINE__;
+ goto err;
+ }
+
+ /* Make sure the netlink message was not spoof'd */
+ if (nladdr.nl_pid) {
+ rc = EINVAL;
+ line == __LINE__;
+ goto err;
+ }
+
+ rc = set_internal_fields(rep, len);
+ if (rc < 0) {
+ rc = errno;
+ line == __LINE__;
+ goto err;
+ }
+
+out:
+ return rc;
+err:
+ errno = GETERRNO(rc);
+ ERROR("%s Failed in %s around line %d with error: %s\n", __FILE__, __FUNCTION__, line, strerror(errno));
+ rc = -1;
+ goto out;
+}
+
+/**
+ * Closes the fd returned from audit_open()
+ * @param fd
+ * The fd to close
+ *
+ * @note
+ * This function was left void to be complaint
+ * to an existing interface, however it clears
+ * errno on entry, so errno can be used to check
+ * if the fd you gave close was wrong.
+ *
+ */
+void audit_close(int fd) {
+
+ int line = 0;
+ int rc = close(fd);
+ if(rc) {
+ line == __LINE__;
+ rc = errno;
+ goto err;
+ }
+out:
+ return;
+
+err:
+ errno = GETERRNO(rc);
+ ERROR("%s Failed in %s around line %d with error: %s\n", __FILE__, __FUNCTION__, line, strerror(errno));
+ goto out;
+}
+
+/**
+ *
+ * @param fd
+ * The netlink socket fd
+ * @param type
+ * The type of netlink message
+ * @param data
+ * The data to send
+ * @param size
+ * The length of the data in bytes
+ * @return
+ * Sequence number on success or -errno on error.
+ */
+int audit_send(int fd, int type, const void *data, unsigned int size) {
+
+ int rc = 0;
+ static int16_t sequence = 0;
+ struct audit_message req = _new_req;
+ struct sockaddr_nl addr = _new_addr;
+
+ /* We always send netlink messaged */
+ addr.nl_family = AF_NETLINK;
+
+ /* Set up the netlink headers */
+ req.nlh.nlmsg_type = type;
+ req.nlh.nlmsg_len = NLMSG_SPACE(size);
+ req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+
+ /*
+ * Check for a valid fd, even though sendto would catch this, its easier to always
+ * blindly increment the sequence number
+ */
+ if (fd < 0) {
+ rc = EBADF;
+ goto err;
+ }
+
+ /* Ensure the message is not too big */
+ if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
+ rc = EINVAL;
+ goto err;
+ }
+
+ /* Only memcpy in the data if it was specified */
+ if (size && data)
+ memcpy(NLMSG_DATA(&req.nlh), data, size);
+
+ /*
+ * Only increment the sequence number on a guarantee
+ * you will send it to the kernel.
+ *
+ * Also, the sequence is defined as a u32 in the kernel
+ * struct. Using an int here might not work on 32/64 bit splits. A
+ * signed 64 bit value can overflow a u32..but a u32
+ * might not fit in the response, so we need to use s32.
+ * Which is still kind of hackish since int could be 16 bits
+ * in size. The only safe type to use here is a signed 16
+ * bit value.
+ */
+ req.nlh.nlmsg_seq = ++sequence;
+
+ /* While failing and its due to interrupts */
+ do {
+ /* Try and send the netlink message */
+ rc = sendto(fd, &req, req.nlh.nlmsg_len, 0,
+ (struct sockaddr*)&addr, sizeof(addr));
+
+ } while (rc < 0 && errno == EINTR);
+
+ /* Not all the bytes were sent */
+ if ((uint32_t)rc != req.nlh.nlmsg_len) {
+ rc = EPROTO;
+ goto err;
+ }
+ else if (rc < 0) {
+ rc = errno;
+ goto out;
+ }
+
+ /* We sent all the bytes, get the ack */
+ rc = (get_ack(fd, sequence) == 0) ? (int)sequence : rc;
+
+out:
+
+ /* Don't let sequence roll to negative */
+ sequence = (sequence < 0) ? 0 : sequence;
+
+ return rc;
+
+err:
+ errno = rc;
+ rc = -rc;
+ goto out;
+}
+
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 8bddf31..d261e4a 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -218,6 +218,7 @@ on post-fs-data
# create basic filesystem structure
mkdir /data/misc 01771 system misc
mkdir /data/misc/adb 02750 system shell
+ mkdir /data/misc/audit 02750 audit system
mkdir /data/misc/bluedroid 0770 bluetooth net_bt_stack
mkdir /data/misc/bluetooth 0770 system system
mkdir /data/misc/keystore 0700 keystore keystore
@@ -453,6 +454,9 @@ service console /system/bin/sh
user shell
group log
+service auditd /system/bin/auditd -k
+ class main
+
on property:ro.debuggable=1
start console