The branch main has been updated by ae:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=3b67473b97574d13eef8302c61c7245b3b3c52c1

commit 3b67473b97574d13eef8302c61c7245b3b3c52c1
Author:     Andrey V. Elsukov <a...@freebsd.org>
AuthorDate: 2025-07-22 08:12:36 +0000
Commit:     Andrey V. Elsukov <a...@freebsd.org>
CommitDate: 2025-08-03 09:54:39 +0000

    ipfw: add additional handling for orphaned states
    
    When parent rule of dynamic state is deleted and
    net.inet.ip.fw.dyn_keep_states is enabled, dynamic states are kept
    working and such states are called ORPHANED.
    Orphaned states still keep pointer to original parent rule. And in
    case when rule action is skipto this can lead to unpredictable
    consequences. To avoid this problem add special handling for skipto
    action when we have found ORPHANED state.
    Check that new rule has the same opcode and skipto number for
    O_SKIPTO rule action.
    
    Obtained from:  Yandex LLC
    Sponsored by:   Yandex LLC
    Differential Revision: https://reviews.freebsd.org/D51459
---
 sys/netpfil/ipfw/ip_fw_dynamic.c | 36 ++++++++++++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/sys/netpfil/ipfw/ip_fw_dynamic.c b/sys/netpfil/ipfw/ip_fw_dynamic.c
index 40598cef8076..9694c145e112 100644
--- a/sys/netpfil/ipfw/ip_fw_dynamic.c
+++ b/sys/netpfil/ipfw/ip_fw_dynamic.c
@@ -1323,6 +1323,33 @@ dyn_lookup_ipv6_parent_locked(const struct ipfw_flow_id 
*pkt, uint32_t zoneid,
 
 #endif /* INET6 */
 
+static int
+dyn_handle_orphaned(struct ip_fw *old_rule, struct dyn_data *data)
+{
+       struct ip_fw *rule;
+       const ipfw_insn *cmd, *old_cmd;
+
+       old_cmd = ACTION_PTR(old_rule);
+       switch (old_cmd->opcode) {
+       case O_SETMARK:
+       case O_SKIPTO:
+               /*
+                * Rule pointer was changed. For O_SKIPTO action it can be
+                * dangerous to keep use old rule. If new rule has the same
+                * action and the same destination number, then use this dynamic
+                * state. Otherwise it is better to create new one.
+                */
+               rule = V_layer3_chain.map[data->f_pos];
+               cmd = ACTION_PTR(rule);
+               if (cmd->opcode != old_cmd->opcode ||
+                   cmd->len != old_cmd->len || cmd->arg1 != old_cmd->arg1 ||
+                   insntoc(cmd, u32)->d[0] != insntoc(old_cmd, u32)->d[0])
+                       return (-1);
+               break;
+       }
+       return (0);
+}
+
 /*
  * Lookup dynamic state.
  *  pkt - filled by ipfw_chk() ipfw_flow_id;
@@ -1426,8 +1453,13 @@ ipfw_dyn_lookup_state(const struct ip_fw_args *args, 
const void *ulp,
                                 * changed to point to the penultimate rule.
                                 */
                                MPASS(V_layer3_chain.n_rules > 1);
-                               data->chain_id = V_layer3_chain.id;
-                               data->f_pos = V_layer3_chain.n_rules - 2;
+                               if (dyn_handle_orphaned(rule, data) == 0) {
+                                       data->chain_id = V_layer3_chain.id;
+                                       data->f_pos = V_layer3_chain.n_rules - 
2;
+                               } else {
+                                       rule = NULL;
+                                       info->direction = MATCH_NONE;
+                               }
                        } else {
                                rule = NULL;
                                info->direction = MATCH_NONE;

Reply via email to