lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <3d8f73f4-3a64-4a86-8fc9-d910d4fa3be1@gmail.com>
Date: Wed, 18 Feb 2026 16:29:30 +0300
From: Vyacheslav Kovalevsky <slava.kovalevskiy.2014@...il.com>
To: tytso@....edu, adilger.kernel@...ger.ca
Cc: linux-ext4@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Writing more than 4096 bytes with O_SYNC flag does not persist all
 previously written data if system crashes

Detailed description
====================

Hello, there seems to be an issue with ext4 crash behavior:

1. Create and sync a new file.
2. Open the file and write some data (must be more than 4096 bytes).
3. Close the file.
4. Open the file with O_SYNC flag and write some data.

After system crash the file will have the wrong size and some previously 
written data will be lost.

According to Linux manual 
<https://man7.org/linux/man-pages/man2/open.2.html> O_SYNC can replaced 
with fsync() call after each write operation:

```
By the time write(2) (or similar) returns, the output data
and associated file metadata have been transferred to the
underlying hardware (i.e., as though each write(2) was
followed by a call to fsync(2)).
```

In this case it is not true, using O_SYNC does not persist the data like 
fsync() does (see test below).


System info
===========

Linux version 6.19.2


How to reproduce
================

```
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define BUFFER_LEN 5000 // should be at least ~ 4096+1

int main() {
   int status;
   int file_fd0;
   int file_fd1;
   int file_fd2;

   char buffer[BUFFER_LEN + 1] = {};
   for (int i = 0; i <= BUFFER_LEN; ++i) {
     buffer[i] = (char)i;
   }

   status = creat("file", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
   printf("CREAT: %d\n", status);
   file_fd0 = status;

   status = close(file_fd0);
   printf("CLOSE: %d\n", status);

   sync();

   status = open("file", O_WRONLY);
   printf("OPEN: %d\n", status);
   file_fd1 = status;

   status = write(file_fd1, buffer, BUFFER_LEN);
   printf("WRITE: %d\n", status);

   status = close(file_fd1);
   printf("CLOSE: %d\n", status);

   status = open("file", O_WRONLY | O_SYNC);
   printf("OPEN: %d\n", status);
   file_fd2 = status;

   status = write(file_fd2, "Test data!", 10);
   printf("WRITE: %d\n", status);

   status = close(file_fd2);
   printf("CLOSE: %d\n", status);
}
// after crash file size is 4096 instead of 5000
```

Output:

```
CREAT: 3
CLOSE: 0
OPEN: 3
WRITE: 5000
CLOSE: 0
OPEN: 3
WRITE: 10
CLOSE: 0
```

File content after crash:

```
$ xxd file
00000000: 5465 7374 2064 6174 6121 0a0b 0c0d 0e0f  Test data!......
00000010: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f ................
00000020: 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f  !"#$%&'()*+,-./

.........

00000ff0: f0f1 f2f3 f4f5 f6f7 f8f9 fafb fcfd feff ................
```

Steps:

1. Create and mount new ext4 file system in default configuration.
2. Change directory to root of the file system and run the compiled test.
3. Cause hard system crash (e.g. QEMU `system_reset` command).
4. Remount file system after crash.
5. Observe that file size is 4096 instead of 5000.

Notes:

- This also seems to affect XFS in the same way.


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ