On Fri, Sep 6, 2013 at 12:50 PM, Joshua Brindle
<[email protected]>wrote:

> 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
>
Dont like these hardcodes, can't we allow arbitrary sized lines?

> +
> +/* 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];
>
Dont like these hardcodes, can't we allow arbitrary amount of 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;
>
What if the line is bigger then what fgets got? Shouldn't we be growing a
buffer based on newline?

> +        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]
> the words "unsubscribe seandroid-list" without quotes as the message.
>



-- 
Respectfully,

William C Roberts

Reply via email to