summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hutchings <ben@decadent.org.uk>2019-04-25 18:03:37 +0100
committerBen Hutchings <ben@decadent.org.uk>2019-04-26 01:03:24 +0100
commitcdbf76978f8ac984c08e1412d7139c135402fbb0 (patch)
tree66b557572c7c44cb3f7bc42503d9354bc98cf2a4
parenta7bb7d8cd998299ead2e8f3718193793501a2abd (diff)
downloadlinux-stable-queue-cdbf76978f8ac984c08e1412d7139c135402fbb0.tar.gz
Add various security fixes
-rw-r--r--queue-3.16/bluetooth-check-l2cap-option-sizes-returned-from-l2cap_get_conf_opt.patch193
-rw-r--r--queue-3.16/bluetooth-verify-that-l2cap_get_conf_opt-provides-large-enough.patch61
-rw-r--r--queue-3.16/media-em28xx-dvb-fix-em28xx_dvb_resume-to-not-unregister.patch53
-rw-r--r--queue-3.16/media-em28xx-fix-use-after-free-when-disconnecting.patch86
-rw-r--r--queue-3.16/series4
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