LCOV - code coverage report
Current view: top level - fs - fs_struct.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 88 101 87.1 %
Date: 2021-04-22 12:43:58 Functions: 7 8 87.5 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : #include <linux/export.h>
       3             : #include <linux/sched/signal.h>
       4             : #include <linux/sched/task.h>
       5             : #include <linux/fs.h>
       6             : #include <linux/path.h>
       7             : #include <linux/slab.h>
       8             : #include <linux/fs_struct.h>
       9             : #include "internal.h"
      10             : 
      11             : /*
      12             :  * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
      13             :  * It can block.
      14             :  */
      15          12 : void set_fs_root(struct fs_struct *fs, const struct path *path)
      16             : {
      17          12 :         struct path old_root;
      18             : 
      19          12 :         path_get(path);
      20          12 :         spin_lock(&fs->lock);
      21          24 :         write_seqcount_begin(&fs->seq);
      22          12 :         old_root = fs->root;
      23          12 :         fs->root = *path;
      24          12 :         write_seqcount_end(&fs->seq);
      25          12 :         spin_unlock(&fs->lock);
      26          12 :         if (old_root.dentry)
      27          11 :                 path_put(&old_root);
      28          12 : }
      29             : 
      30             : /*
      31             :  * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values.
      32             :  * It can block.
      33             :  */
      34        1735 : void set_fs_pwd(struct fs_struct *fs, const struct path *path)
      35             : {
      36        1735 :         struct path old_pwd;
      37             : 
      38        1735 :         path_get(path);
      39        1735 :         spin_lock(&fs->lock);
      40        3470 :         write_seqcount_begin(&fs->seq);
      41        1735 :         old_pwd = fs->pwd;
      42        1735 :         fs->pwd = *path;
      43        1735 :         write_seqcount_end(&fs->seq);
      44        1735 :         spin_unlock(&fs->lock);
      45             : 
      46        1735 :         if (old_pwd.dentry)
      47        1734 :                 path_put(&old_pwd);
      48        1735 : }
      49             : 
      50         174 : static inline int replace_path(struct path *p, const struct path *old, const struct path *new)
      51             : {
      52         155 :         if (likely(p->dentry != old->dentry || p->mnt != old->mnt))
      53             :                 return 0;
      54           2 :         *p = *new;
      55           2 :         return 1;
      56             : }
      57             : 
      58           1 : void chroot_fs_refs(const struct path *old_root, const struct path *new_root)
      59             : {
      60           1 :         struct task_struct *g, *p;
      61           1 :         struct fs_struct *fs;
      62           1 :         int count = 0;
      63             : 
      64           1 :         read_lock(&tasklist_lock);
      65          85 :         do_each_thread(g, p) {
      66          87 :                 task_lock(p);
      67          87 :                 fs = p->fs;
      68          87 :                 if (fs) {
      69          87 :                         int hits = 0;
      70          87 :                         spin_lock(&fs->lock);
      71         174 :                         write_seqcount_begin(&fs->seq);
      72          87 :                         hits += replace_path(&fs->root, old_root, new_root);
      73          87 :                         hits += replace_path(&fs->pwd, old_root, new_root);
      74          87 :                         write_seqcount_end(&fs->seq);
      75          89 :                         while (hits--) {
      76           2 :                                 count++;
      77           2 :                                 path_get(new_root);
      78             :                         }
      79          87 :                         spin_unlock(&fs->lock);
      80             :                 }
      81          87 :                 task_unlock(p);
      82          87 :         } while_each_thread(g, p);
      83           1 :         read_unlock(&tasklist_lock);
      84           3 :         while (count--)
      85           2 :                 path_put(old_root);
      86           1 : }
      87             : 
      88        1355 : void free_fs_struct(struct fs_struct *fs)
      89             : {
      90        1355 :         path_put(&fs->root);
      91        1355 :         path_put(&fs->pwd);
      92        1355 :         kmem_cache_free(fs_cachep, fs);
      93        1355 : }
      94             : 
      95        1357 : void exit_fs(struct task_struct *tsk)
      96             : {
      97        1357 :         struct fs_struct *fs = tsk->fs;
      98             : 
      99        1357 :         if (fs) {
     100        1357 :                 int kill;
     101        1357 :                 task_lock(tsk);
     102        1357 :                 spin_lock(&fs->lock);
     103        1357 :                 tsk->fs = NULL;
     104        1357 :                 kill = !--fs->users;
     105        1357 :                 spin_unlock(&fs->lock);
     106        1357 :                 task_unlock(tsk);
     107        1357 :                 if (kill)
     108        1355 :                         free_fs_struct(fs);
     109             :         }
     110        1357 : }
     111             : 
     112        1379 : struct fs_struct *copy_fs_struct(struct fs_struct *old)
     113             : {
     114        1379 :         struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);
     115             :         /* We don't need to lock fs - think why ;-) */
     116        1379 :         if (fs) {
     117        1379 :                 fs->users = 1;
     118        1379 :                 fs->in_exec = 0;
     119        1379 :                 spin_lock_init(&fs->lock);
     120        1379 :                 seqcount_spinlock_init(&fs->seq, &fs->lock);
     121        1379 :                 fs->umask = old->umask;
     122             : 
     123        1379 :                 spin_lock(&old->lock);
     124        1379 :                 fs->root = old->root;
     125        1379 :                 path_get(&fs->root);
     126        1379 :                 fs->pwd = old->pwd;
     127        1379 :                 path_get(&fs->pwd);
     128        1379 :                 spin_unlock(&old->lock);
     129             :         }
     130        1379 :         return fs;
     131             : }
     132             : 
     133           0 : int unshare_fs_struct(void)
     134             : {
     135           0 :         struct fs_struct *fs = current->fs;
     136           0 :         struct fs_struct *new_fs = copy_fs_struct(fs);
     137           0 :         int kill;
     138             : 
     139           0 :         if (!new_fs)
     140             :                 return -ENOMEM;
     141             : 
     142           0 :         task_lock(current);
     143           0 :         spin_lock(&fs->lock);
     144           0 :         kill = !--fs->users;
     145           0 :         current->fs = new_fs;
     146           0 :         spin_unlock(&fs->lock);
     147           0 :         task_unlock(current);
     148             : 
     149           0 :         if (kill)
     150           0 :                 free_fs_struct(fs);
     151             : 
     152             :         return 0;
     153             : }
     154             : EXPORT_SYMBOL_GPL(unshare_fs_struct);
     155             : 
     156        1977 : int current_umask(void)
     157             : {
     158        1977 :         return current->fs->umask;
     159             : }
     160             : EXPORT_SYMBOL(current_umask);
     161             : 
     162             : /* to be mentioned only in INIT_TASK */
     163             : struct fs_struct init_fs = {
     164             :         .users          = 1,
     165             :         .lock           = __SPIN_LOCK_UNLOCKED(init_fs.lock),
     166             :         .seq            = SEQCNT_SPINLOCK_ZERO(init_fs.seq, &init_fs.lock),
     167             :         .umask          = 0022,
     168             : };

Generated by: LCOV version 1.14