diff options
-rw-r--r-- | kernel/audit.c | 134 | ||||
-rw-r--r-- | kernel/auditsc.c | 150 |
2 files changed, 238 insertions, 46 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index 0a813d2..973ca5a 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -72,7 +72,7 @@ static int audit_failure = AUDIT_FAIL_PRINTK; * contains the (non-zero) pid. */ int audit_pid; -/* If audit_limit is non-zero, limit the rate of sending audit records +/* If audit_rate_limit is non-zero, limit the rate of sending audit records * to that number per second. This prevents DoS attacks, but results in * audit records being dropped. */ static int audit_rate_limit; @@ -102,7 +102,7 @@ static struct sock *audit_sock; * than AUDIT_MAXFREE are in use, the audit buffer is freed instead of * being placed on the freelist). */ static DEFINE_SPINLOCK(audit_freelist_lock); -static int audit_freelist_count = 0; +static int audit_freelist_count; static LIST_HEAD(audit_freelist); static struct sk_buff_head audit_skb_queue; @@ -186,8 +186,14 @@ static inline int audit_rate_check(void) return retval; } -/* Emit at least 1 message per second, even if audit_rate_check is - * throttling. */ +/** + * audit_log_lost - conditionally log lost audit message event + * @message: the message stating reason for lost audit message + * + * Emit at least 1 message per second, even if audit_rate_check is + * throttling. + * Always increment the lost messages counter. +*/ void audit_log_lost(const char *message) { static unsigned long last_msg = 0; @@ -218,7 +224,6 @@ void audit_log_lost(const char *message) audit_backlog_limit); audit_panic(message); } - } static int audit_set_rate_limit(int limit, uid_t loginuid) @@ -302,6 +307,19 @@ static int kauditd_thread(void *dummy) } } +/** + * audit_send_reply - send an audit reply message via netlink + * @pid: process id to send reply to + * @seq: sequence number + * @type: audit message type + * @done: done (last) flag + * @multi: multi-part message flag + * @payload: payload data + * @size: payload size + * + * Allocates an skb, builds the netlink message, and sends it to the pid. + * No failure notifications. + */ void audit_send_reply(int pid, int seq, int type, int done, int multi, void *payload, int size) { @@ -376,7 +394,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (err) return err; - /* As soon as there's any sign of userspace auditd, start kauditd to talk to it */ + /* As soon as there's any sign of userspace auditd, + * start kauditd to talk to it */ if (!kauditd_task) kauditd_task = kthread_run(kauditd_thread, NULL, "kauditd"); if (IS_ERR(kauditd_task)) { @@ -469,9 +488,11 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return err < 0 ? err : 0; } -/* Get message from skb (based on rtnetlink_rcv_skb). Each message is +/* + * Get message from skb (based on rtnetlink_rcv_skb). Each message is * processed by audit_receive_msg. Malformed skbs with wrong length are - * discarded silently. */ + * discarded silently. + */ static void audit_receive_skb(struct sk_buff *skb) { int err; @@ -600,7 +621,10 @@ err: return NULL; } -/* Compute a serial number for the audit record. Audit records are +/** + * audit_serial - compute a serial number for the audit record + * + * Compute a serial number for the audit record. Audit records are * written to user-space as soon as they are generated, so a complete * audit record may be written in several pieces. The timestamp of the * record and this serial number are used by the user-space tools to @@ -612,8 +636,8 @@ err: * audit context (for those records that have a context), and emit them * all at syscall exit. However, this could delay the reporting of * significant errors until syscall exit (or never, if the system - * halts). */ - + * halts). + */ unsigned int audit_serial(void) { static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED; @@ -649,6 +673,21 @@ static inline void audit_get_stamp(struct audit_context *ctx, * will be written at syscall exit. If there is no associated task, tsk * should be NULL. */ +/** + * audit_log_start - obtain an audit buffer + * @ctx: audit_context (may be NULL) + * @gfp_mask: type of allocation + * @type: audit message type + * + * Returns audit_buffer pointer on success or NULL on error. + * + * Obtain an audit buffer. This routine does locking to obtain the + * audit buffer, but then no locking is required for calls to + * audit_log_*format. If the task (ctx) is a task that is currently in a + * syscall, then the syscall is marked as auditable and an audit record + * will be written at syscall exit. If there is no associated task, then + * task context (ctx) should be NULL. + */ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type) { @@ -713,6 +752,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, /** * audit_expand - expand skb in the audit buffer * @ab: audit_buffer + * @extra: space to add at tail of the skb * * Returns 0 (no space) on failed expansion, or available space if * successful. @@ -729,10 +769,12 @@ static inline int audit_expand(struct audit_buffer *ab, int extra) return skb_tailroom(skb); } -/* Format an audit message into the audit buffer. If there isn't enough +/* + * Format an audit message into the audit buffer. If there isn't enough * room in the audit buffer, more room will be allocated and vsnprint * will be called a second time. Currently, we assume that a printk - * can't format message larger than 1024 bytes, so we don't either. */ + * can't format message larger than 1024 bytes, so we don't either. + */ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt, va_list args) { @@ -757,7 +799,8 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt, /* The printk buffer is 1024 bytes long, so if we get * here and AUDIT_BUFSIZ is at least 1024, then we can * log everything that printk could have logged. */ - avail = audit_expand(ab, max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail)); + avail = audit_expand(ab, + max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail)); if (!avail) goto out; len = vsnprintf(skb->tail, avail, fmt, args2); @@ -768,8 +811,14 @@ out: return; } -/* Format a message into the audit buffer. All the work is done in - * audit_log_vformat. */ +/** + * audit_log_format - format a message into the audit buffer. + * @ab: audit_buffer + * @fmt: format string + * @...: optional parameters matching @fmt string + * + * All the work is done in audit_log_vformat. + */ void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) { va_list args; @@ -781,9 +830,18 @@ void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) va_end(args); } -/* This function will take the passed buf and convert it into a string of - * ascii hex digits. The new string is placed onto the skb. */ -void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, +/** + * audit_log_hex - convert a buffer to hex and append it to the audit skb + * @ab: the audit_buffer + * @buf: buffer to convert to hex + * @len: length of @buf to be converted + * + * No return value; failure to expand is silently ignored. + * + * This function will take the passed buf and convert it into a string of + * ascii hex digits. The new string is placed onto the skb. + */ +void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, size_t len) { int i, avail, new_len; @@ -812,10 +870,16 @@ void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf, skb_put(skb, len << 1); /* new string is twice the old string */ } -/* This code will escape a string that is passed to it if the string - * contains a control character, unprintable character, double quote mark, +/** + * audit_log_unstrustedstring - log a string that may contain random characters + * @ab: audit_buffer + * @string: string to be logged + * + * This code will escape a string that is passed to it if the string + * contains a control character, unprintable character, double quote mark, * or a space. Unescaped strings will start and end with a double quote mark. - * Strings that are escaped are printed in hex (2 digits per char). */ + * Strings that are escaped are printed in hex (2 digits per char). + */ void audit_log_untrustedstring(struct audit_buffer *ab, const char *string) { const unsigned char *p = string; @@ -854,10 +918,15 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix, kfree(path); } -/* The netlink_* functions cannot be called inside an irq context, so - * the audit buffer is places on a queue and a tasklet is scheduled to +/** + * audit_log_end - end one audit record + * @ab: the audit_buffer + * + * The netlink_* functions cannot be called inside an irq context, so + * the audit buffer is placed on a queue and a tasklet is scheduled to * remove them from the queue outside the irq context. May be called in - * any context. */ + * any context. + */ void audit_log_end(struct audit_buffer *ab) { if (!ab) @@ -878,9 +947,18 @@ void audit_log_end(struct audit_buffer *ab) audit_buffer_free(ab); } -/* Log an audit record. This is a convenience function that calls - * audit_log_start, audit_log_vformat, and audit_log_end. It may be - * called in any context. */ +/** + * audit_log - Log an audit record + * @ctx: audit context + * @gfp_mask: type of allocation + * @type: audit message type + * @fmt: format string to use + * @...: variable parameters matching the format string + * + * This is a convenience function that calls audit_log_start, + * audit_log_vformat, and audit_log_end. It may be called + * in any context. + */ void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, const char *fmt, ...) { diff --git a/kernel/auditsc.c b/kernel/auditsc.c index cfaa4a2..51a4f58a 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -330,6 +330,15 @@ static int audit_list_rules(void *_dest) return 0; } +/** + * audit_receive_filter - apply all rules to the specified message type + * @type: audit message type + * @pid: target pid for netlink audit messages + * @uid: target uid for netlink audit messages + * @seq: netlink audit message sequence (serial) number + * @data: payload data + * @loginuid: loginuid of sender + */ int audit_receive_filter(int type, int pid, int uid, int seq, void *data, uid_t loginuid) { @@ -527,7 +536,7 @@ static enum audit_state audit_filter_task(struct task_struct *tsk) /* At syscall entry and exit time, this filter is called if the * audit_state is not low enough that auditing cannot take place, but is * also not high enough that we already know we have to write an audit - * record (i.e., the state is AUDIT_SETUP_CONTEXT or AUDIT_BUILD_CONTEXT). + * record (i.e., the state is AUDIT_SETUP_CONTEXT or AUDIT_BUILD_CONTEXT). */ static enum audit_state audit_filter_syscall(struct task_struct *tsk, struct audit_context *ctx, @@ -721,10 +730,15 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state) return context; } -/* Filter on the task information and allocate a per-task audit context +/** + * audit_alloc - allocate an audit context block for a task + * @tsk: task + * + * Filter on the task information and allocate a per-task audit context * if necessary. Doing so turns on system call auditing for the * specified task. This is called from copy_process, so no lock is - * needed. */ + * needed. + */ int audit_alloc(struct task_struct *tsk) { struct audit_context *context; @@ -911,8 +925,12 @@ static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask) } } -/* Free a per-task audit context. Called from copy_process and - * __put_task_struct. */ +/** + * audit_free - free a per-task audit context + * @tsk: task whose audit context block to free + * + * Called from copy_process and __put_task_struct. + */ void audit_free(struct task_struct *tsk) { struct audit_context *context; @@ -934,13 +952,24 @@ void audit_free(struct task_struct *tsk) audit_free_context(context); } -/* Fill in audit context at syscall entry. This only happens if the +/** + * audit_syscall_entry - fill in an audit record at syscall entry + * @tsk: task being audited + * @arch: architecture type + * @major: major syscall type (function) + * @a1: additional syscall register 1 + * @a2: additional syscall register 2 + * @a3: additional syscall register 3 + * @a4: additional syscall register 4 + * + * Fill in audit context at syscall entry. This only happens if the * audit context was created when the task was created and the state or * filters demand the audit context be built. If the state from the * per-task filter or from the per-syscall filter is AUDIT_RECORD_CONTEXT, * then the record will be written at syscall exit time (otherwise, it * will only be written if another part of the kernel requests that it - * be written). */ + * be written). + */ void audit_syscall_entry(struct task_struct *tsk, int arch, int major, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4) @@ -950,7 +979,8 @@ void audit_syscall_entry(struct task_struct *tsk, int arch, int major, BUG_ON(!context); - /* This happens only on certain architectures that make system + /* + * This happens only on certain architectures that make system * calls in kernel_thread via the entry.S interface, instead of * with direct calls. (If you are porting to a new * architecture, hitting this condition can indicate that you @@ -1009,11 +1039,18 @@ void audit_syscall_entry(struct task_struct *tsk, int arch, int major, context->auditable = !!(state == AUDIT_RECORD_CONTEXT); } -/* Tear down after system call. If the audit context has been marked as +/** + * audit_syscall_exit - deallocate audit context after a system call + * @tsk: task being audited + * @valid: success/failure flag + * @return_code: syscall return value + * + * Tear down after system call. If the audit context has been marked as * auditable (either because of the AUDIT_RECORD_CONTEXT state from * filtering, or because some other part of the kernel write an audit * message), then write out the syscall information. In call cases, - * free the names stored from getname(). */ + * free the names stored from getname(). + */ void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code) { struct audit_context *context; @@ -1048,7 +1085,13 @@ void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code) put_task_struct(tsk); } -/* Add a name to the list. Called from fs/namei.c:getname(). */ +/** + * audit_getname - add a name to the list + * @name: name to add + * + * Add a name to the list of audit names for this context. + * Called from fs/namei.c:getname(). + */ void audit_getname(const char *name) { struct audit_context *context = current->audit_context; @@ -1077,10 +1120,13 @@ void audit_getname(const char *name) } -/* Intercept a putname request. Called from - * include/linux/fs.h:putname(). If we have stored the name from - * getname in the audit context, then we delay the putname until syscall - * exit. */ +/* audit_putname - intercept a putname request + * @name: name to intercept and delay for putname + * + * If we have stored the name from getname in the audit context, + * then we delay the putname until syscall exit. + * Called from include/linux/fs.h:putname(). + */ void audit_putname(const char *name) { struct audit_context *context = current->audit_context; @@ -1117,8 +1163,14 @@ void audit_putname(const char *name) #endif } -/* Store the inode and device from a lookup. Called from - * fs/namei.c:path_lookup(). */ +/** + * audit_inode - store the inode and device from a lookup + * @name: name being audited + * @inode: inode being audited + * @flags: lookup flags (as used in path_lookup()) + * + * Called from fs/namei.c:path_lookup(). + */ void audit_inode(const char *name, const struct inode *inode, unsigned flags) { int idx; @@ -1154,6 +1206,14 @@ void audit_inode(const char *name, const struct inode *inode, unsigned flags) context->names[idx].rdev = inode->i_rdev; } +/** + * auditsc_get_stamp - get local copies of audit_context values + * @ctx: audit_context for the task + * @t: timespec to store time recorded in the audit_context + * @serial: serial value that is recorded in the audit_context + * + * Also sets the context as auditable. + */ void auditsc_get_stamp(struct audit_context *ctx, struct timespec *t, unsigned int *serial) { @@ -1165,6 +1225,15 @@ void auditsc_get_stamp(struct audit_context *ctx, ctx->auditable = 1; } +/** + * audit_set_loginuid - set a task's audit_context loginuid + * @task: task whose audit context is being modified + * @loginuid: loginuid value + * + * Returns 0. + * + * Called (set) from fs/proc/base.c::proc_loginuid_write(). + */ int audit_set_loginuid(struct task_struct *task, uid_t loginuid) { if (task->audit_context) { @@ -1183,11 +1252,26 @@ int audit_set_loginuid(struct task_struct *task, uid_t loginuid) return 0; } +/** + * audit_get_loginuid - get the loginuid for an audit_context + * @ctx: the audit_context + * + * Returns the context's loginuid or -1 if @ctx is NULL. + */ uid_t audit_get_loginuid(struct audit_context *ctx) { return ctx ? ctx->loginuid : -1; } +/** + * audit_ipc_perms - record audit data for ipc + * @qbytes: msgq bytes + * @uid: msgq user id + * @gid: msgq group id + * @mode: msgq mode (permissions) + * + * Returns 0 for success or NULL context or < 0 on error. + */ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) { struct audit_aux_data_ipcctl *ax; @@ -1211,6 +1295,13 @@ int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) return 0; } +/** + * audit_socketcall - record audit data for sys_socketcall + * @nargs: number of args + * @args: args array + * + * Returns 0 for success or NULL context or < 0 on error. + */ int audit_socketcall(int nargs, unsigned long *args) { struct audit_aux_data_socketcall *ax; @@ -1232,6 +1323,13 @@ int audit_socketcall(int nargs, unsigned long *args) return 0; } +/** + * audit_sockaddr - record audit data for sys_bind, sys_connect, sys_sendto + * @len: data length in user space + * @a: data address in kernel space + * + * Returns 0 for success or NULL context or < 0 on error. + */ int audit_sockaddr(int len, void *a) { struct audit_aux_data_sockaddr *ax; @@ -1253,6 +1351,15 @@ int audit_sockaddr(int len, void *a) return 0; } +/** + * audit_avc_path - record the granting or denial of permissions + * @dentry: dentry to record + * @mnt: mnt to record + * + * Returns 0 for success or NULL context or < 0 on error. + * + * Called from security/selinux/avc.c::avc_audit() + */ int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt) { struct audit_aux_data_path *ax; @@ -1274,6 +1381,14 @@ int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt) return 0; } +/** + * audit_signal_info - record signal info for shutting down audit subsystem + * @sig: signal value + * @t: task being signaled + * + * If the audit subsystem is being terminated, record the task (pid) + * and uid that is doing that. + */ void audit_signal_info(int sig, struct task_struct *t) { extern pid_t audit_sig_pid; @@ -1290,4 +1405,3 @@ void audit_signal_info(int sig, struct task_struct *t) } } } - |