Commit 14197d54 authored by Al Viro's avatar Al Viro Committed by David S. Miller

[EBTABLES]: Prevent wraparounds in checks for entry components' sizes.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 98a0824a
...@@ -338,10 +338,11 @@ ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e, ...@@ -338,10 +338,11 @@ ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
const char *name, unsigned int hookmask, unsigned int *cnt) const char *name, unsigned int hookmask, unsigned int *cnt)
{ {
struct ebt_match *match; struct ebt_match *match;
size_t left = ((char *)e + e->watchers_offset) - (char *)m;
int ret; int ret;
if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) > if (left < sizeof(struct ebt_entry_match) ||
((char *)e) + e->watchers_offset) left - sizeof(struct ebt_entry_match) < m->match_size)
return -EINVAL; return -EINVAL;
match = find_match_lock(m->u.name, &ret, &ebt_mutex); match = find_match_lock(m->u.name, &ret, &ebt_mutex);
if (!match) if (!match)
...@@ -367,10 +368,11 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e, ...@@ -367,10 +368,11 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
const char *name, unsigned int hookmask, unsigned int *cnt) const char *name, unsigned int hookmask, unsigned int *cnt)
{ {
struct ebt_watcher *watcher; struct ebt_watcher *watcher;
size_t left = ((char *)e + e->target_offset) - (char *)w;
int ret; int ret;
if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) > if (left < sizeof(struct ebt_entry_watcher) ||
((char *)e) + e->target_offset) left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
return -EINVAL; return -EINVAL;
watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex); watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
if (!watcher) if (!watcher)
...@@ -573,6 +575,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, ...@@ -573,6 +575,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
struct ebt_entry_target *t; struct ebt_entry_target *t;
struct ebt_target *target; struct ebt_target *target;
unsigned int i, j, hook = 0, hookmask = 0; unsigned int i, j, hook = 0, hookmask = 0;
size_t gap = e->next_offset - e->target_offset;
int ret; int ret;
/* don't mess with the struct ebt_entries */ /* don't mess with the struct ebt_entries */
...@@ -634,8 +637,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, ...@@ -634,8 +637,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
t->u.target = target; t->u.target = target;
if (t->u.target == &ebt_standard_target) { if (t->u.target == &ebt_standard_target) {
if (e->target_offset + sizeof(struct ebt_standard_target) > if (gap < sizeof(struct ebt_standard_target)) {
e->next_offset) {
BUGPRINT("Standard target size too big\n"); BUGPRINT("Standard target size too big\n");
ret = -EFAULT; ret = -EFAULT;
goto cleanup_watchers; goto cleanup_watchers;
...@@ -646,8 +648,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo, ...@@ -646,8 +648,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
ret = -EFAULT; ret = -EFAULT;
goto cleanup_watchers; goto cleanup_watchers;
} }
} else if ((e->target_offset + t->target_size + } else if (t->target_size > gap - sizeof(struct ebt_entry_target) ||
sizeof(struct ebt_entry_target) > e->next_offset) ||
(t->u.target->check && (t->u.target->check &&
t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){ t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){
module_put(t->u.target->me); module_put(t->u.target->me);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment