diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt index 819caf8ca05f8b4b16226c0f5d6f76068de09131..15ec58f0dd31c1beeea8e62757efdc59cb90fed3 100644 --- a/Documentation/sysctl/fs.txt +++ b/Documentation/sysctl/fs.txt @@ -36,6 +36,7 @@ Currently, these files are in /proc/sys/fs: - pipe-user-pages-soft - protected_fifos - protected_hardlinks +- hardlink_cross_projid - protected_regular - protected_symlinks - suid_dumpable @@ -238,6 +239,15 @@ When set to "2" it also applies to group writable sticky directories. ============================================================== +hardlink_cross_projid: + +This is a temporary workaround plan to avoid the limitation when creating +hard link cross two projids. When set to "0", hardlink creation cross +two projids is restricted. When set to "1" hardlinks can be created +cross two projids. + +============================================================== + protected_symlinks: A long-standing class of security issues is the symlink-based diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index f56d6f1950b9827e98a80e125f8bf1f933ffca68..62f57fcb8e8bee13eb383c2170c705a7c0b2aa2b 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3224,7 +3224,8 @@ static int ext4_link(struct dentry *old_dentry, if (err) return err; - if ((ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) && + if (!sysctl_hardlink_cross_projid && + (ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) && (!projid_eq(EXT4_I(dir)->i_projid, EXT4_I(old_dentry->d_inode)->i_projid))) return -EXDEV; diff --git a/include/linux/fs.h b/include/linux/fs.h index 92420009b9bcbffbb904d9261e958190562f1eb7..71827fc026f051a47697a4506e7deec1c85bc5ee 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -74,6 +74,7 @@ extern struct inodes_stat_t inodes_stat; extern int leases_enable, lease_break_time; extern int sysctl_protected_symlinks; extern int sysctl_protected_hardlinks; +extern int sysctl_hardlink_cross_projid; extern int sysctl_protected_fifos; extern int sysctl_protected_regular; diff --git a/kernel/sys.c b/kernel/sys.c index 096932a450466675df687b849d1beb4077e6df21..6f7a0c9e83f3335e10505f0828ec1cfc06c0abee 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -144,6 +144,9 @@ int fs_overflowgid = DEFAULT_FS_OVERFLOWGID; EXPORT_SYMBOL(fs_overflowuid); EXPORT_SYMBOL(fs_overflowgid); +int sysctl_hardlink_cross_projid = 0; +EXPORT_SYMBOL(sysctl_hardlink_cross_projid); + /* * Returns true if current's euid is same as p's uid or euid, * or has CAP_SYS_NICE to p's user_ns. diff --git a/kernel/sysctl.c b/kernel/sysctl.c index b7fd0528747504bbe72829abfa63b2942a38b860..8a5f85651ba687149622aac3a2d5041e32c0b78e 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1874,6 +1874,15 @@ static struct ctl_table fs_table[] = { .proc_handler = proc_dointvec_minmax, .extra1 = &one, }, + { + .procname = "hardlink_cross_projid", + .data = &sysctl_hardlink_cross_projid, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &one, + }, { } };