xref: /netbsd-src/sys/miscfs/genfs/genfs_vnops.c (revision 93bf6008f8b7982c1d1a9486e4a4a0e687fe36eb)
1 /*	$NetBSD: genfs_vnops.c,v 1.169 2009/04/22 22:57:08 elad Exp $	*/
2 
3 /*-
4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /*
30  * Copyright (c) 1982, 1986, 1989, 1993
31  *	The Regents of the University of California.  All rights reserved.
32  *
33  * Redistribution and use in source and binary forms, with or without
34  * modification, are permitted provided that the following conditions
35  * are met:
36  * 1. Redistributions of source code must retain the above copyright
37  *    notice, this list of conditions and the following disclaimer.
38  * 2. Redistributions in binary form must reproduce the above copyright
39  *    notice, this list of conditions and the following disclaimer in the
40  *    documentation and/or other materials provided with the distribution.
41  * 3. Neither the name of the University nor the names of its contributors
42  *    may be used to endorse or promote products derived from this software
43  *    without specific prior written permission.
44  *
45  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55  * SUCH DAMAGE.
56  *
57  */
58 
59 #include <sys/cdefs.h>
60 __KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.169 2009/04/22 22:57:08 elad Exp $");
61 
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/proc.h>
65 #include <sys/kernel.h>
66 #include <sys/mount.h>
67 #include <sys/namei.h>
68 #include <sys/vnode.h>
69 #include <sys/fcntl.h>
70 #include <sys/kmem.h>
71 #include <sys/poll.h>
72 #include <sys/mman.h>
73 #include <sys/file.h>
74 #include <sys/kauth.h>
75 #include <sys/stat.h>
76 
77 #include <miscfs/genfs/genfs.h>
78 #include <miscfs/genfs/genfs_node.h>
79 #include <miscfs/specfs/specdev.h>
80 
81 #include <uvm/uvm.h>
82 #include <uvm/uvm_pager.h>
83 
84 static void filt_genfsdetach(struct knote *);
85 static int filt_genfsread(struct knote *, long);
86 static int filt_genfsvnode(struct knote *, long);
87 
88 int
89 genfs_poll(void *v)
90 {
91 	struct vop_poll_args /* {
92 		struct vnode *a_vp;
93 		int a_events;
94 		struct lwp *a_l;
95 	} */ *ap = v;
96 
97 	return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
98 }
99 
100 int
101 genfs_seek(void *v)
102 {
103 	struct vop_seek_args /* {
104 		struct vnode *a_vp;
105 		off_t a_oldoff;
106 		off_t a_newoff;
107 		kauth_cred_t cred;
108 	} */ *ap = v;
109 
110 	if (ap->a_newoff < 0)
111 		return (EINVAL);
112 
113 	return (0);
114 }
115 
116 int
117 genfs_abortop(void *v)
118 {
119 	struct vop_abortop_args /* {
120 		struct vnode *a_dvp;
121 		struct componentname *a_cnp;
122 	} */ *ap = v;
123 
124 	if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
125 		PNBUF_PUT(ap->a_cnp->cn_pnbuf);
126 	return (0);
127 }
128 
129 int
130 genfs_fcntl(void *v)
131 {
132 	struct vop_fcntl_args /* {
133 		struct vnode *a_vp;
134 		u_int a_command;
135 		void *a_data;
136 		int a_fflag;
137 		kauth_cred_t a_cred;
138 		struct lwp *a_l;
139 	} */ *ap = v;
140 
141 	if (ap->a_command == F_SETFL)
142 		return (0);
143 	else
144 		return (EOPNOTSUPP);
145 }
146 
147 /*ARGSUSED*/
148 int
149 genfs_badop(void *v)
150 {
151 
152 	panic("genfs: bad op");
153 }
154 
155 /*ARGSUSED*/
156 int
157 genfs_nullop(void *v)
158 {
159 
160 	return (0);
161 }
162 
163 /*ARGSUSED*/
164 int
165 genfs_einval(void *v)
166 {
167 
168 	return (EINVAL);
169 }
170 
171 /*
172  * Called when an fs doesn't support a particular vop.
173  * This takes care to vrele, vput, or vunlock passed in vnodes.
174  */
175 int
176 genfs_eopnotsupp(void *v)
177 {
178 	struct vop_generic_args /*
179 		struct vnodeop_desc *a_desc;
180 		/ * other random data follows, presumably * /
181 	} */ *ap = v;
182 	struct vnodeop_desc *desc = ap->a_desc;
183 	struct vnode *vp, *vp_last = NULL;
184 	int flags, i, j, offset;
185 
186 	flags = desc->vdesc_flags;
187 	for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) {
188 		if ((offset = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET)
189 			break;	/* stop at end of list */
190 		if ((j = flags & VDESC_VP0_WILLPUT)) {
191 			vp = *VOPARG_OFFSETTO(struct vnode **, offset, ap);
192 
193 			/* Skip if NULL */
194 			if (!vp)
195 				continue;
196 
197 			switch (j) {
198 			case VDESC_VP0_WILLPUT:
199 				/* Check for dvp == vp cases */
200 				if (vp == vp_last)
201 					vrele(vp);
202 				else {
203 					vput(vp);
204 					vp_last = vp;
205 				}
206 				break;
207 			case VDESC_VP0_WILLUNLOCK:
208 				VOP_UNLOCK(vp, 0);
209 				break;
210 			case VDESC_VP0_WILLRELE:
211 				vrele(vp);
212 				break;
213 			}
214 		}
215 	}
216 
217 	return (EOPNOTSUPP);
218 }
219 
220 /*ARGSUSED*/
221 int
222 genfs_ebadf(void *v)
223 {
224 
225 	return (EBADF);
226 }
227 
228 /* ARGSUSED */
229 int
230 genfs_enoioctl(void *v)
231 {
232 
233 	return (EPASSTHROUGH);
234 }
235 
236 
237 /*
238  * Eliminate all activity associated with the requested vnode
239  * and with all vnodes aliased to the requested vnode.
240  */
241 int
242 genfs_revoke(void *v)
243 {
244 	struct vop_revoke_args /* {
245 		struct vnode *a_vp;
246 		int a_flags;
247 	} */ *ap = v;
248 
249 #ifdef DIAGNOSTIC
250 	if ((ap->a_flags & REVOKEALL) == 0)
251 		panic("genfs_revoke: not revokeall");
252 #endif
253 	vrevoke(ap->a_vp);
254 	return (0);
255 }
256 
257 /*
258  * Lock the node.
259  */
260 int
261 genfs_lock(void *v)
262 {
263 	struct vop_lock_args /* {
264 		struct vnode *a_vp;
265 		int a_flags;
266 	} */ *ap = v;
267 	struct vnode *vp = ap->a_vp;
268 	int flags = ap->a_flags;
269 
270 	if ((flags & LK_INTERLOCK) != 0) {
271 		flags &= ~LK_INTERLOCK;
272 		mutex_exit(&vp->v_interlock);
273 	}
274 
275 	return (vlockmgr(vp->v_vnlock, flags));
276 }
277 
278 /*
279  * Unlock the node.
280  */
281 int
282 genfs_unlock(void *v)
283 {
284 	struct vop_unlock_args /* {
285 		struct vnode *a_vp;
286 		int a_flags;
287 	} */ *ap = v;
288 	struct vnode *vp = ap->a_vp;
289 
290 	KASSERT(ap->a_flags == 0);
291 
292 	return (vlockmgr(vp->v_vnlock, LK_RELEASE));
293 }
294 
295 /*
296  * Return whether or not the node is locked.
297  */
298 int
299 genfs_islocked(void *v)
300 {
301 	struct vop_islocked_args /* {
302 		struct vnode *a_vp;
303 	} */ *ap = v;
304 	struct vnode *vp = ap->a_vp;
305 
306 	return (vlockstatus(vp->v_vnlock));
307 }
308 
309 /*
310  * Stubs to use when there is no locking to be done on the underlying object.
311  */
312 int
313 genfs_nolock(void *v)
314 {
315 	struct vop_lock_args /* {
316 		struct vnode *a_vp;
317 		int a_flags;
318 		struct lwp *a_l;
319 	} */ *ap = v;
320 
321 	/*
322 	 * Since we are not using the lock manager, we must clear
323 	 * the interlock here.
324 	 */
325 	if (ap->a_flags & LK_INTERLOCK)
326 		mutex_exit(&ap->a_vp->v_interlock);
327 	return (0);
328 }
329 
330 int
331 genfs_nounlock(void *v)
332 {
333 
334 	return (0);
335 }
336 
337 int
338 genfs_noislocked(void *v)
339 {
340 
341 	return (0);
342 }
343 
344 int
345 genfs_mmap(void *v)
346 {
347 
348 	return (0);
349 }
350 
351 /*
352  * VOP_PUTPAGES() for vnodes which never have pages.
353  */
354 
355 int
356 genfs_null_putpages(void *v)
357 {
358 	struct vop_putpages_args /* {
359 		struct vnode *a_vp;
360 		voff_t a_offlo;
361 		voff_t a_offhi;
362 		int a_flags;
363 	} */ *ap = v;
364 	struct vnode *vp = ap->a_vp;
365 
366 	KASSERT(vp->v_uobj.uo_npages == 0);
367 	mutex_exit(&vp->v_interlock);
368 	return (0);
369 }
370 
371 void
372 genfs_node_init(struct vnode *vp, const struct genfs_ops *ops)
373 {
374 	struct genfs_node *gp = VTOG(vp);
375 
376 	rw_init(&gp->g_glock);
377 	gp->g_op = ops;
378 }
379 
380 void
381 genfs_node_destroy(struct vnode *vp)
382 {
383 	struct genfs_node *gp = VTOG(vp);
384 
385 	rw_destroy(&gp->g_glock);
386 }
387 
388 void
389 genfs_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
390 {
391 	int bsize;
392 
393 	bsize = 1 << vp->v_mount->mnt_fs_bshift;
394 	*eobp = (size + bsize - 1) & ~(bsize - 1);
395 }
396 
397 static void
398 filt_genfsdetach(struct knote *kn)
399 {
400 	struct vnode *vp = (struct vnode *)kn->kn_hook;
401 
402 	mutex_enter(&vp->v_interlock);
403 	SLIST_REMOVE(&vp->v_klist, kn, knote, kn_selnext);
404 	mutex_exit(&vp->v_interlock);
405 }
406 
407 static int
408 filt_genfsread(struct knote *kn, long hint)
409 {
410 	struct vnode *vp = (struct vnode *)kn->kn_hook;
411 	int rv;
412 
413 	/*
414 	 * filesystem is gone, so set the EOF flag and schedule
415 	 * the knote for deletion.
416 	 */
417 	switch (hint) {
418 	case NOTE_REVOKE:
419 		KASSERT(mutex_owned(&vp->v_interlock));
420 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
421 		return (1);
422 	case 0:
423 		mutex_enter(&vp->v_interlock);
424 		kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
425 		rv = (kn->kn_data != 0);
426 		mutex_exit(&vp->v_interlock);
427 		return rv;
428 	default:
429 		KASSERT(mutex_owned(&vp->v_interlock));
430 		kn->kn_data = vp->v_size - ((file_t *)kn->kn_obj)->f_offset;
431 		return (kn->kn_data != 0);
432 	}
433 }
434 
435 static int
436 filt_genfsvnode(struct knote *kn, long hint)
437 {
438 	struct vnode *vp = (struct vnode *)kn->kn_hook;
439 	int fflags;
440 
441 	switch (hint) {
442 	case NOTE_REVOKE:
443 		KASSERT(mutex_owned(&vp->v_interlock));
444 		kn->kn_flags |= EV_EOF;
445 		if ((kn->kn_sfflags & hint) != 0)
446 			kn->kn_fflags |= hint;
447 		return (1);
448 	case 0:
449 		mutex_enter(&vp->v_interlock);
450 		fflags = kn->kn_fflags;
451 		mutex_exit(&vp->v_interlock);
452 		break;
453 	default:
454 		KASSERT(mutex_owned(&vp->v_interlock));
455 		if ((kn->kn_sfflags & hint) != 0)
456 			kn->kn_fflags |= hint;
457 		fflags = kn->kn_fflags;
458 		break;
459 	}
460 
461 	return (fflags != 0);
462 }
463 
464 static const struct filterops genfsread_filtops =
465 	{ 1, NULL, filt_genfsdetach, filt_genfsread };
466 static const struct filterops genfsvnode_filtops =
467 	{ 1, NULL, filt_genfsdetach, filt_genfsvnode };
468 
469 int
470 genfs_kqfilter(void *v)
471 {
472 	struct vop_kqfilter_args /* {
473 		struct vnode	*a_vp;
474 		struct knote	*a_kn;
475 	} */ *ap = v;
476 	struct vnode *vp;
477 	struct knote *kn;
478 
479 	vp = ap->a_vp;
480 	kn = ap->a_kn;
481 	switch (kn->kn_filter) {
482 	case EVFILT_READ:
483 		kn->kn_fop = &genfsread_filtops;
484 		break;
485 	case EVFILT_VNODE:
486 		kn->kn_fop = &genfsvnode_filtops;
487 		break;
488 	default:
489 		return (EINVAL);
490 	}
491 
492 	kn->kn_hook = vp;
493 
494 	mutex_enter(&vp->v_interlock);
495 	SLIST_INSERT_HEAD(&vp->v_klist, kn, kn_selnext);
496 	mutex_exit(&vp->v_interlock);
497 
498 	return (0);
499 }
500 
501 void
502 genfs_node_wrlock(struct vnode *vp)
503 {
504 	struct genfs_node *gp = VTOG(vp);
505 
506 	rw_enter(&gp->g_glock, RW_WRITER);
507 }
508 
509 void
510 genfs_node_rdlock(struct vnode *vp)
511 {
512 	struct genfs_node *gp = VTOG(vp);
513 
514 	rw_enter(&gp->g_glock, RW_READER);
515 }
516 
517 void
518 genfs_node_unlock(struct vnode *vp)
519 {
520 	struct genfs_node *gp = VTOG(vp);
521 
522 	rw_exit(&gp->g_glock);
523 }
524 
525 /*
526  * Common routine to check if chmod() is allowed.
527  *
528  * Policy:
529  *   - You must be root, or
530  *   - You must own the file, and
531  *     - You must not set the "sticky" bit (meaningless, see chmod(2))
532  *     - You must be a member of the group if you're trying to set the
533  *       SGIDf bit
534  *
535  * cred - credentials of the invoker
536  * vp - vnode of the file-system object
537  * cur_uid, cur_gid - current uid/gid of the file-system object
538  * new_mode - new mode for the file-system object
539  *
540  * Returns 0 if the change is allowed, or an error value otherwise.
541  */
542 int
543 genfs_can_chmod(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid,
544     gid_t cur_gid, mode_t new_mode)
545 {
546 	int error;
547 
548 	/* Superuser can always change mode. */
549 	error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
550 	    NULL);
551 	if (!error)
552 		return (0);
553 
554 	/* Otherwise, user must own the file. */
555 	if (kauth_cred_geteuid(cred) != cur_uid)
556 		return (EPERM);
557 
558 	/*
559 	 * Non-root users can't set the sticky bit on files.
560 	 */
561 	if ((vp->v_type != VDIR) && (new_mode & S_ISTXT))
562 		return (EFTYPE);
563 
564 	/*
565 	 * If the invoker is trying to set the SGID bit on the file,
566 	 * check group membership.
567 	 */
568 	if (new_mode & S_ISGID) {
569 		int ismember;
570 
571 		error = kauth_cred_ismember_gid(cred, cur_gid,
572 		    &ismember);
573 		if (error || !ismember)
574 			return (EPERM);
575 	}
576 
577 	return (0);
578 }
579 
580 /*
581  * Common routine to check if chown() is allowed.
582  *
583  * Policy:
584  *   - You must be root, or
585  *   - You must own the file, and
586  *     - You must not try to change ownership, and
587  *     - You must be member of the new group
588  *
589  * cred - credentials of the invoker
590  * cur_uid, cur_gid - current uid/gid of the file-system object
591  * new_uid, new_gid - target uid/gid of the file-system object
592  *
593  * Returns 0 if the change is allowed, or an error value otherwise.
594  */
595 int
596 genfs_can_chown(vnode_t *vp, kauth_cred_t cred, uid_t cur_uid,
597     gid_t cur_gid, uid_t new_uid, gid_t new_gid)
598 {
599 	int error, ismember;
600 
601 	/*
602 	 * You can only change ownership of a file if:
603 	 * You are the superuser, or...
604 	 */
605 	error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
606 	    NULL);
607 	if (!error)
608 		return (0);
609 
610 	/*
611 	 * You own the file and...
612 	 */
613 	if (kauth_cred_geteuid(cred) == cur_uid) {
614 		/*
615 		 * You don't try to change ownership, and...
616 		 */
617 		if (new_uid != cur_uid)
618 			return (EPERM);
619 
620 		/*
621 		 * You don't try to change group (no-op), or...
622 		 */
623 		if (new_gid == cur_gid)
624 			return (0);
625 
626 		/*
627 		 * Your effective gid is the new gid, or...
628 		 */
629 		if (kauth_cred_getegid(cred) == new_gid)
630 			return (0);
631 
632 		/*
633 		 * The new gid is one you're a member of.
634 		 */
635 		ismember = 0;
636 		error = kauth_cred_ismember_gid(cred, new_gid,
637 		    &ismember);
638 		if (error || !ismember)
639 			return (EPERM);
640 	}
641 
642 	return (0);
643 }
644 
645