Syzbot recently found a number of issues related to incremental-fs
(see bug numbers below). All have to do with the fact that incr-fs
allows mounts of the same source and target multiple times.
The correct behavior for a file system is to allow only one such
mount, and then every subsequent attempt should fail with a -EBUSY
error code. In case of the issues listed below the common pattern
is that the reproducer calls:
mount("./file0", "./file0", "incremental-fs", 0, NULL)
many times and then invokes a file operation like chmod, setxattr,
or open on the ./file0. This causes a recursive call for all the
mounted instances, which eventually causes a stack overflow and
a kernel crash:
BUG: stack guard page was hit at ffffc90000c0fff8
kernel stack overflow (double-fault): 0000 [#1] PREEMPT SMP KASAN
The reason why many mounts with the same source and target are
possible is because the incfs_mount_fs() as it is allocates a new
super_block for every call, regardless of whether a given mount already
exists or not. This happens every time the sget() function is called
with a test param equal to NULL.
The correct behavior for an FS mount implementation is to call
appropriate mount vfs call for it's type, i.e. mount_bdev() for
a block device backed FS, mount_single() for a pseudo file system,
like sysfs that is mounted in a single, well know location, or
mount_nodev() for other special purpose FS like overlayfs.
In case of incremental-fs the open coded mount logic doesn't check
for abusive mount attempts such as overlays.
To fix this issue the logic needs to be changed to pass a proper
test function to sget() call, which then checks if a super_block
for a mount instance has already been allocated and also allows
the VFS to properly verify invalid mount attempts.
Bug: 211066171
Bug: 213140206
Bug: 213215835
Bug: 211914587
Bug: 211213635
Bug: 213137376
Bug: 211161296
Signed-off-by: Tadeusz Struk <tadeusz.struk@linaro.org>
Change-Id: I66cfc3f1b5aaffb32b0845b2dad3ff26fe952e27
33 lines
768 B
C
33 lines
768 B
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright 2018 Google LLC
|
|
*/
|
|
|
|
#ifndef _INCFS_VFS_H
|
|
#define _INCFS_VFS_H
|
|
|
|
extern const struct file_operations incfs_file_ops;
|
|
extern const struct inode_operations incfs_file_inode_ops;
|
|
|
|
void incfs_kill_sb(struct super_block *sb);
|
|
struct dentry *incfs_mount_fs(struct file_system_type *type, int flags,
|
|
const char *dev_name, void *data);
|
|
int incfs_link(struct dentry *what, struct dentry *where);
|
|
int incfs_unlink(struct dentry *dentry);
|
|
|
|
static inline struct mount_info *get_mount_info(struct super_block *sb)
|
|
{
|
|
struct mount_info *result = sb->s_fs_info;
|
|
|
|
return result;
|
|
}
|
|
|
|
static inline struct super_block *file_superblock(struct file *f)
|
|
{
|
|
struct inode *inode = file_inode(f);
|
|
|
|
return inode->i_sb;
|
|
}
|
|
|
|
#endif
|