|
@@ -654,6 +654,11 @@ struct compat_xt_standard_target {
|
|
|
compat_uint_t verdict;
|
|
|
};
|
|
|
|
|
|
+struct compat_xt_error_target {
|
|
|
+ struct compat_xt_entry_target t;
|
|
|
+ char errorname[XT_FUNCTION_MAXNAMELEN];
|
|
|
+};
|
|
|
+
|
|
|
static bool verdict_ok(int verdict)
|
|
|
{
|
|
|
if (verdict > 0)
|
|
@@ -679,6 +684,12 @@ static bool verdict_ok(int verdict)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+static bool error_tg_ok(unsigned int usersize, unsigned int kernsize,
|
|
|
+ const char *msg, unsigned int msglen)
|
|
|
+{
|
|
|
+ return usersize == kernsize && strnlen(msg, msglen) < msglen;
|
|
|
+}
|
|
|
+
|
|
|
int xt_compat_check_entry_offsets(const void *base, const char *elems,
|
|
|
unsigned int target_offset,
|
|
|
unsigned int next_offset)
|
|
@@ -708,6 +719,12 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,
|
|
|
|
|
|
if (!verdict_ok(st->verdict))
|
|
|
return -EINVAL;
|
|
|
+ } else if (strcmp(t->u.user.name, XT_ERROR_TARGET) == 0) {
|
|
|
+ const struct compat_xt_error_target *et = (const void *)t;
|
|
|
+
|
|
|
+ if (!error_tg_ok(t->u.target_size, sizeof(*et),
|
|
|
+ et->errorname, sizeof(et->errorname)))
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
/* compat_xt_entry match has less strict alignment requirements,
|
|
@@ -796,6 +813,12 @@ int xt_check_entry_offsets(const void *base,
|
|
|
|
|
|
if (!verdict_ok(st->verdict))
|
|
|
return -EINVAL;
|
|
|
+ } else if (strcmp(t->u.user.name, XT_ERROR_TARGET) == 0) {
|
|
|
+ const struct xt_error_target *et = (const void *)t;
|
|
|
+
|
|
|
+ if (!error_tg_ok(t->u.target_size, sizeof(*et),
|
|
|
+ et->errorname, sizeof(et->errorname)))
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
return xt_check_entry_match(elems, base + target_offset,
|