Author: ae
Date: Fri Jul 12 09:48:42 2019
New Revision: 349940
URL: https://svnweb.freebsd.org/changeset/base/349940

Log:
  Correctly truncate the rule in case when it has several action opcodes.
  
  It is possible, that opcode at the ACTION_PTR() location is not real
  action, but action modificator like "log", "tag" etc. In this case we
  need to check for each opcode in the loop to find O_EXTERNAL_ACTION.
  
  Obtained from:        Yandex LLC
  MFC after:    1 week
  Sponsored by: Yandex LLC

Modified:
  head/sys/netpfil/ipfw/ip_fw_eaction.c

Modified: head/sys/netpfil/ipfw/ip_fw_eaction.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw_eaction.c       Fri Jul 12 09:02:12 2019        
(r349939)
+++ head/sys/netpfil/ipfw/ip_fw_eaction.c       Fri Jul 12 09:48:42 2019        
(r349940)
@@ -377,35 +377,51 @@ ipfw_reset_eaction(struct ip_fw_chain *ch, struct ip_f
     uint16_t eaction_id, uint16_t default_id, uint16_t instance_id)
 {
        ipfw_insn *cmd, *icmd;
+       int l, cmdlen;
 
        IPFW_UH_WLOCK_ASSERT(ch);
        IPFW_WLOCK_ASSERT(ch);
 
        cmd = ACTION_PTR(rule);
+       l = rule->cmd_len - rule->act_ofs;
+       while (l > 0) {
+               cmdlen = F_LEN(cmd);
+               l -= cmdlen;
+               if (cmd->opcode == O_EXTERNAL_ACTION)
+                       break;
+               cmd += cmdlen;
+       }
+       /*
+        * Return if there is not O_EXTERNAL_ACTION or its id is
+        * different.
+        */
        if (cmd->opcode != O_EXTERNAL_ACTION ||
            cmd->arg1 != eaction_id)
                return (0);
-
-       if (instance_id != 0 && rule->act_ofs < rule->cmd_len - 1) {
+       /*
+        * If instance_id is specified, we need to truncate the
+        * rule length. Check if there is O_EXTERNAL_INSTANCE opcode.
+        */
+       if (instance_id != 0 && l > 0) {
+               MPASS(cmdlen == 1);
                icmd = cmd + 1;
                if (icmd->opcode != O_EXTERNAL_INSTANCE ||
                    icmd->arg1 != instance_id)
                        return (0);
-               /* FALLTHROUGH */
+               /*
+                * Since named_object related to this instance will be
+                * destroyed, truncate the chain of opcodes to remove
+                * the rest of cmd chain just after O_EXTERNAL_ACTION
+                * opcode.
+                */
+               EACTION_DEBUG("truncate rule %d: len %u -> %u",
+                   rule->rulenum, rule->cmd_len, rule->cmd_len - l);
+               rule->cmd_len -= l;
+               MPASS(((uint32_t *)icmd -
+                   (uint32_t *)rule->cmd) == rule->cmd_len);
        }
 
        cmd->arg1 = default_id; /* Set to default id */
-       /*
-        * Since named_object related to this instance will be
-        * also destroyed, truncate the chain of opcodes to
-        * remove the rest of cmd chain just after O_EXTERNAL_ACTION
-        * opcode.
-        */
-       if (rule->act_ofs < rule->cmd_len - 1) {
-               EACTION_DEBUG("truncate rule %d: len %u -> %u",
-                   rule->rulenum, rule->cmd_len, rule->act_ofs + 1);
-               rule->cmd_len = rule->act_ofs + 1;
-       }
        /*
         * Return 1 when reset successfully happened.
         */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to