|
@@ -529,10 +529,15 @@ static int xt_check_entry_match(const char *match, const char *target,
|
|
|
*/
|
|
|
int xt_check_table_hooks(const struct xt_table_info *info, unsigned int valid_hooks)
|
|
|
{
|
|
|
- unsigned int i;
|
|
|
+ const char *err = "unsorted underflow";
|
|
|
+ unsigned int i, max_uflow, max_entry;
|
|
|
+ bool check_hooks = false;
|
|
|
|
|
|
BUILD_BUG_ON(ARRAY_SIZE(info->hook_entry) != ARRAY_SIZE(info->underflow));
|
|
|
|
|
|
+ max_entry = 0;
|
|
|
+ max_uflow = 0;
|
|
|
+
|
|
|
for (i = 0; i < ARRAY_SIZE(info->hook_entry); i++) {
|
|
|
if (!(valid_hooks & (1 << i)))
|
|
|
continue;
|
|
@@ -541,9 +546,33 @@ int xt_check_table_hooks(const struct xt_table_info *info, unsigned int valid_ho
|
|
|
return -EINVAL;
|
|
|
if (info->underflow[i] == 0xFFFFFFFF)
|
|
|
return -EINVAL;
|
|
|
+
|
|
|
+ if (check_hooks) {
|
|
|
+ if (max_uflow > info->underflow[i])
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ if (max_uflow == info->underflow[i]) {
|
|
|
+ err = "duplicate underflow";
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ if (max_entry > info->hook_entry[i]) {
|
|
|
+ err = "unsorted entry";
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ if (max_entry == info->hook_entry[i]) {
|
|
|
+ err = "duplicate entry";
|
|
|
+ goto error;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ max_entry = info->hook_entry[i];
|
|
|
+ max_uflow = info->underflow[i];
|
|
|
+ check_hooks = true;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
+error:
|
|
|
+ pr_err_ratelimited("%s at hook %d\n", err, i);
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
EXPORT_SYMBOL(xt_check_table_hooks);
|
|
|
|