Blame SOURCES/0012-netlink_delinearize-Fix-resource-leaks.patch

ba04b3
From 5e9e2dc7e972f6bbbc0156ad97b4ee9d11fcb837 Mon Sep 17 00:00:00 2001
ba04b3
From: Phil Sutter <psutter@redhat.com>
ba04b3
Date: Wed, 20 Jun 2018 09:22:47 +0200
ba04b3
Subject: [PATCH] netlink_delinearize: Fix resource leaks
ba04b3
ba04b3
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1504157
ba04b3
Upstream Status: nftables commit 671851617c8d8
ba04b3
ba04b3
commit 671851617c8d8c1dfe9822eee8dcc7b827fff850
ba04b3
Author: Phil Sutter <phil@nwl.cc>
ba04b3
Date:   Thu Mar 1 15:00:32 2018 +0100
ba04b3
ba04b3
    netlink_delinearize: Fix resource leaks
ba04b3
ba04b3
    Most of the cases are basically the same: Error path fails to free the
ba04b3
    previously allocated statement or expression. A few cases received
ba04b3
    special treatment though:
ba04b3
ba04b3
    - In netlink_parse_payload_stmt(), the leak is easily avoided by code
ba04b3
      reordering.
ba04b3
ba04b3
    - In netlink_parse_exthdr(), there's no point in introducing a goto
ba04b3
      label since there is but a single affected error check.
ba04b3
ba04b3
    - In netlink_parse_hash() non-error path leaked as well if sreg
ba04b3
      contained a concatenated expression.
ba04b3
ba04b3
    Signed-off-by: Phil Sutter <phil@nwl.cc>
ba04b3
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
ba04b3
---
ba04b3
 src/netlink_delinearize.c | 144 +++++++++++++++++++++++++++++-----------------
ba04b3
 1 file changed, 92 insertions(+), 52 deletions(-)
ba04b3
ba04b3
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
ba04b3
index 61cba52..e25160a 100644
ba04b3
--- a/src/netlink_delinearize.c
ba04b3
+++ b/src/netlink_delinearize.c
ba04b3
@@ -470,15 +470,15 @@ static void netlink_parse_payload_stmt(struct netlink_parse_ctx *ctx,
ba04b3
 	offset = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_OFFSET) * BITS_PER_BYTE;
ba04b3
 	len    = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_LEN) * BITS_PER_BYTE;
ba04b3
 
ba04b3
-	expr = payload_expr_alloc(loc, NULL, 0);
ba04b3
-	payload_init_raw(expr, base, offset, len);
ba04b3
-
ba04b3
 	sreg = netlink_parse_register(nle, NFTNL_EXPR_PAYLOAD_SREG);
ba04b3
 	val  = netlink_get_register(ctx, loc, sreg);
ba04b3
 	if (val == NULL)
ba04b3
 		return netlink_error(ctx, loc,
ba04b3
 				     "payload statement has no expression");
ba04b3
 
ba04b3
+	expr = payload_expr_alloc(loc, NULL, 0);
ba04b3
+	payload_init_raw(expr, base, offset, len);
ba04b3
+
ba04b3
 	stmt = payload_stmt_alloc(loc, expr, val);
ba04b3
 
ba04b3
 	list_add_tail(&stmt->list, &ctx->rule->stmts);
ba04b3
@@ -523,9 +523,11 @@ static void netlink_parse_exthdr(struct netlink_parse_ctx *ctx,
ba04b3
 
ba04b3
 		sreg = netlink_parse_register(nle, NFTNL_EXPR_EXTHDR_SREG);
ba04b3
 		val = netlink_get_register(ctx, loc, sreg);
ba04b3
-		if (val == NULL)
ba04b3
+		if (val == NULL) {
ba04b3
+			xfree(expr);
ba04b3
 			return netlink_error(ctx, loc,
ba04b3
 					     "exthdr statement has no expression");
ba04b3
+		}
ba04b3
 
ba04b3
 		expr_set_type(val, expr->dtype, expr->byteorder);
ba04b3
 
ba04b3
@@ -556,22 +558,27 @@ static void netlink_parse_hash(struct netlink_parse_ctx *ctx,
ba04b3
 		sreg = netlink_parse_register(nle, NFTNL_EXPR_HASH_SREG);
ba04b3
 		hexpr = netlink_get_register(ctx, loc, sreg);
ba04b3
 
ba04b3
-		if (hexpr == NULL)
ba04b3
-			return
ba04b3
+		if (hexpr == NULL) {
ba04b3
 			netlink_error(ctx, loc,
ba04b3
 				      "hash statement has no expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 		len = nftnl_expr_get_u32(nle,
ba04b3
 					 NFTNL_EXPR_HASH_LEN) * BITS_PER_BYTE;
ba04b3
 		if (hexpr->len < len) {
ba04b3
+			xfree(hexpr);
ba04b3
 			hexpr = netlink_parse_concat_expr(ctx, loc, sreg, len);
ba04b3
 			if (hexpr == NULL)
ba04b3
-				return;
ba04b3
+				goto out_err;
ba04b3
 		}
ba04b3
 		expr->hash.expr = hexpr;
ba04b3
 	}
ba04b3
 
ba04b3
 	dreg = netlink_parse_register(nle, NFTNL_EXPR_HASH_DREG);
ba04b3
 	netlink_set_register(ctx, dreg, expr);
ba04b3
+	return;
ba04b3
+out_err:
ba04b3
+	xfree(expr);
ba04b3
 }
ba04b3
 
ba04b3
 static void netlink_parse_fib(struct netlink_parse_ctx *ctx,
ba04b3
@@ -853,10 +860,11 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
ba04b3
 	reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN);
ba04b3
 	if (reg1) {
ba04b3
 		addr = netlink_get_register(ctx, loc, reg1);
ba04b3
-		if (addr == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "NAT statement has no address "
ba04b3
-					     "expression");
ba04b3
+		if (addr == NULL) {
ba04b3
+			netlink_error(ctx, loc,
ba04b3
+				      "NAT statement has no address expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 
ba04b3
 		if (family == AF_INET)
ba04b3
 			expr_set_type(addr, &ipaddr_type, BYTEORDER_BIG_ENDIAN);
ba04b3
@@ -869,10 +877,11 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
ba04b3
 	reg2 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX);
ba04b3
 	if (reg2 && reg2 != reg1) {
ba04b3
 		addr = netlink_get_register(ctx, loc, reg2);
ba04b3
-		if (addr == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "NAT statement has no address "
ba04b3
-					     "expression");
ba04b3
+		if (addr == NULL) {
ba04b3
+			netlink_error(ctx, loc,
ba04b3
+				      "NAT statement has no address expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 
ba04b3
 		if (family == AF_INET)
ba04b3
 			expr_set_type(addr, &ipaddr_type, BYTEORDER_BIG_ENDIAN);
ba04b3
@@ -887,10 +896,11 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
ba04b3
 	reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MIN);
ba04b3
 	if (reg1) {
ba04b3
 		proto = netlink_get_register(ctx, loc, reg1);
ba04b3
-		if (proto == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "NAT statement has no proto "
ba04b3
-					     "expression");
ba04b3
+		if (proto == NULL) {
ba04b3
+			netlink_error(ctx, loc,
ba04b3
+				      "NAT statement has no proto expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 
ba04b3
 		expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
ba04b3
 		stmt->nat.proto = proto;
ba04b3
@@ -899,10 +909,11 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
ba04b3
 	reg2 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MAX);
ba04b3
 	if (reg2 && reg2 != reg1) {
ba04b3
 		proto = netlink_get_register(ctx, loc, reg2);
ba04b3
-		if (proto == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "NAT statement has no proto "
ba04b3
-					     "expression");
ba04b3
+		if (proto == NULL) {
ba04b3
+			netlink_error(ctx, loc,
ba04b3
+				      "NAT statement has no proto expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 
ba04b3
 		expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
ba04b3
 		if (stmt->nat.proto != NULL)
ba04b3
@@ -911,6 +922,9 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
ba04b3
 	}
ba04b3
 
ba04b3
 	ctx->stmt = stmt;
ba04b3
+	return;
ba04b3
+out_err:
ba04b3
+	xfree(stmt);
ba04b3
 }
ba04b3
 
ba04b3
 static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
ba04b3
@@ -931,10 +945,11 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
ba04b3
 	reg1 = netlink_parse_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MIN);
ba04b3
 	if (reg1) {
ba04b3
 		proto = netlink_get_register(ctx, loc, reg1);
ba04b3
-		if (proto == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "MASQUERADE statement"
ba04b3
-					     "has no proto expression");
ba04b3
+		if (proto == NULL) {
ba04b3
+			netlink_error(ctx, loc,
ba04b3
+				      "MASQUERADE statement has no proto expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 		expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
ba04b3
 		stmt->masq.proto = proto;
ba04b3
 	}
ba04b3
@@ -942,10 +957,11 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
ba04b3
 	reg2 = netlink_parse_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MAX);
ba04b3
 	if (reg2 && reg2 != reg1) {
ba04b3
 		proto = netlink_get_register(ctx, loc, reg2);
ba04b3
-		if (proto == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "MASQUERADE statement"
ba04b3
-					     "has no proto expression");
ba04b3
+		if (proto == NULL) {
ba04b3
+			netlink_error(ctx, loc,
ba04b3
+				      "MASQUERADE statement has no proto expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 		expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
ba04b3
 		if (stmt->masq.proto != NULL)
ba04b3
 			proto = range_expr_alloc(loc, stmt->masq.proto, proto);
ba04b3
@@ -953,6 +969,9 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
ba04b3
 	}
ba04b3
 
ba04b3
 	ctx->stmt = stmt;
ba04b3
+	return;
ba04b3
+out_err:
ba04b3
+	xfree(stmt);
ba04b3
 }
ba04b3
 
ba04b3
 static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
ba04b3
@@ -974,10 +993,11 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
ba04b3
 	reg1 = netlink_parse_register(nle, NFTNL_EXPR_REDIR_REG_PROTO_MIN);
ba04b3
 	if (reg1) {
ba04b3
 		proto = netlink_get_register(ctx, loc, reg1);
ba04b3
-		if (proto == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "redirect statement has no proto "
ba04b3
-					     "expression");
ba04b3
+		if (proto == NULL) {
ba04b3
+			netlink_error(ctx, loc,
ba04b3
+				      "redirect statement has no proto expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 
ba04b3
 		expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
ba04b3
 		stmt->redir.proto = proto;
ba04b3
@@ -986,10 +1006,11 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
ba04b3
 	reg2 = netlink_parse_register(nle, NFTNL_EXPR_REDIR_REG_PROTO_MAX);
ba04b3
 	if (reg2 && reg2 != reg1) {
ba04b3
 		proto = netlink_get_register(ctx, loc, reg2);
ba04b3
-		if (proto == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "redirect statement has no proto "
ba04b3
-					     "expression");
ba04b3
+		if (proto == NULL) {
ba04b3
+			netlink_error(ctx, loc,
ba04b3
+				      "redirect statement has no proto expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 
ba04b3
 		expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
ba04b3
 		if (stmt->redir.proto != NULL)
ba04b3
@@ -999,6 +1020,9 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
ba04b3
 	}
ba04b3
 
ba04b3
 	ctx->stmt = stmt;
ba04b3
+	return;
ba04b3
+out_err:
ba04b3
+	xfree(stmt);
ba04b3
 }
ba04b3
 
ba04b3
 static void netlink_parse_dup(struct netlink_parse_ctx *ctx,
ba04b3
@@ -1014,9 +1038,11 @@ static void netlink_parse_dup(struct netlink_parse_ctx *ctx,
ba04b3
 	reg1 = netlink_parse_register(nle, NFTNL_EXPR_DUP_SREG_ADDR);
ba04b3
 	if (reg1) {
ba04b3
 		addr = netlink_get_register(ctx, loc, reg1);
ba04b3
-		if (addr == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "DUP statement has no destination expression");
ba04b3
+		if (addr == NULL) {
ba04b3
+			netlink_error(ctx, loc,
ba04b3
+				      "DUP statement has no destination expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 
ba04b3
 		switch (ctx->table->handle.family) {
ba04b3
 		case NFPROTO_IPV4:
ba04b3
@@ -1033,9 +1059,11 @@ static void netlink_parse_dup(struct netlink_parse_ctx *ctx,
ba04b3
 	reg2 = netlink_parse_register(nle, NFTNL_EXPR_DUP_SREG_DEV);
ba04b3
 	if (reg2) {
ba04b3
 		dev = netlink_get_register(ctx, loc, reg2);
ba04b3
-		if (dev == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "DUP statement has no output expression");
ba04b3
+		if (dev == NULL) {
ba04b3
+			netlink_error(ctx, loc,
ba04b3
+				      "DUP statement has no output expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 
ba04b3
 		expr_set_type(dev, &ifindex_type, BYTEORDER_HOST_ENDIAN);
ba04b3
 		if (stmt->dup.to == NULL)
ba04b3
@@ -1045,6 +1073,9 @@ static void netlink_parse_dup(struct netlink_parse_ctx *ctx,
ba04b3
 	}
ba04b3
 
ba04b3
 	ctx->stmt = stmt;
ba04b3
+	return;
ba04b3
+out_err:
ba04b3
+	xfree(stmt);
ba04b3
 }
ba04b3
 
ba04b3
 static void netlink_parse_fwd(struct netlink_parse_ctx *ctx,
ba04b3
@@ -1060,15 +1091,20 @@ static void netlink_parse_fwd(struct netlink_parse_ctx *ctx,
ba04b3
 	reg1 = netlink_parse_register(nle, NFTNL_EXPR_FWD_SREG_DEV);
ba04b3
 	if (reg1) {
ba04b3
 		dev = netlink_get_register(ctx, loc, reg1);
ba04b3
-		if (dev == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "fwd statement has no output expression");
ba04b3
+		if (dev == NULL) {
ba04b3
+			netlink_error(ctx, loc,
ba04b3
+				      "fwd statement has no output expression");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 
ba04b3
 		expr_set_type(dev, &ifindex_type, BYTEORDER_HOST_ENDIAN);
ba04b3
 		stmt->fwd.to = dev;
ba04b3
 	}
ba04b3
 
ba04b3
 	ctx->stmt = stmt;
ba04b3
+	return;
ba04b3
+out_err:
ba04b3
+	xfree(stmt);
ba04b3
 }
ba04b3
 
ba04b3
 static void netlink_parse_queue(struct netlink_parse_ctx *ctx,
ba04b3
@@ -1135,10 +1171,11 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
ba04b3
 	dnle = nftnl_expr_get(nle, NFTNL_EXPR_DYNSET_EXPR, NULL);
ba04b3
 	if (dnle != NULL) {
ba04b3
 		if (netlink_parse_expr(dnle, ctx) < 0)
ba04b3
-			return;
ba04b3
-		if (ctx->stmt == NULL)
ba04b3
-			return netlink_error(ctx, loc,
ba04b3
-					     "Could not parse dynset stmt");
ba04b3
+			goto out_err;
ba04b3
+		if (ctx->stmt == NULL) {
ba04b3
+			netlink_error(ctx, loc, "Could not parse dynset stmt");
ba04b3
+			goto out_err;
ba04b3
+		}
ba04b3
 		dstmt = ctx->stmt;
ba04b3
 	}
ba04b3
 
ba04b3
@@ -1155,6 +1192,9 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
ba04b3
 	}
ba04b3
 
ba04b3
 	ctx->stmt = stmt;
ba04b3
+	return;
ba04b3
+out_err:
ba04b3
+	xfree(expr);
ba04b3
 }
ba04b3
 
ba04b3
 static void netlink_parse_objref(struct netlink_parse_ctx *ctx,
ba04b3
-- 
ba04b3
1.8.3.1
ba04b3