Page 1 of 1

Size overflow detected in btrfs_real_readdir

PostPosted: Mon Oct 19, 2015 1:01 pm
by Stebalien
When I enable CONFIG_PAX_SIZE_OVERFLOW in 4.2.3-201510190716, I get the following error:
PAX: size overflow detected in function btrfs_real_readdir fs/btrfs/inode.c:5759 cicus.1124_299 max, count: 57, decl: pos; num: 0; context: dir_context;

Followed by several:
PAX: size overflow detected in function btrfs_sync_file fs/btrfs/file.c:1871 cicus.677_110 max, count: 57289 decl: btrfs_wait_ordered_range; num: 3; context: fndecl;

And a kernel panic.

BTRFS Options:

Code: Select all
CONFIG_BTRFS_FS=y
CONFIG_BTRFS_FS_POSIX_ACL=y
# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set
# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set
# CONFIG_BTRFS_DEBUG is not set
# CONFIG_BTRFS_ASSERT is not set


Grsecurity Options:

Code: Select all
CONFIG_PAX_KERNEXEC_PLUGIN=y
CONFIG_PAX_PER_CPU_PGD=y
CONFIG_PAX_USERCOPY_SLABS=y
CONFIG_GRKERNSEC=y
# CONFIG_GRKERNSEC_CONFIG_AUTO is not set
CONFIG_GRKERNSEC_CONFIG_CUSTOM=y
CONFIG_GRKERNSEC_TPE_UNTRUSTED_GID=612
CONFIG_PAX=y
# CONFIG_PAX_SOFTMODE is not set
# CONFIG_PAX_EI_PAX is not set
# CONFIG_PAX_PT_PAX_FLAGS is not set
CONFIG_PAX_XATTR_PAX_FLAGS=y
CONFIG_PAX_NO_ACL_FLAGS=y
# CONFIG_PAX_HAVE_ACL_FLAGS is not set
# CONFIG_PAX_HOOK_ACL_FLAGS is not set
CONFIG_PAX_NOEXEC=y
CONFIG_PAX_PAGEEXEC=y
CONFIG_PAX_EMUTRAMP=y
CONFIG_PAX_MPROTECT=y
# CONFIG_PAX_MPROTECT_COMPAT is not set
# CONFIG_PAX_ELFRELOCS is not set
CONFIG_PAX_KERNEXEC=y
CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_BTS=y
# CONFIG_PAX_KERNEXEC_PLUGIN_METHOD_OR is not set
CONFIG_PAX_KERNEXEC_PLUGIN_METHOD="bts"
CONFIG_PAX_ASLR=y
CONFIG_PAX_RANDKSTACK=y
CONFIG_PAX_RANDUSTACK=y
CONFIG_PAX_RANDMMAP=y
# CONFIG_PAX_MEMORY_SANITIZE is not set
# CONFIG_PAX_MEMORY_STACKLEAK is not set
# CONFIG_PAX_MEMORY_STRUCTLEAK is not set
CONFIG_PAX_MEMORY_UDEREF=y
CONFIG_PAX_REFCOUNT=y
CONFIG_PAX_CONSTIFY_PLUGIN=y
CONFIG_PAX_USERCOPY=y
# CONFIG_PAX_USERCOPY_DEBUG is not set
# CONFIG_PAX_LATENT_ENTROPY is not set
CONFIG_GRKERNSEC_KMEM=y
CONFIG_GRKERNSEC_IO=y
CONFIG_GRKERNSEC_BPF_HARDEN=y
CONFIG_GRKERNSEC_PERF_HARDEN=y
CONFIG_GRKERNSEC_RAND_THREADSTACK=y
CONFIG_GRKERNSEC_PROC_MEMMAP=y
CONFIG_GRKERNSEC_KSTACKOVERFLOW=y
CONFIG_GRKERNSEC_BRUTE=y
# CONFIG_GRKERNSEC_MODHARDEN is not set
CONFIG_GRKERNSEC_HIDESYM=y
# CONFIG_GRKERNSEC_RANDSTRUCT is not set
CONFIG_GRKERNSEC_KERN_LOCKOUT=y
CONFIG_GRKERNSEC_NO_RBAC=y
# CONFIG_GRKERNSEC_ACL_HIDEKERN is not set
CONFIG_GRKERNSEC_ACL_MAXTRIES=3
CONFIG_GRKERNSEC_ACL_TIMEOUT=30
# CONFIG_GRKERNSEC_PROC is not set
# CONFIG_GRKERNSEC_LINK is not set
# CONFIG_GRKERNSEC_SYMLINKOWN is not set
CONFIG_GRKERNSEC_FIFO=y
# CONFIG_GRKERNSEC_SYSFS_RESTRICT is not set
# CONFIG_GRKERNSEC_ROFS is not set
CONFIG_GRKERNSEC_DEVICE_SIDECHANNEL=y
CONFIG_GRKERNSEC_CHROOT=y
# CONFIG_GRKERNSEC_CHROOT_MOUNT is not set
# CONFIG_GRKERNSEC_CHROOT_DOUBLE is not set
# CONFIG_GRKERNSEC_CHROOT_PIVOT is not set
# CONFIG_GRKERNSEC_CHROOT_CHDIR is not set
# CONFIG_GRKERNSEC_CHROOT_CHMOD is not set
CONFIG_GRKERNSEC_CHROOT_FCHDIR=y
CONFIG_GRKERNSEC_CHROOT_MKNOD=y
CONFIG_GRKERNSEC_CHROOT_SHMAT=y
# CONFIG_GRKERNSEC_CHROOT_UNIX is not set
# CONFIG_GRKERNSEC_CHROOT_FINDTASK is not set
# CONFIG_GRKERNSEC_CHROOT_NICE is not set
CONFIG_GRKERNSEC_CHROOT_SYSCTL=y
CONFIG_GRKERNSEC_CHROOT_RENAME=y
# CONFIG_GRKERNSEC_CHROOT_CAPS is not set
# CONFIG_GRKERNSEC_AUDIT_GROUP is not set
# CONFIG_GRKERNSEC_EXECLOG is not set
CONFIG_GRKERNSEC_RESLOG=y
# CONFIG_GRKERNSEC_CHROOT_EXECLOG is not set
CONFIG_GRKERNSEC_AUDIT_PTRACE=y
# CONFIG_GRKERNSEC_AUDIT_CHDIR is not set
# CONFIG_GRKERNSEC_AUDIT_MOUNT is not set
CONFIG_GRKERNSEC_SIGNAL=y
CONFIG_GRKERNSEC_FORKFAIL=y
# CONFIG_GRKERNSEC_TIME is not set
# CONFIG_GRKERNSEC_PROC_IPADDR is not set
CONFIG_GRKERNSEC_RWXMAP_LOG=y
# CONFIG_GRKERNSEC_DMESG is not set
CONFIG_GRKERNSEC_HARDEN_PTRACE=y
CONFIG_GRKERNSEC_PTRACE_READEXEC=y
# CONFIG_GRKERNSEC_SETXID is not set
CONFIG_GRKERNSEC_HARDEN_IPC=y
CONFIG_GRKERNSEC_TPE=y
CONFIG_GRKERNSEC_TPE_ALL=y
# CONFIG_GRKERNSEC_TPE_INVERT is not set
CONFIG_GRKERNSEC_TPE_GID=612
CONFIG_GRKERNSEC_BLACKHOLE=y
CONFIG_GRKERNSEC_NO_SIMULT_CONNECT=y
# CONFIG_GRKERNSEC_SOCKET is not set
# CONFIG_GRKERNSEC_DENYUSB is not set
CONFIG_GRKERNSEC_SYSCTL=y
# CONFIG_GRKERNSEC_SYSCTL_DISTRO is not set
CONFIG_GRKERNSEC_SYSCTL_ON=y
CONFIG_GRKERNSEC_FLOODTIME=10
CONFIG_GRKERNSEC_FLOODBURST=6

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Mon Oct 19, 2015 6:30 pm
by ephox
Hi,

Thanks for report. These are real bugs, you should report them to the btrfs kernel mailing list.

First bug: fs/btrfs/inode.c:5759
This patch writes out the pos value that will overflow after the increment:
Code: Select all
--- fs/btrfs/inode.c.orig       2015-10-18 14:33:04.674254062 +0200
+++ fs/btrfs/inode.c    2015-10-18 14:33:38.322252562 +0200
@@ -5756,6 +5756,7 @@
        }
 
        /* Reached end of directory/root. Bump pos past the last item. */
+       printk(KERN_ERR "Overflow: %llx\n", ctx->pos);
        ctx->pos++;
 
        /*

Send the printed value and the btrfs developers will see the overflow.

Second bug: fs/btrfs/file.c:1871
len = end - start + 1

vfs_fsync calls vfs_fsync_range with 0 and LLONG_MAX for start and end.
In btrfs_sync_file the above expression causes a signed overflow (undefined behaviour) with these values.

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Sun Oct 25, 2015 9:17 am
by alan.d
Has this been reported to the btrfs devs yet? If yes, could you please link to it?
I could only report the second issue, I do not observe the first one. I guess for the second issue, the following information is enough?

Second bug: fs/btrfs/file.c:1871
len = end - start + 1

vfs_fsync calls vfs_fsync_range with 0 and LLONG_MAX for start and end.
In btrfs_sync_file the above expression causes a signed overflow (undefined behaviour) with these values.

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Sun Oct 25, 2015 9:34 am
by ephox

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Mon Nov 09, 2015 6:53 am
by kdave
Fix for the overflow in btrfs_sync_file sent upstream, https://patchwork.kernel.org/patch/7582351/ .

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Mon Nov 09, 2015 8:21 am
by PaX Team
cool, we'll have it in the next patch. what about the first bug, is there a patch for that as well perhaps? (i didn't get any replies from the btrfs list)

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Mon Nov 09, 2015 10:09 am
by kdave
I'm working on it right now, the overflow itself seems harmless, the value is reset to LLONG_MAX afterwards, which is enough to stop readdir. There were some concerns regarding compatibility with 32bit apps, I'm rereading the original discussions.

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Mon Nov 09, 2015 10:32 am
by PaX Team
hmm, where does the reset to LLONG_MAX happen? if you mean line 5781 (in 4.2.5, give or take) then that code is under a conditional check (key_type == BTRFS_DIR_INDEX_KEY, but the signed overflow may not occur when it's false, i don't know), and the ctx->pos >= INT_MAX check will fail since the overflow will produce LLONG_MIN so the reset would be to INT_MAX instead (which may or may not be desirable).

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Mon Nov 09, 2015 1:36 pm
by kdave
The section with "ctx->pos++" is called twice, once when the last readdir emits some entries (sets pos to INT_MAX) and according to strace again where it retuns no entries, but still bumps, going from INT_MAX to LLONG_MAX.

[13810.607107] emit 201
[13810.607107] emitted
[13810.607108] DBG: pos 201
[13810.607108] DBG: (pre) pos 202
[13810.607109] DBG: (post) pos 203
[13810.607110] DBG: last pos 2147483647
[13810.607299] DBG: pos at the start 2147483647
[13810.607303] !emitted
[13810.607304] DBG: pos 2147483647
[13810.607304] DBG: (pre) pos 2147483647
[13810.607305] DBG: (post) pos 2147483648
[13810.607306] DBG: last pos 9223372036854775807


What you describe, I've reliably reproduced when 'pos' is larger than INT_MAX from regular entries, then it's first set to LLONG_MAX, overflows to LLONG_MIN and then is set to INT_MAX:

[13500.982658] emit 4294967495
[13500.982658] emitted
[13500.982659] DBG: pos 4294967495
[13500.982660] DBG: (pre) pos 4294967496
[13500.982660] DBG: (post) pos 4294967497
[13500.982661] DBG: last pos 9223372036854775807
[13500.997339] DBG: pos at the start 9223372036854775807
[13500.997345] !emitted
[13500.997346] DBG: pos 9223372036854775807
[13500.997347] DBG: (pre) pos 9223372036854775807
[13500.997347] DBG: (post) pos -9223372036854775808
[13500.997348] DBG: last pos 2147483647


I'm still not sure how it could happen without artificially setting the pos to be larger than INT_MAX, but according to the logs provided by Victor at http://pastebin.com/S9gjYpYX it is possible.

The fix https://patchwork.kernel.org/patch/7585611/.

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Thu Nov 12, 2015 4:20 am
by kdave
FYI, we have reports that the patch for btrfs_real_readdir is buggy and may cause hangs.

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Thu Nov 12, 2015 8:50 pm
by spender

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Fri Nov 13, 2015 2:12 pm
by kdave
Updated fix, https://patchwork.kernel.org/patch/7611351/ also tested by a reporter of v1 issues.

spender wrote:It seems that code has a history of problems:


Yeah, the 'ctx->pos and 0x7f... tricks' approach looks less fragile to me than the proposed 'f_version' approach. I've tested the 32 to 64 bit overflow on ctx->pos, works as expected.

Re: Size overflow detected in btrfs_real_readdir

PostPosted: Fri Dec 18, 2015 7:53 pm
by Dwokfur