blob: 57f9817a98081efbb833235c00e7bd8736290dbf [file] [log] [blame]
Thomas Gleixner457c8992019-05-19 13:08:55 +01001// SPDX-License-Identifier: GPL-2.0-only
Paul Gortmaker630d9c42011-11-16 23:57:37 -05002#include <linux/export.h>
Ingo Molnar3f07c012017-02-08 18:51:30 +01003#include <linux/sched/signal.h>
Ingo Molnar29930022017-02-08 18:51:36 +01004#include <linux/sched/task.h>
Al Viro3e93cd62009-03-29 19:00:13 -04005#include <linux/fs.h>
6#include <linux/path.h>
7#include <linux/slab.h>
Al Viro5ad4e532009-03-29 19:50:06 -04008#include <linux/fs_struct.h>
Al Virof03c6592011-01-14 22:30:21 -05009#include "internal.h"
10
Al Viro3e93cd62009-03-29 19:00:13 -040011/*
12 * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
13 * It can block.
14 */
Al Virodcf787f2013-03-01 23:51:07 -050015void set_fs_root(struct fs_struct *fs, const struct path *path)
Al Viro3e93cd62009-03-29 19:00:13 -040016{
17 struct path old_root;
18
Al Virof7a99c52012-06-09 00:59:08 -040019 path_get(path);
Nick Piggin2a4419b2010-08-18 04:37:33 +100020 spin_lock(&fs->lock);
Nick Pigginc28cc362011-01-07 17:49:53 +110021 write_seqcount_begin(&fs->seq);
Al Viro3e93cd62009-03-29 19:00:13 -040022 old_root = fs->root;
23 fs->root = *path;
Nick Pigginc28cc362011-01-07 17:49:53 +110024 write_seqcount_end(&fs->seq);
Nick Piggin2a4419b2010-08-18 04:37:33 +100025 spin_unlock(&fs->lock);
Al Viro3e93cd62009-03-29 19:00:13 -040026 if (old_root.dentry)
Al Virof7a99c52012-06-09 00:59:08 -040027 path_put(&old_root);
Al Viro3e93cd62009-03-29 19:00:13 -040028}
29
30/*
31 * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values.
32 * It can block.
33 */
Al Virodcf787f2013-03-01 23:51:07 -050034void set_fs_pwd(struct fs_struct *fs, const struct path *path)
Al Viro3e93cd62009-03-29 19:00:13 -040035{
36 struct path old_pwd;
37
Al Virof7a99c52012-06-09 00:59:08 -040038 path_get(path);
Nick Piggin2a4419b2010-08-18 04:37:33 +100039 spin_lock(&fs->lock);
Nick Pigginc28cc362011-01-07 17:49:53 +110040 write_seqcount_begin(&fs->seq);
Al Viro3e93cd62009-03-29 19:00:13 -040041 old_pwd = fs->pwd;
42 fs->pwd = *path;
Nick Pigginc28cc362011-01-07 17:49:53 +110043 write_seqcount_end(&fs->seq);
Nick Piggin2a4419b2010-08-18 04:37:33 +100044 spin_unlock(&fs->lock);
Al Viro3e93cd62009-03-29 19:00:13 -040045
46 if (old_pwd.dentry)
Al Virof7a99c52012-06-09 00:59:08 -040047 path_put(&old_pwd);
Al Viro3e93cd62009-03-29 19:00:13 -040048}
Daniel Rosenbergc0dbfed2018-01-30 14:24:02 -080049EXPORT_SYMBOL(set_fs_pwd);
Al Viro3e93cd62009-03-29 19:00:13 -040050
Al Viro82234e62012-03-15 14:48:55 -040051static inline int replace_path(struct path *p, const struct path *old, const struct path *new)
52{
53 if (likely(p->dentry != old->dentry || p->mnt != old->mnt))
54 return 0;
55 *p = *new;
56 return 1;
57}
58
Al Virodcf787f2013-03-01 23:51:07 -050059void chroot_fs_refs(const struct path *old_root, const struct path *new_root)
Al Viro3e93cd62009-03-29 19:00:13 -040060{
61 struct task_struct *g, *p;
62 struct fs_struct *fs;
63 int count = 0;
64
65 read_lock(&tasklist_lock);
66 do_each_thread(g, p) {
67 task_lock(p);
68 fs = p->fs;
69 if (fs) {
Al Viro82234e62012-03-15 14:48:55 -040070 int hits = 0;
Nick Piggin2a4419b2010-08-18 04:37:33 +100071 spin_lock(&fs->lock);
Nick Pigginc28cc362011-01-07 17:49:53 +110072 write_seqcount_begin(&fs->seq);
Al Viro82234e62012-03-15 14:48:55 -040073 hits += replace_path(&fs->root, old_root, new_root);
74 hits += replace_path(&fs->pwd, old_root, new_root);
Nick Pigginc28cc362011-01-07 17:49:53 +110075 write_seqcount_end(&fs->seq);
Al Viro82234e62012-03-15 14:48:55 -040076 while (hits--) {
77 count++;
Al Virof7a99c52012-06-09 00:59:08 -040078 path_get(new_root);
Al Viro82234e62012-03-15 14:48:55 -040079 }
Nick Piggin2a4419b2010-08-18 04:37:33 +100080 spin_unlock(&fs->lock);
Al Viro3e93cd62009-03-29 19:00:13 -040081 }
82 task_unlock(p);
83 } while_each_thread(g, p);
84 read_unlock(&tasklist_lock);
85 while (count--)
Al Virof7a99c52012-06-09 00:59:08 -040086 path_put(old_root);
Al Viro3e93cd62009-03-29 19:00:13 -040087}
88
Al Viro498052b2009-03-30 07:20:30 -040089void free_fs_struct(struct fs_struct *fs)
Al Viro3e93cd62009-03-29 19:00:13 -040090{
Al Virof7a99c52012-06-09 00:59:08 -040091 path_put(&fs->root);
92 path_put(&fs->pwd);
Al Viro498052b2009-03-30 07:20:30 -040093 kmem_cache_free(fs_cachep, fs);
Al Viro3e93cd62009-03-29 19:00:13 -040094}
Daniel Rosenbergc0dbfed2018-01-30 14:24:02 -080095EXPORT_SYMBOL(free_fs_struct);
Al Viro3e93cd62009-03-29 19:00:13 -040096
97void exit_fs(struct task_struct *tsk)
98{
Al Viro498052b2009-03-30 07:20:30 -040099 struct fs_struct *fs = tsk->fs;
Al Viro3e93cd62009-03-29 19:00:13 -0400100
101 if (fs) {
Al Viro498052b2009-03-30 07:20:30 -0400102 int kill;
Al Viro3e93cd62009-03-29 19:00:13 -0400103 task_lock(tsk);
Nick Piggin2a4419b2010-08-18 04:37:33 +1000104 spin_lock(&fs->lock);
Al Viro3e93cd62009-03-29 19:00:13 -0400105 tsk->fs = NULL;
Al Viro498052b2009-03-30 07:20:30 -0400106 kill = !--fs->users;
Nick Piggin2a4419b2010-08-18 04:37:33 +1000107 spin_unlock(&fs->lock);
Al Viro3e93cd62009-03-29 19:00:13 -0400108 task_unlock(tsk);
Al Viro498052b2009-03-30 07:20:30 -0400109 if (kill)
110 free_fs_struct(fs);
Al Viro3e93cd62009-03-29 19:00:13 -0400111 }
112}
113
114struct fs_struct *copy_fs_struct(struct fs_struct *old)
115{
116 struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL);
117 /* We don't need to lock fs - think why ;-) */
118 if (fs) {
Al Viro498052b2009-03-30 07:20:30 -0400119 fs->users = 1;
120 fs->in_exec = 0;
Nick Piggin2a4419b2010-08-18 04:37:33 +1000121 spin_lock_init(&fs->lock);
Nick Pigginc28cc362011-01-07 17:49:53 +1100122 seqcount_init(&fs->seq);
Al Viro3e93cd62009-03-29 19:00:13 -0400123 fs->umask = old->umask;
Nick Pigginb3e19d92011-01-07 17:50:11 +1100124
125 spin_lock(&old->lock);
126 fs->root = old->root;
Al Virof7a99c52012-06-09 00:59:08 -0400127 path_get(&fs->root);
Nick Pigginb3e19d92011-01-07 17:50:11 +1100128 fs->pwd = old->pwd;
Al Virof7a99c52012-06-09 00:59:08 -0400129 path_get(&fs->pwd);
Nick Pigginb3e19d92011-01-07 17:50:11 +1100130 spin_unlock(&old->lock);
Al Viro3e93cd62009-03-29 19:00:13 -0400131 }
132 return fs;
133}
Daniel Rosenbergc0dbfed2018-01-30 14:24:02 -0800134EXPORT_SYMBOL_GPL(copy_fs_struct);
Al Viro3e93cd62009-03-29 19:00:13 -0400135
136int unshare_fs_struct(void)
137{
Al Viro498052b2009-03-30 07:20:30 -0400138 struct fs_struct *fs = current->fs;
139 struct fs_struct *new_fs = copy_fs_struct(fs);
140 int kill;
141
142 if (!new_fs)
Al Viro3e93cd62009-03-29 19:00:13 -0400143 return -ENOMEM;
Al Viro498052b2009-03-30 07:20:30 -0400144
145 task_lock(current);
Nick Piggin2a4419b2010-08-18 04:37:33 +1000146 spin_lock(&fs->lock);
Al Viro498052b2009-03-30 07:20:30 -0400147 kill = !--fs->users;
148 current->fs = new_fs;
Nick Piggin2a4419b2010-08-18 04:37:33 +1000149 spin_unlock(&fs->lock);
Al Viro498052b2009-03-30 07:20:30 -0400150 task_unlock(current);
151
152 if (kill)
153 free_fs_struct(fs);
154
Al Viro3e93cd62009-03-29 19:00:13 -0400155 return 0;
156}
157EXPORT_SYMBOL_GPL(unshare_fs_struct);
158
Al Viroce3b0f82009-03-29 19:08:22 -0400159int current_umask(void)
160{
161 return current->fs->umask;
162}
163EXPORT_SYMBOL(current_umask);
164
Al Viro3e93cd62009-03-29 19:00:13 -0400165/* to be mentioned only in INIT_TASK */
166struct fs_struct init_fs = {
Al Viro498052b2009-03-30 07:20:30 -0400167 .users = 1,
Nick Piggin2a4419b2010-08-18 04:37:33 +1000168 .lock = __SPIN_LOCK_UNLOCKED(init_fs.lock),
John Stultz1ca7d672013-10-07 15:51:59 -0700169 .seq = SEQCNT_ZERO(init_fs.seq),
Al Viro3e93cd62009-03-29 19:00:13 -0400170 .umask = 0022,
171};