summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_fw2.c
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2003-11-07 23:26:57 +0000
committersam <sam@FreeBSD.org>2003-11-07 23:26:57 +0000
commit94792986aa79c6ce22b1a1cc8826ded182622203 (patch)
tree098ae12e71ce6c2c4f12d95cc8b458aa055209fd /sys/netinet/ip_fw2.c
parentae477bf06017bb98eb66293028ee886bc28d7026 (diff)
downloadFreeBSD-src-94792986aa79c6ce22b1a1cc8826ded182622203.zip
FreeBSD-src-94792986aa79c6ce22b1a1cc8826ded182622203.tar.gz
Move uid/gid checking logic out of line and lock inpcb usage. This
has a LOR between IPFW inpcb locks but I'm committing it now as the lesser of two evils (the other being unlocked use of in_pcblookup). Supported by: FreeBSD Foundation
Diffstat (limited to 'sys/netinet/ip_fw2.c')
-rw-r--r--sys/netinet/ip_fw2.c100
1 files changed, 60 insertions, 40 deletions
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c
index ed5946e..e5960df 100644
--- a/sys/netinet/ip_fw2.c
+++ b/sys/netinet/ip_fw2.c
@@ -1297,6 +1297,59 @@ lookup_next_rule(struct ip_fw *me)
return rule;
}
+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 inpcbinfo *pi;
+ int wildcard;
+ struct inpcb *pcb;
+ int match;
+
+ if (proto == IPPROTO_TCP) {
+ wildcard = 0;
+ pi = &tcbinfo;
+ } else if (proto == IPPROTO_UDP) {
+ wildcard = 1;
+ pi = &udbinfo;
+ } else
+ return 0;
+
+ match = 0;
+
+ INP_INFO_RLOCK(pi); /* XXX LOR with IPFW */
+ pcb = (oif) ?
+ in_pcblookup_hash(pi,
+ dst_ip, htons(dst_port),
+ src_ip, htons(src_port),
+ wildcard, oif) :
+ in_pcblookup_hash(pi,
+ src_ip, htons(src_port),
+ dst_ip, htons(dst_port),
+ wildcard, NULL);
+ if (pcb != NULL) {
+ INP_LOCK(pcb);
+ if (pcb->inp_socket != NULL) {
+#if __FreeBSD_version < 500034
+#define socheckuid(a,b) ((a)->so_cred->cr_uid != (b))
+#endif
+ if (insn->o.opcode == O_UID) {
+ match = !socheckuid(pcb->inp_socket,
+ (uid_t)insn->d[0]);
+ } else {
+ match = groupmember((uid_t)insn->d[0],
+ pcb->inp_socket->so_cred);
+ }
+ }
+ INP_UNLOCK(pcb);
+ }
+ INP_INFO_RUNLOCK(pi);
+
+ return match;
+}
+
/*
* The main check routine for the firewall.
*
@@ -1600,46 +1653,13 @@ check_body:
*/
if (offset!=0)
break;
- {
- struct inpcbinfo *pi;
- int wildcard;
- struct inpcb *pcb;
-
- if (proto == IPPROTO_TCP) {
- wildcard = 0;
- pi = &tcbinfo;
- } else if (proto == IPPROTO_UDP) {
- wildcard = 1;
- pi = &udbinfo;
- } else
- break;
-
- /* XXX locking? */
- pcb = (oif) ?
- in_pcblookup_hash(pi,
- dst_ip, htons(dst_port),
- src_ip, htons(src_port),
- wildcard, oif) :
- in_pcblookup_hash(pi,
- src_ip, htons(src_port),
- dst_ip, htons(dst_port),
- wildcard, NULL);
-
- if (pcb == NULL || pcb->inp_socket == NULL)
- break;
-#if __FreeBSD_version < 500034
-#define socheckuid(a,b) ((a)->so_cred->cr_uid != (b))
-#endif
- if (cmd->opcode == O_UID) {
- match =
- !socheckuid(pcb->inp_socket,
- (uid_t)((ipfw_insn_u32 *)cmd)->d[0]);
- } else {
- match = groupmember(
- (uid_t)((ipfw_insn_u32 *)cmd)->d[0],
- pcb->inp_socket->so_cred);
- }
- }
+ if (proto == IPPROTO_TCP ||
+ proto == IPPROTO_UDP)
+ match = check_uidgid(
+ (ipfw_insn_u32 *)cmd,
+ proto, oif,
+ src_ip, src_port,
+ dst_ip, dst_port);
break;
case O_RECV:
OpenPOWER on IntegriCloud