]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Move pre_check for ASCII string out of PRE(sys_prctl)
authorQuentin Monnet <quentin.monnet@netronome.com>
Sat, 14 Apr 2018 22:23:11 +0000 (23:23 +0100)
committerTom Hughes <tom@compton.nu>
Tue, 14 Aug 2018 19:47:19 +0000 (20:47 +0100)
The sys_prctl wrapper with PR_SET_NAME option reads an ASCII string passed
as its second argument. This string is supposed to be shorter than a given
limit. As the actual length of the string is unknown, the PRE() wrapper
performs a number of checks on it, including, in worst case, trying to
dereference it byte by byte.

To avoid re-implementing all this logic for other wrappers that could
need it, get the string processing out of the wrapper and move it to a
static function. Note that passing tid as an argument to the function is
required for macros PRE_MEM_RASCIIZ and PRE_MEM_READ to work properly.

coregrind/m_syswrap/syswrap-linux.c

index bd7d44776235e29279ca6b14839a9fe46edc4a48..b0d65414a28a7a52db27c109f0271890bb7369c9 100644 (file)
@@ -1389,6 +1389,36 @@ POST(sys_sysctl)
    }
 }
 
+static void pre_asciiz_str(ThreadId tid, Addr str, SizeT maxlen,
+                           const char *attr_name)
+{
+   const HChar *step_str = (const HChar *)str;
+   SizeT len;
+   UInt i;
+
+   /*
+    * The name can be up to maxlen bytes long, including the terminating null
+    * byte. So do not check more than maxlen bytes.
+    */
+   if (ML_(safe_to_deref)((const HChar *)str, maxlen)) {
+      len = VG_(strnlen)((const HChar *)str, maxlen);
+      if (len < maxlen)
+         PRE_MEM_RASCIIZ(attr_name, str);
+      else
+         PRE_MEM_READ(attr_name, str, maxlen);
+   } else {
+      /*
+       * Do it the slow way, one byte at a time, while checking for terminating
+       * '\0'.
+       */
+      for (i = 0; i < maxlen; i++) {
+         PRE_MEM_READ(attr_name, (Addr)&step_str[i], 1);
+         if (!ML_(safe_to_deref)(&step_str[i], 1) || step_str[i] == '\0')
+            break;
+      }
+   }
+}
+
 PRE(sys_prctl)
 {
    *flags |= SfMayBlock;
@@ -1442,27 +1472,7 @@ PRE(sys_prctl)
       break;
    case VKI_PR_SET_NAME:
       PRE_REG_READ2(int, "prctl", int, option, char *, name);
-      /* The name can be up to TASK_COMM_LEN(16) bytes long, including
-         the terminating null byte. So do not check more than 16 bytes. */
-      if (ML_(safe_to_deref)((const HChar *) (Addr)ARG2, VKI_TASK_COMM_LEN)) {
-         SizeT len = VG_(strnlen)((const HChar *) (Addr)ARG2,
-                                  VKI_TASK_COMM_LEN);
-         if (len < VKI_TASK_COMM_LEN) {
-            PRE_MEM_RASCIIZ("prctl(set-name)", ARG2);
-         } else {
-            PRE_MEM_READ("prctl(set-name)", ARG2, VKI_TASK_COMM_LEN);
-         }
-      } else {
-         /* Do it the slow way, one byte at a time, while checking for
-            terminating '\0'. */
-         const HChar *name = (const HChar *) (Addr)ARG2;
-         for (UInt i = 0; i < VKI_TASK_COMM_LEN; i++) {
-            PRE_MEM_READ("prctl(set-name)", (Addr) &name[i], 1);
-            if (!ML_(safe_to_deref)(&name[i], 1) || name[i] == '\0') {
-               break;
-            }
-         }
-      }
+      pre_asciiz_str(tid, ARG2, VKI_TASK_COMM_LEN, "prctl(set-name)");
       break;
    case VKI_PR_GET_NAME:
       PRE_REG_READ2(int, "prctl", int, option, char *, name);