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 "args.h"
|
||||||
#include "logging.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
|
#define MAX_ARGC 1024
|
||||||
static char *argv[MAX_ARGC];
|
static char *argv[MAX_ARGC];
|
||||||
|
|
||||||
static int params_set(const char *cval, const struct kernel_param *kp) {
|
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);
|
int cv_len = strlen(cval);
|
||||||
if (cv_len >= 1 && cval[cv_len - 1] == '\n') {
|
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);
|
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);
|
kfree(val);
|
||||||
|
|
||||||
|
mutex_unlock(&config_free_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,9 +61,15 @@ MODULE_AUTHOR("Vadim Vetrov <vetrovvd@gmail.com>");
|
|||||||
MODULE_DESCRIPTION("Linux kernel module for youtubeUnblock");
|
MODULE_DESCRIPTION("Linux kernel module for youtubeUnblock");
|
||||||
|
|
||||||
static struct socket *rawsocket;
|
static struct socket *rawsocket;
|
||||||
|
|
||||||
static struct socket *raw6socket;
|
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) {
|
static int open_raw_socket(void) {
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
ret = sock_create(AF_INET, SOCK_RAW, IPPROTO_RAW, &rawsocket);
|
ret = sock_create(AF_INET, SOCK_RAW, IPPROTO_RAW, &rawsocket);
|
||||||
@@ -385,6 +391,17 @@ static NF_CALLBACK(ykb_nf_hook, skb) {
|
|||||||
int ret;
|
int ret;
|
||||||
struct packet_data pd = {0};
|
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)
|
if ((skb->mark & config.mark) == config.mark)
|
||||||
goto accept;
|
goto accept;
|
||||||
|
|
||||||
@@ -422,8 +439,10 @@ static NF_CALLBACK(ykb_nf_hook, skb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
accept:
|
accept:
|
||||||
|
atomic_dec(&hot_config_counter);
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
drop:
|
drop:
|
||||||
|
atomic_dec(&hot_config_counter);
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
}
|
}
|
||||||
@@ -505,6 +524,17 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void __exit ykb_destroy(void) {
|
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 (config.use_ipv6) {
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
||||||
struct net *n;
|
struct net *n;
|
||||||
@@ -513,7 +543,6 @@ static void __exit ykb_destroy(void) {
|
|||||||
#else
|
#else
|
||||||
nf_unregister_hook(&ykb6_nf_reg);
|
nf_unregister_hook(&ykb6_nf_reg);
|
||||||
#endif
|
#endif
|
||||||
close_raw6_socket();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,13,0)
|
||||||
@@ -523,9 +552,12 @@ static void __exit ykb_destroy(void) {
|
|||||||
#else
|
#else
|
||||||
nf_unregister_hook(&ykb_nf_reg);
|
nf_unregister_hook(&ykb_nf_reg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (config.use_ipv6) {
|
||||||
|
close_raw6_socket();
|
||||||
|
}
|
||||||
|
|
||||||
close_raw_socket();
|
close_raw_socket();
|
||||||
|
|
||||||
free_config(config);
|
free_config(config);
|
||||||
lginfo("youtubeUnblock kernel module destroyed.\n");
|
lginfo("youtubeUnblock kernel module destroyed.\n");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user