LCOV - code coverage report
Current view: top level - fs - fs_struct.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 33 93 35.5 %
Date: 2023-04-06 08:38:28 Functions: 4 8 50.0 %

          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           1 : void set_fs_root(struct fs_struct *fs, const struct path *path)
      16             : {
      17             :         struct path old_root;
      18             : 
      19           1 :         path_get(path);
      20           2 :         spin_lock(&fs->lock);
      21           3 :         write_seqcount_begin(&fs->seq);
      22           1 :         old_root = fs->root;
      23           1 :         fs->root = *path;
      24           2 :         write_seqcount_end(&fs->seq);
      25           2 :         spin_unlock(&fs->lock);
      26           1 :         if (old_root.dentry)
      27           0 :                 path_put(&old_root);
      28           1 : }
      29             : 
      30             : /*
      31             :  * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values.
      32             :  * It can block.
      33             :  */
      34           1 : void set_fs_pwd(struct fs_struct *fs, const struct path *path)
      35             : {
      36             :         struct path old_pwd;
      37             : 
      38           1 :         path_get(path);
      39           2 :         spin_lock(&fs->lock);
      40           3 :         write_seqcount_begin(&fs->seq);
      41           1 :         old_pwd = fs->pwd;
      42           1 :         fs->pwd = *path;
      43           2 :         write_seqcount_end(&fs->seq);
      44           2 :         spin_unlock(&fs->lock);
      45             : 
      46           1 :         if (old_pwd.dentry)
      47           0 :                 path_put(&old_pwd);
      48           1 : }
      49             : 
      50             : static inline int replace_path(struct path *p, const struct path *old, const struct path *new)
      51             : {
      52           0 :         if (likely(p->dentry != old->dentry || p->mnt != old->mnt))
      53             :                 return 0;
      54           0 :         *p = *new;
      55             :         return 1;
      56             : }
      57             : 
      58           0 : void chroot_fs_refs(const struct path *old_root, const struct path *new_root)
      59             : {
      60             :         struct task_struct *g, *p;
      61             :         struct fs_struct *fs;
      62           0 :         int count = 0;
      63             : 
      64           0 :         read_lock(&tasklist_lock);
      65           0 :         do_each_thread(g, p) {
      66           0 :                 task_lock(p);
      67           0 :                 fs = p->fs;
      68           0 :                 if (fs) {
      69           0 :                         int hits = 0;
      70           0 :                         spin_lock(&fs->lock);
      71           0 :                         write_seqcount_begin(&fs->seq);
      72           0 :                         hits += replace_path(&fs->root, old_root, new_root);
      73           0 :                         hits += replace_path(&fs->pwd, old_root, new_root);
      74           0 :                         write_seqcount_end(&fs->seq);
      75           0 :                         while (hits--) {
      76           0 :                                 count++;
      77           0 :                                 path_get(new_root);
      78             :                         }
      79           0 :                         spin_unlock(&fs->lock);
      80             :                 }
      81           0 :                 task_unlock(p);
      82           0 :         } while_each_thread(g, p);
      83           0 :         read_unlock(&tasklist_lock);
      84           0 :         while (count--)
      85           0 :                 path_put(old_root);
      86           0 : }
      87             : 
      88           0 : void free_fs_struct(struct fs_struct *fs)
      89             : {
      90           0 :         path_put(&fs->root);
      91           0 :         path_put(&fs->pwd);
      92           0 :         kmem_cache_free(fs_cachep, fs);
      93           0 : }
      94             : 
      95         333 : void exit_fs(struct task_struct *tsk)
      96             : {
      97         333 :         struct fs_struct *fs = tsk->fs;
      98             : 
      99         333 :         if (fs) {
     100             :                 int kill;
     101         333 :                 task_lock(tsk);
     102         666 :                 spin_lock(&fs->lock);
     103         333 :                 tsk->fs = NULL;
     104         333 :                 kill = !--fs->users;
     105         666 :                 spin_unlock(&fs->lock);
     106         333 :                 task_unlock(tsk);
     107         333 :                 if (kill)
     108           0 :                         free_fs_struct(fs);
     109             :         }
     110         333 : }
     111             : 
     112           0 : struct fs_struct *copy_fs_struct(struct fs_struct *old)
     113             : {
     114           0 :         struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);
     115             :         /* We don't need to lock fs - think why ;-) */
     116           0 :         if (fs) {
     117           0 :                 fs->users = 1;
     118           0 :                 fs->in_exec = 0;
     119           0 :                 spin_lock_init(&fs->lock);
     120           0 :                 seqcount_spinlock_init(&fs->seq, &fs->lock);
     121           0 :                 fs->umask = old->umask;
     122             : 
     123           0 :                 spin_lock(&old->lock);
     124           0 :                 fs->root = old->root;
     125           0 :                 path_get(&fs->root);
     126           0 :                 fs->pwd = old->pwd;
     127           0 :                 path_get(&fs->pwd);
     128           0 :                 spin_unlock(&old->lock);
     129             :         }
     130           0 :         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             :         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           6 : int current_umask(void)
     157             : {
     158           6 :         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