]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
extensions: among: Fix for use with ebtables-restore
authorPhil Sutter <phil@nwl.cc>
Fri, 30 Sep 2022 15:51:55 +0000 (17:51 +0200)
committerPhil Sutter <phil@nwl.cc>
Sat, 1 Oct 2022 11:44:10 +0000 (13:44 +0200)
When restoring multiple rules which use among match, new size may be
smaller than the old one which caused invalid writes by the memcpy()
call. Expect this and realloc the match only if it needs to grow. Also
use realloc instead of freeing and allocating from scratch.

Fixes: 26753888720d8 ("nft: bridge: Rudimental among extension support")
Signed-off-by: Phil Sutter <phil@nwl.cc>
extensions/libebt_among.c

index c607a775539d3d0fd83ed5027b506a2532fe4dfa..1eab20198440808aae86deab366e3ce6b5a01eb9 100644 (file)
@@ -119,7 +119,6 @@ static int bramong_parse(int c, char **argv, int invert,
                 struct xt_entry_match **match)
 {
        struct nft_among_data *data = (struct nft_among_data *)(*match)->data;
-       struct xt_entry_match *new_match;
        bool have_ip, dst = false;
        size_t new_size, cnt;
        struct stat stats;
@@ -170,18 +169,17 @@ static int bramong_parse(int c, char **argv, int invert,
        new_size *= sizeof(struct nft_among_pair);
        new_size += XT_ALIGN(sizeof(struct xt_entry_match)) +
                        sizeof(struct nft_among_data);
-       new_match = xtables_calloc(1, new_size);
-       memcpy(new_match, *match, (*match)->u.match_size);
-       new_match->u.match_size = new_size;
 
-       data = (struct nft_among_data *)new_match->data;
+       if (new_size > (*match)->u.match_size) {
+               *match = xtables_realloc(*match, new_size);
+               (*match)->u.match_size = new_size;
+               data = (struct nft_among_data *)(*match)->data;
+       }
+
        have_ip = nft_among_pairs_have_ip(optarg);
        poff = nft_among_prepare_data(data, dst, cnt, invert, have_ip);
        parse_nft_among_pairs(data->pairs + poff, optarg, cnt, have_ip);
 
-       free(*match);
-       *match = new_match;
-
        if (c == AMONG_DST_F || c == AMONG_SRC_F) {
                munmap(argv, flen);
                close(fd);