]>
Commit | Line | Data |
---|---|---|
a9214244 GKH |
1 | From 7c9cbd0b5e38a1672fcd137894ace3b042dfbf69 Mon Sep 17 00:00:00 2001 |
2 | From: Marcel Holtmann <marcel@holtmann.org> | |
3 | Date: Fri, 18 Jan 2019 13:43:19 +0100 | |
4 | Subject: Bluetooth: Verify that l2cap_get_conf_opt provides large enough buffer | |
5 | ||
6 | From: Marcel Holtmann <marcel@holtmann.org> | |
7 | ||
8 | commit 7c9cbd0b5e38a1672fcd137894ace3b042dfbf69 upstream. | |
9 | ||
10 | The function l2cap_get_conf_opt will return L2CAP_CONF_OPT_SIZE + opt->len | |
11 | as length value. The opt->len however is in control over the remote user | |
12 | and can be used by an attacker to gain access beyond the bounds of the | |
13 | actual packet. | |
14 | ||
15 | To prevent any potential leak of heap memory, it is enough to check that | |
16 | the resulting len calculation after calling l2cap_get_conf_opt is not | |
17 | below zero. A well formed packet will always return >= 0 here and will | |
18 | end with the length value being zero after the last option has been | |
19 | parsed. In case of malformed packets messing with the opt->len field the | |
20 | length value will become negative. If that is the case, then just abort | |
21 | and ignore the option. | |
22 | ||
23 | In case an attacker uses a too short opt->len value, then garbage will | |
24 | be parsed, but that is protected by the unknown option handling and also | |
25 | the option parameter size checks. | |
26 | ||
27 | Signed-off-by: Marcel Holtmann <marcel@holtmann.org> | |
28 | Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
29 | Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> | |
30 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
31 | ||
32 | --- | |
33 | net/bluetooth/l2cap_core.c | 6 ++++++ | |
34 | 1 file changed, 6 insertions(+) | |
35 | ||
36 | --- a/net/bluetooth/l2cap_core.c | |
37 | +++ b/net/bluetooth/l2cap_core.c | |
38 | @@ -3290,6 +3290,8 @@ static int l2cap_parse_conf_req(struct l | |
39 | ||
40 | while (len >= L2CAP_CONF_OPT_SIZE) { | |
41 | len -= l2cap_get_conf_opt(&req, &type, &olen, &val); | |
42 | + if (len < 0) | |
43 | + break; | |
44 | ||
45 | hint = type & L2CAP_CONF_HINT; | |
46 | type &= L2CAP_CONF_MASK; | |
47 | @@ -3508,6 +3510,8 @@ static int l2cap_parse_conf_rsp(struct l | |
48 | ||
49 | while (len >= L2CAP_CONF_OPT_SIZE) { | |
50 | len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); | |
51 | + if (len < 0) | |
52 | + break; | |
53 | ||
54 | switch (type) { | |
55 | case L2CAP_CONF_MTU: | |
56 | @@ -3693,6 +3697,8 @@ static void l2cap_conf_rfc_get(struct l2 | |
57 | ||
58 | while (len >= L2CAP_CONF_OPT_SIZE) { | |
59 | len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); | |
60 | + if (len < 0) | |
61 | + break; | |
62 | ||
63 | switch (type) { | |
64 | case L2CAP_CONF_RFC: |