From ca24a23ebca17d9d0f2afde4ee49cd810bccc8d7 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 19 Mar 2013 00:02:25 -0700 Subject: audit: Simplify and correct audit_log_capset - Always report the current process as capset now always only works on the current process. This prevents reporting 0 or a random pid in a random pid namespace. - Don't bother to pass the pid as is available. Signed-off-by: "Eric W. Biederman" (cherry picked from commit bcc85f0af31af123e32858069eb2ad8f39f90e67) (cherry picked from commit f911cac4556a7a23e0b3ea850233d13b32328692) Signed-off-by: Richard Guy Briggs [eparis: fix build error when audit disabled] Signed-off-by: Eric Paris diff --git a/include/linux/audit.h b/include/linux/audit.h index a406419..c9a66c6 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -220,7 +220,7 @@ extern void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat); extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm, const struct cred *new, const struct cred *old); -extern void __audit_log_capset(pid_t pid, const struct cred *new, const struct cred *old); +extern void __audit_log_capset(const struct cred *new, const struct cred *old); extern void __audit_mmap_fd(int fd, int flags); static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) @@ -285,11 +285,11 @@ static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, return 0; } -static inline void audit_log_capset(pid_t pid, const struct cred *new, +static inline void audit_log_capset(const struct cred *new, const struct cred *old) { if (unlikely(!audit_dummy_context())) - __audit_log_capset(pid, new, old); + __audit_log_capset(new, old); } static inline void audit_mmap_fd(int fd, int flags) @@ -397,8 +397,8 @@ static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, { return 0; } -static inline void audit_log_capset(pid_t pid, const struct cred *new, - const struct cred *old) +static inline void audit_log_capset(const struct cred *new, + const struct cred *old) { } static inline void audit_mmap_fd(int fd, int flags) { } diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 90594c9..df1e685 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -2321,18 +2321,16 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm, /** * __audit_log_capset - store information about the arguments to the capset syscall - * @pid: target pid of the capset call * @new: the new credentials * @old: the old (current) credentials * * Record the aguments userspace sent to sys_capset for later printing by the * audit system if applicable */ -void __audit_log_capset(pid_t pid, - const struct cred *new, const struct cred *old) +void __audit_log_capset(const struct cred *new, const struct cred *old) { struct audit_context *context = current->audit_context; - context->capset.pid = pid; + context->capset.pid = task_pid_nr(current); context->capset.cap.effective = new->cap_effective; context->capset.cap.inheritable = new->cap_effective; context->capset.cap.permitted = new->cap_permitted; diff --git a/kernel/capability.c b/kernel/capability.c index 4e66bf9..34019c5 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -277,7 +277,7 @@ SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data) if (ret < 0) goto error; - audit_log_capset(pid, new, current_cred()); + audit_log_capset(new, current_cred()); return commit_creds(new); -- cgit v0.10.2 From f9441639e6319f0c0e12bd63fa2f58990af0a9d2 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Wed, 14 Aug 2013 11:32:45 -0400 Subject: audit: fix netlink portid naming and types Normally, netlink ports use the PID of the userspace process as the port ID. If the PID is already in use by a port, the kernel will allocate another port ID to avoid conflict. Re-name all references to netlink ports from pid to portid to reflect this reality and avoid confusion with actual PIDs. Ports use the __u32 type, so re-type all portids accordingly. (This patch is very similar to ebiederman's 5deadd69) Signed-off-by: Richard Guy Briggs Signed-off-by: Gao feng Signed-off-by: Eric Paris diff --git a/include/linux/audit.h b/include/linux/audit.h index c9a66c6..9185bfa 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -461,7 +461,7 @@ extern int audit_update_lsm_rules(void); /* Private API (for audit.c only) */ extern int audit_filter_user(int type); extern int audit_filter_type(int type); -extern int audit_receive_filter(int type, int pid, int seq, +extern int audit_receive_filter(int type, __u32 portid, int seq, void *data, size_t datasz); extern int audit_enabled; #else /* CONFIG_AUDIT */ diff --git a/kernel/audit.c b/kernel/audit.c index 906ae5a0..3d3747b 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -93,7 +93,7 @@ static int audit_failure = AUDIT_FAIL_PRINTK; * the portid to use to send netlink messages to that process. */ int audit_pid; -static int audit_nlk_portid; +static __u32 audit_nlk_portid; /* 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 @@ -175,15 +175,15 @@ struct audit_buffer { }; struct audit_reply { - int pid; + __u32 portid; struct sk_buff *skb; }; -static void audit_set_pid(struct audit_buffer *ab, pid_t pid) +static void audit_set_portid(struct audit_buffer *ab, __u32 portid) { if (ab) { struct nlmsghdr *nlh = nlmsg_hdr(ab->skb); - nlh->nlmsg_pid = pid; + nlh->nlmsg_pid = portid; } } @@ -482,7 +482,7 @@ static int kauditd_thread(void *dummy) int audit_send_list(void *_dest) { struct audit_netlink_list *dest = _dest; - int pid = dest->pid; + __u32 portid = dest->portid; struct sk_buff *skb; /* wait for parent to finish and send an ACK */ @@ -490,14 +490,14 @@ int audit_send_list(void *_dest) mutex_unlock(&audit_cmd_mutex); while ((skb = __skb_dequeue(&dest->q)) != NULL) - netlink_unicast(audit_sock, skb, pid, 0); + netlink_unicast(audit_sock, skb, portid, 0); kfree(dest); return 0; } -struct sk_buff *audit_make_reply(int pid, int seq, int type, int done, +struct sk_buff *audit_make_reply(__u32 portid, int seq, int type, int done, int multi, const void *payload, int size) { struct sk_buff *skb; @@ -510,7 +510,7 @@ struct sk_buff *audit_make_reply(int pid, int seq, int type, int done, if (!skb) return NULL; - nlh = nlmsg_put(skb, pid, seq, t, size, flags); + nlh = nlmsg_put(skb, portid, seq, t, size, flags); if (!nlh) goto out_kfree_skb; data = nlmsg_data(nlh); @@ -531,13 +531,13 @@ static int audit_send_reply_thread(void *arg) /* Ignore failure. It'll only happen if the sender goes away, because our timeout is set to infinite. */ - netlink_unicast(audit_sock, reply->skb, reply->pid, 0); + netlink_unicast(audit_sock, reply->skb, reply->portid, 0); kfree(reply); return 0; } /** * audit_send_reply - send an audit reply message via netlink - * @pid: process id to send reply to + * @portid: netlink port to which to send reply * @seq: sequence number * @type: audit message type * @done: done (last) flag @@ -545,11 +545,11 @@ static int audit_send_reply_thread(void *arg) * @payload: payload data * @size: payload size * - * Allocates an skb, builds the netlink message, and sends it to the pid. + * Allocates an skb, builds the netlink message, and sends it to the port id. * No failure notifications. */ -static void audit_send_reply(int pid, int seq, int type, int done, int multi, - const void *payload, int size) +static void audit_send_reply(__u32 portid, int seq, int type, int done, + int multi, const void *payload, int size) { struct sk_buff *skb; struct task_struct *tsk; @@ -559,11 +559,11 @@ static void audit_send_reply(int pid, int seq, int type, int done, int multi, if (!reply) return; - skb = audit_make_reply(pid, seq, type, done, multi, payload, size); + skb = audit_make_reply(portid, seq, type, done, multi, payload, size); if (!skb) goto out; - reply->pid = pid; + reply->portid = portid; reply->skb = skb; tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply"); @@ -839,7 +839,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) size--; audit_log_n_untrustedstring(ab, data, size); } - audit_set_pid(ab, NETLINK_CB(skb).portid); + audit_set_portid(ab, NETLINK_CB(skb).portid); audit_log_end(ab); } break; diff --git a/kernel/audit.h b/kernel/audit.h index b779642..c7282444 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -240,13 +240,13 @@ extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right); extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); extern int parent_len(const char *path); extern int audit_compare_dname_path(const char *dname, const char *path, int plen); -extern struct sk_buff * audit_make_reply(int pid, int seq, int type, - int done, int multi, - const void *payload, int size); +extern struct sk_buff *audit_make_reply(__u32 portid, int seq, int type, + int done, int multi, + const void *payload, int size); extern void audit_panic(const char *message); struct audit_netlink_list { - int pid; + __u32 portid; struct sk_buff_head q; }; diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 51f3fd4..08f7f7b 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -972,7 +972,7 @@ out: } /* List rules using struct audit_rule_data. */ -static void audit_list_rules(int pid, int seq, struct sk_buff_head *q) +static void audit_list_rules(__u32 portid, int seq, struct sk_buff_head *q) { struct sk_buff *skb; struct audit_krule *r; @@ -987,14 +987,15 @@ static void audit_list_rules(int pid, int seq, struct sk_buff_head *q) data = audit_krule_to_data(r); if (unlikely(!data)) break; - skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 0, 1, - data, sizeof(*data) + data->buflen); + skb = audit_make_reply(portid, seq, AUDIT_LIST_RULES, + 0, 1, data, + sizeof(*data) + data->buflen); if (skb) skb_queue_tail(q, skb); kfree(data); } } - skb = audit_make_reply(pid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0); + skb = audit_make_reply(portid, seq, AUDIT_LIST_RULES, 1, 1, NULL, 0); if (skb) skb_queue_tail(q, skb); } @@ -1024,12 +1025,13 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re /** * audit_receive_filter - apply all rules to the specified message type * @type: audit message type - * @pid: target pid for netlink audit messages + * @portid: target port id for netlink audit messages * @seq: netlink audit message sequence (serial) number * @data: payload data * @datasz: size of payload data */ -int audit_receive_filter(int type, int pid, int seq, void *data, size_t datasz) +int audit_receive_filter(int type, __u32 portid, int seq, void *data, + size_t datasz) { struct task_struct *tsk; struct audit_netlink_list *dest; @@ -1047,11 +1049,11 @@ int audit_receive_filter(int type, int pid, int seq, void *data, size_t datasz) dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL); if (!dest) return -ENOMEM; - dest->pid = pid; + dest->portid = portid; skb_queue_head_init(&dest->q); mutex_lock(&audit_filter_mutex); - audit_list_rules(pid, seq, &dest->q); + audit_list_rules(portid, seq, &dest->q); mutex_unlock(&audit_filter_mutex); tsk = kthread_run(audit_send_list, dest, "audit_send_list"); -- cgit v0.10.2 From 2f2ad1013322c8f6c40fc6dafdbd32442fa730ad Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Mon, 15 Jul 2013 10:23:11 -0400 Subject: audit: restore order of tty and ses fields in log output When being refactored from audit_log_start() to audit_log_task_info(), in commit e23eb920 the tty and ses fields in the log output got transposed. Restore to original order to avoid breaking search tools. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 3d3747b..e88f599 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1716,7 +1716,7 @@ void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk) audit_log_format(ab, " ppid=%ld pid=%d auid=%u uid=%u gid=%u" " euid=%u suid=%u fsuid=%u" - " egid=%u sgid=%u fsgid=%u ses=%u tty=%s", + " egid=%u sgid=%u fsgid=%u tty=%s ses=%u", sys_getppid(), tsk->pid, from_kuid(&init_user_ns, audit_get_loginuid(tsk)), @@ -1728,7 +1728,7 @@ void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk) from_kgid(&init_user_ns, cred->egid), from_kgid(&init_user_ns, cred->sgid), from_kgid(&init_user_ns, cred->fsgid), - audit_get_sessionid(tsk), tty); + tty, audit_get_sessionid(tsk)); get_task_comm(name, tsk); audit_log_format(ab, " comm="); -- cgit v0.10.2 From 33faba7fa7f2288d2f8aaea95958b2c97bf9ebfb Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Tue, 16 Jul 2013 13:18:45 -0400 Subject: audit: listen in all network namespaces Convert audit from only listening in init_net to use register_pernet_subsys() to dynamically manage the netlink socket list. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index e88f599..dd18747 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -63,6 +63,7 @@ #include #include #include +#include #include "audit.h" @@ -121,6 +122,7 @@ static atomic_t audit_lost = ATOMIC_INIT(0); /* The netlink socket. */ static struct sock *audit_sock; +int audit_net_id; /* Hash for inode-based rules */ struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS]; @@ -176,6 +178,7 @@ struct audit_buffer { struct audit_reply { __u32 portid; + pid_t pid; struct sk_buff *skb; }; @@ -401,6 +404,7 @@ static void kauditd_send_skb(struct sk_buff *skb) printk(KERN_ERR "audit: *NO* daemon at audit_pid=%d\n", audit_pid); audit_log_lost("auditd disappeared\n"); audit_pid = 0; + audit_sock = NULL; /* we might get lucky and get this in the next auditd */ audit_hold_skb(skb); } else @@ -482,15 +486,16 @@ static int kauditd_thread(void *dummy) int audit_send_list(void *_dest) { struct audit_netlink_list *dest = _dest; - __u32 portid = dest->portid; struct sk_buff *skb; + struct net *net = get_net_ns_by_pid(dest->pid); + struct audit_net *aunet = net_generic(net, audit_net_id); /* wait for parent to finish and send an ACK */ mutex_lock(&audit_cmd_mutex); mutex_unlock(&audit_cmd_mutex); while ((skb = __skb_dequeue(&dest->q)) != NULL) - netlink_unicast(audit_sock, skb, portid, 0); + netlink_unicast(aunet->nlsk, skb, dest->portid, 0); kfree(dest); @@ -525,13 +530,15 @@ out_kfree_skb: static int audit_send_reply_thread(void *arg) { struct audit_reply *reply = (struct audit_reply *)arg; + struct net *net = get_net_ns_by_pid(reply->pid); + struct audit_net *aunet = net_generic(net, audit_net_id); mutex_lock(&audit_cmd_mutex); mutex_unlock(&audit_cmd_mutex); /* Ignore failure. It'll only happen if the sender goes away, because our timeout is set to infinite. */ - netlink_unicast(audit_sock, reply->skb, reply->portid, 0); + netlink_unicast(aunet->nlsk , reply->skb, reply->portid, 0); kfree(reply); return 0; } @@ -564,6 +571,7 @@ static void audit_send_reply(__u32 portid, int seq, int type, int done, goto out; reply->portid = portid; + reply->pid = task_pid_vnr(current); reply->skb = skb; tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply"); @@ -791,6 +799,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) audit_log_config_change("audit_pid", new_pid, audit_pid, 1); audit_pid = new_pid; audit_nlk_portid = NETLINK_CB(skb).portid; + audit_sock = NETLINK_CB(skb).sk; } if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) { err = audit_set_rate_limit(status_get->rate_limit); @@ -998,24 +1007,58 @@ static void audit_receive(struct sk_buff *skb) mutex_unlock(&audit_cmd_mutex); } -/* Initialize audit support at boot time. */ -static int __init audit_init(void) +static int __net_init audit_net_init(struct net *net) { - int i; struct netlink_kernel_cfg cfg = { .input = audit_receive, }; + struct audit_net *aunet = net_generic(net, audit_net_id); + + pr_info("audit: initializing netlink socket in namespace\n"); + + aunet->nlsk = netlink_kernel_create(net, NETLINK_AUDIT, &cfg); + if (aunet->nlsk == NULL) + return -ENOMEM; + if (!aunet->nlsk) + audit_panic("cannot initialize netlink socket in namespace"); + else + aunet->nlsk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; + return 0; +} + +static void __net_exit audit_net_exit(struct net *net) +{ + struct audit_net *aunet = net_generic(net, audit_net_id); + struct sock *sock = aunet->nlsk; + if (sock == audit_sock) { + audit_pid = 0; + audit_sock = NULL; + } + + rcu_assign_pointer(aunet->nlsk, NULL); + synchronize_net(); + netlink_kernel_release(sock); +} + +static struct pernet_operations __net_initdata audit_net_ops = { + .init = audit_net_init, + .exit = audit_net_exit, + .id = &audit_net_id, + .size = sizeof(struct audit_net), +}; + +/* Initialize audit support at boot time. */ +static int __init audit_init(void) +{ + int i; + if (audit_initialized == AUDIT_DISABLED) return 0; - printk(KERN_INFO "audit: initializing netlink socket (%s)\n", + pr_info("audit: initializing netlink subsys (%s)\n", audit_default ? "enabled" : "disabled"); - audit_sock = netlink_kernel_create(&init_net, NETLINK_AUDIT, &cfg); - if (!audit_sock) - audit_panic("cannot initialize netlink socket"); - else - audit_sock->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; + register_pernet_subsys(&audit_net_ops); skb_queue_head_init(&audit_skb_queue); skb_queue_head_init(&audit_skb_hold_queue); diff --git a/kernel/audit.h b/kernel/audit.h index c7282444..0719b45 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -247,11 +247,16 @@ extern void audit_panic(const char *message); struct audit_netlink_list { __u32 portid; + pid_t pid; struct sk_buff_head q; }; int audit_send_list(void *); +struct audit_net { + struct sock *nlsk; +}; + extern int selinux_audit_rule_update(void); extern struct mutex audit_filter_mutex; diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 08f7f7b..d085cfb 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1050,6 +1050,7 @@ int audit_receive_filter(int type, __u32 portid, int seq, void *data, if (!dest) return -ENOMEM; dest->portid = portid; + dest->pid = task_pid_vnr(current); skb_queue_head_init(&dest->q); mutex_lock(&audit_filter_mutex); -- cgit v0.10.2 From e789e561a50de0aaa8c695662d97aaa5eac9d55f Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Thu, 12 Sep 2013 23:03:51 -0400 Subject: audit: reset audit backlog wait time after error recovery When the audit queue overflows and times out (audit_backlog_wait_time), the audit queue overflow timeout is set to zero. Once the audit queue overflow timeout condition recovers, the timeout should be reset to the original value. See also: https://lkml.org/lkml/2013/9/2/473 Cc: stable@vger.kernel.org # v3.8-rc4+ Signed-off-by: Luiz Capitulino Signed-off-by: Dan Duval Signed-off-by: Chuck Anderson Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index dd18747..6cd2ecc 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -103,7 +103,8 @@ static int audit_rate_limit; /* Number of outstanding audit_buffers allowed. */ static int audit_backlog_limit = 64; -static int audit_backlog_wait_time = 60 * HZ; +#define AUDIT_BACKLOG_WAIT_TIME (60 * HZ) +static int audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME; static int audit_backlog_wait_overflow = 0; /* The identity of the user shutting down the audit system. */ @@ -1282,6 +1283,8 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, return NULL; } + audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME; + ab = audit_buffer_alloc(ctx, gfp_mask, type); if (!ab) { audit_log_lost("out of memory in audit_log_start"); -- cgit v0.10.2 From ae887e0bdcddb9d7acd8f1eb7b7795b438aa4950 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Mon, 16 Sep 2013 10:45:59 -0400 Subject: audit: make use of remaining sleep time from wait_for_auditd If wait_for_auditd() times out, go immediately to the error function rather than retesting the loop conditions. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 6cd2ecc..09e287b 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1209,18 +1209,21 @@ static inline void audit_get_stamp(struct audit_context *ctx, /* * Wait for auditd to drain the queue a little */ -static void wait_for_auditd(unsigned long sleep_time) +static unsigned long wait_for_auditd(unsigned long sleep_time) { + unsigned long timeout = sleep_time; DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&audit_backlog_wait, &wait); if (audit_backlog_limit && skb_queue_len(&audit_skb_queue) > audit_backlog_limit) - schedule_timeout(sleep_time); + timeout = schedule_timeout(sleep_time); __set_current_state(TASK_RUNNING); remove_wait_queue(&audit_backlog_wait, &wait); + + return timeout; } /** @@ -1267,8 +1270,9 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, sleep_time = timeout_start + audit_backlog_wait_time - jiffies; if ((long)sleep_time > 0) { - wait_for_auditd(sleep_time); - continue; + sleep_time = wait_for_auditd(sleep_time); + if ((long)sleep_time > 0) + continue; } } if (audit_rate_check() && printk_ratelimit()) -- cgit v0.10.2 From db897319401e1c111aef59deadd59ea08e11d879 Mon Sep 17 00:00:00 2001 From: Dan Duval Date: Mon, 16 Sep 2013 11:11:12 -0400 Subject: audit: efficiency fix 1: only wake up if queue shorter than backlog limit These and similar errors were seen on a patched 3.8 kernel when the audit subsystem was overrun during boot: udevd[876]: worker [887] unexpectedly returned with status 0x0100 udevd[876]: worker [887] failed while handling '/devices/pci0000:00/0000:00:03.0/0000:40:00.0' udevd[876]: worker [880] unexpectedly returned with status 0x0100 udevd[876]: worker [880] failed while handling '/devices/LNXSYSTM:00/LNXPWRBN:00/input/input1/event1' udevadm settle - timeout of 180 seconds reached, the event queue contains: /sys/devices/LNXSYSTM:00/LNXPWRBN:00/input/input1/event1 (3995) /sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/INT3F0D:00 (4034) audit: audit_backlog=258 > audit_backlog_limit=256 audit: audit_lost=1 audit_rate_limit=0 audit_backlog_limit=256 The change below increases the efficiency of the audit code and prevents it from being overrun: Only issue a wake_up in kauditd if the length of the skb queue is less than the backlog limit. Otherwise, threads waiting in wait_for_auditd() will simply wake up, discover that the queue is still too long for them to proceed, and go back to sleep. This results in wasted context switches and machine cycles. kauditd_thread() is the only function that removes buffers from audit_skb_queue so we can't race. If we did, the timeout in wait_for_auditd() would expire and the waiting thread would continue. See: https://lkml.org/lkml/2013/9/2/479 Signed-off-by: Dan Duval Signed-off-by: Chuck Anderson Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 09e287b..854f482 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -462,8 +462,10 @@ static int kauditd_thread(void *dummy) flush_hold_queue(); skb = skb_dequeue(&audit_skb_queue); - wake_up(&audit_backlog_wait); + if (skb) { + if (skb_queue_len(&audit_skb_queue) <= audit_backlog_limit) + wake_up(&audit_backlog_wait); if (audit_pid) kauditd_send_skb(skb); else -- cgit v0.10.2 From 7ecf69bf50fd3464342cab59fe08533fbe3f6076 Mon Sep 17 00:00:00 2001 From: Dan Duval Date: Mon, 16 Sep 2013 11:16:35 -0400 Subject: audit: efficiency fix 2: request exclusive wait since all need same resource These and similar errors were seen on a patched 3.8 kernel when the audit subsystem was overrun during boot: udevd[876]: worker [887] unexpectedly returned with status 0x0100 udevd[876]: worker [887] failed while handling '/devices/pci0000:00/0000:00:03.0/0000:40:00.0' udevd[876]: worker [880] unexpectedly returned with status 0x0100 udevd[876]: worker [880] failed while handling '/devices/LNXSYSTM:00/LNXPWRBN:00/input/input1/event1' udevadm settle - timeout of 180 seconds reached, the event queue contains: /sys/devices/LNXSYSTM:00/LNXPWRBN:00/input/input1/event1 (3995) /sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/INT3F0D:00 (4034) audit: audit_backlog=258 > audit_backlog_limit=256 audit: audit_lost=1 audit_rate_limit=0 audit_backlog_limit=256 The change below increases the efficiency of the audit code and prevents it from being overrun: Use add_wait_queue_exclusive() in wait_for_auditd() to put the thread on the wait queue. When kauditd dequeues an skb, all of the waiting threads are waiting for the same resource, but only one is going to get it, so there's no need to wake up more than one waiter. See: https://lkml.org/lkml/2013/9/2/479 Signed-off-by: Dan Duval Signed-off-by: Chuck Anderson Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 854f482..b8fa4bf 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1216,7 +1216,7 @@ static unsigned long wait_for_auditd(unsigned long sleep_time) unsigned long timeout = sleep_time; DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&audit_backlog_wait, &wait); + add_wait_queue_exclusive(&audit_backlog_wait, &wait); if (audit_backlog_limit && skb_queue_len(&audit_skb_queue) > audit_backlog_limit) -- cgit v0.10.2 From a106fb0c67727bfbe7f5a5bbdaaa3ae7f47a8c15 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Mon, 23 Sep 2013 21:53:35 -0400 Subject: documentation: document the audit= kernel start-up parameter Add the "audit=" kernel start-up parameter to Documentation/kernel-parameters.txt. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index fcbb736..6f13828 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -463,6 +463,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. atkbd.softrepeat= [HW] Use software keyboard repeat + audit= [KNL] Enable the audit sub-system + Format: { "0" | "1" } (0 = disabled, 1 = enabled) + Default: unset + baycom_epp= [HW,AX25] Format: , -- cgit v0.10.2 From f910fde7307be80a1a228bba969c492f61f13281 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Tue, 17 Sep 2013 12:34:52 -0400 Subject: audit: add kernel set-up parameter to override default backlog limit The default audit_backlog_limit is 64. This was a reasonable limit at one time. systemd causes so much audit queue activity on startup that auditd doesn't start before the backlog queue has already overflowed by more than a factor of 2. On a system with audit= not set on the kernel command line, this isn't an issue since that history isn't kept for auditd when it is available. On a system with audit=1 set on the kernel command line, kaudit tries to keep that history until auditd is able to drain the queue. This default can be changed by the "-b" option in audit.rules once the system has booted, but won't help with lost messages on boot. One way to solve this would be to increase the default backlog queue size to avoid losing any messages before auditd is able to consume them. This would be overkill to the embedded community and insufficient for some servers. Another way to solve it might be to add a kconfig option to set the default based on the system type. An embedded system would get the current (or smaller) default, while Workstations might get more than now and servers might get more. None of these solutions helps if a system's compiled default is too small to see the lost messages without compiling a new kernel. This patch adds a kernel set-up parameter (audit already has one to enable/disable it) "audit_backlog_limit=" that overrides the default to allow the system administrator to set the backlog limit. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 6f13828..ab86766 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -467,6 +467,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. Format: { "0" | "1" } (0 = disabled, 1 = enabled) Default: unset + audit_backlog_limit= [KNL] Set the audit queue size limit. + Format: (must be >=0) + Default: 64 + baycom_epp= [HW,AX25] Format: , diff --git a/kernel/audit.c b/kernel/audit.c index b8fa4bf..833f8e2 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1099,9 +1099,27 @@ static int __init audit_enable(char *str) return 1; } - __setup("audit=", audit_enable); +/* Process kernel command-line parameter at boot time. + * audit_backlog_limit= */ +static int __init audit_backlog_limit_set(char *str) +{ + long int audit_backlog_limit_arg; + pr_info("audit_backlog_limit: "); + if (kstrtol(str, 0, &audit_backlog_limit_arg)) { + printk("using default of %d, unable to parse %s\n", + audit_backlog_limit, str); + return 1; + } + if (audit_backlog_limit_arg >= 0) + audit_backlog_limit = (int)audit_backlog_limit_arg; + printk("%d\n", audit_backlog_limit); + + return 1; +} +__setup("audit_backlog_limit=", audit_backlog_limit_set); + static void audit_buffer_free(struct audit_buffer *ab) { unsigned long flags; -- cgit v0.10.2 From 09f883a9023e7a86f92c731e80f30a9447f4bdbe Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Wed, 18 Sep 2013 09:32:24 -0400 Subject: audit: clean up AUDIT_GET/SET local variables and future-proof API Re-named confusing local variable names (status_set and status_get didn't agree with their command type name) and reduced their scope. Future-proof API changes by not depending on the exact size of the audit_status struct and by adding an API version field. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index e2f0d99..4fdedd4 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -376,6 +376,7 @@ struct audit_status { __u32 backlog_limit; /* waiting messages limit */ __u32 lost; /* messages lost */ __u32 backlog; /* messages waiting in queue */ + __u32 version; /* audit api version number */ }; struct audit_features { diff --git a/kernel/audit.c b/kernel/audit.c index 833f8e2..80b7de0 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -743,7 +743,6 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { u32 seq; void *data; - struct audit_status *status_get, status_set; int err; struct audit_buffer *ab; u16 msg_type = nlh->nlmsg_type; @@ -769,34 +768,38 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) data = nlmsg_data(nlh); switch (msg_type) { - case AUDIT_GET: - memset(&status_set, 0, sizeof(status_set)); - status_set.enabled = audit_enabled; - status_set.failure = audit_failure; - status_set.pid = audit_pid; - status_set.rate_limit = audit_rate_limit; - status_set.backlog_limit = audit_backlog_limit; - status_set.lost = atomic_read(&audit_lost); - status_set.backlog = skb_queue_len(&audit_skb_queue); + case AUDIT_GET: { + struct audit_status s; + memset(&s, 0, sizeof(s)); + s.enabled = audit_enabled; + s.failure = audit_failure; + s.pid = audit_pid; + s.rate_limit = audit_rate_limit; + s.backlog_limit = audit_backlog_limit; + s.lost = atomic_read(&audit_lost); + s.backlog = skb_queue_len(&audit_skb_queue); + s.version = 1; audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0, - &status_set, sizeof(status_set)); + &s, sizeof(s)); break; - case AUDIT_SET: - if (nlmsg_len(nlh) < sizeof(struct audit_status)) - return -EINVAL; - status_get = (struct audit_status *)data; - if (status_get->mask & AUDIT_STATUS_ENABLED) { - err = audit_set_enabled(status_get->enabled); + } + case AUDIT_SET: { + struct audit_status s; + memset(&s, 0, sizeof(s)); + /* guard against past and future API changes */ + memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh))); + if (s.mask & AUDIT_STATUS_ENABLED) { + err = audit_set_enabled(s.enabled); if (err < 0) return err; } - if (status_get->mask & AUDIT_STATUS_FAILURE) { - err = audit_set_failure(status_get->failure); + if (s.mask & AUDIT_STATUS_FAILURE) { + err = audit_set_failure(s.failure); if (err < 0) return err; } - if (status_get->mask & AUDIT_STATUS_PID) { - int new_pid = status_get->pid; + if (s.mask & AUDIT_STATUS_PID) { + int new_pid = s.pid; if (audit_enabled != AUDIT_OFF) audit_log_config_change("audit_pid", new_pid, audit_pid, 1); @@ -804,14 +807,15 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) audit_nlk_portid = NETLINK_CB(skb).portid; audit_sock = NETLINK_CB(skb).sk; } - if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) { - err = audit_set_rate_limit(status_get->rate_limit); + if (s.mask & AUDIT_STATUS_RATE_LIMIT) { + err = audit_set_rate_limit(s.rate_limit); if (err < 0) return err; } - if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT) - err = audit_set_backlog_limit(status_get->backlog_limit); + if (s.mask & AUDIT_STATUS_BACKLOG_LIMIT) + err = audit_set_backlog_limit(s.backlog_limit); break; + } case AUDIT_GET_FEATURE: err = audit_get_feature(skb); if (err) -- cgit v0.10.2 From 51cc83f024ee51de9da70c17e01ec6de524f5906 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Wed, 18 Sep 2013 11:55:12 -0400 Subject: audit: add audit_backlog_wait_time configuration option reaahead-collector abuses the audit logging facility to discover which files are accessed at boot time to make a pre-load list Add a tuning option to audit_backlog_wait_time so that if auditd can't keep up, or gets blocked, the callers won't be blocked. Bump audit_status API version to "2". Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index 4fdedd4..14afb0d 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -319,6 +319,7 @@ enum { #define AUDIT_STATUS_PID 0x0004 #define AUDIT_STATUS_RATE_LIMIT 0x0008 #define AUDIT_STATUS_BACKLOG_LIMIT 0x0010 +#define AUDIT_STATUS_BACKLOG_WAIT_TIME 0x0020 /* Failure-to-log actions */ #define AUDIT_FAIL_SILENT 0 #define AUDIT_FAIL_PRINTK 1 @@ -377,6 +378,7 @@ struct audit_status { __u32 lost; /* messages lost */ __u32 backlog; /* messages waiting in queue */ __u32 version; /* audit api version number */ + __u32 backlog_wait_time;/* message queue wait timeout */ }; struct audit_features { diff --git a/kernel/audit.c b/kernel/audit.c index 80b7de0..37ba599 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -334,6 +334,12 @@ static int audit_set_backlog_limit(int limit) return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit, limit); } +static int audit_set_backlog_wait_time(int timeout) +{ + return audit_do_config_change("audit_backlog_wait_time", + &audit_backlog_wait_time, timeout); +} + static int audit_set_enabled(int state) { int rc; @@ -778,7 +784,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) s.backlog_limit = audit_backlog_limit; s.lost = atomic_read(&audit_lost); s.backlog = skb_queue_len(&audit_skb_queue); - s.version = 1; + s.version = 2; + s.backlog_wait_time = audit_backlog_wait_time; audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0, &s, sizeof(s)); break; @@ -812,8 +819,28 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (err < 0) return err; } - if (s.mask & AUDIT_STATUS_BACKLOG_LIMIT) + if (s.mask & AUDIT_STATUS_BACKLOG_LIMIT) { err = audit_set_backlog_limit(s.backlog_limit); + if (err < 0) + return err; + } + switch (s.version) { + /* add future vers # cases immediately below and allow + * to fall through */ + case 2: + if (s.mask & AUDIT_STATUS_BACKLOG_WAIT_TIME) { + if (sizeof(s) > (size_t)nlh->nlmsg_len) + return -EINVAL; + if (s.backlog_wait_time < 0 || + s.backlog_wait_time > 10*AUDIT_BACKLOG_WAIT_TIME) + return -EINVAL; + err = audit_set_backlog_wait_time(s.backlog_wait_time); + if (err < 0) + return err; + } + default: + break; + } break; } case AUDIT_GET_FEATURE: -- cgit v0.10.2 From d3ca0344b21f04786219bf0f49647f24e4e17323 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Thu, 31 Oct 2013 14:31:01 +0800 Subject: audit: remove useless code in audit_enable Since kernel parameter is operated before initcall, so the audit_initialized must be AUDIT_UNINITIALIZED or DISABLED in audit_enable. Signed-off-by: Gao feng Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 37ba599..14324dd 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1116,17 +1116,8 @@ static int __init audit_enable(char *str) if (!audit_default) audit_initialized = AUDIT_DISABLED; - printk(KERN_INFO "audit: %s", audit_default ? "enabled" : "disabled"); - - if (audit_initialized == AUDIT_INITIALIZED) { - audit_enabled = audit_default; - audit_ever_enabled |= !!audit_default; - } else if (audit_initialized == AUDIT_UNINITIALIZED) { - printk(" (after initialization)"); - } else { - printk(" (until reboot)"); - } - printk("\n"); + pr_info("audit: %s\n", audit_default ? + "enabled (after initialization)" : "disabled (until reboot)"); return 1; } -- cgit v0.10.2 From aabce351b514e21e7768929ba6e5fbd87dc3848c Mon Sep 17 00:00:00 2001 From: Gao feng Date: Fri, 1 Nov 2013 19:34:42 +0800 Subject: audit: fix incorrect order of log new and old feature The order of new feature and old feature is incorrect, this patch fix it. Acked-by: Eric Paris Signed-off-by: Gao feng Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 14324dd..4b6250c 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -681,7 +681,7 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature struct audit_buffer *ab; ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE); - audit_log_format(ab, "feature=%s new=%d old=%d old_lock=%d new_lock=%d res=%d", + audit_log_format(ab, "feature=%s old=%d new=%d old_lock=%d new_lock=%d res=%d", audit_feature_names[which], !!old_feature, !!new_feature, !!old_lock, !!new_lock, res); audit_log_end(ab); -- cgit v0.10.2 From b6c50fe0be5b3a6be9c26f6941bc8c94cfaac1f8 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Fri, 1 Nov 2013 19:34:43 +0800 Subject: audit: don't generate audit feature changed log when audit disabled If audit is disabled,we shouldn't generate the audit log. Acked-by: Eric Paris Signed-off-by: Gao feng Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 4b6250c..2360da9 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -680,6 +680,9 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature { struct audit_buffer *ab; + if (audit_enabled == AUDIT_OFF) + return; + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE); audit_log_format(ab, "feature=%s old=%d new=%d old_lock=%d new_lock=%d res=%d", audit_feature_names[which], !!old_feature, !!new_feature, -- cgit v0.10.2 From 4547b3bc43c64389ca4368be0edf1f90ae1b938d Mon Sep 17 00:00:00 2001 From: Gao feng Date: Fri, 1 Nov 2013 19:34:44 +0800 Subject: audit: use old_lock in audit_set_feature we already have old_lock, no need to calculate it again. Acked-by: Eric Paris Signed-off-by: Gao feng Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 2360da9..0d4865a 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -714,7 +714,7 @@ static int audit_set_feature(struct sk_buff *skb) old_lock = af.lock & feature; /* are we changing a locked feature? */ - if ((af.lock & feature) && (new_feature != old_feature)) { + if (old_lock && (new_feature != old_feature)) { audit_log_feature_change(i, old_feature, new_feature, old_lock, new_lock, 0); return -EPERM; -- cgit v0.10.2 From c2412d91c68426e22add16550f97ae5cd988a159 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Fri, 1 Nov 2013 19:34:45 +0800 Subject: audit: don't generate loginuid log when audit disabled If audit is disabled, we shouldn't generate loginuid audit log. Acked-by: Eric Paris Signed-off-by: Gao feng Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/auditsc.c b/kernel/auditsc.c index df1e685..9ab02fa 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1971,6 +1971,9 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid, struct audit_buffer *ab; uid_t uid, ologinuid, nloginuid; + if (!audit_enabled) + return; + uid = from_kuid(&init_user_ns, task_uid(current)); ologinuid = from_kuid(&init_user_ns, koldloginuid); nloginuid = from_kuid(&init_user_ns, kloginuid), -- cgit v0.10.2 From b6cfee4cce25d8d2cc06c69f0de2b61d4b2249b3 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Tue, 26 Nov 2013 18:01:36 -0500 Subject: audit: fix incorrect type of sessionid The type of task->sessionid is unsigned int, the return type of audit_get_sessionid should be consistent with it. Signed-off-by: Gao feng Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/include/linux/audit.h b/include/linux/audit.h index 9185bfa..1690f95 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -202,7 +202,7 @@ static inline kuid_t audit_get_loginuid(struct task_struct *tsk) return tsk->loginuid; } -static inline int audit_get_sessionid(struct task_struct *tsk) +static inline unsigned int audit_get_sessionid(struct task_struct *tsk) { return tsk->sessionid; } @@ -359,7 +359,7 @@ static inline kuid_t audit_get_loginuid(struct task_struct *tsk) { return INVALID_UID; } -static inline int audit_get_sessionid(struct task_struct *tsk) +static inline unsigned int audit_get_sessionid(struct task_struct *tsk) { return -1; } -- cgit v0.10.2 From 40c0775e5ea47667db497565b79a8dc154530992 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Tue, 22 Oct 2013 13:28:49 -0400 Subject: audit: allow unlimited backlog queue Since audit can already be disabled by "audit=0" on the kernel boot line, or by the command "auditctl -e 0", it would be more useful to have the audit_backlog_limit set to zero mean effectively unlimited (limited only by system RAM). Acked-by: Gao feng Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 0d4865a..72bc1d0 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -101,7 +101,8 @@ static __u32 audit_nlk_portid; * audit records being dropped. */ static int audit_rate_limit; -/* Number of outstanding audit_buffers allowed. */ +/* Number of outstanding audit_buffers allowed. + * When set to zero, this means unlimited. */ static int audit_backlog_limit = 64; #define AUDIT_BACKLOG_WAIT_TIME (60 * HZ) static int audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME; @@ -375,7 +376,8 @@ static int audit_set_failure(int state) static void audit_hold_skb(struct sk_buff *skb) { if (audit_default && - skb_queue_len(&audit_skb_hold_queue) < audit_backlog_limit) + (!audit_backlog_limit || + skb_queue_len(&audit_skb_hold_queue) < audit_backlog_limit)) skb_queue_tail(&audit_skb_hold_queue, skb); else kfree_skb(skb); -- cgit v0.10.2 From 61c0ee8792165f0de7c4aa619343998a6966c1ef Mon Sep 17 00:00:00 2001 From: Paul Davies C Date: Fri, 8 Nov 2013 09:57:39 +0530 Subject: audit: drop audit_log_abend() The audit_log_abend() is used only by the audit_core_dumps(). Thus there is no need of maintaining the audit_log_abend() as a separate function. This patch drops the audit_log_abend() and pushes its functionalities back to the audit_core_dumps(). Apart from that the "reason" field is also dropped from being logged since the reason can be deduced from the signal number. Signed-off-by: Paul Davies C Acked-by: Eric Paris Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 9ab02fa..fc3b3db 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -2368,13 +2368,6 @@ static void audit_log_task(struct audit_buffer *ab) audit_log_untrustedstring(ab, current->comm); } -static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr) -{ - audit_log_task(ab); - audit_log_format(ab, " reason="); - audit_log_string(ab, reason); - audit_log_format(ab, " sig=%ld", signr); -} /** * audit_core_dumps - record information about processes that end abnormally * @signr: signal value @@ -2395,7 +2388,8 @@ void audit_core_dumps(long signr) ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); if (unlikely(!ab)) return; - audit_log_abend(ab, "memory violation", signr); + audit_log_task(ab); + audit_log_format(ab, " sig=%ld", signr); audit_log_end(ab); } -- cgit v0.10.2 From 04ee1a3b8f0584099370f8501ac785fd5d2ed6ff Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Tue, 26 Nov 2013 18:49:12 -0500 Subject: audit: get rid of *NO* daemon at audit_pid=0 message kauditd_send_skb is called after audit_pid was checked to be non-zero. However, it can be set to 0 due to auditd exiting while kauditd_send_skb is still executed and this can result in a spurious warning about missing auditd. Re-check audit_pid before printing the message. Signed-off-by: Mateusz Guzik Cc: Eric Paris Cc: linux-kernel@vger.kernel.org Acked-by: Eric Paris Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 72bc1d0..2dc7573 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -410,10 +410,12 @@ static void kauditd_send_skb(struct sk_buff *skb) err = netlink_unicast(audit_sock, skb, audit_nlk_portid, 0); if (err < 0) { BUG_ON(err != -ECONNREFUSED); /* Shouldn't happen */ - printk(KERN_ERR "audit: *NO* daemon at audit_pid=%d\n", audit_pid); - audit_log_lost("auditd disappeared\n"); - audit_pid = 0; - audit_sock = NULL; + if (audit_pid) { + printk(KERN_ERR "audit: *NO* daemon at audit_pid=%d\n", audit_pid); + audit_log_lost("auditd disappeared\n"); + audit_pid = 0; + audit_sock = NULL; + } /* we might get lucky and get this in the next auditd */ audit_hold_skb(skb); } else -- cgit v0.10.2 From a06e56b2a11b5f7d5354b05988f97118c90580d2 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Fri, 15 Nov 2013 11:29:02 -0500 Subject: audit: log AUDIT_TTY_SET config changes Log transition of config changes when AUDIT_TTY_SET is called, including both enabled and log_passwd values now in the struct. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 2dc7573..fdb8528 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -989,20 +989,38 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) break; } case AUDIT_TTY_SET: { - struct audit_tty_status s; + struct audit_tty_status s, old; struct task_struct *tsk = current; + struct audit_buffer *ab; + int res = 0; + + spin_lock(&tsk->sighand->siglock); + old.enabled = tsk->signal->audit_tty; + old.log_passwd = tsk->signal->audit_tty_log_passwd; + spin_unlock(&tsk->sighand->siglock); memset(&s, 0, sizeof(s)); /* guard against past and future API changes */ memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh))); - if ((s.enabled != 0 && s.enabled != 1) || - (s.log_passwd != 0 && s.log_passwd != 1)) + if ((s.enabled == 0 || s.enabled == 1) && + (s.log_passwd == 0 || s.log_passwd == 1)) + res = 1; + audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); + audit_log_format(ab, " op=tty_set" + " old-enabled=%d old-log_passwd=%d" + " new-enabled=%d new-log_passwd=%d" + " res=%d", + old.enabled, old.log_passwd, + s.enabled, s.log_passwd, + res); + audit_log_end(ab); + if (res) { + spin_lock(&tsk->sighand->siglock); + tsk->signal->audit_tty = s.enabled; + tsk->signal->audit_tty_log_passwd = s.log_passwd; + spin_unlock(&tsk->sighand->siglock); + } else return -EINVAL; - - spin_lock(&tsk->sighand->siglock); - tsk->signal->audit_tty = s.enabled; - tsk->signal->audit_tty_log_passwd = s.log_passwd; - spin_unlock(&tsk->sighand->siglock); break; } default: -- cgit v0.10.2 From ce0d9f04699706843e8a494d12cf6c7663d478c7 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Wed, 20 Nov 2013 14:01:53 -0500 Subject: audit: refactor audit_receive_msg() to clarify AUDIT_*_RULE* cases audit_receive_msg() needlessly contained a fallthrough case that called audit_receive_filter(), containing no common code between the cases. Separate them to make the logic clearer. Refactor AUDIT_LIST_RULES, AUDIT_ADD_RULE, AUDIT_DEL_RULE cases to create audit_rule_change(), audit_list_rules_send() functions. This should not functionally change the logic. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/include/linux/audit.h b/include/linux/audit.h index 1690f95..6976219 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -461,8 +461,10 @@ extern int audit_update_lsm_rules(void); /* Private API (for audit.c only) */ extern int audit_filter_user(int type); extern int audit_filter_type(int type); -extern int audit_receive_filter(int type, __u32 portid, int seq, +extern int audit_rule_change(int type, __u32 portid, int seq, void *data, size_t datasz); +extern int audit_list_rules_send(__u32 portid, int seq); + extern int audit_enabled; #else /* CONFIG_AUDIT */ static inline __printf(4, 5) diff --git a/kernel/audit.c b/kernel/audit.c index fdb8528..c460f33 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -903,11 +903,12 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) audit_log_end(ab); return -EPERM; } - /* fallthrough */ - case AUDIT_LIST_RULES: - err = audit_receive_filter(msg_type, NETLINK_CB(skb).portid, + err = audit_rule_change(msg_type, NETLINK_CB(skb).portid, seq, data, nlmsg_len(nlh)); break; + case AUDIT_LIST_RULES: + err = audit_list_rules_send(NETLINK_CB(skb).portid, seq); + break; case AUDIT_TRIM: audit_trim_trees(); audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index d085cfb..6cc8240 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1023,47 +1023,20 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re } /** - * audit_receive_filter - apply all rules to the specified message type + * audit_rule_change - apply all rules to the specified message type * @type: audit message type * @portid: target port id for netlink audit messages * @seq: netlink audit message sequence (serial) number * @data: payload data * @datasz: size of payload data */ -int audit_receive_filter(int type, __u32 portid, int seq, void *data, - size_t datasz) +int audit_rule_change(int type, __u32 portid, int seq, void *data, + size_t datasz) { - struct task_struct *tsk; - struct audit_netlink_list *dest; int err = 0; struct audit_entry *entry; switch (type) { - case AUDIT_LIST_RULES: - /* We can't just spew out the rules here because we might fill - * the available socket buffer space and deadlock waiting for - * auditctl to read from it... which isn't ever going to - * happen if we're actually running in the context of auditctl - * trying to _send_ the stuff */ - - dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL); - if (!dest) - return -ENOMEM; - dest->portid = portid; - dest->pid = task_pid_vnr(current); - skb_queue_head_init(&dest->q); - - mutex_lock(&audit_filter_mutex); - audit_list_rules(portid, seq, &dest->q); - mutex_unlock(&audit_filter_mutex); - - tsk = kthread_run(audit_send_list, dest, "audit_send_list"); - if (IS_ERR(tsk)) { - skb_queue_purge(&dest->q); - kfree(dest); - err = PTR_ERR(tsk); - } - break; case AUDIT_ADD_RULE: entry = audit_data_to_entry(data, datasz); if (IS_ERR(entry)) @@ -1090,6 +1063,44 @@ int audit_receive_filter(int type, __u32 portid, int seq, void *data, return err; } +/** + * audit_list_rules_send - list the audit rules + * @portid: target portid for netlink audit messages + * @seq: netlink audit message sequence (serial) number + */ +int audit_list_rules_send(__u32 portid, int seq) +{ + struct task_struct *tsk; + struct audit_netlink_list *dest; + int err = 0; + + /* We can't just spew out the rules here because we might fill + * the available socket buffer space and deadlock waiting for + * auditctl to read from it... which isn't ever going to + * happen if we're actually running in the context of auditctl + * trying to _send_ the stuff */ + + dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL); + if (!dest) + return -ENOMEM; + dest->portid = portid; + dest->pid = task_pid_vnr(current); + skb_queue_head_init(&dest->q); + + mutex_lock(&audit_filter_mutex); + audit_list_rules(portid, seq, &dest->q); + mutex_unlock(&audit_filter_mutex); + + tsk = kthread_run(audit_send_list, dest, "audit_send_list"); + if (IS_ERR(tsk)) { + skb_queue_purge(&dest->q); + kfree(dest); + err = PTR_ERR(tsk); + } + + return err; +} + int audit_comparator(u32 left, u32 op, u32 right) { switch (op) { -- cgit v0.10.2 From 34eab0a7cd45ce0eab744a86a85d83aa7ddf99a5 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Fri, 21 Jun 2013 14:47:13 -0400 Subject: audit: prevent an older auditd shutdown from orphaning a newer auditd startup There have been reports of auditd restarts resulting in kaudit not being able to find a newly registered auditd. It results in reports such as: kernel: [ 2077.233573] audit: *NO* daemon at audit_pid=1614 kernel: [ 2077.234712] audit: audit_lost=97 audit_rate_limit=0 audit_backlog_limit=320 kernel: [ 2077.234718] audit: auditd disappeared (previously mis-spelled "dissapeared") One possible cause is a race between the shutdown of an older auditd and a newer one. If the newer one sets the daemon pid to itself in kauditd before the older one has cleared the daemon pid, the newer daemon pid will be erased. This could be caused by an automated system, or by manual intervention, but in either case, there is no use in having the older daemon clear the daemon pid reference since its old pid is no longer being referenced. This patch will prevent that specific case, returning an error of EACCES. The case for preventing a newer auditd from registering itself if there is an existing auditd is a more difficult case that is beyond the scope of this patch. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index c460f33..f207289 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -815,6 +815,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (s.mask & AUDIT_STATUS_PID) { int new_pid = s.pid; + if ((!new_pid) && (task_tgid_vnr(current) != audit_pid)) + return -EACCES; if (audit_enabled != AUDIT_OFF) audit_log_config_change("audit_pid", new_pid, audit_pid, 1); audit_pid = new_pid; -- cgit v0.10.2 From ff235f51a138fc61e1a22dcb8b072d9c78c2a8cc Mon Sep 17 00:00:00 2001 From: Paul Davies C Date: Thu, 21 Nov 2013 08:14:03 +0530 Subject: audit: Added exe field to audit core dump signal log Currently when the coredump signals are logged by the audit system, the actual path to the executable is not logged. Without details of exe, the system admin may not have an exact idea on what program failed. This patch changes the audit_log_task() so that the path to the exe is also logged. This was copied from audit_log_task_info() and the latter enhanced to avoid disappearing text fields. Signed-off-by: Paul Davies C Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index f207289..25e4ed0 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1859,7 +1859,8 @@ void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk) if (mm->exe_file) audit_log_d_path(ab, " exe=", &mm->exe_file->f_path); up_read(&mm->mmap_sem); - } + } else + audit_log_format(ab, " exe=(null)"); audit_log_task_context(ab); } EXPORT_SYMBOL(audit_log_task_info); diff --git a/kernel/auditsc.c b/kernel/auditsc.c index fc3b3db..05634b3 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -2353,6 +2353,7 @@ static void audit_log_task(struct audit_buffer *ab) kuid_t auid, uid; kgid_t gid; unsigned int sessionid; + struct mm_struct *mm = current->mm; auid = audit_get_loginuid(current); sessionid = audit_get_sessionid(current); @@ -2366,6 +2367,13 @@ static void audit_log_task(struct audit_buffer *ab) audit_log_task_context(ab); audit_log_format(ab, " pid=%d comm=", current->pid); audit_log_untrustedstring(ab, current->comm); + if (mm) { + down_read(&mm->mmap_sem); + if (mm->exe_file) + audit_log_d_path(ab, " exe=", &mm->exe_file->f_path); + up_read(&mm->mmap_sem); + } else + audit_log_format(ab, " exe=(null)"); } /** -- cgit v0.10.2 From 4440e8548153e9e6d56db9abe6f3bc0e5b9eb74f Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Wed, 27 Nov 2013 17:35:17 -0500 Subject: audit: convert all sessionid declaration to unsigned int Right now the sessionid value in the kernel is a combination of u32, int, and unsigned int. Just use unsigned int throughout. Signed-off-by: Eric Paris Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c index a4fdce7..b0e5401 100644 --- a/drivers/tty/tty_audit.c +++ b/drivers/tty/tty_audit.c @@ -67,7 +67,7 @@ static void tty_audit_log(const char *description, int major, int minor, struct task_struct *tsk = current; uid_t uid = from_kuid(&init_user_ns, task_uid(tsk)); uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(tsk)); - u32 sessionid = audit_get_sessionid(tsk); + unsigned int sessionid = audit_get_sessionid(tsk); ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY); if (ab) { diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 5cd0f09..a143df5 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -95,7 +95,7 @@ extern struct group_info init_groups; #ifdef CONFIG_AUDITSYSCALL #define INIT_IDS \ .loginuid = INVALID_UID, \ - .sessionid = -1, + .sessionid = (unsigned int)-1, #else #define INIT_IDS #endif diff --git a/include/net/netlabel.h b/include/net/netlabel.h index 2c95d55..97e6dca 100644 --- a/include/net/netlabel.h +++ b/include/net/netlabel.h @@ -111,7 +111,7 @@ struct cipso_v4_doi; struct netlbl_audit { u32 secid; kuid_t loginuid; - u32 sessionid; + unsigned int sessionid; }; /* diff --git a/include/net/xfrm.h b/include/net/xfrm.h index e253bf0..f8d32b9 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -679,7 +679,7 @@ struct xfrm_spi_skb_cb { struct xfrm_audit { u32 secid; kuid_t loginuid; - u32 sessionid; + unsigned int sessionid; }; #ifdef CONFIG_AUDITSYSCALL @@ -697,7 +697,7 @@ static inline struct audit_buffer *xfrm_audit_start(const char *op) return audit_buf; } -static inline void xfrm_audit_helper_usrinfo(kuid_t auid, u32 ses, u32 secid, +static inline void xfrm_audit_helper_usrinfo(kuid_t auid, unsigned int ses, u32 secid, struct audit_buffer *audit_buf) { char *secctx; @@ -714,13 +714,13 @@ static inline void xfrm_audit_helper_usrinfo(kuid_t auid, u32 ses, u32 secid, } extern void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, - kuid_t auid, u32 ses, u32 secid); + kuid_t auid, unsigned int ses, u32 secid); extern void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, - kuid_t auid, u32 ses, u32 secid); + kuid_t auid, unsigned int ses, u32 secid); extern void xfrm_audit_state_add(struct xfrm_state *x, int result, - kuid_t auid, u32 ses, u32 secid); + kuid_t auid, unsigned int ses, u32 secid); extern void xfrm_audit_state_delete(struct xfrm_state *x, int result, - kuid_t auid, u32 ses, u32 secid); + kuid_t auid, unsigned int ses, u32 secid); extern void xfrm_audit_state_replay_overflow(struct xfrm_state *x, struct sk_buff *skb); extern void xfrm_audit_state_replay(struct xfrm_state *x, @@ -733,22 +733,22 @@ extern void xfrm_audit_state_icvfail(struct xfrm_state *x, #else static inline void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, - kuid_t auid, u32 ses, u32 secid) + kuid_t auid, unsigned int ses, u32 secid) { } static inline void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, - kuid_t auid, u32 ses, u32 secid) + kuid_t auid, unsigned int ses, u32 secid) { } static inline void xfrm_audit_state_add(struct xfrm_state *x, int result, - kuid_t auid, u32 ses, u32 secid) + kuid_t auid, unsigned int ses, u32 secid) { } static inline void xfrm_audit_state_delete(struct xfrm_state *x, int result, - kuid_t auid, u32 ses, u32 secid) + kuid_t auid, unsigned int ses, u32 secid) { } diff --git a/kernel/audit.c b/kernel/audit.c index 25e4ed0..ce8514f9 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1611,7 +1611,7 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix, void audit_log_session_info(struct audit_buffer *ab) { - u32 sessionid = audit_get_sessionid(current); + unsigned int sessionid = audit_get_sessionid(current); uid_t auid = from_kuid(&init_user_ns, audit_get_loginuid(current)); audit_log_format(ab, " auid=%u ses=%u", auid, sessionid); diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 6cc8240..629834a 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1005,7 +1005,7 @@ static void audit_log_rule_change(char *action, struct audit_krule *rule, int re { struct audit_buffer *ab; uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(current)); - u32 sessionid = audit_get_sessionid(current); + unsigned int sessionid = audit_get_sessionid(current); if (!audit_enabled) return; diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 05634b3..5c23734 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -2011,7 +2011,7 @@ int audit_set_loginuid(kuid_t loginuid) /* are we setting or clearing? */ if (uid_valid(loginuid)) - sessionid = atomic_inc_return(&session_id); + sessionid = (unsigned int)atomic_inc_return(&session_id); task->sessionid = sessionid; task->loginuid = loginuid; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 76e1873..767c74a 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2899,12 +2899,12 @@ static void xfrm_policy_fini(struct net *net) flush_work(&net->xfrm.policy_hash_work); #ifdef CONFIG_XFRM_SUB_POLICY audit_info.loginuid = INVALID_UID; - audit_info.sessionid = -1; + audit_info.sessionid = (unsigned int)-1; audit_info.secid = 0; xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info); #endif audit_info.loginuid = INVALID_UID; - audit_info.sessionid = -1; + audit_info.sessionid = (unsigned int)-1; audit_info.secid = 0; xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); @@ -3010,7 +3010,7 @@ static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp, } void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, - kuid_t auid, u32 sessionid, u32 secid) + kuid_t auid, unsigned int sessionid, u32 secid) { struct audit_buffer *audit_buf; @@ -3025,7 +3025,7 @@ void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, EXPORT_SYMBOL_GPL(xfrm_audit_policy_add); void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, - kuid_t auid, u32 sessionid, u32 secid) + kuid_t auid, unsigned int sessionid, u32 secid) { struct audit_buffer *audit_buf; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index b9c3f9e..dbf0719 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -2043,7 +2043,7 @@ void xfrm_state_fini(struct net *net) flush_work(&net->xfrm.state_hash_work); audit_info.loginuid = INVALID_UID; - audit_info.sessionid = -1; + audit_info.sessionid = (unsigned int)-1; audit_info.secid = 0; xfrm_state_flush(net, IPSEC_PROTO_ANY, &audit_info); flush_work(&net->xfrm.state_gc_work); @@ -2109,7 +2109,7 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, } void xfrm_audit_state_add(struct xfrm_state *x, int result, - kuid_t auid, u32 sessionid, u32 secid) + kuid_t auid, unsigned int sessionid, u32 secid) { struct audit_buffer *audit_buf; @@ -2124,7 +2124,7 @@ void xfrm_audit_state_add(struct xfrm_state *x, int result, EXPORT_SYMBOL_GPL(xfrm_audit_state_add); void xfrm_audit_state_delete(struct xfrm_state *x, int result, - kuid_t auid, u32 sessionid, u32 secid) + kuid_t auid, unsigned int sessionid, u32 secid) { struct audit_buffer *audit_buf; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index f964d4c..ec97e13 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -600,7 +600,7 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, int err; struct km_event c; kuid_t loginuid = audit_get_loginuid(current); - u32 sessionid = audit_get_sessionid(current); + unsigned int sessionid = audit_get_sessionid(current); u32 sid; err = verify_newsa_info(p, attrs); @@ -679,7 +679,7 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct km_event c; struct xfrm_usersa_id *p = nlmsg_data(nlh); kuid_t loginuid = audit_get_loginuid(current); - u32 sessionid = audit_get_sessionid(current); + unsigned int sessionid = audit_get_sessionid(current); u32 sid; x = xfrm_user_state_lookup(net, p, attrs, &err); @@ -1405,7 +1405,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, int err; int excl; kuid_t loginuid = audit_get_loginuid(current); - u32 sessionid = audit_get_sessionid(current); + unsigned int sessionid = audit_get_sessionid(current); u32 sid; err = verify_newpolicy_info(p); @@ -1663,7 +1663,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, } } else { kuid_t loginuid = audit_get_loginuid(current); - u32 sessionid = audit_get_sessionid(current); + unsigned int sessionid = audit_get_sessionid(current); u32 sid; security_task_getsecid(current, &sid); @@ -1959,7 +1959,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, err = 0; if (up->hard) { kuid_t loginuid = audit_get_loginuid(current); - u32 sessionid = audit_get_sessionid(current); + unsigned int sessionid = audit_get_sessionid(current); u32 sid; security_task_getsecid(current, &sid); @@ -2002,7 +2002,7 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, if (ue->hard) { kuid_t loginuid = audit_get_loginuid(current); - u32 sessionid = audit_get_sessionid(current); + unsigned int sessionid = audit_get_sessionid(current); u32 sid; security_task_getsecid(current, &sid); -- cgit v0.10.2 From 9ad42a79247d5e16d26f7d1531a68f20a889c5af Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Thu, 21 Nov 2013 13:31:40 -0500 Subject: selinux: call WARN_ONCE() instead of calling audit_log_start() Two of the conditions in selinux_audit_rule_match() should never happen and the third indicates a race that should be retried. Remove the calls to audit_log() (which call audit_log_start()) and deal with the errors in the caller, logging only once if the condition is met. Calling audit_log_start() in this location makes buffer allocation and locking more complicated in the calling tree (audit_filter_user()). Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b4feecc..f4dda05 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2938,25 +2938,21 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, struct selinux_audit_rule *rule = vrule; int match = 0; - if (!rule) { - audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, - "selinux_audit_rule_match: missing rule\n"); + if (unlikely(!rule)) { + WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n"); return -ENOENT; } read_lock(&policy_rwlock); if (rule->au_seqno < latest_granting) { - audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, - "selinux_audit_rule_match: stale rule\n"); match = -ESTALE; goto out; } ctxt = sidtab_search(&sidtab, sid); - if (!ctxt) { - audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, - "selinux_audit_rule_match: unrecognized SID %d\n", + if (unlikely(!ctxt)) { + WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", sid); match = -ENOENT; goto out; -- cgit v0.10.2 From 4eb0f4abfb9441849530ea19389ae57cc62c8078 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Thu, 21 Nov 2013 13:57:33 -0500 Subject: smack: call WARN_ONCE() instead of calling audit_log_start() Remove the call to audit_log() (which call audit_log_start()) and deal with the errors in the caller, logging only once if the condition is met. Calling audit_log_start() in this location makes buffer allocation and locking more complicated in the calling tree (audit_filter_user()). Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 8825375..185e2e7 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3615,9 +3615,8 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, struct smack_known *skp; char *rule = vrule; - if (!rule) { - audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, - "Smack: missing rule\n"); + if (unlikely(!rule)) { + WARN_ONCE(1, "Smack: missing rule\n"); return -ENOENT; } -- cgit v0.10.2 From 1b7b533f65db9b31f76972b2899ec7ec6433ae77 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Mon, 2 Dec 2013 11:33:01 -0500 Subject: audit: drop audit_cmd_lock in AUDIT_USER family of cases We do not need to hold the audit_cmd_mutex for this family of cases. The possible exception to this is the call to audit_filter_user(), so drop the lock immediately after. To help in fixing the race we are trying to avoid, make sure that nothing called by audit_filter_user() calls audit_log_start(). In particular, watch out for *_audit_rule_match(). This fix will take care of systemd and anything USING audit. It still means that we could race with something configuring audit and auditd shutting down. Signed-off-by: Richard Guy Briggs Reported-by: toshi.okajima@jp.fujitsu.com Tested-by: toshi.okajima@jp.fujitsu.com Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index ce8514f9..c05b602 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -876,6 +876,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (err) break; } + mutex_unlock(&audit_cmd_mutex); audit_log_common_recv_msg(&ab, msg_type); if (msg_type != AUDIT_USER_TTY) audit_log_format(ab, " msg='%.*s'", @@ -893,6 +894,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) } audit_set_portid(ab, NETLINK_CB(skb).portid); audit_log_end(ab); + mutex_lock(&audit_cmd_mutex); } break; case AUDIT_ADD_RULE: -- cgit v0.10.2 From 6dd80aba90639d1765396aa5e5f55e34dc3356e5 Mon Sep 17 00:00:00 2001 From: Toshiyuki Okajima Date: Thu, 5 Dec 2013 16:15:23 +0900 Subject: audit: audit_log_start running on auditd should not stop The backlog cannot be consumed when audit_log_start is running on auditd even if audit_log_start calls wait_for_auditd to consume it. The situation is the deadlock because only auditd can consume the backlog. If the other process needs to send the backlog, it can be also stopped by the deadlock. So, audit_log_start running on auditd should not stop. You can see the deadlock with the following reproducer: # auditctl -a exit,always -S all # reboot Signed-off-by: Toshiyuki Okajima Reviewed-by: gaofeng@cn.fujitsu.com Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index c05b602..9c4ec29 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1319,7 +1319,8 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, struct audit_buffer *ab = NULL; struct timespec t; unsigned int uninitialized_var(serial); - int reserve; + int reserve = 5; /* Allow atomic callers to go up to five + entries over the normal backlog limit */ unsigned long timeout_start = jiffies; if (audit_initialized != AUDIT_INITIALIZED) @@ -1328,11 +1329,12 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, if (unlikely(audit_filter_type(type))) return NULL; - if (gfp_mask & __GFP_WAIT) - reserve = 0; - else - reserve = 5; /* Allow atomic callers to go up to five - entries over the normal backlog limit */ + if (gfp_mask & __GFP_WAIT) { + if (audit_pid && audit_pid == current->pid) + gfp_mask &= ~__GFP_WAIT; + else + reserve = 0; + } while (audit_backlog_limit && skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) { -- cgit v0.10.2 From 724e4fcc8d80c63c7e56873b41987533db2a04c2 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Mon, 25 Nov 2013 21:57:51 -0500 Subject: audit: log on errors from filter user rules An error on an AUDIT_NEVER rule disabled logging on that rule. On error on AUDIT_NEVER rules, log. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 9c4ec29..15661ef 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -869,7 +869,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return 0; err = audit_filter_user(msg_type); - if (err == 1) { + if (err == 1) { /* match or error */ err = 0; if (msg_type == AUDIT_USER_TTY) { err = tty_audit_push_current(); diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 629834a..14a78cc 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -1290,19 +1290,22 @@ int audit_filter_user(int type) { enum audit_state state = AUDIT_DISABLED; struct audit_entry *e; - int ret = 1; + int rc, ret; + + ret = 1; /* Audit by default */ rcu_read_lock(); list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) { - if (audit_filter_user_rules(&e->rule, type, &state)) { - if (state == AUDIT_DISABLED) + rc = audit_filter_user_rules(&e->rule, type, &state); + if (rc) { + if (rc > 0 && state == AUDIT_DISABLED) ret = 0; break; } } rcu_read_unlock(); - return ret; /* Audit by default */ + return ret; } int audit_filter_type(int type) -- cgit v0.10.2 From 5ee9a75c9fdaebd3ac8176f9f5c73fdcd27c1ad1 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Wed, 11 Dec 2013 15:28:09 -0500 Subject: audit: fix dangling keywords in audit_log_set_loginuid() output Remove spaces between "new", "old" label modifiers and "auid", "ses" labels in log output since userspace tools can't parse orphaned keywords. Make variable names more consistent and intuitive. Make audit_log_format() argument code easier to read. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 5c23734..10176cd 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -1969,21 +1969,24 @@ static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid, int rc) { struct audit_buffer *ab; - uid_t uid, ologinuid, nloginuid; + uid_t uid, oldloginuid, loginuid; if (!audit_enabled) return; uid = from_kuid(&init_user_ns, task_uid(current)); - ologinuid = from_kuid(&init_user_ns, koldloginuid); - nloginuid = from_kuid(&init_user_ns, kloginuid), + oldloginuid = from_kuid(&init_user_ns, koldloginuid); + loginuid = from_kuid(&init_user_ns, kloginuid), ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN); if (!ab) return; - audit_log_format(ab, "pid=%d uid=%u old auid=%u new auid=%u old " - "ses=%u new ses=%u res=%d", current->pid, uid, ologinuid, - nloginuid, oldsessionid, sessionid, !rc); + audit_log_format(ab, "pid=%d uid=%u" + " old-auid=%u new-auid=%u old-ses=%u new-ses=%u" + " res=%d", + current->pid, uid, + oldloginuid, loginuid, oldsessionid, sessionid, + !rc); audit_log_end(ab); } -- cgit v0.10.2 From 11ee39ebf756821966fe1e2f65df4f728098d467 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Tue, 17 Dec 2013 11:10:41 +0800 Subject: audit: print error message when fail to create audit socket print the error message and then return -ENOMEM. Signed-off-by: Gao feng Acked-by: Eric Paris Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 15661ef..b27b706 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1082,12 +1082,11 @@ static int __net_init audit_net_init(struct net *net) pr_info("audit: initializing netlink socket in namespace\n"); aunet->nlsk = netlink_kernel_create(net, NETLINK_AUDIT, &cfg); - if (aunet->nlsk == NULL) - return -ENOMEM; - if (!aunet->nlsk) + if (aunet->nlsk == NULL) { audit_panic("cannot initialize netlink socket in namespace"); - else - aunet->nlsk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; + return -ENOMEM; + } + aunet->nlsk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; return 0; } -- cgit v0.10.2 From de92fc97e12d4b9170d1ab3dbccbdcb8c56add31 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Tue, 17 Dec 2013 11:10:42 +0800 Subject: audit: fix incorrect set of audit_sock NETLINK_CB(skb).sk is the socket of user space process, netlink_unicast in kauditd_send_skb wants the kernel side socket. Since the sk_state of audit netlink socket is not NETLINK_CONNECTED, so the netlink_getsockbyportid doesn't return -ECONNREFUSED. And the socket of userspace process can be released anytime, so the audit_sock may point to invalid socket. this patch sets the audit_sock to the kernel side audit netlink socket. Signed-off-by: Gao feng Acked-by: Eric Paris Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index b27b706..ef5bd63 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -821,7 +821,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) audit_log_config_change("audit_pid", new_pid, audit_pid, 1); audit_pid = new_pid; audit_nlk_portid = NETLINK_CB(skb).portid; - audit_sock = NETLINK_CB(skb).sk; + audit_sock = skb->sk; } if (s.mask & AUDIT_STATUS_RATE_LIMIT) { err = audit_set_rate_limit(s.rate_limit); -- cgit v0.10.2 From ad2ac263278620205555a572c29b3ebb4a5bce3b Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Tue, 7 Jan 2014 13:08:41 -0500 Subject: audit: log task info on feature change Add task information to the log when changing a feature state. Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index ef5bd63..40b28b5 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -688,6 +688,7 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature return; ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE); + audit_log_task_info(ab, current); audit_log_format(ab, "feature=%s old=%d new=%d old_lock=%d new_lock=%d res=%d", audit_feature_names[which], !!old_feature, !!new_feature, !!old_lock, !!new_lock, res); -- cgit v0.10.2 From 8c8115faca28c7118e2a5b0153998710ea3e01c4 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Mon, 23 Dec 2013 16:56:43 -0500 Subject: audit: update MAINTAINERS Al's tree is stale and no longer updated. Al is no longer active in maitaining audit. Eric's tree is authoritative. Signed-off-by: Eric Paris diff --git a/MAINTAINERS b/MAINTAINERS index ffcaf97..bfbfe51 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1584,11 +1584,10 @@ S: Supported F: drivers/scsi/esas2r AUDIT SUBSYSTEM -M: Al Viro M: Eric Paris L: linux-audit@redhat.com (subscribers-only) W: http://people.redhat.com/sgrubb/audit/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current.git +T: git git://git.infradead.org/users/eparis/audit.git S: Maintained F: include/linux/audit.h F: include/uapi/linux/audit.h -- cgit v0.10.2 From c81825dd6b2ab9dcbdbc5b3ae12cc724c550341d Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 13 Jan 2014 15:42:16 -0500 Subject: audit: wait_for_auditd rework for readability We had some craziness with signed to unsigned long casting which appears wholely unnecessary. Just use signed long. Even though 2 values of the math equation are unsigned longs the result is expected to be a signed long. So why keep casting the result to signed long? Just make it signed long and use it. We also remove the needless "timeout" variable. We already have the stack "sleep_time" variable. Just use that... Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 40b28b5..57d47f0 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1281,21 +1281,20 @@ static inline void audit_get_stamp(struct audit_context *ctx, /* * Wait for auditd to drain the queue a little */ -static unsigned long wait_for_auditd(unsigned long sleep_time) +static long wait_for_auditd(long sleep_time) { - unsigned long timeout = sleep_time; DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue_exclusive(&audit_backlog_wait, &wait); if (audit_backlog_limit && skb_queue_len(&audit_skb_queue) > audit_backlog_limit) - timeout = schedule_timeout(sleep_time); + sleep_time = schedule_timeout(sleep_time); __set_current_state(TASK_RUNNING); remove_wait_queue(&audit_backlog_wait, &wait); - return timeout; + return sleep_time; } /** @@ -1339,13 +1338,12 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, while (audit_backlog_limit && skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) { if (gfp_mask & __GFP_WAIT && audit_backlog_wait_time) { - unsigned long sleep_time; + long sleep_time; - sleep_time = timeout_start + audit_backlog_wait_time - - jiffies; - if ((long)sleep_time > 0) { + sleep_time = timeout_start + audit_backlog_wait_time - jiffies; + if (sleep_time > 0) { sleep_time = wait_for_auditd(sleep_time); - if ((long)sleep_time > 0) + if (sleep_time > 0) continue; } } -- cgit v0.10.2 From d7961148258cfe19908b5a29941a8c9f3fa7a4d6 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 13 Jan 2014 16:01:06 -0500 Subject: audit: documentation of audit= kernel parameter Further documentation of the 3 possible kernel value of the audit command line option. Signed-off-by: Eric Paris diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index ab86766..e81e1d0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -465,6 +465,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. audit= [KNL] Enable the audit sub-system Format: { "0" | "1" } (0 = disabled, 1 = enabled) + 0 - kernel audit is disabled and can not be enabled + until the next reboot + unset - kernel audit is initialized but disabled and + will be fully enabled by the userspace auditd. + 1 - kernel audit is initialized and partially enabled, + storing at most audit_backlog_limit messages in + RAM until it is fully enabled by the userspace + auditd. Default: unset audit_backlog_limit= [KNL] Set the audit queue size limit. -- cgit v0.10.2 From 70249a9cfdb405f654708699c679c6774efb31d8 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 13 Jan 2014 16:48:45 -0500 Subject: audit: use define's for audit version Give names to the audit versions. Just something for a userspace programmer to know what the version provides. Signed-off-by: Eric Paris diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h index 14afb0d..3e1fbe9 100644 --- a/include/uapi/linux/audit.h +++ b/include/uapi/linux/audit.h @@ -320,6 +320,11 @@ enum { #define AUDIT_STATUS_RATE_LIMIT 0x0008 #define AUDIT_STATUS_BACKLOG_LIMIT 0x0010 #define AUDIT_STATUS_BACKLOG_WAIT_TIME 0x0020 + +#define AUDIT_VERSION_BACKLOG_LIMIT 1 +#define AUDIT_VERSION_BACKLOG_WAIT_TIME 2 +#define AUDIT_VERSION_LATEST AUDIT_VERSION_BACKLOG_WAIT_TIME + /* Failure-to-log actions */ #define AUDIT_FAIL_SILENT 0 #define AUDIT_FAIL_PRINTK 1 diff --git a/kernel/audit.c b/kernel/audit.c index 57d47f0..b671723 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -792,7 +792,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) s.backlog_limit = audit_backlog_limit; s.lost = atomic_read(&audit_lost); s.backlog = skb_queue_len(&audit_skb_queue); - s.version = 2; + s.version = AUDIT_VERSION_LATEST; s.backlog_wait_time = audit_backlog_wait_time; audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0, &s, sizeof(s)); -- cgit v0.10.2 From 3f0c5fad89c2c287baee0f314177b82aeafa7363 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 13 Jan 2014 16:49:28 -0500 Subject: audit: remove needless switch in AUDIT_SET If userspace specified that it was setting values via the mask we do not need a second check to see if they also set the version field high enough to understand those values. (clearly if they set the mask they knew those values). Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index b671723..ab2e3d8 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -834,22 +834,15 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (err < 0) return err; } - switch (s.version) { - /* add future vers # cases immediately below and allow - * to fall through */ - case 2: - if (s.mask & AUDIT_STATUS_BACKLOG_WAIT_TIME) { - if (sizeof(s) > (size_t)nlh->nlmsg_len) - return -EINVAL; - if (s.backlog_wait_time < 0 || - s.backlog_wait_time > 10*AUDIT_BACKLOG_WAIT_TIME) - return -EINVAL; - err = audit_set_backlog_wait_time(s.backlog_wait_time); - if (err < 0) - return err; - } - default: - break; + if (s.mask & AUDIT_STATUS_BACKLOG_WAIT_TIME) { + if (sizeof(s) > (size_t)nlh->nlmsg_len) + return -EINVAL; + if (s.backlog_wait_time < 0 || + s.backlog_wait_time > 10*AUDIT_BACKLOG_WAIT_TIME) + return -EINVAL; + err = audit_set_backlog_wait_time(s.backlog_wait_time); + if (err < 0) + return err; } break; } -- cgit v0.10.2 From 0e23baccaae4f752cfa89cca44e84a439ed8bd13 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 13 Jan 2014 21:12:34 -0500 Subject: audit: rework AUDIT_TTY_SET to only grab spin_lock once We can simplify the AUDIT_TTY_SET code to only grab the spin_lock one time. We need to determine if the new values are valid and if so, set the new values at the same time we grab the old onces. While we are here get rid of 'res' and just use err. Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index ab2e3d8..b1d24a0 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -991,19 +991,24 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) struct audit_tty_status s, old; struct task_struct *tsk = current; struct audit_buffer *ab; - int res = 0; + + memset(&s, 0, sizeof(s)); + /* guard against past and future API changes */ + memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh))); + /* check if new data is valid */ + if ((s.enabled != 0 && s.enabled != 1) || + (s.log_passwd != 0 && s.log_passwd != 1)) + err = -EINVAL; spin_lock(&tsk->sighand->siglock); old.enabled = tsk->signal->audit_tty; old.log_passwd = tsk->signal->audit_tty_log_passwd; + if (!err) { + tsk->signal->audit_tty = s.enabled; + tsk->signal->audit_tty_log_passwd = s.log_passwd; + } spin_unlock(&tsk->sighand->siglock); - memset(&s, 0, sizeof(s)); - /* guard against past and future API changes */ - memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh))); - if ((s.enabled == 0 || s.enabled == 1) && - (s.log_passwd == 0 || s.log_passwd == 1)) - res = 1; audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); audit_log_format(ab, " op=tty_set" " old-enabled=%d old-log_passwd=%d" @@ -1011,15 +1016,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) " res=%d", old.enabled, old.log_passwd, s.enabled, s.log_passwd, - res); + !err); audit_log_end(ab); - if (res) { - spin_lock(&tsk->sighand->siglock); - tsk->signal->audit_tty = s.enabled; - tsk->signal->audit_tty_log_passwd = s.log_passwd; - spin_unlock(&tsk->sighand->siglock); - } else - return -EINVAL; break; } default: -- cgit v0.10.2 From 1ce319f11ccc5ee5ed1bc1e020f1ac6e6d689c74 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Mon, 13 Jan 2014 21:16:59 -0500 Subject: audit: reorder AUDIT_TTY_SET arguments An admin is likely to want to see old and new values next to each other. Putting all of the old values followed by all of the new values is just hard to read as a human. Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index b1d24a0..9daf243 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1010,13 +1010,10 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) spin_unlock(&tsk->sighand->siglock); audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); - audit_log_format(ab, " op=tty_set" - " old-enabled=%d old-log_passwd=%d" - " new-enabled=%d new-log_passwd=%d" - " res=%d", - old.enabled, old.log_passwd, - s.enabled, s.log_passwd, - !err); + audit_log_format(ab, " op=tty_set old-enabled=%d new-enabled=%d" + " old-log_passwd=%d new-log_passwd=%d res=%d", + old.enabled, s.enabled, old.log_passwd, + s.log_passwd, !err); audit_log_end(ab); break; } -- cgit v0.10.2 From 06bdadd7634551cfe8ce071fe44d0311b3033d9e Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Mon, 13 Jan 2014 13:33:09 -0800 Subject: audit: correct a type mismatch in audit_syscall_exit() audit_syscall_exit() saves a result of regs_return_value() in intermediate "int" variable and passes it to __audit_syscall_exit(), which expects its second argument as a "long" value. This will result in truncating the value returned by a system call and making a wrong audit record. I don't know why gcc compiler doesn't complain about this, but anyway it causes a problem at runtime on arm64 (and probably most 64-bit archs). Signed-off-by: AKASHI Takahiro Cc: Al Viro Cc: Eric Paris Cc: Signed-off-by: Andrew Morton Signed-off-by: Eric Paris diff --git a/include/linux/audit.h b/include/linux/audit.h index 6976219..98fe8a2 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -137,7 +137,7 @@ static inline void audit_syscall_exit(void *pt_regs) { if (unlikely(current->audit_context)) { int success = is_syscall_success(pt_regs); - int return_code = regs_return_value(pt_regs); + long return_code = regs_return_value(pt_regs); __audit_syscall_exit(success, return_code); } -- cgit v0.10.2 From b8dbc3241fff043213e8be8e798d45eb6ed28b96 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 13 Jan 2014 23:31:27 -0800 Subject: audit: Use hex_byte_pack_upper Using the generic kernel function causes the object size to increase with gcc 4.8.1. $ size kernel/audit.o* text data bss dec hex filename 18577 6079 8436 33092 8144 kernel/audit.o.new 18579 6015 8420 33014 80f6 kernel/audit.o.old Unsigned... diff --git a/kernel/audit.c b/kernel/audit.c index 9daf243..b5e6fd8 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1466,7 +1466,6 @@ void audit_log_n_hex(struct audit_buffer *ab, const unsigned char *buf, int i, avail, new_len; unsigned char *ptr; struct sk_buff *skb; - static const unsigned char *hex = "0123456789ABCDEF"; if (!ab) return; @@ -1484,10 +1483,8 @@ void audit_log_n_hex(struct audit_buffer *ab, const unsigned char *buf, } ptr = skb_tail_pointer(skb); - for (i=0; i>4]; /* Upper nibble */ - *ptr++ = hex[buf[i] & 0x0F]; /* Lower nibble */ - } + for (i = 0; i < len; i++) + ptr = hex_byte_pack_upper(ptr, buf[i]); *ptr = 0; skb_put(skb, len << 1); /* new string is twice the old string */ } -- cgit v0.10.2 From d957f7b726ccce4967ae0d668b5b10f0f1d10401 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 14 Jan 2014 10:33:12 -0800 Subject: audit: Use more current logging style Add pr_fmt to prefix "audit: " to output Convert printk(KERN_ to pr_ Coalesce formats Use pr_cont Move a brace after switch Signed-off-by: Joe Perches diff --git a/kernel/audit.c b/kernel/audit.c index b5e6fd8..5f4766f 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -41,6 +41,8 @@ * Example user-space utilities: http://people.redhat.com/sgrubb/audit/ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -194,13 +196,12 @@ static void audit_set_portid(struct audit_buffer *ab, __u32 portid) void audit_panic(const char *message) { - switch (audit_failure) - { + switch (audit_failure) { case AUDIT_FAIL_SILENT: break; case AUDIT_FAIL_PRINTK: if (printk_ratelimit()) - printk(KERN_ERR "audit: %s\n", message); + pr_err("%s\n", message); break; case AUDIT_FAIL_PANIC: /* test audit_pid since printk is always losey, why bother? */ @@ -271,9 +272,7 @@ void audit_log_lost(const char *message) if (print) { if (printk_ratelimit()) - printk(KERN_WARNING - "audit: audit_lost=%d audit_rate_limit=%d " - "audit_backlog_limit=%d\n", + pr_warn("audit_lost=%d audit_rate_limit=%d audit_backlog_limit=%d\n", atomic_read(&audit_lost), audit_rate_limit, audit_backlog_limit); @@ -394,7 +393,7 @@ static void audit_printk_skb(struct sk_buff *skb) if (nlh->nlmsg_type != AUDIT_EOE) { if (printk_ratelimit()) - printk(KERN_NOTICE "type=%d %s\n", nlh->nlmsg_type, data); + pr_notice("type=%d %s\n", nlh->nlmsg_type, data); else audit_log_lost("printk limit exceeded\n"); } @@ -411,7 +410,7 @@ static void kauditd_send_skb(struct sk_buff *skb) if (err < 0) { BUG_ON(err != -ECONNREFUSED); /* Shouldn't happen */ if (audit_pid) { - printk(KERN_ERR "audit: *NO* daemon at audit_pid=%d\n", audit_pid); + pr_err("*NO* daemon at audit_pid=%d\n", audit_pid); audit_log_lost("auditd disappeared\n"); audit_pid = 0; audit_sock = NULL; @@ -1068,7 +1067,7 @@ static int __net_init audit_net_init(struct net *net) struct audit_net *aunet = net_generic(net, audit_net_id); - pr_info("audit: initializing netlink socket in namespace\n"); + pr_info("initializing netlink socket in namespace\n"); aunet->nlsk = netlink_kernel_create(net, NETLINK_AUDIT, &cfg); if (aunet->nlsk == NULL) { @@ -1108,8 +1107,8 @@ static int __init audit_init(void) if (audit_initialized == AUDIT_DISABLED) return 0; - pr_info("audit: initializing netlink subsys (%s)\n", - audit_default ? "enabled" : "disabled"); + pr_info("initializing netlink subsys (%s)\n", + audit_default ? "enabled" : "disabled"); register_pernet_subsys(&audit_net_ops); skb_queue_head_init(&audit_skb_queue); @@ -1134,7 +1133,7 @@ static int __init audit_enable(char *str) if (!audit_default) audit_initialized = AUDIT_DISABLED; - pr_info("audit: %s\n", audit_default ? + pr_info("%s\n", audit_default ? "enabled (after initialization)" : "disabled (until reboot)"); return 1; @@ -1146,15 +1145,16 @@ __setup("audit=", audit_enable); static int __init audit_backlog_limit_set(char *str) { long int audit_backlog_limit_arg; + pr_info("audit_backlog_limit: "); if (kstrtol(str, 0, &audit_backlog_limit_arg)) { - printk("using default of %d, unable to parse %s\n", - audit_backlog_limit, str); + pr_cont("using default of %d, unable to parse %s\n", + audit_backlog_limit, str); return 1; } if (audit_backlog_limit_arg >= 0) audit_backlog_limit = (int)audit_backlog_limit_arg; - printk("%d\n", audit_backlog_limit); + pr_cont("%d\n", audit_backlog_limit); return 1; } @@ -1336,11 +1336,9 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, } } if (audit_rate_check() && printk_ratelimit()) - printk(KERN_WARNING - "audit: audit_backlog=%d > " - "audit_backlog_limit=%d\n", - skb_queue_len(&audit_skb_queue), - audit_backlog_limit); + pr_warn("audit_backlog=%d > audit_backlog_limit=%d\n", + skb_queue_len(&audit_skb_queue), + audit_backlog_limit); audit_log_lost("backlog limit exceeded"); audit_backlog_wait_time = audit_backlog_wait_overflow; wake_up(&audit_backlog_wait); -- cgit v0.10.2 From 3e1d0bb6224f019893d1c498cc3327559d183674 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 14 Jan 2014 10:33:13 -0800 Subject: audit: Convert int limit uses to u32 The equivalent uapi struct uses __u32 so make the kernel uses u32 too. This can prevent some oddities where the limit is logged/emitted as a negative value. Convert kstrtol to kstrtouint to disallow negative values. Signed-off-by: Joe Perches [eparis: do not remove static from audit_default declaration] diff --git a/include/linux/audit.h b/include/linux/audit.h index 98fe8a2..aa865a9 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -465,7 +465,7 @@ extern int audit_rule_change(int type, __u32 portid, int seq, void *data, size_t datasz); extern int audit_list_rules_send(__u32 portid, int seq); -extern int audit_enabled; +extern u32 audit_enabled; #else /* CONFIG_AUDIT */ static inline __printf(4, 5) void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, diff --git a/kernel/audit.c b/kernel/audit.c index 5f4766f..2df247d 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -79,16 +79,16 @@ static int audit_initialized; #define AUDIT_OFF 0 #define AUDIT_ON 1 #define AUDIT_LOCKED 2 -int audit_enabled; -int audit_ever_enabled; +u32 audit_enabled; +u32 audit_ever_enabled; EXPORT_SYMBOL_GPL(audit_enabled); /* Default state when kernel boots without any parameters. */ -static int audit_default; +static u32 audit_default; /* If auditing cannot proceed, audit_failure selects what happens. */ -static int audit_failure = AUDIT_FAIL_PRINTK; +static u32 audit_failure = AUDIT_FAIL_PRINTK; /* * If audit records are to be written to the netlink socket, audit_pid @@ -101,14 +101,14 @@ static __u32 audit_nlk_portid; /* 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; +static u32 audit_rate_limit; /* Number of outstanding audit_buffers allowed. * When set to zero, this means unlimited. */ -static int audit_backlog_limit = 64; +static u32 audit_backlog_limit = 64; #define AUDIT_BACKLOG_WAIT_TIME (60 * HZ) -static int audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME; -static int audit_backlog_wait_overflow = 0; +static u32 audit_backlog_wait_time = AUDIT_BACKLOG_WAIT_TIME; +static u32 audit_backlog_wait_overflow = 0; /* The identity of the user shutting down the audit system. */ kuid_t audit_sig_uid = INVALID_UID; @@ -272,7 +272,7 @@ void audit_log_lost(const char *message) if (print) { if (printk_ratelimit()) - pr_warn("audit_lost=%d audit_rate_limit=%d audit_backlog_limit=%d\n", + pr_warn("audit_lost=%u audit_rate_limit=%u audit_backlog_limit=%u\n", atomic_read(&audit_lost), audit_rate_limit, audit_backlog_limit); @@ -280,7 +280,7 @@ void audit_log_lost(const char *message) } } -static int audit_log_config_change(char *function_name, int new, int old, +static int audit_log_config_change(char *function_name, u32 new, u32 old, int allow_changes) { struct audit_buffer *ab; @@ -289,7 +289,7 @@ static int audit_log_config_change(char *function_name, int new, int old, ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); if (unlikely(!ab)) return rc; - audit_log_format(ab, "%s=%d old=%d", function_name, new, old); + audit_log_format(ab, "%s=%u old=%u", function_name, new, old); audit_log_session_info(ab); rc = audit_log_task_context(ab); if (rc) @@ -299,9 +299,10 @@ static int audit_log_config_change(char *function_name, int new, int old, return rc; } -static int audit_do_config_change(char *function_name, int *to_change, int new) +static int audit_do_config_change(char *function_name, u32 *to_change, u32 new) { - int allow_changes, rc = 0, old = *to_change; + int allow_changes, rc = 0; + u32 old = *to_change; /* check if we are locked */ if (audit_enabled == AUDIT_LOCKED) @@ -324,23 +325,23 @@ static int audit_do_config_change(char *function_name, int *to_change, int new) return rc; } -static int audit_set_rate_limit(int limit) +static int audit_set_rate_limit(u32 limit) { return audit_do_config_change("audit_rate_limit", &audit_rate_limit, limit); } -static int audit_set_backlog_limit(int limit) +static int audit_set_backlog_limit(u32 limit) { return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit, limit); } -static int audit_set_backlog_wait_time(int timeout) +static int audit_set_backlog_wait_time(u32 timeout) { return audit_do_config_change("audit_backlog_wait_time", &audit_backlog_wait_time, timeout); } -static int audit_set_enabled(int state) +static int audit_set_enabled(u32 state) { int rc; if (state < AUDIT_OFF || state > AUDIT_LOCKED) @@ -353,7 +354,7 @@ static int audit_set_enabled(int state) return rc; } -static int audit_set_failure(int state) +static int audit_set_failure(u32 state) { if (state != AUDIT_FAIL_SILENT && state != AUDIT_FAIL_PRINTK @@ -688,7 +689,7 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE); audit_log_task_info(ab, current); - audit_log_format(ab, "feature=%s old=%d new=%d old_lock=%d new_lock=%d res=%d", + audit_log_format(ab, "feature=%s old=%u new=%u old_lock=%u new_lock=%u res=%d", audit_feature_names[which], !!old_feature, !!new_feature, !!old_lock, !!new_lock, res); audit_log_end(ab); @@ -1144,16 +1145,16 @@ __setup("audit=", audit_enable); * audit_backlog_limit= */ static int __init audit_backlog_limit_set(char *str) { - long int audit_backlog_limit_arg; + u32 audit_backlog_limit_arg; pr_info("audit_backlog_limit: "); - if (kstrtol(str, 0, &audit_backlog_limit_arg)) { - pr_cont("using default of %d, unable to parse %s\n", + if (kstrtouint(str, 0, &audit_backlog_limit_arg)) { + pr_cont("using default of %u, unable to parse %s\n", audit_backlog_limit, str); return 1; } - if (audit_backlog_limit_arg >= 0) - audit_backlog_limit = (int)audit_backlog_limit_arg; + + audit_backlog_limit = audit_backlog_limit_arg; pr_cont("%d\n", audit_backlog_limit); return 1; diff --git a/kernel/audit.h b/kernel/audit.h index 0719b45..57cc64d 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -209,7 +209,7 @@ struct audit_context { #endif }; -extern int audit_ever_enabled; +extern u32 audit_ever_enabled; extern void audit_copy_inode(struct audit_names *name, const struct dentry *dentry, -- cgit v0.10.2 From 262fd3aad61100cb4f281efa292374817c25a479 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 17 Jan 2014 17:05:03 +0900 Subject: audit: Modify a set of system calls in audit class definitions Each asm-generic/audit_xx.h defines a set of system calls for respective audit permission class (read, write, change attribute or exec). This patch changes two entries: 1) fchown in audit_change_attr.h Make fchown included by its own because in asm-generic/unistd.h, for example, fchown always exists while chown is optional. This change is necessary at least for arm64. 2) truncate64 in audit_write.h Add missing truncate64/ftruncate64 as well as truncate/ftruncate Signed-off-by: AKASHI Takahiro Acked-by: Will Deacon Signed-off-by: Eric Paris diff --git a/include/asm-generic/audit_change_attr.h b/include/asm-generic/audit_change_attr.h index 89b73e5..a186553 100644 --- a/include/asm-generic/audit_change_attr.h +++ b/include/asm-generic/audit_change_attr.h @@ -4,9 +4,11 @@ __NR_chmod, __NR_fchmod, #ifdef __NR_chown __NR_chown, -__NR_fchown, __NR_lchown, #endif +#ifdef __NR_fchown +__NR_fchown, +#endif __NR_setxattr, __NR_lsetxattr, __NR_fsetxattr, diff --git a/include/asm-generic/audit_write.h b/include/asm-generic/audit_write.h index e7020c5..274575d 100644 --- a/include/asm-generic/audit_write.h +++ b/include/asm-generic/audit_write.h @@ -10,6 +10,12 @@ __NR_truncate, #ifdef __NR_truncate64 __NR_truncate64, #endif +#ifdef __NR_ftruncate +__NR_ftruncate, +#endif +#ifdef __NR_ftruncate64 +__NR_ftruncate64, +#endif #ifdef __NR_bind __NR_bind, /* bind can affect fs object only in one way... */ #endif -- cgit v0.10.2 From 4f066328abec7f67518051e0eba67246ef2bfc07 Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Fri, 17 Jan 2014 17:04:38 -0500 Subject: audit: remove pr_info for every network namespace A message about creating the audit socket might be fine at startup, but a pr_info for every single network namespace created on a system isn't useful. Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 2df247d..5dd3dfa 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1068,8 +1068,6 @@ static int __net_init audit_net_init(struct net *net) struct audit_net *aunet = net_generic(net, audit_net_id); - pr_info("initializing netlink socket in namespace\n"); - aunet->nlsk = netlink_kernel_create(net, NETLINK_AUDIT, &cfg); if (aunet->nlsk == NULL) { audit_panic("cannot initialize netlink socket in namespace"); -- cgit v0.10.2 From 8626877b5252c78be9e3e819e7de65740a7e6f90 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Tue, 16 Jul 2013 13:18:45 -0400 Subject: audit: fix location of __net_initdata for audit_net_ops Fixup caught by checkpatch. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/kernel/audit.c b/kernel/audit.c index 5dd3dfa..34c5a23 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1091,7 +1091,7 @@ static void __net_exit audit_net_exit(struct net *net) netlink_kernel_release(sock); } -static struct pernet_operations __net_initdata audit_net_ops = { +static struct pernet_operations audit_net_ops __net_initdata = { .init = audit_net_init, .exit = audit_net_exit, .id = &audit_net_id, -- cgit v0.10.2 From f3411cb2b2e396a41ed3a439863f028db7140a34 Mon Sep 17 00:00:00 2001 From: Richard Guy Briggs Date: Tue, 17 Sep 2013 12:34:52 -0400 Subject: audit: whitespace fix in kernel-parameters.txt Fixup caught by checkpatch. Signed-off-by: Richard Guy Briggs Signed-off-by: Eric Paris diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index e81e1d0..a068591 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -474,7 +474,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. RAM until it is fully enabled by the userspace auditd. Default: unset - + audit_backlog_limit= [KNL] Set the audit queue size limit. Format: (must be >=0) Default: 64 -- cgit v0.10.2