diff options
author | mlaier <mlaier@FreeBSD.org> | 2004-09-29 04:54:33 +0000 |
---|---|---|
committer | mlaier <mlaier@FreeBSD.org> | 2004-09-29 04:54:33 +0000 |
commit | b65eae4c193f1c3c9580e5ac2bad5585034743f2 (patch) | |
tree | b760834c7691b17430788d5a6041455045da8ac1 /sys/netinet/ip_fw2.c | |
parent | e455dd69f84961133d47cca1588021dfafac9e28 (diff) | |
download | FreeBSD-src-b65eae4c193f1c3c9580e5ac2bad5585034743f2.zip FreeBSD-src-b65eae4c193f1c3c9580e5ac2bad5585034743f2.tar.gz |
Add an additional struct inpcb * argument to pfil(9) in order to enable
passing along socket information. This is required to work around a LOR with
the socket code which results in an easy reproducible hard lockup with
debug.mpsafenet=1. This commit does *not* fix the LOR, but enables us to do
so later. The missing piece is to turn the filter locking into a leaf lock
and will follow in a seperate (later) commit.
This will hopefully be MT5'ed in order to fix the problem for RELENG_5 in
forseeable future.
Suggested by: rwatson
A lot of work by: csjp (he'd be even more helpful w/o mentor-reviews ;)
Reviewed by: rwatson, csjp
Tested by: -pf, -ipfw, LINT, csjp and myself
MFC after: 3 days
LOR IDs: 14 - 17 (not fixed yet)
Diffstat (limited to 'sys/netinet/ip_fw2.c')
-rw-r--r-- | sys/netinet/ip_fw2.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index a33b361..a8bcede 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -1532,21 +1532,48 @@ dump_table(ipfw_table *tbl) return (0); } +static void +fill_ugid_cache(struct inpcb *inp, struct ip_fw_ugid *ugp) +{ + struct ucred *cr; + + if (inp->inp_socket != NULL) { + cr = inp->inp_socket->so_cred; + ugp->fw_prid = jailed(cr) ? + cr->cr_prison->pr_id : -1; + ugp->fw_uid = cr->cr_uid; + ugp->fw_ngroups = cr->cr_ngroups; + bcopy(cr->cr_groups, ugp->fw_groups, + sizeof(ugp->fw_groups)); + } +} + static int check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif, struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip, u_int16_t src_port, - struct ip_fw_ugid *ugp, int *lookup) + struct ip_fw_ugid *ugp, int *lookup, struct inpcb *inp) { struct inpcbinfo *pi; int wildcard; struct inpcb *pcb; int match; - struct ucred *cr; gid_t *gp; /* + * Check to see if the UDP or TCP stack supplied us with + * the PCB. If so, rather then holding a lock and looking + * up the PCB, we can use the one that was supplied. + */ + if (inp && *lookup == 0) { + INP_LOCK_ASSERT(inp); + if (inp->inp_socket != NULL) { + fill_ugid_cache(inp, ugp); + *lookup = 1; + } + } + /* * If we have already been here and the packet has no * PCB entry associated with it, then we can safely * assume that this is a no match. @@ -1563,7 +1590,7 @@ check_uidgid(ipfw_insn_u32 *insn, return 0; match = 0; if (*lookup == 0) { - INP_INFO_RLOCK(pi); /* XXX LOR with IPFW */ + INP_INFO_RLOCK(pi); pcb = (oif) ? in_pcblookup_hash(pi, dst_ip, htons(dst_port), @@ -1576,13 +1603,7 @@ check_uidgid(ipfw_insn_u32 *insn, if (pcb != NULL) { INP_LOCK(pcb); if (pcb->inp_socket != NULL) { - cr = pcb->inp_socket->so_cred; - ugp->fw_prid = jailed(cr) ? - cr->cr_prison->pr_id : -1; - ugp->fw_uid = cr->cr_uid; - ugp->fw_ngroups = cr->cr_ngroups; - bcopy(cr->cr_groups, ugp->fw_groups, - sizeof(ugp->fw_groups)); + fill_ugid_cache(pcb, ugp); *lookup = 1; } INP_UNLOCK(pcb); @@ -1938,7 +1959,7 @@ check_body: proto, oif, dst_ip, dst_port, src_ip, src_port, &fw_ugid_cache, - &ugid_lookup); + &ugid_lookup, args->inp); break; case O_RECV: |