diff options
author | Jeff Layton <jlayton@kernel.org> | 2021-02-25 21:04:16 +0100 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2021-03-08 16:19:37 +0100 |
commit | ed94f87c2b123241ae5644cf82327e2da653adb6 (patch) | |
tree | ae2a0f3cc394f5ef0be1f3ab2ebf79914fd0fb84 /fs/ceph/caps.c | |
parent | ceph: fix up error handling with snapdirs (diff) | |
download | linux-ed94f87c2b123241ae5644cf82327e2da653adb6.tar.xz linux-ed94f87c2b123241ae5644cf82327e2da653adb6.zip |
ceph: don't allow type or device number to change on non-I_NEW inodes
Al pointed out that a malicious or broken MDS could change the type or
device number of a given inode number. It may also be possible for the
MDS to reuse an old inode number.
Ensure that we never allow fill_inode to change the type part of the
i_mode or the i_rdev unless I_NEW is set. Throw warnings if the MDS ever
changes these on us mid-stream, and return an error.
Don't set i_rdev directly, and rely on init_special_inode to do it.
Also, fix up error handling in the callers of ceph_get_inode.
In handle_cap_grant, check for and warn if the inode type changes, and
only overwrite the mode if it didn't.
Reported-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/ceph/caps.c')
-rw-r--r-- | fs/ceph/caps.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 570731c4d019..3c03fa37cac4 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -3358,7 +3358,13 @@ static void handle_cap_grant(struct inode *inode, if ((newcaps & CEPH_CAP_AUTH_SHARED) && (extra_info->issued & CEPH_CAP_AUTH_EXCL) == 0) { - inode->i_mode = le32_to_cpu(grant->mode); + umode_t mode = le32_to_cpu(grant->mode); + + if (inode_wrong_type(inode, mode)) + pr_warn_once("inode type changed! (ino %llx.%llx is 0%o, mds says 0%o)\n", + ceph_vinop(inode), inode->i_mode, mode); + else + inode->i_mode = mode; inode->i_uid = make_kuid(&init_user_ns, le32_to_cpu(grant->uid)); inode->i_gid = make_kgid(&init_user_ns, le32_to_cpu(grant->gid)); ci->i_btime = extra_info->btime; |