/*
 * Audit information about a file, either the file's vnode info, or its
 * socket address info.
 */
void
audit_arg_file(struct proc *p, struct file *fp)
{
	struct kaudit_record *ar;
	struct socket *so;
	struct inpcb *pcb;
	struct vnode *vp;
	int vfslocked;

	ar = currecord();
	if (ar == NULL)
		return;

	switch (fp->f_type) {
	case DTYPE_VNODE:
	case DTYPE_FIFO:
		/*
		 * XXXAUDIT: Only possibly to record as first vnode?
		 */
		vp = fp->f_vnode;
		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
		vn_lock(vp, LK_SHARED | LK_RETRY);
		audit_arg_vnode1(vp);
		VOP_UNLOCK(vp, 0);
		VFS_UNLOCK_GIANT(vfslocked);
		break;

	case DTYPE_SOCKET:
		so = (struct socket *)fp->f_data;
		if (INP_CHECK_SOCKAF(so, PF_INET)) {
			SOCK_LOCK(so);
			ar->k_ar.ar_arg_sockinfo.so_type =
			    so->so_type;
			ar->k_ar.ar_arg_sockinfo.so_domain =
			    INP_SOCKAF(so);
			ar->k_ar.ar_arg_sockinfo.so_protocol =
			    so->so_proto->pr_protocol;
			SOCK_UNLOCK(so);
			pcb = (struct inpcb *)so->so_pcb;
			INP_RLOCK(pcb);
			ar->k_ar.ar_arg_sockinfo.so_raddr =
			    pcb->inp_faddr.s_addr;
			ar->k_ar.ar_arg_sockinfo.so_laddr =
			    pcb->inp_laddr.s_addr;
			ar->k_ar.ar_arg_sockinfo.so_rport =
			    pcb->inp_fport;
			ar->k_ar.ar_arg_sockinfo.so_lport =
			    pcb->inp_lport;
			INP_RUNLOCK(pcb);
			ARG_SET_VALID(ar, ARG_SOCKINFO);
		}
		break;

	default:
		/* XXXAUDIT: else? */
		break;
	}
}
Exemple #2
0
__private_extern__ uint32_t
inpcb_count_opportunistic(unsigned int ifindex, struct inpcbinfo *pcbinfo,
    u_int32_t flags)
{
	uint32_t opportunistic = 0;

	lck_rw_lock_shared(pcbinfo->mtx);

	struct inpcb *inp;
	inp_gen_t	gencnt = pcbinfo->ipi_gencnt;
	for (inp = LIST_FIRST(pcbinfo->listhead);
		inp; inp = LIST_NEXT(inp, inp_list)) {
		if (inp->inp_gencnt <= gencnt &&
		    inp->inp_state != INPCB_STATE_DEAD &&
		    inp->inp_socket != NULL &&
		    so_get_opportunistic(inp->inp_socket) &&
		    inp->inp_last_outifp != NULL &&
		    ifindex == inp->inp_last_outifp->if_index) {
			opportunistic++;
			struct socket *so = inp->inp_socket;
			if ((flags & INPCB_OPPORTUNISTIC_SETCMD) &&
			    (so->so_state & SS_ISCONNECTED)) {
				socket_lock(so, 1);
				if (flags & INPCB_OPPORTUNISTIC_THROTTLEON) {
					so->so_flags |= SOF_SUSPENDED;
					soevent(so,
					    (SO_FILT_HINT_LOCKED |
					    SO_FILT_HINT_SUSPEND));
				} else {
					so->so_flags &= ~(SOF_SUSPENDED);
					soevent(so,
					    (SO_FILT_HINT_LOCKED |
					    SO_FILT_HINT_RESUME));
				}
				SOTHROTTLELOG(("throttle[%d]: so %p [%d,%d] "
				    "%s\n", so->last_pid, so, INP_SOCKAF(so),
				    INP_SOCKTYPE(so),
				    (so->so_flags & SOF_SUSPENDED) ?
				    "SUSPENDED" : "RESUMED"));
				socket_unlock(so, 1);
			}
		}
	}

	lck_rw_done(pcbinfo->mtx);

	return (opportunistic);
}
Exemple #3
0
int
in6_pcbbind(
	struct inpcb *inp,
	struct sockaddr *nam,
	struct proc *p)
{
	struct socket *so = inp->inp_socket;
	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)NULL;
	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
	u_short	lport = 0;
	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);

	if (!in6_ifaddrs) /* XXX broken! */
		return (EADDRNOTAVAIL);
	if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
		return(EINVAL);
	if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
		wild = 1;
	socket_unlock(so, 0); /* keep reference */
	lck_rw_lock_exclusive(pcbinfo->mtx);
	if (nam) {
		sin6 = (struct sockaddr_in6 *)nam;
		if (nam->sa_len != sizeof(*sin6)) {
			lck_rw_done(pcbinfo->mtx);
			socket_lock(so, 0);
			return(EINVAL);
		}
		/*
		 * family check.
		 */
		if (nam->sa_family != AF_INET6) {
			lck_rw_done(pcbinfo->mtx);
			socket_lock(so, 0);
			return(EAFNOSUPPORT);
		}

		/* KAME hack: embed scopeid */
		if (in6_embedscope(&sin6->sin6_addr, sin6, inp, NULL) != 0) {
			lck_rw_done(pcbinfo->mtx);
			socket_lock(so, 0);
			return EINVAL;
		}
		/* this must be cleared for ifa_ifwithaddr() */
		sin6->sin6_scope_id = 0;

		lport = sin6->sin6_port;
		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
			/*
			 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
			 * allow compepte duplication of binding if
			 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
			 * and a multicast address is bound on both
			 * new and duplicated sockets.
			 */
			if (so->so_options & SO_REUSEADDR)
				reuseport = SO_REUSEADDR|SO_REUSEPORT;
		} else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
			struct ifaddr *ia = NULL;

			sin6->sin6_port = 0;		/* yech... */
			if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == 0) {
				lck_rw_done(pcbinfo->mtx);
				socket_lock(so, 0);
				return(EADDRNOTAVAIL);
			}

			/*
			 * XXX: bind to an anycast address might accidentally
			 * cause sending a packet with anycast source address.
			 * We should allow to bind to a deprecated address, since
			 * the application dare to use it.
			 */
			if (ia &&
			    ((struct in6_ifaddr *)ia)->ia6_flags &
			    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) {
			    	ifafree(ia);
				lck_rw_done(pcbinfo->mtx);
				socket_lock(so, 0);
				return(EADDRNOTAVAIL);
			}
			ifafree(ia);
			ia = NULL;
		}
		if (lport) {
			struct inpcb *t;

			/* GROSS */
			if (ntohs(lport) < IPV6PORT_RESERVED && p &&
                            ((so->so_state & SS_PRIV) == 0)) {
				lck_rw_done(pcbinfo->mtx);
				socket_lock(so, 0);
				return(EACCES);
			}

			if (so->so_uid &&
			    !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
				t = in6_pcblookup_local_and_cleanup(pcbinfo,
				    &sin6->sin6_addr, lport,
				    INPLOOKUP_WILDCARD);
				if (t &&
				    (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ||
				     !IN6_IS_ADDR_UNSPECIFIED(&t->in6p_laddr) ||
				     (t->inp_socket->so_options &
				      SO_REUSEPORT) == 0) &&
				     (so->so_uid != t->inp_socket->so_uid) &&
				     ((t->inp_socket->so_flags & SOF_REUSESHAREUID) == 0)) {
					lck_rw_done(pcbinfo->mtx);
					socket_lock(so, 0);
					return (EADDRINUSE);
				}
				if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
				    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
					struct sockaddr_in sin;

					in6_sin6_2_sin(&sin, sin6);
					t = in_pcblookup_local_and_cleanup(pcbinfo,
						sin.sin_addr, lport,
						INPLOOKUP_WILDCARD);
					if (t && (t->inp_socket->so_options & SO_REUSEPORT) == 0 &&
					    (so->so_uid !=
					     t->inp_socket->so_uid) &&
					    (ntohl(t->inp_laddr.s_addr) !=
					     INADDR_ANY ||
					     INP_SOCKAF(so) ==
					     INP_SOCKAF(t->inp_socket))) {

						lck_rw_done(pcbinfo->mtx);
						socket_lock(so, 0);
						return (EADDRINUSE);
					}
				}
			}
			t = in6_pcblookup_local_and_cleanup(pcbinfo, &sin6->sin6_addr,
						lport, wild);
			if (t && (reuseport & t->inp_socket->so_options) == 0) {
				lck_rw_done(pcbinfo->mtx);
				socket_lock(so, 0);
				return(EADDRINUSE);
			}
			if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
			    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
				struct sockaddr_in sin;

				in6_sin6_2_sin(&sin, sin6);
				t = in_pcblookup_local_and_cleanup(pcbinfo, sin.sin_addr,
						       lport, wild);
				if (t &&
				    (reuseport & t->inp_socket->so_options)
				    == 0 &&
				    (ntohl(t->inp_laddr.s_addr)
				     != INADDR_ANY ||
				     INP_SOCKAF(so) ==
				     INP_SOCKAF(t->inp_socket))) {
					lck_rw_done(pcbinfo->mtx);
					socket_lock(so, 0);
					return (EADDRINUSE);
				}
			}
		}
		inp->in6p_laddr = sin6->sin6_addr;
	}
	socket_lock(so, 0);
	if (lport == 0) {
		int e;
		if ((e = in6_pcbsetport(&inp->in6p_laddr, inp, p, 1)) != 0) {
			lck_rw_done(pcbinfo->mtx);
			return(e);
		}
	}
	else {
		inp->inp_lport = lport;
		if (in_pcbinshash(inp, 1) != 0) {
			inp->in6p_laddr = in6addr_any;
			inp->inp_lport = 0;
			lck_rw_done(pcbinfo->mtx);
			return (EAGAIN);
		}
	}	
	lck_rw_done(pcbinfo->mtx);
	sflt_notify(so, sock_evt_bound, NULL);
	return(0);
}