CVE-2016-3134 netfilter: missing bounds check in ipt_entry struct (rhbz 1317383 1317384)
This commit is contained in:
		
							parent
							
								
									835b170e9c
								
							
						
					
					
						commit
						b653e2ee31
					
				| @ -619,6 +619,9 @@ Patch663: USB-serial-ftdi_sio-Add-support-for-ICP-DAS-I-756xU-.patch | ||||
| #CVE-2016-3135 rhbz 1317386 1317387 | ||||
| Patch664: netfilter-x_tables-check-for-size-overflow.patch | ||||
| 
 | ||||
| #CVE-2016-3134 rhbz 1317383 1317384 | ||||
| Patch665: netfilter-x_tables-deal-with-bogus-nextoffset-values.patch | ||||
| 
 | ||||
| # END OF PATCH DEFINITIONS | ||||
| 
 | ||||
| %endif | ||||
| @ -2141,6 +2144,7 @@ fi | ||||
| #  | ||||
| %changelog | ||||
| * Mon Mar 14 2016 Josh Boyer <jwboyer@fedoraproject.org> | ||||
| - CVE-2016-3134 netfilter: missing bounds check in ipt_entry struct (rhbz 1317383 1317384) | ||||
| - CVE-2016-3135 netfilter: size overflow in x_tables (rhbz 1317386 1317387) | ||||
| 
 | ||||
| * Fri Mar 11 2016 Josh Boyer <jwboyer@fedoraproject.org> | ||||
|  | ||||
							
								
								
									
										150
									
								
								netfilter-x_tables-deal-with-bogus-nextoffset-values.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								netfilter-x_tables-deal-with-bogus-nextoffset-values.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,150 @@ | ||||
| Subject:    [PATCH nf] netfilter: x_tables: deal with bogus nextoffset values | ||||
| From:       Florian Westphal <fw () strlen ! de> | ||||
| Date:       2016-03-10 0:56:02 | ||||
| 
 | ||||
| Ben Hawkes says: | ||||
| 
 | ||||
|  In the mark_source_chains function (net/ipv4/netfilter/ip_tables.c) it | ||||
|  is possible for a user-supplied ipt_entry structure to have a large | ||||
|  next_offset field. This field is not bounds checked prior to writing a | ||||
|  counter value at the supplied offset. | ||||
| 
 | ||||
| Problem is that xt_entry_foreach() macro stops iterating once e->next_offset | ||||
| is out of bounds, assuming this is the last entry. | ||||
| 
 | ||||
| With malformed data thats not necessarily the case so we can | ||||
| write outside of allocated area later as we might not have walked the | ||||
| entire blob. | ||||
| 
 | ||||
| Fix this by simplifying mark_source_chains -- it already has to check | ||||
| if nextoff is in range to catch invalid jumps, so just do the check | ||||
| when we move to a next entry as well. | ||||
| 
 | ||||
| Signed-off-by: Florian Westphal <fw@strlen.de> | ||||
| ---
 | ||||
|  net/ipv4/netfilter/arp_tables.c | 16 ++++++++-------- | ||||
|  net/ipv4/netfilter/ip_tables.c  | 15 ++++++++------- | ||||
|  net/ipv6/netfilter/ip6_tables.c | 13 ++++++------- | ||||
|  3 files changed, 22 insertions(+), 22 deletions(-) | ||||
| 
 | ||||
| diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
 | ||||
| index b488cac..5a0b591 100644
 | ||||
| --- a/net/ipv4/netfilter/arp_tables.c
 | ||||
| +++ b/net/ipv4/netfilter/arp_tables.c
 | ||||
| @@ -437,6 +437,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
 | ||||
|   | ||||
|  				/* Move along one */ | ||||
|  				size = e->next_offset; | ||||
| +
 | ||||
| +				if (pos + size > newinfo->size - sizeof(*e))
 | ||||
| +					return 0;
 | ||||
| +
 | ||||
|  				e = (struct arpt_entry *) | ||||
|  					(entry0 + pos + size); | ||||
|  				e->counters.pcnt = pos; | ||||
| @@ -447,14 +451,6 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
 | ||||
|  				if (strcmp(t->target.u.user.name, | ||||
|  					   XT_STANDARD_TARGET) == 0 && | ||||
|  				    newpos >= 0) { | ||||
| -					if (newpos > newinfo->size -
 | ||||
| -						sizeof(struct arpt_entry)) {
 | ||||
| -						duprintf("mark_source_chains: "
 | ||||
| -							"bad verdict (%i)\n",
 | ||||
| -								newpos);
 | ||||
| -						return 0;
 | ||||
| -					}
 | ||||
| -
 | ||||
|  					/* This a jump; chase it. */ | ||||
|  					duprintf("Jump rule %u -> %u\n", | ||||
|  						 pos, newpos); | ||||
| @@ -462,6 +458,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
 | ||||
|  					/* ... this is a fallthru */ | ||||
|  					newpos = pos + e->next_offset; | ||||
|  				} | ||||
| +
 | ||||
| +				if (newpos > newinfo->size - sizeof(*e))
 | ||||
| +					return 0;
 | ||||
| +
 | ||||
|  				e = (struct arpt_entry *) | ||||
|  					(entry0 + newpos); | ||||
|  				e->counters.pcnt = pos; | ||||
| diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
 | ||||
| index b99affa..ceb995f 100644
 | ||||
| --- a/net/ipv4/netfilter/ip_tables.c
 | ||||
| +++ b/net/ipv4/netfilter/ip_tables.c
 | ||||
| @@ -519,6 +519,10 @@ mark_source_chains(const struct xt_table_info *newinfo,
 | ||||
|   | ||||
|  				/* Move along one */ | ||||
|  				size = e->next_offset; | ||||
| +
 | ||||
| +				if (pos + size > newinfo->size - sizeof(*e))
 | ||||
| +					return 0;
 | ||||
| +
 | ||||
|  				e = (struct ipt_entry *) | ||||
|  					(entry0 + pos + size); | ||||
|  				e->counters.pcnt = pos; | ||||
| @@ -529,13 +533,6 @@ mark_source_chains(const struct xt_table_info *newinfo,
 | ||||
|  				if (strcmp(t->target.u.user.name, | ||||
|  					   XT_STANDARD_TARGET) == 0 && | ||||
|  				    newpos >= 0) { | ||||
| -					if (newpos > newinfo->size -
 | ||||
| -						sizeof(struct ipt_entry)) {
 | ||||
| -						duprintf("mark_source_chains: "
 | ||||
| -							"bad verdict (%i)\n",
 | ||||
| -								newpos);
 | ||||
| -						return 0;
 | ||||
| -					}
 | ||||
|  					/* This a jump; chase it. */ | ||||
|  					duprintf("Jump rule %u -> %u\n", | ||||
|  						 pos, newpos); | ||||
| @@ -543,6 +540,10 @@ mark_source_chains(const struct xt_table_info *newinfo,
 | ||||
|  					/* ... this is a fallthru */ | ||||
|  					newpos = pos + e->next_offset; | ||||
|  				} | ||||
| +
 | ||||
| +				if (newpos > newinfo->size - sizeof(*e))
 | ||||
| +					return 0;
 | ||||
| +
 | ||||
|  				e = (struct ipt_entry *) | ||||
|  					(entry0 + newpos); | ||||
|  				e->counters.pcnt = pos; | ||||
| diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
 | ||||
| index 99425cf..d88a794 100644
 | ||||
| --- a/net/ipv6/netfilter/ip6_tables.c
 | ||||
| +++ b/net/ipv6/netfilter/ip6_tables.c
 | ||||
| @@ -531,6 +531,8 @@ mark_source_chains(const struct xt_table_info *newinfo,
 | ||||
|   | ||||
|  				/* Move along one */ | ||||
|  				size = e->next_offset; | ||||
| +				if (pos + size > newinfo->size - sizeof(*e))
 | ||||
| +					return 0;
 | ||||
|  				e = (struct ip6t_entry *) | ||||
|  					(entry0 + pos + size); | ||||
|  				e->counters.pcnt = pos; | ||||
| @@ -541,13 +543,6 @@ mark_source_chains(const struct xt_table_info *newinfo,
 | ||||
|  				if (strcmp(t->target.u.user.name, | ||||
|  					   XT_STANDARD_TARGET) == 0 && | ||||
|  				    newpos >= 0) { | ||||
| -					if (newpos > newinfo->size -
 | ||||
| -						sizeof(struct ip6t_entry)) {
 | ||||
| -						duprintf("mark_source_chains: "
 | ||||
| -							"bad verdict (%i)\n",
 | ||||
| -								newpos);
 | ||||
| -						return 0;
 | ||||
| -					}
 | ||||
|  					/* This a jump; chase it. */ | ||||
|  					duprintf("Jump rule %u -> %u\n", | ||||
|  						 pos, newpos); | ||||
| @@ -555,6 +550,10 @@ mark_source_chains(const struct xt_table_info *newinfo,
 | ||||
|  					/* ... this is a fallthru */ | ||||
|  					newpos = pos + e->next_offset; | ||||
|  				} | ||||
| +
 | ||||
| +				if (newpos > newinfo->size - sizeof(*e))
 | ||||
| +					return 0;
 | ||||
| +
 | ||||
|  				e = (struct ip6t_entry *) | ||||
|  					(entry0 + newpos); | ||||
|  				e->counters.pcnt = pos; | ||||
| -- 
 | ||||
| 2.4.10 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user