@@ -193,17 +193,101 @@ void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
193193 swap (req -> r_fscrypt_auth , as -> fscrypt_auth );
194194}
195195
196- int ceph_encode_encrypted_dname (const struct inode * parent ,
197- struct qstr * d_name , char * buf )
196+ /*
197+ * User-created snapshots can't start with '_'. Snapshots that start with this
198+ * character are special (hint: there aren't real snapshots) and use the
199+ * following format:
200+ *
201+ * _<SNAPSHOT-NAME>_<INODE-NUMBER>
202+ *
203+ * where:
204+ * - <SNAPSHOT-NAME> - the real snapshot name that may need to be decrypted,
205+ * - <INODE-NUMBER> - the inode number (in decimal) for the actual snapshot
206+ *
207+ * This function parses these snapshot names and returns the inode
208+ * <INODE-NUMBER>. 'name_len' will also bet set with the <SNAPSHOT-NAME>
209+ * length.
210+ */
211+ static struct inode * parse_longname (const struct inode * parent ,
212+ const char * name , int * name_len )
198213{
214+ struct inode * dir = NULL ;
215+ struct ceph_vino vino = { .snap = CEPH_NOSNAP };
216+ char * inode_number ;
217+ char * name_end ;
218+ int orig_len = * name_len ;
219+ int ret = - EIO ;
220+
221+ /* Skip initial '_' */
222+ name ++ ;
223+ name_end = strrchr (name , '_' );
224+ if (!name_end ) {
225+ dout ("Failed to parse long snapshot name: %s\n" , name );
226+ return ERR_PTR (- EIO );
227+ }
228+ * name_len = (name_end - name );
229+ if (* name_len <= 0 ) {
230+ pr_err ("Failed to parse long snapshot name\n" );
231+ return ERR_PTR (- EIO );
232+ }
233+
234+ /* Get the inode number */
235+ inode_number = kmemdup_nul (name_end + 1 ,
236+ orig_len - * name_len - 2 ,
237+ GFP_KERNEL );
238+ if (!inode_number )
239+ return ERR_PTR (- ENOMEM );
240+ ret = kstrtou64 (inode_number , 10 , & vino .ino );
241+ if (ret ) {
242+ dout ("Failed to parse inode number: %s\n" , name );
243+ dir = ERR_PTR (ret );
244+ goto out ;
245+ }
246+
247+ /* And finally the inode */
248+ dir = ceph_find_inode (parent -> i_sb , vino );
249+ if (!dir ) {
250+ /* This can happen if we're not mounting cephfs on the root */
251+ dir = ceph_get_inode (parent -> i_sb , vino , NULL );
252+ if (!dir )
253+ dir = ERR_PTR (- ENOENT );
254+ }
255+ if (IS_ERR (dir ))
256+ dout ("Can't find inode %s (%s)\n" , inode_number , name );
257+
258+ out :
259+ kfree (inode_number );
260+ return dir ;
261+ }
262+
263+ int ceph_encode_encrypted_dname (struct inode * parent , struct qstr * d_name ,
264+ char * buf )
265+ {
266+ struct inode * dir = parent ;
267+ struct qstr iname ;
199268 u32 len ;
269+ int name_len ;
200270 int elen ;
201271 int ret ;
202- u8 * cryptbuf ;
272+ u8 * cryptbuf = NULL ;
273+
274+ iname .name = d_name -> name ;
275+ name_len = d_name -> len ;
276+
277+ /* Handle the special case of snapshot names that start with '_' */
278+ if ((ceph_snap (dir ) == CEPH_SNAPDIR ) && (name_len > 0 ) &&
279+ (iname .name [0 ] == '_' )) {
280+ dir = parse_longname (parent , iname .name , & name_len );
281+ if (IS_ERR (dir ))
282+ return PTR_ERR (dir );
283+ iname .name ++ ; /* skip initial '_' */
284+ }
285+ iname .len = name_len ;
203286
204- if (!fscrypt_has_encryption_key (parent )) {
287+ if (!fscrypt_has_encryption_key (dir )) {
205288 memcpy (buf , d_name -> name , d_name -> len );
206- return d_name -> len ;
289+ elen = d_name -> len ;
290+ goto out ;
207291 }
208292
209293 /*
@@ -212,19 +296,23 @@ int ceph_encode_encrypted_dname(const struct inode *parent,
212296 *
213297 * See: fscrypt_setup_filename
214298 */
215- if (!fscrypt_fname_encrypted_size (parent , d_name -> len , NAME_MAX , & len ))
216- return - ENAMETOOLONG ;
299+ if (!fscrypt_fname_encrypted_size (dir , iname .len , NAME_MAX , & len )) {
300+ elen = - ENAMETOOLONG ;
301+ goto out ;
302+ }
217303
218304 /* Allocate a buffer appropriate to hold the result */
219305 cryptbuf = kmalloc (len > CEPH_NOHASH_NAME_MAX ? NAME_MAX : len ,
220306 GFP_KERNEL );
221- if (!cryptbuf )
222- return - ENOMEM ;
307+ if (!cryptbuf ) {
308+ elen = - ENOMEM ;
309+ goto out ;
310+ }
223311
224- ret = fscrypt_fname_encrypt (parent , d_name , cryptbuf , len );
312+ ret = fscrypt_fname_encrypt (dir , & iname , cryptbuf , len );
225313 if (ret ) {
226- kfree ( cryptbuf ) ;
227- return ret ;
314+ elen = ret ;
315+ goto out ;
228316 }
229317
230318 /* hash the end if the name is long enough */
@@ -243,13 +331,31 @@ int ceph_encode_encrypted_dname(const struct inode *parent,
243331
244332 /* base64 encode the encrypted name */
245333 elen = ceph_base64_encode (cryptbuf , len , buf );
246- kfree (cryptbuf );
247334 dout ("base64-encoded ciphertext name = %.*s\n" , elen , buf );
335+
336+ /* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */
337+ WARN_ON (elen > 240 );
338+ if ((elen > 0 ) && (dir != parent )) {
339+ char tmp_buf [NAME_MAX ];
340+
341+ elen = snprintf (tmp_buf , sizeof (tmp_buf ), "_%.*s_%ld" ,
342+ elen , buf , dir -> i_ino );
343+ memcpy (buf , tmp_buf , elen );
344+ }
345+
346+ out :
347+ kfree (cryptbuf );
348+ if (dir != parent ) {
349+ if ((dir -> i_state & I_NEW ))
350+ discard_new_inode (dir );
351+ else
352+ iput (dir );
353+ }
248354 return elen ;
249355}
250356
251- int ceph_encode_encrypted_fname (const struct inode * parent ,
252- struct dentry * dentry , char * buf )
357+ int ceph_encode_encrypted_fname (struct inode * parent , struct dentry * dentry ,
358+ char * buf )
253359{
254360 WARN_ON_ONCE (!fscrypt_has_encryption_key (parent ));
255361
@@ -274,37 +380,51 @@ int ceph_encode_encrypted_fname(const struct inode *parent,
274380int ceph_fname_to_usr (const struct ceph_fname * fname , struct fscrypt_str * tname ,
275381 struct fscrypt_str * oname , bool * is_nokey )
276382{
277- int ret ;
383+ struct inode * dir = fname -> dir ;
278384 struct fscrypt_str _tname = FSTR_INIT (NULL , 0 );
279385 struct fscrypt_str iname ;
280-
281- if (!IS_ENCRYPTED (fname -> dir )) {
282- oname -> name = fname -> name ;
283- oname -> len = fname -> name_len ;
284- return 0 ;
285- }
386+ char * name = fname -> name ;
387+ int name_len = fname -> name_len ;
388+ int ret ;
286389
287390 /* Sanity check that the resulting name will fit in the buffer */
288391 if (fname -> name_len > NAME_MAX || fname -> ctext_len > NAME_MAX )
289392 return - EIO ;
290393
291- ret = ceph_fscrypt_prepare_readdir (fname -> dir );
292- if (ret < 0 )
293- return ret ;
394+ /* Handle the special case of snapshot names that start with '_' */
395+ if ((ceph_snap (dir ) == CEPH_SNAPDIR ) && (name_len > 0 ) &&
396+ (name [0 ] == '_' )) {
397+ dir = parse_longname (dir , name , & name_len );
398+ if (IS_ERR (dir ))
399+ return PTR_ERR (dir );
400+ name ++ ; /* skip initial '_' */
401+ }
402+
403+ if (!IS_ENCRYPTED (dir )) {
404+ oname -> name = fname -> name ;
405+ oname -> len = fname -> name_len ;
406+ ret = 0 ;
407+ goto out_inode ;
408+ }
409+
410+ ret = ceph_fscrypt_prepare_readdir (dir );
411+ if (ret )
412+ goto out_inode ;
294413
295414 /*
296415 * Use the raw dentry name as sent by the MDS instead of
297416 * generating a nokey name via fscrypt.
298417 */
299- if (!fscrypt_has_encryption_key (fname -> dir )) {
418+ if (!fscrypt_has_encryption_key (dir )) {
300419 if (fname -> no_copy )
301420 oname -> name = fname -> name ;
302421 else
303422 memcpy (oname -> name , fname -> name , fname -> name_len );
304423 oname -> len = fname -> name_len ;
305424 if (is_nokey )
306425 * is_nokey = true;
307- return 0 ;
426+ ret = 0 ;
427+ goto out_inode ;
308428 }
309429
310430 if (fname -> ctext_len == 0 ) {
@@ -313,12 +433,11 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
313433 if (!tname ) {
314434 ret = fscrypt_fname_alloc_buffer (NAME_MAX , & _tname );
315435 if (ret )
316- return ret ;
436+ goto out_inode ;
317437 tname = & _tname ;
318438 }
319439
320- declen = ceph_base64_decode (fname -> name , fname -> name_len ,
321- tname -> name );
440+ declen = ceph_base64_decode (name , name_len , tname -> name );
322441 if (declen <= 0 ) {
323442 ret = - EIO ;
324443 goto out ;
@@ -330,9 +449,25 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
330449 iname .len = fname -> ctext_len ;
331450 }
332451
333- ret = fscrypt_fname_disk_to_usr (fname -> dir , 0 , 0 , & iname , oname );
452+ ret = fscrypt_fname_disk_to_usr (dir , 0 , 0 , & iname , oname );
453+ if (!ret && (dir != fname -> dir )) {
454+ char tmp_buf [CEPH_BASE64_CHARS (NAME_MAX )];
455+
456+ name_len = snprintf (tmp_buf , sizeof (tmp_buf ), "_%.*s_%ld" ,
457+ oname -> len , oname -> name , dir -> i_ino );
458+ memcpy (oname -> name , tmp_buf , name_len );
459+ oname -> len = name_len ;
460+ }
461+
334462out :
335463 fscrypt_fname_free_buffer (& _tname );
464+ out_inode :
465+ if ((dir != fname -> dir ) && !IS_ERR (dir )) {
466+ if ((dir -> i_state & I_NEW ))
467+ discard_new_inode (dir );
468+ else
469+ iput (dir );
470+ }
336471 return ret ;
337472}
338473
0 commit comments