audit: catch possible NULL audit buffers
PATCH 1/1 audit: catch possible NULL audit buffers
It's possible for audit_log_start() to return NULL. Handle it in the various callers.
---
This leaves out the change to the audit_seccomp, since I fixed that in a separate patch ("audit: create explicit AUDIT_SECCOMP event type").
--- kernel/audit.c | 4 ++++ kernel/audit_tree.c | 26 +++++++++++++++++--------- kernel/audit_watch.c | 2 ++ kernel/auditsc.c | 6 ++++-- 4 files changed, 27 insertions(+), 11 deletions(-)
kernel/audit.c +4 -0
@@ -272,6 +272,8 @@ static int audit_log_config_change(char *function_name, int new, int old,int rc =0 ; ab =audit_log_start (NULL ,GFP_KERNEL ,AUDIT_CONFIG_CHANGE ); +if (unlikely (!ab)) +return rc;audit_log_format (ab,"%s=%d old=%d auid=%u ses=%u" , function_name, new, old,from_kuid (&init_user_ns, loginuid), sessionid);if (sid) {
@@ -619,6 +621,8 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type, } *ab =audit_log_start (NULL ,GFP_KERNEL , msg_type); +if (unlikely (!*ab)) +return rc; audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u", task_tgid_vnr(current), from_kuid(&init_user_ns, current_uid()),
kernel/audit_tree.c +17 -9
@@ -449,11 +449,26 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)return 0 ; } +static void audit_log_remove_rule (struct audit_krule *rule) +{ +struct audit_buffer *ab; + + ab =audit_log_start (NULL ,GFP_KERNEL ,AUDIT_CONFIG_CHANGE ); +if (unlikely (!ab)) +return ; +audit_log_format (ab,"op=" ); +audit_log_string (ab,"remove rule" ); +audit_log_format (ab," dir=" ); +audit_log_untrustedstring (ab, rule->tree->pathname); +audit_log_key (ab, rule->filterkey); +audit_log_format (ab," list=%d res=1" , rule->listnr); +audit_log_end (ab); +} +static void kill_rules (struct audit_tree *tree) {struct audit_krule *rule, *next;struct audit_entry *entry; -struct audit_buffer *ab;list_for_each_entry_safe (rule, next, &tree->rules, rlist) { entry = container_of(rule, struct audit_entry, rule);
@@ -461,14 +476,7 @@ static void kill_rules(struct audit_tree *tree)list_del_init (&rule->rlist);if (rule->tree) {/* not a half-baked one */ - ab =audit_log_start (NULL ,GFP_KERNEL ,AUDIT_CONFIG_CHANGE ); -audit_log_format (ab,"op=" ); -audit_log_string (ab,"remove rule" ); -audit_log_format (ab," dir=" ); -audit_log_untrustedstring (ab, rule->tree->pathname); -audit_log_key (ab, rule->filterkey); -audit_log_format (ab," list=%d res=1" , rule->listnr); -audit_log_end (ab); +audit_log_remove_rule (rule); rule->tree =NULL ;list_del_rcu (&entry->list);list_del (&entry->rule.list);
kernel/audit_watch.c +2 -0
@@ -240,6 +240,8 @@ static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watcif (audit_enabled) {struct audit_buffer *ab; ab =audit_log_start (NULL ,GFP_NOFS ,AUDIT_CONFIG_CHANGE ); +if (unlikely (!ab)) +return ;audit_log_format (ab,"auid=%u ses=%u op=" ,from_kuid (&init_user_ns,audit_get_loginuid (current)),audit_get_sessionid (current));
kernel/auditsc.c +4 -2
@@ -1481,14 +1481,14 @@ static void show_special(struct audit_context *context, int *call_panic)audit_log_end (ab); ab =audit_log_start (context,GFP_KERNEL ,AUDIT_IPC_SET_PERM ); +if (unlikely (!ab)) +return ;audit_log_format (ab,"qbytes=%lx ouid=%u ogid=%u mode=%#ho" , context->ipc.qbytes, context->ipc.perm_uid, context->ipc.perm_gid, context->ipc.perm_mode); -if (!ab) -return ; }break ; }case AUDIT_MQ_OPEN : {
@@ -2775,6 +2775,8 @@ void audit_core_dumps(long signr)return ; ab =audit_log_start (NULL ,GFP_KERNEL ,AUDIT_ANOM_ABEND ); +if (unlikely (!ab)) +return ;audit_log_abend (ab,"memory violation" , signr);audit_log_end (ab); }
Signature · 6 lines
1.7.9.5 -- Kees Cook Chrome OS Security
kernel/audit.c static int audit_log_config_change(char *function_name, int new, int old, · line 276
Quoted 13 lines · On Mon, 19 Nov 2012 14:00:51 -0800 Kees Cook <[email protected]> wrote:
It's possible for
audit_log_start()to return NULL. Handle it in the various callers....
kernel/audit.c +2
-0@@ -272,6 +272,8 @@ static int audit_log_config_change(char *function_name, int new, int old,int rc =0 ; ab =audit_log_start (NULL ,GFP_KERNEL ,AUDIT_CONFIG_CHANGE ); +if (unlikely (!ab)) +return rc;
Returning success here looks suspicious. audit_do_config_change() will fail to take its wtf-just-happened action (which audit_log_config_change() duplicates, btw).
Meanwhile audit_receive_msg() is off living in a happy land where nothing ever goes wrong.
kernel/audit.c static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type, · line 625
Quoted 9 lines
kernel/audit.c +2
-0audit_log_format (ab,"%s=%d old=%d auid=%u ses=%u" , function_name, new, old,from_kuid (&init_user_ns, loginuid), sessionid);if (sid) {@@ -619,6 +621,8 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type, } *ab =audit_log_start (NULL ,GFP_KERNEL , msg_type); +if (unlikely (!*ab)) +return rc;
Also looks fishy.
Quoted 6 lines
kernel/audit.c +0
-0audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u", task_tgid_vnr(current), from_kuid(&init_user_ns, current_uid()),
Quoted 13 lines · Andrew Morton
Quoted 10 lines · On Mon, 19 Nov 2012 14:00:51 -0800 Kees Cook <[email protected]> wrote:
It's possible for
audit_log_start()to return NULL. Handle it in the various callers....
kernel/audit.c +0
-0@@ -272,6 +272,8 @@ static int audit_log_config_change(char *function_name, int new, int old,int rc =0 ;
Quoted 7 lines
kernel/audit.c static int audit_log_config_change(char *function_name, int new, int old, · line 276
Quoted 3 lines
kernel/audit.c +2
-0ab =audit_log_start (NULL ,GFP_KERNEL ,AUDIT_CONFIG_CHANGE ); +if (unlikely (!ab)) +return rc;Returning success here looks suspicious.
audit_do_config_change()will fail to take its wtf-just-happened action (whichaudit_log_config_change()duplicates, btw).
It seemed like the only meaningful rc was from when security_secid_to_secctx failed, which changes the audit report and has external side-effects that seem specific to that condition. It seemed that audit_log_start() failing was less of a problem than security_secid_to_secctx failing, which seems supposed be all the other code in the kernel that gives up if audit_log_start() fails.
Quoted 2 lines
Meanwhile
audit_receive_msg()is off living in a happy land where nothing ever goes wrong.
Right, this reinforced my perceptions that a audit_log_start() failure wasn't meaningful to propagate to callers of audit_log_config_change().
Quoted 7 lines
Quoted 7 lines
kernel/audit.c +0
-0audit_log_format (ab,"%s=%d old=%d auid=%u ses=%u" , function_name, new, old,from_kuid (&init_user_ns, loginuid), sessionid);if (sid) {@@ -619,6 +621,8 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type, }
Quoted 5 lines
kernel/audit.c static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type, · line 625
Quoted 3 lines
kernel/audit.c +2
-0*ab =audit_log_start (NULL ,GFP_KERNEL , msg_type); +if (unlikely (!*ab)) +return rc;Also looks fishy.
Without any callers checking the return value, it seemed useless to propagate here too.
-Kees
Signature · 2 lines
Kees Cook Chrome OS Security