| From ec25ccdf0f8be45cfb09da4f48769224930878c6 Mon Sep 17 00:00:00 2001 |
| From: Paul Moore <paul@paul-moore.com> |
| Date: Mon, 24 Feb 2020 16:38:57 -0500 |
| Subject: [PATCH] audit: always check the netlink payload length in |
| audit_receive_msg() |
| |
| commit 756125289285f6e55a03861bf4b6257aa3d19a93 upstream. |
| |
| This patch ensures that we always check the netlink payload length |
| in audit_receive_msg() before we take any action on the payload |
| itself. |
| |
| Cc: stable@vger.kernel.org |
| Reported-by: syzbot+399c44bf1f43b8747403@syzkaller.appspotmail.com |
| Reported-by: syzbot+e4b12d8d202701f08b6d@syzkaller.appspotmail.com |
| Signed-off-by: Paul Moore <paul@paul-moore.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/kernel/audit.c b/kernel/audit.c |
| index 486c968214d9..4be0f0786556 100644 |
| --- a/kernel/audit.c |
| +++ b/kernel/audit.c |
| @@ -1100,13 +1100,11 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature |
| audit_log_end(ab); |
| } |
| |
| -static int audit_set_feature(struct sk_buff *skb) |
| +static int audit_set_feature(struct audit_features *uaf) |
| { |
| - struct audit_features *uaf; |
| int i; |
| |
| BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > ARRAY_SIZE(audit_feature_names)); |
| - uaf = nlmsg_data(nlmsg_hdr(skb)); |
| |
| /* if there is ever a version 2 we should handle that here */ |
| |
| @@ -1174,6 +1172,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
| { |
| u32 seq; |
| void *data; |
| + int data_len; |
| int err; |
| struct audit_buffer *ab; |
| u16 msg_type = nlh->nlmsg_type; |
| @@ -1187,6 +1186,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
| |
| seq = nlh->nlmsg_seq; |
| data = nlmsg_data(nlh); |
| + data_len = nlmsg_len(nlh); |
| |
| switch (msg_type) { |
| case AUDIT_GET: { |
| @@ -1210,7 +1210,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
| 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))); |
| + memcpy(&s, data, min_t(size_t, sizeof(s), data_len)); |
| if (s.mask & AUDIT_STATUS_ENABLED) { |
| err = audit_set_enabled(s.enabled); |
| if (err < 0) |
| @@ -1314,7 +1314,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
| return err; |
| break; |
| case AUDIT_SET_FEATURE: |
| - err = audit_set_feature(skb); |
| + if (data_len < sizeof(struct audit_features)) |
| + return -EINVAL; |
| + err = audit_set_feature(data); |
| if (err) |
| return err; |
| break; |
| @@ -1326,6 +1328,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
| |
| err = audit_filter(msg_type, AUDIT_FILTER_USER); |
| if (err == 1) { /* match or error */ |
| + char *str = data; |
| + |
| err = 0; |
| if (msg_type == AUDIT_USER_TTY) { |
| err = tty_audit_push(); |
| @@ -1333,26 +1337,24 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
| break; |
| } |
| audit_log_user_recv_msg(&ab, msg_type); |
| - if (msg_type != AUDIT_USER_TTY) |
| + if (msg_type != AUDIT_USER_TTY) { |
| + /* ensure NULL termination */ |
| + str[data_len - 1] = '\0'; |
| audit_log_format(ab, " msg='%.*s'", |
| AUDIT_MESSAGE_TEXT_MAX, |
| - (char *)data); |
| - else { |
| - int size; |
| - |
| + str); |
| + } else { |
| audit_log_format(ab, " data="); |
| - size = nlmsg_len(nlh); |
| - if (size > 0 && |
| - ((unsigned char *)data)[size - 1] == '\0') |
| - size--; |
| - audit_log_n_untrustedstring(ab, data, size); |
| + if (data_len > 0 && str[data_len - 1] == '\0') |
| + data_len--; |
| + audit_log_n_untrustedstring(ab, str, data_len); |
| } |
| audit_log_end(ab); |
| } |
| break; |
| case AUDIT_ADD_RULE: |
| case AUDIT_DEL_RULE: |
| - if (nlmsg_len(nlh) < sizeof(struct audit_rule_data)) |
| + if (data_len < sizeof(struct audit_rule_data)) |
| return -EINVAL; |
| if (audit_enabled == AUDIT_LOCKED) { |
| audit_log_common_recv_msg(audit_context(), &ab, |
| @@ -1364,7 +1366,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
| audit_log_end(ab); |
| return -EPERM; |
| } |
| - err = audit_rule_change(msg_type, seq, data, nlmsg_len(nlh)); |
| + err = audit_rule_change(msg_type, seq, data, data_len); |
| break; |
| case AUDIT_LIST_RULES: |
| err = audit_list_rules_send(skb, seq); |
| @@ -1379,7 +1381,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
| case AUDIT_MAKE_EQUIV: { |
| void *bufp = data; |
| u32 sizes[2]; |
| - size_t msglen = nlmsg_len(nlh); |
| + size_t msglen = data_len; |
| char *old, *new; |
| |
| err = -EINVAL; |
| @@ -1455,7 +1457,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
| |
| memset(&s, 0, sizeof(s)); |
| /* guard against past and future API changes */ |
| - memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh))); |
| + memcpy(&s, data, min_t(size_t, sizeof(s), data_len)); |
| /* check if new data is valid */ |
| if ((s.enabled != 0 && s.enabled != 1) || |
| (s.log_passwd != 0 && s.log_passwd != 1)) |
| -- |
| 2.7.4 |
| |