Bug 208035 - IPFW firewall heap overflow
Summary: IPFW firewall heap overflow
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Only Me
Assignee: freebsd-ipfw
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-03-15 17:50 UTC by CTurt
Modified: 2016-05-16 14:08 UTC (History)
6 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description CTurt 2016-03-15 17:50:01 UTC
There is a heap overflow, triggerable as root only in the IPFW firewall handling code.

sys/netpfil/ipfw/ip_fw_nat.c:

static int
ipfw_nat_cfg(struct sockopt *sopt)
{
	struct cfg_nat_legacy *cfg;
	struct nat44_cfg_nat *ucfg;
	struct cfg_redir_legacy *rdir;
	struct nat44_cfg_redir *urdir;
	char *buf;
	size_t len, len2;
	int error, i;

	len = sopt->sopt_valsize;
	len2 = len + 128;

	/*
	 * Allocate 2x buffer to store converted structures.
	 * new redir_cfg has shrinked, so we're sure that
	 * new buffer size is enough.
	 */
	buf = malloc(roundup2(len, 8) + len2, M_TEMP, M_WAITOK | M_ZERO);
	error = sooptcopyin(sopt, buf, len, sizeof(struct cfg_nat_legacy));

The size calculation passed to `malloc` can be overflown, resulting in heap overflow on `sooptcopyin`.

This function is called when the `IP_FW_NAT_CFG` command is passed to `ipfw_ctl`:

int
ipfw_ctl(struct sockopt *sopt)
{
	...

	/* Save original valsize before it is altered via sooptcopyin() */
	valsize = sopt->sopt_valsize;
	opt = sopt->sopt_name;

	...

	switch (opt) {
		...
case IP_FW_NAT_CFG:
		if (IPFW_NAT_LOADED)
			error = ipfw_nat_cfg_ptr(sopt);
		else {
			printf("IP_FW_NAT_CFG: %s\n",
			    "ipfw_nat not present, please load it");
			error = EINVAL;
		}
		break;

`ipfw_ctl` is only called by `ipfw_ctl3`, which is available only to root processes (must have `PRIV_NETINET_IPFW` privilege):

int
ipfw_ctl3(struct sockopt *sopt)
{
	...

	error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
	if (error != 0)
		return (error);

	if (sopt->sopt_name != IP_FW3)
		return (ipfw_ctl(sopt));
Comment 1 Andrey V. Elsukov freebsd_committer 2016-05-16 14:08:33 UTC
This code looks like left for compatibility with old binaries. Probably it can be completely removed.