audit: always check the netlink payload length in audit_receive_msg()
[ Upstream commit 756125289285f6e55a03861bf4b6257aa3d19a93 ] 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: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
09b97fd4d2
commit
8affc54134
|
@ -787,13 +787,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 */
|
||||
|
||||
|
@ -849,6 +847,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;
|
||||
|
@ -872,6 +871,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: {
|
||||
|
@ -893,7 +893,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)
|
||||
|
@ -948,7 +948,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;
|
||||
|
@ -960,6 +962,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
|
||||
err = audit_filter_user(msg_type);
|
||||
if (err == 1) { /* match or error */
|
||||
char *str = data;
|
||||
|
||||
err = 0;
|
||||
if (msg_type == AUDIT_USER_TTY) {
|
||||
err = tty_audit_push_current();
|
||||
|
@ -968,19 +972,17 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
}
|
||||
mutex_unlock(&audit_cmd_mutex);
|
||||
audit_log_common_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_set_portid(ab, NETLINK_CB(skb).portid);
|
||||
audit_log_end(ab);
|
||||
|
@ -989,7 +991,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
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(&ab, AUDIT_CONFIG_CHANGE);
|
||||
|
@ -998,7 +1000,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
|
|||
return -EPERM;
|
||||
}
|
||||
err = audit_rule_change(msg_type, NETLINK_CB(skb).portid,
|
||||
seq, data, nlmsg_len(nlh));
|
||||
seq, data, data_len);
|
||||
break;
|
||||
case AUDIT_LIST_RULES:
|
||||
err = audit_list_rules_send(skb, seq);
|
||||
|
@ -1012,7 +1014,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;
|
||||
|
@ -1089,7 +1091,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))
|
||||
|
|
Loading…
Reference in New Issue
Block a user