/proc/<pid>/cmdline: add back the setproctitle() special case
[platform/kernel/linux-rpi.git] / fs / readdir.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  linux/fs/readdir.c
4  *
5  *  Copyright (C) 1995  Linus Torvalds
6  */
7
8 #include <linux/stddef.h>
9 #include <linux/kernel.h>
10 #include <linux/export.h>
11 #include <linux/time.h>
12 #include <linux/mm.h>
13 #include <linux/errno.h>
14 #include <linux/stat.h>
15 #include <linux/file.h>
16 #include <linux/fs.h>
17 #include <linux/fsnotify.h>
18 #include <linux/dirent.h>
19 #include <linux/security.h>
20 #include <linux/syscalls.h>
21 #include <linux/unistd.h>
22 #include <linux/compat.h>
23
24 #include <linux/uaccess.h>
25
26 int iterate_dir(struct file *file, struct dir_context *ctx)
27 {
28         struct inode *inode = file_inode(file);
29         bool shared = false;
30         int res = -ENOTDIR;
31         if (file->f_op->iterate_shared)
32                 shared = true;
33         else if (!file->f_op->iterate)
34                 goto out;
35
36         res = security_file_permission(file, MAY_READ);
37         if (res)
38                 goto out;
39
40         if (shared)
41                 res = down_read_killable(&inode->i_rwsem);
42         else
43                 res = down_write_killable(&inode->i_rwsem);
44         if (res)
45                 goto out;
46
47         res = -ENOENT;
48         if (!IS_DEADDIR(inode)) {
49                 ctx->pos = file->f_pos;
50                 if (shared)
51                         res = file->f_op->iterate_shared(file, ctx);
52                 else
53                         res = file->f_op->iterate(file, ctx);
54                 file->f_pos = ctx->pos;
55                 fsnotify_access(file);
56                 file_accessed(file);
57         }
58         if (shared)
59                 inode_unlock_shared(inode);
60         else
61                 inode_unlock(inode);
62 out:
63         return res;
64 }
65 EXPORT_SYMBOL(iterate_dir);
66
67 /*
68  * Traditional linux readdir() handling..
69  *
70  * "count=1" is a special case, meaning that the buffer is one
71  * dirent-structure in size and that the code can't handle more
72  * anyway. Thus the special "fillonedir()" function for that
73  * case (the low-level handlers don't need to care about this).
74  */
75
76 #ifdef __ARCH_WANT_OLD_READDIR
77
78 struct old_linux_dirent {
79         unsigned long   d_ino;
80         unsigned long   d_offset;
81         unsigned short  d_namlen;
82         char            d_name[1];
83 };
84
85 struct readdir_callback {
86         struct dir_context ctx;
87         struct old_linux_dirent __user * dirent;
88         int result;
89 };
90
91 static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
92                       loff_t offset, u64 ino, unsigned int d_type)
93 {
94         struct readdir_callback *buf =
95                 container_of(ctx, struct readdir_callback, ctx);
96         struct old_linux_dirent __user * dirent;
97         unsigned long d_ino;
98
99         if (buf->result)
100                 return -EINVAL;
101         d_ino = ino;
102         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
103                 buf->result = -EOVERFLOW;
104                 return -EOVERFLOW;
105         }
106         buf->result++;
107         dirent = buf->dirent;
108         if (!access_ok(VERIFY_WRITE, dirent,
109                         (unsigned long)(dirent->d_name + namlen + 1) -
110                                 (unsigned long)dirent))
111                 goto efault;
112         if (    __put_user(d_ino, &dirent->d_ino) ||
113                 __put_user(offset, &dirent->d_offset) ||
114                 __put_user(namlen, &dirent->d_namlen) ||
115                 __copy_to_user(dirent->d_name, name, namlen) ||
116                 __put_user(0, dirent->d_name + namlen))
117                 goto efault;
118         return 0;
119 efault:
120         buf->result = -EFAULT;
121         return -EFAULT;
122 }
123
124 SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
125                 struct old_linux_dirent __user *, dirent, unsigned int, count)
126 {
127         int error;
128         struct fd f = fdget_pos(fd);
129         struct readdir_callback buf = {
130                 .ctx.actor = fillonedir,
131                 .dirent = dirent
132         };
133
134         if (!f.file)
135                 return -EBADF;
136
137         error = iterate_dir(f.file, &buf.ctx);
138         if (buf.result)
139                 error = buf.result;
140
141         fdput_pos(f);
142         return error;
143 }
144
145 #endif /* __ARCH_WANT_OLD_READDIR */
146
147 /*
148  * New, all-improved, singing, dancing, iBCS2-compliant getdents()
149  * interface. 
150  */
151 struct linux_dirent {
152         unsigned long   d_ino;
153         unsigned long   d_off;
154         unsigned short  d_reclen;
155         char            d_name[1];
156 };
157
158 struct getdents_callback {
159         struct dir_context ctx;
160         struct linux_dirent __user * current_dir;
161         struct linux_dirent __user * previous;
162         int count;
163         int error;
164 };
165
166 static int filldir(struct dir_context *ctx, const char *name, int namlen,
167                    loff_t offset, u64 ino, unsigned int d_type)
168 {
169         struct linux_dirent __user * dirent;
170         struct getdents_callback *buf =
171                 container_of(ctx, struct getdents_callback, ctx);
172         unsigned long d_ino;
173         int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
174                 sizeof(long));
175
176         buf->error = -EINVAL;   /* only used if we fail.. */
177         if (reclen > buf->count)
178                 return -EINVAL;
179         d_ino = ino;
180         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
181                 buf->error = -EOVERFLOW;
182                 return -EOVERFLOW;
183         }
184         dirent = buf->previous;
185         if (dirent) {
186                 if (signal_pending(current))
187                         return -EINTR;
188                 if (__put_user(offset, &dirent->d_off))
189                         goto efault;
190         }
191         dirent = buf->current_dir;
192         if (__put_user(d_ino, &dirent->d_ino))
193                 goto efault;
194         if (__put_user(reclen, &dirent->d_reclen))
195                 goto efault;
196         if (copy_to_user(dirent->d_name, name, namlen))
197                 goto efault;
198         if (__put_user(0, dirent->d_name + namlen))
199                 goto efault;
200         if (__put_user(d_type, (char __user *) dirent + reclen - 1))
201                 goto efault;
202         buf->previous = dirent;
203         dirent = (void __user *)dirent + reclen;
204         buf->current_dir = dirent;
205         buf->count -= reclen;
206         return 0;
207 efault:
208         buf->error = -EFAULT;
209         return -EFAULT;
210 }
211
212 SYSCALL_DEFINE3(getdents, unsigned int, fd,
213                 struct linux_dirent __user *, dirent, unsigned int, count)
214 {
215         struct fd f;
216         struct linux_dirent __user * lastdirent;
217         struct getdents_callback buf = {
218                 .ctx.actor = filldir,
219                 .count = count,
220                 .current_dir = dirent
221         };
222         int error;
223
224         if (!access_ok(VERIFY_WRITE, dirent, count))
225                 return -EFAULT;
226
227         f = fdget_pos(fd);
228         if (!f.file)
229                 return -EBADF;
230
231         error = iterate_dir(f.file, &buf.ctx);
232         if (error >= 0)
233                 error = buf.error;
234         lastdirent = buf.previous;
235         if (lastdirent) {
236                 if (put_user(buf.ctx.pos, &lastdirent->d_off))
237                         error = -EFAULT;
238                 else
239                         error = count - buf.count;
240         }
241         fdput_pos(f);
242         return error;
243 }
244
245 struct getdents_callback64 {
246         struct dir_context ctx;
247         struct linux_dirent64 __user * current_dir;
248         struct linux_dirent64 __user * previous;
249         int count;
250         int error;
251 };
252
253 static int filldir64(struct dir_context *ctx, const char *name, int namlen,
254                      loff_t offset, u64 ino, unsigned int d_type)
255 {
256         struct linux_dirent64 __user *dirent;
257         struct getdents_callback64 *buf =
258                 container_of(ctx, struct getdents_callback64, ctx);
259         int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
260                 sizeof(u64));
261
262         buf->error = -EINVAL;   /* only used if we fail.. */
263         if (reclen > buf->count)
264                 return -EINVAL;
265         dirent = buf->previous;
266         if (dirent) {
267                 if (signal_pending(current))
268                         return -EINTR;
269                 if (__put_user(offset, &dirent->d_off))
270                         goto efault;
271         }
272         dirent = buf->current_dir;
273         if (__put_user(ino, &dirent->d_ino))
274                 goto efault;
275         if (__put_user(0, &dirent->d_off))
276                 goto efault;
277         if (__put_user(reclen, &dirent->d_reclen))
278                 goto efault;
279         if (__put_user(d_type, &dirent->d_type))
280                 goto efault;
281         if (copy_to_user(dirent->d_name, name, namlen))
282                 goto efault;
283         if (__put_user(0, dirent->d_name + namlen))
284                 goto efault;
285         buf->previous = dirent;
286         dirent = (void __user *)dirent + reclen;
287         buf->current_dir = dirent;
288         buf->count -= reclen;
289         return 0;
290 efault:
291         buf->error = -EFAULT;
292         return -EFAULT;
293 }
294
295 int ksys_getdents64(unsigned int fd, struct linux_dirent64 __user *dirent,
296                     unsigned int count)
297 {
298         struct fd f;
299         struct linux_dirent64 __user * lastdirent;
300         struct getdents_callback64 buf = {
301                 .ctx.actor = filldir64,
302                 .count = count,
303                 .current_dir = dirent
304         };
305         int error;
306
307         if (!access_ok(VERIFY_WRITE, dirent, count))
308                 return -EFAULT;
309
310         f = fdget_pos(fd);
311         if (!f.file)
312                 return -EBADF;
313
314         error = iterate_dir(f.file, &buf.ctx);
315         if (error >= 0)
316                 error = buf.error;
317         lastdirent = buf.previous;
318         if (lastdirent) {
319                 typeof(lastdirent->d_off) d_off = buf.ctx.pos;
320                 if (__put_user(d_off, &lastdirent->d_off))
321                         error = -EFAULT;
322                 else
323                         error = count - buf.count;
324         }
325         fdput_pos(f);
326         return error;
327 }
328
329
330 SYSCALL_DEFINE3(getdents64, unsigned int, fd,
331                 struct linux_dirent64 __user *, dirent, unsigned int, count)
332 {
333         return ksys_getdents64(fd, dirent, count);
334 }
335
336 #ifdef CONFIG_COMPAT
337 struct compat_old_linux_dirent {
338         compat_ulong_t  d_ino;
339         compat_ulong_t  d_offset;
340         unsigned short  d_namlen;
341         char            d_name[1];
342 };
343
344 struct compat_readdir_callback {
345         struct dir_context ctx;
346         struct compat_old_linux_dirent __user *dirent;
347         int result;
348 };
349
350 static int compat_fillonedir(struct dir_context *ctx, const char *name,
351                              int namlen, loff_t offset, u64 ino,
352                              unsigned int d_type)
353 {
354         struct compat_readdir_callback *buf =
355                 container_of(ctx, struct compat_readdir_callback, ctx);
356         struct compat_old_linux_dirent __user *dirent;
357         compat_ulong_t d_ino;
358
359         if (buf->result)
360                 return -EINVAL;
361         d_ino = ino;
362         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
363                 buf->result = -EOVERFLOW;
364                 return -EOVERFLOW;
365         }
366         buf->result++;
367         dirent = buf->dirent;
368         if (!access_ok(VERIFY_WRITE, dirent,
369                         (unsigned long)(dirent->d_name + namlen + 1) -
370                                 (unsigned long)dirent))
371                 goto efault;
372         if (    __put_user(d_ino, &dirent->d_ino) ||
373                 __put_user(offset, &dirent->d_offset) ||
374                 __put_user(namlen, &dirent->d_namlen) ||
375                 __copy_to_user(dirent->d_name, name, namlen) ||
376                 __put_user(0, dirent->d_name + namlen))
377                 goto efault;
378         return 0;
379 efault:
380         buf->result = -EFAULT;
381         return -EFAULT;
382 }
383
384 COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
385                 struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
386 {
387         int error;
388         struct fd f = fdget_pos(fd);
389         struct compat_readdir_callback buf = {
390                 .ctx.actor = compat_fillonedir,
391                 .dirent = dirent
392         };
393
394         if (!f.file)
395                 return -EBADF;
396
397         error = iterate_dir(f.file, &buf.ctx);
398         if (buf.result)
399                 error = buf.result;
400
401         fdput_pos(f);
402         return error;
403 }
404
405 struct compat_linux_dirent {
406         compat_ulong_t  d_ino;
407         compat_ulong_t  d_off;
408         unsigned short  d_reclen;
409         char            d_name[1];
410 };
411
412 struct compat_getdents_callback {
413         struct dir_context ctx;
414         struct compat_linux_dirent __user *current_dir;
415         struct compat_linux_dirent __user *previous;
416         int count;
417         int error;
418 };
419
420 static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
421                 loff_t offset, u64 ino, unsigned int d_type)
422 {
423         struct compat_linux_dirent __user * dirent;
424         struct compat_getdents_callback *buf =
425                 container_of(ctx, struct compat_getdents_callback, ctx);
426         compat_ulong_t d_ino;
427         int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
428                 namlen + 2, sizeof(compat_long_t));
429
430         buf->error = -EINVAL;   /* only used if we fail.. */
431         if (reclen > buf->count)
432                 return -EINVAL;
433         d_ino = ino;
434         if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
435                 buf->error = -EOVERFLOW;
436                 return -EOVERFLOW;
437         }
438         dirent = buf->previous;
439         if (dirent) {
440                 if (signal_pending(current))
441                         return -EINTR;
442                 if (__put_user(offset, &dirent->d_off))
443                         goto efault;
444         }
445         dirent = buf->current_dir;
446         if (__put_user(d_ino, &dirent->d_ino))
447                 goto efault;
448         if (__put_user(reclen, &dirent->d_reclen))
449                 goto efault;
450         if (copy_to_user(dirent->d_name, name, namlen))
451                 goto efault;
452         if (__put_user(0, dirent->d_name + namlen))
453                 goto efault;
454         if (__put_user(d_type, (char  __user *) dirent + reclen - 1))
455                 goto efault;
456         buf->previous = dirent;
457         dirent = (void __user *)dirent + reclen;
458         buf->current_dir = dirent;
459         buf->count -= reclen;
460         return 0;
461 efault:
462         buf->error = -EFAULT;
463         return -EFAULT;
464 }
465
466 COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
467                 struct compat_linux_dirent __user *, dirent, unsigned int, count)
468 {
469         struct fd f;
470         struct compat_linux_dirent __user * lastdirent;
471         struct compat_getdents_callback buf = {
472                 .ctx.actor = compat_filldir,
473                 .current_dir = dirent,
474                 .count = count
475         };
476         int error;
477
478         if (!access_ok(VERIFY_WRITE, dirent, count))
479                 return -EFAULT;
480
481         f = fdget_pos(fd);
482         if (!f.file)
483                 return -EBADF;
484
485         error = iterate_dir(f.file, &buf.ctx);
486         if (error >= 0)
487                 error = buf.error;
488         lastdirent = buf.previous;
489         if (lastdirent) {
490                 if (put_user(buf.ctx.pos, &lastdirent->d_off))
491                         error = -EFAULT;
492                 else
493                         error = count - buf.count;
494         }
495         fdput_pos(f);
496         return error;
497 }
498 #endif