--- /dev/null
+From 31cc578ae2de19c748af06d859019dced68e325d Mon Sep 17 00:00:00 2001
+From: Saeed Mirzamohammadi <saeed.mirzamohammadi@oracle.com>
+Date: Tue, 20 Oct 2020 13:41:36 +0200
+Subject: netfilter: nftables_offload: KASAN slab-out-of-bounds Read in nft_flow_rule_create
+
+From: Saeed Mirzamohammadi <saeed.mirzamohammadi@oracle.com>
+
+commit 31cc578ae2de19c748af06d859019dced68e325d upstream.
+
+This patch fixes the issue due to:
+
+BUG: KASAN: slab-out-of-bounds in nft_flow_rule_create+0x622/0x6a2
+net/netfilter/nf_tables_offload.c:40
+Read of size 8 at addr ffff888103910b58 by task syz-executor227/16244
+
+The error happens when expr->ops is accessed early on before performing the boundary check and after nft_expr_next() moves the expr to go out-of-bounds.
+
+This patch checks the boundary condition before expr->ops that fixes the slab-out-of-bounds Read issue.
+
+Add nft_expr_more() and use it to fix this problem.
+
+Signed-off-by: Saeed Mirzamohammadi <saeed.mirzamohammadi@oracle.com>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/net/netfilter/nf_tables.h | 6 ++++++
+ net/netfilter/nf_tables_api.c | 6 +++---
+ net/netfilter/nf_tables_offload.c | 4 ++--
+ 3 files changed, 11 insertions(+), 5 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -896,6 +896,12 @@ static inline struct nft_expr *nft_expr_
+ return (struct nft_expr *)&rule->data[rule->dlen];
+ }
+
++static inline bool nft_expr_more(const struct nft_rule *rule,
++ const struct nft_expr *expr)
++{
++ return expr != nft_expr_last(rule) && expr->ops;
++}
++
+ static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule)
+ {
+ return (void *)&rule->data[rule->dlen];
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -295,7 +295,7 @@ static void nft_rule_expr_activate(const
+ struct nft_expr *expr;
+
+ expr = nft_expr_first(rule);
+- while (expr != nft_expr_last(rule) && expr->ops) {
++ while (nft_expr_more(rule, expr)) {
+ if (expr->ops->activate)
+ expr->ops->activate(ctx, expr);
+
+@@ -310,7 +310,7 @@ static void nft_rule_expr_deactivate(con
+ struct nft_expr *expr;
+
+ expr = nft_expr_first(rule);
+- while (expr != nft_expr_last(rule) && expr->ops) {
++ while (nft_expr_more(rule, expr)) {
+ if (expr->ops->deactivate)
+ expr->ops->deactivate(ctx, expr, phase);
+
+@@ -2917,7 +2917,7 @@ static void nf_tables_rule_destroy(const
+ * is called on error from nf_tables_newrule().
+ */
+ expr = nft_expr_first(rule);
+- while (expr != nft_expr_last(rule) && expr->ops) {
++ while (nft_expr_more(rule, expr)) {
+ next = nft_expr_next(expr);
+ nf_tables_expr_destroy(ctx, expr);
+ expr = next;
+--- a/net/netfilter/nf_tables_offload.c
++++ b/net/netfilter/nf_tables_offload.c
+@@ -37,7 +37,7 @@ struct nft_flow_rule *nft_flow_rule_crea
+ struct nft_expr *expr;
+
+ expr = nft_expr_first(rule);
+- while (expr->ops && expr != nft_expr_last(rule)) {
++ while (nft_expr_more(rule, expr)) {
+ if (expr->ops->offload_flags & NFT_OFFLOAD_F_ACTION)
+ num_actions++;
+
+@@ -61,7 +61,7 @@ struct nft_flow_rule *nft_flow_rule_crea
+ ctx->net = net;
+ ctx->dep.type = NFT_OFFLOAD_DEP_UNSPEC;
+
+- while (expr->ops && expr != nft_expr_last(rule)) {
++ while (nft_expr_more(rule, expr)) {
+ if (!expr->ops->offload) {
+ err = -EOPNOTSUPP;
+ goto err_out;