Kernel pointer in uapi struct causes alignment issues moving between user-space and kernel-space. Change this to an unsigned int and make kernel accesses explicitly cast back to pointer.
Signed-off-by: Joshua Lant joshualant@gmail.com --- include/uapi/linux/netfilter/x_tables.h | 2 +- net/ipv4/netfilter/ip_tables.c | 18 +++++++++--------- net/ipv6/netfilter/ip6_tables.c | 18 +++++++++--------- net/netfilter/x_tables.c | 16 ++++++++-------- net/netfilter/xt_TCPMSS.c | 2 +- 5 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/include/uapi/linux/netfilter/x_tables.h b/include/uapi/linux/netfilter/x_tables.h index 796af83a963a..0122c4624886 100644 --- a/include/uapi/linux/netfilter/x_tables.h +++ b/include/uapi/linux/netfilter/x_tables.h @@ -21,7 +21,7 @@ struct xt_entry_match { __u16 match_size;
/* Used inside the kernel */ - struct xt_match *match; + unsigned long match; } kernel;
/* Total length */ diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index a54c54d4ba9c..236c2a7abad7 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -288,7 +288,7 @@ ipt_do_table(void *priv, }
xt_ematch_foreach(ematch, e) { - acpar.match = ematch->u.kernel.match; + acpar.match = (const struct xt_match *) ematch->u.kernel.match; acpar.matchinfo = ematch->data; if (!acpar.match->match(skb, &acpar)) goto no_match; @@ -452,7 +452,7 @@ static void cleanup_match(struct xt_entry_match *m, struct net *net) struct xt_mtdtor_param par;
par.net = net; - par.match = m->u.kernel.match; + par.match = (const struct xt_match *) m->u.kernel.match; par.matchinfo = m->data; par.family = NFPROTO_IPV4; if (par.match->destroy != NULL) @@ -465,7 +465,7 @@ check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) { const struct ipt_ip *ip = par->entryinfo;
- par->match = m->u.kernel.match; + par->match = (const struct xt_match *) m->u.kernel.match; par->matchinfo = m->data;
return xt_check_match(par, m->u.match_size - sizeof(*m), @@ -482,7 +482,7 @@ find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) m->u.user.revision); if (IS_ERR(match)) return PTR_ERR(match); - m->u.kernel.match = match; + m->u.kernel.match = (unsigned long) match;
ret = check_match(m, par); if (ret) @@ -490,7 +490,7 @@ find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
return 0; err: - module_put(m->u.kernel.match->me); + module_put(((struct xt_match *)(m->u.kernel.match))->me); return ret; }
@@ -898,7 +898,7 @@ static int compat_calc_entry(const struct ipt_entry *e, off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry); entry_offset = (void *)e - base; xt_ematch_foreach(ematch, e) - off += xt_compat_match_offset(ematch->u.kernel.match); + off += xt_compat_match_offset((struct xt_match *) ematch->u.kernel.match); t = ipt_get_target_c(e); off += xt_compat_target_offset(t->u.kernel.target); newinfo->size -= off; @@ -1265,7 +1265,7 @@ compat_find_calc_match(struct xt_entry_match *m, if (IS_ERR(match)) return PTR_ERR(match);
- m->u.kernel.match = match; + m->u.kernel.match = (unsigned long) match; *size += xt_compat_match_offset(match); return 0; } @@ -1277,7 +1277,7 @@ static void compat_release_entry(struct compat_ipt_entry *e)
/* Cleanup all matches */ xt_ematch_foreach(ematch, e) - module_put(ematch->u.kernel.match->me); + module_put(((struct xt_match *)ematch->u.kernel.match)->me); t = compat_ipt_get_target(e); module_put(t->u.kernel.target->me); } @@ -1346,7 +1346,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, xt_ematch_foreach(ematch, e) { if (j-- == 0) break; - module_put(ematch->u.kernel.match->me); + module_put(((struct xt_match *)ematch->u.kernel.match)->me); } return ret; } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 9bb1fa0f497c..120018ed7cd8 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -311,7 +311,7 @@ ip6t_do_table(void *priv, struct sk_buff *skb, }
xt_ematch_foreach(ematch, e) { - acpar.match = ematch->u.kernel.match; + acpar.match = (const struct xt_match *) ematch->u.kernel.match; acpar.matchinfo = ematch->data; if (!acpar.match->match(skb, &acpar)) goto no_match; @@ -470,7 +470,7 @@ static void cleanup_match(struct xt_entry_match *m, struct net *net) struct xt_mtdtor_param par;
par.net = net; - par.match = m->u.kernel.match; + par.match = (const struct xt_match *) m->u.kernel.match; par.matchinfo = m->data; par.family = NFPROTO_IPV6; if (par.match->destroy != NULL) @@ -482,7 +482,7 @@ static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) { const struct ip6t_ip6 *ipv6 = par->entryinfo;
- par->match = m->u.kernel.match; + par->match = (const struct xt_match *) m->u.kernel.match; par->matchinfo = m->data;
return xt_check_match(par, m->u.match_size - sizeof(*m), @@ -500,7 +500,7 @@ find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) if (IS_ERR(match)) return PTR_ERR(match);
- m->u.kernel.match = match; + m->u.kernel.match = (unsigned long) match;
ret = check_match(m, par); if (ret) @@ -508,7 +508,7 @@ find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
return 0; err: - module_put(m->u.kernel.match->me); + module_put(((struct xt_match *)(m->u.kernel.match))->me); return ret; }
@@ -914,7 +914,7 @@ static int compat_calc_entry(const struct ip6t_entry *e, off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry); entry_offset = (void *)e - base; xt_ematch_foreach(ematch, e) - off += xt_compat_match_offset(ematch->u.kernel.match); + off += xt_compat_match_offset((struct xt_match *) ematch->u.kernel.match); t = ip6t_get_target_c(e); off += xt_compat_target_offset(t->u.kernel.target); newinfo->size -= off; @@ -1281,7 +1281,7 @@ compat_find_calc_match(struct xt_entry_match *m, if (IS_ERR(match)) return PTR_ERR(match);
- m->u.kernel.match = match; + m->u.kernel.match = (unsigned long) match; *size += xt_compat_match_offset(match); return 0; } @@ -1293,7 +1293,7 @@ static void compat_release_entry(struct compat_ip6t_entry *e)
/* Cleanup all matches */ xt_ematch_foreach(ematch, e) - module_put(ematch->u.kernel.match->me); + module_put(((struct xt_match *)ematch->u.kernel.match)->me); t = compat_ip6t_get_target(e); module_put(t->u.kernel.target->me); } @@ -1362,7 +1362,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, xt_ematch_foreach(ematch, e) { if (j-- == 0) break; - module_put(ematch->u.kernel.match->me); + module_put(((struct xt_match *)ematch->u.kernel.match)->me); } return ret; } diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index caf838d56f4d..2e347789593a 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -306,8 +306,8 @@ static int xt_obj_to_user(u16 __user *psize, u16 size,
#define XT_OBJ_TO_USER(U, K, TYPE, C_SIZE) \ xt_obj_to_user(&U->u.TYPE##_size, C_SIZE ? : K->u.TYPE##_size, \ - U->u.user.name, K->u.kernel.TYPE->name, \ - &U->u.user.revision, K->u.kernel.TYPE->revision) + U->u.user.name, ((struct xt_##TYPE *)(K->u.kernel.TYPE))->name, \ + &U->u.user.revision, ((struct xt_##TYPE *)(K->u.kernel.TYPE))->revision)
int xt_data_to_user(void __user *dst, const void *src, int usersize, int size, int aligned_size) @@ -325,9 +325,9 @@ EXPORT_SYMBOL_GPL(xt_data_to_user);
#define XT_DATA_TO_USER(U, K, TYPE) \ xt_data_to_user(U->data, K->data, \ - K->u.kernel.TYPE->usersize, \ - K->u.kernel.TYPE->TYPE##size, \ - XT_ALIGN(K->u.kernel.TYPE->TYPE##size)) + ((struct xt_##TYPE *)(K->u.kernel.TYPE))->usersize, \ + ((struct xt_##TYPE *)(K->u.kernel.TYPE))->TYPE##size, \ + XT_ALIGN(((struct xt_##TYPE *)(K->u.kernel.TYPE))->TYPE##size))
int xt_match_to_user(const struct xt_entry_match *m, struct xt_entry_match __user *u) @@ -751,7 +751,7 @@ EXPORT_SYMBOL_GPL(xt_compat_match_offset); void xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, unsigned int *size) { - const struct xt_match *match = m->u.kernel.match; + const struct xt_match *match = (struct xt_match *) m->u.kernel.match; struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m; int off = xt_compat_match_offset(match); u_int16_t msize = cm->u.user.match_size; @@ -777,7 +777,7 @@ EXPORT_SYMBOL_GPL(xt_compat_match_from_user);
#define COMPAT_XT_DATA_TO_USER(U, K, TYPE, C_SIZE) \ xt_data_to_user(U->data, K->data, \ - K->u.kernel.TYPE->usersize, \ + ((struct xt_##TYPE *)(K->u.kernel.TYPE))->usersize, \ C_SIZE, \ COMPAT_XT_ALIGN(C_SIZE))
@@ -788,7 +788,7 @@ int xt_compat_match_to_user(const struct xt_entry_match *m, void __user **dstptr, unsigned int *size) #endif { - const struct xt_match *match = m->u.kernel.match; + const struct xt_match *match = (struct xt_match *) m->u.kernel.match; struct compat_xt_entry_match __user *cm = *dstptr; int off = xt_compat_match_offset(match); u_int16_t msize = m->u.user.match_size - off; diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 116a885adb3c..81841f55e6e8 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -252,7 +252,7 @@ static inline bool find_syn_match(const struct xt_entry_match *m) { const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
- if (strcmp(m->u.kernel.match->name, "tcp") == 0 && + if (strcmp(((struct xt_match *)(m->u.kernel.match))->name, "tcp") == 0 && tcpinfo->flg_cmp & TCPHDR_SYN && !(tcpinfo->invflags & XT_TCP_INV_FLAGS)) return true;