Add libaudit support for adding directory watch rules.

Add rule parsing support to auditd.

Rule format matches auditctl. Currently only supports -w and -e.

Change-Id: I8bdaea1b5e2a216eec79cd8c9dae583de8295d26

Signed-off-by: Joshua Brindle <[email protected]>
---
 auditd/Android.mk    |    3 +-
 auditd/audit_log.c   |    2 +-
 auditd/audit_rules.c |  145 ++++++++++++++++++++++++++++++++++++++++++++++++++
 auditd/audit_rules.h |   24 +++++++++
 auditd/auditd.c      |    7 +++
 auditd/libaudit.c    |   75 +++++++++++++++++++++++++-
 auditd/libaudit.h    |   52 ++++++++++++++++++
 7 files changed, 305 insertions(+), 3 deletions(-)
 create mode 100644 auditd/audit_rules.c
 create mode 100644 auditd/audit_rules.h

diff --git a/auditd/Android.mk b/auditd/Android.mk
index c29319a..a53b72f 100644
--- a/auditd/Android.mk
+++ b/auditd/Android.mk
@@ -11,7 +11,8 @@ AUDITD_MAX_LOG_FILE_SIZEKB ?= 100
 LOCAL_SRC_FILES:= \
        auditd.c \
        libaudit.c \
-       audit_log.c
+       audit_log.c \
+       audit_rules.c
 
 LOCAL_SHARED_LIBRARIES := \
        libcutils \
diff --git a/auditd/audit_log.c b/auditd/audit_log.c
index ef77a3f..fc50caf 100644
--- a/auditd/audit_log.c
+++ b/auditd/audit_log.c
@@ -44,7 +44,7 @@
 /* Mode for fopen */
 #define AUDIT_LOG_FMODE "w+"
 /* mode for fchmod*/
-#define AUDIT_LOG_MODE  (S_IRUSR | S_IWUSR | S_IRGRP)
+#define AUDIT_LOG_MODE  (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
 /* flags for fcntl */
 #define AUDIT_LOG_FLAGS (O_RDWR | O_CREAT | O_SYNC)
 
diff --git a/auditd/audit_rules.c b/auditd/audit_rules.c
new file mode 100644
index 0000000..9e132a9
--- /dev/null
+++ b/auditd/audit_rules.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2013, Quark Security Inc
+ *
+ * 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 Joshua Brindle <[email protected]>
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#define LOG_TAG "audit_rules"
+#include <cutils/log.h>
+
+#include "libaudit.h"
+
+#define LINE_LEN 255
+
+/* Reevaluate this number when support for more commands are added */
+#define MAX_OPTIONS 15
+
+static int audit_rules_parse_and_add(int audit_fd, char *line)
+{
+    char *argv[MAX_OPTIONS];
+    int argc;
+    int rc = 0, added_rule = 0;
+    char p;
+    int o;
+    size_t len;
+    struct audit_rule_data *rule;
+
+    /* Strip crlf */
+    line[strlen(line) -1] = '\0';
+
+    argv[0] = "auditd";
+
+    for (argc=1; argc < MAX_OPTIONS; argc++) {
+        argv[argc] = strsep(&line, " ");
+        if (argv[argc] == NULL)
+            break;
+    }
+
+    optind = 0;
+
+    while ((o = getopt(argc, argv, "w:e:p:")) != -1) {
+        switch(o) {
+        case 'w':
+            if (audit_add_dir(&rule, optarg)) {
+                SLOGE("Error adding rule");
+                return -1;
+            }
+            added_rule = 1;
+            break;
+        case 'e':
+            if (audit_set_enabled(audit_fd, strtoul(optarg, NULL, 10)))
+                return -1;
+            break;
+        case 'p':
+            if (added_rule == 0) {
+                SLOGE("Specify rule type before permissions");
+                return -1;
+            }
+            uint32_t perms = 0;
+            for (len=0; len < strlen(optarg); len++) {
+                 switch(optarg[len]) {
+                 case 'w':
+                     perms |= AUDIT_PERM_WRITE;
+                     break;
+                 case 'e':
+                     perms |= AUDIT_PERM_EXEC;
+                     break;
+                 case 'r':
+                     perms |= AUDIT_PERM_READ;
+                     break;
+                 case 'a':
+                     perms |= AUDIT_PERM_ATTR;
+                     break;
+                 default:
+                     SLOGE("Unknown permission %c", optarg[len]);
+                     break;
+                 }
+            }
+            if (audit_update_watch_perms(rule, perms)) {
+                SLOGE("Could not set perms on rule");
+                return -1;
+            }
+            break;
+        case '?':
+            SLOGE("Unsupported option: %c", optopt);
+            break;
+        }
+    }
+
+    if (added_rule) {
+        rc = audit_send(audit_fd, AUDIT_ADD_RULE, rule, sizeof(*rule) + 
rule->buflen);
+        free(rule);
+    }
+
+    return rc;
+}
+
+int audit_rules_read_and_add(int audit_fd, const char *rulefile)
+{
+    int rc;
+    struct stat s;
+    char line[LINE_LEN];
+    FILE *rules;
+
+    rc = stat(rulefile, &s);
+    if (rc < 0) {
+        SLOGE("Could not read audit rules %s: %s", rulefile, strerror(errno));
+        return 0;
+    }
+
+    rules = fopen(rulefile, "r");
+    if (rules == NULL) {
+        return -1;
+    }
+
+    while (fgets(line, sizeof(line), rules)) {
+        SLOGE(line);
+        if (line[0] != '-')
+            continue;
+        if (audit_rules_parse_and_add(audit_fd, line) < 0) {
+           SLOGE("Could not read audit rules");
+           return -1;
+        }
+    }
+
+    fclose(rules);
+    return 0;
+}
diff --git a/auditd/audit_rules.h b/auditd/audit_rules.h
new file mode 100644
index 0000000..16a617e
--- /dev/null
+++ b/auditd/audit_rules.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2013, Quark Security Inc
+ *
+ * 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 Joshua Brindle <[email protected]>
+ */
+
+#ifndef _AUDIT_RULES_H_
+#define _AUDIT_RULES_H_
+
+extern int audit_rules_read_and_add(int audit_fd, const char *rulefile);
+
+#endif
diff --git a/auditd/auditd.c b/auditd/auditd.c
index 65ec855..875eed0 100644
--- a/auditd/auditd.c
+++ b/auditd/auditd.c
@@ -46,6 +46,7 @@
 
 #include "libaudit.h"
 #include "audit_log.h"
+#include "audit_rules.h"
 
 /*
  * TODO:
@@ -61,6 +62,8 @@
 #define AUDITD_LOG_FILE AUDITD_LOG_DIR "/audit.log"
 #define AUDITD_OLD_LOG_FILE AUDITD_LOG_DIR "/audit.old"
 
+#define AUDITD_RULES_FILE "/data/misc/audit/audit.rules"
+
 #define AUDITD_MAX_LOG_FILE_SIZE (1024 * AUDITD_MAX_LOG_FILE_SIZEKB)
 
 static volatile int quit = 0;
@@ -189,6 +192,10 @@ int main(int argc, char *argv[])
         goto err;
     }
 
+    if (audit_rules_read_and_add(audit_fd, AUDITD_RULES_FILE)) {
+        SLOGE("error reading audit rules: %s", strerror(errno));
+    }
+
     pfds.fd = audit_fd;
     pfds.events = POLLIN;
 
diff --git a/auditd/libaudit.c b/auditd/libaudit.c
index 06e5557..0f40be4 100644
--- a/auditd/libaudit.c
+++ b/auditd/libaudit.c
@@ -137,7 +137,7 @@ static int get_ack(int fd, int16_t seq)
  * @return
  *  This function returns a positive sequence number on success, else -errno.
  */
-static int audit_send(int fd, int type, const void *data, unsigned int size)
+int audit_send(int fd, int type, const void *data, unsigned int size)
 {
     int rc;
     static int16_t sequence = 0;
@@ -220,6 +220,79 @@ out:
     return rc;
 }
 
+int audit_update_watch_perms(struct audit_rule_data *rule, int perms)
+{
+    uint32_t i;
+
+    if (rule == NULL)
+         return -1;
+
+    for (i = 0; i < rule->field_count; i++) {
+        if (rule->fields[i] == AUDIT_PERM) {
+            rule->values[i] = perms;
+            break;
+        }
+    }
+
+    if (rule->fields[i] == AUDIT_PERM)
+        return 0;
+
+    if (rule->field_count > AUDIT_MAX_FIELDS)
+        return -2;
+
+    rule->fields[rule->field_count] = AUDIT_PERM;
+    rule->fieldflags[rule->field_count] = AUDIT_EQUAL;
+    rule->values[rule->field_count] = perms;
+    rule->field_count++;
+
+    return 0;
+}
+
+int audit_add_dir(struct audit_rule_data **rulep, const char *path)
+{
+    int len = strlen(path);
+    struct audit_rule_data *rule;
+    *rulep = calloc(1, sizeof(*rule) + len);
+    rule = *rulep;
+    if (!rule) {
+        SLOGE("Out of memory");
+        return -1;
+    }
+
+    rule->flags = AUDIT_FILTER_EXIT;
+    rule->action = AUDIT_ALWAYS;
+    rule->field_count = 2;
+
+    rule->mask[0] = ~0;
+    rule->fields[0] = AUDIT_DIR;
+    rule->fieldflags[0] = AUDIT_EQUAL;
+    rule->values[0] = len;
+
+    rule->mask[1] = ~0;
+    rule->fields[1] = AUDIT_PERM;
+    rule->fieldflags[1] = AUDIT_EQUAL;
+    rule->values[1] = AUDIT_PERM_READ | AUDIT_PERM_WRITE |
+                      AUDIT_PERM_EXEC | AUDIT_PERM_ATTR;
+
+    rule->buflen = len;
+    memcpy(&rule->buf[0], path, len);
+
+    return 0;
+}
+
+int audit_set_enabled(int fd, uint32_t state)
+{
+       if (state > AUDIT_LOCKED)
+               return -1;
+
+       struct audit_status s;
+       memset(&s, 0, sizeof(s));
+       s.mask = AUDIT_STATUS_ENABLED;
+       s.enabled = state;
+
+       return audit_send(fd, AUDIT_SET, &s, sizeof(s));
+}
+
 int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode)
 {
     int rc;
diff --git a/auditd/libaudit.h b/auditd/libaudit.h
index fbaa7b9..bc21807 100644
--- a/auditd/libaudit.h
+++ b/auditd/libaudit.h
@@ -27,6 +27,10 @@
 
 #define MAX_AUDIT_MESSAGE_LENGTH    8970
 
+#define AUDIT_OFF       0
+#define AUDIT_ON        1
+#define AUDIT_LOCKED    2
+
 typedef enum {
     GET_REPLY_BLOCKING=0,
     GET_REPLY_NONBLOCKING
@@ -108,4 +112,52 @@ extern int  audit_get_reply(int fd, struct audit_reply 
*rep, reply_t block,
  */
 extern int  audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode);
 
+/**
+ * sends a command to the audit netlink socket
+ * @param fd
+ *  The fd returned by a call to audit_open()
+ * @param type
+ *  message type, see audit.h in the kernel
+ * @param data
+ *  opaque data pointer
+ * @param size
+ *  size of data in *data
+ * @return
+ *  This function returns 0 on success, -errno on error.
+ */
+extern int  audit_send(int fd, int type, const void *data, unsigned int size);
+
+/**
+ * allocates a rule and adds a directory to watch, defaults to all permissions
+ * @param rulep
+ *  pointer to pointer of an unallocated audit_rule_data, will be allocated, 
must be freed
+ * @param path
+ *  path to add to the rule
+ * @return
+ *  This function returns 0 on success, -errno on error.
+ */
+extern int  audit_add_dir(struct audit_rule_data **rulep, const char *path);
+
+/**
+ * sets enabled flag, 0 for audit off, 1 for audit on, 2 for audit locked
+ * @param fd
+ *  file descripter returned by audit_open()
+ * @param state
+ *  0 for audit off, 1 for audit on, 2 for audit locked
+ * @return
+ *  This function returns 0 on success, -errno on error, -1 if already locked
+ */
+extern int  audit_set_enabled(int fd, uint32_t state);
+
+/**
+ * Sets permissions for an already allocated watch rule
+ * @param rule
+ *  rule to set permissions on
+ * @param perms
+ *  permissions to set, AUDIT_PERM_{READ,WRITE,EXEC,ATTR}
+ * @return
+ *  This function returns 0 on success, -1 if rule is NULL and -2 if there are 
too many fields
+ */
+extern int  audit_update_watch_perms(struct audit_rule_data *rule, int perms);
+
 #endif
-- 
1.7.9.5


--
This message was distributed to subscribers of the seandroid-list mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe seandroid-list" without quotes as the message.

Reply via email to