libctf, lookup: fix bounds of pptrtab lookup
authorNick Alcock <nick.alcock@oracle.com>
Mon, 27 Sep 2021 19:31:21 +0000 (20:31 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Mon, 27 Sep 2021 19:31:26 +0000 (20:31 +0100)
An off-by-one bug in the check for pptrtab lookup meant that we could
access the pptrtab past its bounds (*well* past its bounds),
particularly if we called ctf_lookup_by_name in a child dict with "*foo"
where "foo" is a type that exists in the parent but not the child and no
previous lookups by name have been carried out.  (Note that "*foo" is
not even a valid thing to call ctf_lookup_by_name with: foo * is.
Nonetheless, users sometimes do call ctf_lookup_by_name with invalid
content, and it should return ECTF_NOTYPE, not crash.)

ctf_pptrtab_len, as its name suggests (and as other tests of it in
ctf-lookup.c confirm), is one higher than the maximum valid permissible
index, so the comparison is wrong.

(Test added, which should fail pretty reliably in the presence of this
bug on any machine with 4KiB pages.)

libctf/ChangeLog
2021-09-27  Nick Alcock  <nick.alcock@oracle.com>

* ctf-lookup.c (ctf_lookup_by_name_internal): Fix pptrtab bounds.
* testsuite/libctf-writable/pptrtab-writable-page-deep-lookup.*:
New test.

libctf/ChangeLog
libctf/ctf-lookup.c
libctf/testsuite/libctf-writable/pptrtab-writable-page-deep-lookup.c [new file with mode: 0644]
libctf/testsuite/libctf-writable/pptrtab-writable-page-deep-lookup.lk [new file with mode: 0644]

index e66cf2a88ea4d8b7cdca3f733bc0282d94e003e1..5907e2f856ae529322fb47bf617166962860bb65 100644 (file)
@@ -1,3 +1,9 @@
+2021-09-27  Nick Alcock  <nick.alcock@oracle.com>
+
+       * ctf-lookup.c (ctf_lookup_by_name_internal): Fix pptrtab bounds.
+       * testsuite/libctf-writable/pptrtab-writable-page-deep-lookup.*:
+       New test.
+
 2021-09-27  Nick Alcock  <nick.alcock@oracle.com>
 
        * testsuite/libctf-lookup/enum-symbol.c: Remove unused label.
index fe66bc4c00ce30753a562782a5abe9b7ce42f2c7..d1828f8e15a8cedaeb1a6becd078e035dc8a8f1f 100644 (file)
@@ -176,7 +176,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
          int in_child = 0;
 
          ntype = CTF_ERR;
-         if (child && idx <= child->ctf_pptrtab_len)
+         if (child && idx < child->ctf_pptrtab_len)
            {
              ntype = child->ctf_pptrtab[idx];
              if (ntype)
@@ -206,7 +206,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
              idx = LCTF_TYPE_TO_INDEX (fp, ntype);
 
              ntype = CTF_ERR;
-             if (child && idx <= child->ctf_pptrtab_len)
+             if (child && idx < child->ctf_pptrtab_len)
                {
                  ntype = child->ctf_pptrtab[idx];
                  if (ntype)
diff --git a/libctf/testsuite/libctf-writable/pptrtab-writable-page-deep-lookup.c b/libctf/testsuite/libctf-writable/pptrtab-writable-page-deep-lookup.c
new file mode 100644 (file)
index 0000000..ca42065
--- /dev/null
@@ -0,0 +1,68 @@
+/* Make sure we can look up a pointer-to-type where the type is more than a page
+   into the parent and the child has never had a lookup before.  */
+
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main (void)
+{
+  ctf_dict_t *pfp, *cfp;
+  ctf_encoding_t e = { CTF_INT_SIGNED, 0, sizeof (long) };
+  ctf_id_t ptype, ptrtype, type, foo;
+  size_t i;
+  int err;
+
+  if ((pfp = ctf_create (&err)) == NULL)
+    goto create_err;
+
+  if ((ptype = ctf_add_integer (pfp, CTF_ADD_NONROOT, "blah", &e)) == CTF_ERR)
+    goto create_parent;
+
+  for (i = 0; i < 4096; i++)
+    if ((foo = ctf_add_pointer (pfp, CTF_ADD_NONROOT, ptype)) == CTF_ERR)
+      goto create_parent;
+
+  if ((cfp = ctf_create (&err)) == NULL)
+    goto create_err;
+
+  if (ctf_import (cfp, pfp) < 0)
+    goto create_child;
+
+  if ((ptype = ctf_add_integer (pfp, CTF_ADD_ROOT, "foo", &e)) == CTF_ERR)
+    goto create_parent;
+
+  if ((ptrtype = ctf_add_pointer (pfp, CTF_ADD_ROOT, ptype)) == CTF_ERR)
+    goto create_parent;
+
+  if ((type = ctf_lookup_by_name (cfp, "*foo")) != CTF_ERR)
+    {
+      fprintf (stderr, "Type lookup unexpectedly succeeded: %s\n", ctf_errmsg (ctf_errno (cfp)));
+      exit (1);
+    }
+
+  if ((type = ctf_lookup_by_name (cfp, "foo *")) == CTF_ERR)
+    {
+      fprintf (stderr, "Type lookup error: %s\n", ctf_errmsg (ctf_errno (cfp)));
+      exit (1);
+    }
+
+  ctf_dict_close (cfp);
+  ctf_dict_close (pfp);
+
+  printf ("Type lookup succeeded.\n");
+
+  return 0;
+
+ create_err:
+  fprintf (stderr, "Creation failed: %s\n", ctf_errmsg (err));
+  exit (1);
+ create_parent:
+  fprintf (stderr, "Cannot create parent type: %s\n", ctf_errmsg (ctf_errno (pfp)));
+  exit (1);
+ create_child:
+  fprintf (stderr, "Cannot create child type: %s\n", ctf_errmsg (ctf_errno (cfp)));
+  exit (1);
+}
diff --git a/libctf/testsuite/libctf-writable/pptrtab-writable-page-deep-lookup.lk b/libctf/testsuite/libctf-writable/pptrtab-writable-page-deep-lookup.lk
new file mode 100644 (file)
index 0000000..4f23d14
--- /dev/null
@@ -0,0 +1,2 @@
+Type lookup succeeded.
+