Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: x_tables: do not fail xt_alloc_table_info too easilly

eacd86ca3b03 ("net/netfilter/x_tables.c: use kvmalloc()
in xt_alloc_table_info()") has unintentionally fortified
xt_alloc_table_info allocation when __GFP_RETRY has been dropped from
the vmalloc fallback. Later on there was a syzbot report that this
can lead to OOM killer invocations when tables are too large and
0537250fdc6c ("netfilter: x_tables: make allocation less aggressive")
has been merged to restore the original behavior. Georgi Nikolov however
noticed that he is not able to install his iptables anymore so this can
be seen as a regression.

The primary argument for 0537250fdc6c was that this allocation path
shouldn't really trigger the OOM killer and kill innocent tasks. On the
other hand the interface requires root and as such should allow what the
admin asks for. Root inside a namespaces makes this more complicated
because those might be not trusted in general. If they are not then such
namespaces should be restricted anyway. Therefore drop the __GFP_NORETRY
and replace it by __GFP_ACCOUNT to enfore memcg constrains on it.

Fixes: 0537250fdc6c ("netfilter: x_tables: make allocation less aggressive")
Reported-by: Georgi Nikolov <gnikolov@icdsoft.com>
Suggested-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Michal Hocko <mhocko@suse.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Michal Hocko and committed by
Pablo Neira Ayuso
a148ce15 1c117d3b

+1 -6
+1 -6
net/netfilter/x_tables.c
··· 1178 1178 if (sz < sizeof(*info) || sz >= XT_MAX_TABLE_SIZE) 1179 1179 return NULL; 1180 1180 1181 - /* __GFP_NORETRY is not fully supported by kvmalloc but it should 1182 - * work reasonably well if sz is too large and bail out rather 1183 - * than shoot all processes down before realizing there is nothing 1184 - * more to reclaim. 1185 - */ 1186 - info = kvmalloc(sz, GFP_KERNEL | __GFP_NORETRY); 1181 + info = kvmalloc(sz, GFP_KERNEL_ACCOUNT); 1187 1182 if (!info) 1188 1183 return NULL; 1189 1184