diff options
author | rwatson <rwatson@FreeBSD.org> | 2008-07-29 19:37:16 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2008-07-29 19:37:16 +0000 |
commit | 4082f248156aae5409102554cfe53d44d2f421e6 (patch) | |
tree | 5e289ab59443e0fdff6f3ba6d038b082ef4dd6fe /sys/netinet6/icmp6.c | |
parent | 2f0c3f6d28da0886e68ac911efb23033c8b1e48f (diff) | |
download | FreeBSD-src-4082f248156aae5409102554cfe53d44d2f421e6.zip FreeBSD-src-4082f248156aae5409102554cfe53d44d2f421e6.tar.gz |
When copying in and out current ICMPv6 filters on a raw IPv6 socket,
lock the inpcb and use a local stack variable to copy to/from userspace
so that sooptcopyin()/sooptcopyout() aren't called while holding an
rwlock.
While here, fix a bug in which a failed sooptcopyin() might lead to
partially consistent ICMPv6 filters on the socket by not ignoring the
error returned by sooptcopyin().
MFC after: 2 weeks
Diffstat (limited to 'sys/netinet6/icmp6.c')
-rw-r--r-- | sys/netinet6/icmp6.c | 20 |
1 files changed, 14 insertions, 6 deletions
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 3fdff60..89fbe29 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -2715,14 +2715,18 @@ icmp6_ctloutput(struct socket *so, struct sockopt *sopt) switch (optname) { case ICMP6_FILTER: { - struct icmp6_filter *p; + struct icmp6_filter ic6f; - if (optlen != sizeof(*p)) { + if (optlen != sizeof(ic6f)) { error = EMSGSIZE; break; } - error = sooptcopyin(sopt, inp->in6p_icmp6filt, optlen, - optlen); + error = sooptcopyin(sopt, &ic6f, optlen, optlen); + if (error == 0) { + INP_WLOCK(inp); + *inp->in6p_icmp6filt = ic6f; + INP_WUNLOCK(inp); + } break; } @@ -2736,8 +2740,12 @@ icmp6_ctloutput(struct socket *so, struct sockopt *sopt) switch (optname) { case ICMP6_FILTER: { - error = sooptcopyout(sopt, inp->in6p_icmp6filt, - sizeof(struct icmp6_filter)); + struct icmp6_filter ic6f; + + INP_RLOCK(inp); + ic6f = *inp->in6p_icmp6filt; + INP_RUNLOCK(inp); + error = sooptcopyout(sopt, &ic6f, sizeof(ic6f)); break; } |