@@ -187,17 +187,6 @@ static int get_path_from_fd(int fd, struct path *root)
187187 return 0 ;
188188}
189189
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-
201190static int vfs_dentry_acceptable (void * context , struct dentry * dentry )
202191{
203192 struct handle_to_path_ctx * ctx = context ;
@@ -261,50 +250,55 @@ static int do_handle_to_path(struct file_handle *handle, struct path *path,
261250{
262251 int handle_dwords ;
263252 struct vfsmount * mnt = ctx -> root .mnt ;
253+ struct dentry * dentry ;
264254
265255 /* change the handle size to multiple of sizeof(u32) */
266256 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 ))
274263 return - ENOMEM ;
275264 return - ESTALE ;
276265 }
266+ path -> dentry = dentry ;
277267 path -> mnt = mntget (mnt );
278268 return 0 ;
279269}
280270
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 )
297273{
298274 struct path * root = & ctx -> root ;
299275
276+ if (capable (CAP_DAC_READ_SEARCH ))
277+ return 0 ;
278+
300279 /*
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.
303297 *
304298 * There's only one dentry for each directory inode (VFS rule)...
305299 */
306300 if (!(o_flags & O_DIRECTORY ))
307- return false ;
301+ return - EPERM ;
308302
309303 if (ns_capable (root -> mnt -> mnt_sb -> s_user_ns , CAP_SYS_ADMIN ))
310304 ctx -> flags = HANDLE_CHECK_PERMS ;
@@ -314,14 +308,14 @@ static inline bool may_decode_fh(struct handle_to_path_ctx *ctx,
314308 !has_locked_children (real_mount (root -> mnt ), root -> dentry ))
315309 ctx -> flags = HANDLE_CHECK_PERMS | HANDLE_CHECK_SUBTREE ;
316310 else
317- return false ;
311+ return - EPERM ;
318312
319313 /* Are we able to override DAC permissions? */
320314 if (!ns_capable (current_user_ns (), CAP_DAC_READ_SEARCH ))
321- return false ;
315+ return - EPERM ;
322316
323317 ctx -> fh_flags = EXPORT_FH_DIR_ONLY ;
324- return true ;
318+ return 0 ;
325319}
326320
327321static 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,
331325 struct file_handle f_handle ;
332326 struct file_handle * handle = NULL ;
333327 struct handle_to_path_ctx ctx = {};
328+ const struct export_operations * eops ;
334329
335330 retval = get_path_from_fd (mountdirfd , & ctx .root );
336331 if (retval )
337332 goto out_err ;
338333
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 )
341340 goto out_path ;
342- }
343341
344342 if (copy_from_user (& f_handle , ufh , sizeof (struct file_handle ))) {
345343 retval = - EFAULT ;
@@ -398,29 +396,28 @@ static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
398396 int open_flag )
399397{
400398 long retval = 0 ;
401- struct path path ;
399+ struct path path __free ( path_put ) = {} ;
402400 struct file * file ;
403- int fd ;
401+ const struct export_operations * eops ;
404402
405403 retval = handle_to_path (mountdirfd , ufh , & path , open_flag );
406404 if (retval )
407405 return retval ;
408406
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 )
412409 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 ) ;
424421}
425422
426423/**
0 commit comments