Hi Steve, I am Logeswari working for HP.
We want to know audit performance impact on RHEL and Suse linux to help us evaluate linux audit as data source for our host based IDS. When we ran our own performance test with a test audispd plugin, we found if a system can perform 200000 open/close system calls per second without auditing, system can perform only 3000 open/close system calls auditing is enabled for open/close system call which is a HUGE impact on the system performance. It would be great if anyone can help us answering the following questions. 1) Is this performance impact expected? If yes, what is the reason behind it and can we fix it? 2) Have anyone done any benchmarking for performance impact? If yes, can you please share the numbers and also the steps/programs used the run the same. 3) Help us validating the performance test we have done in our test setup using the steps mentioned along with the results attached. Attached test program (loader.c) to invoke open and close system calls. Attached idskerndsp is the audispd plugin program. We used time command to determine how much time the system took to complete 50000 open/close system calls without (results attached Without-auditing) and with auditing enabled on the system (With-auditing-NOLOG-audispd-plugin and With-auditing-RAW) System details: 1 CPU machine OS Version RHEL 6.5 Kernel Version uname -r 2.6.32-431.el6.x86_64 Note: auditd was occupying 35% of CPU and was sleeping for most of the time whereas kauditd was occupying 20% of the CPU. Thanks & Regards, Logeswari.
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> void create_load(int iters); int high_rate = 0; int num_iters = 50000; int fd1; char file1[50]; /* Purpose: To create system load by invoking system calls used by templates. * * Note: The unlink(2) of a file can be an expensive operation (i.e., event * rate goes way down). * Note: Needs to be run as a non-ids user since IDDS is typically configured * to not audit ids. Some system calls below require you to run as root. */ main(int argc, char **argv) { int num_children; int iters; int i; char c; struct passwd *passwd_entry; while ((c = getopt(argc, argv, "hi:")) != -1) { switch (c) { case 'h': /* * Desire "high" event rate */ high_rate = 1; argc--; break; case 'i': /* * Desire a specified number of iterations */ num_iters = atoi(optarg); argc--; break; default: fprintf(stderr,"Unknown option: %c\n",optarg); exit(1); } } if(argv[optind] != NULL) { num_children = atoi(argv[optind]); } else { num_children = 4; } num_children = 1; /* fork child processes, if any requested */ for(i=1; i < num_children; i++) { if(fork() == 0) { printf("child pid: %d\n",getpid()); /* Setup file names based on child's pid */ //sprintf(file1,"./file1_%d",getpid()); /* each child creates load */ iters=0; if (num_iters == -1) { while(1) { create_load(iters); iters++; if( (iters % 1000) == 0) { printf("pid %d iteration %d\n",getpid(),iters); } } } else { while(iters < num_iters) { create_load(iters); iters++; if( (iters % 1000) == 0) { printf("pid %d iteration %d\n",getpid(),iters); } } } } } /* Parent creates load also */ printf("parent pid: %d\n",getpid()); /* Setup file names based on parent's pid */ //sprintf(file1,"./file1_%d",getpid()); iters=0; if (num_iters == -1) { while(1) { create_load(iters); iters++; if( (iters % 1000) == 0) { printf("pid %d iteration %d\n",getpid(),iters); } } } else { while(iters < num_iters) { create_load(iters); iters++; if( (iters % 1000) == 0) { printf("pid %d iteration %d\n",getpid(),iters); } } } } /* main */ void create_load(int iters) { int pid; char *args[2]; struct stat stat_buf; fd1 = open("file1", O_RDWR, 0777); if (fd1 == -1) { fprintf(stderr,"pid %d: open() returned error, errno=%d(%s)\n", getpid(),errno,strerror(errno)); exit(1); } if (close(fd1) == -1) { fprintf(stderr,"pid %d: close() returned error, errno=%d(%s)\n", getpid(),errno,strerror(errno)); exit(1); } /*if (chown("file1",0,0) == -1) { fprintf(stderr,"pid %d: chown(%d,%d) returned error, errno=%d(%s)\n", getpid(),0,0,errno,strerror(errno)); exit(1); } pid = fork(); if(pid == 0) { fprintf(stderr,"child pid %d: fork!\n",getpid()); args[0] = "/bin/ls"; args[1] = NULL; close(1); close(2); execve(args[0], args, NULL); fprintf(stderr,"pid %d: execve(%s) returned error, errno=%d(%s)\n", getpid(),args[0],errno,strerror(errno)); _exit(1); } else if (pid < 0) { fprintf(stderr,"pid %d: fork() returned error, errno=%d(%s)\n", getpid(),errno,strerror(errno)); exit(1); } else { fprintf(stderr,"parent pid %d, child pid: %d: fork!\n",getpid(),pid); } pid = vfork(); if(pid == 0) { args[0] = "/bin/pwd"; args[1] = NULL; close(1); close(2); execv(args[0], args); fprintf(stderr,"pid %d: execve(%s) returned error, errno=%d(%s)\n", getpid(),args[0],errno,strerror(errno)); _exit(1); } else if (pid < 0) { fprintf(stderr,"pid %d: vfork() returned error, errno=%d(%s)\n", getpid(),errno,strerror(errno)); exit(1); }*/ return; } /* create_load() */
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <syslog.h> #include <string.h> #include <ctype.h> #include <pwd.h> #include <sys/stat.h> #include <sys/select.h> #include <errno.h> #include "libaudit.h" #include "auparse.h" /* Global Data */ static auparse_state_t *au = NULL; /* Local declarations */ static void handle_event(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data); int main(int argc, char *argv[]) { char tmp[MAX_AUDIT_MESSAGE_LENGTH+1]; /* Initialize the auparse library */ au = auparse_init(AUSOURCE_FEED, 0); if (au == NULL) { return -1; } auparse_add_callback(au, handle_event, NULL, NULL); do { fd_set read_mask; struct timeval tv; int retval; do { tv.tv_sec = 5; tv.tv_usec = 0; FD_ZERO(&read_mask); FD_SET(0, &read_mask); retval= select(1, &read_mask, NULL, NULL, &tv); } while (retval == -1 && errno == EINTR); /* Now the event loop */ if (retval > 0) { if (fgets_unlocked(tmp, MAX_AUDIT_MESSAGE_LENGTH, stdin)){ auparse_feed(au, tmp, strnlen(tmp, MAX_AUDIT_MESSAGE_LENGTH)); } } else if (retval == 0) auparse_flush_feed(au); if (feof(stdin)) break; } while (1); /* Flush any accumulated events from queue */ auparse_flush_feed(au); auparse_destroy(au); return 0; } static void handle_event(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data) { return; }
Audit Status # auditctl -s AUDIT_STATUS: enabled=0 flag=1 pid=20358 rate_limit=0 backlog_limit=320 lost=0 backlog=0 Without auditing enabled, time taken is real 0m0.252s user 0m0.018s sys 0m0.215s
audispd-plugin configuration # cat /etc/audisp/plugins.d/idskerndsp.conf active = yes direction = out path = /ux/ids/idskerndsp type = always args = --test format = string Rules Configured # auditctl -l LIST_RULES: exit,always syscall=open,close Audit Status # auditctl -s AUDIT_STATUS: enabled=1 flag=1 pid=20358 rate_limit=0 backlog_limit=320 lost=0 backlog=0 With log_format = NOLOG, above rule enabled for auditing, time taken is real 0m16.849s user 0m0.045s sys 0m3.838s
We tried to disable the plugin i.e. idskerndsp and restarted auditd process to log the audit events to disk. audispd-plugin configuration # cat /etc/audisp/plugins.d/idskerndsp.conf active = no direction = out path = /ux/ids/idskerndsp type = always args = --test format = string Rules Configured # auditctl -l LIST_RULES: exit,always syscall=open,close Audit Status # auditctl -s AUDIT_STATUS: enabled=1 flag=1 pid=20819 rate_limit=0 backlog_limit=320 lost=0 backlog=0 With log_format = RAW, above rule enabled for auditing, time taken is real 2m41.484s user 0m0.028s sys 0m8.789s
-- Linux-audit mailing list Linux-audit@redhat.com https://www.redhat.com/mailman/listinfo/linux-audit