<html>
    <head>
      <base href="https://bugzilla.netfilter.org/" />
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Segmentation fault when printing a rule checking byte zero of NFT_PAYLOAD_LL_HEADER"
   href="https://bugzilla.netfilter.org/show_bug.cgi?id=1226">1226</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Segmentation fault when printing a rule checking byte zero of NFT_PAYLOAD_LL_HEADER
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>nftables
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>unspecified
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>x86_64
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Debian GNU/Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P5
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>nft
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>pablo@netfilter.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>linus@mullvad.net
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Created <span class=""><a href="attachment.cgi?id=529" name="attach_529" title="Program adding rule that crashes nft">attachment 529</a> <a href="attachment.cgi?id=529&action=edit" title="Program adding rule that crashes nft">[details]</a></span>
Program adding rule that crashes nft

Hi! I'm writing a wrapper for libnftnl for Rust. As I'm doing that I use the
nft tool to debug/print the rules I'm creating.

I was guessing the NFT_PAYLOAD_LL_HEADER payload base would look at the
Ethernet frame header, and would thus allow me to match on the MAC addresses.
As I was playing around with that, I managed to create a rule that made nft
segfault when trying to print it. The rule itself is probably very invalid, but
nft should likely not segfault when printing it.

# Rule that triggers the segfault:

This is how to create the rule from C using libnftnl:

static struct nftnl_rule *setup_rule()
{
    struct nftnl_rule *rule;
    struct nftnl_expr *payload_expr, *cmp_expr;
    uint8_t mac[6] = {0, 0, 0, 0, 0, 0};

    rule = nftnl_rule_alloc();
    // The segfault is only triggered if the rule is an NFPROTO_INET rule.
    nftnl_rule_set(rule, NFTNL_RULE_TABLE, "my_table");
    nftnl_rule_set(rule, NFTNL_RULE_CHAIN, "my_chain");
    nftnl_rule_set_u32(rule, NFTNL_RULE_FAMILY, NFPROTO_INET);


    payload_expr = nftnl_expr_alloc("payload");
    nftnl_expr_set_u32(payload_expr, NFTNL_EXPR_PAYLOAD_BASE,
NFT_PAYLOAD_LL_HEADER);
    nftnl_expr_set_u32(payload_expr, NFTNL_EXPR_PAYLOAD_DREG, NFT_REG_1);
    nftnl_expr_set_u32(payload_expr, NFTNL_EXPR_PAYLOAD_OFFSET, 0);
    nftnl_expr_set_u32(payload_expr, NFTNL_EXPR_PAYLOAD_LEN, 6);
    nftnl_rule_add_expr(rule, payload_expr);

    cmp_expr = nftnl_expr_alloc("cmp");
    nftnl_expr_set_u32(cmp_expr, NFTNL_EXPR_CMP_SREG, NFT_REG_1);
    nftnl_expr_set_u32(cmp_expr, NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
    nftnl_expr_set(cmp_expr, NFTNL_EXPR_CMP_DATA, &mac, 6);
    nftnl_rule_add_expr(rule, cmp_expr);

    return rule;
}

Complete code, as a modification of nft-add-rule.c from the libnftnl examples:
<a href="https://gist.github.com/faern/5f26bba2e34858176d24a421906209f3">https://gist.github.com/faern/5f26bba2e34858176d24a421906209f3</a>

Please note that NFTNL_EXPR_PAYLOAD_LEN can be lowered to 1 and still produce
the same result. But changing the NFTNL_EXPR_PAYLOAD_OFFSET to something
non-zero makes it not segfault. Also adding the exact same rule but under
another NFTNL_RULE_FAMILY also makes it not segfault.


# Steps to reproduce:

1. Add the corresponding table and chain, must be in the inet family.
  > nft add table inet my_table
  > nft add chain inet my_table my_chain
2. Add the breaking rule by building the code above and running it:
  > ./nft-add-rule
3. Trigger the segfault by listing the table containing the rule:
  > nft list ruleset inet


nft version: Built from latest master today, nftables v0.8.2 commit b6143aa</pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are watching all bug changes.</li>
      </ul>
    </body>
</html>