DF-5710 / harness_netmap_clamp.c
/* DF-5711: netmap_vale.c:331-332 clamp off-by-one. * * if (namelen >= IFNAMSIZ) * namelen = IFNAMSIZ; <-- should be IFNAMSIZ - 1 * ... * strncpy(b->bdg_basename, name, namelen); * * bdg_basename is char[IFNAMSIZ] (netmap_vale.c:198). A bridge name of * >=16 non-NUL chars makes strncpy write exactly 16 non-NUL bytes and the * array is left unterminated. Demonstrated here with the kernel strncpy * from /usr/src/sys/libkern/strncpy.c; the struct analogue embeds * bdg_basename before a canary so an OOB strlen is observable. */ #include <stdio.h> #include <string.h> char *kstrncpy(char *dst, const char *src, size_t n); /* kernel source */ #define IFNAMSIZ 16 struct bridge_shim { char bdg_basename[IFNAMSIZ]; char canary[32]; }; int main(void) { struct bridge_shim b; char name[64] = "vale123456789abcd"; /* 16 chars, no NUL until 16 */ int namelen = (int)strlen(name); memset(&b, 0x41, sizeof(b)); b.canary[sizeof(b.canary) - 1] = 0; /* NUL only after the canary */ if (namelen >= IFNAMSIZ) namelen = IFNAMSIZ; /* netmap_vale.c:331-332 verbatim */ kstrncpy(b.bdg_basename, name, (size_t)namelen); { int nul = -1, i; for (i = 0; i < IFNAMSIZ; i++) if (b.bdg_basename[i] == 0) { nul = i; break; } printf("bdg_basename has NUL within [0,%d)? -> %s (index %d)\n", IFNAMSIZ, nul >= 0 ? "YES" : "NO", nul); printf("strlen(bdg_basename) (what any %%s consumer reads): %zu\n", strlen(b.bdg_basename)); printf("printf(\"%%s\") reads: '%s'\n", b.bdg_basename); } printf("\nin-tree consumers of bdg_basename: ND() at netmap_vale.c:353,482\n" "and D() at :566 -- ND/D are no-ops in release (netmap_kern.h:80-81)\n" "-> latent non-termination, no live consumer: hardening.\n"); return 0; } |