[NETFILTER]: ip6_queue: deobfuscate entry lookups
A queue entry lookup currently looks like this: ipq_find_dequeue_entry -> __ipq_find_dequeue_entry -> __ipq_find_entry -> cmpfn -> id_cmp Use simple open-coded list walking and kill the cmpfn for ipq_find_dequeue_entry. Instead add it to ipq_flush (after similar cleanups) and use ipq_flush for both complete flushes and flushing entries related to a device. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
9521409265
Коммит
171b7fc4fc
|
@ -75,52 +75,6 @@ __ipq_enqueue_entry(struct ipq_queue_entry *entry)
|
|||
queue_total++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find and return a queued entry matched by cmpfn, or return the last
|
||||
* entry if cmpfn is NULL.
|
||||
*/
|
||||
static inline struct ipq_queue_entry *
|
||||
__ipq_find_entry(ipq_cmpfn cmpfn, unsigned long data)
|
||||
{
|
||||
struct ipq_queue_entry *entry;
|
||||
|
||||
list_for_each_entry(entry, &queue_list, list) {
|
||||
if (!cmpfn || cmpfn(entry, data))
|
||||
return entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__ipq_dequeue_entry(struct ipq_queue_entry *entry)
|
||||
{
|
||||
list_del(&entry->list);
|
||||
queue_total--;
|
||||
}
|
||||
|
||||
static inline struct ipq_queue_entry *
|
||||
__ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
|
||||
{
|
||||
struct ipq_queue_entry *entry;
|
||||
|
||||
entry = __ipq_find_entry(cmpfn, data);
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
|
||||
__ipq_dequeue_entry(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
__ipq_flush(int verdict)
|
||||
{
|
||||
struct ipq_queue_entry *entry;
|
||||
|
||||
while ((entry = __ipq_find_dequeue_entry(NULL, 0)))
|
||||
ipq_issue_verdict(entry, verdict);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__ipq_set_mode(unsigned char mode, unsigned int range)
|
||||
{
|
||||
|
@ -147,31 +101,59 @@ __ipq_set_mode(unsigned char mode, unsigned int range)
|
|||
return status;
|
||||
}
|
||||
|
||||
static void __ipq_flush(ipq_cmpfn cmpfn, unsigned long data);
|
||||
|
||||
static inline void
|
||||
__ipq_reset(void)
|
||||
{
|
||||
peer_pid = 0;
|
||||
net_disable_timestamp();
|
||||
__ipq_set_mode(IPQ_COPY_NONE, 0);
|
||||
__ipq_flush(NF_DROP);
|
||||
__ipq_flush(NULL, 0);
|
||||
}
|
||||
|
||||
static struct ipq_queue_entry *
|
||||
ipq_find_dequeue_entry(ipq_cmpfn cmpfn, unsigned long data)
|
||||
ipq_find_dequeue_entry(unsigned long id)
|
||||
{
|
||||
struct ipq_queue_entry *entry;
|
||||
struct ipq_queue_entry *entry = NULL, *i;
|
||||
|
||||
write_lock_bh(&queue_lock);
|
||||
entry = __ipq_find_dequeue_entry(cmpfn, data);
|
||||
|
||||
list_for_each_entry(i, &queue_list, list) {
|
||||
if ((unsigned long)i == id) {
|
||||
entry = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry) {
|
||||
list_del(&entry->list);
|
||||
queue_total--;
|
||||
}
|
||||
|
||||
write_unlock_bh(&queue_lock);
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void
|
||||
ipq_flush(int verdict)
|
||||
__ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
|
||||
{
|
||||
struct ipq_queue_entry *entry, *next;
|
||||
|
||||
list_for_each_entry_safe(entry, next, &queue_list, list) {
|
||||
if (!cmpfn || cmpfn(entry, data)) {
|
||||
list_del(&entry->list);
|
||||
queue_total--;
|
||||
ipq_issue_verdict(entry, NF_DROP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
|
||||
{
|
||||
write_lock_bh(&queue_lock);
|
||||
__ipq_flush(verdict);
|
||||
__ipq_flush(cmpfn, data);
|
||||
write_unlock_bh(&queue_lock);
|
||||
}
|
||||
|
||||
|
@ -364,12 +346,6 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
id_cmp(struct ipq_queue_entry *e, unsigned long id)
|
||||
{
|
||||
return (id == (unsigned long )e);
|
||||
}
|
||||
|
||||
static int
|
||||
ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
|
||||
{
|
||||
|
@ -378,7 +354,7 @@ ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
|
|||
if (vmsg->value > NF_MAX_VERDICT)
|
||||
return -EINVAL;
|
||||
|
||||
entry = ipq_find_dequeue_entry(id_cmp, vmsg->id);
|
||||
entry = ipq_find_dequeue_entry(vmsg->id);
|
||||
if (entry == NULL)
|
||||
return -ENOENT;
|
||||
else {
|
||||
|
@ -449,10 +425,7 @@ dev_cmp(struct ipq_queue_entry *entry, unsigned long ifindex)
|
|||
static void
|
||||
ipq_dev_drop(int ifindex)
|
||||
{
|
||||
struct ipq_queue_entry *entry;
|
||||
|
||||
while ((entry = ipq_find_dequeue_entry(dev_cmp, ifindex)) != NULL)
|
||||
ipq_issue_verdict(entry, NF_DROP);
|
||||
ipq_flush(dev_cmp, ifindex);
|
||||
}
|
||||
|
||||
#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
|
||||
|
@ -689,7 +662,7 @@ static void __exit ip6_queue_fini(void)
|
|||
{
|
||||
nf_unregister_queue_handlers(&nfqh);
|
||||
synchronize_net();
|
||||
ipq_flush(NF_DROP);
|
||||
ipq_flush(NULL, 0);
|
||||
|
||||
unregister_sysctl_table(ipq_sysctl_header);
|
||||
unregister_netdevice_notifier(&ipq_dev_notifier);
|
||||
|
|
Загрузка…
Ссылка в новой задаче