~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/fhandle.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /fs/fhandle.c (Version linux-6.12-rc7) and /fs/fhandle.c (Version linux-5.15.169)


** Warning: Cannot open xref database.

  1 // SPDX-License-Identifier: GPL-2.0                 1 
  2 #include <linux/syscalls.h>                       
  3 #include <linux/slab.h>                           
  4 #include <linux/fs.h>                             
  5 #include <linux/file.h>                           
  6 #include <linux/mount.h>                          
  7 #include <linux/namei.h>                          
  8 #include <linux/exportfs.h>                       
  9 #include <linux/fs_struct.h>                      
 10 #include <linux/fsnotify.h>                       
 11 #include <linux/personality.h>                    
 12 #include <linux/uaccess.h>                        
 13 #include <linux/compat.h>                         
 14 #include "internal.h"                             
 15 #include "mount.h"                                
 16                                                   
 17 static long do_sys_name_to_handle(const struct    
 18                                   struct file_    
 19                                   void __user     
 20                                   int fh_flags    
 21 {                                                 
 22         long retval;                              
 23         struct file_handle f_handle;              
 24         int handle_dwords, handle_bytes;          
 25         struct file_handle *handle = NULL;        
 26                                                   
 27         /*                                        
 28          * We need to make sure whether the fi    
 29          * the file handle if decodeable file     
 30          */                                       
 31         if (!exportfs_can_encode_fh(path->dent    
 32                 return -EOPNOTSUPP;               
 33                                                   
 34         if (copy_from_user(&f_handle, ufh, siz    
 35                 return -EFAULT;                   
 36                                                   
 37         if (f_handle.handle_bytes > MAX_HANDLE    
 38                 return -EINVAL;                   
 39                                                   
 40         handle = kzalloc(struct_size(handle, f    
 41                          GFP_KERNEL);             
 42         if (!handle)                              
 43                 return -ENOMEM;                   
 44                                                   
 45         /* convert handle size to multiple of     
 46         handle_dwords = f_handle.handle_bytes     
 47                                                   
 48         /* we ask for a non connectable maybe     
 49         retval = exportfs_encode_fh(path->dent    
 50                                     (struct fi    
 51                                     &handle_dw    
 52         handle->handle_type = retval;             
 53         /* convert handle size to bytes */        
 54         handle_bytes = handle_dwords * sizeof(    
 55         handle->handle_bytes = handle_bytes;      
 56         if ((handle->handle_bytes > f_handle.h    
 57             (retval == FILEID_INVALID) || (ret    
 58                 /* As per old exportfs_encode_    
 59                  * we could return ENOSPC to i    
 60                  * But file system returned 25    
 61                  * both the values                
 62                  */                               
 63                 if (retval == FILEID_INVALID |    
 64                         retval = -EOVERFLOW;      
 65                 /*                                
 66                  * set the handle size to zero    
 67                  * non variable part of the fi    
 68                  */                               
 69                 handle_bytes = 0;                 
 70         } else                                    
 71                 retval = 0;                       
 72         /* copy the mount id */                   
 73         if (unique_mntid) {                       
 74                 if (put_user(real_mount(path->    
 75                              (u64 __user *) mn    
 76                         retval = -EFAULT;         
 77         } else {                                  
 78                 if (put_user(real_mount(path->    
 79                              (int __user *) mn    
 80                         retval = -EFAULT;         
 81         }                                         
 82         /* copy the handle */                     
 83         if (retval != -EFAULT &&                  
 84                 copy_to_user(ufh, handle,         
 85                              struct_size(handl    
 86                 retval = -EFAULT;                 
 87         kfree(handle);                            
 88         return retval;                            
 89 }                                                 
 90                                                   
 91 /**                                               
 92  * sys_name_to_handle_at: convert name to hand    
 93  * @dfd: directory relative to which name is i    
 94  * @name: name that should be converted to han    
 95  * @handle: resulting file handle                 
 96  * @mnt_id: mount id of the file system contai    
 97  *          (u64 if AT_HANDLE_MNT_ID_UNIQUE, o    
 98  * @flag: flag value to indicate whether to fo    
 99  *        and whether a decodable file handle     
100  *                                                
101  * @handle->handle_size indicate the space ava    
102  * variable part of the file handle in bytes.     
103  * enough space, the field is updated to retur    
104  * value required.                                
105  */                                               
106 SYSCALL_DEFINE5(name_to_handle_at, int, dfd, c    
107                 struct file_handle __user *, h    
108                 int, flag)                        
109 {                                                 
110         struct path path;                         
111         int lookup_flags;                         
112         int fh_flags;                             
113         int err;                                  
114                                                   
115         if (flag & ~(AT_SYMLINK_FOLLOW | AT_EM    
116                      AT_HANDLE_MNT_ID_UNIQUE))    
117                 return -EINVAL;                   
118                                                   
119         lookup_flags = (flag & AT_SYMLINK_FOLL    
120         fh_flags = (flag & AT_HANDLE_FID) ? EX    
121         if (flag & AT_EMPTY_PATH)                 
122                 lookup_flags |= LOOKUP_EMPTY;     
123         err = user_path_at(dfd, name, lookup_f    
124         if (!err) {                               
125                 err = do_sys_name_to_handle(&p    
126                                             fl    
127                                             fh    
128                 path_put(&path);                  
129         }                                         
130         return err;                               
131 }                                                 
132                                                   
133 static int get_path_from_fd(int fd, struct pat    
134 {                                                 
135         if (fd == AT_FDCWD) {                     
136                 struct fs_struct *fs = current    
137                 spin_lock(&fs->lock);             
138                 *root = fs->pwd;                  
139                 path_get(root);                   
140                 spin_unlock(&fs->lock);           
141         } else {                                  
142                 struct fd f = fdget(fd);          
143                 if (!fd_file(f))                  
144                         return -EBADF;            
145                 *root = fd_file(f)->f_path;       
146                 path_get(root);                   
147                 fdput(f);                         
148         }                                         
149                                                   
150         return 0;                                 
151 }                                                 
152                                                   
153 enum handle_to_path_flags {                       
154         HANDLE_CHECK_PERMS   = (1 << 0),          
155         HANDLE_CHECK_SUBTREE = (1 << 1),          
156 };                                                
157                                                   
158 struct handle_to_path_ctx {                       
159         struct path root;                         
160         enum handle_to_path_flags flags;          
161         unsigned int fh_flags;                    
162 };                                                
163                                                   
164 static int vfs_dentry_acceptable(void *context    
165 {                                                 
166         struct handle_to_path_ctx *ctx = conte    
167         struct user_namespace *user_ns = curre    
168         struct dentry *d, *root = ctx->root.de    
169         struct mnt_idmap *idmap = mnt_idmap(ct    
170         int retval = 0;                           
171                                                   
172         if (!root)                                
173                 return 1;                         
174                                                   
175         /* Old permission model with global CA    
176         if (!ctx->flags)                          
177                 return 1;                         
178                                                   
179         /*                                        
180          * It's racy as we're not taking renam    
181          * permissions and we just need an app    
182          * to follow a path to the file.          
183          *                                        
184          * It's also potentially expensive on     
185          * there is a deep path.                  
186          */                                       
187         d = dget(dentry);                         
188         while (d != root && !IS_ROOT(d)) {        
189                 struct dentry *parent = dget_p    
190                                                   
191                 /*                                
192                  * We know that we have the ab    
193                  * as we've verified this earl    
194                  * we also need to make sure t    
195                  * inodes in the path that wou    
196                  * file.                          
197                  */                               
198                 if (!privileged_wrt_inode_uidg    
199                                                   
200                         dput(d);                  
201                         dput(parent);             
202                         return retval;            
203                 }                                 
204                                                   
205                 dput(d);                          
206                 d = parent;                       
207         }                                         
208                                                   
209         if (!(ctx->flags & HANDLE_CHECK_SUBTRE    
210                 retval = 1;                       
211         WARN_ON_ONCE(d != root && d != root->d    
212         dput(d);                                  
213         return retval;                            
214 }                                                 
215                                                   
216 static int do_handle_to_path(struct file_handl    
217                              struct handle_to_    
218 {                                                 
219         int handle_dwords;                        
220         struct vfsmount *mnt = ctx->root.mnt;     
221                                                   
222         /* change the handle size to multiple     
223         handle_dwords = handle->handle_bytes >    
224         path->dentry = exportfs_decode_fh_raw(    
225                                           (str    
226                                           hand    
227                                           ctx-    
228                                           vfs_    
229         if (IS_ERR_OR_NULL(path->dentry)) {       
230                 if (path->dentry == ERR_PTR(-E    
231                         return -ENOMEM;           
232                 return -ESTALE;                   
233         }                                         
234         path->mnt = mntget(mnt);                  
235         return 0;                                 
236 }                                                 
237                                                   
238 /*                                                
239  * Allow relaxed permissions of file handles i    
240  * ability to mount the filesystem or create a    
241  * provided @mountdirfd.                          
242  *                                                
243  * In both cases the caller may be able to get    
244  * the encoded file handle. If the caller is o    
245  * bind-mount we need to verify that there are    
246  * of it that could prevent us from getting to    
247  *                                                
248  * In principle, locked mounts can prevent the    
249  * filesystem but that only applies to procfs     
250  * support decoding file handles.                 
251  */                                               
252 static inline bool may_decode_fh(struct handle    
253                                  unsigned int     
254 {                                                 
255         struct path *root = &ctx->root;           
256                                                   
257         /*                                        
258          * Restrict to O_DIRECTORY to provide     
259          * confusing api in the face of discon    
260          *                                        
261          * There's only one dentry for each di    
262          */                                       
263         if (!(o_flags & O_DIRECTORY))             
264                 return false;                     
265                                                   
266         if (ns_capable(root->mnt->mnt_sb->s_us    
267                 ctx->flags = HANDLE_CHECK_PERM    
268         else if (is_mounted(root->mnt) &&         
269                  ns_capable(real_mount(root->m    
270                             CAP_SYS_ADMIN) &&     
271                  !has_locked_children(real_mou    
272                 ctx->flags = HANDLE_CHECK_PERM    
273         else                                      
274                 return false;                     
275                                                   
276         /* Are we able to override DAC permiss    
277         if (!ns_capable(current_user_ns(), CAP    
278                 return false;                     
279                                                   
280         ctx->fh_flags = EXPORT_FH_DIR_ONLY;       
281         return true;                              
282 }                                                 
283                                                   
284 static int handle_to_path(int mountdirfd, stru    
285                    struct path *path, unsigned    
286 {                                                 
287         int retval = 0;                           
288         struct file_handle f_handle;              
289         struct file_handle *handle = NULL;        
290         struct handle_to_path_ctx ctx = {};       
291                                                   
292         retval = get_path_from_fd(mountdirfd,     
293         if (retval)                               
294                 goto out_err;                     
295                                                   
296         if (!capable(CAP_DAC_READ_SEARCH) && !    
297                 retval = -EPERM;                  
298                 goto out_path;                    
299         }                                         
300                                                   
301         if (copy_from_user(&f_handle, ufh, siz    
302                 retval = -EFAULT;                 
303                 goto out_path;                    
304         }                                         
305         if ((f_handle.handle_bytes > MAX_HANDL    
306             (f_handle.handle_bytes == 0)) {       
307                 retval = -EINVAL;                 
308                 goto out_path;                    
309         }                                         
310         handle = kmalloc(struct_size(handle, f    
311                          GFP_KERNEL);             
312         if (!handle) {                            
313                 retval = -ENOMEM;                 
314                 goto out_path;                    
315         }                                         
316         /* copy the full handle */                
317         *handle = f_handle;                       
318         if (copy_from_user(&handle->f_handle,     
319                            &ufh->f_handle,        
320                            f_handle.handle_byt    
321                 retval = -EFAULT;                 
322                 goto out_handle;                  
323         }                                         
324                                                   
325         retval = do_handle_to_path(handle, pat    
326                                                   
327 out_handle:                                       
328         kfree(handle);                            
329 out_path:                                         
330         path_put(&ctx.root);                      
331 out_err:                                          
332         return retval;                            
333 }                                                 
334                                                   
335 static long do_handle_open(int mountdirfd, str    
336                            int open_flag)         
337 {                                                 
338         long retval = 0;                          
339         struct path path;                         
340         struct file *file;                        
341         int fd;                                   
342                                                   
343         retval = handle_to_path(mountdirfd, uf    
344         if (retval)                               
345                 return retval;                    
346                                                   
347         fd = get_unused_fd_flags(open_flag);      
348         if (fd < 0) {                             
349                 path_put(&path);                  
350                 return fd;                        
351         }                                         
352         file = file_open_root(&path, "", open_    
353         if (IS_ERR(file)) {                       
354                 put_unused_fd(fd);                
355                 retval =  PTR_ERR(file);          
356         } else {                                  
357                 retval = fd;                      
358                 fd_install(fd, file);             
359         }                                         
360         path_put(&path);                          
361         return retval;                            
362 }                                                 
363                                                   
364 /**                                               
365  * sys_open_by_handle_at: Open the file handle    
366  * @mountdirfd: directory file descriptor         
367  * @handle: file handle to be opened              
368  * @flags: open flags.                            
369  *                                                
370  * @mountdirfd indicate the directory file des    
371  * of the mount point. file handle is decoded     
372  * to the vfsmount pointed by the @mountdirfd.    
373  * value is same as the open(2) flags.            
374  */                                               
375 SYSCALL_DEFINE3(open_by_handle_at, int, mountd    
376                 struct file_handle __user *, h    
377                 int, flags)                       
378 {                                                 
379         long ret;                                 
380                                                   
381         if (force_o_largefile())                  
382                 flags |= O_LARGEFILE;             
383                                                   
384         ret = do_handle_open(mountdirfd, handl    
385         return ret;                               
386 }                                                 
387                                                   
388 #ifdef CONFIG_COMPAT                              
389 /*                                                
390  * Exactly like fs/open.c:sys_open_by_handle_a    
391  * doesn't set the O_LARGEFILE flag.              
392  */                                               
393 COMPAT_SYSCALL_DEFINE3(open_by_handle_at, int,    
394                              struct file_handl    
395 {                                                 
396         return do_handle_open(mountdirfd, hand    
397 }                                                 
398 #endif                                            
399                                                   

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php