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