@@ -3383,6 +3383,9 @@ struct cap_extra_info {
33833383 /* currently issued */
33843384 int issued ;
33853385 struct timespec64 btime ;
3386+ u8 * fscrypt_auth ;
3387+ u32 fscrypt_auth_len ;
3388+ u64 fscrypt_file_size ;
33863389};
33873390
33883391/*
@@ -3415,6 +3418,14 @@ static void handle_cap_grant(struct inode *inode,
34153418 bool deleted_inode = false;
34163419 bool fill_inline = false;
34173420
3421+ /*
3422+ * If there is at least one crypto block then we'll trust
3423+ * fscrypt_file_size. If the real length of the file is 0, then
3424+ * ignore it (it has probably been truncated down to 0 by the MDS).
3425+ */
3426+ if (IS_ENCRYPTED (inode ) && size )
3427+ size = extra_info -> fscrypt_file_size ;
3428+
34183429 dout ("handle_cap_grant inode %p cap %p mds%d seq %d %s\n" ,
34193430 inode , cap , session -> s_mds , seq , ceph_cap_string (newcaps ));
34203431 dout (" size %llu max_size %llu, i_size %llu\n" , size , max_size ,
@@ -3481,6 +3492,14 @@ static void handle_cap_grant(struct inode *inode,
34813492 dout ("%p mode 0%o uid.gid %d.%d\n" , inode , inode -> i_mode ,
34823493 from_kuid (& init_user_ns , inode -> i_uid ),
34833494 from_kgid (& init_user_ns , inode -> i_gid ));
3495+ #if IS_ENABLED (CONFIG_FS_ENCRYPTION )
3496+ if (ci -> fscrypt_auth_len != extra_info -> fscrypt_auth_len ||
3497+ memcmp (ci -> fscrypt_auth , extra_info -> fscrypt_auth ,
3498+ ci -> fscrypt_auth_len ))
3499+ pr_warn_ratelimited ("%s: cap grant attempt to change fscrypt_auth on non-I_NEW inode (old len %d new len %d)\n" ,
3500+ __func__ , ci -> fscrypt_auth_len ,
3501+ extra_info -> fscrypt_auth_len );
3502+ #endif
34843503 }
34853504
34863505 if ((newcaps & CEPH_CAP_LINK_SHARED ) &&
@@ -3897,7 +3916,8 @@ static void handle_cap_flushsnap_ack(struct inode *inode, u64 flush_tid,
38973916 */
38983917static bool handle_cap_trunc (struct inode * inode ,
38993918 struct ceph_mds_caps * trunc ,
3900- struct ceph_mds_session * session )
3919+ struct ceph_mds_session * session ,
3920+ struct cap_extra_info * extra_info )
39013921{
39023922 struct ceph_inode_info * ci = ceph_inode (inode );
39033923 int mds = session -> s_mds ;
@@ -3914,6 +3934,14 @@ static bool handle_cap_trunc(struct inode *inode,
39143934
39153935 issued |= implemented | dirty ;
39163936
3937+ /*
3938+ * If there is at least one crypto block then we'll trust
3939+ * fscrypt_file_size. If the real length of the file is 0, then
3940+ * ignore it (it has probably been truncated down to 0 by the MDS).
3941+ */
3942+ if (IS_ENCRYPTED (inode ) && size )
3943+ size = extra_info -> fscrypt_file_size ;
3944+
39173945 dout ("handle_cap_trunc inode %p mds%d seq %d to %lld seq %d\n" ,
39183946 inode , mds , seq , truncate_size , truncate_seq );
39193947 queue_trunc = ceph_fill_file_size (inode , issued ,
@@ -4135,6 +4163,52 @@ static void handle_cap_import(struct ceph_mds_client *mdsc,
41354163 * target_cap = cap ;
41364164}
41374165
4166+ #ifdef CONFIG_FS_ENCRYPTION
4167+ static int parse_fscrypt_fields (void * * p , void * end ,
4168+ struct cap_extra_info * extra )
4169+ {
4170+ u32 len ;
4171+
4172+ ceph_decode_32_safe (p , end , extra -> fscrypt_auth_len , bad );
4173+ if (extra -> fscrypt_auth_len ) {
4174+ ceph_decode_need (p , end , extra -> fscrypt_auth_len , bad );
4175+ extra -> fscrypt_auth = kmalloc (extra -> fscrypt_auth_len ,
4176+ GFP_KERNEL );
4177+ if (!extra -> fscrypt_auth )
4178+ return - ENOMEM ;
4179+ ceph_decode_copy_safe (p , end , extra -> fscrypt_auth ,
4180+ extra -> fscrypt_auth_len , bad );
4181+ }
4182+
4183+ ceph_decode_32_safe (p , end , len , bad );
4184+ if (len >= sizeof (u64 )) {
4185+ ceph_decode_64_safe (p , end , extra -> fscrypt_file_size , bad );
4186+ len -= sizeof (u64 );
4187+ }
4188+ ceph_decode_skip_n (p , end , len , bad );
4189+ return 0 ;
4190+ bad :
4191+ return - EIO ;
4192+ }
4193+ #else
4194+ static int parse_fscrypt_fields (void * * p , void * end ,
4195+ struct cap_extra_info * extra )
4196+ {
4197+ u32 len ;
4198+
4199+ /* Don't care about these fields unless we're encryption-capable */
4200+ ceph_decode_32_safe (p , end , len , bad );
4201+ if (len )
4202+ ceph_decode_skip_n (p , end , len , bad );
4203+ ceph_decode_32_safe (p , end , len , bad );
4204+ if (len )
4205+ ceph_decode_skip_n (p , end , len , bad );
4206+ return 0 ;
4207+ bad :
4208+ return - EIO ;
4209+ }
4210+ #endif
4211+
41384212/*
41394213 * Handle a caps message from the MDS.
41404214 *
@@ -4255,6 +4329,11 @@ void ceph_handle_caps(struct ceph_mds_session *session,
42554329 ceph_decode_64_safe (& p , end , extra_info .nsubdirs , bad );
42564330 }
42574331
4332+ if (msg_version >= 12 ) {
4333+ if (parse_fscrypt_fields (& p , end , & extra_info ))
4334+ goto bad ;
4335+ }
4336+
42584337 /* lookup ino */
42594338 inode = ceph_find_inode (mdsc -> fsc -> sb , vino );
42604339 dout (" op %s ino %llx.%llx inode %p\n" , ceph_cap_op_name (op ), vino .ino ,
@@ -4352,7 +4431,8 @@ void ceph_handle_caps(struct ceph_mds_session *session,
43524431 break ;
43534432
43544433 case CEPH_CAP_OP_TRUNC :
4355- queue_trunc = handle_cap_trunc (inode , h , session );
4434+ queue_trunc = handle_cap_trunc (inode , h , session ,
4435+ & extra_info );
43564436 spin_unlock (& ci -> i_ceph_lock );
43574437 if (queue_trunc )
43584438 ceph_queue_vmtruncate (inode );
@@ -4375,6 +4455,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
43754455 if (close_sessions )
43764456 ceph_mdsc_close_sessions (mdsc );
43774457
4458+ kfree (extra_info .fscrypt_auth );
43784459 return ;
43794460
43804461flush_cap_releases :
0 commit comments