net: ipv4: Fix parsing of IPv4 header options
If IPv4 header options has wrong options length (e.g. options length is more that actual data), then parser decrements opts_len without checking actual data length. Which crashes the network stack. Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@linux.intel.com>
This commit is contained in:
parent
60563977df
commit
22f93b35ab
1 changed files with 15 additions and 7 deletions
|
@ -116,7 +116,7 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt,
|
||||||
{
|
{
|
||||||
struct net_pkt_cursor cur;
|
struct net_pkt_cursor cur;
|
||||||
u8_t opt_data[NET_IPV4_HDR_OPTNS_MAX_LEN];
|
u8_t opt_data[NET_IPV4_HDR_OPTNS_MAX_LEN];
|
||||||
u8_t opts_len;
|
u8_t total_opts_len;
|
||||||
|
|
||||||
if (!cb) {
|
if (!cb) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -129,9 +129,9 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
opts_len = net_pkt_ipv4_opts_len(pkt);
|
total_opts_len = net_pkt_ipv4_opts_len(pkt);
|
||||||
|
|
||||||
while (opts_len) {
|
while (total_opts_len) {
|
||||||
u8_t opt_len = 0U;
|
u8_t opt_len = 0U;
|
||||||
u8_t opt_type;
|
u8_t opt_type;
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
opts_len--;
|
total_opts_len--;
|
||||||
|
|
||||||
if (!(opt_type == NET_IPV4_OPTS_EO ||
|
if (!(opt_type == NET_IPV4_OPTS_EO ||
|
||||||
opt_type == NET_IPV4_OPTS_NOP)) {
|
opt_type == NET_IPV4_OPTS_NOP)) {
|
||||||
|
@ -147,11 +147,15 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (opt_len < 2U || total_opts_len < 1U) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
opt_len -= 2U;
|
opt_len -= 2U;
|
||||||
opts_len--;
|
total_opts_len--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opt_len > opts_len) {
|
if (opt_len > total_opts_len) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +191,7 @@ int net_ipv4_parse_hdr_options(struct net_pkt *pkt,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
opts_len -= opt_len;
|
total_opts_len -= opt_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
net_pkt_cursor_restore(pkt, &cur);
|
net_pkt_cursor_restore(pkt, &cur);
|
||||||
|
@ -239,6 +243,10 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt)
|
||||||
net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
|
net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
|
||||||
|
|
||||||
opts_len = hdr_len - sizeof(struct net_ipv4_hdr);
|
opts_len = hdr_len - sizeof(struct net_ipv4_hdr);
|
||||||
|
if (opts_len > NET_IPV4_HDR_OPTNS_MAX_LEN) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
net_pkt_set_ipv4_opts_len(pkt, opts_len);
|
net_pkt_set_ipv4_opts_len(pkt, opts_len);
|
||||||
|
|
||||||
pkt_len = ntohs(hdr->len);
|
pkt_len = ntohs(hdr->len);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue