Check the alignment of the IP header before passing the packet up to the
packet filter. This would cause a panic on architectures that require strict alignment such as sparc64 (tier1) and ia64/ppc (tier2). This adds two new macros that check the alignment, these are compile time dependent on __NO_STRICT_ALIGNMENT which is set for i386 and amd64 where alignment isn't need so the cost is avoided. IP_HDR_ALIGNED_P() IP6_HDR_ALIGNED_P() Move bridge_ip_checkbasic()/bridge_ip6_checkbasic() up so that the alignment is checked for ipfw and dummynet too. PR: ia64/81284 Obtained from: NetBSD Approved by: re (dwhite), mlaier (mentor)
This commit is contained in:
parent
dd5c43b572
commit
d7e928629d
@ -43,6 +43,8 @@
|
||||
#error this file needs sys/cdefs.h as a prerequisite
|
||||
#endif
|
||||
|
||||
#define __NO_STRICT_ALIGNMENT
|
||||
|
||||
/*
|
||||
* Basic types upon which most other types are built.
|
||||
*/
|
||||
|
@ -43,6 +43,8 @@
|
||||
#error this file needs sys/cdefs.h as a prerequisite
|
||||
#endif
|
||||
|
||||
#define __NO_STRICT_ALIGNMENT
|
||||
|
||||
/*
|
||||
* Basic types upon which most other types are built.
|
||||
*/
|
||||
|
@ -2249,7 +2249,28 @@ static int bridge_pfil(struct mbuf **mp, struct ifnet *bifp,
|
||||
m_adj(*mp, sizeof(struct llc));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the IP header for alignment and errors
|
||||
*/
|
||||
if (dir == PFIL_IN) {
|
||||
switch (ether_type) {
|
||||
case ETHERTYPE_IP:
|
||||
error = bridge_ip_checkbasic(mp);
|
||||
break;
|
||||
# ifdef INET6
|
||||
case ETHERTYPE_IPV6:
|
||||
error = bridge_ip6_checkbasic(mp);
|
||||
break;
|
||||
# endif /* INET6 */
|
||||
default:
|
||||
error = 0;
|
||||
}
|
||||
if (error)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (IPFW_LOADED && pfil_ipfw != 0 && dir == PFIL_OUT) {
|
||||
error = -1;
|
||||
args.rule = ip_dn_claim_rule(*mp);
|
||||
if (args.rule != NULL && fw_one_pass)
|
||||
goto ipfwpass; /* packet already partially processed */
|
||||
@ -2286,26 +2307,22 @@ static int bridge_pfil(struct mbuf **mp, struct ifnet *bifp,
|
||||
}
|
||||
|
||||
ipfwpass:
|
||||
error = 0;
|
||||
|
||||
/*
|
||||
* Check basic packet sanity and run pfil through pfil.
|
||||
* Run the packet through pfil
|
||||
*/
|
||||
switch (ether_type)
|
||||
{
|
||||
case ETHERTYPE_IP :
|
||||
error = (dir == PFIL_IN) ? bridge_ip_checkbasic(mp) : 0;
|
||||
/*
|
||||
* before calling the firewall, swap fields the same as
|
||||
* IP does. here we assume the header is contiguous
|
||||
*/
|
||||
if (error == 0) {
|
||||
ip = mtod(*mp, struct ip *);
|
||||
ip = mtod(*mp, struct ip *);
|
||||
|
||||
ip->ip_len = ntohs(ip->ip_len);
|
||||
ip->ip_off = ntohs(ip->ip_off);
|
||||
} else {
|
||||
error = -1;
|
||||
break;
|
||||
}
|
||||
ip->ip_len = ntohs(ip->ip_len);
|
||||
ip->ip_off = ntohs(ip->ip_off);
|
||||
|
||||
/*
|
||||
* Run pfil on the member interface and the bridge, both can
|
||||
@ -2314,21 +2331,21 @@ ipfwpass:
|
||||
* Keep the order:
|
||||
* in_if -> bridge_if -> out_if
|
||||
*/
|
||||
if (error == 0 && pfil_bridge && dir == PFIL_OUT)
|
||||
if (pfil_bridge && dir == PFIL_OUT)
|
||||
error = pfil_run_hooks(&inet_pfil_hook, mp, bifp,
|
||||
dir, NULL);
|
||||
|
||||
if (*mp == NULL) /* filter may consume */
|
||||
if (*mp == NULL || error != 0) /* filter may consume */
|
||||
break;
|
||||
|
||||
if (error == 0 && pfil_member)
|
||||
if (pfil_member)
|
||||
error = pfil_run_hooks(&inet_pfil_hook, mp, ifp,
|
||||
dir, NULL);
|
||||
|
||||
if (*mp == NULL) /* filter may consume */
|
||||
if (*mp == NULL || error != 0) /* filter may consume */
|
||||
break;
|
||||
|
||||
if (error == 0 && pfil_bridge && dir == PFIL_IN)
|
||||
if (pfil_bridge && dir == PFIL_IN)
|
||||
error = pfil_run_hooks(&inet_pfil_hook, mp, bifp,
|
||||
dir, NULL);
|
||||
|
||||
@ -2342,23 +2359,21 @@ ipfwpass:
|
||||
break;
|
||||
# ifdef INET6
|
||||
case ETHERTYPE_IPV6 :
|
||||
error = (dir == PFIL_IN) ? bridge_ip6_checkbasic(mp) : 0;
|
||||
|
||||
if (error == 0 && pfil_bridge && dir == PFIL_OUT)
|
||||
if (pfil_bridge && dir == PFIL_OUT)
|
||||
error = pfil_run_hooks(&inet6_pfil_hook, mp, bifp,
|
||||
dir, NULL);
|
||||
|
||||
if (*mp == NULL) /* filter may consume */
|
||||
if (*mp == NULL || error != 0) /* filter may consume */
|
||||
break;
|
||||
|
||||
if (error == 0 && pfil_member)
|
||||
if (pfil_member)
|
||||
error = pfil_run_hooks(&inet6_pfil_hook, mp, ifp,
|
||||
dir, NULL);
|
||||
|
||||
if (*mp == NULL) /* filter may consume */
|
||||
if (*mp == NULL || error != 0) /* filter may consume */
|
||||
break;
|
||||
|
||||
if (error == 0 && pfil_bridge && dir == PFIL_IN)
|
||||
if (pfil_bridge && dir == PFIL_IN)
|
||||
error = pfil_run_hooks(&inet6_pfil_hook, mp, bifp,
|
||||
dir, NULL);
|
||||
break;
|
||||
@ -2421,7 +2436,14 @@ bridge_ip_checkbasic(struct mbuf **mp)
|
||||
if (*mp == NULL)
|
||||
return -1;
|
||||
|
||||
if (__predict_false(m->m_len < sizeof (struct ip))) {
|
||||
if (IP_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) {
|
||||
if ((m = m_copyup(m, sizeof(struct ip),
|
||||
(max_linkhdr + 3) & ~3)) == NULL) {
|
||||
/* XXXJRT new stat, please */
|
||||
ipstat.ips_toosmall++;
|
||||
goto bad;
|
||||
}
|
||||
} else if (__predict_false(m->m_len < sizeof (struct ip))) {
|
||||
if ((m = m_pullup(m, sizeof (struct ip))) == NULL) {
|
||||
ipstat.ips_toosmall++;
|
||||
goto bad;
|
||||
@ -2509,18 +2531,17 @@ bridge_ip6_checkbasic(struct mbuf **mp)
|
||||
* mbuf with space for link headers, in the event we forward
|
||||
* it. Otherwise, if it is aligned, make sure the entire base
|
||||
* IPv6 header is in the first mbuf of the chain.
|
||||
|
||||
*/
|
||||
if (IP6_HDR_ALIGNED_P(mtod(m, caddr_t)) == 0) {
|
||||
struct ifnet *inifp = m->m_pkthdr.rcvif;
|
||||
if ((m = m_copyup(m, sizeof(struct ip6_hdr),
|
||||
(max_linkhdr + 3) & ~3)) == NULL) {
|
||||
* XXXJRT new stat, please *
|
||||
/* XXXJRT new stat, please */
|
||||
ip6stat.ip6s_toosmall++;
|
||||
in6_ifstat_inc(inifp, ifs6_in_hdrerr);
|
||||
goto bad;
|
||||
}
|
||||
} else */
|
||||
if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) {
|
||||
} else if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) {
|
||||
struct ifnet *inifp = m->m_pkthdr.rcvif;
|
||||
if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
|
||||
ip6stat.ip6s_toosmall++;
|
||||
|
@ -136,6 +136,12 @@ struct ipstat {
|
||||
/* mbuf flag used by ip_fastfwd */
|
||||
#define M_FASTFWD_OURS M_PROTO1 /* changed dst to local */
|
||||
|
||||
#ifdef __NO_STRICT_ALIGNMENT
|
||||
#define IP_HDR_ALIGNED_P(ip) 1
|
||||
#else
|
||||
#define IP_HDR_ALIGNED_P(ip) ((((intptr_t) (ip)) & 3) == 0)
|
||||
#endif
|
||||
|
||||
struct ip;
|
||||
struct inpcb;
|
||||
struct route;
|
||||
|
@ -282,6 +282,12 @@ struct ip6aux {
|
||||
#define IPV6_FORWARDING 0x02 /* most of IPv6 header exists */
|
||||
#define IPV6_MINMTU 0x04 /* use minimum MTU (IPV6_USE_MIN_MTU) */
|
||||
|
||||
#ifdef __NO_STRICT_ALIGNMENT
|
||||
#define IP6_HDR_ALIGNED_P(ip) 1
|
||||
#else
|
||||
#define IP6_HDR_ALIGNED_P(ip) ((((intptr_t) (ip)) & 3) == 0)
|
||||
#endif
|
||||
|
||||
extern struct ip6stat ip6stat; /* statistics */
|
||||
extern int ip6_defhlim; /* default hop limit */
|
||||
extern int ip6_defmcasthlim; /* default multicast hop limit */
|
||||
|
Loading…
x
Reference in New Issue
Block a user