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

netfilter: log: protect nf_log_register against double registering

Currently, despite the comment right before the function,
nf_log_register allows registering two loggers on with the same type and
end up overwriting the previous register.

Not a real issue today as current tree doesn't have two loggers for the
same type but it's better to get this protected.

Also make sure that all of its callers do error checking.

Signed-off-by: Marcelo Ricardo Leitner <mleitner@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Marcelo Leitner and committed by
Pablo Neira Ayuso
8ac2bde2 0c26ed1c

+46 -6
+11 -1
net/ipv4/netfilter/nf_log_arp.c
··· 10 10 * it under the terms of the GNU General Public License version 2 as 11 11 * published by the Free Software Foundation. 12 12 */ 13 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13 14 14 15 #include <linux/module.h> 15 16 #include <linux/spinlock.h> ··· 131 130 if (ret < 0) 132 131 return ret; 133 132 134 - nf_log_register(NFPROTO_ARP, &nf_arp_logger); 133 + ret = nf_log_register(NFPROTO_ARP, &nf_arp_logger); 134 + if (ret < 0) { 135 + pr_err("failed to register logger\n"); 136 + goto err1; 137 + } 138 + 135 139 return 0; 140 + 141 + err1: 142 + unregister_pernet_subsys(&nf_log_arp_net_ops); 143 + return ret; 136 144 } 137 145 138 146 static void __exit nf_log_arp_exit(void)
+11 -1
net/ipv4/netfilter/nf_log_ipv4.c
··· 5 5 * it under the terms of the GNU General Public License version 2 as 6 6 * published by the Free Software Foundation. 7 7 */ 8 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 8 9 9 10 #include <linux/module.h> 10 11 #include <linux/spinlock.h> ··· 367 366 if (ret < 0) 368 367 return ret; 369 368 370 - nf_log_register(NFPROTO_IPV4, &nf_ip_logger); 369 + ret = nf_log_register(NFPROTO_IPV4, &nf_ip_logger); 370 + if (ret < 0) { 371 + pr_err("failed to register logger\n"); 372 + goto err1; 373 + } 374 + 371 375 return 0; 376 + 377 + err1: 378 + unregister_pernet_subsys(&nf_log_ipv4_net_ops); 379 + return ret; 372 380 } 373 381 374 382 static void __exit nf_log_ipv4_exit(void)
+11 -1
net/ipv6/netfilter/nf_log_ipv6.c
··· 5 5 * it under the terms of the GNU General Public License version 2 as 6 6 * published by the Free Software Foundation. 7 7 */ 8 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 8 9 9 10 #include <linux/module.h> 10 11 #include <linux/spinlock.h> ··· 399 398 if (ret < 0) 400 399 return ret; 401 400 402 - nf_log_register(NFPROTO_IPV6, &nf_ip6_logger); 401 + ret = nf_log_register(NFPROTO_IPV6, &nf_ip6_logger); 402 + if (ret < 0) { 403 + pr_err("failed to register logger\n"); 404 + goto err1; 405 + } 406 + 403 407 return 0; 408 + 409 + err1: 410 + unregister_pernet_subsys(&nf_log_ipv6_net_ops); 411 + return ret; 404 412 } 405 413 406 414 static void __exit nf_log_ipv6_exit(void)
+13 -3
net/netfilter/nf_log.c
··· 75 75 int nf_log_register(u_int8_t pf, struct nf_logger *logger) 76 76 { 77 77 int i; 78 + int ret = 0; 78 79 79 80 if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers)) 80 81 return -EINVAL; ··· 83 82 mutex_lock(&nf_log_mutex); 84 83 85 84 if (pf == NFPROTO_UNSPEC) { 85 + for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) { 86 + if (rcu_access_pointer(loggers[i][logger->type])) { 87 + ret = -EEXIST; 88 + goto unlock; 89 + } 90 + } 86 91 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) 87 92 rcu_assign_pointer(loggers[i][logger->type], logger); 88 93 } else { 89 - /* register at end of list to honor first register win */ 94 + if (rcu_access_pointer(loggers[pf][logger->type])) { 95 + ret = -EEXIST; 96 + goto unlock; 97 + } 90 98 rcu_assign_pointer(loggers[pf][logger->type], logger); 91 99 } 92 100 101 + unlock: 93 102 mutex_unlock(&nf_log_mutex); 94 - 95 - return 0; 103 + return ret; 96 104 } 97 105 EXPORT_SYMBOL(nf_log_register); 98 106