fallocate on 32 bit boundary on 32 bit systems with setrlimit fails to generate SIGXFSZ signal

Bug #1994079 reported by Colin Ian King
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Linux
Confirmed
Medium
linux (Ubuntu)
New
High
Unassigned

Bug Description

This is a corner case on 32 bit systems when using large file offsets, fallocate and setrlimit.

Setting the RLIMIT_FSIZE with setrlimit to 0xffffffff and then fallocating 1 or more bytes at the offset of 0xffffffff should make the fallocate fail with EFBIG and generate a SIGXFSZ signal. On 64 bit platforms this works, on 32 bit platforms such as i386 Ubuntu bionic with 4.15 kernels it fails to generate EFBIG errors and SIGXFSZ.

Attached is a test program to illustrate the problem. It sets the file size limit and allocates 1024 bytes at the boundary file size limit for 3 offsets:

On 64 bit systems we get the expected results:
got signal SIGXFSZ
offset: 65536 (0x10000), fallocate returned: -1
got signal SIGXFSZ
offset: 4294966271 (0xfffffbff), fallocate returned: -1
got signal SIGXFSZ
offset: 4294967295 (0xffffffff), fallocate returned: -1

On 32 bit systems the code fails on the 0xffffffff offset:

got signal SIGXFSZ
offset: 65536 (0x10000), fallocate returned: -1
got signal SIGXFSZ
offset: 4294966271 (0xfffffbff), fallocate returned: -1
offset: 4294967295 (0xffffffff), fallocate returned: 0

Attached is the reproducer.

I found this while developing a file limit boundary test case in stress-ng and discovered it breaks on all 32 bit kernels (armhf, i386, etc), even with recent 5.15 kernels.

This could be seen as a security issue; the sysadmin can set the file size limit and yet a 32 bit system can use a corner case like this to fallocate a much larger file by using the 0xffffffff offset and a huge fallocate size.

Revision history for this message
Colin Ian King (colin-king) wrote :
Changed in linux (Ubuntu):
importance: Undecided → High
Revision history for this message
Ubuntu Kernel Bot (ubuntu-kernel-bot) wrote : Missing required logs.

This bug is missing log files that will aid in diagnosing the problem. While running an Ubuntu kernel (not a mainline or third-party kernel) please enter the following command in a terminal window:

apport-collect 1994079

and then change the status of the bug to 'Confirmed'.

If, due to the nature of the issue you have encountered, you are unable to run this command, please add a comment stating that fact and change the bug status to 'Confirmed'.

This change has been made by an automated script, maintained by the Ubuntu Kernel Team.

Changed in linux (Ubuntu):
status: New → Incomplete
Revision history for this message
Colin Ian King (colin-king) wrote :

occurs on 6.0 i386 kernels too

Changed in linux (Ubuntu):
status: Incomplete → New
Revision history for this message
In , colin.i.king (colin.i.king-linux-kernel-bugs) wrote :

Created attachment 303085
C source to reproduce the fallocate/SIGXFSZ issue

This is a corner case on 32 bit systems when using large file offsets, fallocate and setrlimit. Issue found on ext4, probably also on other file systems(?).

Setting the RLIMIT_FSIZE with setrlimit to 0xffffffff and then fallocating 1 or more bytes at the offset of 0xffffffff should make the fallocate fail with EFBIG and generate a SIGXFSZ signal. On 64 bit platforms this works, on 32 bit platforms such as i386 4.15 kernels through to linux 6.0 it fails to generate EFBIG errors and SIGXFSZ.

Attached is a test program to illustrate the problem. It sets the file size limit and allocates 1024 bytes at the boundary file size limit for 3 offsets:

On 64 bit systems we get the expected results:
got signal SIGXFSZ
offset: 65536 (0x10000), fallocate returned: -1
got signal SIGXFSZ
offset: 4294966271 (0xfffffbff), fallocate returned: -1
got signal SIGXFSZ
offset: 4294967295 (0xffffffff), fallocate returned: -1

On 32 bit systems the code fails on the 0xffffffff offset:

got signal SIGXFSZ
offset: 65536 (0x10000), fallocate returned: -1
got signal SIGXFSZ
offset: 4294966271 (0xfffffbff), fallocate returned: -1
offset: 4294967295 (0xffffffff), fallocate returned: 0

Attached is the reproducer.

I found this while developing a file limit boundary test case in stress-ng and discovered it breaks on all 32 bit kernels (armhf, i386, etc), even with recent 5.15 and 6.0 kernels.

attached is a simple reproducer

Changed in linux:
importance: Unknown → Medium
status: Unknown → Confirmed
Revision history for this message
In , colin.i.king (colin.i.king-linux-kernel-bugs) wrote :

Tested and fails also on m68k Linux 4.16

Revision history for this message
In , colin.i.king (colin.i.king-linux-kernel-bugs) wrote :

Tested and fails on m68k with ext4 and btrfs; occurs across arches and across file systems.

Revision history for this message
In , brauner (brauner-linux-kernel-bugs) wrote :

Hey Colin,

This looks to be intentional? Afaict, the -EFBIG might ceome directly from vfs_fallocate():

 /* Check for wrap through zero too */
 if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
  return -EFBIG;

and you should see the same behavior for 64bit if you pass in -1 as offset:

brauner@wittgenstein|~/Downloads
> sudo ./fallocate
got signal SIGXFSZ
offset: 65536 (0x10000), fallocate returned: -1
got signal SIGXFSZ
offset: 4294966271 (0xfffffbff), fallocate returned: -1
offset: 18446744073709551615 (0xffffffffffffffff), fallocate returned: -1

Revision history for this message
In , colin.i.king (colin.i.king-linux-kernel-bugs) wrote :

The behavior for 32 bit is not what I expected,

offset: 4294967295 (0xffffffff), fallocate returned: 0

allocating at the boundary is OK, where as at 0xfffffbff it fails. I'd expect at the boundary for it to fail too.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.