Commit 60eb1894 authored by Patrick McHardy's avatar Patrick McHardy Committed by Pablo Neira Ayuso

netfilter: nf_tables: handle more than 8 * PAGE_SIZE set name allocations

We currently have a limit of 8 * PAGE_SIZE anonymous sets. Lift that limit
by continuing the scan if the entire page is exhausted.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent d60ce62f
...@@ -2049,7 +2049,7 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set, ...@@ -2049,7 +2049,7 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
const struct nft_set *i; const struct nft_set *i;
const char *p; const char *p;
unsigned long *inuse; unsigned long *inuse;
unsigned int n = 0; unsigned int n = 0, min = 0;
p = strnchr(name, IFNAMSIZ, '%'); p = strnchr(name, IFNAMSIZ, '%');
if (p != NULL) { if (p != NULL) {
...@@ -2059,23 +2059,28 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set, ...@@ -2059,23 +2059,28 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL); inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
if (inuse == NULL) if (inuse == NULL)
return -ENOMEM; return -ENOMEM;
cont:
list_for_each_entry(i, &ctx->table->sets, list) { list_for_each_entry(i, &ctx->table->sets, list) {
int tmp; int tmp;
if (!sscanf(i->name, name, &tmp)) if (!sscanf(i->name, name, &tmp))
continue; continue;
if (tmp < 0 || tmp >= BITS_PER_BYTE * PAGE_SIZE) if (tmp < min || tmp >= min + BITS_PER_BYTE * PAGE_SIZE)
continue; continue;
set_bit(tmp, inuse); set_bit(tmp - min, inuse);
} }
n = find_first_zero_bit(inuse, BITS_PER_BYTE * PAGE_SIZE); n = find_first_zero_bit(inuse, BITS_PER_BYTE * PAGE_SIZE);
if (n >= BITS_PER_BYTE * PAGE_SIZE) {
min += BITS_PER_BYTE * PAGE_SIZE;
memset(inuse, 0, PAGE_SIZE);
goto cont;
}
free_page((unsigned long)inuse); free_page((unsigned long)inuse);
} }
snprintf(set->name, sizeof(set->name), name, n); snprintf(set->name, sizeof(set->name), name, min + n);
list_for_each_entry(i, &ctx->table->sets, list) { list_for_each_entry(i, &ctx->table->sets, list) {
if (!strcmp(set->name, i->name)) if (!strcmp(set->name, i->name))
return -ENFILE; return -ENFILE;
......
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