Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: MGMT: fix crash in set_mesh_sync and set_mesh_complete

There is a BUG: KASAN: stack-out-of-bounds in set_mesh_sync due to
memcpy from badly declared on-stack flexible array.

Another crash is in set_mesh_complete() due to double list_del via
mgmt_pending_valid + mgmt_pending_remove.

Use DEFINE_FLEX to declare the flexible array right, and don't memcpy
outside bounds.

As mgmt_pending_valid removes the cmd from list, use mgmt_pending_free,
and also report status on error.

Fixes: 302a1f674c00d ("Bluetooth: MGMT: Fix possible UAFs")
Signed-off-by: Pauli Virtanen <pav@iki.fi>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Pauli Virtanen and committed by
Luiz Augusto von Dentz
e8785404 0d928080

+16 -12
+1 -1
include/net/bluetooth/mgmt.h
··· 853 853 __le16 window; 854 854 __le16 period; 855 855 __u8 num_ad_types; 856 - __u8 ad_types[]; 856 + __u8 ad_types[] __counted_by(num_ad_types); 857 857 } __packed; 858 858 #define MGMT_SET_MESH_RECEIVER_SIZE 6 859 859
+15 -11
net/bluetooth/mgmt.c
··· 2175 2175 sk = cmd->sk; 2176 2176 2177 2177 if (status) { 2178 + mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER, 2179 + status); 2178 2180 mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true, 2179 2181 cmd_status_rsp, &status); 2180 - return; 2182 + goto done; 2181 2183 } 2182 2184 2183 - mgmt_pending_remove(cmd); 2184 2185 mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_MESH_RECEIVER, 0, NULL, 0); 2186 + 2187 + done: 2188 + mgmt_pending_free(cmd); 2185 2189 } 2186 2190 2187 2191 static int set_mesh_sync(struct hci_dev *hdev, void *data) 2188 2192 { 2189 2193 struct mgmt_pending_cmd *cmd = data; 2190 - struct mgmt_cp_set_mesh cp; 2194 + DEFINE_FLEX(struct mgmt_cp_set_mesh, cp, ad_types, num_ad_types, 2195 + sizeof(hdev->mesh_ad_types)); 2191 2196 size_t len; 2192 2197 2193 2198 mutex_lock(&hdev->mgmt_pending_lock); ··· 2202 2197 return -ECANCELED; 2203 2198 } 2204 2199 2205 - memcpy(&cp, cmd->param, sizeof(cp)); 2200 + len = cmd->param_len; 2201 + memcpy(cp, cmd->param, min(__struct_size(cp), len)); 2206 2202 2207 2203 mutex_unlock(&hdev->mgmt_pending_lock); 2208 2204 2209 - len = cmd->param_len; 2210 - 2211 2205 memset(hdev->mesh_ad_types, 0, sizeof(hdev->mesh_ad_types)); 2212 2206 2213 - if (cp.enable) 2207 + if (cp->enable) 2214 2208 hci_dev_set_flag(hdev, HCI_MESH); 2215 2209 else 2216 2210 hci_dev_clear_flag(hdev, HCI_MESH); 2217 2211 2218 - hdev->le_scan_interval = __le16_to_cpu(cp.period); 2219 - hdev->le_scan_window = __le16_to_cpu(cp.window); 2212 + hdev->le_scan_interval = __le16_to_cpu(cp->period); 2213 + hdev->le_scan_window = __le16_to_cpu(cp->window); 2220 2214 2221 - len -= sizeof(cp); 2215 + len -= sizeof(struct mgmt_cp_set_mesh); 2222 2216 2223 2217 /* If filters don't fit, forward all adv pkts */ 2224 2218 if (len <= sizeof(hdev->mesh_ad_types)) 2225 - memcpy(hdev->mesh_ad_types, cp.ad_types, len); 2219 + memcpy(hdev->mesh_ad_types, cp->ad_types, len); 2226 2220 2227 2221 hci_update_passive_scan_sync(hdev); 2228 2222 return 0;