* Re: [BUG] WARNING in ext4_journalled_invalidate_folio
2026-08-28 14:30 ` Theodore Tso
@ 2026-09-08 4:11 ` Farhad Alemi
0 siblings, 0 replies; 3+ messages in thread
From: Farhad Alemi @ 2026-09-08 4:11 UTC (permalink / raw)
To: Theodore Tso
Cc: Alexander Viro, Christian Brauner, linux-ext4, linux-fsdevel,
linux-kernel
[-- Attachment #1: Type: text/plain, Size: 834 bytes --]
Attaching the reproducer; thanks!
On Fri, Aug 28, 2026 at 7:31 AM Theodore Tso <tytso@mit.edu> wrote:
>
> On Thu, Aug 27, 2026 at 10:45:30PM -0500, Farhad Alemi wrote:
> > Hello,
> >
> > As part of the kernel research at ASU's SEFCOM
> > lab, we hit the crash below. Crash reports can be found here:
> >
> > https://github.com/farhad-alemi/public_bug_reports/tree/main/172-warning-in-ext4-journalled-invalidate-folio/
>
> Please send the reproducer. Note that if it requries a maliciously
> fuzzed file system, we consider this to be a minor bug (especially if
> the maliciously file system would be fixed when the system
> administrator runs fsck on the file system first), and not "security"
> issue, so feel free to just send it to the list.
>
> Cheers,
>
> - Ted
[-- Attachment #2: reproducer.c --]
[-- Type: application/octet-stream, Size: 2757 bytes --]
/*
* WARNING in ext4_journalled_invalidate_folio, fs/ext4/inode.c.
*/
#define _GNU_SOURCE
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#define IMAGE "/tmp/ext4.img"
#define MOUNTPOINT "/mnt/ext4j"
#define NR_WRITERS 6
#define NR_FSYNCERS 2
static unsigned char *short_copy_source; /* readable page, then PROT_NONE */
static volatile int stop;
/* Straddle i_size inside one folio, then write past it with a count the
* source cannot satisfy: the write_end sees a short copy and truncates. */
static void *partial_writer(void *arg)
{
long id = (long)arg;
unsigned long round = 0;
char path[64];
int fd;
snprintf(path, sizeof(path), MOUNTPOINT "/w%ld", id);
fd = open(path, O_RDWR | O_CREAT, 0600);
if (fd < 0)
return NULL;
while (!stop) {
off_t size_inside_folio = 4096 + 400 + (off_t)(round % 600);
size_t source_offset = 3000 + (round % 1000);
off_t write_pos = 4096 + 1500 + (off_t)(round % 2000);
ftruncate(fd, 0);
ftruncate(fd, size_inside_folio);
/* write(2), not pwrite(2): the reported trace enters through
* new_sync_write()/ksys_write(). */
lseek(fd, write_pos, SEEK_SET);
write(fd, short_copy_source + source_offset, 0x20000);
round++;
}
close(fd);
return NULL;
}
/* Keep jbd2 cycling so a transaction is in the committing state. */
static void *fsyncer(void *arg)
{
long id = (long)arg;
char path[64], buf[512];
int fd;
memset(buf, 'c', sizeof(buf));
snprintf(path, sizeof(path), MOUNTPOINT "/s%ld", id);
fd = open(path, O_RDWR | O_CREAT, 0600);
if (fd < 0)
return NULL;
while (!stop) {
pwrite(fd, buf, sizeof(buf), 0);
fsync(fd);
}
close(fd);
return NULL;
}
int main(void)
{
pthread_t threads[NR_WRITERS + NR_FSYNCERS];
long i;
short_copy_source = mmap(NULL, 3 * 4096, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (short_copy_source == MAP_FAILED)
return 1;
memset(short_copy_source, 'A', 3 * 4096);
mprotect(short_copy_source + 4096, 2 * 4096, PROT_NONE);
unlink(IMAGE);
if (system("dd if=/dev/zero of=" IMAGE " bs=1M count=160 status=none"))
return 1;
if (system("mkfs.ext4 -q -F -b 1024 -J size=16 -I 256 " IMAGE))
return 1;
mkdir(MOUNTPOINT, 0755);
if (system("mount -t ext4 -o loop,data=journal,commit=1 "
IMAGE " " MOUNTPOINT))
return 1;
for (i = 0; i < NR_WRITERS; i++)
pthread_create(&threads[i], NULL, partial_writer, (void *)i);
for (i = 0; i < NR_FSYNCERS; i++)
pthread_create(&threads[NR_WRITERS + i], NULL, fsyncer, (void *)i);
sleep(42);
stop = 1;
for (i = 0; i < NR_WRITERS + NR_FSYNCERS; i++)
pthread_join(threads[i], NULL);
system("umount " MOUNTPOINT " 2>/dev/null");
return 0;
}
^ permalink raw reply [flat|nested] 3+ messages in thread