Merge "Add force_encrypt flag to fstab to force encryption on appropriate devices"
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
index c8c87c3..5b98de2 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -22,8 +22,11 @@
 
 extern "C" {
 
+// Definitions exist in C++11
+#if defined __cplusplus && __cplusplus < 201103L
 typedef uint32_t char32_t;
 typedef uint16_t char16_t;
+#endif
 
 // Standard string functions on char16_t strings.
 int strcmp16(const char16_t *, const char16_t *);
diff --git a/logd/Android.mk b/logd/Android.mk
index b0bc746..61895c4 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -19,7 +19,9 @@
     LogBufferElement.cpp \
     LogTimes.cpp \
     LogStatistics.cpp \
-    LogWhiteBlackList.cpp
+    LogWhiteBlackList.cpp \
+    libaudit.c \
+    LogAudit.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libsysutils \
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
new file mode 100644
index 0000000..ea6eece
--- /dev/null
+++ b/logd/LogAudit.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2014 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 <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/klog.h>
+#include <sys/uio.h>
+
+#include "libaudit.h"
+#include "LogAudit.h"
+
+LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmsg)
+        : SocketListener(getLogSocket(), false)
+        , logbuf(buf)
+        , reader(reader)
+        , fdDmesg(-1) {
+    logDmesg();
+    fdDmesg = fdDmsg;
+}
+
+bool LogAudit::onDataAvailable(SocketClient *cli) {
+    struct audit_message rep;
+
+    if (audit_get_reply(cli->getSocket(), &rep, GET_REPLY_BLOCKING, 0) < 0) {
+        SLOGE("Failed on audit_get_reply with error: %s", strerror(errno));
+        return false;
+    }
+
+    logPrint("type=%d %.*s", rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
+
+    return true;
+}
+
+#define AUDIT_LOG_ID   LOG_ID_MAIN
+#define AUDIT_LOG_PRIO ANDROID_LOG_WARN
+
+int LogAudit::logPrint(const char *fmt, ...) {
+    if (fmt == NULL) {
+        return -EINVAL;
+    }
+
+    va_list args;
+
+    char *str = NULL;
+    va_start(args, fmt);
+    int rc = vasprintf(&str, fmt, args);
+    va_end(args);
+
+    if (rc < 0) {
+        return rc;
+    }
+
+    if (fdDmesg >= 0) {
+        struct iovec iov[2];
+
+        iov[0].iov_base = str;
+        iov[0].iov_len = strlen(str);
+        iov[1].iov_base = const_cast<char *>("\n");
+        iov[1].iov_len = 1;
+
+        writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+    }
+
+    pid_t pid = getpid();
+    pid_t tid = gettid();
+    uid_t uid = getuid();
+    log_time now;
+
+    static const char audit_str[] = " audit(";
+    char *timeptr = strstr(str, audit_str);
+    char *cp;
+    if (timeptr
+            && ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q")))
+            && (*cp == ':')) {
+        memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
+        strcpy(timeptr + sizeof(audit_str) - 1 + 3, cp);
+    } else {
+        now.strptime("", ""); // side effect of setting CLOCK_REALTIME
+    }
+
+    static const char pid_str[] = " pid=";
+    char *pidptr = strstr(str, pid_str);
+    if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
+        cp = pidptr + sizeof(pid_str) - 1;
+        pid = 0;
+        while (isdigit(*cp)) {
+            pid = (pid * 10) + (*cp - '0');
+            ++cp;
+        }
+        tid = pid;
+        uid = logbuf->pidToUid(pid);
+        strcpy(pidptr, cp);
+    }
+
+    static const char comm_str[] = " comm=\"";
+    char *comm = strstr(str, comm_str);
+    if (comm) {
+        cp = comm;
+        comm += sizeof(comm_str) - 1;
+        char *ecomm = strchr(comm, '"');
+        if (ecomm) {
+            *ecomm = '\0';
+        }
+        comm = strdup(comm);
+        if (ecomm) {
+            strcpy(cp, ecomm + 1);
+        }
+    } else if (pid == getpid()) {
+        pid = tid;
+        comm = strdup("auditd");
+    } else if (!(comm = logbuf->pidToName(pid))) {
+        comm = strdup("unknown");
+    }
+
+    size_t l = strlen(comm) + 1;
+    size_t n = l + strlen(str) + 2;
+
+    char *newstr = reinterpret_cast<char *>(malloc(n));
+    if (!newstr) {
+        free(comm);
+        free(str);
+        return -ENOMEM;
+    }
+
+    *newstr = AUDIT_LOG_PRIO;
+    strcpy(newstr + 1, comm);
+    free(comm);
+    strcpy(newstr + 1 + l, str);
+    free(str);
+
+    unsigned short len = n; // cap to internal maximum
+    if (len != n) {
+        len = -1;
+    }
+    logbuf->log(AUDIT_LOG_ID, now, uid, pid, tid, newstr, len);
+    reader->notifyNewLog();
+
+    free(newstr);
+
+    return rc;
+}
+
+void LogAudit::logDmesg() {
+    int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
+    if (len <= 0) {
+        return;
+    }
+
+    len++;
+    char buf[len];
+
+    int rc = klogctl(KLOG_READ_ALL, buf, len);
+
+    buf[len - 1] = '\0';
+
+    for(char *tok = buf; (rc >= 0) && ((tok = strtok(tok, "\r\n"))); tok = NULL) {
+        char *audit = strstr(tok, " audit(");
+        if (!audit) {
+            continue;
+        }
+
+        *audit++ = '\0';
+
+        char *type = strstr(tok, "type=");
+        if (type) {
+            rc = logPrint("%s %s", type, audit);
+        } else {
+            rc = logPrint("%s", audit);
+        }
+    }
+}
+
+int LogAudit::getLogSocket() {
+    int fd = audit_open();
+    if (fd < 0) {
+        return fd;
+    }
+    if (audit_set_pid(fd, getpid(), WAIT_YES) < 0) {
+        audit_close(fd);
+        fd = -1;
+    }
+    return fd;
+}
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
new file mode 100644
index 0000000..111030a
--- /dev/null
+++ b/logd/LogAudit.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef _LOGD_LOG_AUDIT_H__
+#define _LOGD_LOG_AUDIT_H__
+
+#include <sysutils/SocketListener.h>
+#include "LogReader.h"
+
+class LogAudit : public SocketListener {
+    LogBuffer *logbuf;
+    LogReader *reader;
+    int fdDmesg;
+
+public:
+    LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg);
+
+protected:
+    virtual bool onDataAvailable(SocketClient *cli);
+
+private:
+    static int getLogSocket();
+    void logDmesg();
+    int logPrint(const char *fmt, ...)
+        __attribute__ ((__format__ (__printf__, 2, 3)));
+};
+
+#endif
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index c3460ca..bdb3179 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -77,6 +77,10 @@
     void formatPrune(char **strp) { mPrune.format(strp); }
 #endif
 
+    // helper
+    char *pidToName(pid_t pid) { return stats.pidToName(pid); }
+    uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
+
 private:
     void maybePrune(log_id_t id);
     void prune(log_id_t id, unsigned long pruneRows);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 5622ee5..fc6e6b2 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <fcntl.h>
 #include <stdarg.h>
 #include <time.h>
 
@@ -23,12 +24,34 @@
 
 #include "LogStatistics.h"
 
-PidStatistics::PidStatistics(pid_t pid)
+PidStatistics::PidStatistics(pid_t pid, char *name)
         : pid(pid)
         , mSizesTotal(0)
         , mElementsTotal(0)
         , mSizes(0)
-        , mElements(0) { }
+        , mElements(0)
+        , name(name)
+{ }
+
+#ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR
+PidStatistics::PidStatistics(const PidStatistics &copy)
+        : pid(copy->pid)
+        , name(copy->name ? strdup(copy->name) : NULL)
+        , mSizesTotal(copy->mSizesTotal)
+        , mElementsTotal(copy->mElementsTotal)
+        , mSizes(copy->mSizes)
+        , mElements(copy->mElements)
+{ }
+#endif
+
+PidStatistics::~PidStatistics() {
+    free(name);
+}
+
+void PidStatistics::setName(char *new_name) {
+    free(name);
+    name = new_name;
+}
 
 void PidStatistics::add(unsigned short size) {
     mSizesTotal += size;
@@ -50,6 +73,28 @@
     }
 }
 
+// must call free to release return value
+char *PidStatistics::pidToName(pid_t pid) {
+    char *retval = NULL;
+    if (pid != PidStatistics::gone) {
+        char buffer[512];
+        snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
+        int fd = open(buffer, O_RDONLY);
+        if (fd >= 0) {
+            ssize_t ret = read(fd, buffer, sizeof(buffer));
+            if (ret > 0) {
+                buffer[sizeof(buffer)-1] = '\0';
+                // frameworks intermediate state
+                if (strcmp(buffer, "<pre-initialized>")) {
+                    retval = strdup(buffer);
+                }
+            }
+            close(fd);
+        }
+    }
+    return retval;
+}
+
 UidStatistics::UidStatistics(uid_t uid)
         : uid(uid) {
     Pids.clear();
@@ -83,7 +128,7 @@
     bool insert = (last != it)
         && ((p->getPid() == p->gone)
             || ((*last)->sizesTotal() < (size_t) size));
-    p = new PidStatistics(pid);
+    p = new PidStatistics(pid, pidToName(pid));
     if (insert) {
         Pids.insert(last, p);
     } else {
@@ -397,11 +442,11 @@
 
 void LogStatistics::format(char **buf,
                            uid_t uid, unsigned int logMask, log_time oldest) {
-    const unsigned short spaces_current = 13;
-    const unsigned short spaces_total = 19;
+    static const unsigned short spaces_current = 13;
+    static const unsigned short spaces_total = 19;
 
     if (*buf) {
-        free(buf);
+        free(*buf);
         *buf = NULL;
     }
 
@@ -683,3 +728,20 @@
 
     *buf = strdup(string.string());
 }
+
+uid_t LogStatistics::pidToUid(pid_t pid) {
+    log_id_for_each(i) {
+        LidStatistics &l = id(i);
+        UidStatisticsCollection::iterator iu;
+        for (iu = l.begin(); iu != l.end(); ++iu) {
+            UidStatistics &u = *(*iu);
+            PidStatisticsCollection::iterator ip;
+            for (ip = u.begin(); ip != u.end(); ++ip) {
+                if ((*ip)->getPid() == pid) {
+                    return u.getUid();
+                }
+            }
+        }
+    }
+    return getuid(); // associate this with the logger
+}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 6a26263..12c68d5 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -36,12 +36,18 @@
     size_t mSizes;
     size_t mElements;
 
+    char *name;
+
 public:
     static const pid_t gone = (pid_t) -1;
 
-    PidStatistics(pid_t pid);
+    PidStatistics(pid_t pid, char *name = NULL);
+    PidStatistics(const PidStatistics &copy);
+    ~PidStatistics();
 
     pid_t getPid() const { return pid; }
+    char *getName() const { return name; }
+    void setName(char *name);
 
     void add(unsigned short size);
     bool subtract(unsigned short size); // returns true if stats and PID gone
@@ -52,6 +58,9 @@
 
     size_t sizesTotal() const { return mSizesTotal; }
     size_t elementsTotal() const { return mElementsTotal; }
+
+    // helper
+    static char *pidToName(pid_t pid);
 };
 
 typedef android::List<PidStatistics *> PidStatisticsCollection;
@@ -80,6 +89,9 @@
 
     size_t sizesTotal(pid_t pid = pid_all);
     size_t elementsTotal(pid_t pid = pid_all);
+
+    // helper
+    static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
 };
 
 typedef android::List<UidStatistics *> UidStatisticsCollection;
@@ -157,6 +169,10 @@
 
     // *strp = malloc, balance with free
     void format(char **strp, uid_t uid, unsigned int logMask, log_time oldest);
+
+    // helper
+    static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
+    uid_t pidToUid(pid_t pid);
 };
 
 #endif // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 8cb015c..c32ac2d 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -46,14 +46,25 @@
 { }
 
 void LogTimeEntry::startReader_Locked(void) {
+    pthread_attr_t attr;
+
     threadRunning = true;
-    if (pthread_create(&mThread, NULL, LogTimeEntry::threadStart, this)) {
-        threadRunning = false;
-        if (mClient) {
-            mClient->decRef();
+
+    if (!pthread_attr_init(&attr)) {
+        if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
+            if (!pthread_create(&mThread, &attr,
+                                LogTimeEntry::threadStart, this)) {
+                pthread_attr_destroy(&attr);
+                return;
+            }
         }
-        decRef_Locked();
+        pthread_attr_destroy(&attr);
     }
+    threadRunning = false;
+    if (mClient) {
+        mClient->decRef();
+    }
+    decRef_Locked();
 }
 
 void LogTimeEntry::threadStop(void *obj) {
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index 5f8173f..2c10861 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -49,7 +49,7 @@
 }
 
 PruneList::PruneList()
-        : mWorstUidEnabled(true) {
+        : mWorstUidEnabled(false) {
     mNaughty.clear();
     mNice.clear();
 }
diff --git a/logd/README.auditd b/logd/README.auditd
new file mode 100644
index 0000000..3f614a3
--- /dev/null
+++ b/logd/README.auditd
@@ -0,0 +1,17 @@
+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
+
+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.
diff --git a/logd/libaudit.c b/logd/libaudit.c
new file mode 100644
index 0000000..ca88d1b
--- /dev/null
+++ b/logd/libaudit.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2012, Samsung Telecommunications of America
+ * Copyright (C) 2014 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.
+ *
+ * Written by William Roberts <w.roberts@sta.samsung.com>
+ *
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#define LOG_TAG "libaudit"
+#include <log/log.h>
+
+#include "libaudit.h"
+
+/**
+ * Waits for an ack from the kernel
+ * @param fd
+ *  The netlink socket fd
+ * @param seq
+ *  The current sequence number were acking on
+ * @return
+ *  This function returns 0 on success, else -errno.
+ */
+static int get_ack(int fd, int16_t seq)
+{
+    int rc;
+    struct audit_message rep;
+
+    /* Sanity check, this is an internal interface this shouldn't happen */
+    if (fd < 0) {
+        return -EINVAL;
+    }
+
+    rc = audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, MSG_PEEK);
+    if (rc < 0) {
+        return rc;
+    }
+
+    if (rep.nlh.nlmsg_type == NLMSG_ERROR) {
+        audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0);
+        rc = ((struct nlmsgerr *)rep.data)->error;
+        if (rc) {
+            return -rc;
+        }
+    }
+
+    if ((int16_t)rep.nlh.nlmsg_seq != seq) {
+        SLOGW("Expected sequence number between user space and kernel space is out of skew, "
+          "expected %u got %u", seq, rep.nlh.nlmsg_seq);
+    }
+
+    return 0;
+}
+
+/**
+ *
+ * @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
+ *  This function returns a positive sequence number on success, else -errno.
+ */
+static int audit_send(int fd, int type, const void *data, size_t size)
+{
+    int rc;
+    static int16_t sequence = 0;
+    struct audit_message req;
+    struct sockaddr_nl addr;
+
+    memset(&req, 0, sizeof(req));
+    memset(&addr, 0, sizeof(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) {
+        return -EBADF;
+    }
+
+    /* Ensure the message is not too big */
+    if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
+        SLOGE("netlink message is too large");
+        return -EINVAL;
+    }
+
+    /* 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 */
+
+    rc = TEMP_FAILURE_RETRY(sendto(fd, &req, req.nlh.nlmsg_len, 0,
+                                   (struct sockaddr*) &addr, sizeof(addr)));
+
+    /* Not all the bytes were sent */
+    if (rc < 0) {
+        rc = -errno;
+        SLOGE("Error sending data over the netlink socket: %s", strerror(-errno));
+        goto out;
+    } else if ((uint32_t) rc != req.nlh.nlmsg_len) {
+        rc = -EPROTO;
+        goto out;
+    }
+
+    /* We sent all the bytes, get the ack */
+    rc = get_ack(fd, sequence);
+
+    /* If the ack failed, return the error, else return the sequence number */
+    rc = (rc == 0) ? (int) sequence : rc;
+
+out:
+    /* Don't let sequence roll to negative */
+    if (sequence < 0) {
+        SLOGW("Auditd to Kernel sequence number has rolled over");
+        sequence = 0;
+    }
+
+    return rc;
+}
+
+int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode)
+{
+    int rc;
+    struct audit_message rep;
+    struct audit_status status;
+
+    memset(&status, 0, sizeof(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) {
+        SLOGE("Could net set pid for audit events, error: %s", strerror(-rc));
+        return rc;
+    }
+
+    /*
+     * 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.
+         */
+        audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
+    }
+
+    return 0;
+}
+
+int audit_open()
+{
+    return socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
+}
+
+int audit_get_reply(int fd, struct audit_message *rep, reply_t block, int peek)
+{
+    ssize_t len;
+    int flags;
+    int rc = 0;
+
+    struct sockaddr_nl nladdr;
+    socklen_t nladdrlen = sizeof(nladdr);
+
+    if (fd < 0) {
+        return -EBADF;
+    }
+
+    /* 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.
+     */
+    len = TEMP_FAILURE_RETRY(recvfrom(fd, rep, sizeof(*rep), flags,
+                                      (struct sockaddr*) &nladdr, &nladdrlen));
+
+    /*
+     * EAGAIN should be re-tried until success or another error manifests.
+     */
+    if (len < 0) {
+        rc = -errno;
+        if (block == GET_REPLY_NONBLOCKING && rc == -EAGAIN) {
+            /* If request is non blocking and errno is EAGAIN, just return 0 */
+            return 0;
+        }
+        SLOGE("Error receiving from netlink socket, error: %s", strerror(-rc));
+        return rc;
+    }
+
+    if (nladdrlen != sizeof(nladdr)) {
+        SLOGE("Protocol fault, error: %s", strerror(EPROTO));
+        return -EPROTO;
+    }
+
+    /* Make sure the netlink message was not spoof'd */
+    if (nladdr.nl_pid) {
+        SLOGE("Invalid netlink pid received, expected 0 got: %d", nladdr.nl_pid);
+        return -EINVAL;
+    }
+
+    /* Check if the reply from the kernel was ok */
+    if (!NLMSG_OK(&rep->nlh, (size_t)len)) {
+        rc = (len == sizeof(*rep)) ? -EFBIG : -EBADE;
+        SLOGE("Bad kernel response %s", strerror(-rc));
+    }
+
+    return rc;
+}
+
+void audit_close(int fd)
+{
+    int rc = close(fd);
+    if (rc < 0) {
+        SLOGE("Attempting to close invalid fd %d, error: %s", fd, strerror(errno));
+    }
+    return;
+}
diff --git a/logd/libaudit.h b/logd/libaudit.h
new file mode 100644
index 0000000..cb114f9
--- /dev/null
+++ b/logd/libaudit.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012, Samsung Telecommunications of America
+ * Copyright (C) 2014 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.
+ *
+ * Written by William Roberts <w.roberts@sta.samsung.com>
+ */
+
+#ifndef _LIBAUDIT_H_
+#define _LIBAUDIT_H_
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <linux/netlink.h>
+#include <linux/audit.h>
+
+__BEGIN_DECLS
+
+#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;
+
+/* type == AUDIT_SIGNAL_INFO */
+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];
+};
+
+/**
+ * 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.
+ */
+extern int  audit_open(void);
+
+/**
+ * Closes the fd returned from audit_open()
+ * @param fd
+ *  The fd to close
+ */
+extern void audit_close(int fd);
+
+/**
+ *
+ * @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
+ *  This function returns 0 on success, else -errno.
+ */
+extern int  audit_get_reply(int fd, struct audit_message *rep, reply_t block,
+               int peek);
+
+/**
+ * Sets a pid to recieve audit netlink events from the kernel
+ * @param fd
+ *  The fd returned by a call to audit_open()
+ * @param pid
+ *  The pid whom to set as the reciever of audit messages
+ * @param wmode
+ *  Whether or not to block on the underlying socket io calls.
+ * @return
+ *  This function returns 0 on success, -errno on error.
+ */
+extern int  audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode);
+
+__END_DECLS
+
+#endif
diff --git a/logd/main.cpp b/logd/main.cpp
index 8792d32..7346e2f 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -34,6 +34,7 @@
 #include "CommandListener.h"
 #include "LogBuffer.h"
 #include "LogListener.h"
+#include "LogAudit.h"
 
 static int drop_privs() {
     struct sched_param param;
@@ -63,7 +64,10 @@
     capheader.pid = 0;
 
     capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
-    capdata[CAP_TO_INDEX(CAP_SYSLOG)].effective = CAP_TO_MASK(CAP_SYSLOG);
+    capdata[CAP_TO_INDEX(CAP_AUDIT_CONTROL)].permitted |= CAP_TO_MASK(CAP_AUDIT_CONTROL);
+
+    capdata[0].effective = capdata[0].permitted;
+    capdata[1].effective = capdata[1].permitted;
     capdata[0].inheritable = 0;
     capdata[1].inheritable = 0;
 
@@ -80,6 +84,13 @@
 // space logger.  Additional transitory per-client threads are created
 // for each reader once they register.
 int main() {
+    int fdDmesg = -1;
+    char dmesg[PROPERTY_VALUE_MAX];
+    property_get("logd.auditd.dmesg", dmesg, "1");
+    if (atol(dmesg)) {
+        fdDmesg = open("/dev/kmsg", O_WRONLY);
+    }
+
     if (drop_privs() != 0) {
         return -1;
     }
@@ -127,6 +138,17 @@
         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.
+
+    // failure is an option ... messages are in dmesg (required by standard)
+    LogAudit *al = new LogAudit(logBuf, reader, fdDmesg);
+    if (al->startListener()) {
+        delete al;
+        close(fdDmesg);
+    }
+
     pause();
     exit(0);
 }
diff --git a/toolbox/date.c b/toolbox/date.c
index d6c9052..aa3b72e 100644
--- a/toolbox/date.c
+++ b/toolbox/date.c
@@ -1,10 +1,13 @@
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <string.h>
-#include <errno.h>
 #include <time.h>
+#include <unistd.h>
+
 #include <linux/android_alarm.h>
 #include <linux/rtc.h>
 #include <sys/ioctl.h>
@@ -108,6 +111,33 @@
         settime_rtc_tm(&tm);
 }
 
+static char *parse_time(const char *str, struct timeval *ts) {
+  char *s;
+  long fs = 0; /* fractional seconds */
+
+  ts->tv_sec = strtoumax(str, &s, 10);
+
+  if (*s == '.') {
+    s++;
+    int count = 0;
+
+    /* read up to 6 digits (microseconds) */
+    while (*s && isdigit(*s)) {
+      if (++count < 7) {
+        fs = fs*10 + (*s - '0');
+      }
+      s++;
+    }
+
+    for (; count < 6; count++) {
+      fs *= 10;
+    }
+  }
+
+  ts->tv_usec = fs;
+  return s;
+}
+
 int date_main(int argc, char *argv[])
 {
 	int c;
@@ -181,7 +211,7 @@
         //strptime(argv[optind], NULL, &tm);
         //tv.tv_sec = mktime(&tm);
         //tv.tv_usec = 0;
-        strtotimeval(argv[optind], &tv);
+        parse_time(argv[optind], &tv);
         printf("time %s -> %lu.%lu\n", argv[optind], tv.tv_sec, tv.tv_usec);
         res = settime_alarm_timeval(&tv);
         if (res < 0)