mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-30 08:04:13 +08:00
netfilter: x_tables: check standard verdicts in core
Userspace must provide a valid verdict to the standard target. The verdict can be either a jump (signed int > 0), or a return code. Allowed return codes are either RETURN (pop from stack), NF_ACCEPT, DROP and QUEUE (latter is allowed for legacy reasons). Jump offsets (verdict > 0) are checked in more detail later on when loop-detection is performed. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
f31e5f1a89
commit
07a9da51b4
@ -334,11 +334,6 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
|
|||||||
t->verdict < 0) || visited) {
|
t->verdict < 0) || visited) {
|
||||||
unsigned int oldpos, size;
|
unsigned int oldpos, size;
|
||||||
|
|
||||||
if ((strcmp(t->target.u.user.name,
|
|
||||||
XT_STANDARD_TARGET) == 0) &&
|
|
||||||
t->verdict < -NF_MAX_VERDICT - 1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Return: backtrack through the last
|
/* Return: backtrack through the last
|
||||||
* big jump.
|
* big jump.
|
||||||
*/
|
*/
|
||||||
|
@ -402,11 +402,6 @@ mark_source_chains(const struct xt_table_info *newinfo,
|
|||||||
t->verdict < 0) || visited) {
|
t->verdict < 0) || visited) {
|
||||||
unsigned int oldpos, size;
|
unsigned int oldpos, size;
|
||||||
|
|
||||||
if ((strcmp(t->target.u.user.name,
|
|
||||||
XT_STANDARD_TARGET) == 0) &&
|
|
||||||
t->verdict < -NF_MAX_VERDICT - 1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Return: backtrack through the last
|
/* Return: backtrack through the last
|
||||||
big jump. */
|
big jump. */
|
||||||
do {
|
do {
|
||||||
|
@ -420,11 +420,6 @@ mark_source_chains(const struct xt_table_info *newinfo,
|
|||||||
t->verdict < 0) || visited) {
|
t->verdict < 0) || visited) {
|
||||||
unsigned int oldpos, size;
|
unsigned int oldpos, size;
|
||||||
|
|
||||||
if ((strcmp(t->target.u.user.name,
|
|
||||||
XT_STANDARD_TARGET) == 0) &&
|
|
||||||
t->verdict < -NF_MAX_VERDICT - 1)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Return: backtrack through the last
|
/* Return: backtrack through the last
|
||||||
big jump. */
|
big jump. */
|
||||||
do {
|
do {
|
||||||
|
@ -654,6 +654,31 @@ struct compat_xt_standard_target {
|
|||||||
compat_uint_t verdict;
|
compat_uint_t verdict;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool verdict_ok(int verdict)
|
||||||
|
{
|
||||||
|
if (verdict > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (verdict < 0) {
|
||||||
|
int v = -verdict - 1;
|
||||||
|
|
||||||
|
if (verdict == XT_RETURN)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
switch (v) {
|
||||||
|
case NF_ACCEPT: return true;
|
||||||
|
case NF_DROP: return true;
|
||||||
|
case NF_QUEUE: return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int xt_compat_check_entry_offsets(const void *base, const char *elems,
|
int xt_compat_check_entry_offsets(const void *base, const char *elems,
|
||||||
unsigned int target_offset,
|
unsigned int target_offset,
|
||||||
unsigned int next_offset)
|
unsigned int next_offset)
|
||||||
@ -675,9 +700,15 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,
|
|||||||
if (target_offset + t->u.target_size > next_offset)
|
if (target_offset + t->u.target_size > next_offset)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 &&
|
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0) {
|
||||||
COMPAT_XT_ALIGN(target_offset + sizeof(struct compat_xt_standard_target)) != next_offset)
|
const struct compat_xt_standard_target *st = (const void *)t;
|
||||||
return -EINVAL;
|
|
||||||
|
if (COMPAT_XT_ALIGN(target_offset + sizeof(*st)) != next_offset)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!verdict_ok(st->verdict))
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
/* compat_xt_entry match has less strict alignment requirements,
|
/* compat_xt_entry match has less strict alignment requirements,
|
||||||
* otherwise they are identical. In case of padding differences
|
* otherwise they are identical. In case of padding differences
|
||||||
@ -757,9 +788,15 @@ int xt_check_entry_offsets(const void *base,
|
|||||||
if (target_offset + t->u.target_size > next_offset)
|
if (target_offset + t->u.target_size > next_offset)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 &&
|
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0) {
|
||||||
XT_ALIGN(target_offset + sizeof(struct xt_standard_target)) != next_offset)
|
const struct xt_standard_target *st = (const void *)t;
|
||||||
return -EINVAL;
|
|
||||||
|
if (XT_ALIGN(target_offset + sizeof(*st)) != next_offset)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!verdict_ok(st->verdict))
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
return xt_check_entry_match(elems, base + target_offset,
|
return xt_check_entry_match(elems, base + target_offset,
|
||||||
__alignof__(struct xt_entry_match));
|
__alignof__(struct xt_entry_match));
|
||||||
|
Loading…
Reference in New Issue
Block a user