mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	audit: always check the netlink payload length in audit_receive_msg()
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>
This commit is contained in:
		
							parent
							
								
									2ad3e17ebf
								
							
						
					
					
						commit
						7561252892
					
				
					 1 changed files with 21 additions and 19 deletions
				
			
		|  | @ -1101,13 +1101,11 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature | ||||||
| 	audit_log_end(ab); | 	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; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > ARRAY_SIZE(audit_feature_names)); | 	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 */ | 	/* if there is ever a version 2 we should handle that here */ | ||||||
| 
 | 
 | ||||||
|  | @ -1175,6 +1173,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | ||||||
| { | { | ||||||
| 	u32			seq; | 	u32			seq; | ||||||
| 	void			*data; | 	void			*data; | ||||||
|  | 	int			data_len; | ||||||
| 	int			err; | 	int			err; | ||||||
| 	struct audit_buffer	*ab; | 	struct audit_buffer	*ab; | ||||||
| 	u16			msg_type = nlh->nlmsg_type; | 	u16			msg_type = nlh->nlmsg_type; | ||||||
|  | @ -1188,6 +1187,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | ||||||
| 
 | 
 | ||||||
| 	seq  = nlh->nlmsg_seq; | 	seq  = nlh->nlmsg_seq; | ||||||
| 	data = nlmsg_data(nlh); | 	data = nlmsg_data(nlh); | ||||||
|  | 	data_len = nlmsg_len(nlh); | ||||||
| 
 | 
 | ||||||
| 	switch (msg_type) { | 	switch (msg_type) { | ||||||
| 	case AUDIT_GET: { | 	case AUDIT_GET: { | ||||||
|  | @ -1211,7 +1211,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | ||||||
| 		struct audit_status	s; | 		struct audit_status	s; | ||||||
| 		memset(&s, 0, sizeof(s)); | 		memset(&s, 0, sizeof(s)); | ||||||
| 		/* guard against past and future API changes */ | 		/* 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) { | 		if (s.mask & AUDIT_STATUS_ENABLED) { | ||||||
| 			err = audit_set_enabled(s.enabled); | 			err = audit_set_enabled(s.enabled); | ||||||
| 			if (err < 0) | 			if (err < 0) | ||||||
|  | @ -1315,7 +1315,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | ||||||
| 			return err; | 			return err; | ||||||
| 		break; | 		break; | ||||||
| 	case AUDIT_SET_FEATURE: | 	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) | 		if (err) | ||||||
| 			return err; | 			return err; | ||||||
| 		break; | 		break; | ||||||
|  | @ -1327,6 +1329,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | ||||||
| 
 | 
 | ||||||
| 		err = audit_filter(msg_type, AUDIT_FILTER_USER); | 		err = audit_filter(msg_type, AUDIT_FILTER_USER); | ||||||
| 		if (err == 1) { /* match or error */ | 		if (err == 1) { /* match or error */ | ||||||
|  | 			char *str = data; | ||||||
|  | 
 | ||||||
| 			err = 0; | 			err = 0; | ||||||
| 			if (msg_type == AUDIT_USER_TTY) { | 			if (msg_type == AUDIT_USER_TTY) { | ||||||
| 				err = tty_audit_push(); | 				err = tty_audit_push(); | ||||||
|  | @ -1334,26 +1338,24 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | ||||||
| 					break; | 					break; | ||||||
| 			} | 			} | ||||||
| 			audit_log_user_recv_msg(&ab, msg_type); | 			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_log_format(ab, " msg='%.*s'", | ||||||
| 						 AUDIT_MESSAGE_TEXT_MAX, | 						 AUDIT_MESSAGE_TEXT_MAX, | ||||||
| 						 (char *)data); | 						 str); | ||||||
| 			else { | 			} else { | ||||||
| 				int size; |  | ||||||
| 
 |  | ||||||
| 				audit_log_format(ab, " data="); | 				audit_log_format(ab, " data="); | ||||||
| 				size = nlmsg_len(nlh); | 				if (data_len > 0 && str[data_len - 1] == '\0') | ||||||
| 				if (size > 0 && | 					data_len--; | ||||||
| 				    ((unsigned char *)data)[size - 1] == '\0') | 				audit_log_n_untrustedstring(ab, str, data_len); | ||||||
| 					size--; |  | ||||||
| 				audit_log_n_untrustedstring(ab, data, size); |  | ||||||
| 			} | 			} | ||||||
| 			audit_log_end(ab); | 			audit_log_end(ab); | ||||||
| 		} | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case AUDIT_ADD_RULE: | 	case AUDIT_ADD_RULE: | ||||||
| 	case AUDIT_DEL_RULE: | 	case AUDIT_DEL_RULE: | ||||||
| 		if (nlmsg_len(nlh) < sizeof(struct audit_rule_data)) | 		if (data_len < sizeof(struct audit_rule_data)) | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 		if (audit_enabled == AUDIT_LOCKED) { | 		if (audit_enabled == AUDIT_LOCKED) { | ||||||
| 			audit_log_common_recv_msg(audit_context(), &ab, | 			audit_log_common_recv_msg(audit_context(), &ab, | ||||||
|  | @ -1365,7 +1367,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | ||||||
| 			audit_log_end(ab); | 			audit_log_end(ab); | ||||||
| 			return -EPERM; | 			return -EPERM; | ||||||
| 		} | 		} | ||||||
| 		err = audit_rule_change(msg_type, seq, data, nlmsg_len(nlh)); | 		err = audit_rule_change(msg_type, seq, data, data_len); | ||||||
| 		break; | 		break; | ||||||
| 	case AUDIT_LIST_RULES: | 	case AUDIT_LIST_RULES: | ||||||
| 		err = audit_list_rules_send(skb, seq); | 		err = audit_list_rules_send(skb, seq); | ||||||
|  | @ -1380,7 +1382,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | ||||||
| 	case AUDIT_MAKE_EQUIV: { | 	case AUDIT_MAKE_EQUIV: { | ||||||
| 		void *bufp = data; | 		void *bufp = data; | ||||||
| 		u32 sizes[2]; | 		u32 sizes[2]; | ||||||
| 		size_t msglen = nlmsg_len(nlh); | 		size_t msglen = data_len; | ||||||
| 		char *old, *new; | 		char *old, *new; | ||||||
| 
 | 
 | ||||||
| 		err = -EINVAL; | 		err = -EINVAL; | ||||||
|  | @ -1456,7 +1458,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | ||||||
| 
 | 
 | ||||||
| 		memset(&s, 0, sizeof(s)); | 		memset(&s, 0, sizeof(s)); | ||||||
| 		/* guard against past and future API changes */ | 		/* 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 */ | 		/* check if new data is valid */ | ||||||
| 		if ((s.enabled != 0 && s.enabled != 1) || | 		if ((s.enabled != 0 && s.enabled != 1) || | ||||||
| 		    (s.log_passwd != 0 && s.log_passwd != 1)) | 		    (s.log_passwd != 0 && s.log_passwd != 1)) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Paul Moore
						Paul Moore