syzbot - memory leak in gsm_activate_mux

2026. 4. 24. 03:03·Linux/start_contribute()

그나마 쉬운 버그를 찾아서 방황하던중 누군가 패치를 제출했지만, 승인이 되지 않은 memory leak 관련 버그를 찾았다. 도전할만 하다고 생각돼서 분석, 해결 시작.

Crash Report

[  165.195884][T11142] sysfs: cannot create duplicate filename '/devices/virtual/tty/gsmtty1'
[  165.196865][T11142] CPU: 1 PID: 11142 Comm: repro Tainted: G        W          6.7.0-rc8-00055-g5eff55d725a4 #14
[  165.198016][T11142] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[  165.199369][T11142] Call Trace:
[  165.199697][T11142]  <TASK>
[  165.199962][T11142]  dump_stack_lvl+0x72/0xa0
[  165.200387][T11142]  sysfs_warn_dup+0x64/0x70
[  165.200799][T11142]  sysfs_create_dir_ns+0x123/0x140
[  165.201274][T11142]  kobject_add_internal+0x104/0x340
[  165.201753][T11142]  kobject_add+0xd0/0x140
[  165.202149][T11142]  ? device_add+0x71a/0xc90
[  165.202618][T11142]  device_add+0x142/0xc90
[  165.203011][T11142]  tty_register_device_attr+0x14e/0x300
[  165.203520][T11142]  ? __kmalloc+0x4b/0x150
[  165.203931][T11142]  gsm_activate_mux+0xd7/0x1b0
[  165.204404][T11142]  gsmld_ioctl+0x1b8/0xa10
[  165.204890][T11142]  ? gsm_dlci_config+0x610/0x610
[  165.205443][T11142]  tty_ioctl+0x799/0xc60
[  165.205904][T11142]  ? do_vfs_ioctl+0x221/0xe50
[  165.206432][T11142]  ? __tty_hangup.part.0+0x450/0x450
[  165.207007][T11142]  __x64_sys_ioctl+0xf2/0x140
[  165.207590][T11142]  do_syscall_64+0x40/0x110
[  165.208038][T11142]  entry_SYSCALL_64_after_hwframe+0x63/0x6b
[  165.208723][T11142] RIP: 0033:0x42339d
[  165.209171][T11142] Code: b3 66 2e 0f 1f 84 00 00 00 00 00 66 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 b8 ff ff ff f7 d8 64 89 01 48
[  165.211270][T11142] RSP: 002b:00007f293d2801e8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[  165.212204][T11142] RAX: ffffffffffffffda RBX: 00007f293d280cdc RCX: 000000000042339d
[  165.213081][T11142] RDX: 0000000020000000 RSI: 0000000040204706 RDI: 0000000000000003
[  165.213944][T11142] RBP: 00007f293d280210 R08: 00007f293d2806c0 R09: 203a6362696c6720
[  165.214663][T11142] R10: 0000000000000000 R11: 0000000000000246 R12: 00007f293d2806c0
[  165.215381][T11142] R13: ffffffffffffffb8 R14: 000000000000006e R15: 00007ffcb726e820
[  165.216099][T11142]  </TASK>
[  165.254497][T11142] kobject: kobject_add_internal failed for gsmtty1 with -EEXIST, don't try to register things with the same name in the same directory.
[  170.847592][ T8183] kmemleak: 2 new suspected memory leaks (see /sys/kernel/debug/kmemleak)
BUG: memory leak
unreferenced object 0xffff88810ae44800 (size 1024):
  comm "repro", pid 11079, jiffies 4294953772 (age 11.680s)
  hex dump (first 32 bytes):
    00 74 e4 0a 81 88 ff ff 00 00 00 00 00 00 00 00  .t..............
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  backtrace:
    [<ffffffff8163532d>] __kmem_cache_alloc_node+0x2dd/0x3f0
    [<ffffffff815801e5>] kmalloc_trace+0x25/0x90
    [<ffffffff8280d577>] gsm_dlci_alloc+0x27/0x1f0
    [<ffffffff8280d75a>] gsm_activate_mux+0x1a/0x1b0
    [<ffffffff82813d88>] gsmld_ioctl+0x1b8/0xa10
    [<ffffffff827f8ec9>] tty_ioctl+0x799/0xc60
    [<ffffffff816c00b2>] __x64_sys_ioctl+0xf2/0x140
    [<ffffffff84b5d100>] do_syscall_64+0x40/0x110
    [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b

BUG: memory leak
unreferenced object 0xffff88800e0f0000 (size 4096):
  comm "repro", pid 11079, jiffies 4294953772 (age 11.680s)
  hex dump (first 32 bytes):
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  backtrace:
    [<ffffffff8163532d>] __kmem_cache_alloc_node+0x2dd/0x3f0
    [<ffffffff8158087b>] __kmalloc+0x4b/0x150
    [<ffffffff8251b739>] __kfifo_alloc+0x89/0xe0
    [<ffffffff8280d5c1>] gsm_dlci_alloc+0x71/0x1f0
    [<ffffffff8280d75a>] gsm_activate_mux+0x1a/0x1b0
    [<ffffffff82813d88>] gsmld_ioctl+0x1b8/0xa10
    [<ffffffff827f8ec9>] tty_ioctl+0x799/0xc60
    [<ffffffff816c00b2>] __x64_sys_ioctl+0xf2/0x140
    [<ffffffff84b5d100>] do_syscall_64+0x40/0x110
    [<ffffffff84c0008b>] entry_SYSCALL_64_after_hwframe+0x63/0x6b

크래시 리포트에서 볼 수 있듯이, 메모리 릭이 2군데에서 발생한다.

  • 0xffff88810ae44800
  • 0xffff88800e0f0000

gsm_dlci_alloc()함수에서 발생을 햇을것이라 추측하고 이 함수 내부에서 일단 메모리를 어디서 할당하는지 알아보았다.

 

static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
{
	struct gsm_dlci *dlci = kzalloc(sizeof(struct gsm_dlci), GFP_ATOMIC);
	if (dlci == NULL)
		return NULL;
	spin_lock_init(&dlci->lock);
	mutex_init(&dlci->mutex);
	if (kfifo_alloc(&dlci->fifo, TX_SIZE, GFP_KERNEL) < 0) {
		kfree(dlci);
		return NULL;
	}

2개의 할당이 이뤄진다.

  • kzalloc()에 의한 할당
  • kfifo_alloc()에 의한 할당

이 2개의 할당에서 유발된 메모리 릭인지 확인하기 위해서, printk()를 심어 메모리 주소를 찍어보니, 메모리 릭이 발생한 주소와 동일했다. 따라서, 범인은 kzalloc()과 kfifo_alloc()에서 할당한 메모리가 어딘가에서 제대로 kfree()되지 않거나, 주소를 상실했을거라 생각한다.

 

해결 방법

첫번째로, gsm_dlci_alloc()함수의 모든 호출지에 printk()를 넣어서, repro를 돌렸을 때, 어떤 호출지에서 크래시가 발생하는지 찾아보니, repro에서는 gsm_activate_mux()에서만 gsm_dlci_alloc()을 호출하는 것을 알 수 있었다. 그리고 이 과정에서 크래시가 발생...

 

그래서 gsm_active_mux() 함수의 코드를 살펴보았다.

static int gsm_activate_mux(struct gsm_mux *gsm)
{
	struct gsm_dlci *dlci;
	int ret;

	dlci = gsm_dlci_alloc(gsm, 0);
	if (dlci == NULL)
		return -ENOMEM;

	if (gsm->encoding == GSM_BASIC_OPT)
		gsm->receive = gsm0_receive;
	else
		gsm->receive = gsm1_receive;

	ret = gsm_register_devices(gsm_tty_driver, gsm->num);
	if (ret)
		return ret;

	gsm->has_devices = true;
	gsm->dead = false;		/* Tty opens are now permissible */
	return 0;
}

dlci = gsm_dlci_alloc(gsm, 0)으로 할당을 받고, gsm_register_devices()가 실패하면 할당받았던 dlci를 해제하는 부분이 없다. 그래서 처음에는 이 부분이 원인이라고 특정하고 실패시 해제하도록 코드를 바꿔주었다.

 

ret = gsm_register_devices(gsm_tty_driver, gsm->num);
if (ret) {
	gsm_dlci_free(&dlci->port);
	return ret;
}

이렇게 해제 로직을 추가해주었다. 다시 repro를 돌리고 에러가 사라졌을거라고 생각했지만...
그대로였다.

 

그래서 다시 gsm_dlci_alloc()함수를 살펴보았다.

static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
{
	struct gsm_dlci *dlci = kzalloc(sizeof(struct gsm_dlci), GFP_ATOMIC);
	if (dlci == NULL)
		return NULL;
	spin_lock_init(&dlci->lock);
	mutex_init(&dlci->mutex);
	if (kfifo_alloc(&dlci->fifo, TX_SIZE, GFP_KERNEL) < 0) {
		kfree(dlci);
		return NULL;
	}

	skb_queue_head_init(&dlci->skb_list);
	timer_setup(&dlci->t1, gsm_dlci_t1, 0);
	tty_port_init(&dlci->port);
	dlci->port.ops = &gsm_port_ops;
	dlci->gsm = gsm;
	dlci->addr = addr;
	dlci->adaption = gsm->adaption;
	dlci->mtu = gsm->mtu;
	if (addr == 0)
		dlci->prio = 0;
	else
		dlci->prio = roundup(addr + 1, 8) - 1;
	dlci->ftype = gsm->ftype;
	dlci->k = gsm->k;
	dlci->state = DLCI_CLOSED;
	if (addr) {
		dlci->data = gsm_dlci_data;
		/* Prevent us from sending data before the link is up */
		dlci->constipated = true;
	} else {
		dlci->data = gsm_dlci_command;
	}
	gsm->dlci[addr] = dlci;
	return dlci;
}

함수의 가장 하단을 살펴보면, gsm->dlci[addr] = dlci 부분이 보인다. gsm_activate_mux()에서는 gsm_dlci_alloc()을 어떻게 호출하냐면, dlci = gsm_dlci_alloc(gsm, 0) 이렇게 호출한다. 인자로 0을 고정으로 넣는다.

 

그러면, gsm_dlci_alloc()에서는 하단 코드가 gsm->dlci[0] = dlci 이렇게 되는데, 이미 이전에 gsm->dlci[0]에 메모리 주소가 적혀있는데 이걸 덮어씌운다. 따라서, 기존에 gsm->dlci[0]에 있던 메모리 주소가 영영 접근할 수 없는 형태가 되버린다. 그래서 메모리 릭이 발생하는 것으로 추정된다.(가설)

 

static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
{
	struct gsm_dlci *dlci;
    
 	if (gsm->dlci[addr])
		return gsm->dlci[addr];
        
	dlci = kzalloc(sizeof(struct gsm_dlci), GFP_ATOMIC);

위와 같이, gsm->dlci[addr]에 이미 메모리 주소가 있는지 확인하고, 있다면 그 주소를 반환하는 코드로 바꿧다.

 

이렇게 2가지의 수정을 거친 후,

다시 repro를 돌리니 크래시가 발생하지 않는다..!


수정한 패치를 syzbot에게 테스트 요청을 보냈고,

https://lore.kernel.org/all/69e90d92.a00a0220.9259.0020.GAE@google.com/

문제가 없다는 답장을 받았다.

'Linux > start_contribute()' 카테고리의 다른 글

syzbot 버그픽스 기여 방법  (0) 2026.04.22
커널 기여: race condition 가능성 해결  (0) 2026.02.01
커널 기여 근황  (0) 2026.01.27
리눅스 커널 2번째 기여: 수동 메모리 정렬 연산 PTR_ALIGN으로 최적화  (2) 2026.01.12
첫 리눅스 커널 기여  (4) 2025.12.22
'Linux/start_contribute()' 카테고리의 다른 글
  • syzbot 버그픽스 기여 방법
  • 커널 기여: race condition 가능성 해결
  • 커널 기여 근황
  • 리눅스 커널 2번째 기여: 수동 메모리 정렬 연산 PTR_ALIGN으로 최적화
Minu Jin
Minu Jin
정보의 바다
  • Minu Jin
    뇌 구조가 바이너리
    Minu Jin
  • 전체
    오늘
    어제
    • 분류 전체보기
      • C프로그래밍
        • 오류해결
        • 개인 공부
        • Programming Lab(학교수업)
        • MemoryTracker
      • C++
        • 개인 공부
      • 자료구조(Data Structure)
      • ARM arch
        • Cortex-M
        • FreeRTOS
      • 컴퓨터 공학(Computer Science)
        • OS
        • 컴퓨터 구조
      • Qualcomm 기업과제
      • Linux
        • start_contribute()
        • start_analyse()
      • Web
      • 똥글
      • 백준
      • Git 학습
        • 오류해결
        • 학습중
      • Python
        • 오류해결
        • 개인 공부
  • 블로그 메뉴

    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    시스템콜
    포인터
    C++
    동적메모리
    자료구조
    드라이버 분석
    arm
    리눅스
    rubikpi3
    yolo
    소수
    파이썬
    commit
    커널
    순환
    커널 기여
    스택
    Qualcomm
    이진 트리
    Git
    rubik pi
    토발즈
    Branch
    버퍼
    파일 입출력
    c언어
    피보나치
    앤드류모튼
    INIT
    백준
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Minu Jin
syzbot - memory leak in gsm_activate_mux
상단으로

티스토리툴바