Home | History | Annotate | Line # | Download | only in kern
      1 /*	$NetBSD: subr_exec_fd.c,v 1.14 2026/01/04 03:17:30 riastradh 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 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: subr_exec_fd.c,v 1.14 2026/01/04 03:17:30 riastradh Exp $");
     31 
     32 #include <sys/param.h>
     33 
     34 #include <sys/atomic.h>
     35 #include <sys/file.h>
     36 #include <sys/filedesc.h>
     37 #include <sys/ktrace.h>
     38 #include <sys/mutex.h>
     39 #include <sys/namei.h>
     40 #include <sys/sdt.h>
     41 #include <sys/syslog.h>
     42 #include <sys/vnode.h>
     43 
     44 void
     45 fd_ktrexecfd(void)
     46 {
     47 	proc_t *p;
     48 	filedesc_t *fdp;
     49 	fdfile_t *ff;
     50 	lwp_t *l;
     51 	fdtab_t *dt;
     52 	file_t *fp;
     53 	int fd;
     54 
     55 	l = curlwp;
     56 	p = l->l_proc;
     57 	fdp = p->p_fd;
     58 	dt = atomic_load_consume(&fdp->fd_dt);
     59 
     60 	for (fd = 0; fd <= fdp->fd_lastfile; fd++) {
     61 		if ((ff = dt->dt_ff[fd]) == NULL) {
     62 			KASSERT(fd >= NDFDFILE);
     63 			continue;
     64 		}
     65 		KASSERT(fd >= NDFDFILE ||
     66 		    ff == (fdfile_t *)fdp->fd_dfdfile[fd]);
     67 		if ((fp = atomic_load_consume(&ff->ff_file)) == NULL)
     68 			continue;
     69 		ktr_execfd(fd, fp->f_type);
     70 	}
     71 }
     72 
     73 /*
     74  * It is unsafe for set[ug]id processes to be started with file
     75  * descriptors 0..2 closed, as these descriptors are given implicit
     76  * significance in the Standard C library.  fd_checkstd() will create a
     77  * descriptor referencing /dev/null for each of stdin, stdout, and
     78  * stderr that is not already open.
     79  */
     80 #define CHECK_UPTO 3
     81 int
     82 fd_checkstd(void)
     83 {
     84 	struct proc *p;
     85 	struct pathbuf *pb;
     86 	struct vnode *vp;
     87 	filedesc_t *fdp;
     88 	file_t *fp;
     89 	fdtab_t *dt;
     90 	struct proc *pp;
     91 	int fd, i, error, flags = FREAD|FWRITE;
     92 	char closed[CHECK_UPTO * 3 + 1], which[3 + 1];
     93 
     94 	p = curproc;
     95 	closed[0] = '\0';
     96 	if ((fdp = p->p_fd) == NULL)
     97 		return 0;
     98 	dt = atomic_load_consume(&fdp->fd_dt);
     99 	for (i = 0; i < CHECK_UPTO; i++) {
    100 		KASSERT(i >= NDFDFILE ||
    101 		    dt->dt_ff[i] == (fdfile_t *)fdp->fd_dfdfile[i]);
    102 		if (dt->dt_ff[i]->ff_file != NULL)
    103 			continue;
    104 		snprintf(which, sizeof(which), ",%d", i);
    105 		strlcat(closed, which, sizeof(closed));
    106 		if ((error = fd_allocfile(&fp, &fd)) != 0)
    107 			return error;
    108 		KASSERT(fd < CHECK_UPTO);
    109 		pb = pathbuf_create("/dev/null");
    110 		if (pb == NULL) {
    111 			return SET_ERROR(ENOMEM);
    112 		}
    113 		error = vn_open(NULL, pb, 0, flags, 0, &vp, NULL, NULL);
    114 		if (error != 0) {
    115 			pathbuf_destroy(pb);
    116 			fd_abort(p, fp, fd);
    117 			return error;
    118 		}
    119 		fp->f_type = DTYPE_VNODE;
    120 		fp->f_vnode = vp;
    121 		fp->f_flag = flags;
    122 		fp->f_ops = &vnops;
    123 		VOP_UNLOCK(vp);
    124 		fd_affix(p, fp, fd);
    125 		pathbuf_destroy(pb);
    126 	}
    127 	if (closed[0] != '\0') {
    128 		mutex_enter(&proc_lock);
    129 		pp = p->p_pptr;
    130 		mutex_enter(pp->p_lock);
    131 		log(LOG_WARNING, "set{u,g}id pid %d (%s) "
    132 		    "was invoked by uid %d ppid %d (%s) "
    133 		    "with fd %s closed\n",
    134 		    p->p_pid, p->p_comm, kauth_cred_geteuid(pp->p_cred),
    135 		    pp->p_pid, pp->p_comm, &closed[1]);
    136 		mutex_exit(pp->p_lock);
    137 		mutex_exit(&proc_lock);
    138 	}
    139 	return 0;
    140 }
    141 #undef CHECK_UPTO
    142