]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/5.0.6/bluetooth-check-l2cap-option-sizes-returned-from-l2cap_get_conf_opt.patch
Linux 5.0.6
[thirdparty/kernel/stable-queue.git] / releases / 5.0.6 / bluetooth-check-l2cap-option-sizes-returned-from-l2cap_get_conf_opt.patch
1 From af3d5d1c87664a4f150fcf3534c6567cb19909b0 Mon Sep 17 00:00:00 2001
2 From: Marcel Holtmann <marcel@holtmann.org>
3 Date: Fri, 18 Jan 2019 12:56:20 +0100
4 Subject: Bluetooth: Check L2CAP option sizes returned from l2cap_get_conf_opt
5
6 From: Marcel Holtmann <marcel@holtmann.org>
7
8 commit af3d5d1c87664a4f150fcf3534c6567cb19909b0 upstream.
9
10 When doing option parsing for standard type values of 1, 2 or 4 octets,
11 the value is converted directly into a variable instead of a pointer. To
12 avoid being tricked into being a pointer, check that for these option
13 types that sizes actually match. In L2CAP every option is fixed size and
14 thus it is prudent anyway to ensure that the remote side sends us the
15 right option size along with option paramters.
16
17 If the option size is not matching the option type, then that option is
18 silently ignored. It is a protocol violation and instead of trying to
19 give the remote attacker any further hints just pretend that option is
20 not present and proceed with the default values. Implementation
21 following the specification and its qualification procedures will always
22 use the correct size and thus not being impacted here.
23
24 To keep the code readable and consistent accross all options, a few
25 cosmetic changes were also required.
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 | 77 ++++++++++++++++++++++++++-------------------
34 1 file changed, 46 insertions(+), 31 deletions(-)
35
36 --- a/net/bluetooth/l2cap_core.c
37 +++ b/net/bluetooth/l2cap_core.c
38 @@ -3343,10 +3343,14 @@ static int l2cap_parse_conf_req(struct l
39
40 switch (type) {
41 case L2CAP_CONF_MTU:
42 + if (olen != 2)
43 + break;
44 mtu = val;
45 break;
46
47 case L2CAP_CONF_FLUSH_TO:
48 + if (olen != 2)
49 + break;
50 chan->flush_to = val;
51 break;
52
53 @@ -3354,26 +3358,30 @@ static int l2cap_parse_conf_req(struct l
54 break;
55
56 case L2CAP_CONF_RFC:
57 - if (olen == sizeof(rfc))
58 - memcpy(&rfc, (void *) val, olen);
59 + if (olen != sizeof(rfc))
60 + break;
61 + memcpy(&rfc, (void *) val, olen);
62 break;
63
64 case L2CAP_CONF_FCS:
65 + if (olen != 1)
66 + break;
67 if (val == L2CAP_FCS_NONE)
68 set_bit(CONF_RECV_NO_FCS, &chan->conf_state);
69 break;
70
71 case L2CAP_CONF_EFS:
72 - if (olen == sizeof(efs)) {
73 - remote_efs = 1;
74 - memcpy(&efs, (void *) val, olen);
75 - }
76 + if (olen != sizeof(efs))
77 + break;
78 + remote_efs = 1;
79 + memcpy(&efs, (void *) val, olen);
80 break;
81
82 case L2CAP_CONF_EWS:
83 + if (olen != 2)
84 + break;
85 if (!(chan->conn->local_fixed_chan & L2CAP_FC_A2MP))
86 return -ECONNREFUSED;
87 -
88 set_bit(FLAG_EXT_CTRL, &chan->flags);
89 set_bit(CONF_EWS_RECV, &chan->conf_state);
90 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
91 @@ -3383,7 +3391,6 @@ static int l2cap_parse_conf_req(struct l
92 default:
93 if (hint)
94 break;
95 -
96 result = L2CAP_CONF_UNKNOWN;
97 *((u8 *) ptr++) = type;
98 break;
99 @@ -3551,55 +3558,60 @@ static int l2cap_parse_conf_rsp(struct l
100
101 switch (type) {
102 case L2CAP_CONF_MTU:
103 + if (olen != 2)
104 + break;
105 if (val < L2CAP_DEFAULT_MIN_MTU) {
106 *result = L2CAP_CONF_UNACCEPT;
107 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
108 } else
109 chan->imtu = val;
110 - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr);
111 + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu,
112 + endptr - ptr);
113 break;
114
115 case L2CAP_CONF_FLUSH_TO:
116 + if (olen != 2)
117 + break;
118 chan->flush_to = val;
119 - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
120 - 2, chan->flush_to, endptr - ptr);
121 + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2,
122 + chan->flush_to, endptr - ptr);
123 break;
124
125 case L2CAP_CONF_RFC:
126 - if (olen == sizeof(rfc))
127 - memcpy(&rfc, (void *)val, olen);
128 -
129 + if (olen != sizeof(rfc))
130 + break;
131 + memcpy(&rfc, (void *)val, olen);
132 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
133 rfc.mode != chan->mode)
134 return -ECONNREFUSED;
135 -
136 chan->fcs = 0;
137 -
138 - l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
139 - sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
140 + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
141 + (unsigned long) &rfc, endptr - ptr);
142 break;
143
144 case L2CAP_CONF_EWS:
145 + if (olen != 2)
146 + break;
147 chan->ack_win = min_t(u16, val, chan->ack_win);
148 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
149 chan->tx_win, endptr - ptr);
150 break;
151
152 case L2CAP_CONF_EFS:
153 - if (olen == sizeof(efs)) {
154 - memcpy(&efs, (void *)val, olen);
155 -
156 - if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
157 - efs.stype != L2CAP_SERV_NOTRAFIC &&
158 - efs.stype != chan->local_stype)
159 - return -ECONNREFUSED;
160 -
161 - l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
162 - (unsigned long) &efs, endptr - ptr);
163 - }
164 + if (olen != sizeof(efs))
165 + break;
166 + memcpy(&efs, (void *)val, olen);
167 + if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
168 + efs.stype != L2CAP_SERV_NOTRAFIC &&
169 + efs.stype != chan->local_stype)
170 + return -ECONNREFUSED;
171 + l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
172 + (unsigned long) &efs, endptr - ptr);
173 break;
174
175 case L2CAP_CONF_FCS:
176 + if (olen != 1)
177 + break;
178 if (*result == L2CAP_CONF_PENDING)
179 if (val == L2CAP_FCS_NONE)
180 set_bit(CONF_RECV_NO_FCS,
181 @@ -3731,10 +3743,13 @@ static void l2cap_conf_rfc_get(struct l2
182
183 switch (type) {
184 case L2CAP_CONF_RFC:
185 - if (olen == sizeof(rfc))
186 - memcpy(&rfc, (void *)val, olen);
187 + if (olen != sizeof(rfc))
188 + break;
189 + memcpy(&rfc, (void *)val, olen);
190 break;
191 case L2CAP_CONF_EWS:
192 + if (olen != 2)
193 + break;
194 txwin_ext = val;
195 break;
196 }