diff -urN linux-2.0.31pre9-privs-clean/Documentation/Configure.help linux-2.0.31pre9-privs/Documentation/Configure.help --- linux-2.0.31pre9-privs-clean/Documentation/Configure.help Wed Sep 10 15:05:33 1997 +++ linux-2.0.31pre9-privs/Documentation/Configure.help Sun Sep 14 15:00:30 1997 @@ -830,6 +830,24 @@ than all being tied to UID zero. This completely changes the way a Unix system works; say N unless you really know what you are doing. +POSIX.6 auditing +CONFIG_POSIX6_AUDIT + This option turns on kernel level auditing. Every time a user process + makes a system call that performs some function that may impact on the + security of the system, the kernel may choose to log information about + the event. The kernel maintains an internal circular buffer for such + data which must be drained periodically or the kernel will grind to a + halt. The internal buffer is not very large so unless you are sure + that something is going to drain it, just say NO. + +Auditing optimized for speed not verifiability +CONFIG_POSIX6_AUDIT_MAXSPEED + This option makes the kernel check if an event is likely to be audited + before constructing an audit record for it. You should only disable + this option if you want to centralize control over which events get + logged. (Mainly for the purposes of verifiability). It is safe to + say YES here. + Default security level DEFAULT_SECURE_LEVEL This is a potentially dangerous number to change. The default is diff -urN linux-2.0.31pre9-privs-clean/Makefile linux-2.0.31pre9-privs/Makefile --- linux-2.0.31pre9-privs-clean/Makefile Wed Sep 10 15:04:45 1997 +++ linux-2.0.31pre9-privs/Makefile Sat Sep 13 17:52:18 1997 @@ -164,7 +164,7 @@ endif -Version: dummy +Version: dummy @rm -f include/linux/compile.h boot: vmlinux @@ -202,6 +202,9 @@ $(TOPDIR)/include/linux/version.h: include/linux/version.h $(TOPDIR)/include/linux/compile.h: include/linux/compile.h +include/asm-$(ARCH)/audit_aet.h: include/asm-$(ARCH)/unistd.h + scripts/mkaudit_aet_h + newversion: @if [ ! -f .version ]; then \ echo 1 > .version; \ @@ -228,7 +231,7 @@ @echo \#define LINUX_COMPILER \"`$(CC) -v 2>&1 | tail -1`\" >> .ver @mv -f .ver $@ -include/linux/version.h: ./Makefile +include/linux/version.h: ./Makefile include/asm-$(ARCH)/audit_aet.h @echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > .ver @echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver @mv -f .ver $@ @@ -317,6 +320,7 @@ rm -f submenu* mrproper: clean + rm -f include/asm-$(ARCH)/audit_aet.h rm -f include/linux/autoconf.h include/linux/version.h rm -f drivers/sound/local.h drivers/sound/.defines rm -f drivers/char/uni_hash.tbl drivers/char/conmakehash diff -urN linux-2.0.31pre9-privs-clean/arch/i386/config.in linux-2.0.31pre9-privs/arch/i386/config.in --- linux-2.0.31pre9-privs-clean/arch/i386/config.in Wed Sep 10 15:05:33 1997 +++ linux-2.0.31pre9-privs/arch/i386/config.in Sun Sep 14 14:38:34 1997 @@ -40,7 +40,11 @@ bool ' Autodetect GCC trampolines' CONFIG_STACKEXEC_AUTOENABLE bool ' Log buffer overflow exploit attempts' CONFIG_STACKEXEC_LOG fi - bool 'POSIX.6 (aka. .1e) capability system (experimental)' CONFIG_POSIX6_CAP + bool 'POSIX.6 (.1e v15) capability system (experimental)' CONFIG_POSIX6_CAP + bool 'POSIX.6 (.1e v15) auditing (experimental)' CONFIG_POSIX6_AUDIT + if [ "$CONFIG_POSIX6_AUDIT" = "y" ]; then + bool ' Optimize audit for speed not verifiability' CONFIG_POSIX6_AUDIT_MAXSPEED + fi fi int 'Default security level - see help' DEFAULT_SECURE_LEVEL 0 bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF diff -urN linux-2.0.31pre9-privs-clean/arch/i386/defconfig linux-2.0.31pre9-privs/arch/i386/defconfig --- linux-2.0.31pre9-privs-clean/arch/i386/defconfig Wed Sep 10 15:05:33 1997 +++ linux-2.0.31pre9-privs/arch/i386/defconfig Sun Sep 14 15:05:58 1997 @@ -33,6 +33,8 @@ CONFIG_M586=y # CONFIG_M686 is not set # CONFIG_POSIX6_CAP is not set +# CONFIG_POSIX6_AUDIT is not set +CONFIG_POSIX6_AUDIT_MAXSPEED=y DEFAULT_SECURE_LEVEL=0 # diff -urN linux-2.0.31pre9-privs-clean/arch/i386/kernel/entry.S linux-2.0.31pre9-privs/arch/i386/kernel/entry.S --- linux-2.0.31pre9-privs-clean/arch/i386/kernel/entry.S Wed Sep 10 15:05:33 1997 +++ linux-2.0.31pre9-privs/arch/i386/kernel/entry.S Fri Sep 12 06:39:44 1997 @@ -710,4 +710,7 @@ .long SYMBOL_NAME(sys_getfilecap) .long SYMBOL_NAME(sys_fsetfilecap) .long SYMBOL_NAME(sys_fgetfilecap) /* 175 */ - .space (NR_syscalls-175)*4 + .long SYMBOL_NAME(sys_auditor) + .long SYMBOL_NAME(sys_auditswitch) + .long SYMBOL_NAME(sys_auditwrite) + .space (NR_syscalls-178)*4 diff -urN linux-2.0.31pre9-privs-clean/arch/i386/kernel/process.c linux-2.0.31pre9-privs/arch/i386/kernel/process.c --- linux-2.0.31pre9-privs-clean/arch/i386/kernel/process.c Tue Oct 29 17:42:40 1996 +++ linux-2.0.31pre9-privs/arch/i386/kernel/process.c Sat Sep 13 19:29:20 1997 @@ -11,6 +11,7 @@ #define __KERNEL_SYSCALLS__ #include +#include #include #include #include @@ -550,7 +551,26 @@ asmlinkage int sys_fork(struct pt_regs regs) { - return do_fork(SIGCHLD, regs.esp, ®s); + int retval; + int audit_mask = AUDIT_EVENT_CLASS_PROGRESS|AUDIT_EVENT_CLASS_PROC; + + retval = do_fork(SIGCHLD, regs.esp, ®s); + audit_mask |= retval <= 0 ? + AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS; + + /* audit this attempt */ + _Audit_if_want_event(current,audit_mask) { + int result; + + _Audit_begin(2*sizeof(int)); + _Audit_append_simple(int, AUD_AET_FORK); + _Audit_append_simple(int, retval); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK, audit_mask, &result) { + panic("failed audit fork (%d)", current->pid); + } + } + + return retval; } asmlinkage int sys_clone(struct pt_regs regs) diff -urN linux-2.0.31pre9-privs-clean/arch/i386/kernel/sys_i386.c linux-2.0.31pre9-privs/arch/i386/kernel/sys_i386.c --- linux-2.0.31pre9-privs-clean/arch/i386/kernel/sys_i386.c Thu Apr 11 23:49:30 1996 +++ linux-2.0.31pre9-privs/arch/i386/kernel/sys_i386.c Sun Sep 14 11:40:54 1997 @@ -6,6 +6,7 @@ * platform. */ +#include #include #include #include @@ -23,18 +24,32 @@ */ asmlinkage int sys_pipe(unsigned long * fildes) { + __u32 audit_mask = AUDIT_EVENT_CLASS_FILE|AUDIT_EVENT_CLASS_BEGIN; int fd[2]; int error; - error = verify_area(VERIFY_WRITE,fildes,8); - if (error) - return error; - error = do_pipe(fd); - if (error) - return error; - put_fs_long(fd[0],0+fildes); - put_fs_long(fd[1],1+fildes); - return 0; + error = verify_area(VERIFY_WRITE,fildes,2*sizeof(*fildes)); + if (!error && !(error = do_pipe(fd))) { + put_fs_long(fd[0],0+fildes); + put_fs_long(fd[1],1+fildes); + } else { + fd[0] = fd[1] = -1; + } + audit_mask |= error ? + AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS; + _Audit_if_want_event(current,audit_mask) { + int result; + + _Audit_begin(3*sizeof(int)); + _Audit_append_simple(int, AUD_AET_PIPE); + _Audit_append_simple(int, fd[0]); + _Audit_append_simple(int, fd[1]); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK,audit_mask,&result) { + panic("failed audit-state change (%d)",current->pid); + } + } + + return error; } /* diff -urN linux-2.0.31pre9-privs-clean/fs/namei.c linux-2.0.31pre9-privs/fs/namei.c --- linux-2.0.31pre9-privs-clean/fs/namei.c Wed Sep 10 15:05:40 1997 +++ linux-2.0.31pre9-privs/fs/namei.c Sun Sep 14 11:44:11 1997 @@ -13,6 +13,7 @@ #include +#include #include #include #include @@ -641,15 +642,39 @@ return error; } -asmlinkage int sys_mkdir(const char * pathname, int mode) +asmlinkage int sys_mkdir(const char * pathname, mode_t mode) { - int error; - char * tmp; + __u32 audit_mask = AUDIT_EVENT_CLASS_DIR|AUDIT_EVENT_CLASS_BEGIN; + int error, length; + char * tmp=NULL; + const char *d_name; error = getname(pathname,&tmp); if (!error) { remove_trailing_slashes(tmp); + d_name = tmp; error = do_mkdir(tmp,mode); + } else { + d_name = "(nomem)"; + } + audit_mask |= error ? + AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS; + + /* audit this attempt */ + length = 1+strlen(d_name); + _Audit_if_want_event(current,audit_mask) { + int result; + + _Audit_begin(length + sizeof(int) + sizeof(mode_t)); + _Audit_append_simple(int, AUD_AET_MKDIR); + _Audit_append_simple(mode_t, mode); + _Audit_append_n_data(length-2*sizeof(int), d_name); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK,audit_mask,&result) { + panic("failed mkdir audit (%d)",current->pid); + } + } + + if (tmp) { putname(tmp); } return error; @@ -697,13 +722,36 @@ asmlinkage int sys_rmdir(const char * pathname) { - int error; - char * tmp; + __u32 audit_mask = AUDIT_EVENT_CLASS_DIR|AUDIT_EVENT_CLASS_END; + int error, length; + char * tmp=NULL; + const char *d_name; error = getname(pathname,&tmp); if (!error) { remove_trailing_slashes(tmp); + d_name = tmp; error = do_rmdir(tmp); + } else { + d_name = "(nomem)"; + } + audit_mask |= error ? + AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS; + + /* audit this attempt */ + length = 1+strlen(d_name) + sizeof(int); + _Audit_if_want_event(current,audit_mask) { + int result; + + _Audit_begin(length); + _Audit_append_simple(int, AUD_AET_RMDIR); + _Audit_append_n_data(length-sizeof(int), d_name); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK,audit_mask,&result) { + panic("failed rmdir audit (%d)",current->pid); + } + } + + if (tmp) { putname(tmp); } return error; @@ -751,12 +799,36 @@ asmlinkage int sys_unlink(const char * pathname) { - int error; - char * tmp; + __u32 audit_mask = AUDIT_EVENT_CLASS_FILE|AUDIT_EVENT_CLASS_DIR + |AUDIT_EVENT_CLASS_END; + int error, length; + char * tmp=NULL; + const char *d_name; error = getname(pathname,&tmp); if (!error) { + d_name = tmp; error = do_unlink(tmp); + } else { + d_name = "(nomem)"; + } + audit_mask |= error ? + AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS; + + /* audit this attempt */ + length = 1+strlen(d_name) + sizeof(int); + _Audit_if_want_event(current,audit_mask) { + int result; + + _Audit_begin(length); + _Audit_append_simple(int, AUD_AET_UNLINK); + _Audit_append_n_data(length-sizeof(int), d_name); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK,audit_mask,&result) { + panic("failed unlink audit (%d)",current->pid); + } + } + + if (tmp) { putname(tmp); } return error; @@ -886,20 +958,53 @@ asmlinkage int sys_link(const char * oldname, const char * newname) { - int error; - char * to; + __u32 audit_mask = AUDIT_EVENT_CLASS_FILE|AUDIT_EVENT_CLASS_DIR + |AUDIT_EVENT_CLASS_BEGIN; + int error, length1, length2; + char * to=NULL, *from=NULL; + const char *c_to, *c_from; struct inode * oldinode; error = lnamei(oldname, &oldinode); - if (error) - return error; - error = getname(newname,&to); - if (error) { - iput(oldinode); - return error; + if (!error) { + error = getname(newname,&to); + if (error) { + c_to = "(nomem)"; + iput(oldinode); + } else { + c_to = to; + error = do_link(oldinode,to); + } + } else { + c_to = "(nomem)"; } - error = do_link(oldinode,to); - putname(to); + + audit_mask |= error ? + AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS; + + if (getname(oldname, &from)) { + c_from = "(nomem)"; + } else { + c_from = from; + } + length1 = 1+strlen(c_from); + length2 = 1+strlen(c_to); + _Audit_if_want_event(current,audit_mask) { + int result; + + _Audit_begin(length1+length2+sizeof(int)); + _Audit_append_simple(int, AUD_AET_LINK); + _Audit_append_n_data(length1, c_from); + _Audit_append_n_data(length2, c_to); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK,audit_mask,&result) { + panic("failed link audit (%d)",current->pid); + } + } + + if (from) + putname(from); + if (to) + putname(to); return error; } @@ -975,19 +1080,49 @@ asmlinkage int sys_rename(const char * oldname, const char * newname) { - int error; - char * from, * to; + __u32 audit_mask = AUDIT_EVENT_CLASS_FILE|AUDIT_EVENT_CLASS_DIR; + int error, length1, length2; + char * from=NULL, * to=NULL; + const char *c_from, *c_to; error = getname(oldname,&from); if (!error) { + c_from = from; error = getname(newname,&to); if (!error) { + c_to = to; error = do_rename(from,to, remove_trailing_slashes(from) | remove_trailing_slashes(to)); - putname(to); + } else { + c_to = "(nomem)"; } - putname(from); + } else { + c_from = c_to = "(nomem)"; } + + audit_mask |= error ? + AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS; + + /* audit this attempt */ + length1 = 1+strlen(c_from); + length2 = 1+strlen(c_to); + _Audit_if_want_event(current,audit_mask) { + int result; + + _Audit_begin(length1+length2+sizeof(int)); + _Audit_append_simple(int, AUD_AET_RENAME); + _Audit_append_n_data(length1, c_from); + _Audit_append_n_data(length2, c_to); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK,audit_mask,&result) { + panic("failed rename audit (%d)",current->pid); + } + } + + if (to) + putname(to); + if (from) + putname(from); + return error; } diff -urN linux-2.0.31pre9-privs-clean/fs/open.c linux-2.0.31pre9-privs/fs/open.c --- linux-2.0.31pre9-privs-clean/fs/open.c Wed Sep 10 15:05:40 1997 +++ linux-2.0.31pre9-privs/fs/open.c Sun Sep 14 11:31:54 1997 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include #include @@ -268,23 +269,56 @@ asmlinkage int sys_chdir(const char * filename) { + __u32 audit_mask = AUDIT_EVENT_CLASS_DIR; struct inode * inode; int error; error = namei(filename,&inode); if (error) - return error; + goto failed; + if (!S_ISDIR(inode->i_mode)) { iput(inode); - return -ENOTDIR; - } - if ((error = permission(inode,MAY_EXEC)) != 0) { + error = -ENOTDIR; + } else if ((error = permission(inode,MAY_EXEC)) != 0) { iput(inode); - return error; + } else { + iput(current->fs->pwd); + current->fs->pwd = inode; + audit_mask |= AUDIT_EVENT_CLASS_SUCCESS; + goto audit; + } +failed: + audit_mask |= AUDIT_EVENT_CLASS_DENIED; +audit: + /* audit this attempt */ + _Audit_if_want_event(current,audit_mask) { + int result; + char *tmp_name=NULL; + const char *d_name; + + result = getname(filename, &tmp_name); + if (result) + d_name = "(nomem)"; + else + d_name = tmp_name; + result = 1+strlen(d_name) + sizeof(int); + { + _Audit_begin(result); + _Audit_append_simple(int, AUD_AET_CHDIR); + _Audit_append_n_data(result-sizeof(int), d_name); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK, + audit_mask, &result) { + panic("failed audit chdir (%d)", current->pid); + } + } + /* clean up */ + if (tmp_name) { + putname(tmp_name); + } } - iput(current->fs->pwd); - current->fs->pwd = inode; - return (0); + + return error; } asmlinkage int sys_fchdir(unsigned int fd) @@ -352,28 +386,60 @@ asmlinkage int sys_chmod(const char * filename, mode_t mode) { + __u32 audit_mask = AUDIT_EVENT_CLASS_DIR|AUDIT_EVENT_CLASS_FILE; struct inode * inode; int error; struct iattr newattrs; error = namei(filename,&inode); - if (error) - return error; - if (IS_RDONLY(inode)) { - iput(inode); - return -EROFS; - } - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { - iput(inode); - return -EPERM; + if (error) { + goto audit; + } else if (IS_RDONLY(inode)) { + error = -EROFS; + } else if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) { + error = -EPERM; + } else { + if (mode == (mode_t) -1) + mode = inode->i_mode; + newattrs.ia_mode = (mode & S_IALLUGO) | + (inode->i_mode & ~S_IALLUGO); + newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; + inode->i_dirt = 1; + error = notify_change(inode, &newattrs); } - if (mode == (mode_t) -1) - mode = inode->i_mode; - newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); - newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - inode->i_dirt = 1; - error = notify_change(inode, &newattrs); + + /* drop link to inode */ iput(inode); +audit: + audit_mask |= error ? + AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS; + _Audit_if_want_event(current,audit_mask) { + int result; + char *tmp_name=NULL; + const char *d_name; + + result = getname(filename, &tmp_name); + if (result) + d_name = "(nomem)"; + else + d_name = tmp_name; + result = 1+strlen(d_name); + { + _Audit_begin(result + sizeof(int) + sizeof(mode_t)); + _Audit_append_simple(int, AUD_AET_CHMOD); + _Audit_append_simple(mode_t, mode); + _Audit_append_n_data(result, d_name); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK, + audit_mask, &result) { + panic("failed audit chdir (%d)", current->pid); + } + } + /* clean up */ + if (tmp_name) { + putname(tmp_name); + } + } + return error; } @@ -578,23 +644,50 @@ FD_CLR(fd, ¤t->files->open_fds); } -asmlinkage int sys_open(const char * filename,int flags,int mode) +asmlinkage int sys_open(const char * filename, int flags, mode_t mode) { - char * tmp; - int fd, error; + __u32 audit_mask = AUDIT_EVENT_CLASS_FILE|AUDIT_EVENT_CLASS_BEGIN; + char * tmp=NULL; + const char *c_tmp; + int fd, error, length; - fd = get_unused_fd(); - if (fd < 0) - return fd; error = getname(filename, &tmp); - if (!error) { - error = do_open(tmp,flags,mode, fd); - putname(tmp); - if (!error) - return fd; + if (error) { + c_tmp = "(nomem)"; + fd = error; + } else { + c_tmp = tmp; + fd = get_unused_fd(); + if (fd >= 0) { + error = do_open(tmp,flags,mode, fd); + if (error) { + put_unused_fd(fd); + fd = error; + } + } } - put_unused_fd(fd); - return error; + + /* audit event */ + audit_mask |= (fd < 0) ? + AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS; + length = 1+strlen(c_tmp); + _Audit_if_want_event(current,audit_mask) { + int result; + + _Audit_begin(4*sizeof(int) + length); + _Audit_append_simple(int, AUD_AET_OPEN); + _Audit_append_simple(int, flags); + _Audit_append_simple(int, fd); + _Audit_append_simple(mode_t, mode); + _Audit_append_n_data(length, c_tmp); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK,audit_mask,&result) { + panic("failed audit-state change (%d)",current->pid); + } + } + + if (tmp) + putname(tmp); + return fd; } #ifndef __alpha__ diff -urN linux-2.0.31pre9-privs-clean/include/asm-i386/unistd.h linux-2.0.31pre9-privs/include/asm-i386/unistd.h --- linux-2.0.31pre9-privs-clean/include/asm-i386/unistd.h Wed Sep 10 15:05:41 1997 +++ linux-2.0.31pre9-privs/include/asm-i386/unistd.h Sat Sep 13 17:11:59 1997 @@ -181,6 +181,9 @@ #define __NR__getfilecap 173 #define __NR__fsetfilecap 174 #define __NR__fgetfilecap 175 +#define __NR__auditor 176 +#define __NR__auditswitch 177 +#define __NR__auditwrite 178 /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ #define _syscall0(type,name) \ diff -urN linux-2.0.31pre9-privs-clean/include/linux/audit.h linux-2.0.31pre9-privs/include/linux/audit.h --- linux-2.0.31pre9-privs-clean/include/linux/audit.h Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/include/linux/audit.h Sun Sep 14 21:24:10 1997 @@ -0,0 +1,228 @@ +#ifndef LINUX_AUDIT_H +#define LINUX_AUDIT_H + +#include +#include +#include + +/* the kernel audit structure, flags indicates if the rest of the header + * is in little or big endian format. */ + +struct __aud_header_s { + __u8 flags; /* For configuration use (includes byteordering) */ + __u8 generation; /* Indicator of generation of audit record */ + __u16 length; /* Number of __aud_s's that follow this */ + __u32 audit_id; /* Audit id - for tracing process trees */ + __u32 proc_id; /* PID of audited process */ + __u32 event_class; /* bits that triggered event recording: + * (bit 0)=0 -> user-level event + * (bit 0)=1 -> kernel-level event + */ + __u32 time_sec; /* when did event occur (seconds) */ + __u32 time_nsec; /* offset (nanosec) */ + __u64 unused; /* pad out to 256-bits = 32 bytes */ +} __attribute__ ((packed)); + +#ifdef __KERNEL__ + +/* some numbers that determine how many atoms of the internal audit + trail are to be buffered */ + +#define AUDIT_DATA_ATOM_SIZE sizeof(struct __aud_header_s) +#define MAX_AUDIT_ATOMS 1024 /* number of lines stored at + * any time in audit buffer: + * must be power of 2 */ +#define MAX_AUDIT_WRAP_MASK (MAX_AUDIT_ATOMS-1) +#define MAX_AUDIT_DATA (MAX_AUDIT_WRAP_MASK*AUDIT_DATA_ATOM) + +/* union for type of internal audit buffer */ + +union audit_atom { + struct __aud_header_s header; + __u8 data[AUDIT_DATA_ATOM_SIZE]; +}; + +/* The following are a set of tools for building an audit record. + * + * They can be conveniently #define'd to [empty] in the case that one + * wishes to compile code with auditing removed (gcc +02 will in all + * such cases investigated completely remove every trace of the + * auditing code). Note that the writing of an audit record macro is + * defined in the way it is to encourage the programmer to verify the + * exit status of the command. + * + * Usage is to place all commands between a single pair of { }'s: + * + * _Audit_if_want_event(current, event_mask) { + * int result; + * _Audit_begin(sizeof(int) + sizeof(gid_t)); + * _Audit_append_simple(int, AUD_AET_SETGID); + * _Audit_append_simple(gid_t, current->gid); + * _Audit_if_not_ok(_AUDIT_CAN_BLOCK, event_mask, &result) { + * panic("attempt to audit setgid event failed (%d)", result); + * } + * } + * + * In the case of non-blocking calls, the 'result' should be checked + * for being '+ERESTARTSYS' before panic()ing and the appropriate + * action is taken. + * + * It is anticipated that the list of audit events might most + * efficiently be stored in a single meta-data file which can be used + * to create both the auditing components within the kernel and the + * audit report generator application. It is also possible that one + * can 'parse' the kernel tree for events audited in the above fashion + * and generate the event profiles from that. (I currently favor this + * latter approach as it would offer some sort of verification process + * for the kernel's auditing code. My guess is that if someone doesn't + * beat me to it, I'll blow the dust of my lex/yacc books and put that + * together - AGM 1997/9/13) + */ + +/* this #define is used to mark a section for auditing. If + * CONFIG_POSIX6_AUDIT_MAXSPEED is in effect, an auditing decision is + * made here and now about whether this event will be audited or not. + * The alternative is that all such decisions will be made within the + * auditing function (kernel_audit) itself - where it is easier to + * "prove" for correctness. The advantage is one of speed, namely + * that we do not have to construct the audit record in advance of + * rejecting it because of information that was available in the first + * place... The idea is that the compiler of kernel makes this + * choice. XXX - add to config scripts. */ + +#ifdef CONFIG_POSIX6_AUDIT + +#ifdef CONFIG_POSIX6_AUDIT_MAXSPEED +# define _Audit_if_want_event(task, mask) \ + if ((mask) & (AUDIT_EVENT_CLASS_MANDATORY|(task)->audit_event_mask)) +#else +# define _Audit_if_want_event(task, mask) if (1) +#endif + +#define _Audit_begin(max_length) \ + __u8 _Audit_data[max_length] __attribute__ ((aligned)); \ + __u16 _Audit_length = 0 + +#define _Audit_append_simple(prototype, datum) \ + *((prototype *)(_Audit_length + _Audit_data)) = datum; \ + _Audit_length += sizeof(prototype) + +#define _Audit_append_by_ptr(prototype, data_p) \ + memcpy(_Audit_length+_Audit_data, data_p, sizeof(prototype)); \ + _Audit_length += sizeof(prototype) + +#define _Audit_append_n_data(length, data_p) \ + memcpy(_Audit_length+_Audit_data, data_p, length); \ + _Audit_length += length + +#define _Audit_if_not_ok(ok_to_block, event_mask, result_p) \ + if ((_Audit_length > sizeof(_Audit_data) && (*(result_p)=EINVAL)) || \ + (*(result_p) = kernel_auditwrite(ok_to_block,event_mask, \ + _Audit_length,_Audit_data))) + +#define _AUDIT_DONT_BLOCK 0 +#define _AUDIT_CAN_BLOCK 1 + +extern int kernel_auditwrite(int may_block, __u32 mask, __u16 length, + const void *data); + +#else /* ie. "not" CONFIG_POSIX6_AUDIT */ + +/* We don't want auditing: gcc -O2 should optimize away any trace of + the auditing code (the "if (0) ..." stuff is to silence gcc over + warnings about unused variables). This has been the case where I + looked at the assembly. */ + +#define _Audit_if_want_event(task, mask) if (0) +#define _Audit_begin(max_length) +#define _Audit_append_simple(prototype, datum) +#define _Audit_append_by_ptr(prototype, data_p) +#define _Audit_append_n_data(length, data_p) +#define _Audit_if_not_ok(ok_to_block, event_mask, result_p) \ + if (0) { *result_p = 0; } + +#endif /* CONFIG_POSIX6_AUDIT */ + +/* the current audit format generation number. Note, '0' is used to lock + record so it is not drained before it is written... */ + +#define AUDIT_RECORD_LOCKED 0 +#define AUDIT_CURRENT_GENERATION 1 + +/* flag-bits to indicate the nature of the audited event. These can be + combined to generate a profile of the event that can be more easily + vetoed as it is written to the audit log */ + +#define AUDIT_EVENT_CLASS_USER 0x00000000 /* user generated event */ +#define AUDIT_EVENT_CLASS_KERNEL 0x00000001 /* kernel generated event */ + +/* this event class is special - it cannot be turned off. It could be + defined as a union of other event classes, thus hard-wiring a + specified selection of events for mandated auditing. */ + +#define AUDIT_EVENT_CLASS_MANDATORY 0x80000000 /* "must audit" class */ + +#endif /* __KERNEL__ */ + +/* flags for interpreting audit header/record structure */ + +#define AUDIT_FLAG_BIG_ENDIAN 0x80 + +/* make a choice based on the endianness of the local chip */ + +#ifndef __LITTLE_ENDIAN +# define AUDIT_FLAG_PREFIX AUDIT_FLAG_BIG_ENDIAN +#else +# define AUDIT_FLAG_PREFIX 0x00 +#endif + +/* state bit pairs - mutually exclusive triads (0 = not applicable) */ +#define AUDIT_EVENT_CLASS_SUCCESS 0x00000002 /* event success notice */ +#define AUDIT_EVENT_CLASS_DENIED 0x00000004 /* event failure notice */ +#define AUDIT_EVENT_CLASS_PROGRESS 0x00000006 /* ambiguous state notice */ +#define AUDIT_EVENT_CLASS_RESULT_MASK 0x00000006 + +/* state bit pairs - mutually exclusive triads (0 = not applicable) */ +#define AUDIT_EVENT_CLASS_BEGIN 0x00000008 /* event starting notice */ +#define AUDIT_EVENT_CLASS_END 0x00000010 /* event ending notice */ +#define AUDIT_EVENT_CLASS_INTERIM 0x00000018 /* intermediate notice */ +#define AUDIT_EVENT_CLASS_EPOCH_MASK 0x00000018 + +#define AUDIT_EVENT_CLASS_FILE 0x00000100 /* related to file access */ +#define AUDIT_EVENT_CLASS_DRIVER 0x00000200 /* related to device driver */ +#define AUDIT_EVENT_CLASS_NET 0x00000400 /* related to a network */ +#define AUDIT_EVENT_CLASS_PROC 0x00000800 /* related to a process */ +#define AUDIT_EVENT_CLASS_CAP 0x00001000 /* change capability(ies) */ +#define AUDIT_EVENT_CLASS_AUDIT 0x00002000 /* to do with audit control */ +#define AUDIT_EVENT_CLASS_UID 0x00004000 /* to do with uids */ +#define AUDIT_EVENT_CLASS_GID 0x00008000 /* to do with gids */ +#define AUDIT_EVENT_CLASS_DIR 0x00010000 /* related to directories */ + +/* syscall control codes for sys_auditswitch */ + +#define LINUX_PROBE_AUDIT_MASK 1 +#define LINUX_PROBE_AUDIT_ID 2 +#define LINUX_GET_AUDIT_ID 3 + +/* POSIX event types - XXX. some of this belongs in */ + +#define AUD_STD_96_1 0xAD5D199601 /* draft 15, p296 par 3 */ +#define AUD_SYSTEM_LOG -1 /* file descriptor for system + audit log - cannot be 'opened'. */ +#define AUD_NATIVE 0 /* default format of records */ + +/* macros (types of numeric argument) - this is built from */ + +#include + +#define AUD_AET_AUD_SWITCH AUD_AET__AUDITSWITCH /* aud_switch() */ +#define AUD_AET_AUD_WRITE AUD_AET__AUDITWRITE /* aud_write() */ +#define AUD_AET_EXEC AUD_AET_EXECVE +#define AUD_AET_MKFIFO ?? /* mkfifo() */ + +/* Linux specific event types */ + +/* sys_auditswitch(LINUX_PROBE_AUDIT_ID) */ +#define AUD_AET_SYS_PROBE_ID 10001 + +#endif /* LINUX_AUDIT_H */ diff -urN linux-2.0.31pre9-privs-clean/include/linux/fs.h linux-2.0.31pre9-privs/include/linux/fs.h --- linux-2.0.31pre9-privs-clean/include/linux/fs.h Wed Sep 10 15:05:42 1997 +++ linux-2.0.31pre9-privs/include/linux/fs.h Sun Sep 14 15:38:19 1997 @@ -538,7 +538,7 @@ extern int register_filesystem(struct file_system_type *); extern int unregister_filesystem(struct file_system_type *); -asmlinkage int sys_open(const char *, int, int); +asmlinkage int sys_open(const char *, int, mode_t); asmlinkage int sys_close(unsigned int); /* yes, it's really unsigned */ extern void kill_fasync(struct fasync_struct *fa, int sig); diff -urN linux-2.0.31pre9-privs-clean/include/linux/sched.h linux-2.0.31pre9-privs/include/linux/sched.h --- linux-2.0.31pre9-privs-clean/include/linux/sched.h Wed Sep 10 15:05:42 1997 +++ linux-2.0.31pre9-privs/include/linux/sched.h Sun Sep 14 15:38:20 1997 @@ -232,6 +232,7 @@ #ifdef CONFIG_POSIX6_CAP __cap_s cap_effective, cap_inheritable, cap_permitted; #endif + __u32 aid, audit_event_mask; /* audit id & event mask */ char comm[16]; /* limits */ struct rlimit rlim[RLIM_NLIMITS]; @@ -295,6 +296,8 @@ # define INIT_CAPS #endif +#define INIT_AUDIT 0, ~0, + /* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) @@ -318,6 +321,7 @@ /* uid etc */ 0,0,0,0,0,0,0,0, \ /* suppl grps*/ {NOGROUP,}, \ /* cap's */ INIT_CAPS \ +/* aid, audit_event_mask */ INIT_AUDIT \ /* comm */ "swapper", \ /* rlimits */ INIT_RLIMITS, \ /* math */ 0, \ diff -urN linux-2.0.31pre9-privs-clean/kernel/Makefile linux-2.0.31pre9-privs/kernel/Makefile --- linux-2.0.31pre9-privs-clean/kernel/Makefile Wed Sep 10 15:05:45 1997 +++ linux-2.0.31pre9-privs/kernel/Makefile Thu Sep 11 07:57:51 1997 @@ -13,7 +13,7 @@ O_TARGET := kernel.o O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \ module.o exit.o signal.o itimer.o info.o time.o softirq.o \ - resource.o sysctl.o cap.o + resource.o sysctl.o cap.o audit.o ifeq ($(CONFIG_MODULES),y) OX_OBJS = ksyms.o diff -urN linux-2.0.31pre9-privs-clean/kernel/audit.c linux-2.0.31pre9-privs/kernel/audit.c --- linux-2.0.31pre9-privs-clean/kernel/audit.c Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/kernel/audit.c Sun Sep 14 15:18:27 1997 @@ -0,0 +1,472 @@ +/* + * This file contains the kernel auditing interface. + * + * Copyright (c) 1997 Andrew G. Morgan + * 1024/2A398175 D7 B8 FB 8F 9C E5 43 A3 3D 41 17 8F D5 71 69 50 + * + * There are three user-level auditing functions, they are used to + * modify/query the auditing status of the current task + * (sys_auditswitch), write to the audit buffer (sys_auditwrite), and + * to drain the audit buffer (sys_auditor). + * + * There is also an internal audit function that can be used to write + * kernel-driven audit events to the audit trail: kernel_auditor(). + * + * The intentions of these functions is to provide a mechanism for + * both the kernel and userspace to write arbitrary audit events to a + * kernel maintained audit buffer. This buffer is then drained from a + * sufficiently capable userspace daemon. The daemon itself is + * responsible for ensuring that the audit trail is safely deposited + * on some permanent medium (through calls to other parts of the + * kernel). This daemon is likely to need to turn off/limit auditing for + * its own actions. + * + * XXX - we could control task specific auditing with a task specific + * mask perhaps? */ + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_POSIX6_AUDIT + +/* this should probably be dynamically allocated */ + +static union audit_atom audit_buffer[MAX_AUDIT_ATOMS]; + +/* some global variables for blocking auditing calls */ + +struct wait_queue *audit_wait_queue = NULL; /* queued audit events */ +int audit_first_full_atom=0; /* where drain reads from */ +int audit_filled_data_atoms=0; /* how many filled atoms are there? */ +int audit_empty_atoms=MAX_AUDIT_ATOMS; /* how many empty atoms? */ +int audit_first_empty_atom=0; /* where new audit records are written to */ + +/* + * kernel level interface for writing to the audit trail + */ + +int kernel_auditwrite(int will_block, __u32 event_mask, __u16 length, + const void *data) +{ + int audit_atoms_needed, from, i; + /* Note, kernel calls; we can be severe about failures */ + audit_atoms_needed = ((length+AUDIT_DATA_ATOM_SIZE-1) + /AUDIT_DATA_ATOM_SIZE) + 1; + if (audit_atoms_needed > MAX_AUDIT_ATOMS) { + panic("kernel_auditor choked on large request (%d/%d)", + audit_atoms_needed, MAX_AUDIT_ATOMS); + } + + /* this must be after the above checks to avoid covert anlysis */ + if (!((AUDIT_EVENT_CLASS_MANDATORY|current->audit_event_mask) + & event_mask)) { + return 0; + } + + /* + * XXX - this is where we would probably employ an audit filter. + * See the sys_auditor() function below for more comments. + */ + + /* now we wait(?) for an opportunity to write to the audit trail */ + cli(); + if (audit_atoms_needed > audit_empty_atoms) { + if (!will_block) { + sti(); + return ERESTARTSYS; /* no blocking so return */ + } + /* wait for chance to write to audit trail */ + do { + /* we do not acknowledge signals until later + * -- XXX is there an + * "noninterruptible_sleep_on() fn? */ + interruptible_sleep_on(&audit_wait_queue); + } while (audit_atoms_needed > audit_empty_atoms); + } + + from = audit_first_empty_atom & MAX_AUDIT_WRAP_MASK; + audit_empty_atoms -= audit_atoms_needed; + audit_first_empty_atom += audit_atoms_needed; + audit_filled_data_atoms += audit_atoms_needed--; /* NB '--' */ + audit_buffer[from].header.generation = AUDIT_RECORD_LOCKED; + sti(); + + /* now we have control of enough of the audit buffer to write this + kernel audit event - we are _committed_ to doing it to. */ + + /* copy the whole blocks */ + for (i=1; iaid; + audit_buffer[from].header.proc_id = current->pid; + audit_buffer[from].header.event_class = + event_mask | AUDIT_EVENT_CLASS_KERNEL; + audit_buffer[from].header.time_sec = xtime.tv_sec; + audit_buffer[from].header.time_nsec = 1000*xtime.tv_usec; + audit_buffer[from].header.unused = 0; + + /* header is prepared now: mark buffer as ready to go. */ + audit_buffer[from].header.generation = AUDIT_CURRENT_GENERATION; + + /* wake up next process waiting on this queue */ + wake_up_interruptible(&audit_wait_queue); + + return 0; /* success! */ +} + +/* user level interface for changing audit status of current task */ + +asmlinkage int sys_auditswitch(int control, + int pid, + __u32 audit_mask_flags, + __u32 audit_append_flags, + __u32 *old_value_p) +{ + struct task_struct * p; + int retval; + __u32 audit_mask = AUDIT_EVENT_CLASS_AUDIT|AUDIT_EVENT_CLASS_PROC + |AUDIT_EVENT_CLASS_MANDATORY; + __u32 tmp, old; + + if (!capable(CAP_AUDIT_CONTROL)) { + /* user is not permitted to interact with auditing control */ + return -EPERM; + } + if (verify_area(VERIFY_WRITE, old_value_p, sizeof(*old_value_p))) { + return -EINVAL; + } + + /* verify control parameter */ + switch (control) { + case LINUX_PROBE_AUDIT_MASK: + case LINUX_PROBE_AUDIT_ID: + break; + default: + return -EINVAL; + } + + /* locate process */ + if (current->pid == pid) { + p = current; + retval = 0; + } else { + retval = -ESRCH; + for_each_task(p) { + if (p->pid == pid) { + retval = 0; + break; + } + } + } + + if (!retval) { + /* may want to set some defaults */ + old = tmp = 0; /* new setting */ + audit_mask |= AUDIT_EVENT_CLASS_DENIED; + goto audit; + } + + audit_mask |= AUDIT_EVENT_CLASS_SUCCESS; + + /* the resetting actions need to be atomic -- note, there is a + * race here between the getting of the old value and the + * setting of the new one. However, assuming that the two + * assignments (**) are atomic, we cannot ever be in an + * undefined audit state. */ + + switch (control) { + case LINUX_PROBE_AUDIT_MASK: + /* this is used to get a copy of the previous audit + * mask and or modify it in the process. */ + +/* (**) */ old = tmp = p->audit_event_mask; + memcpy_tofs(old_value_p, &tmp, sizeof(*old_value_p)); + + /* user may be changing audit properties of 'pid' */ + tmp &= audit_mask_flags; + tmp |= audit_append_flags; + +/* (**) */ p->audit_event_mask = tmp; + + break; + case LINUX_PROBE_AUDIT_ID: + /* this is used to get a copy of the former audit id + * and to possibly modify it for this process */ +/* (**) */ old = tmp = p->aid; + memcpy_tofs(old_value_p, &tmp, sizeof(*old_value_p)); + + /* user is attempting to change audit id of 'pid' */ + tmp &= audit_mask_flags; + tmp |= audit_append_flags; + +/* (**) */ p->aid = tmp; + + break; + default: + /* how did we get here? */ + panic("audit control parameter unknown (%d)\n", control); + } + +audit: + /* audit this attempt */ + _Audit_if_want_event(current,audit_mask) { + int result; + + _Audit_begin(3*sizeof(int)+2*sizeof(__u32)); + _Audit_append_simple(int, AUD_AET_AUD_SWITCH); + _Audit_append_simple(int, control); + _Audit_append_simple(int, pid); + _Audit_append_simple(__u32, old); + _Audit_append_simple(__u32, tmp); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK,audit_mask,&result) { + panic("failed audit-state change (%d)",current->pid); + } + } + + return retval; +} + +/* user level interface for writing audit data */ + +asmlinkage int sys_auditwrite(__u32 event_mask, int length, + const void *user_audit_data) +{ + int audit_atoms_needed, from, i; + + /* verify that the request is valid */ + if (!capable(CAP_AUDIT_WRITE)) { + /* user is not permitted to write to the audit log */ + return -EPERM; + } + audit_atoms_needed = ((length+AUDIT_DATA_ATOM_SIZE-1) + /AUDIT_DATA_ATOM_SIZE) + 1; + if (audit_atoms_needed > MAX_AUDIT_ATOMS) { + /* user is trying to dump too much into the audit buffer */ + return -EMSGSIZE; + } + if (verify_area(VERIFY_READ, user_audit_data, length)) { + return -EINVAL; + } + + /* this must be after the above checks to avoid covert anlysis */ + if (!((AUDIT_EVENT_CLASS_MANDATORY|current->audit_event_mask) + & event_mask)) { + return 0; + } + + /* + * XXX.CAP - this is likely where we would call an audit filter + * that would decide if we want events to be + * logged. A possible candidate for a module and/or + * an accept reject rule-set. + * + * It is also possible that such a facility could be + * (ab)used to regulate the behavior of users (cf. big blue) + * and offer the local sys-admin/auditor the option of simply + * terminating a process if it tries to do something + * inappropriate. + * + * Note, to avoid a user-level program probing the + * severity of the current audit selection rules, this + * check has to be _after_ verifying the user-provided + * arguments are valid. + */ + + /* + * block until we can get a section of the audit buffer to ourselves + */ + cli(); + while (audit_atoms_needed > audit_empty_atoms) { + /* return if interrupted */ + if (current->signal & ~current->blocked) { + sti(); + return -ERESTARTSYS; + } + /* sleep until we next get to the front of the queue */ + interruptible_sleep_on(&audit_wait_queue); + } + from = audit_first_empty_atom & MAX_AUDIT_WRAP_MASK; + audit_empty_atoms -= audit_atoms_needed; + audit_first_empty_atom += audit_atoms_needed; + audit_filled_data_atoms += audit_atoms_needed--; /* NB '--' */ + audit_buffer[from].header.generation = AUDIT_RECORD_LOCKED; + sti(); + + /* now we have a section of the buffer (possibly wrapped) that + is ours to keep. It will not be drained until the 'generation' + field of the first block in this reserved section is + non-zero... */ + + /* copy the whole blocks */ + for (i=1; iaid; + audit_buffer[from].header.proc_id = current->pid; + audit_buffer[from].header.event_class = + event_mask & ~AUDIT_EVENT_CLASS_KERNEL; + audit_buffer[from].header.time_sec = xtime.tv_sec; + audit_buffer[from].header.time_nsec = 1000*xtime.tv_usec; + audit_buffer[from].header.unused = 0; + + /* header is prepared now: mark buffer as ready to go. */ + audit_buffer[from].header.generation = AUDIT_CURRENT_GENERATION; + + /* wake up next process waiting on this queue */ + wake_up_interruptible(&audit_wait_queue); + + /* XXX.AUDIT - kernel should audit this action? */ + + return 0; /* success! */ +} + +/* userspace function to drain the audit buffer - not POSIX, but + needed if we are to avoid too much kernel bloat. */ + +asmlinkage int sys_auditor(void *sink_for_audit_data, int length, + int *number_p) +{ + int from, i, audit_atoms_needed; + + /* verify that we are permitted to drain the buffer */ + if (!capable(CAP_AUDIT_CONTROL)) { + return -EPERM; + } + + /* verify argument pointers */ + if (verify_area(VERIFY_WRITE, sink_for_audit_data, length) + || verify_area(VERIFY_WRITE, number_p, sizeof(int))) { + return -EINVAL; + } + + /* loop until we have read everything or filled the supplied buffer */ + cli(); + /* loop until something is available */ + while (audit_first_full_atom == audit_first_empty_atom) { + /* return if interrupted */ + if (current->signal & ~current->blocked) { + sti(); + return -ERESTARTSYS; + } + /* sleep until we next get to the front of the queue - we + share this queue with the writing part of the audit + code. */ + interruptible_sleep_on(&audit_wait_queue); + } + + /* we have some audit data - verify that nothing has broken */ + if (audit_first_full_atom > audit_first_empty_atom) { + sti(); + panic("auditor has overrun audit trail (%d/%d)\n", + audit_first_full_atom, audit_first_empty_atom); + } + + /* now we take out as many individual audit entries as we can + given the space limitations imposed by the calling process. */ + + i = 0; + while (audit_first_full_atom < audit_first_empty_atom && + (from = (audit_first_full_atom & MAX_AUDIT_WRAP_MASK), + audit_buffer[from].header.generation)) { + /* check we have space left */ + if (length < i+audit_buffer[from].header.length) { + if (i) { + break; /* have something so return it */ + } else { + sti(); + return -EMSGSIZE; + } + } + + /* we have enough space to copy this audit record (too) */ + audit_atoms_needed = + (audit_buffer[from].header.length + + AUDIT_DATA_ATOM_SIZE-1)/ AUDIT_DATA_ATOM_SIZE; + + if ((from + audit_atoms_needed) > MAX_AUDIT_ATOMS) { + /* need to handle the wrapped entry case */ + int partial = AUDIT_DATA_ATOM_SIZE + *(MAX_AUDIT_ATOMS-from); + + memcpy_tofs(sink_for_audit_data+i, + &audit_buffer[from].header, partial); + memcpy_tofs(sink_for_audit_data+i+partial, + &audit_buffer[0].header, + audit_buffer[from].header.length-partial); + } else { + /* one simple chunk */ + memcpy_tofs(sink_for_audit_data+i, + &audit_buffer[from].header, + audit_buffer[from].header.length); + } + /* less space available for any more audit events */ + i += audit_buffer[from].header.length; + + /* and finally we move on to the next block */ + audit_filled_data_atoms -= audit_atoms_needed; + audit_empty_atoms += audit_atoms_needed; + audit_first_full_atom += audit_atoms_needed; + } + sti(); + memcpy_tofs(number_p, &i, sizeof(i)); + + /* wake up next process waiting on this queue */ + wake_up_interruptible(&audit_wait_queue); + + return 0; /* success! */ +} + +#else /* ie. "not" CONFIG_POSIX6_AUDIT */ + +asmlinkage int sys_auditswitch(int control, + int pid, + __u32 audit_mask_flags, + __u32 audit_append_flags, + __u32 *old_value_p) +{ + return -ENOSYS; +} + +asmlinkage int sys_auditwrite(__u32 event_mask, int length, + const void *user_audit_data) +{ + return -ENOSYS; +} + +asmlinkage int sys_auditor(void *sink_for_audit_data, int length, + int *number_p) +{ + return -ENOSYS; +} + +#endif /* CONFIG_POSIX6_AUDIT */ diff -urN linux-2.0.31pre9-privs-clean/kernel/exit.c linux-2.0.31pre9-privs/kernel/exit.c --- linux-2.0.31pre9-privs-clean/kernel/exit.c Wed Sep 10 15:05:45 1997 +++ linux-2.0.31pre9-privs/kernel/exit.c Sat Sep 13 13:26:05 1997 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -318,9 +319,9 @@ { int err, retval = 0, count = 0; - if (!pid) - return(kill_pg(current->pgrp,sig,0)); - if (pid == -1) { + if (!pid) { + retval = kill_pg(current->pgrp,sig,0); + } else if (pid == -1) { struct task_struct * p; for_each_task(p) { if (p->pid > 1 && p != current) { @@ -329,12 +330,33 @@ retval = err; } } - return(count ? retval : -ESRCH); + retval = count ? retval : -ESRCH; + } else if (pid < 0) { + retval = kill_pg(-pid,sig,0); + } else { + /* Normal kill */ + retval = kill_proc(pid,sig,0); + } + + /* use err for audit event_mask */ + err = AUDIT_EVENT_CLASS_END|AUDIT_EVENT_CLASS_PROC| + (retval ? AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS); + + /* audit this event */ + _Audit_if_want_event(current,err) { + int result; + + _Audit_begin(4*sizeof(int)); + _Audit_append_simple(int, AUD_AET_KILL); + _Audit_append_simple(int, pid); + _Audit_append_simple(int, sig); + _Audit_append_simple(int, retval); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK, err, &result) { + panic("failed to audit kill (%d)", current->pid); + } } - if (pid < 0) - return(kill_pg(-pid,sig,0)); - /* Normal kill */ - return(kill_proc(pid,sig,0)); + + return retval; } /* @@ -604,6 +626,21 @@ asmlinkage int sys_exit(int error_code) { + _Audit_if_want_event(current, + AUDIT_EVENT_CLASS_END|AUDIT_EVENT_CLASS_PROC) { + int result; + + _Audit_begin(2*sizeof(int)); + _Audit_append_simple(int, AUD_AET_EXIT); + _Audit_append_simple(int, error_code); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK, + AUDIT_EVENT_CLASS_END + |AUDIT_EVENT_CLASS_PROC + |AUDIT_EVENT_CLASS_SUCCESS, + &result) { + panic("failed to audit exit pid=%d", current->pid); + } + } do_exit((error_code&0xff)<<8); } diff -urN linux-2.0.31pre9-privs-clean/kernel/printk.c linux-2.0.31pre9-privs/kernel/printk.c --- linux-2.0.31pre9-privs-clean/kernel/printk.c Wed Sep 10 15:05:46 1997 +++ linux-2.0.31pre9-privs/kernel/printk.c Wed Sep 10 20:36:10 1997 @@ -66,7 +66,7 @@ char c; int error; - if ((type != 3) && !capable(CAP_AUDIT_CONTROL)) /* CAP.FIXME */ + if ((type != 3) && !capable(CAP_SYS_ADMIN)) /* CAP.FIXME */ return -EPERM; switch (type) { case 0: /* Close log */ diff -urN linux-2.0.31pre9-privs-clean/kernel/sys.c linux-2.0.31pre9-privs/kernel/sys.c --- linux-2.0.31pre9-privs-clean/kernel/sys.c Wed Sep 10 15:05:46 1997 +++ linux-2.0.31pre9-privs/kernel/sys.c Sat Sep 13 22:18:36 1997 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include #include @@ -282,18 +283,36 @@ */ asmlinkage int sys_setgid(gid_t gid) { + __u32 audit_mask = AUDIT_EVENT_CLASS_GID|AUDIT_EVENT_CLASS_PROC; + int retval = 0; int old_egid = current->egid; - if (capable(CAP_SETGID)) + if ((gid == current->gid) || (gid == current->sgid)) + current->egid = current->fsgid = gid; + else if (capable(CAP_SETGID)) { current->gid = current->egid = current->sgid = current->fsgid = gid; - else if ((gid == current->gid) || (gid == current->sgid)) - current->egid = current->fsgid = gid; - else - return -EPERM; - if (current->egid != old_egid) + } else + retval = -EPERM; + + if (!retval && current->egid != old_egid) current->dumpable = 0; - return 0; + + audit_mask |= retval ? + AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS; + + _Audit_if_want_event(current,audit_mask) { + int result; + + _Audit_begin(2*sizeof(int)); + _Audit_append_simple(int, AUD_AET_SETGID); + _Audit_append_simple(int, gid); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK,audit_mask,&result) { + panic("failed to audit setuid (%d)", current->pid); + } + } + + return retval; } static char acct_active = 0; @@ -504,22 +523,41 @@ */ asmlinkage int sys_setuid(uid_t uid) { + __u32 audit_mask = AUDIT_EVENT_CLASS_UID|AUDIT_EVENT_CLASS_PROC; + int retval = 0; int old_euid = current->euid; - if (capable(CAP_SETUID)) + if ((uid == current->uid) || (uid == current->suid)) + current->fsuid = current->euid = uid; + else if (capable(CAP_SETUID)) { current->uid = current->euid = current->suid = current->fsuid = uid; - else if ((uid == current->uid) || (uid == current->suid)) - current->fsuid = current->euid = uid; - else - return -EPERM; - if (current->euid != old_euid) { + } else + retval = -EPERM; + + if (!retval && current->euid != old_euid) { #ifdef CONFIG_POSIX6_CAP + /* XXX.CAP - should we do this? clear permitted too? */ cap_clear(¤t->cap_effective); #endif current->dumpable = 0; } - return(0); + + audit_mask |= retval ? + AUDIT_EVENT_CLASS_DENIED:AUDIT_EVENT_CLASS_SUCCESS; + + _Audit_if_want_event(current,audit_mask) { + int result; + + _Audit_begin(2*sizeof(int)); + _Audit_append_simple(int, AUD_AET_SETUID); + _Audit_append_simple(int, uid); + _Audit_if_not_ok(_AUDIT_CAN_BLOCK,audit_mask,&result) { + panic("failed to audit setuid (%d)", current->pid); + } + } + + return retval; } /* diff -urN linux-2.0.31pre9-privs-clean/scripts/audit_events.pre linux-2.0.31pre9-privs/scripts/audit_events.pre --- linux-2.0.31pre9-privs-clean/scripts/audit_events.pre Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/scripts/audit_events.pre Thu Sep 11 17:28:32 1997 @@ -0,0 +1,29 @@ +# +# It is intended that this file will contain all of the audit events. +# Before compiling the kernel, this file will be parsed into the form +# of an include file that can be used to include appropriate events +# with a custom macro. It should also be noted that the output file +# will contain appropriate provision for compiling without audit support +# by providing an alternative #define for each macro. +# +# Version 0 of the syntax is something like: +# +# macro_name(macro_args) AUD_AET_"EVENT_IDENTIFIER" { +# [ type , value ] +# < type , value_p > +# ... +# } +# +# Where the AUD_AET_"EVENT_IDENTIFIER" is the id for the specific audit +# event. [ ] indicates that the datum will expand to _Audit_append_simple() +# and <> to _Audit_append_by_ptr . +# +# The principal reason for thinking this is a good idea is that this will +# make the creation of an audit analysis tool much easier. Another +# alternative is to simply parse the 'C' of the kernel for events as they +# appear there.. +# +# Currently, this latter course is chosen as we have few audited events. +# Later this may become inappropriate and we can return to the suggestions +# above. +# diff -urN linux-2.0.31pre9-privs-clean/scripts/mkaudit_aet_h linux-2.0.31pre9-privs/scripts/mkaudit_aet_h --- linux-2.0.31pre9-privs-clean/scripts/mkaudit_aet_h Wed Dec 31 16:00:00 1969 +++ linux-2.0.31pre9-privs/scripts/mkaudit_aet_h Sat Sep 13 17:49:39 1997 @@ -0,0 +1,20 @@ +#!/bin/bash +# +# This script makes a file from the current +# file. +cat > include/asm/audit_aet.h < it should not + * be changed by hand. If you need to add anything, add it to + * which includes this file + */ +#ifndef ASM_AUDIT_AET_H +#define ASM_AUDIT_AET_H + +EOF +cat include/asm/unistd.h | sed -ne '/^#define[\t ]__NR_/{s/^#define[\t ]__NR_//;s/[ \t]+/\t/;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/;s/^/#define AUD_AET_/;s@[\t]*/\*[^\n]*\*/[\t]*$@@;p;}' | fgrep -v '_NR_' >> include/asm/audit_aet.h +cat >> include/asm/audit_aet.h <