mirror of
https://github.com/Waujito/youtubeUnblock.git
synced 2025-12-06 11:36:45 +03:00
Concurrency defenders in config parse and module destroy
This commit is parr of #213 fix. In this issue kernel module crashes on high bandwidth usage has been reported. The part of the problem is concurrency usage: when config gets freed, callbacks keep to depend on it.
This commit is contained in:
31
src/kargs.c
31
src/kargs.c
@@ -24,11 +24,23 @@
|
||||
#include "args.h"
|
||||
#include "logging.h"
|
||||
|
||||
/**
|
||||
* Defined in kyoutubeUnblock.c
|
||||
*/
|
||||
extern struct spinlock hot_config_spinlock;
|
||||
extern atomic_t hot_config_counter;
|
||||
extern atomic_t hot_config_rep;
|
||||
extern struct mutex config_free_mutex;
|
||||
|
||||
#define MAX_ARGC 1024
|
||||
static char *argv[MAX_ARGC];
|
||||
|
||||
static int params_set(const char *cval, const struct kernel_param *kp) {
|
||||
int ret = 0;
|
||||
int ret;
|
||||
ret = mutex_trylock(&config_free_mutex);
|
||||
if (ret == 0)
|
||||
return -EBUSY;
|
||||
|
||||
|
||||
int cv_len = strlen(cval);
|
||||
if (cv_len >= 1 && cval[cv_len - 1] == '\n') {
|
||||
@@ -58,8 +70,25 @@ static int params_set(const char *cval, const struct kernel_param *kp) {
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock(&hot_config_spinlock);
|
||||
// lock netfilter youtubeUnblock
|
||||
atomic_set(&hot_config_rep, 1);
|
||||
spin_unlock(&hot_config_spinlock);
|
||||
|
||||
// lock config hot replacement process until all
|
||||
// netfilter callbacks keep running
|
||||
while (atomic_read(&hot_config_counter) > 0) {}
|
||||
|
||||
ret = yparse_args(argc, argv);
|
||||
|
||||
spin_lock(&hot_config_spinlock);
|
||||
// relaunch youtubeUnblock
|
||||
atomic_set(&hot_config_rep, 0);
|
||||
spin_unlock(&hot_config_spinlock);
|
||||
|
||||
kfree(val);
|
||||
|
||||
mutex_unlock(&config_free_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,9 +61,15 @@ MODULE_AUTHOR("Vadim Vetrov <vetrovvd@gmail.com>");
|
||||
MODULE_DESCRIPTION("Linux kernel module for youtubeUnblock");
|
||||
|
||||
static struct socket *rawsocket;
|
||||
|
||||
static struct socket *raw6socket;
|
||||
|
||||
DEFINE_SPINLOCK(hot_config_spinlock);
|
||||
DEFINE_MUTEX(config_free_mutex);
|
||||
atomic_t hot_config_counter = ATOMIC_INIT(0);
|
||||
// boolean flag for hot config replacement
|
||||
// if 1, youtubeUnblock should stop processing
|
||||
atomic_t hot_config_rep = ATOMIC_INIT(0);
|
||||
|
||||
static int open_raw_socket(void) {
|
||||
int ret = 0;
|
||||
ret = sock_create(AF_INET, SOCK_RAW, IPPROTO_RAW, &rawsocket);
|
||||
@@ -385,6 +391,17 @@ static NF_CALLBACK(ykb_nf_hook, skb) {
|
||||
int ret;
|
||||
struct packet_data pd = {0};
|
||||
|
||||
spin_lock(&hot_config_spinlock);
|
||||
// if set flag to disable processing,
|
||||
// explicitly accept all packets
|
||||
if (atomic_read(&hot_config_rep)) {
|
||||
spin_unlock(&hot_config_spinlock);
|
||||
return NF_ACCEPT;
|
||||
} else {
|
||||
atomic_inc(&hot_config_counter);
|
||||
}
|
||||
spin_unlock(&hot_config_spinlock);
|
||||
|
||||
if ((skb->mark & config.mark) == config.mark)
|
||||
goto accept;
|
||||
|
||||
@@ -422,8 +439,10 @@ static NF_CALLBACK(ykb_nf_hook, skb) {
|
||||
}
|
||||
|
||||
accept:
|
||||
atomic_dec(&hot_config_counter);
|
||||
return NF_ACCEPT;
|
||||
drop:
|
||||
atomic_dec(&hot_config_counter);
|
||||
kfree_skb(skb);
|
||||
return NF_STOLEN;
|
||||
}
|
||||
@@ -505,6 +524,17 @@ err:
|
||||
}
|
||||
|
||||
static void __exit ykb_destroy(void) {
|
||||
mutex_lock(&config_free_mutex);
|
||||
// acquire all locks.
|
||||
spin_lock(&hot_config_spinlock);
|
||||
// lock netfilter youtubeUnblock
|
||||
atomic_set(&hot_config_rep, 1);
|
||||
spin_unlock(&hot_config_spinlock);
|
||||
|
||||
// wait until all
|
||||
// netfilter callbacks keep running
|
||||
while (atomic_read(&hot_config_counter) > 0) {}
|
||||
|
||||
if (config.use_ipv6) {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
||||
struct net *n;
|
||||
@@ -513,7 +543,6 @@ static void __exit ykb_destroy(void) {
|
||||
#else
|
||||
nf_unregister_hook(&ykb6_nf_reg);
|
||||
#endif
|
||||
close_raw6_socket();
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
||||
@@ -524,8 +553,11 @@ static void __exit ykb_destroy(void) {
|
||||
nf_unregister_hook(&ykb_nf_reg);
|
||||
#endif
|
||||
|
||||
close_raw_socket();
|
||||
if (config.use_ipv6) {
|
||||
close_raw6_socket();
|
||||
}
|
||||
|
||||
close_raw_socket();
|
||||
free_config(config);
|
||||
lginfo("youtubeUnblock kernel module destroyed.\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user