xorl %eax, %eax

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

with 2 comments

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 linux, vulnerabilities

2 Responses

Subscribe to comments with RSS.

  1. awsome ;)

    proller

    July 13, 2011 at 20:19

  2. Nice blog right here! Also your web site loads up fast! What
    web host are you the use of? Can I am getting your affiliate hyperlink for your host?

    I want my website loaded up as quickly as yours lol

    top laptops

    June 5, 2013 at 17:16


Leave a comment