diff --git a/target/linux/generic/pending-4.14/900-gen_stats-fix-netlink-stats-padding.patch b/target/linux/generic/pending-4.14/900-gen_stats-fix-netlink-stats-padding.patch new file mode 100644 index 0000000000..f5ceecca93 --- /dev/null +++ b/target/linux/generic/pending-4.14/900-gen_stats-fix-netlink-stats-padding.patch @@ -0,0 +1,49 @@ +The gen_stats facility will add a header for the toplevel nlattr of type +TCA_STATS2 that contains all stats added by qdisc callbacks. A reference +to this header is stored in the gnet_dump struct, and when all the +per-qdisc callbacks have finished adding their stats, the length of the +containing header will be adjusted to the right value. + +However, on architectures that need padding (i.e., that don't set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), the padding nlattr is added +before the stats, which means that the stored pointer will point to the +padding, and so when the header is fixed up, the result is just a very +big padding nlattr. Because most qdiscs also supply the legacy TCA_STATS +struct, this problem has been mostly invisible, but we exposed it with +the netlink attribute-based statistics in CAKE. + +Fix the issue by fixing up the stored pointer if it points to a padding +nlattr. + +Tested-by: Pete Heist +Tested-by: Kevin Darbyshire-Bryant +Signed-off-by: Toke Høiland-Jørgensen +--- + net/core/gen_stats.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +--- a/net/core/gen_stats.c ++++ b/net/core/gen_stats.c +@@ -77,8 +77,20 @@ gnet_stats_start_copy_compat(struct sk_b + d->lock = lock; + spin_lock_bh(lock); + } +- if (d->tail) +- return gnet_stats_copy(d, type, NULL, 0, padattr); ++ if (d->tail) { ++ int ret = gnet_stats_copy(d, type, NULL, 0, padattr); ++ ++ /* The initial attribute added in gnet_stats_copy() may be ++ * preceded by a padding attribute, in which case d->tail will ++ * end up pointing at the padding instead of the real attribute. ++ * Fix this so gnet_stats_finish_copy() adjusts the length of ++ * the right attribute. ++ */ ++ if (ret == 0 && d->tail->nla_type == padattr) ++ d->tail = (struct nlattr *)((char *)d->tail + ++ NLA_ALIGN(d->tail->nla_len)); ++ return ret; ++ } + + return 0; + } diff --git a/target/linux/generic/pending-4.9/900-gen_stats-fix-netlink-stats-padding.patch b/target/linux/generic/pending-4.9/900-gen_stats-fix-netlink-stats-padding.patch new file mode 100644 index 0000000000..f5ceecca93 --- /dev/null +++ b/target/linux/generic/pending-4.9/900-gen_stats-fix-netlink-stats-padding.patch @@ -0,0 +1,49 @@ +The gen_stats facility will add a header for the toplevel nlattr of type +TCA_STATS2 that contains all stats added by qdisc callbacks. A reference +to this header is stored in the gnet_dump struct, and when all the +per-qdisc callbacks have finished adding their stats, the length of the +containing header will be adjusted to the right value. + +However, on architectures that need padding (i.e., that don't set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), the padding nlattr is added +before the stats, which means that the stored pointer will point to the +padding, and so when the header is fixed up, the result is just a very +big padding nlattr. Because most qdiscs also supply the legacy TCA_STATS +struct, this problem has been mostly invisible, but we exposed it with +the netlink attribute-based statistics in CAKE. + +Fix the issue by fixing up the stored pointer if it points to a padding +nlattr. + +Tested-by: Pete Heist +Tested-by: Kevin Darbyshire-Bryant +Signed-off-by: Toke Høiland-Jørgensen +--- + net/core/gen_stats.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +--- a/net/core/gen_stats.c ++++ b/net/core/gen_stats.c +@@ -77,8 +77,20 @@ gnet_stats_start_copy_compat(struct sk_b + d->lock = lock; + spin_lock_bh(lock); + } +- if (d->tail) +- return gnet_stats_copy(d, type, NULL, 0, padattr); ++ if (d->tail) { ++ int ret = gnet_stats_copy(d, type, NULL, 0, padattr); ++ ++ /* The initial attribute added in gnet_stats_copy() may be ++ * preceded by a padding attribute, in which case d->tail will ++ * end up pointing at the padding instead of the real attribute. ++ * Fix this so gnet_stats_finish_copy() adjusts the length of ++ * the right attribute. ++ */ ++ if (ret == 0 && d->tail->nla_type == padattr) ++ d->tail = (struct nlattr *)((char *)d->tail + ++ NLA_ALIGN(d->tail->nla_len)); ++ return ret; ++ } + + return 0; + }