⬢ DragonFlyBSD Kernel Audit
DF-2234 / addtest.c
← back to finding ↓ download raw
/*
 * DF-2234 -- boundary prover for kern.iconv.add (sys/libiconv/iconv.c:394-424).
 *
 * iconv_sysctl_add() validates:
 *      strlen(din.ia_from) >= ICONV_CSNMAXLEN  -> EINVAL
 *      strlen(din.ia_to)   >= ICONV_CSNMAXLEN  -> EINVAL
 *
 * usage: addtest <namelen>
 *   root, namelen=30 -> pair registered (csid printed)
 *   root, namelen=31 -> EINVAL (kernel-side bound holds on THIS path)
 *   unprivileged     -> EPERM (kern_sysctl.c:1447 caps_priv_check
 *                            SYSCAP_NOSYSCTL_WR on sysctl writes)
 */
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/iconv.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main(int argc, char **argv)
{
	struct iconv_add_in din;
	struct iconv_add_out dout;
	size_t olen = sizeof(dout);
	int n, r;

	if (argc < 2)
		return (2);
	n = atoi(argv[1]);
	if (n > ICONV_CSNMAXLEN) {
		printf("namelen %d exceeds userland field, use <= 31\n", n);
		return (2);
	}
	memset(&din, 0, sizeof(din));
	memset(&dout, 0, sizeof(dout));
	din.ia_version = ICONV_ADD_VER;
	strlcpy(din.ia_converter, "UTF-16BE", sizeof(din.ia_converter));
	memset(din.ia_to, 'T', n);
	memset(din.ia_from, 'F', n);
	din.ia_to[n] = 0;
	din.ia_from[n] = 0;
	din.ia_datalen = 0;
	din.ia_data = NULL;

	r = sysctlbyname("kern.iconv.add", &dout, &olen, &din, sizeof(din));
	printf("addtest namelen=%d: sysctl=%d errno=%d (%s) csid=%d\n",
	    n, r, errno, r ? strerror(errno) : "ok", r ? -1 : dout.ia_csid);
	return (r ? 1 : 0);
}