libprot: add pr_PrintContEntry function
authorMichael Meffie <mmeffie@sinenomine.net>
Wed, 18 Feb 2015 02:11:50 +0000 (21:11 -0500)
committerBenjamin Kaduk <kaduk@mit.edu>
Wed, 18 Nov 2015 04:47:51 +0000 (23:47 -0500)
A continuation entry (struct contentry) contains 39 id elements, however
a regular entry (struct prentry) contains only 10 id elements. Attempting
to access more than 10 elements of a regular entry is undefined
behavior.

Add a new function to safely print continuation entries and change
pr_PrintEntry to avoid accessing the entries array out of bounds.

The pr_PrintEntry function is at this time only used by the prdb_check
and ptclient debugging utilities.

Change-Id: Ie836983c8a5970a9495b87d0627ba6c05d117a9b
Reviewed-on: http://gerrit.openafs.org/11750
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>

src/ptserver/display.c
src/ptserver/display.h
src/ptserver/liboafs_prot.la.sym

index 2f57def..64fcf6b 100644 (file)
@@ -40,89 +40,107 @@ pr_TimeToString(time_t clock)
 
 #define host(a) (hostOrder ? (a) : ntohl(a))
 
-static void
-PrintEntries(FILE *f, int hostOrder, int indent, struct prentry *e, int n)
-{
-    int i;
-    int newline;
-
-    newline = 0;
-    for (i = 0; i < n; i++) {
-       if (e->entries[i] == 0)
-           break;
-
-       if (i == 0)
-           fprintf(f, "%*sids ", indent, "");
-       else if (newline == 0)
-           fprintf(f, "%*s", indent + 4, "");
+#define PRINT_COMMON_FIELDS(e)                                             \
+do {                                                                       \
+    int i;                                                                 \
+    if ((e)->cellid)                                                       \
+       fprintf(f, "cellid == %d\n", host((e)->cellid));                   \
+    for (i = 0; i < sizeof((e)->reserved) / sizeof((e)->reserved[0]); i++) \
+       if ((e)->reserved[i])                                              \
+           fprintf(f, "reserved field [%d] not zero: %d\n", i,            \
+                   host((e)->reserved[i]));                               \
+    fprintf(f, "%*s", indent, "");                                         \
+    fprintf(f, "Entry at %d: flags 0x%x, id %di, next %d.\n", ea,          \
+           host((e)->flags), host((e)->id), host((e)->next));             \
+} while (0)
 
-       if (host(e->entries[i]) == PRBADID)
-           fprintf(f, " EMPTY");
-       else
-           fprintf(f, "%6d", host(e->entries[i]));
-       newline = 1;
-       if (i % 10 == 9) {
-           fprintf(f, "\n");
-           newline = 0;
-       } else
-           fprintf(f, " ");
-    }
-    if (newline)
-       fprintf(f, "\n");
-}
+#define PRINT_IDS(e)                                                       \
+do {                                                                       \
+    int i;                                                                 \
+    int newline = 0;                                                       \
+    for (i = 0; i < sizeof((e)->entries)/sizeof((e)->entries[0]); i++) {   \
+       if ((e)->entries[i] == 0)                                          \
+           break;                                                         \
+       if (i == 0)                                                        \
+           fprintf(f, "%*sids ", indent, "");                             \
+       else if (newline == 0)                                             \
+           fprintf(f, "%*s", indent + 4, "");                             \
+       if (host((e)->entries[i]) == PRBADID)                              \
+           fprintf(f, " EMPTY");                                          \
+       else                                                               \
+           fprintf(f, "%6d", host((e)->entries[i]));                      \
+       newline = 1;                                                       \
+       if (i % 10 == 9) {                                                 \
+           fprintf(f, "\n");                                              \
+           newline = 0;                                                   \
+       } else                                                             \
+           fprintf(f, " ");                                               \
+    }                                                                      \
+    if (newline)                                                           \
+       fprintf(f, "\n");                                                  \
+} while (0)
 
+/* regular entry */
 int
-pr_PrintEntry(FILE *f, int hostOrder, afs_int32 ea, struct prentry *e, int indent)
+pr_PrintEntry(FILE *f, int hostOrder, afs_int32 ea, struct prentry *e,
+             int indent)
 {
-    int i;
-
-    if (e->cellid)
-       fprintf(f, "cellid == %d\n", host(e->cellid));
-    for (i = 0; i < sizeof(e->reserved) / sizeof(e->reserved[0]); i++)
-       if (e->reserved[i])
-           fprintf(f, "reserved field [%d] not zero: %d\n", i,
-                   host(e->reserved[i]));
+    /* In case we are given the wrong type of entry. */
+    if ((host(e->flags) & PRTYPE) == PRCONT) {
+       struct contentry c;
+       memcpy(&c, e, sizeof(c));
+       return pr_PrintContEntry(f, hostOrder, ea, &c, indent);
+    }
 
-    fprintf(f, "%*s", indent, "");
-    fprintf(f, "Entry at %d: flags 0x%x, id %di, next %d.\n", ea,
-           host(e->flags), host(e->id), host(e->next));
+    PRINT_COMMON_FIELDS(e);
     fprintf(f, "%*s", indent, "");
     fprintf(f, "c:%s ", pr_TimeToString(host(e->createTime)));
     fprintf(f, "a:%s ", pr_TimeToString(host(e->addTime)));
     fprintf(f, "r:%s ", pr_TimeToString(host(e->removeTime)));
     fprintf(f, "n:%s\n", pr_TimeToString(host(e->changeTime)));
-    if (host(e->flags) & PRCONT)
-       PrintEntries(f, hostOrder, indent, e, COSIZE);
-    else {                     /* regular entry */
-       PrintEntries(f, hostOrder, indent, e, PRSIZE);
-       fprintf(f, "%*s", indent, "");
-       fprintf(f, "hash (id %d name %d).  Owner %di, creator %di\n",
-               host(e->nextID), host(e->nextName), host(e->owner),
-               host(e->creator));
-       fprintf(f, "%*s", indent, "");
+    PRINT_IDS(e);
+    fprintf(f, "%*s", indent, "");
+    fprintf(f, "hash (id %d name %d).  Owner %di, creator %di\n",
+           host(e->nextID), host(e->nextName), host(e->owner),
+           host(e->creator));
+    fprintf(f, "%*s", indent, "");
 #if defined(SUPERGROUPS)
-       fprintf(f, "quota groups %d, foreign users %d.  Mem: %d, cntsg: %d\n",
-               host(e->ngroups), host(e->nusers), host(e->count),
-               host(e->instance));
+    fprintf(f, "quota groups %d, foreign users %d.  Mem: %d, cntsg: %d\n",
+           host(e->ngroups), host(e->nusers), host(e->count),
+           host(e->instance));
 #else
-       fprintf(f, "quota groups %d, foreign users %d.  Mem: %d, inst: %d\n",
-               host(e->ngroups), host(e->nusers), host(e->count),
-               host(e->instance));
+    fprintf(f, "quota groups %d, foreign users %d.  Mem: %d, inst: %d\n",
+           host(e->ngroups), host(e->nusers), host(e->count),
+           host(e->instance));
 #endif
-       fprintf(f, "%*s", indent, "");
+    fprintf(f, "%*s", indent, "");
 #if defined(SUPERGROUPS)
-       fprintf(f, "Owned chain %d, next owned %d, nextsg %d, sg (%d %d).\n",
-               host(e->owned), host(e->nextOwned), host(e->parent),
-               host(e->sibling), host(e->child));
+    fprintf(f, "Owned chain %d, next owned %d, nextsg %d, sg (%d %d).\n",
+           host(e->owned), host(e->nextOwned), host(e->parent),
+           host(e->sibling), host(e->child));
 #else
-       fprintf(f, "Owned chain %d, next owned %d, inst ptrs(%d %d %d).\n",
-               host(e->owned), host(e->nextOwned), host(e->parent),
-               host(e->sibling), host(e->child));
+    fprintf(f, "Owned chain %d, next owned %d, inst ptrs(%d %d %d).\n",
+           host(e->owned), host(e->nextOwned), host(e->parent),
+           host(e->sibling), host(e->child));
 #endif
-       fprintf(f, "%*s", indent, "");
-       if (strlen(e->name) >= PR_MAXNAMELEN)
-           fprintf(f, "NAME TOO LONG: ");
-       fprintf(f, "Name is '%.*s'\n", PR_MAXNAMELEN, e->name);
-    }
+    fprintf(f, "%*s", indent, "");
+    if (strlen(e->name) >= PR_MAXNAMELEN)
+       fprintf(f, "NAME TOO LONG: ");
+    fprintf(f, "Name is '%.*s'\n", PR_MAXNAMELEN, e->name);
+    return 0;
+}
+
+int
+pr_PrintContEntry(FILE *f, int hostOrder, afs_int32 ea, struct contentry *c, int indent)
+{
+    PRINT_COMMON_FIELDS(c);
+    /* Print the reserved fields for compatibility with older versions.
+     * They should always be zero, checked in PRINT_COMMON_FIELDS(). */
+    fprintf(f, "%*s", indent, "");
+    fprintf(f, "c:%s ", pr_TimeToString(host((c)->reserved[0])));
+    fprintf(f, "a:%s ", pr_TimeToString(host((c)->reserved[1])));
+    fprintf(f, "r:%s ", pr_TimeToString(host((c)->reserved[2])));
+    fprintf(f, "n:%s\n", pr_TimeToString(host((c)->reserved[3])));
+    PRINT_IDS(c);
     return 0;
 }
index 177b7c5..b34d413 100644 (file)
@@ -12,5 +12,7 @@
 
 extern int pr_PrintEntry(FILE *f, int hostOrder, afs_int32 ea,
                         struct prentry *e, int indent);
+extern int pr_PrintContEntry(FILE *f, int hostOrder, afs_int32 ea,
+                        struct contentry *e, int indent);
 
 #endif
index af1109a..dc6c782 100644 (file)
@@ -20,6 +20,7 @@ pr_ListMembers
 pr_ListOwned
 pr_ListSuperGroups
 pr_NameToId
+pr_PrintContEntry
 pr_PrintEntry
 pr_RemoveUserFromGroup
 pr_SIdToName