[PATCH] audit: catch possible NULL buffers
It's possible for audit_log_start() to return NULL. Handle it in various callers. Cc: sta...@vger.kernel.org Signed-off-by: Kees Cook --- kernel/audit.c |4 kernel/audit_tree.c | 26 +- kernel/audit_watch.c |2 ++ kernel/auditsc.c |8 ++-- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/kernel/audit.c b/kernel/audit.c index 40414e9..a219998 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -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(_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(_user_ns, current_uid()), diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index ed206fd..29dc061 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -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, >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(>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(>list); list_del(>rule.list); diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 9a9ae6e..3e29b7a 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -240,6 +240,8 @@ static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watc if (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(_user_ns, audit_get_loginuid(current)), audit_get_sessionid(current)); diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 2f186ed..9a836b8 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -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,
[PATCH] audit: catch possible NULL buffers
It's possible for audit_log_start() to return NULL. Handle it in various callers. Cc: sta...@vger.kernel.org Signed-off-by: Kees Cook keesc...@chromium.org --- kernel/audit.c |4 kernel/audit_tree.c | 26 +- kernel/audit_watch.c |2 ++ kernel/auditsc.c |8 ++-- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/kernel/audit.c b/kernel/audit.c index 40414e9..a219998 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -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()), diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index ed206fd..29dc061 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -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); diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 9a9ae6e..3e29b7a 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -240,6 +240,8 @@ static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watc if (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)); diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 2f186ed..9a836b8 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -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 =