@@ -187,17 +187,6 @@ static int get_path_from_fd(int fd, struct path *root)
187
187
return 0 ;
188
188
}
189
189
190
- enum handle_to_path_flags {
191
- HANDLE_CHECK_PERMS = (1 << 0 ),
192
- HANDLE_CHECK_SUBTREE = (1 << 1 ),
193
- };
194
-
195
- struct handle_to_path_ctx {
196
- struct path root ;
197
- enum handle_to_path_flags flags ;
198
- unsigned int fh_flags ;
199
- };
200
-
201
190
static int vfs_dentry_acceptable (void * context , struct dentry * dentry )
202
191
{
203
192
struct handle_to_path_ctx * ctx = context ;
@@ -261,50 +250,55 @@ static int do_handle_to_path(struct file_handle *handle, struct path *path,
261
250
{
262
251
int handle_dwords ;
263
252
struct vfsmount * mnt = ctx -> root .mnt ;
253
+ struct dentry * dentry ;
264
254
265
255
/* change the handle size to multiple of sizeof(u32) */
266
256
handle_dwords = handle -> handle_bytes >> 2 ;
267
- path -> dentry = exportfs_decode_fh_raw (mnt ,
268
- (struct fid * )handle -> f_handle ,
269
- handle_dwords , handle -> handle_type ,
270
- ctx -> fh_flags ,
271
- vfs_dentry_acceptable , ctx );
272
- if (IS_ERR_OR_NULL (path -> dentry )) {
273
- if (path -> dentry == ERR_PTR (- ENOMEM ))
257
+ dentry = exportfs_decode_fh_raw (mnt , (struct fid * )handle -> f_handle ,
258
+ handle_dwords , handle -> handle_type ,
259
+ ctx -> fh_flags , vfs_dentry_acceptable ,
260
+ ctx );
261
+ if (IS_ERR_OR_NULL (dentry )) {
262
+ if (dentry == ERR_PTR (- ENOMEM ))
274
263
return - ENOMEM ;
275
264
return - ESTALE ;
276
265
}
266
+ path -> dentry = dentry ;
277
267
path -> mnt = mntget (mnt );
278
268
return 0 ;
279
269
}
280
270
281
- /*
282
- * Allow relaxed permissions of file handles if the caller has the
283
- * ability to mount the filesystem or create a bind-mount of the
284
- * provided @mountdirfd.
285
- *
286
- * In both cases the caller may be able to get an unobstructed way to
287
- * the encoded file handle. If the caller is only able to create a
288
- * bind-mount we need to verify that there are no locked mounts on top
289
- * of it that could prevent us from getting to the encoded file.
290
- *
291
- * In principle, locked mounts can prevent the caller from mounting the
292
- * filesystem but that only applies to procfs and sysfs neither of which
293
- * support decoding file handles.
294
- */
295
- static inline bool may_decode_fh (struct handle_to_path_ctx * ctx ,
296
- unsigned int o_flags )
271
+ static inline int may_decode_fh (struct handle_to_path_ctx * ctx ,
272
+ unsigned int o_flags )
297
273
{
298
274
struct path * root = & ctx -> root ;
299
275
276
+ if (capable (CAP_DAC_READ_SEARCH ))
277
+ return 0 ;
278
+
300
279
/*
301
- * Restrict to O_DIRECTORY to provide a deterministic API that avoids a
302
- * confusing api in the face of disconnected non-dir dentries.
280
+ * Allow relaxed permissions of file handles if the caller has
281
+ * the ability to mount the filesystem or create a bind-mount of
282
+ * the provided @mountdirfd.
283
+ *
284
+ * In both cases the caller may be able to get an unobstructed
285
+ * way to the encoded file handle. If the caller is only able to
286
+ * create a bind-mount we need to verify that there are no
287
+ * locked mounts on top of it that could prevent us from getting
288
+ * to the encoded file.
289
+ *
290
+ * In principle, locked mounts can prevent the caller from
291
+ * mounting the filesystem but that only applies to procfs and
292
+ * sysfs neither of which support decoding file handles.
293
+ *
294
+ * Restrict to O_DIRECTORY to provide a deterministic API that
295
+ * avoids a confusing api in the face of disconnected non-dir
296
+ * dentries.
303
297
*
304
298
* There's only one dentry for each directory inode (VFS rule)...
305
299
*/
306
300
if (!(o_flags & O_DIRECTORY ))
307
- return false ;
301
+ return - EPERM ;
308
302
309
303
if (ns_capable (root -> mnt -> mnt_sb -> s_user_ns , CAP_SYS_ADMIN ))
310
304
ctx -> flags = HANDLE_CHECK_PERMS ;
@@ -314,14 +308,14 @@ static inline bool may_decode_fh(struct handle_to_path_ctx *ctx,
314
308
!has_locked_children (real_mount (root -> mnt ), root -> dentry ))
315
309
ctx -> flags = HANDLE_CHECK_PERMS | HANDLE_CHECK_SUBTREE ;
316
310
else
317
- return false ;
311
+ return - EPERM ;
318
312
319
313
/* Are we able to override DAC permissions? */
320
314
if (!ns_capable (current_user_ns (), CAP_DAC_READ_SEARCH ))
321
- return false ;
315
+ return - EPERM ;
322
316
323
317
ctx -> fh_flags = EXPORT_FH_DIR_ONLY ;
324
- return true ;
318
+ return 0 ;
325
319
}
326
320
327
321
static int handle_to_path (int mountdirfd , struct file_handle __user * ufh ,
@@ -331,15 +325,19 @@ static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
331
325
struct file_handle f_handle ;
332
326
struct file_handle * handle = NULL ;
333
327
struct handle_to_path_ctx ctx = {};
328
+ const struct export_operations * eops ;
334
329
335
330
retval = get_path_from_fd (mountdirfd , & ctx .root );
336
331
if (retval )
337
332
goto out_err ;
338
333
339
- if (!capable (CAP_DAC_READ_SEARCH ) && !may_decode_fh (& ctx , o_flags )) {
340
- retval = - EPERM ;
334
+ eops = ctx .root .mnt -> mnt_sb -> s_export_op ;
335
+ if (eops && eops -> permission )
336
+ retval = eops -> permission (& ctx , o_flags );
337
+ else
338
+ retval = may_decode_fh (& ctx , o_flags );
339
+ if (retval )
341
340
goto out_path ;
342
- }
343
341
344
342
if (copy_from_user (& f_handle , ufh , sizeof (struct file_handle ))) {
345
343
retval = - EFAULT ;
@@ -398,29 +396,28 @@ static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
398
396
int open_flag )
399
397
{
400
398
long retval = 0 ;
401
- struct path path ;
399
+ struct path path __free ( path_put ) = {} ;
402
400
struct file * file ;
403
- int fd ;
401
+ const struct export_operations * eops ;
404
402
405
403
retval = handle_to_path (mountdirfd , ufh , & path , open_flag );
406
404
if (retval )
407
405
return retval ;
408
406
409
- fd = get_unused_fd_flags (open_flag );
410
- if (fd < 0 ) {
411
- path_put (& path );
407
+ CLASS (get_unused_fd , fd )(O_CLOEXEC );
408
+ if (fd < 0 )
412
409
return fd ;
413
- }
414
- file = file_open_root ( & path , "" , open_flag , 0 ) ;
415
- if (IS_ERR ( file )) {
416
- put_unused_fd ( fd );
417
- retval = PTR_ERR ( file );
418
- } else {
419
- retval = fd ;
420
- fd_install ( fd , file );
421
- }
422
- path_put ( & path );
423
- return retval ;
410
+
411
+ eops = path . mnt -> mnt_sb -> s_export_op ;
412
+ if (eops -> open )
413
+ file = eops -> open ( & path , open_flag );
414
+ else
415
+ file = file_open_root ( & path , "" , open_flag , 0 );
416
+ if ( IS_ERR ( file ))
417
+ return PTR_ERR ( file );
418
+
419
+ fd_install ( fd , file );
420
+ return take_fd ( fd ) ;
424
421
}
425
422
426
423
/**
0 commit comments