]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
gnulib/regcomp: Fix resource leak
authorAlec Brown <alec.r.brown@oracle.com>
Tue, 10 Jun 2025 15:19:44 +0000 (15:19 +0000)
committerDaniel Kiper <daniel.kiper@oracle.com>
Tue, 17 Jun 2025 12:17:56 +0000 (14:17 +0200)
In the functions create_initial_state() and calc_eclosure_iter(), memory
is allocated for the elems member of a re_node_set structure but that
memory isn't freed on error. Before returning an error, a call to
re_node_set_free() should be made to prevent the resource leak.

This issue has been fixed in the latest version of gnulib and I've
backported this change to maintain consistency.

This issue was found by a Coverity scan of GRUB2 under the following
CIDs: 473869, 473888.

Fixes: CID 473869
Fixes: CID 473888
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
bootstrap.conf
conf/Makefile.extra-dist
grub-core/lib/gnulib-patches/fix-regcomp-resource-leak.patch [new file with mode: 0644]

index 7a7813d2825456f076fd0ea7eb8b8b0c0987f5c7..7a464a289d00897cf853c3a62a3d0f12be67ea0b 100644 (file)
@@ -84,7 +84,10 @@ bootstrap_post_import_hook () {
   # Instead of patching our gnulib and therefore maintaining a fork, submit
   # changes to gnulib and update the hash above when they've merged.  Do not
   # add new patches here.
-  patch -d grub-core/lib/gnulib -p2 < grub-core/lib/gnulib-patches/fix-width.patch
+  for patchname in fix-width fix-regcomp-resource-leak; do
+    patch -d grub-core/lib/gnulib -p2 \
+       < "grub-core/lib/gnulib-patches/$patchname.patch"
+  done
 
   for patchname in \
       0001-Support-POTFILES-shell \
index b61052a189d87ca2895c23f54fb05b443f0ebfca..230a1d68f0640dc79ae3dca0b8a39f1301a980d5 100644 (file)
@@ -29,6 +29,7 @@ EXTRA_DIST += grub-core/genemuinit.sh
 EXTRA_DIST += grub-core/genemuinitheader.sh
 
 EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch
+EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-resource-leak.patch
 
 EXTRA_DIST += grub-core/lib/libgcrypt
 EXTRA_DIST += grub-core/lib/libgcrypt-grub/mpi/generic
diff --git a/grub-core/lib/gnulib-patches/fix-regcomp-resource-leak.patch b/grub-core/lib/gnulib-patches/fix-regcomp-resource-leak.patch
new file mode 100644 (file)
index 0000000..b2e9000
--- /dev/null
@@ -0,0 +1,110 @@
+--- a/lib/regcomp.c
++++ b/lib/regcomp.c
+@@ -1001,21 +1001,25 @@ create_initial_state (re_dfa_t *dfa)
+           Idx dest_idx = dfa->edests[node_idx].elems[0];
+           if (!re_node_set_contains (&init_nodes, dest_idx))
+             {
+-              reg_errcode_t merge_err
++              err
+                   = re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx);
+-              if (merge_err != REG_NOERROR)
+-                return merge_err;
++              if (err != REG_NOERROR)
++                break;
+               i = 0;
+             }
+         }
+       }
+   /* It must be the first time to invoke acquire_state.  */
+-  dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0);
+-  /* We don't check ERR here, since the initial state must not be NULL.  */
++  dfa->init_state
++    = (err == REG_NOERROR
++       ? re_acquire_state_context (&err, dfa, &init_nodes, 0)
++       : NULL);
+   if (__glibc_unlikely (dfa->init_state == NULL))
+-    return err;
+-  if (dfa->init_state->has_constraint)
++    {
++      /* Don't check ERR here, as the initial state must not be null.  */
++    }
++  else if (dfa->init_state->has_constraint)
+     {
+       dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
+                                                      CONTEXT_WORD);
+@@ -1025,17 +1029,13 @@ create_initial_state (re_dfa_t *dfa)
+                                                        &init_nodes,
+                                                        CONTEXT_NEWLINE
+                                                        | CONTEXT_BEGBUF);
+-      if (__glibc_unlikely (dfa->init_state_word == NULL
+-                          || dfa->init_state_nl == NULL
+-                          || dfa->init_state_begbuf == NULL))
+-      return err;
+     }
+   else
+     dfa->init_state_word = dfa->init_state_nl
+       = dfa->init_state_begbuf = dfa->init_state;
+   re_node_set_free (&init_nodes);
+-  return REG_NOERROR;
++  return err;
+ }
+ /* If it is possible to do searching in single byte encoding instead of UTF-8
+@@ -1677,12 +1677,11 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
+     {
+       err = duplicate_node_closure (dfa, node, node, node,
+                                   dfa->nodes[node].constraint);
+-      if (__glibc_unlikely (err != REG_NOERROR))
+-      return err;
+     }
+   /* Expand each epsilon destination nodes.  */
+-  if (IS_EPSILON_NODE(dfa->nodes[node].type))
++  if (__glibc_likely (err == REG_NOERROR)
++      && IS_EPSILON_NODE (dfa->nodes[node].type))
+     for (i = 0; i < dfa->edests[node].nelem; ++i)
+       {
+       re_node_set eclosure_elem;
+@@ -1700,14 +1699,14 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
+         {
+           err = calc_eclosure_iter (&eclosure_elem, dfa, edest, false);
+           if (__glibc_unlikely (err != REG_NOERROR))
+-            return err;
++            break;
+         }
+       else
+         eclosure_elem = dfa->eclosures[edest];
+       /* Merge the epsilon closure of 'edest'.  */
+       err = re_node_set_merge (&eclosure, &eclosure_elem);
+       if (__glibc_unlikely (err != REG_NOERROR))
+-        return err;
++        break;
+       /* If the epsilon closure of 'edest' is incomplete,
+          the epsilon closure of this node is also incomplete.  */
+       if (dfa->eclosures[edest].nelem == 0)
+@@ -1717,12 +1716,18 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
+         }
+       }
+-  if (incomplete && !root)
+-    dfa->eclosures[node].nelem = 0;
++  if (err != REG_NOERROR)
++    re_node_set_free (&eclosure);
+   else
+-    dfa->eclosures[node] = eclosure;
+-  *new_set = eclosure;
+-  return REG_NOERROR;
++    {
++      if (incomplete && !root)
++      dfa->eclosures[node].nelem = 0;
++      else
++      dfa->eclosures[node] = eclosure;
++      *new_set = eclosure;
++    }
++
++  return err;
+ }
+ /* Functions for token which are used in the parser.  */