Jeremy Cline 0f8450a
From 20614b74e481f0c9f94032ae99f110d4647b65a6 Mon Sep 17 00:00:00 2001
Jeremy Cline 0f8450a
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Jeremy Cline 0f8450a
Date: Thu, 10 Jan 2019 07:28:33 +0100
Jeremy Cline 0f8450a
Subject: [PATCH 1/2] Bluetooth: check message types in l2cap_get_conf_opt
Jeremy Cline 0f8450a
Jeremy Cline 0f8450a
l2cap_get_conf_opt can handle a "default" message type, but it needs to
Jeremy Cline 0f8450a
be verified that it really is the correct type (CONF_EFS or CONF_RFC)
Jeremy Cline 0f8450a
before passing it back to the caller.  To do this we need to check the
Jeremy Cline 0f8450a
return value of this call now and handle the error correctly up the
Jeremy Cline 0f8450a
stack.
Jeremy Cline 0f8450a
Jeremy Cline 0f8450a
Based on a patch from Ran Menscher.
Jeremy Cline 0f8450a
Jeremy Cline 0f8450a
Reported-by: Ran Menscher <ran.menscher@karambasecurity.com>
Jeremy Cline 0f8450a
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Jeremy Cline 0f8450a
Signed-off-by: Jeremy Cline <jcline@redhat.com>
Jeremy Cline 0f8450a
---
Jeremy Cline 0f8450a
 net/bluetooth/l2cap_core.c | 25 +++++++++++++++++++------
Jeremy Cline 0f8450a
 1 file changed, 19 insertions(+), 6 deletions(-)
Jeremy Cline 0f8450a
Jeremy Cline 0f8450a
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
Jeremy Cline 0f8450a
index d17a4736e47c..a0ce6e8e5ef7 100644
Jeremy Cline 0f8450a
--- a/net/bluetooth/l2cap_core.c
Jeremy Cline 0f8450a
+++ b/net/bluetooth/l2cap_core.c
Jeremy Cline 0f8450a
@@ -2979,6 +2979,10 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen,
Jeremy Cline 0f8450a
 		break;
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 	default:
Jeremy Cline 0f8450a
+		/* Only CONF_EFS and CONF_RFC are allowed here */
Jeremy Cline 0f8450a
+		if ((opt->type != L2CAP_CONF_EFS) &&
Jeremy Cline 0f8450a
+		    (opt->type != L2CAP_CONF_RFC))
Jeremy Cline 0f8450a
+			return -EPROTO;
Jeremy Cline 0f8450a
 		*val = (unsigned long) opt->val;
Jeremy Cline 0f8450a
 		break;
Jeremy Cline 0f8450a
 	}
Jeremy Cline 0f8450a
@@ -3323,7 +3327,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
Jeremy Cline 0f8450a
 	void *endptr = data + data_size;
Jeremy Cline 0f8450a
 	void *req = chan->conf_req;
Jeremy Cline 0f8450a
 	int len = chan->conf_len;
Jeremy Cline 0f8450a
-	int type, hint, olen;
Jeremy Cline 0f8450a
+	int type, hint, olen, err;
Jeremy Cline 0f8450a
 	unsigned long val;
Jeremy Cline 0f8450a
 	struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Jeremy Cline 0f8450a
 	struct l2cap_conf_efs efs;
Jeremy Cline 0f8450a
@@ -3335,7 +3339,10 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
Jeremy Cline 0f8450a
 	BT_DBG("chan %p", chan);
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 	while (len >= L2CAP_CONF_OPT_SIZE) {
Jeremy Cline 0f8450a
-		len -= l2cap_get_conf_opt(&req, &type, &olen, &val;;
Jeremy Cline 0f8450a
+		err = l2cap_get_conf_opt(&req, &type, &olen, &val;;
Jeremy Cline 0f8450a
+		if (err < 0)
Jeremy Cline 0f8450a
+			return err;
Jeremy Cline 0f8450a
+		len -= err;
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 		hint  = type & L2CAP_CONF_HINT;
Jeremy Cline 0f8450a
 		type &= L2CAP_CONF_MASK;
Jeremy Cline 0f8450a
@@ -3538,7 +3545,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
Jeremy Cline 0f8450a
 	struct l2cap_conf_req *req = data;
Jeremy Cline 0f8450a
 	void *ptr = req->data;
Jeremy Cline 0f8450a
 	void *endptr = data + size;
Jeremy Cline 0f8450a
-	int type, olen;
Jeremy Cline 0f8450a
+	int type, olen, err;
Jeremy Cline 0f8450a
 	unsigned long val;
Jeremy Cline 0f8450a
 	struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Jeremy Cline 0f8450a
 	struct l2cap_conf_efs efs;
Jeremy Cline 0f8450a
@@ -3546,7 +3553,10 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
Jeremy Cline 0f8450a
 	BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 	while (len >= L2CAP_CONF_OPT_SIZE) {
Jeremy Cline 0f8450a
-		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val;;
Jeremy Cline 0f8450a
+		err = l2cap_get_conf_opt(&rsp, &type, &olen, &val;;
Jeremy Cline 0f8450a
+		if (err < 0)
Jeremy Cline 0f8450a
+			return err;
Jeremy Cline 0f8450a
+		len -= err;
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 		switch (type) {
Jeremy Cline 0f8450a
 		case L2CAP_CONF_MTU:
Jeremy Cline 0f8450a
@@ -3706,7 +3716,7 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Jeremy Cline 0f8450a
 {
Jeremy Cline 0f8450a
-	int type, olen;
Jeremy Cline 0f8450a
+	int type, olen, err;
Jeremy Cline 0f8450a
 	unsigned long val;
Jeremy Cline 0f8450a
 	/* Use sane default values in case a misbehaving remote device
Jeremy Cline 0f8450a
 	 * did not send an RFC or extended window size option.
Jeremy Cline 0f8450a
@@ -3726,7 +3736,10 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Jeremy Cline 0f8450a
 		return;
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 	while (len >= L2CAP_CONF_OPT_SIZE) {
Jeremy Cline 0f8450a
-		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val;;
Jeremy Cline 0f8450a
+		err = l2cap_get_conf_opt(&rsp, &type, &olen, &val;;
Jeremy Cline 0f8450a
+		if (err < 0)
Jeremy Cline 0f8450a
+			return;
Jeremy Cline 0f8450a
+		len -= err;
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 		switch (type) {
Jeremy Cline 0f8450a
 		case L2CAP_CONF_RFC:
Jeremy Cline 0f8450a
-- 
Jeremy Cline 0f8450a
2.20.1
Jeremy Cline 0f8450a
Jeremy Cline 0f8450a
From 50cd5314f5ffa264906f4986f414750d648c4ece Mon Sep 17 00:00:00 2001
Jeremy Cline 0f8450a
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Jeremy Cline 0f8450a
Date: Thu, 10 Jan 2019 07:29:17 +0100
Jeremy Cline 0f8450a
Subject: [PATCH 2/2] Bluetooth: check the buffer size for some messages before
Jeremy Cline 0f8450a
 parsing
Jeremy Cline 0f8450a
Jeremy Cline 0f8450a
The L2CAP_CONF_EFS and L2CAP_CONF_RFC messages can be sent from
Jeremy Cline 0f8450a
userspace so their structure sizes need to be checked before parsing
Jeremy Cline 0f8450a
them.
Jeremy Cline 0f8450a
Jeremy Cline 0f8450a
Based on a patch from Ran Menscher.
Jeremy Cline 0f8450a
Jeremy Cline 0f8450a
Reported-by: Ran Menscher <ran.menscher@karambasecurity.com>
Jeremy Cline 0f8450a
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Jeremy Cline 0f8450a
Signed-off-by: Jeremy Cline <jcline@redhat.com>
Jeremy Cline 0f8450a
---
Jeremy Cline 0f8450a
 net/bluetooth/l2cap_core.c | 12 ++++++++----
Jeremy Cline 0f8450a
 1 file changed, 8 insertions(+), 4 deletions(-)
Jeremy Cline 0f8450a
Jeremy Cline 0f8450a
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
Jeremy Cline 0f8450a
index a0ce6e8e5ef7..d8d3cbdc0d29 100644
Jeremy Cline 0f8450a
--- a/net/bluetooth/l2cap_core.c
Jeremy Cline 0f8450a
+++ b/net/bluetooth/l2cap_core.c
Jeremy Cline 0f8450a
@@ -3360,7 +3360,8 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
Jeremy Cline 0f8450a
 			break;
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 		case L2CAP_CONF_RFC:
Jeremy Cline 0f8450a
-			if (olen == sizeof(rfc))
Jeremy Cline 0f8450a
+			if ((olen == sizeof(rfc)) &&
Jeremy Cline 0f8450a
+			    (endptr - ptr >= L2CAP_CONF_OPT_SIZE + sizeof(rfc)))
Jeremy Cline 0f8450a
 				memcpy(&rfc, (void *) val, olen);
Jeremy Cline 0f8450a
 			break;
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
@@ -3370,7 +3371,8 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
Jeremy Cline 0f8450a
 			break;
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 		case L2CAP_CONF_EFS:
Jeremy Cline 0f8450a
-			if (olen == sizeof(efs)) {
Jeremy Cline 0f8450a
+			if ((olen == sizeof(efs)) &&
Jeremy Cline 0f8450a
+			    (endptr - ptr >= L2CAP_CONF_OPT_SIZE + sizeof(efs))) {
Jeremy Cline 0f8450a
 				remote_efs = 1;
Jeremy Cline 0f8450a
 				memcpy(&efs, (void *) val, olen);
Jeremy Cline 0f8450a
 			}
Jeremy Cline 0f8450a
@@ -3575,7 +3577,8 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
Jeremy Cline 0f8450a
 			break;
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 		case L2CAP_CONF_RFC:
Jeremy Cline 0f8450a
-			if (olen == sizeof(rfc))
Jeremy Cline 0f8450a
+			if ((olen == sizeof(rfc)) &&
Jeremy Cline 0f8450a
+			    (endptr - ptr >= L2CAP_CONF_OPT_SIZE + sizeof(rfc)))
Jeremy Cline 0f8450a
 				memcpy(&rfc, (void *)val, olen);
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 			if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Jeremy Cline 0f8450a
@@ -3595,7 +3598,8 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
Jeremy Cline 0f8450a
 			break;
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 		case L2CAP_CONF_EFS:
Jeremy Cline 0f8450a
-			if (olen == sizeof(efs)) {
Jeremy Cline 0f8450a
+			if ((olen == sizeof(efs)) &&
Jeremy Cline 0f8450a
+			    (endptr - ptr >= L2CAP_CONF_OPT_SIZE + sizeof(efs))) {
Jeremy Cline 0f8450a
 				memcpy(&efs, (void *)val, olen);
Jeremy Cline 0f8450a
 
Jeremy Cline 0f8450a
 				if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
Jeremy Cline 0f8450a
-- 
Jeremy Cline 0f8450a
2.20.1
Jeremy Cline 0f8450a