Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ceph: handle fscrypt fields in cap messages from MDS

Handle the new fscrypt_file and fscrypt_auth fields in cap messages. Use
them to populate new fields in cap_extra_info and update the inode with
those values.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Xiubo Li <xiubli@redhat.com>
Reviewed-and-tested-by: Luís Henriques <lhenriques@suse.de>
Reviewed-by: Milind Changire <mchangir@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>

authored by

Jeff Layton and committed by
Ilya Dryomov
0d91f0ad 16be62fc

+83 -2
+83 -2
fs/ceph/caps.c
··· 3383 3383 /* currently issued */ 3384 3384 int issued; 3385 3385 struct timespec64 btime; 3386 + u8 *fscrypt_auth; 3387 + u32 fscrypt_auth_len; 3388 + u64 fscrypt_file_size; 3386 3389 }; 3387 3390 3388 3391 /* ··· 3417 3414 bool queue_invalidate = false; 3418 3415 bool deleted_inode = false; 3419 3416 bool fill_inline = false; 3417 + 3418 + /* 3419 + * If there is at least one crypto block then we'll trust 3420 + * fscrypt_file_size. If the real length of the file is 0, then 3421 + * ignore it (it has probably been truncated down to 0 by the MDS). 3422 + */ 3423 + if (IS_ENCRYPTED(inode) && size) 3424 + size = extra_info->fscrypt_file_size; 3420 3425 3421 3426 dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n", 3422 3427 inode, cap, session->s_mds, seq, ceph_cap_string(newcaps)); ··· 3492 3481 dout("%p mode 0%o uid.gid %d.%d\n", inode, inode->i_mode, 3493 3482 from_kuid(&init_user_ns, inode->i_uid), 3494 3483 from_kgid(&init_user_ns, inode->i_gid)); 3484 + #if IS_ENABLED(CONFIG_FS_ENCRYPTION) 3485 + if (ci->fscrypt_auth_len != extra_info->fscrypt_auth_len || 3486 + memcmp(ci->fscrypt_auth, extra_info->fscrypt_auth, 3487 + ci->fscrypt_auth_len)) 3488 + pr_warn_ratelimited("%s: cap grant attempt to change fscrypt_auth on non-I_NEW inode (old len %d new len %d)\n", 3489 + __func__, ci->fscrypt_auth_len, 3490 + extra_info->fscrypt_auth_len); 3491 + #endif 3495 3492 } 3496 3493 3497 3494 if ((newcaps & CEPH_CAP_LINK_SHARED) && ··· 3916 3897 */ 3917 3898 static bool handle_cap_trunc(struct inode *inode, 3918 3899 struct ceph_mds_caps *trunc, 3919 - struct ceph_mds_session *session) 3900 + struct ceph_mds_session *session, 3901 + struct cap_extra_info *extra_info) 3920 3902 { 3921 3903 struct ceph_inode_info *ci = ceph_inode(inode); 3922 3904 int mds = session->s_mds; ··· 3933 3913 lockdep_assert_held(&ci->i_ceph_lock); 3934 3914 3935 3915 issued |= implemented | dirty; 3916 + 3917 + /* 3918 + * If there is at least one crypto block then we'll trust 3919 + * fscrypt_file_size. If the real length of the file is 0, then 3920 + * ignore it (it has probably been truncated down to 0 by the MDS). 3921 + */ 3922 + if (IS_ENCRYPTED(inode) && size) 3923 + size = extra_info->fscrypt_file_size; 3936 3924 3937 3925 dout("handle_cap_trunc inode %p mds%d seq %d to %lld seq %d\n", 3938 3926 inode, mds, seq, truncate_size, truncate_seq); ··· 4163 4135 *target_cap = cap; 4164 4136 } 4165 4137 4138 + #ifdef CONFIG_FS_ENCRYPTION 4139 + static int parse_fscrypt_fields(void **p, void *end, 4140 + struct cap_extra_info *extra) 4141 + { 4142 + u32 len; 4143 + 4144 + ceph_decode_32_safe(p, end, extra->fscrypt_auth_len, bad); 4145 + if (extra->fscrypt_auth_len) { 4146 + ceph_decode_need(p, end, extra->fscrypt_auth_len, bad); 4147 + extra->fscrypt_auth = kmalloc(extra->fscrypt_auth_len, 4148 + GFP_KERNEL); 4149 + if (!extra->fscrypt_auth) 4150 + return -ENOMEM; 4151 + ceph_decode_copy_safe(p, end, extra->fscrypt_auth, 4152 + extra->fscrypt_auth_len, bad); 4153 + } 4154 + 4155 + ceph_decode_32_safe(p, end, len, bad); 4156 + if (len >= sizeof(u64)) { 4157 + ceph_decode_64_safe(p, end, extra->fscrypt_file_size, bad); 4158 + len -= sizeof(u64); 4159 + } 4160 + ceph_decode_skip_n(p, end, len, bad); 4161 + return 0; 4162 + bad: 4163 + return -EIO; 4164 + } 4165 + #else 4166 + static int parse_fscrypt_fields(void **p, void *end, 4167 + struct cap_extra_info *extra) 4168 + { 4169 + u32 len; 4170 + 4171 + /* Don't care about these fields unless we're encryption-capable */ 4172 + ceph_decode_32_safe(p, end, len, bad); 4173 + if (len) 4174 + ceph_decode_skip_n(p, end, len, bad); 4175 + ceph_decode_32_safe(p, end, len, bad); 4176 + if (len) 4177 + ceph_decode_skip_n(p, end, len, bad); 4178 + return 0; 4179 + bad: 4180 + return -EIO; 4181 + } 4182 + #endif 4183 + 4166 4184 /* 4167 4185 * Handle a caps message from the MDS. 4168 4186 * ··· 4329 4255 ceph_decode_64_safe(&p, end, extra_info.nsubdirs, bad); 4330 4256 } 4331 4257 4258 + if (msg_version >= 12) { 4259 + if (parse_fscrypt_fields(&p, end, &extra_info)) 4260 + goto bad; 4261 + } 4262 + 4332 4263 /* lookup ino */ 4333 4264 inode = ceph_find_inode(mdsc->fsc->sb, vino); 4334 4265 dout(" op %s ino %llx.%llx inode %p\n", ceph_cap_op_name(op), vino.ino, ··· 4431 4352 break; 4432 4353 4433 4354 case CEPH_CAP_OP_TRUNC: 4434 - queue_trunc = handle_cap_trunc(inode, h, session); 4355 + queue_trunc = handle_cap_trunc(inode, h, session, 4356 + &extra_info); 4435 4357 spin_unlock(&ci->i_ceph_lock); 4436 4358 if (queue_trunc) 4437 4359 ceph_queue_vmtruncate(inode); ··· 4455 4375 if (close_sessions) 4456 4376 ceph_mdsc_close_sessions(mdsc); 4457 4377 4378 + kfree(extra_info.fscrypt_auth); 4458 4379 return; 4459 4380 4460 4381 flush_cap_releases: