Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e1b4b9f3 authored by Al Viro's avatar Al Viro Committed by David S. Miller
Browse files

[NETFILTER]: {ip,ip6,arp}_tables: fix exponential worst-case search for loops



If we come to node we'd already marked as seen and it's not a part of path
(i.e. we don't have a loop right there), we already know that it isn't a
part of any loop, so we don't need to revisit it.

That speeds the things up if some chain is refered to from several places
and kills O(exp(table size)) worst-case behaviour (without sleeping,
at that, so if you manage to self-LART that way, you are SOL for a long
time)...

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a96be246
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -358,6 +358,7 @@ static int mark_source_chains(struct xt_table_info *newinfo,
		for (;;) {
			struct arpt_standard_target *t
				= (void *)arpt_get_target(e);
			int visited = e->comefrom & (1 << hook);

			if (e->comefrom & (1 << NF_ARP_NUMHOOKS)) {
				printk("arptables: loop hook %u pos %u %08X.\n",
@@ -368,11 +369,11 @@ static int mark_source_chains(struct xt_table_info *newinfo,
				|= ((1 << hook) | (1 << NF_ARP_NUMHOOKS));

			/* Unconditional return/END. */
			if (e->target_offset == sizeof(struct arpt_entry)
			if ((e->target_offset == sizeof(struct arpt_entry)
			    && (strcmp(t->target.u.user.name,
				       ARPT_STANDARD_TARGET) == 0)
			    && t->verdict < 0
			    && unconditional(&e->arp)) {
			    && unconditional(&e->arp)) || visited) {
				unsigned int oldpos, size;

				if (t->verdict < -NF_MAX_VERDICT - 1) {
+3 −2
Original line number Diff line number Diff line
@@ -384,6 +384,7 @@ mark_source_chains(struct xt_table_info *newinfo,
		for (;;) {
			struct ipt_standard_target *t
				= (void *)ipt_get_target(e);
			int visited = e->comefrom & (1 << hook);

			if (e->comefrom & (1 << NF_IP_NUMHOOKS)) {
				printk("iptables: loop hook %u pos %u %08X.\n",
@@ -394,11 +395,11 @@ mark_source_chains(struct xt_table_info *newinfo,
				|= ((1 << hook) | (1 << NF_IP_NUMHOOKS));

			/* Unconditional return/END. */
			if (e->target_offset == sizeof(struct ipt_entry)
			if ((e->target_offset == sizeof(struct ipt_entry)
			    && (strcmp(t->target.u.user.name,
				       IPT_STANDARD_TARGET) == 0)
			    && t->verdict < 0
			    && unconditional(&e->ip)) {
			    && unconditional(&e->ip)) || visited) {
				unsigned int oldpos, size;

				if (t->verdict < -NF_MAX_VERDICT - 1) {
+3 −2
Original line number Diff line number Diff line
@@ -413,6 +413,7 @@ mark_source_chains(struct xt_table_info *newinfo,
		unsigned int pos = newinfo->hook_entry[hook];
		struct ip6t_entry *e
			= (struct ip6t_entry *)(entry0 + pos);
		int visited = e->comefrom & (1 << hook);

		if (!(valid_hooks & (1 << hook)))
			continue;
@@ -433,11 +434,11 @@ mark_source_chains(struct xt_table_info *newinfo,
				|= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));

			/* Unconditional return/END. */
			if (e->target_offset == sizeof(struct ip6t_entry)
			if ((e->target_offset == sizeof(struct ip6t_entry)
			    && (strcmp(t->target.u.user.name,
				       IP6T_STANDARD_TARGET) == 0)
			    && t->verdict < 0
			    && unconditional(&e->ipv6)) {
			    && unconditional(&e->ipv6)) || visited) {
				unsigned int oldpos, size;

				if (t->verdict < -NF_MAX_VERDICT - 1) {