diff options
Diffstat (limited to 'framework/src/audit/src/autrace.c')
-rw-r--r-- | framework/src/audit/src/autrace.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/framework/src/audit/src/autrace.c b/framework/src/audit/src/autrace.c new file mode 100644 index 00000000..03c0b556 --- /dev/null +++ b/framework/src/audit/src/autrace.c @@ -0,0 +1,329 @@ +/* autrace.c -- + * Copyright 2005-09,2011,2015 Red Hat Inc., Durham, North Carolina. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * Steve Grubb <sgrubb@redhat.com> + */ + +#include "config.h" +#include <stdio.h> +#include <string.h> +#include <sys/wait.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <time.h> +#include <linux/net.h> +#include "libaudit.h" +#include "private.h" + +/* + * This program will add the audit rules to trace a process similar + * to strace. It will then execute the process. + */ +static int threat = 0; +static int count_rules(void); +static int count_em(int fd); +extern int delete_all_rules(int fd); + +static void usage(void) +{ + fprintf(stderr, "usage: autrace [-r] program\n"); +} + +static int insert_rule(int audit_fd, const char *field) +{ + int rc; + int flags = AUDIT_FILTER_EXIT; + int action = AUDIT_ALWAYS; + struct audit_rule_data *rule = malloc(sizeof(struct audit_rule_data)); + int machine = audit_detect_machine(); + char *t_field = NULL; + + if (rule == NULL) + goto err; + memset(rule, 0, sizeof(struct audit_rule_data)); + if (threat) { + rc = 0; + if (machine != MACH_AARCH64) { + rc |= audit_rule_syscallbyname_data(rule, "open"); + rc |= audit_rule_syscallbyname_data(rule, "creat"); + rc |= audit_rule_syscallbyname_data(rule, "rename"); + rc |= audit_rule_syscallbyname_data(rule, "unlink"); + rc |= audit_rule_syscallbyname_data(rule, "mknod"); + rc |= audit_rule_syscallbyname_data(rule, "mkdir"); + rc |= audit_rule_syscallbyname_data(rule, "rmdir"); + rc |= audit_rule_syscallbyname_data(rule, "chown"); + rc |= audit_rule_syscallbyname_data(rule, "lchown"); + rc |= audit_rule_syscallbyname_data(rule, "chmod"); + rc |= audit_rule_syscallbyname_data(rule, "link"); + rc |= audit_rule_syscallbyname_data(rule, "symlink"); + rc |= audit_rule_syscallbyname_data(rule, "readlink"); + } + rc |= audit_rule_syscallbyname_data(rule, "openat"); + rc |= audit_rule_syscallbyname_data(rule, "truncate"); + rc |= audit_rule_syscallbyname_data(rule, "renameat"); + rc |= audit_rule_syscallbyname_data(rule, "unlinkat"); + rc |= audit_rule_syscallbyname_data(rule, "mknodat"); + rc |= audit_rule_syscallbyname_data(rule, "mkdirat"); + rc |= audit_rule_syscallbyname_data(rule, "chdir"); + rc |= audit_rule_syscallbyname_data(rule, "fchownat"); + rc |= audit_rule_syscallbyname_data(rule, "fchmodat"); + rc |= audit_rule_syscallbyname_data(rule, "linkat"); + rc |= audit_rule_syscallbyname_data(rule, "symlinkat"); + rc |= audit_rule_syscallbyname_data(rule, "readlinkat"); + rc |= audit_rule_syscallbyname_data(rule, "execve"); + rc |= audit_rule_syscallbyname_data(rule, "name_to_handle_at"); + + if (machine != MACH_X86 && machine != MACH_S390X && + machine != MACH_S390) { + rc |= audit_rule_syscallbyname_data(rule, "connect"); + rc |= audit_rule_syscallbyname_data(rule, "bind"); + rc |= audit_rule_syscallbyname_data(rule, "accept"); + rc |= audit_rule_syscallbyname_data(rule, "sendto"); + rc |= audit_rule_syscallbyname_data(rule, "recvfrom"); + rc |= audit_rule_syscallbyname_data(rule, "accept4"); + } + + rc |= audit_rule_syscallbyname_data(rule, "sendfile"); + } else + rc = audit_rule_syscallbyname_data(rule, "all"); + if (rc < 0) + goto err; + t_field = strdup(field); + rc = audit_rule_fieldpair_data(&rule, t_field, flags); + free(t_field); + if (rc < 0) + goto err; + rc = audit_add_rule_data(audit_fd, rule, flags, action); + if (rc < 0) + goto err; + + // Now if i386, lets add its network rules + if (machine == MACH_X86 || machine == MACH_S390X || + machine == MACH_S390) { + int i, a0[6] = { SYS_CONNECT, SYS_BIND, SYS_ACCEPT, SYS_SENDTO, + SYS_RECVFROM, SYS_ACCEPT4 }; + for (i=0; i<6; i++) { + char pair[32]; + + memset(rule, 0, sizeof(struct audit_rule_data)); + rc |= audit_rule_syscallbyname_data(rule, "socketcall"); + snprintf(pair, sizeof(pair), "a0=%d", a0[i]); + rc |= audit_rule_fieldpair_data(&rule, pair, flags); + t_field = strdup(field); + rc |= audit_rule_fieldpair_data(&rule, t_field, flags); + free(t_field); + rc |= audit_add_rule_data(audit_fd, rule, flags, action); + } + } + free(rule); + return 0; +err: + fprintf(stderr, "Error inserting audit rule for %s\n", field); + free(rule); + return 1; +} + +int key_match(struct audit_reply *rep) +{ + return 1; +} + +/* + * Algorithm: + * check that user is root + * check to see if program exists + * if so fork, child waits for parent + * parent clears audit rules, loads audit all syscalls with child's pid + * parent tells child to go & waits for sigchld + * child exec's program + * parent deletes rules after getting sigchld + */ +int main(int argc, char *argv[]) +{ + int fd[2]; + int pid,cmd=1; + char buf[2]; + + if (argc < 2) { + usage(); + return 1; + } + if (strcmp(argv[cmd], "-h") == 0) { + usage(); + return 1; + } + if (strcmp(argv[cmd], "-r") == 0) { + threat = 1; + cmd++; + } + if (getuid() != 0) { + fprintf(stderr, "You must be root to run this program.\n"); + return 1; + } + if (access(argv[cmd], X_OK)) { + if (errno == ENOENT) + fprintf(stderr, "Error - can't find: %s\n", argv[cmd]); + else + fprintf(stderr, "Error checking %s (%s)\n", + argv[cmd], strerror(errno)); + return 1; + } + set_aumessage_mode(MSG_STDERR, DBG_NO); + switch (count_rules()) + { + case -1: + if (errno == ECONNREFUSED) + fprintf(stderr, + "The audit system is disabled\n"); + else + fprintf(stderr, + "Error - can't get rule count.\n"); + return 1; + case 0: + break; + default: + fprintf(stderr, + "autrace cannot be run with rules loaded.\n" + "Please delete all rules using 'auditctl -D' if you " + "really wanted to\nrun this command.\n"); + return 1; + } + if (pipe(fd) != 0) { + fprintf(stderr, "Error creating pipe.\n"); + return 1; + } + + switch ((pid=fork())) + { + case -1: + fprintf(stderr, "Error forking.\n"); + return 1; + case 0: /* Child */ + close(fd[1]); + printf("Waiting to execute: %s\n", argv[cmd]); + while (read(fd[0], buf, 1) == -1 && errno == EINTR) + /* blank */ ; + close(fd[0]); + execvp(argv[cmd], &argv[cmd]); + fprintf(stderr, "Failed to exec %s\n", argv[cmd]); + return 1; + default: /* Parent */ + close(fd[0]); + fcntl(fd[1], F_SETFD, FD_CLOEXEC); + { + char field[16]; + int audit_fd; + audit_fd = audit_open(); + if (audit_fd < 0) + exit(1); + snprintf(field, sizeof(field), "pid=%d", pid); + if (insert_rule(audit_fd, field)) { + kill(pid,SIGTERM); + (void)delete_all_rules(audit_fd); + exit(1); + } + snprintf(field, sizeof(field), "ppid=%d", pid); + if (insert_rule(audit_fd, field)) { + kill(pid,SIGTERM); + (void)delete_all_rules(audit_fd); + exit(1); + } + sleep(1); + if (write(fd[1],"1", 1) != 1) { + kill(pid,SIGTERM); + (void)delete_all_rules(audit_fd); + exit(1); + } + waitpid(pid, NULL, 0); + close(fd[1]); + puts("Cleaning up..."); + (void)delete_all_rules(audit_fd); + close(audit_fd); + } + printf("Trace complete. " + "You can locate the records with " + "\'ausearch -i -p %d\'\n", + pid); + break; + } + + return 0; +} + +static int count_rules(void) +{ + int fd, total, rc; + + fd = audit_open(); + if (fd < 0) + return -1; + + rc = audit_request_rules_list_data(fd); + if (rc > 0) + total = count_em(fd); + else + total = -1; + + close(fd); + return total; +} + +static int count_em(int fd) +{ + int i, retval, count = 0; + int timeout = 40; /* loop has delay of .1 - this is 4 seconds */ + struct audit_reply rep; + fd_set read_mask; + + FD_ZERO(&read_mask); + FD_SET(fd, &read_mask); + + for (i = 0; i < timeout; i++) { + retval = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0); + if (retval > 0) { + struct timeval t; + + if (rep.type == NLMSG_ERROR && + rep.error->error == 0) + continue; + t.tv_sec = 0; + t.tv_usec = 100000; /* .1 second */ + do { + retval=select(fd+1, &read_mask, NULL, NULL, &t); + } while (retval < 0 && errno == EINTR); + switch (rep.type) + { + case NLMSG_DONE: + return count; + case AUDIT_LIST_RULES: + i = 0; + count++; + break; + case NLMSG_ERROR: + return -1; + default: + break; + } + } + } + return count; +} + |