Browse Source

[IPV6] SNMP: Avoid unaligned accesses.

Because stats pointer may not be aligned for u64, use memcpy
to fill u64 values.
Issue reported by David Miller <davem@davemloft.net>.

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
YOSHIFUJI Hideaki 18 years ago
parent
commit
2334e97355
2 changed files with 17 additions and 7 deletions
  1. 1 1
      include/net/ipv6.h
  2. 16 6
      net/ipv6/proc.c

+ 1 - 1
include/net/ipv6.h

@@ -172,7 +172,7 @@ int snmp6_alloc_dev(struct inet6_dev *idev);
 int snmp6_free_dev(struct inet6_dev *idev);
 int snmp6_free_dev(struct inet6_dev *idev);
 int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign);
 int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign);
 void snmp6_mib_free(void *ptr[2]);
 void snmp6_mib_free(void *ptr[2]);
-void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, int bytes);
+void snmp6_fill_stats(void *stats, struct inet6_dev *idev, int attrtype, int bytes);
 
 
 struct ip6_ra_chain
 struct ip6_ra_chain
 {
 {

+ 16 - 6
net/ipv6/proc.c

@@ -210,20 +210,30 @@ static const struct file_operations snmp6_seq_fops = {
 };
 };
 #endif	/* CONFIG_PROC_FS */
 #endif	/* CONFIG_PROC_FS */
 
 
+/*
+ * Stats may not be aligned for u64, so use memcpy to avoid
+ * unaligned accesses.
+ */
+static inline void __set_u64(void *p, u64 v)
+{
+	memcpy(p, &v, sizeof(u64));
+}
+
 static inline void
 static inline void
-__snmp6_fill_stats(u64 *stats, void **mib, int items, int bytes)
+__snmp6_fill_stats(void *stats, void **mib, int items, int bytes)
 {
 {
 	int i;
 	int i;
+	u8 *p = stats;
 	int pad = bytes - sizeof(u64) * items;
 	int pad = bytes - sizeof(u64) * items;
 	BUG_ON(pad < 0);
 	BUG_ON(pad < 0);
-	stats[0] = items;
-	for (i = 1; i < items; i++)
-		stats[i] = (u64)fold_field(mib, i);
-	memset(&stats[items], 0, pad);
+	__set_u64(p, items);
+	for (i = 1, p += sizeof(u64); i < items; i++, p += sizeof(u64))
+		__set_u64(p, fold_field(mib, i));
+	memset(p, 0, pad);
 }
 }
 
 
 void
 void
-snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, int bytes)
+snmp6_fill_stats(void *stats, struct inet6_dev *idev, int attrtype, int bytes)
 {
 {
 	switch(attrtype) {
 	switch(attrtype) {
 	case IFLA_INET6_STATS:
 	case IFLA_INET6_STATS: