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/arp_tables.c | 22 ++++++++++----------- net/ipv4/netfilter/ip_tables.c | 26 ++++++++++++------------- net/ipv6/netfilter/ip6_tables.c | 26 ++++++++++++------------- net/netfilter/x_tables.c | 4 ++-- 5 files changed, 40 insertions(+), 40 deletions(-)
diff --git a/include/uapi/linux/netfilter/x_tables.h b/include/uapi/linux/netfilter/x_tables.h index 0122c4624886..8866b87ccc82 100644 --- a/include/uapi/linux/netfilter/x_tables.h +++ b/include/uapi/linux/netfilter/x_tables.h @@ -44,7 +44,7 @@ struct xt_entry_target { __u16 target_size;
/* Used inside the kernel */ - struct xt_target *target; + unsigned long target; } kernel;
/* Total length */ diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index fb6eb846c381..b222396221ec 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -233,7 +233,7 @@ unsigned int arpt_do_table(void *priv, t = arpt_get_target_c(e);
/* Standard target? */ - if (!t->u.kernel.target->target) { + if (!((struct xt_target *)t->u.kernel.target)->target) { int v;
v = ((struct xt_standard_target *)t)->verdict; @@ -265,9 +265,9 @@ unsigned int arpt_do_table(void *priv, continue; }
- acpar.target = t->u.kernel.target; + acpar.target = (struct xt_target *) t->u.kernel.target; acpar.targinfo = t->data; - verdict = t->u.kernel.target->target(skb, &acpar); + verdict = ((struct xt_target *)t->u.kernel.target)->target(skb, &acpar);
if (verdict == XT_CONTINUE) { /* Target might have changed stuff. */ @@ -392,7 +392,7 @@ static int check_target(struct arpt_entry *e, struct net *net, const char *name) .net = net, .table = name, .entryinfo = e, - .target = t->u.kernel.target, + .target = (struct xt_target *) t->u.kernel.target, .targinfo = t->data, .hook_mask = e->comefrom, .family = NFPROTO_ARP, @@ -420,14 +420,14 @@ find_check_entry(struct arpt_entry *e, struct net *net, const char *name, ret = PTR_ERR(target); goto out; } - t->u.kernel.target = target; + t->u.kernel.target = (unsigned long) target;
ret = check_target(e, net, name); if (ret) goto err; return 0; err: - module_put(t->u.kernel.target->me); + module_put(((struct xt_target *)t->u.kernel.target)->me); out: xt_percpu_counter_free(&e->counters);
@@ -504,7 +504,7 @@ static void cleanup_entry(struct arpt_entry *e, struct net *net)
t = arpt_get_target(e); par.net = net; - par.target = t->u.kernel.target; + par.target = (struct xt_target *) t->u.kernel.target; par.targinfo = t->data; par.family = NFPROTO_ARP; if (par.target->destroy != NULL) @@ -745,7 +745,7 @@ static int compat_calc_entry(const struct arpt_entry *e, entry_offset = (void *)e - base;
t = arpt_get_target_c(e); - off += xt_compat_target_offset(t->u.kernel.target); + off += xt_compat_target_offset((struct xt_target *)t->u.kernel.target); newinfo->size -= off; ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off); if (ret) @@ -1063,7 +1063,7 @@ static inline void compat_release_entry(struct compat_arpt_entry *e) struct xt_entry_target *t;
t = compat_arpt_get_target(e); - module_put(t->u.kernel.target->me); + module_put(((struct xt_target *)t->u.kernel.target)->me); }
static int @@ -1105,7 +1105,7 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, ret = PTR_ERR(target); goto out; } - t->u.kernel.target = target; + t->u.kernel.target = (unsigned long) target;
off += xt_compat_target_offset(target); *size += off; @@ -1116,7 +1116,7 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e, return 0;
release_target: - module_put(t->u.kernel.target->me); + module_put(((struct xt_target *)t->u.kernel.target)->me); out: return ret; } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 236c2a7abad7..f69c5d47221f 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -159,7 +159,7 @@ get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e, { const struct xt_standard_target *t = (void *)ipt_get_target_c(s);
- if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) { + if (strcmp(((struct xt_target *)t->target.u.kernel.target)->name, XT_ERROR_TARGET) == 0) { /* Head of user chain: ERROR target with chainname */ *chainname = t->target.data; (*rulenum) = 0; @@ -167,7 +167,7 @@ get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e, (*rulenum)++;
if (unconditional(s) && - strcmp(t->target.u.kernel.target->name, + strcmp(((struct xt_target *)t->target.u.kernel.target)->name, XT_STANDARD_TARGET) == 0 && t->verdict < 0) { /* Tail of chains: STANDARD target (return/policy) */ @@ -307,7 +307,7 @@ ipt_do_table(void *priv, state->out, table->name, private, e); #endif /* Standard target? */ - if (!t->u.kernel.target->target) { + if (!((struct xt_target *)t->u.kernel.target)->target) { int v;
v = ((struct xt_standard_target *)t)->verdict; @@ -339,10 +339,10 @@ ipt_do_table(void *priv, continue; }
- acpar.target = t->u.kernel.target; + acpar.target = (struct xt_target *) t->u.kernel.target; acpar.targinfo = t->data;
- verdict = t->u.kernel.target->target(skb, &acpar); + verdict = ((struct xt_target *)t->u.kernel.target)->target(skb, &acpar); if (verdict == XT_CONTINUE) { /* Target might have changed stuff. */ ip = ip_hdr(skb); @@ -501,7 +501,7 @@ static int check_target(struct ipt_entry *e, struct net *net, const char *name) .net = net, .table = name, .entryinfo = e, - .target = t->u.kernel.target, + .target = (struct xt_target *) t->u.kernel.target, .targinfo = t->data, .hook_mask = e->comefrom, .family = NFPROTO_IPV4, @@ -547,7 +547,7 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, ret = PTR_ERR(target); goto cleanup_matches; } - t->u.kernel.target = target; + t->u.kernel.target = (unsigned long) target;
ret = check_target(e, net, name); if (ret) @@ -555,7 +555,7 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
return 0; err: - module_put(t->u.kernel.target->me); + module_put(((struct xt_target *)t->u.kernel.target)->me); cleanup_matches: xt_ematch_foreach(ematch, e) { if (j-- == 0) @@ -645,7 +645,7 @@ cleanup_entry(struct ipt_entry *e, struct net *net) t = ipt_get_target(e);
par.net = net; - par.target = t->u.kernel.target; + par.target = (struct xt_target *) t->u.kernel.target; par.targinfo = t->data; par.family = NFPROTO_IPV4; if (par.target->destroy != NULL) @@ -900,7 +900,7 @@ static int compat_calc_entry(const struct ipt_entry *e, xt_ematch_foreach(ematch, e) 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); + off += xt_compat_target_offset((struct xt_target *) t->u.kernel.target); newinfo->size -= off; ret = xt_compat_add_offset(AF_INET, entry_offset, off); if (ret) @@ -1279,7 +1279,7 @@ static void compat_release_entry(struct compat_ipt_entry *e) xt_ematch_foreach(ematch, e) module_put(((struct xt_match *)ematch->u.kernel.match)->me); t = compat_ipt_get_target(e); - module_put(t->u.kernel.target->me); + module_put(((struct xt_target *)t->u.kernel.target)->me); }
static int @@ -1330,7 +1330,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, ret = PTR_ERR(target); goto release_matches; } - t->u.kernel.target = target; + t->u.kernel.target = (unsigned long) target;
off += xt_compat_target_offset(target); *size += off; @@ -1341,7 +1341,7 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e, return 0;
out: - module_put(t->u.kernel.target->me); + module_put(((struct xt_target *)t->u.kernel.target)->me); release_matches: xt_ematch_foreach(ematch, e) { if (j-- == 0) diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 120018ed7cd8..7d70576f499d 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -184,7 +184,7 @@ get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e, { const struct xt_standard_target *t = (void *)ip6t_get_target_c(s);
- if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) { + if (strcmp(((struct xt_target *)t->target.u.kernel.target)->name, XT_ERROR_TARGET) == 0) { /* Head of user chain: ERROR target with chainname */ *chainname = t->target.data; (*rulenum) = 0; @@ -192,7 +192,7 @@ get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e, (*rulenum)++;
if (unconditional(s) && - strcmp(t->target.u.kernel.target->name, + strcmp(((struct xt_target *)t->target.u.kernel.target)->name, XT_STANDARD_TARGET) == 0 && t->verdict < 0) { /* Tail of chains: STANDARD target (return/policy) */ @@ -330,7 +330,7 @@ ip6t_do_table(void *priv, struct sk_buff *skb, state->out, table->name, private, e); #endif /* Standard target? */ - if (!t->u.kernel.target->target) { + if (!((struct xt_target *)t->u.kernel.target)->target) { int v;
v = ((struct xt_standard_target *)t)->verdict; @@ -360,10 +360,10 @@ ip6t_do_table(void *priv, struct sk_buff *skb, continue; }
- acpar.target = t->u.kernel.target; + acpar.target = (struct xt_target *) t->u.kernel.target; acpar.targinfo = t->data;
- verdict = t->u.kernel.target->target(skb, &acpar); + verdict = ((struct xt_target *)t->u.kernel.target)->target(skb, &acpar); if (verdict == XT_CONTINUE) e = ip6t_next_entry(e); else @@ -519,7 +519,7 @@ static int check_target(struct ip6t_entry *e, struct net *net, const char *name) .net = net, .table = name, .entryinfo = e, - .target = t->u.kernel.target, + .target = (struct xt_target *) t->u.kernel.target, .targinfo = t->data, .hook_mask = e->comefrom, .family = NFPROTO_IPV6, @@ -566,14 +566,14 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, ret = PTR_ERR(target); goto cleanup_matches; } - t->u.kernel.target = target; + t->u.kernel.target = (unsigned long) target;
ret = check_target(e, net, name); if (ret) goto err; return 0; err: - module_put(t->u.kernel.target->me); + module_put(((struct xt_target *)t->u.kernel.target)->me); cleanup_matches: xt_ematch_foreach(ematch, e) { if (j-- == 0) @@ -662,7 +662,7 @@ static void cleanup_entry(struct ip6t_entry *e, struct net *net) t = ip6t_get_target(e);
par.net = net; - par.target = t->u.kernel.target; + par.target = (struct xt_target *) t->u.kernel.target; par.targinfo = t->data; par.family = NFPROTO_IPV6; if (par.target->destroy != NULL) @@ -916,7 +916,7 @@ static int compat_calc_entry(const struct ip6t_entry *e, xt_ematch_foreach(ematch, e) 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); + off += xt_compat_target_offset((struct xt_target *) t->u.kernel.target); newinfo->size -= off; ret = xt_compat_add_offset(AF_INET6, entry_offset, off); if (ret) @@ -1295,7 +1295,7 @@ static void compat_release_entry(struct compat_ip6t_entry *e) xt_ematch_foreach(ematch, e) module_put(((struct xt_match *)ematch->u.kernel.match)->me); t = compat_ip6t_get_target(e); - module_put(t->u.kernel.target->me); + module_put(((struct xt_target *)t->u.kernel.target)->me); }
static int @@ -1346,7 +1346,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, ret = PTR_ERR(target); goto release_matches; } - t->u.kernel.target = target; + t->u.kernel.target = (unsigned long) target;
off += xt_compat_target_offset(target); *size += off; @@ -1357,7 +1357,7 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e, return 0;
out: - module_put(t->u.kernel.target->me); + module_put(((struct xt_target *)t->u.kernel.target)->me); release_matches: xt_ematch_foreach(ematch, e) { if (j-- == 0) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 2e347789593a..66168d74ebac 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1135,7 +1135,7 @@ EXPORT_SYMBOL_GPL(xt_compat_target_offset); void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, unsigned int *size) { - const struct xt_target *target = t->u.kernel.target; + const struct xt_target *target = (struct xt_target *) t->u.kernel.target; struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; int off = xt_compat_target_offset(target); u_int16_t tsize = ct->u.user.target_size; @@ -1166,7 +1166,7 @@ int xt_compat_target_to_user(const struct xt_entry_target *t, void __user **dstptr, unsigned int *size) #endif { - const struct xt_target *target = t->u.kernel.target; + const struct xt_target *target = (struct xt_target *) t->u.kernel.target; struct compat_xt_entry_target __user *ct = *dstptr; int off = xt_compat_target_offset(target); u_int16_t tsize = t->u.user.target_size - off;