]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - fs/aufs/rdu.c
UBUNTU: SAUCE: AUFS
[mirror_ubuntu-jammy-kernel.git] / fs / aufs / rdu.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2005-2021 Junjiro R. Okajima
4 *
5 * This program, aufs is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * readdir in userspace.
21 */
22
23 #include <linux/compat.h>
24 #include <linux/fs_stack.h>
25 #include <linux/security.h>
26 #include "aufs.h"
27
28 /* bits for struct aufs_rdu.flags */
29 #define AuRdu_CALLED 1
30 #define AuRdu_CONT (1 << 1)
31 #define AuRdu_FULL (1 << 2)
32 #define au_ftest_rdu(flags, name) ((flags) & AuRdu_##name)
33 #define au_fset_rdu(flags, name) \
34 do { (flags) |= AuRdu_##name; } while (0)
35 #define au_fclr_rdu(flags, name) \
36 do { (flags) &= ~AuRdu_##name; } while (0)
37
38 struct au_rdu_arg {
39 struct dir_context ctx;
40 struct aufs_rdu *rdu;
41 union au_rdu_ent_ul ent;
42 unsigned long end;
43
44 struct super_block *sb;
45 int err;
46 };
47
48 static int au_rdu_fill(struct dir_context *ctx, const char *name, int nlen,
49 loff_t offset, u64 h_ino, unsigned int d_type)
50 {
51 int err, len;
52 struct au_rdu_arg *arg = container_of(ctx, struct au_rdu_arg, ctx);
53 struct aufs_rdu *rdu = arg->rdu;
54 struct au_rdu_ent ent;
55
56 err = 0;
57 arg->err = 0;
58 au_fset_rdu(rdu->cookie.flags, CALLED);
59 len = au_rdu_len(nlen);
60 if (arg->ent.ul + len < arg->end) {
61 ent.ino = h_ino;
62 ent.bindex = rdu->cookie.bindex;
63 ent.type = d_type;
64 ent.nlen = nlen;
65 if (unlikely(nlen > AUFS_MAX_NAMELEN))
66 ent.type = DT_UNKNOWN;
67
68 /* unnecessary to support mmap_sem since this is a dir */
69 err = -EFAULT;
70 if (copy_to_user(arg->ent.e, &ent, sizeof(ent)))
71 goto out;
72 if (copy_to_user(arg->ent.e->name, name, nlen))
73 goto out;
74 /* the terminating NULL */
75 if (__put_user(0, arg->ent.e->name + nlen))
76 goto out;
77 err = 0;
78 /* AuDbg("%p, %.*s\n", arg->ent.p, nlen, name); */
79 arg->ent.ul += len;
80 rdu->rent++;
81 } else {
82 err = -EFAULT;
83 au_fset_rdu(rdu->cookie.flags, FULL);
84 rdu->full = 1;
85 rdu->tail = arg->ent;
86 }
87
88 out:
89 /* AuTraceErr(err); */
90 return err;
91 }
92
93 static int au_rdu_do(struct file *h_file, struct au_rdu_arg *arg)
94 {
95 int err;
96 loff_t offset;
97 struct au_rdu_cookie *cookie = &arg->rdu->cookie;
98
99 /* we don't have to care (FMODE_32BITHASH | FMODE_64BITHASH) for ext4 */
100 offset = vfsub_llseek(h_file, cookie->h_pos, SEEK_SET);
101 err = offset;
102 if (unlikely(offset != cookie->h_pos))
103 goto out;
104
105 err = 0;
106 do {
107 arg->err = 0;
108 au_fclr_rdu(cookie->flags, CALLED);
109 /* smp_mb(); */
110 err = vfsub_iterate_dir(h_file, &arg->ctx);
111 if (err >= 0)
112 err = arg->err;
113 } while (!err
114 && au_ftest_rdu(cookie->flags, CALLED)
115 && !au_ftest_rdu(cookie->flags, FULL));
116 cookie->h_pos = h_file->f_pos;
117
118 out:
119 AuTraceErr(err);
120 return err;
121 }
122
123 static int au_rdu(struct file *file, struct aufs_rdu *rdu)
124 {
125 int err;
126 aufs_bindex_t bbot;
127 struct au_rdu_arg arg = {
128 .ctx = {
129 .actor = au_rdu_fill
130 }
131 };
132 struct dentry *dentry;
133 struct inode *inode;
134 struct file *h_file;
135 struct au_rdu_cookie *cookie = &rdu->cookie;
136
137 /* VERIFY_WRITE */
138 err = !access_ok(rdu->ent.e, rdu->sz);
139 if (unlikely(err)) {
140 err = -EFAULT;
141 AuTraceErr(err);
142 goto out;
143 }
144 rdu->rent = 0;
145 rdu->tail = rdu->ent;
146 rdu->full = 0;
147 arg.rdu = rdu;
148 arg.ent = rdu->ent;
149 arg.end = arg.ent.ul;
150 arg.end += rdu->sz;
151
152 err = -ENOTDIR;
153 if (unlikely(!file->f_op->iterate && !file->f_op->iterate_shared))
154 goto out;
155
156 err = security_file_permission(file, MAY_READ);
157 AuTraceErr(err);
158 if (unlikely(err))
159 goto out;
160
161 dentry = file->f_path.dentry;
162 inode = d_inode(dentry);
163 inode_lock_shared(inode);
164
165 arg.sb = inode->i_sb;
166 err = si_read_lock(arg.sb, AuLock_FLUSH | AuLock_NOPLM);
167 if (unlikely(err))
168 goto out_mtx;
169 err = au_alive_dir(dentry);
170 if (unlikely(err))
171 goto out_si;
172 /* todo: reval? */
173 fi_read_lock(file);
174
175 err = -EAGAIN;
176 if (unlikely(au_ftest_rdu(cookie->flags, CONT)
177 && cookie->generation != au_figen(file)))
178 goto out_unlock;
179
180 err = 0;
181 if (!rdu->blk) {
182 rdu->blk = au_sbi(arg.sb)->si_rdblk;
183 if (!rdu->blk)
184 rdu->blk = au_dir_size(file, /*dentry*/NULL);
185 }
186 bbot = au_fbtop(file);
187 if (cookie->bindex < bbot)
188 cookie->bindex = bbot;
189 bbot = au_fbbot_dir(file);
190 /* AuDbg("b%d, b%d\n", cookie->bindex, bbot); */
191 for (; !err && cookie->bindex <= bbot;
192 cookie->bindex++, cookie->h_pos = 0) {
193 h_file = au_hf_dir(file, cookie->bindex);
194 if (!h_file)
195 continue;
196
197 au_fclr_rdu(cookie->flags, FULL);
198 err = au_rdu_do(h_file, &arg);
199 AuTraceErr(err);
200 if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err))
201 break;
202 }
203 AuDbg("rent %llu\n", rdu->rent);
204
205 if (!err && !au_ftest_rdu(cookie->flags, CONT)) {
206 rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH);
207 au_fset_rdu(cookie->flags, CONT);
208 cookie->generation = au_figen(file);
209 }
210
211 ii_read_lock_child(inode);
212 fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibtop(inode)));
213 ii_read_unlock(inode);
214
215 out_unlock:
216 fi_read_unlock(file);
217 out_si:
218 si_read_unlock(arg.sb);
219 out_mtx:
220 inode_unlock_shared(inode);
221 out:
222 AuTraceErr(err);
223 return err;
224 }
225
226 static int au_rdu_ino(struct file *file, struct aufs_rdu *rdu)
227 {
228 int err;
229 ino_t ino;
230 unsigned long long nent;
231 union au_rdu_ent_ul *u;
232 struct au_rdu_ent ent;
233 struct super_block *sb;
234
235 err = 0;
236 nent = rdu->nent;
237 u = &rdu->ent;
238 sb = file->f_path.dentry->d_sb;
239 si_read_lock(sb, AuLock_FLUSH);
240 while (nent-- > 0) {
241 /* unnecessary to support mmap_sem since this is a dir */
242 err = copy_from_user(&ent, u->e, sizeof(ent));
243 if (!err)
244 /* VERIFY_WRITE */
245 err = !access_ok(&u->e->ino, sizeof(ino));
246 if (unlikely(err)) {
247 err = -EFAULT;
248 AuTraceErr(err);
249 break;
250 }
251
252 /* AuDbg("b%d, i%llu\n", ent.bindex, ent.ino); */
253 if (!ent.wh)
254 err = au_ino(sb, ent.bindex, ent.ino, ent.type, &ino);
255 else
256 err = au_wh_ino(sb, ent.bindex, ent.ino, ent.type,
257 &ino);
258 if (unlikely(err)) {
259 AuTraceErr(err);
260 break;
261 }
262
263 err = __put_user(ino, &u->e->ino);
264 if (unlikely(err)) {
265 err = -EFAULT;
266 AuTraceErr(err);
267 break;
268 }
269 u->ul += au_rdu_len(ent.nlen);
270 }
271 si_read_unlock(sb);
272
273 return err;
274 }
275
276 /* ---------------------------------------------------------------------- */
277
278 static int au_rdu_verify(struct aufs_rdu *rdu)
279 {
280 AuDbg("rdu{%llu, %p, %u | %u | %llu, %u, %u | "
281 "%llu, b%d, 0x%x, g%u}\n",
282 rdu->sz, rdu->ent.e, rdu->verify[AufsCtlRduV_SZ],
283 rdu->blk,
284 rdu->rent, rdu->shwh, rdu->full,
285 rdu->cookie.h_pos, rdu->cookie.bindex, rdu->cookie.flags,
286 rdu->cookie.generation);
287
288 if (rdu->verify[AufsCtlRduV_SZ] == sizeof(*rdu))
289 return 0;
290
291 AuDbg("%u:%u\n",
292 rdu->verify[AufsCtlRduV_SZ], (unsigned int)sizeof(*rdu));
293 return -EINVAL;
294 }
295
296 long au_rdu_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
297 {
298 long err, e;
299 struct aufs_rdu rdu;
300 void __user *p = (void __user *)arg;
301
302 err = copy_from_user(&rdu, p, sizeof(rdu));
303 if (unlikely(err)) {
304 err = -EFAULT;
305 AuTraceErr(err);
306 goto out;
307 }
308 err = au_rdu_verify(&rdu);
309 if (unlikely(err))
310 goto out;
311
312 switch (cmd) {
313 case AUFS_CTL_RDU:
314 err = au_rdu(file, &rdu);
315 if (unlikely(err))
316 break;
317
318 e = copy_to_user(p, &rdu, sizeof(rdu));
319 if (unlikely(e)) {
320 err = -EFAULT;
321 AuTraceErr(err);
322 }
323 break;
324 case AUFS_CTL_RDU_INO:
325 err = au_rdu_ino(file, &rdu);
326 break;
327
328 default:
329 /* err = -ENOTTY; */
330 err = -EINVAL;
331 }
332
333 out:
334 AuTraceErr(err);
335 return err;
336 }
337
338 #ifdef CONFIG_COMPAT
339 long au_rdu_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
340 {
341 long err, e;
342 struct aufs_rdu rdu;
343 void __user *p = compat_ptr(arg);
344
345 /* todo: get_user()? */
346 err = copy_from_user(&rdu, p, sizeof(rdu));
347 if (unlikely(err)) {
348 err = -EFAULT;
349 AuTraceErr(err);
350 goto out;
351 }
352 rdu.ent.e = compat_ptr(rdu.ent.ul);
353 err = au_rdu_verify(&rdu);
354 if (unlikely(err))
355 goto out;
356
357 switch (cmd) {
358 case AUFS_CTL_RDU:
359 err = au_rdu(file, &rdu);
360 if (unlikely(err))
361 break;
362
363 rdu.ent.ul = ptr_to_compat(rdu.ent.e);
364 rdu.tail.ul = ptr_to_compat(rdu.tail.e);
365 e = copy_to_user(p, &rdu, sizeof(rdu));
366 if (unlikely(e)) {
367 err = -EFAULT;
368 AuTraceErr(err);
369 }
370 break;
371 case AUFS_CTL_RDU_INO:
372 err = au_rdu_ino(file, &rdu);
373 break;
374
375 default:
376 /* err = -ENOTTY; */
377 err = -EINVAL;
378 }
379
380 out:
381 AuTraceErr(err);
382 return err;
383 }
384 #endif