ipfilter: Verify ipnat on entry into kernel
The ipnat struct is built by ipnat(8), specifically ipnat_y.y when parsing the ipnat configuration file (typically ipnat.conf). ipnat contains a variable length string field at the end of the struct. This data field, called in_names, may contain various text strings such as NIC names. There is no upper bound limit to the length of strings as long as the in_namelen length field specifies the length of in_names within the ipnat structure and in_size specifies the size of the ipnat structure itself. Reported by: Ilja Van Sprundel <ivansprundel@ioactive.com> Reviewed by: markj MFC after: 1 week Differential revision: https://reviews.freebsd.org/D53843
This commit is contained in:
@@ -363,6 +363,12 @@ log" },
|
||||
{ 60074, "unknown next address type (ipv6)" },
|
||||
{ 60075, "one object at a time must be copied" },
|
||||
{ 60076, "NAT ioctl denied in jail without VNET" },
|
||||
{ 60077, "in_names offset is wrapped negative" },
|
||||
{ 60078, "in_names larger than in_namelen" },
|
||||
{ 60079, "ipnat larger than in_size" },
|
||||
{ 60080, "ipnat and in_namelen mismatch in_size" },
|
||||
{ 60081, "ip_names runs off the end of ipnat" },
|
||||
{ 60082, "in_namelen too large" },
|
||||
/* -------------------------------------------------------------------------- */
|
||||
{ 70001, "incorrect object size to get pool stats" },
|
||||
{ 70002, "could not malloc memory for new pool node" },
|
||||
|
||||
@@ -974,9 +974,13 @@ ipf_nat_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd,
|
||||
int mode, int uid, void *ctx)
|
||||
{
|
||||
ipf_nat_softc_t *softn = softc->ipf_nat_soft;
|
||||
int error = 0, ret, arg, getlock;
|
||||
int error = 0, ret, arg, getlock, interr, i;
|
||||
int interr_tbl[3] = { 60077, 60081, 60078 };
|
||||
ipnat_t *nat, *nt, *n;
|
||||
ipnat_t natd;
|
||||
char *name;
|
||||
size_t v_in_size, v_element_size;
|
||||
int v_rem_namelen, v_in_toend;
|
||||
SPL_INT(s);
|
||||
|
||||
#if !SOLARIS && defined(_KERNEL)
|
||||
@@ -1027,6 +1031,16 @@ ipf_nat_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd,
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (sizeof(natd) + natd.in_namelen != natd.in_size) {
|
||||
IPFERROR(60080);
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (natd.in_namelen < 0 || natd.in_namelen > softc->ipf_max_namelen) {
|
||||
IPFERROR(60082);
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
KMALLOCS(nt, ipnat_t *, natd.in_size);
|
||||
if (nt == NULL) {
|
||||
IPFERROR(60070);
|
||||
@@ -1041,6 +1055,32 @@ ipf_nat_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd,
|
||||
nat = nt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the incoming ipnat_t.
|
||||
*/
|
||||
if ((interr = ipf_check_names_string(nat->in_names, nat->in_namelen, nat->in_ifnames[0])) != 0) {
|
||||
IPFERROR(interr_tbl[interr-1]);
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (nat->in_ifnames[0] != nat->in_ifnames[1]) {
|
||||
if ((interr = ipf_check_names_string(nat->in_names, nat->in_namelen, nat->in_ifnames[1])) != 0) {
|
||||
IPFERROR(interr_tbl[interr-1]);
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if ((interr = ipf_check_names_string(nat->in_names, nat->in_namelen, nat->in_plabel)) != 0) {
|
||||
IPFERROR(interr_tbl[interr-1]);
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if ((interr = ipf_check_names_string(nat->in_names, nat->in_namelen, nat->in_pconfig)) != 0) {
|
||||
IPFERROR(interr_tbl[interr-1]);
|
||||
error = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* For add/delete, look to see if the NAT entry is
|
||||
* already present
|
||||
|
||||
Reference in New Issue
Block a user