[PATCH 3/6] linux: Use __libc_procmaps_iterate on __readonly_area_fallback

Adhemerval Zanella adhemerval.zanella@linaro.org
Tue Sep 15 18:34:47 GMT 2026


Instead of stdio and __getdelim, which removes the malloc usage from
the fortify %n check path.  The closure now only checks the mapping
address range and permissions, with the line parsing done by
__libc_procmaps_iterate.

A read error after a successful open is now reported as
readonly_procfs_open_fail instead of readonly_area_writable; both end
up in __libc_fatal on the caller.

Checked on x86_64-linux-gnu.
---
 .../unix/sysv/linux/readonly-area-fallback.c  | 100 ++++++++----------
 1 file changed, 43 insertions(+), 57 deletions(-)

diff --git a/sysdeps/unix/sysv/linux/readonly-area-fallback.c b/sysdeps/unix/sysv/linux/readonly-area-fallback.c
index 395907327da..5d249537a02 100644
--- a/sysdeps/unix/sysv/linux/readonly-area-fallback.c
+++ b/sysdeps/unix/sysv/linux/readonly-area-fallback.c
@@ -16,20 +16,55 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include <errno.h>
+#include <procmaps.h>
 #include <stdint.h>
-#include <stdio.h>
-#include <stdio_ext.h>
 #include <stdlib.h>
-#include <string.h>
-#include "libio/libioP.h"
+
+struct readonly_area_args
+{
+  uintptr_t from;
+  uintptr_t to;
+  size_t size;
+};
+
+static bool
+check_mapping (uintptr_t from, uintptr_t to, const char *perm, void *arg)
+{
+  struct readonly_area_args *args = arg;
+
+  if (from < args->to && to > args->from)
+    {
+      /* Found an entry that at least partially covers the area.  */
+      if (perm[0] != 'r' || perm[1] != '-')
+	return true;
+
+      if (from <= args->from && to >= args->to)
+	args->size = 0;
+      else if (from <= args->from)
+	args->size -= to - args->from;
+      else if (to >= args->to)
+	args->size -= args->to - from;
+      else
+	args->size -= to - from;
+
+      if (args->size == 0)
+	return true;
+    }
+
+  return false;
+}
 
 enum readonly_error_type
 __readonly_area_fallback (const void *ptr, size_t size)
 {
-  const void *ptr_end = ptr + size;
+  struct readonly_area_args args =
+    {
+      .from = (uintptr_t) ptr,
+      .to = (uintptr_t) ptr + size,
+      .size = size,
+    };
 
-  FILE *fp = fopen ("/proc/self/maps", "rce");
-  if (fp == NULL)
+  if (__libc_procmaps_iterate (check_mapping, &args) == procutils_read_error)
     {
       /* It is the system administrator's choice to not have /proc
 	 available to this process (e.g., because it runs in a chroot
@@ -46,54 +81,5 @@ __readonly_area_fallback (const void *ptr, size_t size)
       return readonly_procfs_open_fail;
     }
 
-  /* We need no locking.  */
-  __fsetlocking (fp, FSETLOCKING_BYCALLER);
-
-  char *line = NULL;
-  size_t linelen = 0;
-
-  while (! __feof_unlocked (fp))
-    {
-      if (__getdelim (&line, &linelen, '\n', fp) <= 0)
-	break;
-
-      char *p;
-      uintptr_t from = strtoul (line, &p, 16);
-
-      if (p == line || *p++ != '-')
-	break;
-
-      char *q;
-      uintptr_t to = strtoul (p, &q, 16);
-
-      if (q == p || *q++ != ' ')
-	break;
-
-      if (from < (uintptr_t) ptr_end && to > (uintptr_t) ptr)
-	{
-	  /* Found an entry that at least partially covers the area.  */
-	  if (*q++ != 'r' || *q++ != '-')
-	    break;
-
-	  if (from <= (uintptr_t) ptr && to >= (uintptr_t) ptr_end)
-	    {
-	      size = 0;
-	      break;
-	    }
-	  else if (from <= (uintptr_t) ptr)
-	    size -= to - (uintptr_t) ptr;
-	  else if (to >= (uintptr_t) ptr_end)
-	    size -= (uintptr_t) ptr_end - from;
-	  else
-	    size -= to - from;
-
-	  if (!size)
-	    break;
-	}
-    }
-
-  fclose (fp);
-  free (line);
-
-  return size == 0 ? readonly_noerror : readonly_area_writable;
+  return args.size == 0 ? readonly_noerror : readonly_area_writable;
 }
-- 
2.53.0



More information about the Libc-alpha mailing list