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

Commit b43d8d85 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller
Browse files

[NETFILTER]: nfnetlink_queue: deobfuscate entry lookups



A queue entry lookup currently looks like this:

find_dequeue_entry -> __find_dequeue_entry ->
	__find_entry -> cmpfn -> id_cmp

Use simple open-coded list walking and kill the cmpfn for
find_dequeue_entry. Instead add it to nfqnl_flush (after
similar cleanups) and use nfqnl_flush for both complete
flushes and flushing entries related to a device.

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0ac41e81
Loading
Loading
Loading
Loading
+31 −69
Original line number Diff line number Diff line
@@ -171,7 +171,8 @@ out_unlock:
	return NULL;
}

static void nfqnl_flush(struct nfqnl_instance *queue, int verdict);
static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn,
			unsigned long data);

static void
_instance_destroy2(struct nfqnl_instance *inst, int lock)
@@ -188,7 +189,7 @@ _instance_destroy2(struct nfqnl_instance *inst, int lock)
		write_unlock_bh(&instances_lock);

	/* then flush all pending skbs from the queue */
	nfqnl_flush(inst, NF_DROP);
	nfqnl_flush(inst, NULL, 0);

	/* and finally put the refcount */
	instance_put(inst);
@@ -235,54 +236,6 @@ __enqueue_entry(struct nfqnl_instance *queue,
       queue->queue_total++;
}

/*
 * Find and return a queued entry matched by cmpfn, or return the last
 * entry if cmpfn is NULL.
 */
static inline struct nfqnl_queue_entry *
__find_entry(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn,
		   unsigned long data)
{
	struct nfqnl_queue_entry *entry;

	list_for_each_entry(entry, &queue->queue_list, list) {
		if (!cmpfn || cmpfn(entry, data))
			return entry;
	}
	return NULL;
}

static inline void
__dequeue_entry(struct nfqnl_instance *q, struct nfqnl_queue_entry *entry)
{
	list_del(&entry->list);
	q->queue_total--;
}

static inline struct nfqnl_queue_entry *
__find_dequeue_entry(struct nfqnl_instance *queue,
		     nfqnl_cmpfn cmpfn, unsigned long data)
{
	struct nfqnl_queue_entry *entry;

	entry = __find_entry(queue, cmpfn, data);
	if (entry == NULL)
		return NULL;

	__dequeue_entry(queue, entry);
	return entry;
}


static inline void
__nfqnl_flush(struct nfqnl_instance *queue, int verdict)
{
	struct nfqnl_queue_entry *entry;

	while ((entry = __find_dequeue_entry(queue, NULL, 0)))
		issue_verdict(entry, verdict);
}

static inline int
__nfqnl_set_mode(struct nfqnl_instance *queue,
		 unsigned char mode, unsigned int range)
@@ -313,23 +266,42 @@ __nfqnl_set_mode(struct nfqnl_instance *queue,
}

static struct nfqnl_queue_entry *
find_dequeue_entry(struct nfqnl_instance *queue,
			 nfqnl_cmpfn cmpfn, unsigned long data)
find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id)
{
	struct nfqnl_queue_entry *entry;
	struct nfqnl_queue_entry *entry = NULL, *i;

	spin_lock_bh(&queue->lock);
	entry = __find_dequeue_entry(queue, cmpfn, data);

	list_for_each_entry(i, &queue->queue_list, list) {
		if (i->id == id) {
			entry = i;
			break;
		}
	}

	if (entry) {
		list_del(&entry->list);
		queue->queue_total--;
	}

	spin_unlock_bh(&queue->lock);

	return entry;
}

static void
nfqnl_flush(struct nfqnl_instance *queue, int verdict)
nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
{
	struct nfqnl_queue_entry *entry, *next;

	spin_lock_bh(&queue->lock);
	__nfqnl_flush(queue, verdict);
	list_for_each_entry_safe(entry, next, &queue->queue_list, list) {
		if (!cmpfn || cmpfn(entry, data)) {
			list_del(&entry->list);
			queue->queue_total--;
			issue_verdict(entry, NF_DROP);
		}
	}
	spin_unlock_bh(&queue->lock);
}

@@ -644,12 +616,6 @@ nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e)
	return 0;
}

static inline int
id_cmp(struct nfqnl_queue_entry *e, unsigned long id)
{
	return (id == e->id);
}

static int
nfqnl_set_mode(struct nfqnl_instance *queue,
	       unsigned char mode, unsigned int range)
@@ -706,12 +672,8 @@ nfqnl_dev_drop(int ifindex)
		struct nfqnl_instance *inst;
		struct hlist_head *head = &instance_table[i];

		hlist_for_each_entry(inst, tmp, head, hlist) {
			struct nfqnl_queue_entry *entry;
			while ((entry = find_dequeue_entry(inst, dev_cmp,
							   ifindex)) != NULL)
				issue_verdict(entry, NF_DROP);
		}
		hlist_for_each_entry(inst, tmp, head, hlist)
			nfqnl_flush(inst, dev_cmp, ifindex);
	}

	read_unlock_bh(&instances_lock);
@@ -811,7 +773,7 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
		goto err_out_put;
	}

	entry = find_dequeue_entry(queue, id_cmp, ntohl(vhdr->id));
	entry = find_dequeue_entry(queue, ntohl(vhdr->id));
	if (entry == NULL) {
		err = -ENOENT;
		goto err_out_put;