xorl %eax, %eax

CVE-2011-2497: Linux kernel Bluetooth L2CAP Remote Heap Memory Corruption

with one comment

This was discovered and reported some time ago by Dan Rosenberg (aka bliss) as we can read here. The exact vulnerable code is available in net/bluetooth/l2cap_core.c file.

static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
{
        struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
        u16 dcid, flags;
        u8 rsp[64];
        struct sock *sk;
        int len;

        dcid  = __le16_to_cpu(req->dcid);
        flags = __le16_to_cpu(req->flags);
  ...
        /* Reject if config buffer is too small. */
        len = cmd_len - sizeof(*req);
        if (l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) {
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
                                l2cap_build_conf_rsp(sk, rsp,
                                        L2CAP_CONF_REJECT, flags), rsp);
                goto unlock;
        }

        /* Store config. */
        memcpy(l2cap_pi(sk)->conf_req + l2cap_pi(sk)->conf_len, req->data, len);
        l2cap_pi(sk)->conf_len += len;
  ...
unlock:
        bh_unlock_sock(sk);
        return 0;
}
  ...
static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                        struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
{
        int err = 0;

        switch (cmd->code) {
  ...
        case L2CAP_CONF_REQ:
                err = l2cap_config_req(conn, cmd, cmd_len, data);
                break;
  ...
        default:
                BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
                err = -EINVAL;
                break;
        }

        return err;
}

This code is part of Linux kernel’s implementation of L2CAP Bluetooth protocol. More specifically, the l2cap_bredr_sig_cmd() will trigger the call to l2cap_config_req() in case of a ‘L2CAP_CONF_REQ’ signaling command.

Now, if we move to l2cap_config_req() we will see that the signed integer ‘len’ is initialized with the value of ‘cmd_len’ (command length) minus the request’s size. If this results in an integer underflow, the subsequent check in the ‘if’ clause could be bypassed due to the addition with ‘l2cap_pi(sk)->conf_len’ and the final call to memcpy() passing ‘len’ as an argument could result in kernel heap memory corruption.

So, by providing a small command size value a remote attacker could trigger this bug. At last, the fix dor this vulnerability was to add a check for negative values of ‘len’ as shown below.

 	len = cmd_len - sizeof(*req);
-	if (chan->conf_len + len > sizeof(chan->conf_req)) {
+	if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
 		l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
 				l2cap_build_conf_rsp(chan, rsp,
 					L2CAP_CONF_REJECT, flags), rsp);

You can also see that the l2cap_pi()s have been removed but this was part of a different patch, irrelevant to this issue.

Written by xorl

July 10, 2011 at 16:05

Posted in bugs, linux

One Response

Subscribe to comments with RSS.

  1. awsome ;)

    proller

    July 13, 2011 at 20:19


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s