@@ -193,17 +193,101 @@ void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
193
193
swap (req -> r_fscrypt_auth , as -> fscrypt_auth );
194
194
}
195
195
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 )
198
213
{
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 ;
199
268
u32 len ;
269
+ int name_len ;
200
270
int elen ;
201
271
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 ;
203
286
204
- if (!fscrypt_has_encryption_key (parent )) {
287
+ if (!fscrypt_has_encryption_key (dir )) {
205
288
memcpy (buf , d_name -> name , d_name -> len );
206
- return d_name -> len ;
289
+ elen = d_name -> len ;
290
+ goto out ;
207
291
}
208
292
209
293
/*
@@ -212,19 +296,23 @@ int ceph_encode_encrypted_dname(const struct inode *parent,
212
296
*
213
297
* See: fscrypt_setup_filename
214
298
*/
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
+ }
217
303
218
304
/* Allocate a buffer appropriate to hold the result */
219
305
cryptbuf = kmalloc (len > CEPH_NOHASH_NAME_MAX ? NAME_MAX : len ,
220
306
GFP_KERNEL );
221
- if (!cryptbuf )
222
- return - ENOMEM ;
307
+ if (!cryptbuf ) {
308
+ elen = - ENOMEM ;
309
+ goto out ;
310
+ }
223
311
224
- ret = fscrypt_fname_encrypt (parent , d_name , cryptbuf , len );
312
+ ret = fscrypt_fname_encrypt (dir , & iname , cryptbuf , len );
225
313
if (ret ) {
226
- kfree ( cryptbuf ) ;
227
- return ret ;
314
+ elen = ret ;
315
+ goto out ;
228
316
}
229
317
230
318
/* hash the end if the name is long enough */
@@ -243,13 +331,31 @@ int ceph_encode_encrypted_dname(const struct inode *parent,
243
331
244
332
/* base64 encode the encrypted name */
245
333
elen = ceph_base64_encode (cryptbuf , len , buf );
246
- kfree (cryptbuf );
247
334
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
+ }
248
354
return elen ;
249
355
}
250
356
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 )
253
359
{
254
360
WARN_ON_ONCE (!fscrypt_has_encryption_key (parent ));
255
361
@@ -274,37 +380,51 @@ int ceph_encode_encrypted_fname(const struct inode *parent,
274
380
int ceph_fname_to_usr (const struct ceph_fname * fname , struct fscrypt_str * tname ,
275
381
struct fscrypt_str * oname , bool * is_nokey )
276
382
{
277
- int ret ;
383
+ struct inode * dir = fname -> dir ;
278
384
struct fscrypt_str _tname = FSTR_INIT (NULL , 0 );
279
385
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 ;
286
389
287
390
/* Sanity check that the resulting name will fit in the buffer */
288
391
if (fname -> name_len > NAME_MAX || fname -> ctext_len > NAME_MAX )
289
392
return - EIO ;
290
393
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 ;
294
413
295
414
/*
296
415
* Use the raw dentry name as sent by the MDS instead of
297
416
* generating a nokey name via fscrypt.
298
417
*/
299
- if (!fscrypt_has_encryption_key (fname -> dir )) {
418
+ if (!fscrypt_has_encryption_key (dir )) {
300
419
if (fname -> no_copy )
301
420
oname -> name = fname -> name ;
302
421
else
303
422
memcpy (oname -> name , fname -> name , fname -> name_len );
304
423
oname -> len = fname -> name_len ;
305
424
if (is_nokey )
306
425
* is_nokey = true;
307
- return 0 ;
426
+ ret = 0 ;
427
+ goto out_inode ;
308
428
}
309
429
310
430
if (fname -> ctext_len == 0 ) {
@@ -313,12 +433,11 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
313
433
if (!tname ) {
314
434
ret = fscrypt_fname_alloc_buffer (NAME_MAX , & _tname );
315
435
if (ret )
316
- return ret ;
436
+ goto out_inode ;
317
437
tname = & _tname ;
318
438
}
319
439
320
- declen = ceph_base64_decode (fname -> name , fname -> name_len ,
321
- tname -> name );
440
+ declen = ceph_base64_decode (name , name_len , tname -> name );
322
441
if (declen <= 0 ) {
323
442
ret = - EIO ;
324
443
goto out ;
@@ -330,9 +449,25 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
330
449
iname .len = fname -> ctext_len ;
331
450
}
332
451
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
+
334
462
out :
335
463
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
+ }
336
471
return ret ;
337
472
}
338
473
0 commit comments