mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* Re: divide error in mb_update_avg_fragment_size
@ 2023-12-08 14:12 xingwei lee
  2023-12-09 10:05 ` Baokun Li
  0 siblings, 1 reply; 3+ messages in thread
From: xingwei lee @ 2023-12-08 14:12 UTC (permalink / raw)
  To: harperchen1110
  Cc: adilger.kernel, linux-ext4, linux-kernel, syzkaller-bugs,
	syzkaller, tytso

Hello I saw you can't reproduce this bug and I reproduce it with
repro.c and repro.txt
I test the repro.c in the lastest HEAD: 5e3f5b81de80c98338bcb47c233aebefee5a4801
kernel config: https://syzkaller.appspot.com/text?tag=KernelConfig&x=6ae1a4ee971a7305
and the bug also existed.

=* repro.c =*
// autogenerated by syzkaller (https://github.com/google/syzkaller)

#define _GNU_SOURCE

#include <dirent.h>
#include <endian.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

static unsigned long long procid;

static void sleep_ms(uint64_t ms) { usleep(ms * 1000); }

static uint64_t current_time_ms(void) {
  struct timespec ts;
  if (clock_gettime(CLOCK_MONOTONIC, &ts)) exit(1);
  return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
}

static bool write_file(const char* file, const char* what, ...) {
  char buf[1024];
  va_list args;
  va_start(args, what);
  vsnprintf(buf, sizeof(buf), what, args);
  va_end(args);
  buf[sizeof(buf) - 1] = 0;
  int len = strlen(buf);
  int fd = open(file, O_WRONLY | O_CLOEXEC);
  if (fd == -1) return false;
  if (write(fd, buf, len) != len) {
    int err = errno;
    close(fd);
    errno = err;
    return false;
  }
  close(fd);
  return true;
}

static void kill_and_wait(int pid, int* status) {
  kill(-pid, SIGKILL);
  kill(pid, SIGKILL);
  for (int i = 0; i < 100; i++) {
    if (waitpid(-1, status, WNOHANG | __WALL) == pid) return;
    usleep(1000);
  }
  DIR* dir = opendir("/sys/fs/fuse/connections");
  if (dir) {
    for (;;) {
      struct dirent* ent = readdir(dir);
      if (!ent) break;
      if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
        continue;
      char abort[300];
      snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
               ent->d_name);
      int fd = open(abort, O_WRONLY);
      if (fd == -1) {
        continue;
      }
      if (write(fd, abort, 1) < 0) {
      }
      close(fd);
    }
    closedir(dir);
  } else {
  }
  while (waitpid(-1, status, __WALL) != pid) {
  }
}

static void setup_test() {
  prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
  setpgrp();
  write_file("/proc/self/oom_score_adj", "1000");
}

static void execute_one(void);

#define WAIT_FLAGS __WALL

static void loop(void) {
  int iter = 0;
  for (;; iter++) {
    int pid = fork();
    if (pid < 0) exit(1);
    if (pid == 0) {
      setup_test();
      execute_one();
      exit(0);
    }
    int status = 0;
    uint64_t start = current_time_ms();
    for (;;) {
      if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid) break;
      sleep_ms(1);
      if (current_time_ms() - start < 5000) continue;
      kill_and_wait(pid, &status);
      break;
    }
  }
}

uint64_t r[5] = {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff,
                 0xffffffffffffffff, 0xffffffffffffffff};

void execute_one(void) {
  intptr_t res = 0;
  memcpy((void*)0x20000280, "cgroup.controllers\000", 19);
  res = syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x20000280ul,
                /*flags=*/0x275aul, /*mode=*/0ul);
  if (res != -1) r[0] = res;
  memcpy((void*)0x20000180, "cgroup.controllers\000", 19);
  res = syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x20000180ul,
                /*flags=*/0x275aul, /*mode=*/0ul);
  if (res != -1) r[1] = res;
  res = syscall(__NR_dup3, /*oldfd=*/r[1], /*newfd=*/r[0], /*flags=*/0ul);
  if (res != -1) r[2] = res;
  *(uint32_t*)0x20000140 = 0x20;
  *(uint32_t*)0x20000144 = 0x8c8c;
  *(uint32_t*)0x20000148 = 0;
  *(uint32_t*)0x2000014c = 0;
  *(uint32_t*)0x20000150 = 0;
  memset((void*)0x20000154, 0, 8);
  syscall(__NR_ioctl, /*fd=*/r[0], /*cmd=*/0x401c5820, /*arg=*/0x20000140ul);
  sprintf((char*)0x20000040, "0x%016llx", (long long)0);
  syscall(__NR_write, /*fd=*/r[0], /*buf=*/0x20000040ul, /*len=*/0xfea0ul);
  memcpy((void*)0x200001c0, "cpuset.effective_cpus\000", 22);
  res = syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x200001c0ul,
                /*flags=*/0x275aul, /*mode=*/0ul);
  if (res != -1) r[3] = res;
  sprintf((char*)0x20000380, "0x%016llx", (long long)0);
  syscall(__NR_write, /*fd=*/r[3], /*buf=*/0x20000380ul, /*len=*/0x101bful);
  syscall(__NR_ioctl, /*fd=*/r[3], /*cmd=*/0x660c, 0);
  *(uint32_t*)0x200000c0 = 0;
  *(uint32_t*)0x200000c4 = r[3];
  *(uint64_t*)0x200000c8 = 7;
  *(uint64_t*)0x200000d0 = 0;
  *(uint64_t*)0x200000d8 = 0;
  *(uint64_t*)0x200000e0 = 0;
  syscall(__NR_ioctl, /*fd=*/r[2], /*cmd=*/0xc028660f, /*arg=*/0x200000c0ul);
  syscall(__NR_writev, /*fd=*/-1, /*vec=*/0ul, /*vlen=*/0ul);
  syscall(__NR_ioctl, /*fd=*/-1, /*cmd=*/0x40045569, /*arg=*/9ul);
  syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0ul, /*flags=*/0x275aul,
          /*mode=*/0ul);
  memcpy((void*)0x20000180, "cgroup.controllers\000", 19);
  res = syscall(__NR_openat, /*fd=*/0xffffff9c, /*file=*/0x20000180ul,
                /*flags=*/0x275aul, /*mode=*/0ul);
  if (res != -1) r[4] = res;
  *(uint64_t*)0x200000c0 = 4;
  *(uint64_t*)0x200000c8 = 0x16000000000000;
  *(uint64_t*)0x200000d0 = 0x20;
  syscall(__NR_ioctl, /*fd=*/r[4], /*cmd=*/0xc0185879, /*arg=*/0x200000c0ul);
}
int main(void) {
  syscall(__NR_mmap, /*addr=*/0x1ffff000ul, /*len=*/0x1000ul, /*prot=*/0ul,
          /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
  syscall(__NR_mmap, /*addr=*/0x20000000ul, /*len=*/0x1000000ul, /*prot=*/7ul,
          /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
  syscall(__NR_mmap, /*addr=*/0x21000000ul, /*len=*/0x1000ul, /*prot=*/0ul,
          /*flags=*/0x32ul, /*fd=*/-1, /*offset=*/0ul);
  for (procid = 0; procid < 4; procid++) {
    if (fork() == 0) {
      loop();
    }
  }
  sleep(1000000);
  return 0;
}

=* repro.txt =*
r0 = openat$cgroup_ro(0xffffffffffffff9c,
&(0x7f0000000280)='cgroup.controllers\x00', 0x275a, 0x0)
r1 = openat$cgroup_ro(0xffffffffffffff9c,
&(0x7f0000000180)='cgroup.controllers\x00', 0x275a, 0x0)
r2 = dup3(r1, r0, 0x0)
ioctl$FS_IOC_FSSETXATTR(r0, 0x401c5820, &(0x7f0000000140)={0x20, 0x8c8c})
write$cgroup_int(r0, &(0x7f0000000040), 0xfea0)
r3 = openat$cgroup_ro(0xffffffffffffff9c,
&(0x7f00000001c0)='cpuset.effective_cpus\x00', 0x275a, 0x0)
write$cgroup_int(r3, &(0x7f0000000380), 0x101bf)
ioctl$EXT4_IOC_ALLOC_DA_BLKS(r3, 0x660c)
ioctl$EXT4_IOC_MOVE_EXT(r2, 0xc028660f, &(0x7f00000000c0)={0x0, r3, 0x7})
writev(0xffffffffffffffff, 0x0, 0x0)
ioctl$UI_SET_LEDBIT(0xffffffffffffffff, 0x40045569, 0x9)
openat$cgroup_ro(0xffffffffffffff9c, 0x0, 0x275a, 0x0)
r4 = openat$cgroup_ro(0xffffffffffffff9c,
&(0x7f0000000180)='cgroup.controllers\x00', 0x275a, 0x0)
ioctl$FITRIM(r4, 0xc0185879, &(0x7f00000000c0)={0x4, 0x16000000000000, 0x20})

and also https://gist.github.com/xrivendell7/bad992c2b716ed14310efa2c6f878b7c

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: divide error in mb_update_avg_fragment_size
  2023-12-08 14:12 divide error in mb_update_avg_fragment_size xingwei lee
@ 2023-12-09 10:05 ` Baokun Li
  0 siblings, 0 replies; 3+ messages in thread
From: Baokun Li @ 2023-12-09 10:05 UTC (permalink / raw)
  To: xingwei lee, harperchen1110
  Cc: adilger.kernel, linux-ext4, linux-kernel, syzkaller-bugs,
	syzkaller, tytso, Baokun Li, yangerkun

On 2023/12/8 22:12, xingwei lee wrote:
> Hello I saw you can't reproduce this bug and I reproduce it with
> repro.c and repro.txt
> I test the repro.c in the lastest HEAD: 5e3f5b81de80c98338bcb47c233aebefee5a4801
> kernel config: https://syzkaller.appspot.com/text?tag=KernelConfig&x=6ae1a4ee971a7305
> and the bug also existed.

Hello xingwei!

Thanks for the reproducer!

The problem is that the same range of physical blocks are freed in
ext4_mb_release_inode_pa() and ext4_process_freed_data() successively.
Thus in mb_free_blocks() bb_free is added twice, while bb_fragments
is added only once, the second time exiting early due to checking
for release of already freed blocks. So when fstrim marks all the
blocks in the group as already used, bb_free not being 0 and
bb_fragments being 0 triggers a divide-by-zero problem in
mb_update_avg_fragment_size().

We should avoid freeing blocks in ext4_mb_release_inode_pa() that
are about to be freed in ext4_process_freed_data().  I will send out
a patch after doing some tests.

Cheers!
-- 
With Best Regards,
Baokun Li
.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* divide error in mb_update_avg_fragment_size
@ 2022-12-08 12:27 Wei Chen
  0 siblings, 0 replies; 3+ messages in thread
From: Wei Chen @ 2022-12-08 12:27 UTC (permalink / raw)
  To: tytso, adilger.kernel, syzbot, linux-ext4, linux-kernel, syzkaller-bugs

Dear Linux Developers,

Recently, when using our tool to fuzz kernel, the following crash was triggered.

HEAD commit: 147307c69ba
git tree: linux-next
compiler: clang 12.0.0
console output:
https://drive.google.com/file/d/1tComytzKYQKzKfiS1PwrKBLQJwZn4usl/view?usp=share_link
kernel config: https://drive.google.com/file/d/1NAf4S43d9VOKD52xbrqw-PUP1Mbj8z-S/view?usp=share_link

Unfortunately, I didn't have a reproducer for this crash. When calling
ioctl with command FITRIM, the variable grp->bb_fragments is zero,
thus leading to divide error when executing grp->bb_free /
grp->bb_fragments. I'm wondering if a sanity check is missing when
handling malicious disk image.

IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: Wei Chen <harperchen1110@gmail.com>

divide error: 0000 [#1] PREEMPT SMP
CPU: 0 PID: 8874 Comm: syz-executor.0 Not tainted 6.1.0-rc5-next-20221118 #2
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
rel-1.13.0-48-gd9c812dda519-prebuilt.qemu.org 04/01/2014
RIP: 0010:mb_update_avg_fragment_size+0x84/0x2e0 fs/ext4/mballoc.c:835
Code: 41 5f 5d c3 49 8d 7e 14 e8 a9 38 ca ff 41 8b 5e 14 31 ff 89 de
e8 ac d3 b6 ff 85 db 74 61 49 8d 7e 18 e8 8f 38 ca ff 89 d8 99 <41> f7
7e 18 89 44 24 14 bb ff ff ff ff 0f bd 5c 24 14 8d 73 ff 45
RSP: 0018:ffffc90001bf3a60 EFLAGS: 00010246
RAX: 0000000000000456 RBX: 0000000000000456 RCX: ffffffff8170e251
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88810204e018
RBP: ffff8881030de800 R08: 000188810204e01b R09: 0000000000000000
R10: 0001ffffffffffff R11: 000188810204e020 R12: 0000000000008000
R13: ffff88810315b000 R14: ffff88810204e000 R15: ffffc90001bf3cc0
FS:  00007f4a1db97700(0000) GS:ffff88813bc00000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000055ebcf207bd0 CR3: 0000000131681000 CR4: 00000000003506f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000600
Call Trace:
 <TASK>
 mb_mark_used+0xb5c/0xcc0 fs/ext4/mballoc.c:1958
 ext4_trim_extent+0xd4/0x340 fs/ext4/mballoc.c:6352
 ext4_try_to_trim_range+0x194/0x460 fs/ext4/mballoc.c:6382
 ext4_trim_all_free+0x26e/0x3d0 fs/ext4/mballoc.c:6444
 ext4_trim_fs+0x56b/0x6d0 fs/ext4/mballoc.c:6540
 __ext4_ioctl+0x13b6/0x2990 fs/ext4/ioctl.c:1483
 ext4_ioctl+0x1e/0x30 fs/ext4/ioctl.c:1606
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:870 [inline]
 __se_sys_ioctl+0xcb/0x140 fs/ioctl.c:856
 __x64_sys_ioctl+0x3f/0x50 fs/ioctl.c:856
 do_syscall_x64 arch/x86/entry/common.c:50 [inline]
 do_syscall_64+0x2b/0x70 arch/x86/entry/common.c:80
 entry_SYSCALL_64_after_hwframe+0x63/0xcd
RIP: 0033:0x4697f9
Code: f7 d8 64 89 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 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 bc ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f4a1db96c48 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 000000000077bf80 RCX: 00000000004697f9
RDX: 0000000020000040 RSI: 00000000c0185879 RDI: 0000000000000004
RBP: 00000000004d29e9 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 000000000077bf80
R13: 0000000000000000 R14: 000000000077bf80 R15: 00007fffbabb2d30
 </TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:mb_update_avg_fragment_size+0x84/0x2e0 fs/ext4/mballoc.c:835
Code: 41 5f 5d c3 49 8d 7e 14 e8 a9 38 ca ff 41 8b 5e 14 31 ff 89 de
e8 ac d3 b6 ff 85 db 74 61 49 8d 7e 18 e8 8f 38 ca ff 89 d8 99 <41> f7
7e 18 89 44 24 14 bb ff ff ff ff 0f bd 5c 24 14 8d 73 ff 45
RSP: 0018:ffffc90001bf3a60 EFLAGS: 00010246
RAX: 0000000000000456 RBX: 0000000000000456 RCX: ffffffff8170e251
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88810204e018
RBP: ffff8881030de800 R08: 000188810204e01b R09: 0000000000000000
R10: 0001ffffffffffff R11: 000188810204e020 R12: 0000000000008000
R13: ffff88810315b000 R14: ffff88810204e000 R15: ffffc90001bf3cc0
FS:  00007f4a1db97700(0000) GS:ffff88813bc00000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000055ebcf207bd0 CR3: 0000000131681000 CR4: 00000000003506f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000600
----------------
Code disassembly (best guess):
   0: 41 5f                 pop    %r15
   2: 5d                   pop    %rbp
   3: c3                   retq
   4: 49 8d 7e 14           lea    0x14(%r14),%rdi
   8: e8 a9 38 ca ff       callq  0xffca38b6
   d: 41 8b 5e 14           mov    0x14(%r14),%ebx
  11: 31 ff                 xor    %edi,%edi
  13: 89 de                 mov    %ebx,%esi
  15: e8 ac d3 b6 ff       callq  0xffb6d3c6
  1a: 85 db                 test   %ebx,%ebx
  1c: 74 61                 je     0x7f
  1e: 49 8d 7e 18           lea    0x18(%r14),%rdi
  22: e8 8f 38 ca ff       callq  0xffca38b6
  27: 89 d8                 mov    %ebx,%eax
  29: 99                   cltd
* 2a: 41 f7 7e 18           idivl  0x18(%r14) <-- trapping instruction
  2e: 89 44 24 14           mov    %eax,0x14(%rsp)
  32: bb ff ff ff ff       mov    $0xffffffff,%ebx
  37: 0f bd 5c 24 14       bsr    0x14(%rsp),%ebx
  3c: 8d 73 ff             lea    -0x1(%rbx),%esi
  3f: 45                   rex.RB

Best,
Wei

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2023-12-09 10:30 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-08 14:12 divide error in mb_update_avg_fragment_size xingwei lee
2023-12-09 10:05 ` Baokun Li
  -- strict thread matches above, loose matches on Subject: below --
2022-12-08 12:27 Wei Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®