cover

水一篇蓝牙CVE的分析文章,站在巨人的肩膀上。

漏洞分析

Bleedingtooth

2020年谷歌安全研究人员在Linux kernel中发现了多个蓝牙的安全漏洞,这些漏洞被称之为BleedingTooth。攻击者利用BleedingTooth 漏洞可以实现无用户交互的零点击攻击(zero-click attack)。包括CVE-2020-12351、CVE-2020-12352、CVE-2020-24490。

CVE-2020-12351位于net/bluetooth/l2cap_core.c,基于堆的类型混淆漏洞。在 l2cap_data_channel函数中,当使用的 CID 是 L2CAP_CID_A2MP 并且还没建立一个channel时 , a2mp_channel_create()会被调用用于建立channel, 设定的chan->data 的类型是struct amp_mgr* 。如果 channel 的 mode 是 L2CAP_MODE_ERTM 或 L2CAP_MODE_STREAMING, 就会调用 l2cap_data_rcv(),在l2cap_data_rcv()调用了sk_filter(chan->data, skb),此时chan->data被转换成了struct sock*类型。

CVE-2020-12352位于/net/bluetooth/a2mp.c, 基于栈的信息泄漏漏洞。在a2mp_getinfo_req函数中,如果指定了一个无效的hci device id或者不是 HCI_AMP 类型的 hci device ,错误响应函数a2mp_send会回送一个没完全初始化的结构体a2mp_info_rsp rsp,这时 a2mp_info_rsp 被分配在栈上并且只有前2个字节被初始化了,这意味着可以泄漏前一个栈帧中的16个字节。

CVE-2020-24490 位于net/bluetooth/hci_event.c ,基于堆的缓冲区溢出漏洞。处理扩展广播报告事件的hci_le_ext_adv_report_evt()使用store_pending_adv_report()拷贝数据时,会将最多255个字节的扩展广告数据拷贝到discovery_state->last_adv_addr,但是后者的大小是HCI_MAX_AD_LENGTH=31 bytes,不足以容纳,导致堆溢出。

CVE-2020-12351

CVE-2020-12351,该漏洞CVSS评分为8.3分,是一个基于堆的类型混淆(type confusion) 漏洞。在受害者蓝牙范围内的远程攻击者在指导目标设备的bd地址的情况下就可以利用该漏洞。攻击者可以通过发送恶意l2cap包的方式来触发该漏洞,引发DoS或kernel权限的任意代码执行。谷歌安全研究人员称该漏洞是一个零点击漏洞,也就是说利用的过程中无需任何的用户交互。

A heap-based 类型混淆 affecting Linux kernel 4.8 and higher was discovered in net/bluetooth/l2cap_core.c.

当 CID 不是 L2CAP_CID_SIGNALING, L2CAP_CID_CONN_LESS 或 L2CAP_CID_LE_SIGNALING时, l2cap_recv_frame 会调用 l2cap_data_channel() 。在l2cap_data_channel()中需要关注的是第8行的第27行的这两个分支。

///net/bluetooth/l2cap_core.c
static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
{
    struct l2cap_chan *chan;
    chan = l2cap_get_chan_by_scid(conn, cid);
    if (!chan) {
        if (cid == L2CAP_CID_A2MP) {
            chan = a2mp_channel_create(conn, skb);  //here
            if (!chan) {
                kfree_skb(skb);
                return;
            }

            l2cap_chan_lock(chan);
        } else {
            BT_DBG("unknown cid 0x%4.4x", cid);
            /* Drop packet and return */
            kfree_skb(skb);
            return;
        }
    }
    ...
    switch (chan->mode) {
    ...
    case L2CAP_MODE_ERTM:
    case L2CAP_MODE_STREAMING:
        l2cap_data_rcv(chan, skb);    //here
        goto done;
    ...
    }

drop:
    kfree_skb(skb);

done:
    l2cap_chan_unlock(chan);
}

第27行:在 l2cap_data_channel 函数里如果 channel 的 mode 是 L2CAP_MODE_ERTM 或 L2CAP_MODE_STREAMING, 就会调用 l2cap_data_rcv()。

///net/bluetooth/l2cap_core.c
static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
{
    struct l2cap_ctrl *control = &bt_cb(skb)->l2cap;
    u16 len;
    u8 event;

    __unpack_control(chan, skb);

    len = skb->len;

    /*
     * We can just drop the corrupted I-frame here.
     * Receiver will miss it and start proper recovery
     * procedures and ask for retransmission.
     */
    if (l2cap_check_fcs(chan, skb))  
        goto drop;

    if (!control->sframe && control->sar == L2CAP_SAR_START)
        len -= L2CAP_SDULEN_SIZE;

    if (chan->fcs == L2CAP_FCS_CRC16)
        len -= L2CAP_FCS_SIZE;

    if (len > chan->mps) {
        l2cap_send_disconn_req(chan, ECONNRESET);
        goto drop;
    }

    if ((chan->mode == L2CAP_MODE_ERTM ||
         chan->mode == L2CAP_MODE_STREAMING) && sk_filter(chan->data, skb)) //here
        goto drop;
    ...
}

当packet的 checksum 被验证通过 , 继续调用 sk_filter()//sk_filter是对sk_filter_trim_cap的简单封装。

第8行: l2cap_data_channel 函数里 当使用的 CID 是 L2CAP_CID_A2MP 并且还没建立一个channel时 , a2mp_channel_create() 将被调用。

///net/bluetooth/a2mp.c
static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn, bool locked)
{
    struct amp_mgr *mgr;
    struct l2cap_chan *chan;

    mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
    if (!mgr)
        return NULL;

    BT_DBG("conn %p mgr %p", conn, mgr);

    mgr->l2cap_conn = conn;

    chan = a2mp_chan_open(conn, locked);  //here
    if (!chan) {
        kfree(mgr);
        return NULL;
    }

    mgr->a2mp_chan = chan;
    chan->data = mgr;
    ...
    return mgr;
}

a2mp_chan_open 创建了一个 channel 并且把 mode 初试化为 L2CAP_MODE_ERTM

static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)
{
    struct l2cap_chan *chan;
    int err;

    chan = l2cap_chan_create();
    if (!chan)
        return NULL;

    BT_DBG("chan %p", chan);

    chan->chan_type = L2CAP_CHAN_FIXED;
    chan->scid = L2CAP_CID_A2MP;
    chan->dcid = L2CAP_CID_A2MP;
    ...
    chan->mode = L2CAP_MODE_ERTM;
    ...
    return chan;
}

!!!问题在这里:

amp_mgr_create()里 chan->data 的类型是struct amp_mgr*

static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn, bool locked)
{
    struct amp_mgr *mgr;
     ...
     chan->data = mgr;
    ...
 }

在l2cap_data_rcv()调用了sk_filter(chan->data, skb),定义是这样的 sk_filter(struct sock *sk, struct sk_buff skb); chan->data被转换成了struct sock\类型,类型混淆在此产生。

 static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
{
    ...
    if ((chan->mode == L2CAP_MODE_ERTM ||
         chan->mode == L2CAP_MODE_STREAMING) && sk_filter(chan->data, skb))
        goto drop;
    ...     
}

int sk_filter(struct sock *sk, struct sk_buff *skb);
{}

POC

https://github.com/google/security-research/security/advisories/GHSA-h637-c88j-47wq

mode:a2mp_chan_open 创建 channel的时候已把 mode 初试化为 L2CAP_MODE_ERTM。

cid:不应是 L2CAP_CID_SIGNALING, L2CAP_CID_CONN_LESS 或 L2CAP_CID_LE_SIGNALING,这里选择L2CAP_CID_A2MP。

#define L2CAP_CID_SIGNALING    0x0001
#define L2CAP_CID_CONN_LESS    0x0002
#define L2CAP_CID_A2MP        0x0003
#define L2CAP_CID_ATT        0x0004
#define L2CAP_CID_LE_SIGNALING    0x0005
#define L2CAP_CID_SMP        0x0006
#define L2CAP_CID_SMP_BREDR    0x0007
#define L2CAP_CID_DYN_START    0x0040
#define L2CAP_CID_DYN_END    0xffff
#define L2CAP_CID_LE_DYN_END    0x007f

crash了

CVE-2020-12352

CVE-2020-12352 是基于栈的信息泄露漏洞,漏洞影响Linux kernel 3.6 及更高版本,CVSS 评分为5.3,被评为中危。在蓝牙距离范围内的知道受害者 bd 地址的远程攻击者可以提取含有不同指针的 kernel 栈信息,这些信息可以用来预测内存的布局以及攻击 KASL(内核地址空间布局随机化)。同时泄露的信息还包括加密密钥等重要信息。

when specifying an invalid hci device id or one that is not of type HCI_AMP in the A2MP_GETINFO_REQ request, an error response is sent back with not fully initialized struct members.

//net/bluetooth/a2mp.c.
//在一个A2MP_GETINFO_REQ request中,如果指定了一个无效的hci device id或者不是 HCI_AMP 类型的 hci device 
//错误响应会回送一个没完全初始化结构成员。
static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
                struct a2mp_cmd *hdr)
{
    struct a2mp_info_req *req  = (void *) skb->data; 
    struct hci_dev *hdev;
    struct hci_request hreq;
    int err = 0;

    if (le16_to_cpu(hdr->len) < sizeof(*req))
        return -EINVAL;

    BT_DBG("id %d", req->id);

    hdev = hci_dev_get(req->id);
    if (!hdev || hdev->dev_type != HCI_AMP) {
        struct a2mp_info_rsp rsp;  //this

        rsp.id = req->id;
        rsp.status = A2MP_STATUS_INVALID_CTRL_ID;

        a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp),
              &rsp);//

        goto done;
    }
    ...
}
//a2mp_info_rsp包含以下成员
struct a2mp_info_rsp {
    __u8    id;
    __u8    status;
    __le32    total_bw;
    __le32    max_bw;
    __le32    min_latency;
    __le16    pal_cap;
    __le16    assoc_size;
} __packed;

这时 a2mp_info_rsp 被分配在栈上并且只有前2个字节被初始化了,这意味着可以泄漏前一个栈帧中的16个字节。

a2mp_send_getinfo_rsp()也存在相同的漏洞

CVE-2020-24490

CVE-2020-24490 是位于 net/bluetooth/hci_event.c 中的一个基于堆的缓冲区溢出漏洞。漏洞影响Linux kernel 4.19 及更高版本。该漏洞CVSS 评分为5.3 分,为中危漏洞。远程攻击者可以广播扩展的广告数据,引发配备了蓝牙5芯片以及处于扫描模式的受害者机 DoS 或以 kernel 权限执行任意代码。恶意或有漏洞的蓝牙芯片也可以触发该漏洞。

蓝牙5标准于2016年发布,提供了八倍的广播消息传递能力以及更多功能。 在蓝牙4.0中,广告的有效载荷最大为31个八位位组。在蓝牙5中,我们通过添加其他广告渠道和新的广告PDU将有效负载增加到255个八位位组。

引入了hci_le_ext_adv_report_evt()来处理扩展的advertising报告事件,它基于处理旧的 advertisements的 hci_le_adv_report_evt()。

//在hci_le_adv_report_evt()中,会检查ev->length小于HCI_MAX_AD_LENGTH与否
//但在hci_le_ext_adv_report_evt()中却没有这个检查,但这可能是故意的,因为ev->length是一个 8bit的字段而扩展advertising数据最大为255 bytes
static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
    u8 num_reports = skb->data[0];
    void *ptr = &skb->data[1];

    hci_dev_lock(hdev);

    while (num_reports--) {
        struct hci_ev_le_advertising_info *ev = ptr;
        s8 rssi;

        if (ev->length <= HCI_MAX_AD_LENGTH) {
            rssi = ev->data[ev->length];
            process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
                       ev->bdaddr_type, NULL, 0, rssi,
                       ev->data, ev->length);
        } else {
            bt_dev_err(hdev, "Dropping invalid advertising data");
        }

        ptr += sizeof(*ev) + ev->length + 1;
    }

    hci_dev_unlock(hdev);
}

...

static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
    u8 num_reports = skb->data[0];
    void *ptr = &skb->data[1];

    hci_dev_lock(hdev);

    while (num_reports--) {
        struct hci_ev_le_ext_adv_report *ev = ptr;
        u8 legacy_evt_type;
        u16 evt_type;

        evt_type = __le16_to_cpu(ev->evt_type);
        legacy_evt_type = ext_evt_type_to_legacy(hdev, evt_type);
        if (legacy_evt_type != LE_ADV_INVALID) {
            process_adv_report(hdev, legacy_evt_type, &ev->bdaddr,
                       ev->bdaddr_type, NULL, 0, ev->rssi,
                       ev->data, ev->length);
        }

        ptr += sizeof(*ev) + ev->length;
    }

    hci_dev_unlock(hdev);
}

At some point in process_adv_report(), the data is stored using store_pending_adv_report() if the advertiser is doing indirect advertisement and the recipient is doing active scanning.

static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr,
                   u8 bdaddr_type, bdaddr_t *direct_addr,
                   u8 direct_addr_type, s8 rssi, u8 *data, u8 len)
{
    struct discovery_state *d = &hdev->discovery;
    struct smp_irk *irk;
    struct hci_conn *conn;
    bool match;
    u32 flags;
    u8 *ptr, real_len;

    ...

    /* Passive scanning shouldn't trigger any device found events,
     * except for devices marked as CONN_REPORT for which we do send
     * device found events.
     */
    if (hdev->le_scan_type == LE_SCAN_PASSIVE) {
        ...
        return;
    }

    ...

    /* If there's nothing pending either store the data from this
     * event or send an immediate device found event if the data
     * should not be stored for later.
     */
    if (!has_pending_adv_report(hdev)) {
        /* If the report will trigger a SCAN_REQ store it for
         * later merging.
         */
        if (type == LE_ADV_IND || type == LE_ADV_SCAN_IND) {
            store_pending_adv_report(hdev, bdaddr, bdaddr_type,
                         rssi, flags, data, len);
            return;
        }

        mgmt_device_found(hdev, bdaddr, LE_LINK, bdaddr_type, NULL,
                  rssi, flags, data, len, NULL, 0);
        return;
    }

    ...
}

store_pending_adv_report() 将data拷贝到 d->last_adv_data.

static void store_pending_adv_report(struct hci_dev *hdev, bdaddr_t *bdaddr,
                     u8 bdaddr_type, s8 rssi, u32 flags,
                     u8 *data, u8 len)
{
    struct discovery_state *d = &hdev->discovery;

    bacpy(&d->last_adv_addr, bdaddr);
    d->last_adv_addr_type = bdaddr_type;
    d->last_adv_rssi = rssi;
    d->last_adv_flags = flags;
    memcpy(d->last_adv_data, data, len);
    d->last_adv_data_len = len;
}

但discovery_state->last_adv_addr的大小HCI_MAX_AD_LENGTH=31 bytes不足以容纳最多255个字节的扩展广告数据。因此将导致后续hci_dev的缓冲区溢出。

struct hci_dev {
    ...
    struct discovery_state {
        ...
        u8            last_adv_data[HCI_MAX_AD_LENGTH];
        u8            last_adv_data_len;
        bool            report_invalid_rssi;
        bool            result_filtering;
        bool            limited;
        s8            rssi;
        u16            uuid_count;
        u8            (*uuids)[16];
        unsigned long        scan_start;
        unsigned long        scan_duration;
    } discovery;

    // BEGIN
    // The following fields are available since Linux kernel 5.7.
    int            discovery_old_state;
    bool            discovery_paused;
    int            advertising_old_state;
    bool            advertising_paused;

    struct notifier_block    suspend_notifier;
    struct work_struct    suspend_prepare;
    enum suspended_state    suspend_state_next;
    enum suspended_state    suspend_state;
    bool            scanning_paused;
    bool            suspended;

    wait_queue_head_t    suspend_wait_q;
    DECLARE_BITMAP(suspend_tasks, __SUSPEND_NUM_TASKS);
    // END

    struct hci_conn_hash    conn_hash;

    struct list_head    mgmt_pending;
    ...
};

BlueBorne

包括 CVE-2017-1000250 Linux bluetoothd进程信息泄露 、CVE-2017-1000251 Linux 内核栈溢出 、CVE-2017-0785 Android com.android.bluetooth进程信息泄露 、CVE-2017-0781 Android com.android.bluetooth进程堆溢出、 CVE-2017-0782 Android com.android.bluetooth进程堆溢出、CVE-2017-0783 Android 中间人攻击。

CVE-2017-1000251位于Linux L2CAP层,l2cap_bredr_sig_cmd处理L2CAP的cmd数据时,当cmd->code是L2CAP_CONF_RSP时,会调用l2cap_config_rsp,然后在满足result == L2CAP_CONF_PENDING,且自身的连接状态conf_state == CONF_LOC_CONF_PEND的时候,会走到 l2cap_parse_conf_rsp函数里。l2cap_parse_conf_rsp函数的功能就是根据传进来的包,来构造将要发出去的包,传进来的包的内容都是任意确定的(包括参数len ,参数rsp->data),但是要发出去的包却暂存在长度为64字节的栈空间buf中,那么当len很大时,就会一直往出口buf里写数据,比如有64个L2CAP_CONF_MTU类型的opt,那么就会往buf里写上64*(L2CAP_CONF_OPT_SIZE + 2)个字节,那么显然这里就发生了溢出。由于buf是栈上定义的数据结构,那么这里就是一个栈溢出。

static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
                void *data, u16 *result)
{
    struct l2cap_conf_req *req = data;
    void *ptr = req->data;
    int type, olen;
    unsigned long val;

    while (len >= L2CAP_CONF_OPT_SIZE) { //len没有被检查,由接收到的包内容控制
        len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);

        switch (type) {
        case L2CAP_CONF_MTU:
            if (val < L2CAP_DEFAULT_MIN_MTU) {
                *result = L2CAP_CONF_UNACCEPT;
                chan->imtu = L2CAP_DEFAULT_MIN_MTU;
            } else
                chan->imtu = val;
            l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
            break;
        case ...

        }
    }
}

static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
{
    struct l2cap_conf_opt *opt = *ptr;
    opt->type = type;
    opt->len  = len;

    switch (len) {
    case 1:
        *((u8 *) opt->val)  = val;
        break;

    case 2:
        put_unaligned_le16(val, opt->val);
        break;

    case 4:
        put_unaligned_le32(val, opt->val);
        break;

    default:
        memcpy(opt->val, (void *) val, len);
        break;
    }

    *ptr += L2CAP_CONF_OPT_SIZE + len;
}

BlueFrag

参考 https://paper.seebug.org/1121/#_3

CVE-2020-0022,又称BlueFrag,可影响Android蓝牙子系统。该漏洞是一个远程代码执行漏洞,出现在Bluedroid蓝牙协议栈的HCI层,当无线模块处于活动状态时,攻击者可以利用蓝牙守护程序提升权限进而在设备上执行代码。该漏洞影响Android Oreo(8.0和8.1)、Pie(9),但无法在Android 10上进行利用,仅能触发DoS攻击。

CVE-2020-0022漏洞位于HCI层,代码位于hci/src/packet_fragmenter.cc中的reassemble_and_dispatch()函数中。

reassemble_and_dispatch()函数用于数据包分片的重组,对于过长的ACL数据包进行包重组时,主要是根据ACL包中的PB Flag标志位进行重组,如果当前是起始部分并且是不完整的,则生成一个部分包(partial_packet)放到map里,等下次收到它的后续部分进行拼装,拼装完毕后就分发出去。拼装过程中长度计算有误,导致

第一个参数为partial_packet->data + partial_packet->offset,目的地址是正确的,第二个参数为packet->data + packet->offset,源地址也是正确的,第三个参数是要拷贝的长度len为packet->len - packet->offset,这个值是有问题的,分两种情况。第一种情况是projected_offset小于partial_packet->len,packet->len - packet->offset为L2CAP数据包片段总长度,并且是个正数。第二种是行211的情况,packet->len已经被修正过,不需要再一次packet->len - packet->offset的操作,如果partial_packet剩余空间长度小于4字节,那packet->len - packet->offset 是小于零的,是一个负数。由于memcpy()函数第三个参数类型是一个无符号整型类型,因此整数溢出导致堆溢出。

真机调试环境搭建

Debugger配置

1、下载符号文件和内核源码文件

为了更好地调试内核,gdb需要Debuggee的内核符号文件和源代码文件来实现源码级别的调试。之前发现了一个launchpad.net(https://launchpad.net/ubuntu/+source/linux/5.4.0-42.46)的站点,该站点提供了当前发行版Linux系统的内核符号文件和源码文件供开发者下载。

找到Debuggee的ubuntu版本、 找带dbgsym、unsigned的、系统架构amd64

2、安装符号文件

下载得到linux-image-unsigned-5.4.0-42-generic-dbgsym_5.4.0-42.46_amd64.ddeb文件,在Debugger中执行“dpkg -i”命令安装符号文件。 vmlinux-5.4.0-42-generic是Linux内核公共部分的可执行文件的符号版本

file /usr/lib/debug/boot/vmlinux-5.11.0-38-generic
/usr/lib/debug/boot/vmlinux-5.11.0-38-generic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=3943780ac8a93e50813a3906c205bba1515216d3, with debug_info, not stripped
file /usr/lib/debug/lib/modules/5.11.0-38-generic/kernel/drivers/net/ethernet/realtek/r8169.ko
/usr/lib/debug/lib/modules/5.11.0-38-generic/kernel/drivers/net/ethernet/realtek/r8169.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=ffa1e397cf00e133476ed9d9bcf168dac70a70c7, with debug_info, not stripped

Debugee配置

1、开启kgdb

双机调试需要Debuggee开启Kgdb功能,当前Ubuntu发行版内核已经默认开启了 Kgdb支持,通过命令“cat /boot/config-$(uname -r)| grep -i GDB”查看可知当前内核支持Kgdb以及串口调试。

q1iq@q1iq:~$ cat /boot/config-$(uname -r)| grep -i GDB
CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y
CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y
CONFIG_SERIAL_KGDB_NMI=y
CONFIG_GDB_SCRIPTS=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_KGDB=y
CONFIG_KGDB_HONOUR_BLOCKLIST=y
CONFIG_KGDB_SERIAL_CONSOLE=y
# CONFIG_KGDB_TESTS is not set
CONFIG_KGDB_LOW_LEVEL_TRAP=y
CONFIG_KGDB_KDB=y

如果内核不支持Kgdb,则可以通过下载、编译、安装对应版本的内核源码来打开Kgdb。以Linux5.4.0内核为例,需要设置的编译选项有:

CONFIG_KGDB=y  //开启kgdb服务 
CONFIG_KGDB_SERIAL_CONSOLE=y  //kgdb默认连接到主板串口
CONFIG_DEBUG_INFO=y  //内核中加入调试符号

2、配置grub文件

内核开启Kgdb功能后需要手动配置grub启动文件才能在开机的时候进入Kgdb调试选项,因为默认情况下Kgdb是不工作的,需要向内核传递相关启动参数才能启用。编辑/etc/grub.d/40_custom文件,添加如下menuentry。

kgdboc(串口调试)应加的选项

kgdbwait kgdboc=ttyS0,115200 nokaslr
kgdbwait:进入该启动选项后等待远程主机连接Kgdb
kgdboc:“kgdb over console”的缩写,表示远程主机通过串口连接到Kgdb
ttyS0:在本地默认串口监听连接事件,通常这也是主板上唯一的串口
115200:本地串口的波特率 nokaslr:关闭内核地址随机化。kaslr选项会干扰内核的调试因此要关闭
除了串口还可以使用以太网连接Kgdb,除了传递启动参数还可以在运行时通过sysfs文件系统开启Kgdb 更多详细的Kgdb操作请参考“linux5.4/Documentation/dev-tools/kgdb.rst”。Linux的documentation是一个非常有用的东⻄

kgbboe(网络调试)应该加这些选项(https://mirrors.edge.kernel.org/pub/linux/kernel/people/jwessel/kgdb/ch03s04.html)

kgdbwait kgdbcon kgdboe=@192.168.43.82/,@192.168.43.206/ nokaslr
kgdboe=[src-port]@<src-ip>/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]

src-port默认6443
tgt-port默认6442

系统运行时修改kgdboe
echo "@/,@10.0.2.2/" > /sys/module/kgdboe/paramters/kgdboe

编辑完成后在控制台执行“sudo update-grub”命令更新启动项,重启Debuggee,可以在grub页面看到多出了“Ubuntu,KGDB with nokaslr”选项,这个选项是可以自己写的。

参考

https://mp.weixin.qq.com/s/sl9-2GZaJfqGwoHAHG8onQ

https://www.freebuf.com/vuls/271834.html

CVE-2020-12351 https://github.com/google/security-research/security/advisories/GHSA-h637-c88j-47wq

CVE-2020-12352 https://github.com/google/security-research/security/advisories/GHSA-7mh3-gq28-gfrq

CVE-2020-24490 https://github.com/google/security-research/security/advisories/GHSA-ccx2-w2r4-x649