mirror of https://gitee.com/openkylin/linux.git
ip_options_compile: properly handle unaligned pointer
The current code takes an unaligned pointer and does htonl() on it to make it big-endian, then does a memcpy(). The problem is that the compiler decides that since the pointer is to a __be32, it is legal to optimize the copy into a processor word store. However, on an architecture that does not handled unaligned writes in kernel space, this produces an unaligned exception fault. The solution is to track the pointer as a "char *" (which removes a bunch of unpleasant casts in any case), and then just use put_unaligned_be32() to write the value to memory. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com> Signed-off-by: David S. Miller <davem@zippy.davemloft.net>
This commit is contained in:
parent
11ad2f5282
commit
48bdf072c3
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/unaligned.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/icmp.h>
|
#include <linux/icmp.h>
|
||||||
|
@ -350,7 +351,7 @@ int ip_options_compile(struct net *net,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (optptr[2] <= optlen) {
|
if (optptr[2] <= optlen) {
|
||||||
__be32 *timeptr = NULL;
|
unsigned char *timeptr = NULL;
|
||||||
if (optptr[2]+3 > optptr[1]) {
|
if (optptr[2]+3 > optptr[1]) {
|
||||||
pp_ptr = optptr + 2;
|
pp_ptr = optptr + 2;
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -359,7 +360,7 @@ int ip_options_compile(struct net *net,
|
||||||
case IPOPT_TS_TSONLY:
|
case IPOPT_TS_TSONLY:
|
||||||
opt->ts = optptr - iph;
|
opt->ts = optptr - iph;
|
||||||
if (skb)
|
if (skb)
|
||||||
timeptr = (__be32*)&optptr[optptr[2]-1];
|
timeptr = &optptr[optptr[2]-1];
|
||||||
opt->ts_needtime = 1;
|
opt->ts_needtime = 1;
|
||||||
optptr[2] += 4;
|
optptr[2] += 4;
|
||||||
break;
|
break;
|
||||||
|
@ -371,7 +372,7 @@ int ip_options_compile(struct net *net,
|
||||||
opt->ts = optptr - iph;
|
opt->ts = optptr - iph;
|
||||||
if (rt) {
|
if (rt) {
|
||||||
memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
|
memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
|
||||||
timeptr = (__be32*)&optptr[optptr[2]+3];
|
timeptr = &optptr[optptr[2]+3];
|
||||||
}
|
}
|
||||||
opt->ts_needaddr = 1;
|
opt->ts_needaddr = 1;
|
||||||
opt->ts_needtime = 1;
|
opt->ts_needtime = 1;
|
||||||
|
@ -389,7 +390,7 @@ int ip_options_compile(struct net *net,
|
||||||
if (inet_addr_type(net, addr) == RTN_UNICAST)
|
if (inet_addr_type(net, addr) == RTN_UNICAST)
|
||||||
break;
|
break;
|
||||||
if (skb)
|
if (skb)
|
||||||
timeptr = (__be32*)&optptr[optptr[2]+3];
|
timeptr = &optptr[optptr[2]+3];
|
||||||
}
|
}
|
||||||
opt->ts_needtime = 1;
|
opt->ts_needtime = 1;
|
||||||
optptr[2] += 8;
|
optptr[2] += 8;
|
||||||
|
@ -403,10 +404,10 @@ int ip_options_compile(struct net *net,
|
||||||
}
|
}
|
||||||
if (timeptr) {
|
if (timeptr) {
|
||||||
struct timespec tv;
|
struct timespec tv;
|
||||||
__be32 midtime;
|
u32 midtime;
|
||||||
getnstimeofday(&tv);
|
getnstimeofday(&tv);
|
||||||
midtime = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC);
|
midtime = (tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC;
|
||||||
memcpy(timeptr, &midtime, sizeof(__be32));
|
put_unaligned_be32(midtime, timeptr);
|
||||||
opt->is_changed = 1;
|
opt->is_changed = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue