diff mbox series

[1/1] Bluetooth: Verify that l2cap_get_conf_opt provides large enough buffer

Message ID 20190219104856.29208-2-kai.heng.feng@canonical.com
State New
Headers show
Series CVE-2019-3459 - Heap address infoleak in use of l2cap_get_conf_opt | expand

Commit Message

Kai-Heng Feng Feb. 19, 2019, 10:48 a.m. UTC
From: Marcel Holtmann <marcel@holtmann.org>

The function l2cap_get_conf_opt will return L2CAP_CONF_OPT_SIZE + opt->len
as length value. The opt->len however is in control over the remote user
and can be used by an attacker to gain access beyond the bounds of the
actual packet.

To prevent any potential leak of heap memory, it is enough to check that
the resulting len calculation after calling l2cap_get_conf_opt is not
below zero. A well formed packet will always return >= 0 here and will
end with the length value being zero after the last option has been
parsed. In case of malformed packets messing with the opt->len field the
length value will become negative. If that is the case, then just abort
and ignore the option.

In case an attacker uses a too short opt->len value, then garbage will
be parsed, but that is protected by the unknown option handling and also
the option parameter size checks.

CVE-2019-3459

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
(cherry picked from commit 7c9cbd0b5e38a1672fcd137894ace3b042dfbf69 linux-next)
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
---
 net/bluetooth/l2cap_core.c | 6 ++++++
 1 file changed, 6 insertions(+)

Comments

Tyler Hicks Feb. 19, 2019, 4:27 p.m. UTC | #1
On 2019-02-19 18:48:56, Kai-Heng Feng wrote:
> From: Marcel Holtmann <marcel@holtmann.org>
> 
> The function l2cap_get_conf_opt will return L2CAP_CONF_OPT_SIZE + opt->len
> as length value. The opt->len however is in control over the remote user
> and can be used by an attacker to gain access beyond the bounds of the
> actual packet.
> 
> To prevent any potential leak of heap memory, it is enough to check that
> the resulting len calculation after calling l2cap_get_conf_opt is not
> below zero. A well formed packet will always return >= 0 here and will
> end with the length value being zero after the last option has been
> parsed. In case of malformed packets messing with the opt->len field the
> length value will become negative. If that is the case, then just abort
> and ignore the option.
> 
> In case an attacker uses a too short opt->len value, then garbage will
> be parsed, but that is protected by the unknown option handling and also
> the option parameter size checks.
> 
> CVE-2019-3459
> 
> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> (cherry picked from commit 7c9cbd0b5e38a1672fcd137894ace3b042dfbf69 linux-next)
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>

I don't love the fact that these bluetooth fixes are still sitting in
linux-next and haven't landed in Linus' tree yet but they've been
sitting in linux-next for a while and I don't spot any reports of
breakage. I think we should go ahead and pull these in at this time.

Acked-by: Tyler Hicks <tyhicks@canonical.com>

Tyler

> ---
>  net/bluetooth/l2cap_core.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index d17a4736e47c..6c873dc549b0 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -3336,6 +3336,8 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
>  
>  	while (len >= L2CAP_CONF_OPT_SIZE) {
>  		len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
> +		if (len < 0)
> +			break;
>  
>  		hint  = type & L2CAP_CONF_HINT;
>  		type &= L2CAP_CONF_MASK;
> @@ -3547,6 +3549,8 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
>  
>  	while (len >= L2CAP_CONF_OPT_SIZE) {
>  		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
> +		if (len < 0)
> +			break;
>  
>  		switch (type) {
>  		case L2CAP_CONF_MTU:
> @@ -3727,6 +3731,8 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
>  
>  	while (len >= L2CAP_CONF_OPT_SIZE) {
>  		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
> +		if (len < 0)
> +			break;
>  
>  		switch (type) {
>  		case L2CAP_CONF_RFC:
> -- 
> 2.17.1
> 
> 
> -- 
> kernel-team mailing list
> kernel-team@lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team
Stefan Bader March 1, 2019, 1:57 p.m. UTC | #2
On 19.02.19 11:48, Kai-Heng Feng wrote:
> From: Marcel Holtmann <marcel@holtmann.org>
> 
> The function l2cap_get_conf_opt will return L2CAP_CONF_OPT_SIZE + opt->len
> as length value. The opt->len however is in control over the remote user
> and can be used by an attacker to gain access beyond the bounds of the
> actual packet.
> 
> To prevent any potential leak of heap memory, it is enough to check that
> the resulting len calculation after calling l2cap_get_conf_opt is not
> below zero. A well formed packet will always return >= 0 here and will
> end with the length value being zero after the last option has been
> parsed. In case of malformed packets messing with the opt->len field the
> length value will become negative. If that is the case, then just abort
> and ignore the option.
> 
> In case an attacker uses a too short opt->len value, then garbage will
> be parsed, but that is protected by the unknown option handling and also
> the option parameter size checks.
> 
> CVE-2019-3459
> 
> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> (cherry picked from commit 7c9cbd0b5e38a1672fcd137894ace3b042dfbf69 linux-next)
> Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
> ---

Applied to trusty,xenial,bionic,cosmic/master-next. Thanks.

-Stefan

>  net/bluetooth/l2cap_core.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index d17a4736e47c..6c873dc549b0 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -3336,6 +3336,8 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
>  
>  	while (len >= L2CAP_CONF_OPT_SIZE) {
>  		len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
> +		if (len < 0)
> +			break;
>  
>  		hint  = type & L2CAP_CONF_HINT;
>  		type &= L2CAP_CONF_MASK;
> @@ -3547,6 +3549,8 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
>  
>  	while (len >= L2CAP_CONF_OPT_SIZE) {
>  		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
> +		if (len < 0)
> +			break;
>  
>  		switch (type) {
>  		case L2CAP_CONF_MTU:
> @@ -3727,6 +3731,8 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
>  
>  	while (len >= L2CAP_CONF_OPT_SIZE) {
>  		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
> +		if (len < 0)
> +			break;
>  
>  		switch (type) {
>  		case L2CAP_CONF_RFC:
>
diff mbox series

Patch

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index d17a4736e47c..6c873dc549b0 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3336,6 +3336,8 @@  static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
 
 	while (len >= L2CAP_CONF_OPT_SIZE) {
 		len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
+		if (len < 0)
+			break;
 
 		hint  = type & L2CAP_CONF_HINT;
 		type &= L2CAP_CONF_MASK;
@@ -3547,6 +3549,8 @@  static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
 
 	while (len >= L2CAP_CONF_OPT_SIZE) {
 		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
+		if (len < 0)
+			break;
 
 		switch (type) {
 		case L2CAP_CONF_MTU:
@@ -3727,6 +3731,8 @@  static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
 
 	while (len >= L2CAP_CONF_OPT_SIZE) {
 		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
+		if (len < 0)
+			break;
 
 		switch (type) {
 		case L2CAP_CONF_RFC: