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