Patch "Bluetooth: Properly check L2CAP config option output buffer length" has been added to the 4.9-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.9-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.9 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++; }
@@ -2977,12 +2977,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;
@@ -3007,7 +3010,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;
@@ -3035,7 +3038,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)
@@ -3181,11 +3184,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);
@@ -3210,7 +3214,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 :
@@ -3229,7 +3233,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 :
@@ -3249,21 +3253,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 ;
@@ -3281,17 +3285,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 ; }
@@ -3302,10 +3306,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;
@@ -3407,7 +3412,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 ) {
@@ -3420,7 +3425,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 &&
@@ -3434,7 +3439,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 ;
@@ -3467,7 +3472,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;
@@ -3481,7 +3486,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 ;
@@ -3495,7 +3500,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 ;
@@ -3517,10 +3522,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 };
@@ -3538,13 +3544,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 :
@@ -3558,13 +3564,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 :
@@ -3577,7 +3583,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 :
@@ -3682,7 +3688,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++; }
@@ -3890,7 +3896,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++; }
@@ -3968,7 +3974,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 ;
@@ -4080,7 +4086,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;
@@ -4114,7 +4120,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++; }
@@ -4174,7 +4180,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;
@@ -4204,7 +4210,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;
@@ -4781,7 +4787,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++; } }
@@ -7457,7 +7463,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.9/bluetooth-properly-check-l2cap-config-option-output-buffer-length.patch