Line data Source code
1 : /* $OpenBSD: vfs_syscalls.c,v 1.305 2018/09/01 17:02:12 deraadt Exp $ */
2 : /* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1989, 1993
6 : * The Regents of the University of California. All rights reserved.
7 : * (c) UNIX System Laboratories, Inc.
8 : * All or some portions of this file are derived from material licensed
9 : * to the University of California by American Telephone and Telegraph
10 : * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11 : * the permission of UNIX System Laboratories, Inc.
12 : *
13 : * Redistribution and use in source and binary forms, with or without
14 : * modification, are permitted provided that the following conditions
15 : * are met:
16 : * 1. Redistributions of source code must retain the above copyright
17 : * notice, this list of conditions and the following disclaimer.
18 : * 2. Redistributions in binary form must reproduce the above copyright
19 : * notice, this list of conditions and the following disclaimer in the
20 : * documentation and/or other materials provided with the distribution.
21 : * 3. Neither the name of the University nor the names of its contributors
22 : * may be used to endorse or promote products derived from this software
23 : * without specific prior written permission.
24 : *
25 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 : * SUCH DAMAGE.
36 : *
37 : * @(#)vfs_syscalls.c 8.28 (Berkeley) 12/10/94
38 : */
39 :
40 : #include <sys/param.h>
41 : #include <sys/systm.h>
42 : #include <sys/namei.h>
43 : #include <sys/filedesc.h>
44 : #include <sys/kernel.h>
45 : #include <sys/conf.h>
46 : #include <sys/sysctl.h>
47 : #include <sys/fcntl.h>
48 : #include <sys/file.h>
49 : #include <sys/stat.h>
50 : #include <sys/lock.h>
51 : #include <sys/vnode.h>
52 : #include <sys/mount.h>
53 : #include <sys/proc.h>
54 : #include <sys/pledge.h>
55 : #include <sys/uio.h>
56 : #include <sys/malloc.h>
57 : #include <sys/pool.h>
58 : #include <sys/dkio.h>
59 : #include <sys/disklabel.h>
60 : #include <sys/ktrace.h>
61 : #include <sys/unistd.h>
62 : #include <sys/specdev.h>
63 :
64 : #include <sys/syscallargs.h>
65 :
66 : extern int suid_clear;
67 :
68 : static int change_dir(struct nameidata *, struct proc *);
69 :
70 : void checkdirs(struct vnode *);
71 :
72 : int copyout_statfs(struct statfs *, void *, struct proc *);
73 :
74 : int doopenat(struct proc *, int, const char *, int, mode_t, register_t *);
75 : int domknodat(struct proc *, int, const char *, mode_t, dev_t);
76 : int dolinkat(struct proc *, int, const char *, int, const char *, int);
77 : int dosymlinkat(struct proc *, const char *, int, const char *);
78 : int dounlinkat(struct proc *, int, const char *, int);
79 : int dofaccessat(struct proc *, int, const char *, int, int);
80 : int dofstatat(struct proc *, int, const char *, struct stat *, int);
81 : int doreadlinkat(struct proc *, int, const char *, char *, size_t,
82 : register_t *);
83 : int dochflagsat(struct proc *, int, const char *, u_int, int);
84 : int dovchflags(struct proc *, struct vnode *, u_int);
85 : int dofchmodat(struct proc *, int, const char *, mode_t, int);
86 : int dofchownat(struct proc *, int, const char *, uid_t, gid_t, int);
87 : int dorenameat(struct proc *, int, const char *, int, const char *);
88 : int domkdirat(struct proc *, int, const char *, mode_t);
89 : int doutimensat(struct proc *, int, const char *, struct timespec [2], int);
90 : int dovutimens(struct proc *, struct vnode *, struct timespec [2]);
91 : int dofutimens(struct proc *, int, struct timespec [2]);
92 : int dounmount_leaf(struct mount *, int, struct proc *);
93 : int unveil_add(struct proc *, struct nameidata *, const char *);
94 : void unveil_removevnode(struct vnode *vp);
95 :
96 : /*
97 : * Virtual File System System Calls
98 : */
99 :
100 : /*
101 : * Mount a file system.
102 : */
103 : int
104 0 : sys_mount(struct proc *p, void *v, register_t *retval)
105 : {
106 : struct sys_mount_args /* {
107 : syscallarg(const char *) type;
108 : syscallarg(const char *) path;
109 : syscallarg(int) flags;
110 : syscallarg(void *) data;
111 0 : } */ *uap = v;
112 : struct vnode *vp;
113 : struct mount *mp;
114 : int error, mntflag = 0;
115 0 : char fstypename[MFSNAMELEN];
116 0 : char fspath[MNAMELEN];
117 0 : struct nameidata nd;
118 : struct vfsconf *vfsp;
119 0 : int flags = SCARG(uap, flags);
120 : void *args = NULL;
121 :
122 0 : if ((error = suser(p)))
123 0 : return (error);
124 :
125 : /*
126 : * Mount points must fit in MNAMELEN, not MAXPATHLEN.
127 : */
128 0 : error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL);
129 0 : if (error)
130 0 : return(error);
131 :
132 : /*
133 : * Get vnode to be covered
134 : */
135 0 : NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, p);
136 0 : if ((error = namei(&nd)) != 0)
137 : goto fail;
138 0 : vp = nd.ni_vp;
139 0 : if (flags & MNT_UPDATE) {
140 0 : if ((vp->v_flag & VROOT) == 0) {
141 0 : vput(vp);
142 : error = EINVAL;
143 0 : goto fail;
144 : }
145 0 : mp = vp->v_mount;
146 0 : vfsp = mp->mnt_vfc;
147 :
148 0 : args = malloc(vfsp->vfc_datasize, M_TEMP, M_WAITOK | M_ZERO);
149 0 : error = copyin(SCARG(uap, data), args, vfsp->vfc_datasize);
150 0 : if (error) {
151 0 : vput(vp);
152 0 : goto fail;
153 : }
154 :
155 0 : mntflag = mp->mnt_flag;
156 : /*
157 : * We only allow the filesystem to be reloaded if it
158 : * is currently mounted read-only.
159 : */
160 0 : if ((flags & MNT_RELOAD) &&
161 0 : ((mp->mnt_flag & MNT_RDONLY) == 0)) {
162 0 : vput(vp);
163 : error = EOPNOTSUPP; /* Needs translation */
164 0 : goto fail;
165 : }
166 :
167 0 : if ((error = vfs_busy(mp, VB_READ|VB_NOWAIT)) != 0) {
168 0 : vput(vp);
169 0 : goto fail;
170 : }
171 0 : mp->mnt_flag |= flags & (MNT_RELOAD | MNT_UPDATE);
172 0 : goto update;
173 : }
174 : /*
175 : * Do not allow disabling of permission checks unless exec and access to
176 : * device files is disabled too.
177 : */
178 0 : if ((flags & MNT_NOPERM) &&
179 0 : (flags & (MNT_NODEV | MNT_NOEXEC)) != (MNT_NODEV | MNT_NOEXEC)) {
180 0 : vput(vp);
181 : error = EPERM;
182 0 : goto fail;
183 : }
184 0 : if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) {
185 0 : vput(vp);
186 0 : goto fail;
187 : }
188 0 : if (vp->v_type != VDIR) {
189 0 : vput(vp);
190 0 : goto fail;
191 : }
192 0 : error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL);
193 0 : if (error) {
194 0 : vput(vp);
195 0 : goto fail;
196 : }
197 0 : for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next) {
198 0 : if (!strcmp(vfsp->vfc_name, fstypename))
199 : break;
200 : }
201 :
202 0 : if (vfsp == NULL) {
203 0 : vput(vp);
204 : error = EOPNOTSUPP;
205 0 : goto fail;
206 : }
207 :
208 0 : args = malloc(vfsp->vfc_datasize, M_TEMP, M_WAITOK | M_ZERO);
209 0 : error = copyin(SCARG(uap, data), args, vfsp->vfc_datasize);
210 0 : if (error) {
211 0 : vput(vp);
212 0 : goto fail;
213 : }
214 :
215 0 : if (vp->v_mountedhere != NULL) {
216 0 : vput(vp);
217 : error = EBUSY;
218 0 : goto fail;
219 : }
220 :
221 : /*
222 : * Allocate and initialize the file system.
223 : */
224 0 : mp = malloc(sizeof(*mp), M_MOUNT, M_WAITOK|M_ZERO);
225 0 : (void) vfs_busy(mp, VB_READ|VB_NOWAIT);
226 0 : mp->mnt_op = vfsp->vfc_vfsops;
227 0 : mp->mnt_vfc = vfsp;
228 0 : mp->mnt_flag |= (vfsp->vfc_flags & MNT_VISFLAGMASK);
229 0 : strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
230 0 : mp->mnt_vnodecovered = vp;
231 0 : mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
232 :
233 : update:
234 : /* Ensure that the parent mountpoint does not get unmounted. */
235 0 : error = vfs_busy(vp->v_mount, VB_READ|VB_NOWAIT|VB_DUPOK);
236 0 : if (error) {
237 0 : if (mp->mnt_flag & MNT_UPDATE) {
238 0 : mp->mnt_flag = mntflag;
239 0 : vfs_unbusy(mp);
240 0 : } else {
241 0 : vfs_unbusy(mp);
242 0 : free(mp, M_MOUNT, sizeof(*mp));
243 : }
244 0 : vput(vp);
245 0 : goto fail;
246 : }
247 :
248 : /*
249 : * Set the mount level flags.
250 : */
251 0 : if (flags & MNT_RDONLY)
252 0 : mp->mnt_flag |= MNT_RDONLY;
253 0 : else if (mp->mnt_flag & MNT_RDONLY)
254 0 : mp->mnt_flag |= MNT_WANTRDWR;
255 0 : mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_WXALLOWED | MNT_NODEV |
256 : MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP | MNT_NOATIME |
257 : MNT_NOPERM | MNT_FORCE);
258 0 : mp->mnt_flag |= flags & (MNT_NOSUID | MNT_NOEXEC | MNT_WXALLOWED |
259 : MNT_NODEV | MNT_SYNCHRONOUS | MNT_ASYNC | MNT_SOFTDEP |
260 : MNT_NOATIME | MNT_NOPERM | MNT_FORCE);
261 : /*
262 : * Mount the filesystem.
263 : */
264 0 : error = VFS_MOUNT(mp, fspath, args, &nd, p);
265 0 : if (!error) {
266 0 : mp->mnt_stat.f_ctime = time_second;
267 0 : }
268 0 : if (mp->mnt_flag & MNT_UPDATE) {
269 0 : vfs_unbusy(vp->v_mount);
270 0 : vput(vp);
271 0 : if (mp->mnt_flag & MNT_WANTRDWR)
272 0 : mp->mnt_flag &= ~MNT_RDONLY;
273 0 : mp->mnt_flag &=~
274 : (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
275 0 : if (error)
276 0 : mp->mnt_flag = mntflag;
277 :
278 0 : if ((mp->mnt_flag & MNT_RDONLY) == 0) {
279 0 : if (mp->mnt_syncer == NULL)
280 0 : error = vfs_allocate_syncvnode(mp);
281 : } else {
282 0 : if (mp->mnt_syncer != NULL)
283 0 : vgone(mp->mnt_syncer);
284 0 : mp->mnt_syncer = NULL;
285 : }
286 :
287 0 : vfs_unbusy(mp);
288 0 : goto fail;
289 : }
290 :
291 0 : vp->v_mountedhere = mp;
292 :
293 : /*
294 : * Put the new filesystem on the mount list after root.
295 : */
296 0 : cache_purge(vp);
297 0 : if (!error) {
298 0 : vfsp->vfc_refcount++;
299 0 : TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
300 0 : checkdirs(vp);
301 0 : vfs_unbusy(vp->v_mount);
302 0 : VOP_UNLOCK(vp);
303 0 : if ((mp->mnt_flag & MNT_RDONLY) == 0)
304 0 : error = vfs_allocate_syncvnode(mp);
305 0 : vfs_unbusy(mp);
306 0 : (void) VFS_STATFS(mp, &mp->mnt_stat, p);
307 0 : if ((error = VFS_START(mp, 0, p)) != 0)
308 0 : vrele(vp);
309 : } else {
310 0 : mp->mnt_vnodecovered->v_mountedhere = NULL;
311 0 : vfs_unbusy(mp);
312 0 : free(mp, M_MOUNT, sizeof(*mp));
313 0 : vfs_unbusy(vp->v_mount);
314 0 : vput(vp);
315 : }
316 : fail:
317 0 : if (args)
318 0 : free(args, M_TEMP, vfsp->vfc_datasize);
319 0 : return (error);
320 0 : }
321 :
322 : /*
323 : * Scan all active processes to see if any of them have a current
324 : * or root directory onto which the new filesystem has just been
325 : * mounted. If so, replace them with the new mount point, keeping
326 : * track of how many were replaced. That's the number of references
327 : * the old vnode had that we've replaced, so finish by vrele()'ing
328 : * it that many times. This puts off any possible sleeping until
329 : * we've finished walking the allprocess list.
330 : */
331 : void
332 0 : checkdirs(struct vnode *olddp)
333 : {
334 : struct filedesc *fdp;
335 0 : struct vnode *newdp;
336 : struct process *pr;
337 : u_int free_count = 0;
338 :
339 0 : if (olddp->v_usecount == 1)
340 0 : return;
341 0 : if (VFS_ROOT(olddp->v_mountedhere, &newdp))
342 0 : panic("mount: lost mount");
343 0 : LIST_FOREACH(pr, &allprocess, ps_list) {
344 0 : fdp = pr->ps_fd;
345 0 : if (fdp->fd_cdir == olddp) {
346 0 : free_count++;
347 0 : vref(newdp);
348 0 : fdp->fd_cdir = newdp;
349 0 : }
350 0 : if (fdp->fd_rdir == olddp) {
351 0 : free_count++;
352 0 : vref(newdp);
353 0 : fdp->fd_rdir = newdp;
354 0 : }
355 0 : pr->ps_uvpcwd = NULL;
356 : /* XXX */
357 0 : pr->ps_uvpcwdgone = 1;
358 : }
359 0 : if (rootvnode == olddp) {
360 0 : free_count++;
361 0 : vref(newdp);
362 0 : rootvnode = newdp;
363 0 : }
364 0 : while (free_count-- > 0)
365 0 : vrele(olddp);
366 0 : vput(newdp);
367 0 : }
368 :
369 : /*
370 : * Unmount a file system.
371 : *
372 : * Note: unmount takes a path to the vnode mounted on as argument,
373 : * not special file (as before).
374 : */
375 : int
376 0 : sys_unmount(struct proc *p, void *v, register_t *retval)
377 : {
378 : struct sys_unmount_args /* {
379 : syscallarg(const char *) path;
380 : syscallarg(int) flags;
381 0 : } */ *uap = v;
382 : struct vnode *vp;
383 : struct mount *mp;
384 : int error;
385 0 : struct nameidata nd;
386 :
387 0 : if ((error = suser(p)) != 0)
388 0 : return (error);
389 :
390 0 : NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
391 : SCARG(uap, path), p);
392 0 : if ((error = namei(&nd)) != 0)
393 0 : return (error);
394 0 : vp = nd.ni_vp;
395 0 : mp = vp->v_mount;
396 :
397 : /*
398 : * Don't allow unmounting the root file system.
399 : */
400 0 : if (mp->mnt_flag & MNT_ROOTFS) {
401 0 : vput(vp);
402 0 : return (EINVAL);
403 : }
404 :
405 : /*
406 : * Must be the root of the filesystem
407 : */
408 0 : if ((vp->v_flag & VROOT) == 0) {
409 : vput(vp);
410 0 : return (EINVAL);
411 : }
412 : vput(vp);
413 :
414 0 : if (vfs_busy(mp, VB_WRITE|VB_WAIT))
415 0 : return (EBUSY);
416 :
417 0 : return (dounmount(mp, SCARG(uap, flags) & MNT_FORCE, p));
418 0 : }
419 :
420 : /*
421 : * Do the actual file system unmount.
422 : */
423 : int
424 0 : dounmount(struct mount *mp, int flags, struct proc *p)
425 : {
426 : SLIST_HEAD(, mount) mplist;
427 : struct mount *nmp;
428 : int error;
429 :
430 : SLIST_INIT(&mplist);
431 0 : SLIST_INSERT_HEAD(&mplist, mp, mnt_dounmount);
432 :
433 : /*
434 : * Collect nested mount points. This takes advantage of the mount list
435 : * being ordered - nested mount points come after their parent.
436 : */
437 0 : while ((mp = TAILQ_NEXT(mp, mnt_list)) != NULL) {
438 0 : SLIST_FOREACH(nmp, &mplist, mnt_dounmount) {
439 0 : if (mp->mnt_vnodecovered == NULLVP ||
440 0 : mp->mnt_vnodecovered->v_mount != nmp)
441 : continue;
442 :
443 0 : if ((flags & MNT_FORCE) == 0) {
444 : error = EBUSY;
445 0 : goto err;
446 : }
447 0 : error = vfs_busy(mp, VB_WRITE|VB_WAIT|VB_DUPOK);
448 0 : if (error) {
449 0 : if ((flags & MNT_DOOMED)) {
450 : /*
451 : * If the mount point was busy due to
452 : * being unmounted, it has been removed
453 : * from the mount list already.
454 : * Restart the iteration from the last
455 : * collected busy entry.
456 : */
457 : mp = SLIST_FIRST(&mplist);
458 0 : break;
459 : }
460 : goto err;
461 : }
462 0 : SLIST_INSERT_HEAD(&mplist, mp, mnt_dounmount);
463 0 : break;
464 : }
465 : }
466 :
467 : /*
468 : * Nested mount points cannot appear during this loop as mounting
469 : * requires a read lock for the parent mount point.
470 : */
471 0 : while ((mp = SLIST_FIRST(&mplist)) != NULL) {
472 0 : SLIST_REMOVE(&mplist, mp, mount, mnt_dounmount);
473 0 : error = dounmount_leaf(mp, flags, p);
474 0 : if (error)
475 : goto err;
476 : }
477 0 : return (0);
478 :
479 : err:
480 0 : while ((mp = SLIST_FIRST(&mplist)) != NULL) {
481 0 : SLIST_REMOVE(&mplist, mp, mount, mnt_dounmount);
482 0 : vfs_unbusy(mp);
483 : }
484 0 : return (error);
485 0 : }
486 :
487 : int
488 0 : dounmount_leaf(struct mount *mp, int flags, struct proc *p)
489 : {
490 : struct vnode *coveredvp;
491 : struct vnode *vp, *nvp;
492 : int error;
493 : int hadsyncer = 0;
494 :
495 0 : mp->mnt_flag &=~ MNT_ASYNC;
496 0 : cache_purgevfs(mp); /* remove cache entries for this file sys */
497 0 : if (mp->mnt_syncer != NULL) {
498 : hadsyncer = 1;
499 0 : vgone(mp->mnt_syncer);
500 0 : mp->mnt_syncer = NULL;
501 0 : }
502 :
503 : /*
504 : * Before calling file system unmount, make sure
505 : * all unveils to vnodes in here are dropped.
506 : */
507 0 : LIST_FOREACH_SAFE(vp , &mp->mnt_vnodelist, v_mntvnodes, nvp) {
508 0 : unveil_removevnode(vp);
509 : }
510 :
511 0 : if (((mp->mnt_flag & MNT_RDONLY) ||
512 0 : (error = VFS_SYNC(mp, MNT_WAIT, 0, p->p_ucred, p)) == 0) ||
513 0 : (flags & MNT_FORCE))
514 0 : error = VFS_UNMOUNT(mp, flags, p);
515 :
516 0 : if (error && !(flags & MNT_DOOMED)) {
517 0 : if ((mp->mnt_flag & MNT_RDONLY) == 0 && hadsyncer)
518 0 : (void) vfs_allocate_syncvnode(mp);
519 0 : vfs_unbusy(mp);
520 0 : return (error);
521 : }
522 :
523 0 : TAILQ_REMOVE(&mountlist, mp, mnt_list);
524 0 : if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
525 0 : coveredvp->v_mountedhere = NULL;
526 0 : vrele(coveredvp);
527 0 : }
528 :
529 0 : mp->mnt_vfc->vfc_refcount--;
530 :
531 0 : if (!LIST_EMPTY(&mp->mnt_vnodelist))
532 0 : panic("unmount: dangling vnode");
533 :
534 0 : vfs_unbusy(mp);
535 0 : free(mp, M_MOUNT, sizeof(*mp));
536 :
537 0 : return (0);
538 0 : }
539 :
540 : /*
541 : * Sync each mounted filesystem.
542 : */
543 : #ifdef DEBUG
544 : int syncprt = 0;
545 : struct ctldebug debug0 = { "syncprt", &syncprt };
546 : #endif
547 :
548 : int
549 0 : sys_sync(struct proc *p, void *v, register_t *retval)
550 : {
551 : struct mount *mp;
552 : int asyncflag;
553 :
554 0 : TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) {
555 0 : if (vfs_busy(mp, VB_READ|VB_NOWAIT))
556 : continue;
557 0 : if ((mp->mnt_flag & MNT_RDONLY) == 0) {
558 0 : asyncflag = mp->mnt_flag & MNT_ASYNC;
559 0 : mp->mnt_flag &= ~MNT_ASYNC;
560 0 : uvm_vnp_sync(mp);
561 0 : VFS_SYNC(mp, MNT_NOWAIT, 0, p->p_ucred, p);
562 0 : if (asyncflag)
563 0 : mp->mnt_flag |= MNT_ASYNC;
564 : }
565 0 : vfs_unbusy(mp);
566 0 : }
567 :
568 0 : return (0);
569 : }
570 :
571 : /*
572 : * Change filesystem quotas.
573 : */
574 : int
575 0 : sys_quotactl(struct proc *p, void *v, register_t *retval)
576 : {
577 : struct sys_quotactl_args /* {
578 : syscallarg(const char *) path;
579 : syscallarg(int) cmd;
580 : syscallarg(int) uid;
581 : syscallarg(char *) arg;
582 0 : } */ *uap = v;
583 : struct mount *mp;
584 : int error;
585 0 : struct nameidata nd;
586 :
587 0 : NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
588 0 : if ((error = namei(&nd)) != 0)
589 0 : return (error);
590 0 : mp = nd.ni_vp->v_mount;
591 0 : vrele(nd.ni_vp);
592 0 : return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
593 : SCARG(uap, arg), p));
594 0 : }
595 :
596 : int
597 0 : copyout_statfs(struct statfs *sp, void *uaddr, struct proc *p)
598 : {
599 : size_t co_sz1 = offsetof(struct statfs, f_fsid);
600 : size_t co_off2 = co_sz1 + sizeof(fsid_t);
601 : size_t co_sz2 = sizeof(struct statfs) - co_off2;
602 : char *s, *d;
603 : int error;
604 :
605 : /* Don't let non-root see filesystem id (for NFS security) */
606 0 : if (suser(p)) {
607 0 : fsid_t fsid;
608 :
609 0 : s = (char *)sp;
610 : d = (char *)uaddr;
611 :
612 0 : memset(&fsid, 0, sizeof(fsid));
613 :
614 0 : if ((error = copyout(s, d, co_sz1)) != 0)
615 0 : return (error);
616 0 : if ((error = copyout(&fsid, d + co_sz1, sizeof(fsid))) != 0)
617 0 : return (error);
618 0 : return (copyout(s + co_off2, d + co_off2, co_sz2));
619 0 : }
620 :
621 0 : return (copyout(sp, uaddr, sizeof(*sp)));
622 0 : }
623 :
624 : /*
625 : * Get filesystem statistics.
626 : */
627 : int
628 0 : sys_statfs(struct proc *p, void *v, register_t *retval)
629 : {
630 : struct sys_statfs_args /* {
631 : syscallarg(const char *) path;
632 : syscallarg(struct statfs *) buf;
633 0 : } */ *uap = v;
634 : struct mount *mp;
635 : struct statfs *sp;
636 : int error;
637 0 : struct nameidata nd;
638 :
639 0 : NDINIT(&nd, LOOKUP, FOLLOW | BYPASSUNVEIL, UIO_USERSPACE,
640 : SCARG(uap, path), p);
641 0 : nd.ni_pledge = PLEDGE_RPATH;
642 0 : nd.ni_unveil = UNVEIL_READ;
643 0 : if ((error = namei(&nd)) != 0)
644 0 : return (error);
645 0 : mp = nd.ni_vp->v_mount;
646 0 : sp = &mp->mnt_stat;
647 0 : vrele(nd.ni_vp);
648 0 : if ((error = VFS_STATFS(mp, sp, p)) != 0)
649 0 : return (error);
650 0 : sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
651 :
652 0 : return (copyout_statfs(sp, SCARG(uap, buf), p));
653 0 : }
654 :
655 : /*
656 : * Get filesystem statistics.
657 : */
658 : int
659 0 : sys_fstatfs(struct proc *p, void *v, register_t *retval)
660 : {
661 : struct sys_fstatfs_args /* {
662 : syscallarg(int) fd;
663 : syscallarg(struct statfs *) buf;
664 0 : } */ *uap = v;
665 0 : struct file *fp;
666 : struct mount *mp;
667 : struct statfs *sp;
668 : int error;
669 :
670 0 : if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
671 0 : return (error);
672 0 : mp = ((struct vnode *)fp->f_data)->v_mount;
673 0 : if (!mp) {
674 0 : FRELE(fp, p);
675 0 : return (ENOENT);
676 : }
677 0 : sp = &mp->mnt_stat;
678 0 : error = VFS_STATFS(mp, sp, p);
679 0 : FRELE(fp, p);
680 0 : if (error)
681 0 : return (error);
682 0 : sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
683 :
684 0 : return (copyout_statfs(sp, SCARG(uap, buf), p));
685 0 : }
686 :
687 : /*
688 : * Get statistics on all filesystems.
689 : */
690 : int
691 0 : sys_getfsstat(struct proc *p, void *v, register_t *retval)
692 : {
693 : struct sys_getfsstat_args /* {
694 : syscallarg(struct statfs *) buf;
695 : syscallarg(size_t) bufsize;
696 : syscallarg(int) flags;
697 0 : } */ *uap = v;
698 : struct mount *mp;
699 : struct statfs *sp;
700 : struct statfs *sfsp;
701 : size_t count, maxcount;
702 0 : int error, flags = SCARG(uap, flags);
703 :
704 0 : maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
705 0 : sfsp = SCARG(uap, buf);
706 : count = 0;
707 :
708 0 : TAILQ_FOREACH(mp, &mountlist, mnt_list) {
709 0 : if (vfs_busy(mp, VB_READ|VB_NOWAIT))
710 : continue;
711 0 : if (sfsp && count < maxcount) {
712 0 : sp = &mp->mnt_stat;
713 :
714 : /* Refresh stats unless MNT_NOWAIT is specified */
715 0 : if (flags != MNT_NOWAIT &&
716 0 : flags != MNT_LAZY &&
717 0 : (flags == MNT_WAIT ||
718 0 : flags == 0) &&
719 0 : (error = VFS_STATFS(mp, sp, p))) {
720 0 : vfs_unbusy(mp);
721 0 : continue;
722 : }
723 :
724 0 : sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
725 : #if notyet
726 : if (mp->mnt_flag & MNT_SOFTDEP)
727 : sp->f_eflags = STATFS_SOFTUPD;
728 : #endif
729 0 : error = (copyout_statfs(sp, sfsp, p));
730 0 : if (error) {
731 0 : vfs_unbusy(mp);
732 0 : return (error);
733 : }
734 0 : sfsp++;
735 0 : }
736 0 : count++;
737 0 : vfs_unbusy(mp);
738 0 : }
739 :
740 0 : if (sfsp && count > maxcount)
741 0 : *retval = maxcount;
742 : else
743 0 : *retval = count;
744 :
745 0 : return (0);
746 0 : }
747 :
748 : /*
749 : * Change current working directory to a given file descriptor.
750 : */
751 : int
752 0 : sys_fchdir(struct proc *p, void *v, register_t *retval)
753 : {
754 : struct sys_fchdir_args /* {
755 : syscallarg(int) fd;
756 0 : } */ *uap = v;
757 0 : struct filedesc *fdp = p->p_fd;
758 0 : struct vnode *vp, *tdp, *old_cdir;
759 : struct mount *mp;
760 : struct file *fp;
761 : int error;
762 :
763 0 : if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
764 0 : return (EBADF);
765 0 : vp = fp->f_data;
766 0 : if (fp->f_type != DTYPE_VNODE || vp->v_type != VDIR) {
767 0 : FRELE(fp, p);
768 0 : return (ENOTDIR);
769 : }
770 0 : vref(vp);
771 0 : FRELE(fp, p);
772 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
773 0 : error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
774 :
775 0 : while (!error && (mp = vp->v_mountedhere) != NULL) {
776 0 : if (vfs_busy(mp, VB_READ|VB_WAIT))
777 0 : continue;
778 0 : error = VFS_ROOT(mp, &tdp);
779 0 : vfs_unbusy(mp);
780 0 : if (error)
781 : break;
782 0 : vput(vp);
783 0 : vp = tdp;
784 : }
785 0 : if (error) {
786 0 : vput(vp);
787 0 : return (error);
788 : }
789 0 : VOP_UNLOCK(vp);
790 0 : old_cdir = fdp->fd_cdir;
791 0 : fdp->fd_cdir = vp;
792 0 : vrele(old_cdir);
793 0 : return (0);
794 0 : }
795 :
796 : /*
797 : * Change current working directory (``.'').
798 : */
799 : int
800 0 : sys_chdir(struct proc *p, void *v, register_t *retval)
801 : {
802 : struct sys_chdir_args /* {
803 : syscallarg(const char *) path;
804 0 : } */ *uap = v;
805 0 : struct filedesc *fdp = p->p_fd;
806 : struct vnode *old_cdir;
807 : int error;
808 0 : struct nameidata nd;
809 :
810 0 : NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
811 : SCARG(uap, path), p);
812 0 : nd.ni_pledge = PLEDGE_RPATH;
813 0 : nd.ni_unveil = UNVEIL_READ;
814 0 : if ((error = change_dir(&nd, p)) != 0)
815 0 : return (error);
816 0 : p->p_p->ps_uvpcwd = nd.ni_unveil_match;
817 0 : p->p_p->ps_uvpcwdgone = 0;
818 0 : old_cdir = fdp->fd_cdir;
819 0 : fdp->fd_cdir = nd.ni_vp;
820 0 : vrele(old_cdir);
821 0 : return (0);
822 0 : }
823 :
824 : /*
825 : * Change notion of root (``/'') directory.
826 : */
827 : int
828 0 : sys_chroot(struct proc *p, void *v, register_t *retval)
829 : {
830 : struct sys_chroot_args /* {
831 : syscallarg(const char *) path;
832 0 : } */ *uap = v;
833 0 : struct filedesc *fdp = p->p_fd;
834 : struct vnode *old_cdir, *old_rdir;
835 : int error;
836 0 : struct nameidata nd;
837 :
838 0 : if ((error = suser(p)) != 0)
839 0 : return (error);
840 0 : NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
841 : SCARG(uap, path), p);
842 0 : if ((error = change_dir(&nd, p)) != 0)
843 0 : return (error);
844 0 : if (fdp->fd_rdir != NULL) {
845 : /*
846 : * A chroot() done inside a changed root environment does
847 : * an automatic chdir to avoid the out-of-tree experience.
848 : */
849 0 : vref(nd.ni_vp);
850 0 : old_rdir = fdp->fd_rdir;
851 0 : old_cdir = fdp->fd_cdir;
852 0 : fdp->fd_rdir = fdp->fd_cdir = nd.ni_vp;
853 0 : vrele(old_rdir);
854 0 : vrele(old_cdir);
855 0 : } else
856 0 : fdp->fd_rdir = nd.ni_vp;
857 0 : return (0);
858 0 : }
859 :
860 : /*
861 : * Common routine for chroot and chdir.
862 : */
863 : static int
864 0 : change_dir(struct nameidata *ndp, struct proc *p)
865 : {
866 : struct vnode *vp;
867 : int error;
868 :
869 0 : if ((error = namei(ndp)) != 0)
870 0 : return (error);
871 0 : vp = ndp->ni_vp;
872 0 : if (vp->v_type != VDIR)
873 0 : error = ENOTDIR;
874 : else
875 0 : error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
876 0 : if (error)
877 0 : vput(vp);
878 : else
879 0 : VOP_UNLOCK(vp);
880 0 : return (error);
881 0 : }
882 :
883 : int
884 0 : sys_unveil(struct proc *p, void *v, register_t *retval)
885 : {
886 : struct sys_unveil_args /* {
887 : syscallarg(const char *) path;
888 : syscallarg(const char *) permissions;
889 0 : } */ *uap = v;
890 0 : char pathname[MAXPATHLEN];
891 0 : struct nameidata nd;
892 0 : size_t pathlen;
893 0 : char permissions[5];
894 : int error;
895 :
896 0 : if (SCARG(uap, path) == NULL && SCARG(uap, permissions) == NULL) {
897 0 : p->p_p->ps_uvdone = 1;
898 0 : return (0);
899 : }
900 :
901 0 : if (p->p_p->ps_uvdone != 0)
902 0 : return EPERM;
903 :
904 0 : error = copyinstr(SCARG(uap, permissions), permissions,
905 : sizeof(permissions), NULL);
906 0 : if (error)
907 0 : return(error);
908 0 : error = copyinstr(SCARG(uap, path), pathname, sizeof(pathname), &pathlen);
909 0 : if (error)
910 0 : return(error);
911 :
912 : #ifdef KTRACE
913 0 : if (KTRPOINT(p, KTR_STRUCT))
914 0 : ktrstruct(p, "unveil", permissions, strlen(permissions));
915 : #endif
916 0 : if (pathlen < 2)
917 0 : return EINVAL;
918 :
919 0 : if (pathlen == 2 && pathname[0] == '/')
920 0 : NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME,
921 : UIO_SYSSPACE, pathname, p);
922 : else
923 0 : NDINIT(&nd, CREATE, FOLLOW | LOCKLEAF | LOCKPARENT | SAVENAME,
924 : UIO_SYSSPACE, pathname, p);
925 :
926 0 : nd.ni_pledge = PLEDGE_UNVEIL;
927 0 : if ((error = namei(&nd)) != 0)
928 0 : return (error);
929 :
930 : /*
931 : * XXX Any access to the file or directory will allow us to
932 : * pledge path it
933 : */
934 0 : if ((nd.ni_vp &&
935 0 : (VOP_ACCESS(nd.ni_vp, VREAD, p->p_ucred, p) == 0 ||
936 0 : VOP_ACCESS(nd.ni_vp, VWRITE, p->p_ucred, p) == 0 ||
937 0 : VOP_ACCESS(nd.ni_vp, VEXEC, p->p_ucred, p) == 0)) ||
938 0 : VOP_ACCESS(nd.ni_dvp, VREAD, p->p_ucred, p) == 0 ||
939 0 : VOP_ACCESS(nd.ni_dvp, VWRITE, p->p_ucred, p) == 0 ||
940 0 : VOP_ACCESS(nd.ni_dvp, VEXEC, p->p_ucred, p) == 0)
941 0 : error = unveil_add(p, &nd, permissions);
942 : else
943 : error = EPERM;
944 :
945 : /* release vref and lock from namei, but not vref from ppath_add */
946 0 : if (nd.ni_vp)
947 0 : vput(nd.ni_vp);
948 0 : if (nd.ni_dvp && nd.ni_dvp != nd.ni_vp)
949 0 : vput(nd.ni_dvp);
950 0 : return (error);
951 0 : }
952 :
953 : /*
954 : * Check permissions, allocate an open file structure,
955 : * and call the device open routine if any.
956 : */
957 : int
958 0 : sys_open(struct proc *p, void *v, register_t *retval)
959 : {
960 : struct sys_open_args /* {
961 : syscallarg(const char *) path;
962 : syscallarg(int) flags;
963 : syscallarg(mode_t) mode;
964 0 : } */ *uap = v;
965 :
966 0 : return (doopenat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, flags),
967 0 : SCARG(uap, mode), retval));
968 : }
969 :
970 : int
971 0 : sys_openat(struct proc *p, void *v, register_t *retval)
972 : {
973 : struct sys_openat_args /* {
974 : syscallarg(int) fd;
975 : syscallarg(const char *) path;
976 : syscallarg(int) flags;
977 : syscallarg(mode_t) mode;
978 0 : } */ *uap = v;
979 :
980 0 : return (doopenat(p, SCARG(uap, fd), SCARG(uap, path),
981 0 : SCARG(uap, flags), SCARG(uap, mode), retval));
982 : }
983 :
984 : int
985 0 : doopenat(struct proc *p, int fd, const char *path, int oflags, mode_t mode,
986 : register_t *retval)
987 : {
988 0 : struct filedesc *fdp = p->p_fd;
989 0 : struct file *fp;
990 : struct vnode *vp;
991 0 : struct vattr vattr;
992 : int flags, cloexec, cmode;
993 0 : int type, indx, error, localtrunc = 0;
994 0 : struct flock lf;
995 0 : struct nameidata nd;
996 : uint64_t ni_pledge = 0;
997 : u_char ni_unveil = 0;
998 :
999 0 : if (oflags & (O_EXLOCK | O_SHLOCK)) {
1000 0 : error = pledge_flock(p);
1001 0 : if (error != 0)
1002 0 : return (error);
1003 : }
1004 :
1005 0 : cloexec = (oflags & O_CLOEXEC) ? UF_EXCLOSE : 0;
1006 :
1007 0 : fdplock(fdp);
1008 0 : if ((error = falloc(p, &fp, &indx)) != 0)
1009 : goto out;
1010 0 : fdpunlock(fdp);
1011 :
1012 0 : flags = FFLAGS(oflags);
1013 0 : if (flags & FREAD) {
1014 : ni_pledge |= PLEDGE_RPATH;
1015 : ni_unveil |= UNVEIL_READ;
1016 0 : }
1017 0 : if (flags & FWRITE) {
1018 0 : ni_pledge |= PLEDGE_WPATH;
1019 0 : ni_unveil |= UNVEIL_WRITE;
1020 0 : }
1021 0 : if (oflags & O_CREAT) {
1022 0 : ni_pledge |= PLEDGE_CPATH;
1023 0 : ni_unveil |= UNVEIL_CREATE;
1024 0 : }
1025 :
1026 0 : cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
1027 0 : if ((p->p_p->ps_flags & PS_PLEDGE))
1028 0 : cmode &= ACCESSPERMS;
1029 0 : NDINITAT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fd, path, p);
1030 0 : nd.ni_pledge = ni_pledge;
1031 0 : nd.ni_unveil = ni_unveil;
1032 0 : p->p_dupfd = -1; /* XXX check for fdopen */
1033 0 : if ((flags & O_TRUNC) && (flags & (O_EXLOCK | O_SHLOCK))) {
1034 : localtrunc = 1;
1035 0 : flags &= ~O_TRUNC; /* Must do truncate ourselves */
1036 0 : }
1037 0 : if ((error = vn_open(&nd, flags, cmode)) != 0) {
1038 0 : fdplock(fdp);
1039 0 : if (error == ENODEV &&
1040 0 : p->p_dupfd >= 0 && /* XXX from fdopen */
1041 : (error =
1042 0 : dupfdopen(p, indx, flags)) == 0) {
1043 0 : closef(fp, p);
1044 0 : *retval = indx;
1045 0 : goto out;
1046 : }
1047 0 : if (error == ERESTART)
1048 0 : error = EINTR;
1049 0 : fdremove(fdp, indx);
1050 0 : closef(fp, p);
1051 0 : goto out;
1052 : }
1053 0 : p->p_dupfd = 0;
1054 0 : vp = nd.ni_vp;
1055 0 : fp->f_flag = flags & FMASK;
1056 0 : fp->f_type = DTYPE_VNODE;
1057 0 : fp->f_ops = &vnops;
1058 0 : fp->f_data = vp;
1059 0 : if (flags & (O_EXLOCK | O_SHLOCK)) {
1060 0 : lf.l_whence = SEEK_SET;
1061 0 : lf.l_start = 0;
1062 0 : lf.l_len = 0;
1063 0 : if (flags & O_EXLOCK)
1064 0 : lf.l_type = F_WRLCK;
1065 : else
1066 0 : lf.l_type = F_RDLCK;
1067 : type = F_FLOCK;
1068 0 : if ((flags & FNONBLOCK) == 0)
1069 0 : type |= F_WAIT;
1070 0 : VOP_UNLOCK(vp);
1071 0 : error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
1072 0 : if (error) {
1073 0 : fdplock(fdp);
1074 : /* closef will vn_close the file for us. */
1075 0 : fdremove(fdp, indx);
1076 0 : closef(fp, p);
1077 0 : goto out;
1078 : }
1079 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1080 0 : fp->f_iflags |= FIF_HASLOCK;
1081 0 : }
1082 0 : if (localtrunc) {
1083 0 : if ((fp->f_flag & FWRITE) == 0)
1084 0 : error = EACCES;
1085 0 : else if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_RDONLY))
1086 0 : error = EROFS;
1087 0 : else if (vp->v_type == VDIR)
1088 0 : error = EISDIR;
1089 0 : else if ((error = vn_writechk(vp)) == 0) {
1090 0 : VATTR_NULL(&vattr);
1091 0 : vattr.va_size = 0;
1092 0 : error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
1093 0 : }
1094 0 : if (error) {
1095 0 : VOP_UNLOCK(vp);
1096 0 : fdplock(fdp);
1097 : /* closef will close the file for us. */
1098 0 : fdremove(fdp, indx);
1099 0 : closef(fp, p);
1100 0 : goto out;
1101 : }
1102 : }
1103 0 : VOP_UNLOCK(vp);
1104 0 : *retval = indx;
1105 0 : fdplock(fdp);
1106 0 : fdinsert(fdp, indx, cloexec, fp);
1107 0 : FRELE(fp, p);
1108 : out:
1109 0 : fdpunlock(fdp);
1110 0 : return (error);
1111 0 : }
1112 :
1113 : /*
1114 : * Get file handle system call
1115 : */
1116 : int
1117 0 : sys_getfh(struct proc *p, void *v, register_t *retval)
1118 : {
1119 : struct sys_getfh_args /* {
1120 : syscallarg(const char *) fname;
1121 : syscallarg(fhandle_t *) fhp;
1122 0 : } */ *uap = v;
1123 : struct vnode *vp;
1124 0 : fhandle_t fh;
1125 : int error;
1126 0 : struct nameidata nd;
1127 :
1128 : /*
1129 : * Must be super user
1130 : */
1131 0 : error = suser(p);
1132 0 : if (error)
1133 0 : return (error);
1134 0 : NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1135 : SCARG(uap, fname), p);
1136 0 : error = namei(&nd);
1137 0 : if (error)
1138 0 : return (error);
1139 0 : vp = nd.ni_vp;
1140 0 : memset(&fh, 0, sizeof(fh));
1141 0 : fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1142 0 : error = VFS_VPTOFH(vp, &fh.fh_fid);
1143 0 : vput(vp);
1144 0 : if (error)
1145 0 : return (error);
1146 0 : error = copyout(&fh, SCARG(uap, fhp), sizeof(fh));
1147 0 : return (error);
1148 0 : }
1149 :
1150 : /*
1151 : * Open a file given a file handle.
1152 : *
1153 : * Check permissions, allocate an open file structure,
1154 : * and call the device open routine if any.
1155 : */
1156 : int
1157 0 : sys_fhopen(struct proc *p, void *v, register_t *retval)
1158 : {
1159 : struct sys_fhopen_args /* {
1160 : syscallarg(const fhandle_t *) fhp;
1161 : syscallarg(int) flags;
1162 0 : } */ *uap = v;
1163 0 : struct filedesc *fdp = p->p_fd;
1164 0 : struct file *fp;
1165 0 : struct vnode *vp = NULL;
1166 : struct mount *mp;
1167 0 : struct ucred *cred = p->p_ucred;
1168 : int flags, cloexec;
1169 0 : int type, indx, error=0;
1170 0 : struct flock lf;
1171 0 : struct vattr va;
1172 0 : fhandle_t fh;
1173 :
1174 : /*
1175 : * Must be super user
1176 : */
1177 0 : if ((error = suser(p)))
1178 0 : return (error);
1179 :
1180 0 : flags = FFLAGS(SCARG(uap, flags));
1181 0 : if ((flags & (FREAD | FWRITE)) == 0)
1182 0 : return (EINVAL);
1183 0 : if ((flags & O_CREAT))
1184 0 : return (EINVAL);
1185 :
1186 0 : cloexec = (flags & O_CLOEXEC) ? UF_EXCLOSE : 0;
1187 :
1188 0 : fdplock(fdp);
1189 0 : if ((error = falloc(p, &fp, &indx)) != 0) {
1190 0 : fp = NULL;
1191 0 : goto bad;
1192 : }
1193 :
1194 0 : if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1195 : goto bad;
1196 :
1197 0 : if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) {
1198 : error = ESTALE;
1199 0 : goto bad;
1200 : }
1201 :
1202 0 : if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) {
1203 0 : vp = NULL; /* most likely unnecessary sanity for bad: */
1204 0 : goto bad;
1205 : }
1206 :
1207 : /* Now do an effective vn_open */
1208 :
1209 0 : if (vp->v_type == VSOCK) {
1210 : error = EOPNOTSUPP;
1211 0 : goto bad;
1212 : }
1213 0 : if ((flags & O_DIRECTORY) && vp->v_type != VDIR) {
1214 : error = ENOTDIR;
1215 0 : goto bad;
1216 : }
1217 0 : if (flags & FREAD) {
1218 0 : if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
1219 : goto bad;
1220 : }
1221 0 : if (flags & (FWRITE | O_TRUNC)) {
1222 0 : if (vp->v_type == VDIR) {
1223 : error = EISDIR;
1224 0 : goto bad;
1225 : }
1226 0 : if ((error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0 ||
1227 0 : (error = vn_writechk(vp)) != 0)
1228 : goto bad;
1229 : }
1230 0 : if (flags & O_TRUNC) {
1231 0 : VATTR_NULL(&va);
1232 0 : va.va_size = 0;
1233 0 : if ((error = VOP_SETATTR(vp, &va, cred, p)) != 0)
1234 : goto bad;
1235 : }
1236 0 : if ((error = VOP_OPEN(vp, flags, cred, p)) != 0)
1237 : goto bad;
1238 0 : if (flags & FWRITE)
1239 0 : vp->v_writecount++;
1240 :
1241 : /* done with modified vn_open, now finish what sys_open does. */
1242 :
1243 0 : fp->f_flag = flags & FMASK;
1244 0 : fp->f_type = DTYPE_VNODE;
1245 0 : fp->f_ops = &vnops;
1246 0 : fp->f_data = vp;
1247 0 : if (flags & (O_EXLOCK | O_SHLOCK)) {
1248 0 : lf.l_whence = SEEK_SET;
1249 0 : lf.l_start = 0;
1250 0 : lf.l_len = 0;
1251 0 : if (flags & O_EXLOCK)
1252 0 : lf.l_type = F_WRLCK;
1253 : else
1254 0 : lf.l_type = F_RDLCK;
1255 : type = F_FLOCK;
1256 0 : if ((flags & FNONBLOCK) == 0)
1257 0 : type |= F_WAIT;
1258 0 : VOP_UNLOCK(vp);
1259 0 : error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type);
1260 0 : if (error) {
1261 0 : vp = NULL; /* closef will vn_close the file */
1262 0 : goto bad;
1263 : }
1264 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1265 0 : fp->f_iflags |= FIF_HASLOCK;
1266 0 : }
1267 0 : VOP_UNLOCK(vp);
1268 0 : *retval = indx;
1269 0 : fdinsert(fdp, indx, cloexec, fp);
1270 0 : fdpunlock(fdp);
1271 0 : FRELE(fp, p);
1272 0 : return (0);
1273 :
1274 : bad:
1275 0 : if (fp) {
1276 0 : fdremove(fdp, indx);
1277 0 : closef(fp, p);
1278 0 : if (vp != NULL)
1279 0 : vput(vp);
1280 : }
1281 0 : fdpunlock(fdp);
1282 0 : return (error);
1283 0 : }
1284 :
1285 : int
1286 0 : sys_fhstat(struct proc *p, void *v, register_t *retval)
1287 : {
1288 : struct sys_fhstat_args /* {
1289 : syscallarg(const fhandle_t *) fhp;
1290 : syscallarg(struct stat *) sb;
1291 0 : } */ *uap = v;
1292 0 : struct stat sb;
1293 : int error;
1294 0 : fhandle_t fh;
1295 : struct mount *mp;
1296 0 : struct vnode *vp;
1297 :
1298 : /*
1299 : * Must be super user
1300 : */
1301 0 : if ((error = suser(p)))
1302 0 : return (error);
1303 :
1304 0 : if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1305 0 : return (error);
1306 :
1307 0 : if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
1308 0 : return (ESTALE);
1309 0 : if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
1310 0 : return (error);
1311 0 : error = vn_stat(vp, &sb, p);
1312 0 : vput(vp);
1313 0 : if (error)
1314 0 : return (error);
1315 0 : error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
1316 0 : return (error);
1317 0 : }
1318 :
1319 : int
1320 0 : sys_fhstatfs(struct proc *p, void *v, register_t *retval)
1321 : {
1322 : struct sys_fhstatfs_args /* {
1323 : syscallarg(const fhandle_t *) fhp;
1324 : syscallarg(struct statfs *) buf;
1325 0 : } */ *uap = v;
1326 : struct statfs *sp;
1327 0 : fhandle_t fh;
1328 : struct mount *mp;
1329 0 : struct vnode *vp;
1330 : int error;
1331 :
1332 : /*
1333 : * Must be super user
1334 : */
1335 0 : if ((error = suser(p)))
1336 0 : return (error);
1337 :
1338 0 : if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
1339 0 : return (error);
1340 :
1341 0 : if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
1342 0 : return (ESTALE);
1343 0 : if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
1344 0 : return (error);
1345 0 : mp = vp->v_mount;
1346 0 : sp = &mp->mnt_stat;
1347 0 : vput(vp);
1348 0 : if ((error = VFS_STATFS(mp, sp, p)) != 0)
1349 0 : return (error);
1350 0 : sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
1351 0 : return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
1352 0 : }
1353 :
1354 : /*
1355 : * Create a special file or named pipe.
1356 : */
1357 : int
1358 0 : sys_mknod(struct proc *p, void *v, register_t *retval)
1359 : {
1360 : struct sys_mknod_args /* {
1361 : syscallarg(const char *) path;
1362 : syscallarg(mode_t) mode;
1363 : syscallarg(int) dev;
1364 0 : } */ *uap = v;
1365 :
1366 0 : return (domknodat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode),
1367 0 : SCARG(uap, dev)));
1368 : }
1369 :
1370 : int
1371 0 : sys_mknodat(struct proc *p, void *v, register_t *retval)
1372 : {
1373 : struct sys_mknodat_args /* {
1374 : syscallarg(int) fd;
1375 : syscallarg(const char *) path;
1376 : syscallarg(mode_t) mode;
1377 : syscallarg(dev_t) dev;
1378 0 : } */ *uap = v;
1379 :
1380 0 : return (domknodat(p, SCARG(uap, fd), SCARG(uap, path),
1381 0 : SCARG(uap, mode), SCARG(uap, dev)));
1382 : }
1383 :
1384 : int
1385 0 : domknodat(struct proc *p, int fd, const char *path, mode_t mode, dev_t dev)
1386 : {
1387 : struct vnode *vp;
1388 0 : struct vattr vattr;
1389 : int error;
1390 0 : struct nameidata nd;
1391 :
1392 0 : if (dev == VNOVAL)
1393 0 : return (EINVAL);
1394 0 : NDINITAT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, fd, path, p);
1395 0 : nd.ni_pledge = PLEDGE_DPATH;
1396 0 : nd.ni_unveil = UNVEIL_CREATE;
1397 0 : if ((error = namei(&nd)) != 0)
1398 0 : return (error);
1399 0 : vp = nd.ni_vp;
1400 0 : if (!S_ISFIFO(mode) || dev != 0) {
1401 0 : if ((nd.ni_dvp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
1402 0 : (error = suser(p)) != 0)
1403 : goto out;
1404 0 : if (p->p_fd->fd_rdir) {
1405 : error = EINVAL;
1406 0 : goto out;
1407 : }
1408 : }
1409 0 : if (vp != NULL)
1410 0 : error = EEXIST;
1411 : else {
1412 0 : VATTR_NULL(&vattr);
1413 0 : vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask;
1414 0 : if ((p->p_p->ps_flags & PS_PLEDGE))
1415 0 : vattr.va_mode &= ACCESSPERMS;
1416 0 : vattr.va_rdev = dev;
1417 :
1418 0 : switch (mode & S_IFMT) {
1419 : case S_IFMT: /* used by badsect to flag bad sectors */
1420 0 : vattr.va_type = VBAD;
1421 0 : break;
1422 : case S_IFCHR:
1423 0 : vattr.va_type = VCHR;
1424 0 : break;
1425 : case S_IFBLK:
1426 0 : vattr.va_type = VBLK;
1427 0 : break;
1428 : case S_IFIFO:
1429 : #ifndef FIFO
1430 : error = EOPNOTSUPP;
1431 : break;
1432 : #else
1433 0 : if (dev == 0) {
1434 0 : vattr.va_type = VFIFO;
1435 0 : break;
1436 : }
1437 : /* FALLTHROUGH */
1438 : #endif /* FIFO */
1439 : default:
1440 : error = EINVAL;
1441 0 : break;
1442 : }
1443 : }
1444 : out:
1445 0 : if (!error) {
1446 0 : error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1447 0 : vput(nd.ni_dvp);
1448 0 : } else {
1449 0 : VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1450 0 : if (nd.ni_dvp == vp)
1451 0 : vrele(nd.ni_dvp);
1452 : else
1453 0 : vput(nd.ni_dvp);
1454 0 : if (vp)
1455 0 : vrele(vp);
1456 : }
1457 0 : return (error);
1458 0 : }
1459 :
1460 : /*
1461 : * Create a named pipe.
1462 : */
1463 : int
1464 0 : sys_mkfifo(struct proc *p, void *v, register_t *retval)
1465 : {
1466 : struct sys_mkfifo_args /* {
1467 : syscallarg(const char *) path;
1468 : syscallarg(mode_t) mode;
1469 0 : } */ *uap = v;
1470 :
1471 0 : return (domknodat(p, AT_FDCWD, SCARG(uap, path),
1472 0 : (SCARG(uap, mode) & ALLPERMS) | S_IFIFO, 0));
1473 : }
1474 :
1475 : int
1476 0 : sys_mkfifoat(struct proc *p, void *v, register_t *retval)
1477 : {
1478 : struct sys_mkfifoat_args /* {
1479 : syscallarg(int) fd;
1480 : syscallarg(const char *) path;
1481 : syscallarg(mode_t) mode;
1482 0 : } */ *uap = v;
1483 :
1484 0 : return (domknodat(p, SCARG(uap, fd), SCARG(uap, path),
1485 0 : (SCARG(uap, mode) & ALLPERMS) | S_IFIFO, 0));
1486 : }
1487 :
1488 : /*
1489 : * Make a hard file link.
1490 : */
1491 : int
1492 0 : sys_link(struct proc *p, void *v, register_t *retval)
1493 : {
1494 : struct sys_link_args /* {
1495 : syscallarg(const char *) path;
1496 : syscallarg(const char *) link;
1497 0 : } */ *uap = v;
1498 :
1499 0 : return (dolinkat(p, AT_FDCWD, SCARG(uap, path), AT_FDCWD,
1500 0 : SCARG(uap, link), AT_SYMLINK_FOLLOW));
1501 : }
1502 :
1503 : int
1504 0 : sys_linkat(struct proc *p, void *v, register_t *retval)
1505 : {
1506 : struct sys_linkat_args /* {
1507 : syscallarg(int) fd1;
1508 : syscallarg(const char *) path1;
1509 : syscallarg(int) fd2;
1510 : syscallarg(const char *) path2;
1511 : syscallarg(int) flag;
1512 0 : } */ *uap = v;
1513 :
1514 0 : return (dolinkat(p, SCARG(uap, fd1), SCARG(uap, path1),
1515 0 : SCARG(uap, fd2), SCARG(uap, path2), SCARG(uap, flag)));
1516 : }
1517 :
1518 : int
1519 0 : dolinkat(struct proc *p, int fd1, const char *path1, int fd2,
1520 : const char *path2, int flag)
1521 : {
1522 : struct vnode *vp;
1523 0 : struct nameidata nd;
1524 : int error, follow;
1525 : int flags;
1526 :
1527 0 : if (flag & ~AT_SYMLINK_FOLLOW)
1528 0 : return (EINVAL);
1529 :
1530 0 : follow = (flag & AT_SYMLINK_FOLLOW) ? FOLLOW : NOFOLLOW;
1531 0 : NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd1, path1, p);
1532 0 : nd.ni_pledge = PLEDGE_RPATH;
1533 0 : nd.ni_unveil = UNVEIL_READ;
1534 0 : if ((error = namei(&nd)) != 0)
1535 0 : return (error);
1536 0 : vp = nd.ni_vp;
1537 :
1538 : flags = LOCKPARENT;
1539 0 : if (vp->v_type == VDIR) {
1540 : flags |= STRIPSLASHES;
1541 0 : }
1542 :
1543 0 : NDINITAT(&nd, CREATE, flags, UIO_USERSPACE, fd2, path2, p);
1544 0 : nd.ni_pledge = PLEDGE_CPATH;
1545 0 : nd.ni_unveil = UNVEIL_CREATE;
1546 0 : if ((error = namei(&nd)) != 0)
1547 : goto out;
1548 0 : if (nd.ni_vp) {
1549 0 : VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1550 0 : if (nd.ni_dvp == nd.ni_vp)
1551 0 : vrele(nd.ni_dvp);
1552 : else
1553 0 : vput(nd.ni_dvp);
1554 0 : vrele(nd.ni_vp);
1555 : error = EEXIST;
1556 0 : goto out;
1557 : }
1558 0 : error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1559 : out:
1560 0 : vrele(vp);
1561 0 : return (error);
1562 0 : }
1563 :
1564 : /*
1565 : * Make a symbolic link.
1566 : */
1567 : int
1568 0 : sys_symlink(struct proc *p, void *v, register_t *retval)
1569 : {
1570 : struct sys_symlink_args /* {
1571 : syscallarg(const char *) path;
1572 : syscallarg(const char *) link;
1573 0 : } */ *uap = v;
1574 :
1575 0 : return (dosymlinkat(p, SCARG(uap, path), AT_FDCWD, SCARG(uap, link)));
1576 : }
1577 :
1578 : int
1579 0 : sys_symlinkat(struct proc *p, void *v, register_t *retval)
1580 : {
1581 : struct sys_symlinkat_args /* {
1582 : syscallarg(const char *) path;
1583 : syscallarg(int) fd;
1584 : syscallarg(const char *) link;
1585 0 : } */ *uap = v;
1586 :
1587 0 : return (dosymlinkat(p, SCARG(uap, path), SCARG(uap, fd),
1588 0 : SCARG(uap, link)));
1589 : }
1590 :
1591 : int
1592 0 : dosymlinkat(struct proc *p, const char *upath, int fd, const char *link)
1593 : {
1594 0 : struct vattr vattr;
1595 : char *path;
1596 : int error;
1597 0 : struct nameidata nd;
1598 :
1599 0 : path = pool_get(&namei_pool, PR_WAITOK);
1600 0 : error = copyinstr(upath, path, MAXPATHLEN, NULL);
1601 0 : if (error)
1602 : goto out;
1603 0 : NDINITAT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, fd, link, p);
1604 0 : nd.ni_pledge = PLEDGE_CPATH;
1605 0 : nd.ni_unveil = UNVEIL_CREATE;
1606 0 : if ((error = namei(&nd)) != 0)
1607 : goto out;
1608 0 : if (nd.ni_vp) {
1609 0 : VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1610 0 : if (nd.ni_dvp == nd.ni_vp)
1611 0 : vrele(nd.ni_dvp);
1612 : else
1613 0 : vput(nd.ni_dvp);
1614 0 : vrele(nd.ni_vp);
1615 : error = EEXIST;
1616 0 : goto out;
1617 : }
1618 0 : VATTR_NULL(&vattr);
1619 0 : vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1620 0 : error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1621 : out:
1622 0 : pool_put(&namei_pool, path);
1623 0 : return (error);
1624 0 : }
1625 :
1626 : /*
1627 : * Delete a name from the filesystem.
1628 : */
1629 : int
1630 0 : sys_unlink(struct proc *p, void *v, register_t *retval)
1631 : {
1632 : struct sys_unlink_args /* {
1633 : syscallarg(const char *) path;
1634 0 : } */ *uap = v;
1635 :
1636 0 : return (dounlinkat(p, AT_FDCWD, SCARG(uap, path), 0));
1637 : }
1638 :
1639 : int
1640 0 : sys_unlinkat(struct proc *p, void *v, register_t *retval)
1641 : {
1642 : struct sys_unlinkat_args /* {
1643 : syscallarg(int) fd;
1644 : syscallarg(const char *) path;
1645 : syscallarg(int) flag;
1646 0 : } */ *uap = v;
1647 :
1648 0 : return (dounlinkat(p, SCARG(uap, fd), SCARG(uap, path),
1649 0 : SCARG(uap, flag)));
1650 : }
1651 :
1652 : int
1653 0 : dounlinkat(struct proc *p, int fd, const char *path, int flag)
1654 : {
1655 : struct vnode *vp;
1656 : int error;
1657 0 : struct nameidata nd;
1658 :
1659 0 : if (flag & ~AT_REMOVEDIR)
1660 0 : return (EINVAL);
1661 :
1662 0 : NDINITAT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
1663 : fd, path, p);
1664 0 : nd.ni_pledge = PLEDGE_CPATH;
1665 0 : nd.ni_unveil = UNVEIL_CREATE;
1666 0 : if ((error = namei(&nd)) != 0)
1667 0 : return (error);
1668 0 : vp = nd.ni_vp;
1669 :
1670 0 : if (flag & AT_REMOVEDIR) {
1671 0 : if (vp->v_type != VDIR) {
1672 : error = ENOTDIR;
1673 0 : goto out;
1674 : }
1675 : /*
1676 : * No rmdir "." please.
1677 : */
1678 0 : if (nd.ni_dvp == vp) {
1679 : error = EINVAL;
1680 0 : goto out;
1681 : }
1682 : /*
1683 : * A mounted on directory cannot be deleted.
1684 : */
1685 0 : if (vp->v_mountedhere != NULL) {
1686 : error = EBUSY;
1687 0 : goto out;
1688 : }
1689 : }
1690 :
1691 : /*
1692 : * The root of a mounted filesystem cannot be deleted.
1693 : */
1694 0 : if (vp->v_flag & VROOT)
1695 0 : error = EBUSY;
1696 : out:
1697 0 : if (!error) {
1698 0 : if (flag & AT_REMOVEDIR) {
1699 0 : error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1700 0 : } else {
1701 0 : (void)uvm_vnp_uncache(vp);
1702 0 : error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1703 : }
1704 : } else {
1705 0 : VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1706 0 : if (nd.ni_dvp == vp)
1707 0 : vrele(nd.ni_dvp);
1708 : else
1709 0 : vput(nd.ni_dvp);
1710 0 : vput(vp);
1711 : }
1712 0 : return (error);
1713 0 : }
1714 :
1715 : /*
1716 : * Reposition read/write file offset.
1717 : */
1718 : int
1719 0 : sys_lseek(struct proc *p, void *v, register_t *retval)
1720 : {
1721 : struct sys_lseek_args /* {
1722 : syscallarg(int) fd;
1723 : syscallarg(int) pad;
1724 : syscallarg(off_t) offset;
1725 : syscallarg(int) whence;
1726 0 : } */ *uap = v;
1727 0 : struct filedesc *fdp = p->p_fd;
1728 : struct file *fp;
1729 0 : off_t offset;
1730 : int error;
1731 :
1732 0 : if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
1733 0 : return (EBADF);
1734 0 : if (fp->f_ops->fo_seek == NULL) {
1735 : error = ESPIPE;
1736 0 : goto bad;
1737 : }
1738 0 : offset = SCARG(uap, offset);
1739 :
1740 0 : error = (*fp->f_ops->fo_seek)(fp, &offset, SCARG(uap, whence), p);
1741 0 : if (error)
1742 : goto bad;
1743 :
1744 0 : *(off_t *)retval = offset;
1745 0 : mtx_enter(&fp->f_mtx);
1746 0 : fp->f_seek++;
1747 0 : mtx_leave(&fp->f_mtx);
1748 0 : error = 0;
1749 : bad:
1750 0 : FRELE(fp, p);
1751 0 : return (error);
1752 0 : }
1753 :
1754 : /*
1755 : * Check access permissions.
1756 : */
1757 : int
1758 0 : sys_access(struct proc *p, void *v, register_t *retval)
1759 : {
1760 : struct sys_access_args /* {
1761 : syscallarg(const char *) path;
1762 : syscallarg(int) amode;
1763 0 : } */ *uap = v;
1764 :
1765 0 : return (dofaccessat(p, AT_FDCWD, SCARG(uap, path),
1766 0 : SCARG(uap, amode), 0));
1767 : }
1768 :
1769 : int
1770 0 : sys_faccessat(struct proc *p, void *v, register_t *retval)
1771 : {
1772 : struct sys_faccessat_args /* {
1773 : syscallarg(int) fd;
1774 : syscallarg(const char *) path;
1775 : syscallarg(int) amode;
1776 : syscallarg(int) flag;
1777 0 : } */ *uap = v;
1778 :
1779 0 : return (dofaccessat(p, SCARG(uap, fd), SCARG(uap, path),
1780 0 : SCARG(uap, amode), SCARG(uap, flag)));
1781 : }
1782 :
1783 : int
1784 0 : dofaccessat(struct proc *p, int fd, const char *path, int amode, int flag)
1785 : {
1786 : struct vnode *vp;
1787 : struct ucred *newcred, *oldcred;
1788 0 : struct nameidata nd;
1789 : int error;
1790 :
1791 0 : if (amode & ~(R_OK | W_OK | X_OK))
1792 0 : return (EINVAL);
1793 0 : if (flag & ~AT_EACCESS)
1794 0 : return (EINVAL);
1795 :
1796 : newcred = NULL;
1797 0 : oldcred = p->p_ucred;
1798 :
1799 : /*
1800 : * If access as real ids was requested and they really differ,
1801 : * give the thread new creds with them reset
1802 : */
1803 0 : if ((flag & AT_EACCESS) == 0 &&
1804 0 : (oldcred->cr_uid != oldcred->cr_ruid ||
1805 0 : (oldcred->cr_gid != oldcred->cr_rgid))) {
1806 0 : p->p_ucred = newcred = crdup(oldcred);
1807 0 : newcred->cr_uid = newcred->cr_ruid;
1808 0 : newcred->cr_gid = newcred->cr_rgid;
1809 0 : }
1810 :
1811 0 : NDINITAT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p);
1812 0 : nd.ni_pledge = PLEDGE_RPATH;
1813 0 : nd.ni_unveil = UNVEIL_INSPECT;
1814 0 : if ((error = namei(&nd)) != 0)
1815 : goto out;
1816 0 : vp = nd.ni_vp;
1817 :
1818 : /* Flags == 0 means only check for existence. */
1819 0 : if (amode) {
1820 : int vflags = 0;
1821 :
1822 0 : if (amode & R_OK)
1823 0 : vflags |= VREAD;
1824 0 : if (amode & W_OK)
1825 0 : vflags |= VWRITE;
1826 0 : if (amode & X_OK)
1827 0 : vflags |= VEXEC;
1828 :
1829 0 : error = VOP_ACCESS(vp, vflags, p->p_ucred, p);
1830 0 : if (!error && (vflags & VWRITE))
1831 0 : error = vn_writechk(vp);
1832 0 : }
1833 0 : vput(vp);
1834 : out:
1835 0 : if (newcred != NULL) {
1836 0 : p->p_ucred = oldcred;
1837 0 : crfree(newcred);
1838 0 : }
1839 0 : return (error);
1840 0 : }
1841 :
1842 : /*
1843 : * Get file status; this version follows links.
1844 : */
1845 : int
1846 0 : sys_stat(struct proc *p, void *v, register_t *retval)
1847 : {
1848 : struct sys_stat_args /* {
1849 : syscallarg(const char *) path;
1850 : syscallarg(struct stat *) ub;
1851 0 : } */ *uap = v;
1852 :
1853 0 : return (dofstatat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, ub), 0));
1854 : }
1855 :
1856 : int
1857 0 : sys_fstatat(struct proc *p, void *v, register_t *retval)
1858 : {
1859 : struct sys_fstatat_args /* {
1860 : syscallarg(int) fd;
1861 : syscallarg(const char *) path;
1862 : syscallarg(struct stat *) buf;
1863 : syscallarg(int) flag;
1864 0 : } */ *uap = v;
1865 :
1866 0 : return (dofstatat(p, SCARG(uap, fd), SCARG(uap, path),
1867 0 : SCARG(uap, buf), SCARG(uap, flag)));
1868 : }
1869 :
1870 : int
1871 0 : dofstatat(struct proc *p, int fd, const char *path, struct stat *buf, int flag)
1872 : {
1873 0 : struct stat sb;
1874 : int error, follow;
1875 0 : struct nameidata nd;
1876 :
1877 0 : if (flag & ~AT_SYMLINK_NOFOLLOW)
1878 0 : return (EINVAL);
1879 :
1880 :
1881 0 : follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
1882 0 : NDINITAT(&nd, LOOKUP, follow | LOCKLEAF, UIO_USERSPACE, fd, path, p);
1883 0 : nd.ni_pledge = PLEDGE_RPATH;
1884 0 : nd.ni_unveil = UNVEIL_INSPECT;
1885 0 : if ((error = namei(&nd)) != 0)
1886 0 : return (error);
1887 0 : error = vn_stat(nd.ni_vp, &sb, p);
1888 0 : vput(nd.ni_vp);
1889 0 : if (error)
1890 0 : return (error);
1891 0 : if (nd.ni_pledge & PLEDGE_STATLIE) {
1892 0 : if (S_ISDIR(sb.st_mode) || S_ISLNK(sb.st_mode)) {
1893 0 : if (sb.st_uid >= 1000) {
1894 0 : sb.st_uid = p->p_ucred->cr_uid;
1895 0 : sb.st_gid = p->p_ucred->cr_gid;;
1896 0 : }
1897 0 : sb.st_gen = 0;
1898 : } else
1899 0 : return (ENOENT);
1900 0 : }
1901 : /* Don't let non-root see generation numbers (for NFS security) */
1902 0 : if (suser(p))
1903 0 : sb.st_gen = 0;
1904 0 : error = copyout(&sb, buf, sizeof(sb));
1905 : #ifdef KTRACE
1906 0 : if (error == 0 && KTRPOINT(p, KTR_STRUCT))
1907 0 : ktrstat(p, &sb);
1908 : #endif
1909 0 : return (error);
1910 0 : }
1911 :
1912 : /*
1913 : * Get file status; this version does not follow links.
1914 : */
1915 : int
1916 0 : sys_lstat(struct proc *p, void *v, register_t *retval)
1917 : {
1918 : struct sys_lstat_args /* {
1919 : syscallarg(const char *) path;
1920 : syscallarg(struct stat *) ub;
1921 0 : } */ *uap = v;
1922 :
1923 0 : return (dofstatat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, ub),
1924 : AT_SYMLINK_NOFOLLOW));
1925 : }
1926 :
1927 : /*
1928 : * Get configurable pathname variables.
1929 : */
1930 : int
1931 0 : sys_pathconf(struct proc *p, void *v, register_t *retval)
1932 : {
1933 : struct sys_pathconf_args /* {
1934 : syscallarg(const char *) path;
1935 : syscallarg(int) name;
1936 0 : } */ *uap = v;
1937 : int error;
1938 0 : struct nameidata nd;
1939 :
1940 0 : NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1941 : SCARG(uap, path), p);
1942 0 : nd.ni_pledge = PLEDGE_RPATH;
1943 0 : nd.ni_unveil = UNVEIL_READ;
1944 0 : if ((error = namei(&nd)) != 0)
1945 0 : return (error);
1946 0 : error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1947 0 : vput(nd.ni_vp);
1948 0 : return (error);
1949 0 : }
1950 :
1951 : /*
1952 : * Return target name of a symbolic link.
1953 : */
1954 : int
1955 0 : sys_readlink(struct proc *p, void *v, register_t *retval)
1956 : {
1957 : struct sys_readlink_args /* {
1958 : syscallarg(const char *) path;
1959 : syscallarg(char *) buf;
1960 : syscallarg(size_t) count;
1961 0 : } */ *uap = v;
1962 :
1963 0 : return (doreadlinkat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, buf),
1964 0 : SCARG(uap, count), retval));
1965 : }
1966 :
1967 : int
1968 0 : sys_readlinkat(struct proc *p, void *v, register_t *retval)
1969 : {
1970 : struct sys_readlinkat_args /* {
1971 : syscallarg(int) fd;
1972 : syscallarg(const char *) path;
1973 : syscallarg(char *) buf;
1974 : syscallarg(size_t) count;
1975 0 : } */ *uap = v;
1976 :
1977 0 : return (doreadlinkat(p, SCARG(uap, fd), SCARG(uap, path),
1978 0 : SCARG(uap, buf), SCARG(uap, count), retval));
1979 : }
1980 :
1981 : int
1982 0 : doreadlinkat(struct proc *p, int fd, const char *path, char *buf,
1983 : size_t count, register_t *retval)
1984 : {
1985 : struct vnode *vp;
1986 0 : struct iovec aiov;
1987 0 : struct uio auio;
1988 : int error;
1989 0 : struct nameidata nd;
1990 :
1991 0 : NDINITAT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, fd, path, p);
1992 0 : nd.ni_pledge = PLEDGE_RPATH;
1993 0 : nd.ni_unveil = UNVEIL_INSPECT;
1994 0 : if ((error = namei(&nd)) != 0)
1995 0 : return (error);
1996 0 : vp = nd.ni_vp;
1997 0 : if (vp->v_type != VLNK)
1998 0 : error = EINVAL;
1999 : else {
2000 0 : aiov.iov_base = buf;
2001 0 : aiov.iov_len = count;
2002 0 : auio.uio_iov = &aiov;
2003 0 : auio.uio_iovcnt = 1;
2004 0 : auio.uio_offset = 0;
2005 0 : auio.uio_rw = UIO_READ;
2006 0 : auio.uio_segflg = UIO_USERSPACE;
2007 0 : auio.uio_procp = p;
2008 0 : auio.uio_resid = count;
2009 0 : error = VOP_READLINK(vp, &auio, p->p_ucred);
2010 0 : *retval = count - auio.uio_resid;
2011 : }
2012 0 : vput(vp);
2013 0 : return (error);
2014 0 : }
2015 :
2016 : /*
2017 : * Change flags of a file given a path name.
2018 : */
2019 : int
2020 0 : sys_chflags(struct proc *p, void *v, register_t *retval)
2021 : {
2022 : struct sys_chflags_args /* {
2023 : syscallarg(const char *) path;
2024 : syscallarg(u_int) flags;
2025 0 : } */ *uap = v;
2026 :
2027 0 : return (dochflagsat(p, AT_FDCWD, SCARG(uap, path),
2028 0 : SCARG(uap, flags), 0));
2029 : }
2030 :
2031 : int
2032 0 : sys_chflagsat(struct proc *p, void *v, register_t *retval)
2033 : {
2034 : struct sys_chflagsat_args /* {
2035 : syscallarg(int) fd;
2036 : syscallarg(const char *) path;
2037 : syscallarg(u_int) flags;
2038 : syscallarg(int) atflags;
2039 0 : } */ *uap = v;
2040 :
2041 0 : return (dochflagsat(p, SCARG(uap, fd), SCARG(uap, path),
2042 0 : SCARG(uap, flags), SCARG(uap, atflags)));
2043 : }
2044 :
2045 : int
2046 0 : dochflagsat(struct proc *p, int fd, const char *path, u_int flags, int atflags)
2047 : {
2048 0 : struct nameidata nd;
2049 : int error, follow;
2050 :
2051 0 : if (atflags & ~AT_SYMLINK_NOFOLLOW)
2052 0 : return (EINVAL);
2053 :
2054 0 : follow = (atflags & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
2055 0 : NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
2056 0 : nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH;
2057 0 : nd.ni_unveil = UNVEIL_WRITE;
2058 0 : if ((error = namei(&nd)) != 0)
2059 0 : return (error);
2060 0 : return (dovchflags(p, nd.ni_vp, flags));
2061 0 : }
2062 :
2063 : /*
2064 : * Change flags of a file given a file descriptor.
2065 : */
2066 : int
2067 0 : sys_fchflags(struct proc *p, void *v, register_t *retval)
2068 : {
2069 : struct sys_fchflags_args /* {
2070 : syscallarg(int) fd;
2071 : syscallarg(u_int) flags;
2072 0 : } */ *uap = v;
2073 0 : struct file *fp;
2074 : struct vnode *vp;
2075 : int error;
2076 :
2077 0 : if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
2078 0 : return (error);
2079 0 : vp = fp->f_data;
2080 0 : vref(vp);
2081 0 : FRELE(fp, p);
2082 0 : return (dovchflags(p, vp, SCARG(uap, flags)));
2083 0 : }
2084 :
2085 : int
2086 0 : dovchflags(struct proc *p, struct vnode *vp, u_int flags)
2087 : {
2088 0 : struct vattr vattr;
2089 : int error;
2090 :
2091 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2092 0 : if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY)
2093 0 : error = EROFS;
2094 0 : else if (flags == VNOVAL)
2095 0 : error = EINVAL;
2096 : else {
2097 0 : if (suser(p)) {
2098 0 : if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
2099 0 : != 0)
2100 : goto out;
2101 0 : if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
2102 : error = EINVAL;
2103 0 : goto out;
2104 : }
2105 : }
2106 0 : VATTR_NULL(&vattr);
2107 0 : vattr.va_flags = flags;
2108 0 : error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2109 : }
2110 : out:
2111 0 : vput(vp);
2112 0 : return (error);
2113 0 : }
2114 :
2115 : /*
2116 : * Change mode of a file given path name.
2117 : */
2118 : int
2119 0 : sys_chmod(struct proc *p, void *v, register_t *retval)
2120 : {
2121 : struct sys_chmod_args /* {
2122 : syscallarg(const char *) path;
2123 : syscallarg(mode_t) mode;
2124 0 : } */ *uap = v;
2125 :
2126 0 : return (dofchmodat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode), 0));
2127 : }
2128 :
2129 : int
2130 0 : sys_fchmodat(struct proc *p, void *v, register_t *retval)
2131 : {
2132 : struct sys_fchmodat_args /* {
2133 : syscallarg(int) fd;
2134 : syscallarg(const char *) path;
2135 : syscallarg(mode_t) mode;
2136 : syscallarg(int) flag;
2137 0 : } */ *uap = v;
2138 :
2139 0 : return (dofchmodat(p, SCARG(uap, fd), SCARG(uap, path),
2140 0 : SCARG(uap, mode), SCARG(uap, flag)));
2141 : }
2142 :
2143 : int
2144 0 : dofchmodat(struct proc *p, int fd, const char *path, mode_t mode, int flag)
2145 : {
2146 : struct vnode *vp;
2147 0 : struct vattr vattr;
2148 : int error, follow;
2149 0 : struct nameidata nd;
2150 :
2151 0 : if (mode & ~(S_IFMT | ALLPERMS))
2152 0 : return (EINVAL);
2153 0 : if ((p->p_p->ps_flags & PS_PLEDGE))
2154 0 : mode &= ACCESSPERMS;
2155 0 : if (flag & ~AT_SYMLINK_NOFOLLOW)
2156 0 : return (EINVAL);
2157 :
2158 0 : follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
2159 0 : NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
2160 0 : nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH;
2161 0 : nd.ni_unveil = UNVEIL_WRITE;
2162 0 : if ((error = namei(&nd)) != 0)
2163 0 : return (error);
2164 0 : vp = nd.ni_vp;
2165 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2166 0 : if (vp->v_mount->mnt_flag & MNT_RDONLY)
2167 0 : error = EROFS;
2168 : else {
2169 0 : VATTR_NULL(&vattr);
2170 0 : vattr.va_mode = mode & ALLPERMS;
2171 0 : error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2172 : }
2173 0 : vput(vp);
2174 0 : return (error);
2175 0 : }
2176 :
2177 : /*
2178 : * Change mode of a file given a file descriptor.
2179 : */
2180 : int
2181 0 : sys_fchmod(struct proc *p, void *v, register_t *retval)
2182 : {
2183 : struct sys_fchmod_args /* {
2184 : syscallarg(int) fd;
2185 : syscallarg(mode_t) mode;
2186 0 : } */ *uap = v;
2187 0 : struct vattr vattr;
2188 : struct vnode *vp;
2189 0 : struct file *fp;
2190 0 : mode_t mode = SCARG(uap, mode);
2191 : int error;
2192 :
2193 0 : if (mode & ~(S_IFMT | ALLPERMS))
2194 0 : return (EINVAL);
2195 0 : if ((p->p_p->ps_flags & PS_PLEDGE))
2196 0 : mode &= ACCESSPERMS;
2197 :
2198 0 : if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
2199 0 : return (error);
2200 0 : vp = fp->f_data;
2201 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2202 0 : if (vp->v_mount && vp->v_mount->mnt_flag & MNT_RDONLY)
2203 0 : error = EROFS;
2204 : else {
2205 0 : VATTR_NULL(&vattr);
2206 0 : vattr.va_mode = mode & ALLPERMS;
2207 0 : error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2208 : }
2209 0 : VOP_UNLOCK(vp);
2210 0 : FRELE(fp, p);
2211 0 : return (error);
2212 0 : }
2213 :
2214 : /*
2215 : * Set ownership given a path name.
2216 : */
2217 : int
2218 0 : sys_chown(struct proc *p, void *v, register_t *retval)
2219 : {
2220 : struct sys_chown_args /* {
2221 : syscallarg(const char *) path;
2222 : syscallarg(uid_t) uid;
2223 : syscallarg(gid_t) gid;
2224 0 : } */ *uap = v;
2225 :
2226 0 : return (dofchownat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, uid),
2227 0 : SCARG(uap, gid), 0));
2228 : }
2229 :
2230 : int
2231 0 : sys_fchownat(struct proc *p, void *v, register_t *retval)
2232 : {
2233 : struct sys_fchownat_args /* {
2234 : syscallarg(int) fd;
2235 : syscallarg(const char *) path;
2236 : syscallarg(uid_t) uid;
2237 : syscallarg(gid_t) gid;
2238 : syscallarg(int) flag;
2239 0 : } */ *uap = v;
2240 :
2241 0 : return (dofchownat(p, SCARG(uap, fd), SCARG(uap, path),
2242 0 : SCARG(uap, uid), SCARG(uap, gid), SCARG(uap, flag)));
2243 : }
2244 :
2245 : int
2246 0 : dofchownat(struct proc *p, int fd, const char *path, uid_t uid, gid_t gid,
2247 : int flag)
2248 : {
2249 : struct vnode *vp;
2250 0 : struct vattr vattr;
2251 : int error, follow;
2252 0 : struct nameidata nd;
2253 : mode_t mode;
2254 :
2255 0 : if (flag & ~AT_SYMLINK_NOFOLLOW)
2256 0 : return (EINVAL);
2257 :
2258 0 : follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
2259 0 : NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
2260 0 : nd.ni_pledge = PLEDGE_CHOWN | PLEDGE_RPATH;
2261 0 : nd.ni_unveil = UNVEIL_WRITE;
2262 0 : if ((error = namei(&nd)) != 0)
2263 0 : return (error);
2264 0 : vp = nd.ni_vp;
2265 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2266 0 : if (vp->v_mount->mnt_flag & MNT_RDONLY)
2267 0 : error = EROFS;
2268 : else {
2269 0 : if ((error = pledge_chown(p, uid, gid)))
2270 : goto out;
2271 0 : if ((uid != -1 || gid != -1) &&
2272 0 : (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
2273 0 : (suser(p) || suid_clear)) {
2274 0 : error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
2275 0 : if (error)
2276 : goto out;
2277 0 : mode = vattr.va_mode & ~(VSUID | VSGID);
2278 0 : if (mode == vattr.va_mode)
2279 : mode = VNOVAL;
2280 0 : } else
2281 : mode = VNOVAL;
2282 0 : VATTR_NULL(&vattr);
2283 0 : vattr.va_uid = uid;
2284 0 : vattr.va_gid = gid;
2285 0 : vattr.va_mode = mode;
2286 0 : error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2287 : }
2288 : out:
2289 0 : vput(vp);
2290 0 : return (error);
2291 0 : }
2292 :
2293 : /*
2294 : * Set ownership given a path name, without following links.
2295 : */
2296 : int
2297 0 : sys_lchown(struct proc *p, void *v, register_t *retval)
2298 : {
2299 : struct sys_lchown_args /* {
2300 : syscallarg(const char *) path;
2301 : syscallarg(uid_t) uid;
2302 : syscallarg(gid_t) gid;
2303 0 : } */ *uap = v;
2304 : struct vnode *vp;
2305 0 : struct vattr vattr;
2306 : int error;
2307 0 : struct nameidata nd;
2308 : mode_t mode;
2309 0 : uid_t uid = SCARG(uap, uid);
2310 0 : gid_t gid = SCARG(uap, gid);
2311 :
2312 0 : NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2313 0 : nd.ni_pledge = PLEDGE_CHOWN | PLEDGE_RPATH;
2314 0 : nd.ni_unveil = UNVEIL_WRITE;
2315 0 : if ((error = namei(&nd)) != 0)
2316 0 : return (error);
2317 0 : vp = nd.ni_vp;
2318 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2319 0 : if (vp->v_mount->mnt_flag & MNT_RDONLY)
2320 0 : error = EROFS;
2321 : else {
2322 0 : if ((error = pledge_chown(p, uid, gid)))
2323 : goto out;
2324 0 : if ((uid != -1 || gid != -1) &&
2325 0 : (vp->v_mount->mnt_flag & MNT_NOPERM) == 0 &&
2326 0 : (suser(p) || suid_clear)) {
2327 0 : error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
2328 0 : if (error)
2329 : goto out;
2330 0 : mode = vattr.va_mode & ~(VSUID | VSGID);
2331 0 : if (mode == vattr.va_mode)
2332 : mode = VNOVAL;
2333 0 : } else
2334 : mode = VNOVAL;
2335 0 : VATTR_NULL(&vattr);
2336 0 : vattr.va_uid = uid;
2337 0 : vattr.va_gid = gid;
2338 0 : vattr.va_mode = mode;
2339 0 : error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2340 : }
2341 : out:
2342 0 : vput(vp);
2343 0 : return (error);
2344 0 : }
2345 :
2346 : /*
2347 : * Set ownership given a file descriptor.
2348 : */
2349 : int
2350 0 : sys_fchown(struct proc *p, void *v, register_t *retval)
2351 : {
2352 : struct sys_fchown_args /* {
2353 : syscallarg(int) fd;
2354 : syscallarg(uid_t) uid;
2355 : syscallarg(gid_t) gid;
2356 0 : } */ *uap = v;
2357 : struct vnode *vp;
2358 0 : struct vattr vattr;
2359 : int error;
2360 0 : struct file *fp;
2361 : mode_t mode;
2362 0 : uid_t uid = SCARG(uap, uid);
2363 0 : gid_t gid = SCARG(uap, gid);
2364 :
2365 0 : if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
2366 0 : return (error);
2367 0 : vp = fp->f_data;
2368 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2369 0 : if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_RDONLY))
2370 0 : error = EROFS;
2371 : else {
2372 0 : if ((error = pledge_chown(p, uid, gid)))
2373 : goto out;
2374 0 : if ((uid != -1 || gid != -1) &&
2375 0 : (vp->v_mount &&
2376 0 : (vp->v_mount->mnt_flag & MNT_NOPERM) == 0) &&
2377 0 : (suser(p) || suid_clear)) {
2378 0 : error = VOP_GETATTR(vp, &vattr, p->p_ucred, p);
2379 0 : if (error)
2380 : goto out;
2381 0 : mode = vattr.va_mode & ~(VSUID | VSGID);
2382 0 : if (mode == vattr.va_mode)
2383 : mode = VNOVAL;
2384 0 : } else
2385 : mode = VNOVAL;
2386 0 : VATTR_NULL(&vattr);
2387 0 : vattr.va_uid = uid;
2388 0 : vattr.va_gid = gid;
2389 0 : vattr.va_mode = mode;
2390 0 : error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2391 : }
2392 : out:
2393 0 : VOP_UNLOCK(vp);
2394 0 : FRELE(fp, p);
2395 0 : return (error);
2396 0 : }
2397 :
2398 : /*
2399 : * Set the access and modification times given a path name.
2400 : */
2401 : int
2402 0 : sys_utimes(struct proc *p, void *v, register_t *retval)
2403 : {
2404 : struct sys_utimes_args /* {
2405 : syscallarg(const char *) path;
2406 : syscallarg(const struct timeval *) tptr;
2407 0 : } */ *uap = v;
2408 :
2409 0 : struct timespec ts[2];
2410 0 : struct timeval tv[2];
2411 : const struct timeval *tvp;
2412 : int error;
2413 :
2414 0 : tvp = SCARG(uap, tptr);
2415 0 : if (tvp != NULL) {
2416 0 : error = copyin(tvp, tv, sizeof(tv));
2417 0 : if (error)
2418 0 : return (error);
2419 0 : TIMEVAL_TO_TIMESPEC(&tv[0], &ts[0]);
2420 0 : TIMEVAL_TO_TIMESPEC(&tv[1], &ts[1]);
2421 0 : } else
2422 0 : ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW;
2423 :
2424 0 : return (doutimensat(p, AT_FDCWD, SCARG(uap, path), ts, 0));
2425 0 : }
2426 :
2427 : int
2428 0 : sys_utimensat(struct proc *p, void *v, register_t *retval)
2429 : {
2430 : struct sys_utimensat_args /* {
2431 : syscallarg(int) fd;
2432 : syscallarg(const char *) path;
2433 : syscallarg(const struct timespec *) times;
2434 : syscallarg(int) flag;
2435 0 : } */ *uap = v;
2436 :
2437 0 : struct timespec ts[2];
2438 : const struct timespec *tsp;
2439 : int error;
2440 :
2441 0 : tsp = SCARG(uap, times);
2442 0 : if (tsp != NULL) {
2443 0 : error = copyin(tsp, ts, sizeof(ts));
2444 0 : if (error)
2445 0 : return (error);
2446 : } else
2447 0 : ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW;
2448 :
2449 0 : return (doutimensat(p, SCARG(uap, fd), SCARG(uap, path), ts,
2450 0 : SCARG(uap, flag)));
2451 0 : }
2452 :
2453 : int
2454 0 : doutimensat(struct proc *p, int fd, const char *path,
2455 : struct timespec ts[2], int flag)
2456 : {
2457 : struct vnode *vp;
2458 : int error, follow;
2459 0 : struct nameidata nd;
2460 :
2461 0 : if (flag & ~AT_SYMLINK_NOFOLLOW)
2462 0 : return (EINVAL);
2463 :
2464 0 : follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
2465 0 : NDINITAT(&nd, LOOKUP, follow, UIO_USERSPACE, fd, path, p);
2466 0 : nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH;
2467 0 : nd.ni_unveil = UNVEIL_WRITE;
2468 0 : if ((error = namei(&nd)) != 0)
2469 0 : return (error);
2470 0 : vp = nd.ni_vp;
2471 :
2472 0 : return (dovutimens(p, vp, ts));
2473 0 : }
2474 :
2475 : int
2476 0 : dovutimens(struct proc *p, struct vnode *vp, struct timespec ts[2])
2477 : {
2478 0 : struct vattr vattr;
2479 0 : struct timespec now;
2480 : int error;
2481 :
2482 : #ifdef KTRACE
2483 : /* if they're both UTIME_NOW, then don't report either */
2484 0 : if ((ts[0].tv_nsec != UTIME_NOW || ts[1].tv_nsec != UTIME_NOW) &&
2485 0 : KTRPOINT(p, KTR_STRUCT)) {
2486 0 : ktrabstimespec(p, &ts[0]);
2487 0 : ktrabstimespec(p, &ts[1]);
2488 0 : }
2489 : #endif
2490 :
2491 0 : VATTR_NULL(&vattr);
2492 :
2493 : /* make sure ctime is updated even if neither mtime nor atime is */
2494 0 : vattr.va_vaflags = VA_UTIMES_CHANGE;
2495 :
2496 0 : if (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
2497 0 : if (ts[0].tv_nsec == UTIME_NOW && ts[1].tv_nsec == UTIME_NOW)
2498 0 : vattr.va_vaflags |= VA_UTIMES_NULL;
2499 :
2500 0 : getnanotime(&now);
2501 0 : if (ts[0].tv_nsec == UTIME_NOW)
2502 0 : ts[0] = now;
2503 0 : if (ts[1].tv_nsec == UTIME_NOW)
2504 0 : ts[1] = now;
2505 : }
2506 :
2507 0 : if (ts[0].tv_nsec != UTIME_OMIT) {
2508 0 : if (ts[0].tv_nsec < 0 || ts[0].tv_nsec >= 1000000000) {
2509 0 : vrele(vp);
2510 0 : return (EINVAL);
2511 : }
2512 0 : vattr.va_atime = ts[0];
2513 0 : }
2514 0 : if (ts[1].tv_nsec != UTIME_OMIT) {
2515 0 : if (ts[1].tv_nsec < 0 || ts[1].tv_nsec >= 1000000000) {
2516 0 : vrele(vp);
2517 0 : return (EINVAL);
2518 : }
2519 0 : vattr.va_mtime = ts[1];
2520 0 : }
2521 :
2522 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2523 0 : if (vp->v_mount->mnt_flag & MNT_RDONLY)
2524 0 : error = EROFS;
2525 : else
2526 0 : error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2527 0 : vput(vp);
2528 0 : return (error);
2529 0 : }
2530 :
2531 : /*
2532 : * Set the access and modification times given a file descriptor.
2533 : */
2534 : int
2535 0 : sys_futimes(struct proc *p, void *v, register_t *retval)
2536 : {
2537 : struct sys_futimes_args /* {
2538 : syscallarg(int) fd;
2539 : syscallarg(const struct timeval *) tptr;
2540 0 : } */ *uap = v;
2541 0 : struct timeval tv[2];
2542 0 : struct timespec ts[2];
2543 : const struct timeval *tvp;
2544 : int error;
2545 :
2546 0 : tvp = SCARG(uap, tptr);
2547 0 : if (tvp != NULL) {
2548 0 : error = copyin(tvp, tv, sizeof(tv));
2549 0 : if (error)
2550 0 : return (error);
2551 0 : TIMEVAL_TO_TIMESPEC(&tv[0], &ts[0]);
2552 0 : TIMEVAL_TO_TIMESPEC(&tv[1], &ts[1]);
2553 0 : } else
2554 0 : ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW;
2555 :
2556 0 : return (dofutimens(p, SCARG(uap, fd), ts));
2557 0 : }
2558 :
2559 : int
2560 0 : sys_futimens(struct proc *p, void *v, register_t *retval)
2561 : {
2562 : struct sys_futimens_args /* {
2563 : syscallarg(int) fd;
2564 : syscallarg(const struct timespec *) times;
2565 0 : } */ *uap = v;
2566 0 : struct timespec ts[2];
2567 : const struct timespec *tsp;
2568 : int error;
2569 :
2570 0 : tsp = SCARG(uap, times);
2571 0 : if (tsp != NULL) {
2572 0 : error = copyin(tsp, ts, sizeof(ts));
2573 0 : if (error)
2574 0 : return (error);
2575 : } else
2576 0 : ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW;
2577 :
2578 0 : return (dofutimens(p, SCARG(uap, fd), ts));
2579 0 : }
2580 :
2581 : int
2582 0 : dofutimens(struct proc *p, int fd, struct timespec ts[2])
2583 : {
2584 0 : struct file *fp;
2585 : struct vnode *vp;
2586 : int error;
2587 :
2588 0 : if ((error = getvnode(p, fd, &fp)) != 0)
2589 0 : return (error);
2590 0 : vp = fp->f_data;
2591 0 : vref(vp);
2592 0 : FRELE(fp, p);
2593 :
2594 0 : return (dovutimens(p, vp, ts));
2595 0 : }
2596 :
2597 : /*
2598 : * Truncate a file given its path name.
2599 : */
2600 : int
2601 0 : sys_truncate(struct proc *p, void *v, register_t *retval)
2602 : {
2603 : struct sys_truncate_args /* {
2604 : syscallarg(const char *) path;
2605 : syscallarg(int) pad;
2606 : syscallarg(off_t) length;
2607 0 : } */ *uap = v;
2608 : struct vnode *vp;
2609 0 : struct vattr vattr;
2610 : int error;
2611 0 : struct nameidata nd;
2612 :
2613 0 : NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2614 0 : nd.ni_pledge = PLEDGE_FATTR | PLEDGE_RPATH;
2615 0 : nd.ni_unveil = UNVEIL_WRITE;
2616 0 : if ((error = namei(&nd)) != 0)
2617 0 : return (error);
2618 0 : vp = nd.ni_vp;
2619 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2620 0 : if (vp->v_type == VDIR)
2621 0 : error = EISDIR;
2622 0 : else if ((error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0 &&
2623 0 : (error = vn_writechk(vp)) == 0) {
2624 0 : VATTR_NULL(&vattr);
2625 0 : vattr.va_size = SCARG(uap, length);
2626 0 : error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2627 0 : }
2628 0 : vput(vp);
2629 0 : return (error);
2630 0 : }
2631 :
2632 : /*
2633 : * Truncate a file given a file descriptor.
2634 : */
2635 : int
2636 0 : sys_ftruncate(struct proc *p, void *v, register_t *retval)
2637 : {
2638 : struct sys_ftruncate_args /* {
2639 : syscallarg(int) fd;
2640 : syscallarg(int) pad;
2641 : syscallarg(off_t) length;
2642 0 : } */ *uap = v;
2643 0 : struct vattr vattr;
2644 : struct vnode *vp;
2645 0 : struct file *fp;
2646 : off_t len;
2647 : int error;
2648 :
2649 0 : if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
2650 0 : return (error);
2651 0 : len = SCARG(uap, length);
2652 0 : if ((fp->f_flag & FWRITE) == 0 || len < 0) {
2653 : error = EINVAL;
2654 0 : goto bad;
2655 : }
2656 0 : vp = fp->f_data;
2657 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2658 0 : if (vp->v_type == VDIR)
2659 0 : error = EISDIR;
2660 0 : else if ((error = vn_writechk(vp)) == 0) {
2661 0 : VATTR_NULL(&vattr);
2662 0 : vattr.va_size = len;
2663 0 : error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
2664 0 : }
2665 0 : VOP_UNLOCK(vp);
2666 : bad:
2667 0 : FRELE(fp, p);
2668 0 : return (error);
2669 0 : }
2670 :
2671 : /*
2672 : * Sync an open file.
2673 : */
2674 : int
2675 0 : sys_fsync(struct proc *p, void *v, register_t *retval)
2676 : {
2677 : struct sys_fsync_args /* {
2678 : syscallarg(int) fd;
2679 0 : } */ *uap = v;
2680 : struct vnode *vp;
2681 0 : struct file *fp;
2682 : int error;
2683 :
2684 0 : if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
2685 0 : return (error);
2686 0 : vp = fp->f_data;
2687 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2688 0 : error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
2689 : #ifdef FFS_SOFTUPDATES
2690 0 : if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
2691 0 : error = softdep_fsync(vp);
2692 : #endif
2693 :
2694 0 : VOP_UNLOCK(vp);
2695 0 : FRELE(fp, p);
2696 0 : return (error);
2697 0 : }
2698 :
2699 : /*
2700 : * Rename files. Source and destination must either both be directories,
2701 : * or both not be directories. If target is a directory, it must be empty.
2702 : */
2703 : int
2704 0 : sys_rename(struct proc *p, void *v, register_t *retval)
2705 : {
2706 : struct sys_rename_args /* {
2707 : syscallarg(const char *) from;
2708 : syscallarg(const char *) to;
2709 0 : } */ *uap = v;
2710 :
2711 0 : return (dorenameat(p, AT_FDCWD, SCARG(uap, from), AT_FDCWD,
2712 0 : SCARG(uap, to)));
2713 : }
2714 :
2715 : int
2716 0 : sys_renameat(struct proc *p, void *v, register_t *retval)
2717 : {
2718 : struct sys_renameat_args /* {
2719 : syscallarg(int) fromfd;
2720 : syscallarg(const char *) from;
2721 : syscallarg(int) tofd;
2722 : syscallarg(const char *) to;
2723 0 : } */ *uap = v;
2724 :
2725 0 : return (dorenameat(p, SCARG(uap, fromfd), SCARG(uap, from),
2726 0 : SCARG(uap, tofd), SCARG(uap, to)));
2727 : }
2728 :
2729 : int
2730 0 : dorenameat(struct proc *p, int fromfd, const char *from, int tofd,
2731 : const char *to)
2732 : {
2733 : struct vnode *tvp, *fvp, *tdvp;
2734 0 : struct nameidata fromnd, tond;
2735 : int error;
2736 : int flags;
2737 :
2738 0 : NDINITAT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2739 : fromfd, from, p);
2740 0 : fromnd.ni_pledge = PLEDGE_RPATH | PLEDGE_CPATH;
2741 0 : fromnd.ni_unveil = UNVEIL_READ | UNVEIL_CREATE;
2742 0 : if ((error = namei(&fromnd)) != 0)
2743 0 : return (error);
2744 0 : fvp = fromnd.ni_vp;
2745 :
2746 : flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
2747 : /*
2748 : * rename("foo/", "bar/"); is OK
2749 : */
2750 0 : if (fvp->v_type == VDIR)
2751 0 : flags |= STRIPSLASHES;
2752 :
2753 0 : NDINITAT(&tond, RENAME, flags, UIO_USERSPACE, tofd, to, p);
2754 0 : tond.ni_pledge = PLEDGE_CPATH;
2755 0 : tond.ni_unveil = UNVEIL_CREATE;
2756 0 : if ((error = namei(&tond)) != 0) {
2757 0 : VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2758 0 : vrele(fromnd.ni_dvp);
2759 0 : vrele(fvp);
2760 0 : goto out1;
2761 : }
2762 0 : tdvp = tond.ni_dvp;
2763 0 : tvp = tond.ni_vp;
2764 0 : if (tvp != NULL) {
2765 0 : if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2766 : error = ENOTDIR;
2767 0 : goto out;
2768 0 : } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2769 : error = EISDIR;
2770 0 : goto out;
2771 : }
2772 : }
2773 0 : if (fvp == tdvp)
2774 0 : error = EINVAL;
2775 : /*
2776 : * If source is the same as the destination (that is the
2777 : * same inode number)
2778 : */
2779 0 : if (fvp == tvp)
2780 0 : error = -1;
2781 : out:
2782 0 : if (!error) {
2783 0 : if (tvp) {
2784 0 : (void)uvm_vnp_uncache(tvp);
2785 0 : }
2786 0 : error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2787 0 : tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2788 0 : } else {
2789 0 : VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2790 0 : if (tdvp == tvp)
2791 0 : vrele(tdvp);
2792 : else
2793 0 : vput(tdvp);
2794 0 : if (tvp)
2795 0 : vput(tvp);
2796 0 : VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2797 0 : vrele(fromnd.ni_dvp);
2798 0 : vrele(fvp);
2799 : }
2800 0 : vrele(tond.ni_startdir);
2801 0 : pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf);
2802 : out1:
2803 0 : if (fromnd.ni_startdir)
2804 0 : vrele(fromnd.ni_startdir);
2805 0 : pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf);
2806 0 : if (error == -1)
2807 0 : return (0);
2808 0 : return (error);
2809 0 : }
2810 :
2811 : /*
2812 : * Make a directory file.
2813 : */
2814 : int
2815 0 : sys_mkdir(struct proc *p, void *v, register_t *retval)
2816 : {
2817 : struct sys_mkdir_args /* {
2818 : syscallarg(const char *) path;
2819 : syscallarg(mode_t) mode;
2820 0 : } */ *uap = v;
2821 :
2822 0 : return (domkdirat(p, AT_FDCWD, SCARG(uap, path), SCARG(uap, mode)));
2823 : }
2824 :
2825 : int
2826 0 : sys_mkdirat(struct proc *p, void *v, register_t *retval)
2827 : {
2828 : struct sys_mkdirat_args /* {
2829 : syscallarg(int) fd;
2830 : syscallarg(const char *) path;
2831 : syscallarg(mode_t) mode;
2832 0 : } */ *uap = v;
2833 :
2834 0 : return (domkdirat(p, SCARG(uap, fd), SCARG(uap, path),
2835 0 : SCARG(uap, mode)));
2836 : }
2837 :
2838 : int
2839 0 : domkdirat(struct proc *p, int fd, const char *path, mode_t mode)
2840 : {
2841 : struct vnode *vp;
2842 0 : struct vattr vattr;
2843 : int error;
2844 0 : struct nameidata nd;
2845 :
2846 0 : NDINITAT(&nd, CREATE, LOCKPARENT | STRIPSLASHES, UIO_USERSPACE,
2847 : fd, path, p);
2848 0 : nd.ni_pledge = PLEDGE_CPATH;
2849 0 : nd.ni_unveil = UNVEIL_CREATE;
2850 0 : if ((error = namei(&nd)) != 0)
2851 0 : return (error);
2852 0 : vp = nd.ni_vp;
2853 0 : if (vp != NULL) {
2854 0 : VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2855 0 : if (nd.ni_dvp == vp)
2856 0 : vrele(nd.ni_dvp);
2857 : else
2858 0 : vput(nd.ni_dvp);
2859 0 : vrele(vp);
2860 0 : return (EEXIST);
2861 : }
2862 0 : VATTR_NULL(&vattr);
2863 0 : vattr.va_type = VDIR;
2864 0 : vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
2865 0 : error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2866 0 : if (!error)
2867 0 : vput(nd.ni_vp);
2868 0 : return (error);
2869 0 : }
2870 :
2871 : /*
2872 : * Remove a directory file.
2873 : */
2874 : int
2875 0 : sys_rmdir(struct proc *p, void *v, register_t *retval)
2876 : {
2877 : struct sys_rmdir_args /* {
2878 : syscallarg(const char *) path;
2879 0 : } */ *uap = v;
2880 :
2881 0 : return (dounlinkat(p, AT_FDCWD, SCARG(uap, path), AT_REMOVEDIR));
2882 : }
2883 :
2884 : /*
2885 : * Read a block of directory entries in a file system independent format.
2886 : */
2887 : int
2888 0 : sys_getdents(struct proc *p, void *v, register_t *retval)
2889 : {
2890 : struct sys_getdents_args /* {
2891 : syscallarg(int) fd;
2892 : syscallarg(void *) buf;
2893 : syscallarg(size_t) buflen;
2894 0 : } */ *uap = v;
2895 : struct vnode *vp;
2896 0 : struct file *fp;
2897 0 : struct uio auio;
2898 0 : struct iovec aiov;
2899 : size_t buflen;
2900 0 : int error, eofflag;
2901 :
2902 0 : buflen = SCARG(uap, buflen);
2903 :
2904 0 : if (buflen > INT_MAX)
2905 0 : return EINVAL;
2906 0 : if ((error = getvnode(p, SCARG(uap, fd), &fp)) != 0)
2907 0 : return (error);
2908 0 : if ((fp->f_flag & FREAD) == 0) {
2909 : error = EBADF;
2910 0 : goto bad;
2911 : }
2912 0 : if (fp->f_offset < 0) {
2913 : error = EINVAL;
2914 0 : goto bad;
2915 : }
2916 0 : vp = fp->f_data;
2917 0 : if (vp->v_type != VDIR) {
2918 : error = EINVAL;
2919 0 : goto bad;
2920 : }
2921 0 : aiov.iov_base = SCARG(uap, buf);
2922 0 : aiov.iov_len = buflen;
2923 0 : auio.uio_iov = &aiov;
2924 0 : auio.uio_iovcnt = 1;
2925 0 : auio.uio_rw = UIO_READ;
2926 0 : auio.uio_segflg = UIO_USERSPACE;
2927 0 : auio.uio_procp = p;
2928 0 : auio.uio_resid = buflen;
2929 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2930 0 : auio.uio_offset = fp->f_offset;
2931 0 : error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
2932 0 : fp->f_offset = auio.uio_offset;
2933 0 : VOP_UNLOCK(vp);
2934 0 : if (error)
2935 : goto bad;
2936 0 : *retval = buflen - auio.uio_resid;
2937 : bad:
2938 0 : FRELE(fp, p);
2939 0 : return (error);
2940 0 : }
2941 :
2942 : /*
2943 : * Set the mode mask for creation of filesystem nodes.
2944 : */
2945 : int
2946 0 : sys_umask(struct proc *p, void *v, register_t *retval)
2947 : {
2948 : struct sys_umask_args /* {
2949 : syscallarg(mode_t) newmask;
2950 0 : } */ *uap = v;
2951 : struct filedesc *fdp;
2952 :
2953 0 : fdp = p->p_fd;
2954 0 : *retval = fdp->fd_cmask;
2955 0 : fdp->fd_cmask = SCARG(uap, newmask) & ACCESSPERMS;
2956 0 : return (0);
2957 : }
2958 :
2959 : /*
2960 : * Void all references to file by ripping underlying filesystem
2961 : * away from vnode.
2962 : */
2963 : int
2964 0 : sys_revoke(struct proc *p, void *v, register_t *retval)
2965 : {
2966 : struct sys_revoke_args /* {
2967 : syscallarg(const char *) path;
2968 0 : } */ *uap = v;
2969 : struct vnode *vp;
2970 0 : struct vattr vattr;
2971 : int error;
2972 0 : struct nameidata nd;
2973 :
2974 0 : NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2975 0 : nd.ni_pledge = PLEDGE_RPATH | PLEDGE_TTY;
2976 0 : nd.ni_unveil = UNVEIL_READ;
2977 0 : if ((error = namei(&nd)) != 0)
2978 0 : return (error);
2979 0 : vp = nd.ni_vp;
2980 0 : if (vp->v_type != VCHR || (u_int)major(vp->v_rdev) >= nchrdev ||
2981 0 : cdevsw[major(vp->v_rdev)].d_type != D_TTY) {
2982 : error = ENOTTY;
2983 0 : goto out;
2984 : }
2985 0 : if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
2986 : goto out;
2987 0 : if (p->p_ucred->cr_uid != vattr.va_uid &&
2988 0 : (error = suser(p)))
2989 : goto out;
2990 0 : if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED)))
2991 0 : VOP_REVOKE(vp, REVOKEALL);
2992 : out:
2993 0 : vrele(vp);
2994 0 : return (error);
2995 0 : }
2996 :
2997 : /*
2998 : * Convert a user file descriptor to a kernel file entry.
2999 : *
3000 : * On return *fpp is FREF:ed.
3001 : */
3002 : int
3003 0 : getvnode(struct proc *p, int fd, struct file **fpp)
3004 : {
3005 : struct file *fp;
3006 : struct vnode *vp;
3007 :
3008 0 : if ((fp = fd_getfile(p->p_fd, fd)) == NULL)
3009 0 : return (EBADF);
3010 :
3011 0 : if (fp->f_type != DTYPE_VNODE) {
3012 0 : FRELE(fp, p);
3013 0 : return (EINVAL);
3014 : }
3015 :
3016 0 : vp = fp->f_data;
3017 0 : if (vp->v_type == VBAD) {
3018 0 : FRELE(fp, p);
3019 0 : return (EBADF);
3020 : }
3021 :
3022 0 : *fpp = fp;
3023 :
3024 0 : return (0);
3025 0 : }
3026 :
3027 : /*
3028 : * Positional read system call.
3029 : */
3030 : int
3031 0 : sys_pread(struct proc *p, void *v, register_t *retval)
3032 : {
3033 : struct sys_pread_args /* {
3034 : syscallarg(int) fd;
3035 : syscallarg(void *) buf;
3036 : syscallarg(size_t) nbyte;
3037 : syscallarg(int) pad;
3038 : syscallarg(off_t) offset;
3039 0 : } */ *uap = v;
3040 0 : struct iovec iov;
3041 0 : struct uio auio;
3042 :
3043 0 : iov.iov_base = SCARG(uap, buf);
3044 0 : iov.iov_len = SCARG(uap, nbyte);
3045 0 : if (iov.iov_len > SSIZE_MAX)
3046 0 : return (EINVAL);
3047 :
3048 0 : auio.uio_iov = &iov;
3049 0 : auio.uio_iovcnt = 1;
3050 0 : auio.uio_resid = iov.iov_len;
3051 0 : auio.uio_offset = SCARG(uap, offset);
3052 :
3053 0 : return (dofilereadv(p, SCARG(uap, fd), &auio, FO_POSITION, retval));
3054 0 : }
3055 :
3056 : /*
3057 : * Positional scatter read system call.
3058 : */
3059 : int
3060 0 : sys_preadv(struct proc *p, void *v, register_t *retval)
3061 : {
3062 : struct sys_preadv_args /* {
3063 : syscallarg(int) fd;
3064 : syscallarg(const struct iovec *) iovp;
3065 : syscallarg(int) iovcnt;
3066 : syscallarg(int) pad;
3067 : syscallarg(off_t) offset;
3068 0 : } */ *uap = v;
3069 0 : struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
3070 0 : int error, iovcnt = SCARG(uap, iovcnt);
3071 0 : struct uio auio;
3072 0 : size_t resid;
3073 :
3074 0 : error = iovec_copyin(SCARG(uap, iovp), &iov, aiov, iovcnt, &resid);
3075 0 : if (error)
3076 : goto done;
3077 :
3078 0 : auio.uio_iov = iov;
3079 0 : auio.uio_iovcnt = iovcnt;
3080 0 : auio.uio_resid = resid;
3081 0 : auio.uio_offset = SCARG(uap, offset);
3082 :
3083 0 : error = dofilereadv(p, SCARG(uap, fd), &auio, FO_POSITION, retval);
3084 : done:
3085 0 : iovec_free(iov, iovcnt);
3086 0 : return (error);
3087 0 : }
3088 :
3089 : /*
3090 : * Positional write system call.
3091 : */
3092 : int
3093 0 : sys_pwrite(struct proc *p, void *v, register_t *retval)
3094 : {
3095 : struct sys_pwrite_args /* {
3096 : syscallarg(int) fd;
3097 : syscallarg(const void *) buf;
3098 : syscallarg(size_t) nbyte;
3099 : syscallarg(int) pad;
3100 : syscallarg(off_t) offset;
3101 0 : } */ *uap = v;
3102 0 : struct iovec iov;
3103 0 : struct uio auio;
3104 :
3105 0 : iov.iov_base = (void *)SCARG(uap, buf);
3106 0 : iov.iov_len = SCARG(uap, nbyte);
3107 0 : if (iov.iov_len > SSIZE_MAX)
3108 0 : return (EINVAL);
3109 :
3110 0 : auio.uio_iov = &iov;
3111 0 : auio.uio_iovcnt = 1;
3112 0 : auio.uio_resid = iov.iov_len;
3113 0 : auio.uio_offset = SCARG(uap, offset);
3114 :
3115 0 : return (dofilewritev(p, SCARG(uap, fd), &auio, FO_POSITION, retval));
3116 0 : }
3117 :
3118 : /*
3119 : * Positional gather write system call.
3120 : */
3121 : int
3122 0 : sys_pwritev(struct proc *p, void *v, register_t *retval)
3123 : {
3124 : struct sys_pwritev_args /* {
3125 : syscallarg(int) fd;
3126 : syscallarg(const struct iovec *) iovp;
3127 : syscallarg(int) iovcnt;
3128 : syscallarg(int) pad;
3129 : syscallarg(off_t) offset;
3130 0 : } */ *uap = v;
3131 0 : struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
3132 0 : int error, iovcnt = SCARG(uap, iovcnt);
3133 0 : struct uio auio;
3134 0 : size_t resid;
3135 :
3136 0 : error = iovec_copyin(SCARG(uap, iovp), &iov, aiov, iovcnt, &resid);
3137 0 : if (error)
3138 : goto done;
3139 :
3140 0 : auio.uio_iov = iov;
3141 0 : auio.uio_iovcnt = iovcnt;
3142 0 : auio.uio_resid = resid;
3143 0 : auio.uio_offset = SCARG(uap, offset);
3144 :
3145 0 : error = dofilewritev(p, SCARG(uap, fd), &auio, FO_POSITION, retval);
3146 : done:
3147 0 : iovec_free(iov, iovcnt);
3148 0 : return (error);
3149 0 : }
|