diff options
author | Ben Hutchings <ben@decadent.org.uk> | 2019-04-25 18:03:37 +0100 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2019-04-26 01:03:24 +0100 |
commit | cdbf76978f8ac984c08e1412d7139c135402fbb0 (patch) | |
tree | 66b557572c7c44cb3f7bc42503d9354bc98cf2a4 | |
parent | a7bb7d8cd998299ead2e8f3718193793501a2abd (diff) | |
download | linux-stable-queue-cdbf76978f8ac984c08e1412d7139c135402fbb0.tar.gz |
Add various security fixes
5 files changed, 397 insertions, 0 deletions
diff --git a/queue-3.16/bluetooth-check-l2cap-option-sizes-returned-from-l2cap_get_conf_opt.patch b/queue-3.16/bluetooth-check-l2cap-option-sizes-returned-from-l2cap_get_conf_opt.patch new file mode 100644 index 00000000..3bd3a261 --- /dev/null +++ b/queue-3.16/bluetooth-check-l2cap-option-sizes-returned-from-l2cap_get_conf_opt.patch @@ -0,0 +1,193 @@ +From: Marcel Holtmann <marcel@holtmann.org> +Date: Fri, 18 Jan 2019 12:56:20 +0100 +Subject: Bluetooth: Check L2CAP option sizes returned from l2cap_get_conf_opt + +commit af3d5d1c87664a4f150fcf3534c6567cb19909b0 upstream. + +When doing option parsing for standard type values of 1, 2 or 4 octets, +the value is converted directly into a variable instead of a pointer. To +avoid being tricked into being a pointer, check that for these option +types that sizes actually match. In L2CAP every option is fixed size and +thus it is prudent anyway to ensure that the remote side sends us the +right option size along with option paramters. + +If the option size is not matching the option type, then that option is +silently ignored. It is a protocol violation and instead of trying to +give the remote attacker any further hints just pretend that option is +not present and proceed with the default values. Implementation +following the specification and its qualification procedures will always +use the correct size and thus not being impacted here. + +To keep the code readable and consistent accross all options, a few +cosmetic changes were also required. + +Signed-off-by: Marcel Holtmann <marcel@holtmann.org> +Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> +[bwh: Backported to 3.16: adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + net/bluetooth/l2cap_core.c | 77 +++++++++++++++++++++++--------------- + 1 file changed, 46 insertions(+), 31 deletions(-) + +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -3330,10 +3330,14 @@ static int l2cap_parse_conf_req(struct l + + switch (type) { + case L2CAP_CONF_MTU: ++ if (olen != 2) ++ break; + mtu = val; + break; + + case L2CAP_CONF_FLUSH_TO: ++ if (olen != 2) ++ break; + chan->flush_to = val; + break; + +@@ -3341,26 +3345,30 @@ static int l2cap_parse_conf_req(struct l + break; + + case L2CAP_CONF_RFC: +- if (olen == sizeof(rfc)) +- memcpy(&rfc, (void *) val, olen); ++ if (olen != sizeof(rfc)) ++ break; ++ memcpy(&rfc, (void *) val, olen); + break; + + case L2CAP_CONF_FCS: ++ if (olen != 1) ++ break; + if (val == L2CAP_FCS_NONE) + set_bit(CONF_RECV_NO_FCS, &chan->conf_state); + break; + + case L2CAP_CONF_EFS: +- if (olen == sizeof(efs)) { +- remote_efs = 1; +- memcpy(&efs, (void *) val, olen); +- } ++ if (olen != sizeof(efs)) ++ break; ++ remote_efs = 1; ++ memcpy(&efs, (void *) val, olen); + break; + + case L2CAP_CONF_EWS: ++ if (olen != 2) ++ break; + if (!chan->conn->hs_enabled) + return -ECONNREFUSED; +- + set_bit(FLAG_EXT_CTRL, &chan->flags); + set_bit(CONF_EWS_RECV, &chan->conf_state); + chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW; +@@ -3370,7 +3378,6 @@ static int l2cap_parse_conf_req(struct l + default: + if (hint) + break; +- + result = L2CAP_CONF_UNKNOWN; + *((u8 *) ptr++) = type; + break; +@@ -3540,55 +3547,60 @@ static int l2cap_parse_conf_rsp(struct l + + switch (type) { + case L2CAP_CONF_MTU: ++ if (olen != 2) ++ break; + if (val < L2CAP_DEFAULT_MIN_MTU) { + *result = L2CAP_CONF_UNACCEPT; + chan->imtu = L2CAP_DEFAULT_MIN_MTU; + } else + chan->imtu = val; +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr); ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, ++ endptr - ptr); + break; + + case L2CAP_CONF_FLUSH_TO: ++ if (olen != 2) ++ break; + chan->flush_to = val; +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, +- 2, chan->flush_to, endptr - ptr); ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, ++ chan->flush_to, endptr - ptr); + break; + + case L2CAP_CONF_RFC: +- if (olen == sizeof(rfc)) +- memcpy(&rfc, (void *)val, olen); +- ++ if (olen != sizeof(rfc)) ++ break; ++ memcpy(&rfc, (void *)val, olen); + if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) && + rfc.mode != chan->mode) + return -ECONNREFUSED; +- + chan->fcs = 0; +- +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, +- sizeof(rfc), (unsigned long) &rfc, endptr - ptr); ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), ++ (unsigned long) &rfc, endptr - ptr); + break; + + case L2CAP_CONF_EWS: ++ if (olen != 2) ++ break; + chan->ack_win = min_t(u16, val, chan->ack_win); + l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, + chan->tx_win, endptr - ptr); + break; + + case L2CAP_CONF_EFS: +- if (olen == sizeof(efs)) { +- memcpy(&efs, (void *)val, olen); +- +- if (chan->local_stype != L2CAP_SERV_NOTRAFIC && +- efs.stype != L2CAP_SERV_NOTRAFIC && +- efs.stype != chan->local_stype) +- return -ECONNREFUSED; +- +- l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), +- (unsigned long) &efs, endptr - ptr); +- } ++ if (olen != sizeof(efs)) ++ break; ++ memcpy(&efs, (void *)val, olen); ++ if (chan->local_stype != L2CAP_SERV_NOTRAFIC && ++ efs.stype != L2CAP_SERV_NOTRAFIC && ++ efs.stype != chan->local_stype) ++ return -ECONNREFUSED; ++ l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs), ++ (unsigned long) &efs, endptr - ptr); + break; + + case L2CAP_CONF_FCS: ++ if (olen != 1) ++ break; + if (*result == L2CAP_CONF_PENDING) + if (val == L2CAP_FCS_NONE) + set_bit(CONF_RECV_NO_FCS, +@@ -3722,10 +3734,13 @@ static void l2cap_conf_rfc_get(struct l2 + + switch (type) { + case L2CAP_CONF_RFC: +- if (olen == sizeof(rfc)) +- memcpy(&rfc, (void *)val, olen); ++ if (olen != sizeof(rfc)) ++ break; ++ memcpy(&rfc, (void *)val, olen); + break; + case L2CAP_CONF_EWS: ++ if (olen != 2) ++ break; + txwin_ext = val; + break; + } diff --git a/queue-3.16/bluetooth-verify-that-l2cap_get_conf_opt-provides-large-enough.patch b/queue-3.16/bluetooth-verify-that-l2cap_get_conf_opt-provides-large-enough.patch new file mode 100644 index 00000000..31962e51 --- /dev/null +++ b/queue-3.16/bluetooth-verify-that-l2cap_get_conf_opt-provides-large-enough.patch @@ -0,0 +1,61 @@ +From: Marcel Holtmann <marcel@holtmann.org> +Date: Fri, 18 Jan 2019 13:43:19 +0100 +Subject: Bluetooth: Verify that l2cap_get_conf_opt provides large enough + buffer + +commit 7c9cbd0b5e38a1672fcd137894ace3b042dfbf69 upstream. + +The function l2cap_get_conf_opt will return L2CAP_CONF_OPT_SIZE + opt->len +as length value. The opt->len however is in control over the remote user +and can be used by an attacker to gain access beyond the bounds of the +actual packet. + +To prevent any potential leak of heap memory, it is enough to check that +the resulting len calculation after calling l2cap_get_conf_opt is not +below zero. A well formed packet will always return >= 0 here and will +end with the length value being zero after the last option has been +parsed. In case of malformed packets messing with the opt->len field the +length value will become negative. If that is the case, then just abort +and ignore the option. + +In case an attacker uses a too short opt->len value, then garbage will +be parsed, but that is protected by the unknown option handling and also +the option parameter size checks. + +Signed-off-by: Marcel Holtmann <marcel@holtmann.org> +Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + net/bluetooth/l2cap_core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/net/bluetooth/l2cap_core.c ++++ b/net/bluetooth/l2cap_core.c +@@ -3322,6 +3322,8 @@ static int l2cap_parse_conf_req(struct l + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&req, &type, &olen, &val); ++ if (len < 0) ++ break; + + hint = type & L2CAP_CONF_HINT; + type &= L2CAP_CONF_MASK; +@@ -3533,6 +3535,8 @@ static int l2cap_parse_conf_rsp(struct l + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); ++ if (len < 0) ++ break; + + switch (type) { + case L2CAP_CONF_MTU: +@@ -3713,6 +3717,8 @@ static void l2cap_conf_rfc_get(struct l2 + + while (len >= L2CAP_CONF_OPT_SIZE) { + len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); ++ if (len < 0) ++ break; + + switch (type) { + case L2CAP_CONF_RFC: diff --git a/queue-3.16/media-em28xx-dvb-fix-em28xx_dvb_resume-to-not-unregister.patch b/queue-3.16/media-em28xx-dvb-fix-em28xx_dvb_resume-to-not-unregister.patch new file mode 100644 index 00000000..58d23d3d --- /dev/null +++ b/queue-3.16/media-em28xx-dvb-fix-em28xx_dvb_resume-to-not-unregister.patch @@ -0,0 +1,53 @@ +From: Shuah Khan <shuah.kh@samsung.com> +Date: Wed, 9 Jul 2014 10:21:27 -0300 +Subject: [media] media: em28xx-dvb - fix em28xx_dvb_resume() to not unregister + i2c and dvb + +commit 6eb5e3399e8f45aa191ad21c0556bece8ea559f2 upstream. + +em28xx_dvb_resume() unregisters i2c tuner, i2c demod, and dvb. +This erroneous cleanup results in i2c tuner, i2c demod, and dvb +devices unregistered and removed during resume. This error is a +result of merge conflict between two patches that went into 3.15. + +Signed-off-by: Shuah Khan <shuah.kh@samsung.com> +Reviewed-by: Antti Palosaari <crope@iki.fi> +Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com> +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/media/usb/em28xx/em28xx-dvb.c | 17 ----------------- + 1 file changed, 17 deletions(-) + +--- a/drivers/media/usb/em28xx/em28xx-dvb.c ++++ b/drivers/media/usb/em28xx/em28xx-dvb.c +@@ -1712,7 +1712,6 @@ static int em28xx_dvb_resume(struct em28 + em28xx_info("Resuming DVB extension\n"); + if (dev->dvb) { + struct em28xx_dvb *dvb = dev->dvb; +- struct i2c_client *client = dvb->i2c_client_tuner; + + if (dvb->fe[0]) { + ret = dvb_frontend_resume(dvb->fe[0]); +@@ -1723,22 +1722,6 @@ static int em28xx_dvb_resume(struct em28 + ret = dvb_frontend_resume(dvb->fe[1]); + em28xx_info("fe1 resume %d\n", ret); + } +- /* remove I2C tuner */ +- if (client) { +- module_put(client->dev.driver->owner); +- i2c_unregister_device(client); +- } +- +- /* remove I2C demod */ +- client = dvb->i2c_client_demod; +- if (client) { +- module_put(client->dev.driver->owner); +- i2c_unregister_device(client); +- } +- +- em28xx_unregister_dvb(dvb); +- kfree(dvb); +- dev->dvb = NULL; + } + + return 0; diff --git a/queue-3.16/media-em28xx-fix-use-after-free-when-disconnecting.patch b/queue-3.16/media-em28xx-fix-use-after-free-when-disconnecting.patch new file mode 100644 index 00000000..fa3cabc6 --- /dev/null +++ b/queue-3.16/media-em28xx-fix-use-after-free-when-disconnecting.patch @@ -0,0 +1,86 @@ +From: Matthias Schwarzott <zzam@gentoo.org> +Date: Mon, 30 Oct 2017 06:07:29 -0400 +Subject: media: em28xx: Fix use-after-free when disconnecting + +commit 910b0797fa9e8af09c44a3fa36cb310ba7a7218d upstream. + +Fix bug by moving the i2c_unregister_device calls after deregistration +of dvb frontend. + +The new style i2c drivers already destroys the frontend object at +i2c_unregister_device time. +When the dvb frontend is unregistered afterwards it leads to this oops: + + [ 6058.866459] BUG: unable to handle kernel NULL pointer dereference at 00000000000001f8 + [ 6058.866578] IP: dvb_frontend_stop+0x30/0xd0 [dvb_core] + [ 6058.866644] PGD 0 + [ 6058.866646] P4D 0 + + [ 6058.866726] Oops: 0000 [#1] SMP + [ 6058.866768] Modules linked in: rc_pinnacle_pctv_hd(O) em28xx_rc(O) si2157(O) si2168(O) em28xx_dvb(O) em28xx(O) si2165(O) a8293(O) tda10071(O) tea5767(O) tuner(O) cx23885(O) tda18271(O) videobuf2_dvb(O) videobuf2_dma_sg(O) m88ds3103(O) tveeprom(O) cx2341x(O) v4l2_common(O) dvb_core(O) rc_core(O) videobuf2_memops(O) videobuf2_v4l2(O) videobuf2_core(O) videodev(O) media(O) bluetooth ecdh_generic ums_realtek uas rtl8192cu rtl_usb rtl8192c_common rtlwifi usb_storage snd_hda_codec_realtek snd_hda_codec_hdmi snd_hda_codec_generic i2c_mux snd_hda_intel snd_hda_codec snd_hwdep x86_pkg_temp_thermal snd_hda_core kvm_intel kvm irqbypass [last unloaded: videobuf2_memops] + [ 6058.867497] CPU: 2 PID: 7349 Comm: kworker/2:0 Tainted: G W O 4.13.9-gentoo #1 + [ 6058.867595] Hardware name: MEDION E2050 2391/H81H3-EM2, BIOS H81EM2W08.308 08/25/2014 + [ 6058.867692] Workqueue: usb_hub_wq hub_event + [ 6058.867746] task: ffff88011a15e040 task.stack: ffffc90003074000 + [ 6058.867825] RIP: 0010:dvb_frontend_stop+0x30/0xd0 [dvb_core] + [ 6058.867896] RSP: 0018:ffffc90003077b58 EFLAGS: 00010293 + [ 6058.867964] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 000000010040001f + [ 6058.868056] RDX: ffff88011a15e040 RSI: ffffea000464e400 RDI: ffff88001cbe3028 + [ 6058.868150] RBP: ffffc90003077b68 R08: ffff880119390380 R09: 000000010040001f + [ 6058.868241] R10: ffffc90003077b18 R11: 000000000001e200 R12: ffff88001cbe3028 + [ 6058.868330] R13: ffff88001cbe68d0 R14: ffff8800cf734000 R15: ffff8800cf734098 + [ 6058.868419] FS: 0000000000000000(0000) GS:ffff88011fb00000(0000) knlGS:0000000000000000 + [ 6058.868511] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + [ 6058.868578] CR2: 00000000000001f8 CR3: 00000001113c5000 CR4: 00000000001406e0 + [ 6058.868662] Call Trace: + [ 6058.868705] dvb_unregister_frontend+0x2a/0x80 [dvb_core] + [ 6058.868774] em28xx_dvb_fini+0x132/0x220 [em28xx_dvb] + [ 6058.868840] em28xx_close_extension+0x34/0x90 [em28xx] + [ 6058.868902] em28xx_usb_disconnect+0x4e/0x70 [em28xx] + [ 6058.868968] usb_unbind_interface+0x6d/0x260 + [ 6058.869025] device_release_driver_internal+0x150/0x210 + [ 6058.869094] device_release_driver+0xd/0x10 + [ 6058.869150] bus_remove_device+0xe4/0x160 + [ 6058.869204] device_del+0x1ce/0x2f0 + [ 6058.869253] usb_disable_device+0x99/0x270 + [ 6058.869306] usb_disconnect+0x8d/0x260 + [ 6058.869359] hub_event+0x93d/0x1520 + [ 6058.869408] ? dequeue_task_fair+0xae5/0xd20 + [ 6058.869467] process_one_work+0x1d9/0x3e0 + [ 6058.869522] worker_thread+0x43/0x3e0 + [ 6058.869576] kthread+0x104/0x140 + [ 6058.869602] ? trace_event_raw_event_workqueue_work+0x80/0x80 + [ 6058.869640] ? kthread_create_on_node+0x40/0x40 + [ 6058.869673] ret_from_fork+0x22/0x30 + [ 6058.869698] Code: 54 49 89 fc 53 48 8b 9f 18 03 00 00 0f 1f 44 00 00 41 83 bc 24 04 05 00 00 02 74 0c 41 c7 84 24 04 05 00 00 01 00 00 00 0f ae f0 <48> 8b bb f8 01 00 00 48 85 ff 74 5c e8 df 40 f0 e0 48 8b 93 f8 + [ 6058.869850] RIP: dvb_frontend_stop+0x30/0xd0 [dvb_core] RSP: ffffc90003077b58 + [ 6058.869894] CR2: 00000000000001f8 + [ 6058.875880] ---[ end trace 717eecf7193b3fc6 ]--- + +Signed-off-by: Matthias Schwarzott <zzam@gentoo.org> +Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com> +[bwh: Backported to 3.16: adjust context] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +--- + drivers/media/usb/em28xx/em28xx-dvb.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/media/usb/em28xx/em28xx-dvb.c ++++ b/drivers/media/usb/em28xx/em28xx-dvb.c +@@ -1651,6 +1651,8 @@ static int em28xx_dvb_fini(struct em28xx + prevent_sleep(&dvb->fe[1]->ops); + } + ++ em28xx_unregister_dvb(dvb); ++ + /* remove I2C tuner */ + if (client) { + module_put(client->dev.driver->owner); +@@ -1664,7 +1666,6 @@ static int em28xx_dvb_fini(struct em28xx + i2c_unregister_device(client); + } + +- em28xx_unregister_dvb(dvb); + kfree(dvb); + dev->dvb = NULL; + kref_put(&dev->ref, em28xx_free_device); diff --git a/queue-3.16/series b/queue-3.16/series index 27ac961d..8d3c1a1d 100644 --- a/queue-3.16/series +++ b/queue-3.16/series @@ -156,3 +156,7 @@ mm-enforce-min-addr-even-if-capable-in-expand_downwards.patch netlabel-fix-out-of-bounds-memory-accesses.patch net-netem-fix-skb-length-bug_on-in-__skb_to_sgvec.patch ipc-shm-fix-pid-freeing.patch +media-em28xx-dvb-fix-em28xx_dvb_resume-to-not-unregister.patch +media-em28xx-fix-use-after-free-when-disconnecting.patch +bluetooth-verify-that-l2cap_get_conf_opt-provides-large-enough.patch +bluetooth-check-l2cap-option-sizes-returned-from-l2cap_get_conf_opt.patch |