Subject: [PATCH] Fix audit_list{,_rules} deadlock
Following is Serge's patch:
From: Serge Hallyn <[email protected]>
Subject: [PATCH] Fix audit_list{,_rules} deadlock
The audit_list and audit_list_rules functions send all stored audit rules to userspace over netlink from a kthread. They do this entirely from under the audit_netlink_mutex. If the netlink buffer gets to being too large, then netlink will wait for the receiver to grab the contents. But the receiver is in audit_receive, which also grabs the audit_netlink_mutex. Deadlock.
This patch makes audit_list{,_rules} form a list of rules under the mutex, then drop the mutex, then send the list.
Signed-off-by Serge Hallyn <[email protected]>
---
kernel/auditfilter.c | 54 +++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 46 insertions(+), 8 deletions(-)
kernel/auditfilter.c +46 -8
@@ -510,12 +510,22 @@ static inline int audit_del_rule(struct/* List rules using struct audit_rule. Exists for backward * compatibility with userspace. */ +struct au_rule_list { +union { +struct audit_rule *rule; +struct audit_rule_data *data; + } u; +struct list_head next; +}; +static int audit_list (void *_dest) {int pid, seq;int *dest = _dest;struct audit_entry *entry;int i; +LIST_HEAD (sendlist); +struct au_rule_list *r, *r1; pid = dest[0 ]; seq = dest[1 ];
@@ -532,14 +542,27 @@ static int audit_list(void *_dest) rule =audit_krule_to_rule (&entry->rule);if (unlikely (!rule))break ; -audit_send_reply (pid, seq,AUDIT_LIST ,0 ,1 , - rule,sizeof (*rule)); -kfree (rule); + r =kmalloc (sizeof (*r),GFP_KERNEL ); +if (unlikely (!r)) { +kfree (rule); +break ; + } + r->u.rule = rule; +list_add (&r->next, &sendlist); } } -audit_send_reply (pid, seq,AUDIT_LIST ,1 ,1 ,NULL ,0 );mutex_unlock (&audit_netlink_mutex); + +list_for_each_entry_safe (r, r1, &sendlist, next) { +audit_send_reply (pid, seq,AUDIT_LIST ,0 ,1 , + r->u.rule,sizeof (*r->u.rule)); +list_del (&r->next); +kfree (r->u.rule); +kfree (r); + } + +audit_send_reply (pid, seq,AUDIT_LIST ,1 ,1 ,NULL ,0 );return 0 ; }
@@ -549,6 +572,8 @@ static int audit_list_rules(void *_dest)int pid, seq;int *dest = _dest;struct audit_entry *e; +LIST_HEAD (sendlist); +struct au_rule_list *r, *r1;int i; pid = dest[0 ];
@@ -566,14 +591,27 @@ static int audit_list_rules(void *_dest) data =audit_krule_to_data (&e->rule);if (unlikely (!data))break ; -audit_send_reply (pid, seq,AUDIT_LIST_RULES ,0 ,1 , - data,sizeof (*data)); -kfree (data); + r =kmalloc (sizeof (*r),GFP_KERNEL ); +if (unlikely (!r)) { +kfree (data); +break ; + } + r->u.data = data; +list_add (&r->next, &sendlist); } } +mutex_unlock (&audit_netlink_mutex); + +list_for_each_entry_safe (r, r1, &sendlist, next) { +audit_send_reply (pid, seq,AUDIT_LIST_RULES ,0 ,1 , + r->u.data,sizeof (*r->u.data)); +list_del (&r->next); +kfree (r->u.data); +kfree (r); + } +audit_send_reply (pid, seq,AUDIT_LIST_RULES ,1 ,1 ,NULL ,0 ); -mutex_unlock (&audit_netlink_mutex);return 0 ; }
Signature · 2 lines
George Wilson <[email protected]> IBM Linux Technology Center