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
