xref: /minix3/minix/servers/vfs/filedes.c (revision 27852ebe53d5bf221cf5058cb7e858fa8fa8895e)
1 /* This file contains the procedures that manipulate file descriptors.
2  *
3  * The entry points into this file are
4  *   get_fd:	    look for free file descriptor and free filp slots
5  *   get_filp:	    look up the filp entry for a given file descriptor
6  *   find_filp:	    find a filp slot that points to a given vnode
7  *   inval_filp:    invalidate a filp and associated fd's, only let close()
8  *                  happen on it
9  *   do_copyfd:     copies a file descriptor from or to another endpoint
10  */
11 
12 #include <sys/select.h>
13 #include <minix/callnr.h>
14 #include <minix/u64.h>
15 #include <assert.h>
16 #include <sys/stat.h>
17 #include "fs.h"
18 #include "file.h"
19 #include "vnode.h"
20 
21 
22 #if LOCK_DEBUG
23 /*===========================================================================*
24  *				check_filp_locks			     *
25  *===========================================================================*/
check_filp_locks_by_me(void)26 void check_filp_locks_by_me(void)
27 {
28 /* Check whether this thread still has filp locks held */
29   struct filp *f;
30   int r;
31 
32   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
33 	r = mutex_trylock(&f->filp_lock);
34 	if (r == -EDEADLK)
35 		panic("Thread %d still holds filp lock on filp %p call_nr=%d\n",
36 		      mthread_self(), f, job_call_nr);
37 	else if (r == 0) {
38 		/* We just obtained the lock, release it */
39 		mutex_unlock(&f->filp_lock);
40 	}
41   }
42 }
43 #endif
44 
45 /*===========================================================================*
46  *				check_filp_locks			     *
47  *===========================================================================*/
check_filp_locks(void)48 void check_filp_locks(void)
49 {
50   struct filp *f;
51   int r, count = 0;
52 
53   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
54 	r = mutex_trylock(&f->filp_lock);
55 	if (r == -EBUSY) {
56 		/* Mutex is still locked */
57 		count++;
58 	} else if (r == 0) {
59 		/* We just obtained a lock, don't want it */
60 		mutex_unlock(&f->filp_lock);
61 	} else
62 		panic("filp_lock weird state");
63   }
64   if (count) panic("locked filps");
65 #if 0
66   else printf("check_filp_locks OK\n");
67 #endif
68 }
69 
70 /*===========================================================================*
71  *				init_filps				     *
72  *===========================================================================*/
init_filps(void)73 void init_filps(void)
74 {
75 /* Initialize filps */
76   struct filp *f;
77 
78   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
79 	if (mutex_init(&f->filp_lock, NULL) != 0)
80 		panic("Failed to initialize filp mutex");
81   }
82 
83 }
84 
85 /*===========================================================================*
86  *				check_fds				     *
87  *===========================================================================*/
check_fds(struct fproc * rfp,int nfds)88 int check_fds(struct fproc *rfp, int nfds)
89 {
90 /* Check whether at least 'nfds' file descriptors can be created in the process
91  * 'rfp'.  Return OK on success, or otherwise an appropriate error code.
92  */
93   int i;
94 
95   assert(nfds >= 1);
96 
97   for (i = 0; i < OPEN_MAX; i++) {
98 	if (rfp->fp_filp[i] == NULL) {
99 		if (--nfds == 0)
100 			return OK;
101 	}
102   }
103 
104   return EMFILE;
105 }
106 
107 /*===========================================================================*
108  *				get_fd					     *
109  *===========================================================================*/
get_fd(struct fproc * rfp,int start,mode_t bits,int * k,struct filp ** fpt)110 int get_fd(struct fproc *rfp, int start, mode_t bits, int *k, struct filp **fpt)
111 {
112 /* Look for a free file descriptor and a free filp slot.  Fill in the mode word
113  * in the latter, but don't claim either one yet, since the open() or creat()
114  * may yet fail.
115  */
116 
117   register struct filp *f;
118   register int i;
119 
120   /* Search the fproc fp_filp table for a free file descriptor. */
121   for (i = start; i < OPEN_MAX; i++) {
122 	if (rfp->fp_filp[i] == NULL) {
123 		/* A file descriptor has been located. */
124 		*k = i;
125 		break;
126 	}
127   }
128 
129   /* Check to see if a file descriptor has been found. */
130   if (i >= OPEN_MAX) return(EMFILE);
131 
132   /* If we don't care about a filp, return now */
133   if (fpt == NULL) return(OK);
134 
135   /* Now that a file descriptor has been found, look for a free filp slot. */
136   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
137 	assert(f->filp_count >= 0);
138 	if (f->filp_count == 0 && mutex_trylock(&f->filp_lock) == 0) {
139 		f->filp_mode = bits;
140 		f->filp_pos = 0;
141 		f->filp_selectors = 0;
142 		f->filp_select_ops = 0;
143 		f->filp_pipe_select_ops = 0;
144 		f->filp_select_dev = NO_DEV;
145 		f->filp_flags = 0;
146 		f->filp_select_flags = 0;
147 		f->filp_softlock = NULL;
148 		f->filp_ioctl_fp = NULL;
149 		*fpt = f;
150 		return(OK);
151 	}
152   }
153 
154   /* If control passes here, the filp table must be full.  Report that back. */
155   return(ENFILE);
156 }
157 
158 
159 /*===========================================================================*
160  *				get_filp				     *
161  *===========================================================================*/
162 struct filp *
get_filp(int fild,tll_access_t locktype)163 get_filp(
164 	int fild,			/* file descriptor */
165 	tll_access_t locktype
166 )
167 {
168 /* See if 'fild' refers to a valid file descr.  If so, return its filp ptr. */
169 
170   return get_filp2(fp, fild, locktype);
171 }
172 
173 
174 /*===========================================================================*
175  *				get_filp2				     *
176  *===========================================================================*/
177 struct filp *
get_filp2(register struct fproc * rfp,int fild,tll_access_t locktype)178 get_filp2(
179 	register struct fproc *rfp,
180 	int fild,			/* file descriptor */
181 	tll_access_t locktype
182 )
183 {
184 /* See if 'fild' refers to a valid file descr.  If so, return its filp ptr. */
185   struct filp *filp;
186 
187   filp = NULL;
188   if (fild < 0 || fild >= OPEN_MAX)
189 	err_code = EBADF;
190   else if (locktype != VNODE_OPCL && rfp->fp_filp[fild] != NULL &&
191 		rfp->fp_filp[fild]->filp_mode == FILP_CLOSED)
192 	err_code = EIO; /* disallow all use except close(2) */
193   else if ((filp = rfp->fp_filp[fild]) == NULL)
194 	err_code = EBADF;
195   else if (locktype != VNODE_NONE)	/* Only lock the filp if requested */
196 	lock_filp(filp, locktype);	/* All is fine */
197 
198   return(filp);	/* may also be NULL */
199 }
200 
201 
202 /*===========================================================================*
203  *				find_filp				     *
204  *===========================================================================*/
find_filp(struct vnode * vp,mode_t bits)205 struct filp *find_filp(struct vnode *vp, mode_t bits)
206 {
207 /* Find a filp slot that refers to the vnode 'vp' in a way as described
208  * by the mode bit 'bits'. Used for determining whether somebody is still
209  * interested in either end of a pipe.  Also used when opening a FIFO to
210  * find partners to share a filp field with (to shared the file position).
211  * Like 'get_fd' it performs its job by linear search through the filp table.
212  */
213 
214   struct filp *f;
215 
216   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
217 	if (f->filp_count != 0 && f->filp_vno == vp && (f->filp_mode & bits)) {
218 		return(f);
219 	}
220   }
221 
222   /* If control passes here, the filp wasn't there.  Report that back. */
223   return(NULL);
224 }
225 
226 /*===========================================================================*
227  *				find_filp_by_sock_dev			     *
228  *===========================================================================*/
find_filp_by_sock_dev(dev_t dev)229 struct filp *find_filp_by_sock_dev(dev_t dev)
230 {
231 /* See if there is a file pointer for a socket with the given socket device
232  * number.
233  */
234   struct filp *f;
235 
236   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
237 	if (f->filp_count != 0 && f->filp_vno != NULL &&
238 	    S_ISSOCK(f->filp_vno->v_mode) && f->filp_vno->v_sdev == dev &&
239 	    f->filp_mode != FILP_CLOSED) {
240 		return f;
241 	}
242   }
243 
244   return NULL;
245 }
246 
247 /*===========================================================================*
248  *				invalidate_filp				     *
249  *===========================================================================*/
invalidate_filp(struct filp * rfilp)250 void invalidate_filp(struct filp *rfilp)
251 {
252 /* Invalidate filp. */
253 
254   rfilp->filp_mode = FILP_CLOSED;
255 }
256 
257 /*===========================================================================*
258  *			invalidate_filp_by_char_major			     *
259  *===========================================================================*/
invalidate_filp_by_char_major(devmajor_t major)260 void invalidate_filp_by_char_major(devmajor_t major)
261 {
262   struct filp *f;
263 
264   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
265 	if (f->filp_count != 0 && f->filp_vno != NULL) {
266 		if (major(f->filp_vno->v_sdev) == major &&
267 		    S_ISCHR(f->filp_vno->v_mode)) {
268 			invalidate_filp(f);
269 		}
270 	}
271   }
272 }
273 
274 /*===========================================================================*
275  *			invalidate_filp_by_sock_drv			     *
276  *===========================================================================*/
invalidate_filp_by_sock_drv(unsigned int num)277 void invalidate_filp_by_sock_drv(unsigned int num)
278 {
279 /* Invalidate all file pointers for sockets owned by the socket driver with the
280  * smap number 'num'.
281  */
282   struct filp *f;
283   struct smap *sp;
284 
285   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
286 	if (f->filp_count != 0 && f->filp_vno != NULL) {
287 		if (S_ISSOCK(f->filp_vno->v_mode) &&
288 		    (sp = get_smap_by_dev(f->filp_vno->v_sdev, NULL)) != NULL
289 		    && sp->smap_num == num)
290 			invalidate_filp(f);
291 	}
292   }
293 }
294 
295 /*===========================================================================*
296  *			invalidate_filp_by_endpt			     *
297  *===========================================================================*/
invalidate_filp_by_endpt(endpoint_t proc_e)298 void invalidate_filp_by_endpt(endpoint_t proc_e)
299 {
300   struct filp *f;
301 
302   for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
303 	if (f->filp_count != 0 && f->filp_vno != NULL) {
304 		if (f->filp_vno->v_fs_e == proc_e)
305 			invalidate_filp(f);
306 	}
307   }
308 }
309 
310 /*===========================================================================*
311  *				lock_filp				     *
312  *===========================================================================*/
313 void
lock_filp(struct filp * filp,tll_access_t locktype)314 lock_filp(struct filp *filp, tll_access_t locktype)
315 {
316   struct worker_thread *org_self;
317   struct vnode *vp;
318 
319   assert(filp->filp_count > 0);
320   vp = filp->filp_vno;
321   assert(vp != NULL);
322 
323   /* Lock vnode only if we haven't already locked it. If already locked by us,
324    * we're allowed to have one additional 'soft' lock. */
325   if (tll_locked_by_me(&vp->v_lock)) {
326 	assert(filp->filp_softlock == NULL);
327 	filp->filp_softlock = fp;
328   } else {
329 	/* We have to make an exception for vnodes belonging to pipes. Even
330 	 * read(2) operations on pipes change the vnode and therefore require
331 	 * exclusive access.
332 	 */
333 	if (S_ISFIFO(vp->v_mode) && locktype == VNODE_READ)
334 		locktype = VNODE_WRITE;
335 	lock_vnode(vp, locktype);
336   }
337 
338   assert(vp->v_ref_count > 0);	/* vnode still in use? */
339   assert(filp->filp_vno == vp);	/* vnode still what we think it is? */
340 
341   /* First try to get filp lock right off the bat */
342   if (mutex_trylock(&filp->filp_lock) != 0) {
343 
344 	/* Already in use, let's wait for our turn */
345 	org_self = worker_suspend();
346 
347 	if (mutex_lock(&filp->filp_lock) != 0)
348 		panic("unable to obtain lock on filp");
349 
350 	worker_resume(org_self);
351   }
352 }
353 
354 /*===========================================================================*
355  *				unlock_filp				     *
356  *===========================================================================*/
357 void
unlock_filp(struct filp * filp)358 unlock_filp(struct filp *filp)
359 {
360   /* If this filp holds a soft lock on the vnode, we must be the owner */
361   if (filp->filp_softlock != NULL)
362 	assert(filp->filp_softlock == fp);
363 
364   if (filp->filp_count > 0) {
365 	/* Only unlock vnode if filp is still in use */
366 
367 	/* and if we don't hold a soft lock */
368 	if (filp->filp_softlock == NULL) {
369 		assert(tll_islocked(&(filp->filp_vno->v_lock)));
370 		unlock_vnode(filp->filp_vno);
371 	}
372   }
373 
374   filp->filp_softlock = NULL;
375   if (mutex_unlock(&filp->filp_lock) != 0)
376 	panic("unable to release lock on filp");
377 }
378 
379 /*===========================================================================*
380  *				unlock_filps				     *
381  *===========================================================================*/
382 void
unlock_filps(struct filp * filp1,struct filp * filp2)383 unlock_filps(struct filp *filp1, struct filp *filp2)
384 {
385 /* Unlock two filps that are tied to the same vnode. As a thread can lock a
386  * vnode only once, unlocking the vnode twice would result in an error. */
387 
388   /* No NULL pointers and not equal */
389   assert(filp1);
390   assert(filp2);
391   assert(filp1 != filp2);
392 
393   /* Must be tied to the same vnode and not NULL */
394   assert(filp1->filp_vno == filp2->filp_vno);
395   assert(filp1->filp_vno != NULL);
396 
397   if (filp1->filp_count > 0 && filp2->filp_count > 0) {
398 	/* Only unlock vnode if filps are still in use */
399 	unlock_vnode(filp1->filp_vno);
400   }
401 
402   filp1->filp_softlock = NULL;
403   filp2->filp_softlock = NULL;
404   if (mutex_unlock(&filp2->filp_lock) != 0)
405 	panic("unable to release filp lock on filp2");
406   if (mutex_unlock(&filp1->filp_lock) != 0)
407 	panic("unable to release filp lock on filp1");
408 }
409 
410 /*===========================================================================*
411  *				close_filp				     *
412  *===========================================================================*/
413 int
close_filp(struct filp * f,int may_suspend)414 close_filp(struct filp * f, int may_suspend)
415 {
416 /* Close a file.  Will also unlock filp when done.  The 'may_suspend' flag
417  * indicates whether the current process may be suspended closing a socket.
418  * That is currently supported only when the user issued a close(2), and (only)
419  * in that case may this function return SUSPEND instead of OK.  In all other
420  * cases, this function will always return OK.  It will never return another
421  * error code, for reasons explained below.
422  */
423   int r, rw;
424   dev_t dev;
425   struct vnode *vp;
426 
427   /* Must be locked */
428   assert(mutex_trylock(&f->filp_lock) == -EDEADLK);
429   assert(tll_islocked(&f->filp_vno->v_lock));
430 
431   vp = f->filp_vno;
432 
433   r = OK;
434 
435   if (f->filp_count - 1 == 0 && f->filp_mode != FILP_CLOSED) {
436 	/* Check to see if the file is special. */
437 	if (S_ISCHR(vp->v_mode) || S_ISBLK(vp->v_mode) ||
438 	    S_ISSOCK(vp->v_mode)) {
439 		dev = vp->v_sdev;
440 		if (S_ISBLK(vp->v_mode))  {
441 			lock_bsf();
442 			if (vp->v_bfs_e == ROOT_FS_E && dev != ROOT_DEV) {
443 				/* Invalidate the cache unless the special is
444 				 * mounted. Be careful not to flush the root
445 				 * file system either.
446 				 */
447 				(void) req_flush(vp->v_bfs_e, dev);
448 			}
449 			unlock_bsf();
450 
451 			(void) bdev_close(dev);	/* Ignore errors */
452 		} else if (S_ISCHR(vp->v_mode)) {
453 			(void) cdev_close(dev);	/* Ignore errors */
454 		} else {
455 			/*
456 			 * Sockets may take a while to be closed (SO_LINGER),
457 			 * and thus, we may issue a suspending close to a
458 			 * socket driver.  Getting this working for close(2) is
459 			 * the easy case, and that is all we support for now.
460 			 * However, there is also eg dup2(2), which if
461 			 * interrupted by a signal should technically fail
462 			 * without closing the file descriptor.  Then there are
463 			 * cases where the close should never block: process
464 			 * exit and close-on-exec for example.  Getting all
465 			 * such cases right is left to future work; currently
466 			 * they all perform thread-blocking socket closes and
467 			 * thus cause the socket to perform lingering in the
468 			 * background if at all.
469 			 */
470 			assert(!may_suspend || job_call_nr == VFS_CLOSE);
471 
472 			if (f->filp_flags & O_NONBLOCK)
473 				may_suspend = FALSE;
474 
475 			r = sdev_close(dev, may_suspend);
476 
477 			/*
478 			 * Returning a non-OK error is a bad idea, because it
479 			 * will leave the application wondering whether closing
480 			 * the file descriptor actually succeeded.
481 			 */
482 			if (r != SUSPEND)
483 				r = OK;
484 		}
485 
486 		f->filp_mode = FILP_CLOSED;
487 	}
488   }
489 
490   /* If the inode being closed is a pipe, release everyone hanging on it. */
491   if (S_ISFIFO(vp->v_mode)) {
492 	rw = (f->filp_mode & R_BIT ? VFS_WRITE : VFS_READ);
493 	release(vp, rw, susp_count);
494   }
495 
496   if (--f->filp_count == 0) {
497 	if (S_ISFIFO(vp->v_mode)) {
498 		/* Last reader or writer is going. Tell PFS about latest
499 		 * pipe size.
500 		 */
501 		truncate_vnode(vp, vp->v_size);
502 	}
503 
504 	unlock_vnode(f->filp_vno);
505 	put_vnode(f->filp_vno);
506 	f->filp_vno = NULL;
507 	f->filp_mode = FILP_CLOSED;
508 	f->filp_count = 0;
509   } else if (f->filp_count < 0) {
510 	panic("VFS: invalid filp count: %d ino %llx/%llu", f->filp_count,
511 	      vp->v_dev, vp->v_inode_nr);
512   } else {
513 	unlock_vnode(f->filp_vno);
514   }
515 
516   mutex_unlock(&f->filp_lock);
517 
518   return r;
519 }
520 
521 /*===========================================================================*
522  *				do_copyfd				     *
523  *===========================================================================*/
do_copyfd(void)524 int do_copyfd(void)
525 {
526 /* Copy a file descriptor between processes, or close a remote file descriptor.
527  * This call is used as back-call by device drivers (UDS, VND), and is expected
528  * to be used in response to either an IOCTL to VND or a SEND or RECV socket
529  * request to UDS.
530  */
531   struct fproc *rfp;
532   struct filp *rfilp;
533   struct vnode *vp;
534   struct smap *sp;
535   endpoint_t endpt;
536   int r, fd, what, flags, slot;
537 
538   /* This should be replaced with an ACL check. */
539   if (!super_user) return(EPERM);
540 
541   endpt = job_m_in.m_lsys_vfs_copyfd.endpt;
542   fd = job_m_in.m_lsys_vfs_copyfd.fd;
543   what = job_m_in.m_lsys_vfs_copyfd.what;
544 
545   flags = what & COPYFD_FLAGS;
546   what &= ~COPYFD_FLAGS;
547 
548   if (isokendpt(endpt, &slot) != OK) return(EINVAL);
549   rfp = &fproc[slot];
550 
551   /* FIXME: we should now check that the user process is indeed blocked on an
552    * IOCTL or socket call, so that we can safely mess with its file
553    * descriptors.  We currently do not have the necessary state to verify this,
554    * so we assume that the call is always used in the right way.
555    */
556 
557   /* Depending on the operation, get the file descriptor from the caller or the
558    * user process.  Do not lock the filp yet: we first need to make sure that
559    * locking it will not result in a deadlock.
560    */
561   rfilp = get_filp2((what == COPYFD_TO) ? fp : rfp, fd, VNODE_NONE);
562   if (rfilp == NULL)
563 	return(err_code);
564 
565   /* If the filp is involved in an IOCTL by the user process, locking the filp
566    * here would result in a deadlock.  This would happen if a user process
567    * passes in the file descriptor to the device node on which it is performing
568    * the IOCTL.  We do not allow manipulation of such device nodes.  In
569    * practice, this only applies to block-special files (and thus VND), because
570    * socket files (as used by UDS) are unlocked during the socket operation.
571    */
572   if (rfilp->filp_ioctl_fp == rfp)
573 	return(EBADF);
574 
575   /* Now we can safely lock the filp, copy or close it, and unlock it again. */
576   lock_filp(rfilp, VNODE_READ);
577 
578   switch (what) {
579   case COPYFD_FROM:
580 	/*
581 	 * If the caller is a socket driver (namely, UDS) and the file
582 	 * descriptor being copied in is a socket for that socket driver, then
583 	 * deny the call, because of at least two known issues.  Both issues
584 	 * are related to UDS having an in-flight file descriptor that is the
585 	 * last reference to a UDS socket:
586 	 *
587 	 * 1) if UDS tries to close the file descriptor, this will prompt VFS
588 	 *    to close the underlying object, which is a UDS socket.  As a
589 	 *    result, while UDS is blocked in the close(2), VFS will try to
590 	 *    send a request to UDS to close the socket.  This results in a
591 	 *    deadlock of the UDS service.
592 	 *
593 	 * 2) if a file descriptor for a UDS socket is sent across that same
594 	 *    UDS socket, the socket will remain referenced by UDS, thus open
595 	 *    in VFS, and therefore also open in UDS.  The socket and file
596 	 *    descriptor will both remain in use for the rest of UDS' lifetime.
597 	 *    This can easily result in denial-of-service in the UDS service.
598 	 *    The same problem can be triggered using multiple sockets that
599 	 *    have in-flight file descriptors referencing each other.
600 	 *
601 	 * A proper solution for these problems may consist of some form of
602 	 * "soft reference counting" where VFS does not count UDS having a
603 	 * filp open as a real reference.  That is tricky business, so for now
604 	 * we prevent any such problems with the check here.
605 	 */
606 	if ((vp = rfilp->filp_vno) != NULL && S_ISSOCK(vp->v_mode) &&
607 	    (sp = get_smap_by_dev(vp->v_sdev, NULL)) != NULL &&
608 	    sp->smap_endpt == who_e) {
609 		r = EDEADLK;
610 
611 		break;
612 	}
613 
614 	rfp = fp;
615 	flags &= ~COPYFD_CLOEXEC;
616 
617 	/* FALLTHROUGH */
618   case COPYFD_TO:
619 	/* Find a free file descriptor slot in the local or remote process. */
620 	for (fd = 0; fd < OPEN_MAX; fd++)
621 		if (rfp->fp_filp[fd] == NULL)
622 			break;
623 
624 	/* If found, fill the slot and return the slot number. */
625 	if (fd < OPEN_MAX) {
626 		rfp->fp_filp[fd] = rfilp;
627 		if (flags & COPYFD_CLOEXEC)
628 			FD_SET(fd, &rfp->fp_cloexec_set);
629 		rfilp->filp_count++;
630 		r = fd;
631 	} else
632 		r = EMFILE;
633 
634 	break;
635 
636   case COPYFD_CLOSE:
637 	/* This should be used ONLY to revert a successful copy-to operation,
638 	 * and assumes that the filp is still in use by the caller as well.
639 	 */
640 	if (rfilp->filp_count > 1) {
641 		rfilp->filp_count--;
642 		rfp->fp_filp[fd] = NULL;
643 		r = OK;
644 	} else
645 		r = EBADF;
646 
647 	break;
648 
649   default:
650 	r = EINVAL;
651   }
652 
653   unlock_filp(rfilp);
654 
655   return(r);
656 }
657