Patch "Bluetooth: Properly check L2CAP config option output buffer length" has been added to the 4.13-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
Bluetooth: Properly check L2CAP config option output buffer length
to the 4.13-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
bluetooth-properly-check-l2cap-config-option-output-buffer-length.patch
and it can be found in the queue-4.13 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
e860d2c904d1a9f38a24eb44c9f34b8f915a6ea3Mon Sep 17 00:00:00 2001
From: Ben Seri <[email protected]>
Date: Sat, 9 Sep 2017 23:15:59 +0200
Subject: Bluetooth: Properly check L2CAP config option output buffer length
From: Ben Seri <[email protected]>
commit e860d2c904d1a9f38a24eb44c9f34b8f915a6ea3 upstream.
Validate the output buffer length for L2CAP config requests and responses to avoid overflowing the stack buffer used for building the option blocks.
--- net/bluetooth/l2cap_core.c | 80 ++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 37 deletions(-)
net/bluetooth/l2cap_core.c +43 -37
@@ -58,7 +58,7 @@ static struct sk_buff *l2cap_build_cmd(s u8 code, u8 ident, u16 dlen, void *data);static void l2cap_send_cmd (struct l2cap_conn *conn,u8 ident,u8 code,u16 len,void *data); -static int l2cap_build_conf_req (struct l2cap_chan *chan,void *data); +static int l2cap_build_conf_req (struct l2cap_chan *chan,void *data,size_t data_size);static void l2cap_send_disconn_req (struct l2cap_chan *chan,int err); static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
@@ -1473,7 +1473,7 @@ static void l2cap_conn_start(struct l2caset_bit (CONF_REQ_SENT , &chan->conf_state);l2cap_send_cmd (conn,l2cap_get_ident (conn),L2CAP_CONF_REQ , -l2cap_build_conf_req (chan, buf), buf); +l2cap_build_conf_req (chan, buf,sizeof (buf)), buf); chan->num_conf_req++; }
@@ -2987,12 +2987,15 @@ static inline int l2cap_get_conf_opt(voireturn len; } -static void l2cap_add_conf_opt (void **ptr,u8 type,u8 len,unsigned long val) +static void l2cap_add_conf_opt (void **ptr,u8 type,u8 len,unsigned long val,size_t size) {struct l2cap_conf_opt *opt = *ptr;BT_DBG ("type 0x%2.2x len %u val 0x%lx" , type, len, val); +if (size <L2CAP_CONF_OPT_SIZE + len) +return ; + opt->type = type; opt->len = len;
@@ -3017,7 +3020,7 @@ static void l2cap_add_conf_opt(void **pt *ptr +=L2CAP_CONF_OPT_SIZE + len; } -static void l2cap_add_opt_efs (void **ptr,struct l2cap_chan *chan) +static void l2cap_add_opt_efs (void **ptr,struct l2cap_chan *chan,size_t size) {struct l2cap_conf_efs efs;
@@ -3045,7 +3048,7 @@ static void l2cap_add_opt_efs(void **ptr }l2cap_add_conf_opt (ptr,L2CAP_CONF_EFS ,sizeof (efs), - (unsigned long ) &efs); + (unsigned long ) &efs, size); }static void l2cap_ack_timeout (struct work_struct *work)
@@ -3191,11 +3194,12 @@ static inline void l2cap_txwin_setup(str chan->ack_win = chan->tx_win; } -static int l2cap_build_conf_req (struct l2cap_chan *chan,void *data) +static int l2cap_build_conf_req (struct l2cap_chan *chan,void *data,size_t data_size) {struct l2cap_conf_req *req = data;struct l2cap_conf_rfc rfc = { .mode = chan->mode };void *ptr = req->data; +void *endptr = data + data_size;u16 size;BT_DBG ("chan %p" , chan);
@@ -3220,7 +3224,7 @@ static int l2cap_build_conf_req(struct l done:if (chan->imtu !=L2CAP_DEFAULT_MTU ) -l2cap_add_conf_opt (&ptr,L2CAP_CONF_MTU ,2 , chan->imtu); +l2cap_add_conf_opt (&ptr,L2CAP_CONF_MTU ,2 , chan->imtu, endptr - ptr);switch (chan->mode) {case L2CAP_MODE_BASIC :
@@ -3239,7 +3243,7 @@ done: rfc.max_pdu_size =0 ;l2cap_add_conf_opt (&ptr,L2CAP_CONF_RFC ,sizeof (rfc), - (unsigned long ) &rfc); + (unsigned long ) &rfc, endptr - ptr);break ;case L2CAP_MODE_ERTM :
@@ -3259,21 +3263,21 @@ done: L2CAP_DEFAULT_TX_WINDOW);l2cap_add_conf_opt (&ptr,L2CAP_CONF_RFC ,sizeof (rfc), - (unsigned long ) &rfc); + (unsigned long ) &rfc, endptr - ptr);if (test_bit (FLAG_EFS_ENABLE , &chan->flags)) -l2cap_add_opt_efs (&ptr, chan); +l2cap_add_opt_efs (&ptr, chan, endptr - ptr);if (test_bit (FLAG_EXT_CTRL , &chan->flags))l2cap_add_conf_opt (&ptr,L2CAP_CONF_EWS ,2 , - chan->tx_win); + chan->tx_win, endptr - ptr);if (chan->conn->feat_mask &L2CAP_FEAT_FCS )if (chan->fcs ==L2CAP_FCS_NONE ||test_bit (CONF_RECV_NO_FCS , &chan->conf_state)) { chan->fcs =L2CAP_FCS_NONE ;l2cap_add_conf_opt (&ptr,L2CAP_CONF_FCS ,1 , - chan->fcs); + chan->fcs, endptr - ptr); }break ;
@@ -3291,17 +3295,17 @@ done: rfc.max_pdu_size =cpu_to_le16 (size);l2cap_add_conf_opt (&ptr,L2CAP_CONF_RFC ,sizeof (rfc), - (unsigned long ) &rfc); + (unsigned long ) &rfc, endptr - ptr);if (test_bit (FLAG_EFS_ENABLE , &chan->flags)) -l2cap_add_opt_efs (&ptr, chan); +l2cap_add_opt_efs (&ptr, chan, endptr - ptr);if (chan->conn->feat_mask &L2CAP_FEAT_FCS )if (chan->fcs ==L2CAP_FCS_NONE ||test_bit (CONF_RECV_NO_FCS , &chan->conf_state)) { chan->fcs =L2CAP_FCS_NONE ;l2cap_add_conf_opt (&ptr,L2CAP_CONF_FCS ,1 , - chan->fcs); + chan->fcs, endptr - ptr); }break ; }
@@ -3312,10 +3316,11 @@ done:return ptr - data; } -static int l2cap_parse_conf_req (struct l2cap_chan *chan,void *data) +static int l2cap_parse_conf_req (struct l2cap_chan *chan,void *data,size_t data_size) {struct l2cap_conf_rsp *rsp = data;void *ptr = rsp->data; +void *endptr = data + data_size;void *req = chan->conf_req;int len = chan->conf_len;int type, hint, olen;
@@ -3417,7 +3422,7 @@ done:return -ECONNREFUSED ;l2cap_add_conf_opt (&ptr,L2CAP_CONF_RFC ,sizeof (rfc), - (unsigned long ) &rfc); + (unsigned long ) &rfc, endptr - ptr); }if (result ==L2CAP_CONF_SUCCESS ) {
@@ -3430,7 +3435,7 @@ done: chan->omtu = mtu;set_bit (CONF_MTU_DONE , &chan->conf_state); } -l2cap_add_conf_opt (&ptr,L2CAP_CONF_MTU ,2 , chan->omtu); +l2cap_add_conf_opt (&ptr,L2CAP_CONF_MTU ,2 , chan->omtu, endptr - ptr);if (remote_efs) { if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
@@ -3444,7 +3449,7 @@ done:l2cap_add_conf_opt (&ptr,L2CAP_CONF_EFS ,sizeof (efs), - (unsigned long ) &efs); + (unsigned long ) &efs, endptr - ptr); }else {/* Send PENDING Conf Rsp */ result =L2CAP_CONF_PENDING ;
@@ -3477,7 +3482,7 @@ done:set_bit (CONF_MODE_DONE , &chan->conf_state);l2cap_add_conf_opt (&ptr,L2CAP_CONF_RFC , -sizeof (rfc), (unsigned long ) &rfc); +sizeof (rfc), (unsigned long ) &rfc, endptr - ptr);if (test_bit (FLAG_EFS_ENABLE , &chan->flags)) { chan->remote_id = efs.id;
@@ -3491,7 +3496,7 @@ done:le32_to_cpu (efs.sdu_itime);l2cap_add_conf_opt (&ptr,L2CAP_CONF_EFS ,sizeof (efs), - (unsigned long ) &efs); + (unsigned long ) &efs, endptr - ptr); }break ;
@@ -3505,7 +3510,7 @@ done:set_bit (CONF_MODE_DONE , &chan->conf_state);l2cap_add_conf_opt (&ptr,L2CAP_CONF_RFC ,sizeof (rfc), - (unsigned long ) &rfc); + (unsigned long ) &rfc, endptr - ptr);break ;
@@ -3527,10 +3532,11 @@ done: }static int l2cap_parse_conf_rsp (struct l2cap_chan *chan,void *rsp,int len, -void *data,u16 *result) +void *data,size_t size,u16 *result) {struct l2cap_conf_req *req = data;void *ptr = req->data; +void *endptr = data + size;int type, olen;unsigned long val;struct l2cap_conf_rfc rfc = { .mode =L2CAP_MODE_BASIC };
@@ -3548,13 +3554,13 @@ static int l2cap_parse_conf_rsp(struct l chan->imtu =L2CAP_DEFAULT_MIN_MTU ; }else chan->imtu = val; -l2cap_add_conf_opt (&ptr,L2CAP_CONF_MTU ,2 , chan->imtu); +l2cap_add_conf_opt (&ptr,L2CAP_CONF_MTU ,2 , chan->imtu, endptr - ptr);break ;case L2CAP_CONF_FLUSH_TO : chan->flush_to = val;l2cap_add_conf_opt (&ptr,L2CAP_CONF_FLUSH_TO , -2 , chan->flush_to); +2 , chan->flush_to, endptr - ptr);break ;case L2CAP_CONF_RFC :
@@ -3568,13 +3574,13 @@ static int l2cap_parse_conf_rsp(struct l chan->fcs =0 ;l2cap_add_conf_opt (&ptr,L2CAP_CONF_RFC , -sizeof (rfc), (unsigned long ) &rfc); +sizeof (rfc), (unsigned long ) &rfc, endptr - ptr);break ;case L2CAP_CONF_EWS : chan->ack_win =min_t (u16, val, chan->ack_win);l2cap_add_conf_opt (&ptr,L2CAP_CONF_EWS ,2 , - chan->tx_win); + chan->tx_win, endptr - ptr);break ;case L2CAP_CONF_EFS :
@@ -3587,7 +3593,7 @@ static int l2cap_parse_conf_rsp(struct lreturn -ECONNREFUSED ;l2cap_add_conf_opt (&ptr,L2CAP_CONF_EFS ,sizeof (efs), - (unsigned long ) &efs); + (unsigned long ) &efs, endptr - ptr);break ;case L2CAP_CONF_FCS :
@@ -3692,7 +3698,7 @@ void __l2cap_connect_rsp_defer(struct l2return ;l2cap_send_cmd (conn,l2cap_get_ident (conn),L2CAP_CONF_REQ , -l2cap_build_conf_req (chan, buf), buf); +l2cap_build_conf_req (chan, buf,sizeof (buf)), buf); chan->num_conf_req++; }
@@ -3900,7 +3906,7 @@ sendresp:u8 buf[128 ];set_bit (CONF_REQ_SENT , &chan->conf_state);l2cap_send_cmd (conn,l2cap_get_ident (conn),L2CAP_CONF_REQ , -l2cap_build_conf_req (chan, buf), buf); +l2cap_build_conf_req (chan, buf,sizeof (buf)), buf); chan->num_conf_req++; }
@@ -3978,7 +3984,7 @@ static int l2cap_connect_create_rsp(strubreak ;l2cap_send_cmd (conn,l2cap_get_ident (conn),L2CAP_CONF_REQ , -l2cap_build_conf_req (chan, req), req); +l2cap_build_conf_req (chan, req,sizeof (req)), req); chan->num_conf_req++;break ;
@@ -4090,7 +4096,7 @@ static inline int l2cap_config_req(struc }/* Complete config. */ - len =l2cap_parse_conf_req (chan, rsp); + len =l2cap_parse_conf_req (chan, rsp,sizeof (rsp));if (len <0 ) {l2cap_send_disconn_req (chan,ECONNRESET ); goto unlock;
@@ -4124,7 +4130,7 @@ static inline int l2cap_config_req(strucif (!test_and_set_bit (CONF_REQ_SENT , &chan->conf_state)) {u8 buf[64 ];l2cap_send_cmd (conn,l2cap_get_ident (conn),L2CAP_CONF_REQ , -l2cap_build_conf_req (chan, buf), buf); +l2cap_build_conf_req (chan, buf,sizeof (buf)), buf); chan->num_conf_req++; }
@@ -4184,7 +4190,7 @@ static inline int l2cap_config_rsp(strucchar buf[64 ]; len =l2cap_parse_conf_rsp (chan, rsp->data, len, - buf, &result); + buf,sizeof (buf), &result);if (len <0 ) {l2cap_send_disconn_req (chan,ECONNRESET ); goto done;
@@ -4214,7 +4220,7 @@ static inline int l2cap_config_rsp(struc/* throw out any old stored conf requests */ result =L2CAP_CONF_SUCCESS ; len =l2cap_parse_conf_rsp (chan, rsp->data, len, - req, &result); + req,sizeof (req), &result);if (len <0 ) {l2cap_send_disconn_req (chan,ECONNRESET ); goto done;
@@ -4791,7 +4797,7 @@ static void l2cap_do_create(struct l2capset_bit (CONF_REQ_SENT , &chan->conf_state);l2cap_send_cmd (chan->conn,l2cap_get_ident (chan->conn),L2CAP_CONF_REQ , -l2cap_build_conf_req (chan, buf), buf); +l2cap_build_conf_req (chan, buf,sizeof (buf)), buf); chan->num_conf_req++; } }
@@ -7465,7 +7471,7 @@ static void l2cap_security_cfm(struct hcset_bit (CONF_REQ_SENT , &chan->conf_state);l2cap_send_cmd (conn,l2cap_get_ident (conn),L2CAP_CONF_REQ , -l2cap_build_conf_req (chan, buf), +l2cap_build_conf_req (chan, buf,sizeof (buf)), buf); chan->num_conf_req++; }
Patches currently in stable-queue which might be from [email protected] are
queue-4.13/bluetooth-properly-check-l2cap-config-option-output-buffer-length.patch