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
        • 오류해결
        • 개인 공부
  • 블로그 메뉴

    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

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

  • 최근 글

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

티스토리툴바