From: Peter Krempa <[email protected]>

glib's G_REGEX_OPTIMIZE flag for regex operations implies the use of
pcre's JIT optimizer for regexes which requires writable executable
memory for the optimized code.

Security frameworks such as SELinux can restrict program's access to
writable executable memory to harden the code.

glib's implementation of the regex functions handles downgrade to
interpreted evaluation of regexes gracefully if writable executable
memory is unavailable, but that is non-obvious and has a performance
penalty.

Add a syntax check which requires all uses of G_REGEX_OPTIMIZE to be
annotated so that the reader of the code can be hinted to why
G_REGEX_OPTIMIZE should perhaps be avoided.

Signed-off-by: Peter Krempa <[email protected]>
---
 build-aux/syntax-check.mk | 12 ++++++++++++
 src/conf/domain_event.c   |  2 +-
 src/util/vircommand.c     |  2 +-
 src/util/virlog.c         |  2 +-
 4 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk
index 6e22212944..4ad2a53779 100644
--- a/build-aux/syntax-check.mk
+++ b/build-aux/syntax-check.mk
@@ -1387,6 +1387,15 @@ sc_prohibit_inline_functions:
        halt='avoid inline functions in .c files' \
          $(_sc_search_regexp)

+# glib's G_REGEX_OPTIMIZE instructs the PCRE library to use JIT optimization
+# of the regexes, which requires executable memory to work. Security mechanisms
+# such as SELinux may disallow it. glib gracefully falls back to un-optimized
+# code. This check serves as a warning to not rely on G_REGEX_OPTIMIZE:
+sc_G_REGEX_OPTIMIZE:
+       @prohibit='G_REGEX_OPTIMIZE' \
+       exclude='see sc_G_REGEX_OPTIMIZE' \
+       halt='Optimizations may not work everywhere. Read the warning in 
build-aux/syntax-check.mk' \
+         $(_sc_search_regexp)

 ## ---------- ##
 ## Exceptions ##
@@ -1550,6 +1559,9 @@ exclude_file_name_regexp--sc_spacing-check = \
 exclude_file_name_regexp--sc_prohibit_inline_functions = \
   ^src/storage_file/storage_source.*.c$$

+exclude_file_name_regexp--sc_G_REGEX_OPTIMIZE = \
+       ^build-aux/syntax-check\.mk$$
+
 ## -------------- ##
 ## Implementation ##
 ## -------------- ##
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index a6bf9735aa..434401a5ef 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -2643,7 +2643,7 @@ virDomainQemuMonitorEventStateRegisterID(virConnectPtr 
conn,
     data->flags = flags;
     if (event && flags != -1) {
         if (flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX) {
-            int cflags = G_REGEX_OPTIMIZE;
+            int cflags = G_REGEX_OPTIMIZE; /* see sc_G_REGEX_OPTIMIZE */
             g_autoptr(GError) err = NULL;

             if (flags & VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE)
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index 1a9875fc87..84d4d9c218 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -3270,7 +3270,7 @@ virCommandRunRegex(virCommand *cmd,

     for (i = 0; i < nregex; i++) {
         g_autoptr(GError) err = NULL;
-        reg[i] = g_regex_new(regex[i], G_REGEX_OPTIMIZE, 0, &err);
+        reg[i] = g_regex_new(regex[i], G_REGEX_OPTIMIZE, 0, &err); /* see 
sc_G_REGEX_OPTIMIZE */
         if (!reg[i]) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Failed to compile regex %1$s"), err->message);
diff --git a/src/util/virlog.c b/src/util/virlog.c
index 02b8dd1385..8a6cb939bc 100644
--- a/src/util/virlog.c
+++ b/src/util/virlog.c
@@ -253,7 +253,7 @@ virLogOnceInit(void)
     virLogLock();
     virLogDefaultPriority = VIR_LOG_DEFAULT;

-    virLogRegex = g_regex_new(VIR_LOG_REGEX, G_REGEX_OPTIMIZE, 0, NULL);
+    virLogRegex = g_regex_new(VIR_LOG_REGEX, G_REGEX_OPTIMIZE, 0, NULL); /* 
see sc_G_REGEX_OPTIMIZE */

     /* GLib caches the hostname using a one time thread initializer.
      * We want to prime this cache early though, because at later time
-- 
2.54.0

Reply via email to