LINUX.ORG.RU

Теряется *char.


0

0

Имеется модуль, представляющий собой файервол на базе netfiltra.
Проблемма представляет собой зависание системы, как я пологаю из-за
сегфолта в модуле.
Приведу для начала тот код что имеет отношение к проблемме:

/************************************netfw-bace.h*******************************
*************/
...
struct netfw_chains_table;

//struct of table
struct netfw_table{
	struct netfw_table *prev;
	struct netfw_table *next;
	char *name;
	int id;
	int policy;
	int (* set_rule)(int action, struct netfw_chains_table *new);
	int (* ud_set_rule)(char *table, int action, int id, char *par, char *arg, int num_par);
};

//struct of module
struct netfw_module{
	struct netfw_module *prev;
	struct netfw_module *next;
	char *name;
	int id;
	char *match;
	int (* check)(int action, char *table_name, int id, char *arg, struct sk_buff **skb);
};

//struct of rule chain
struct netfw_rules_chain{
	struct netfw_rules_chain *prev;
	struct netfw_rules_chain *next;

	int it;
	struct netfw_module *m;
	int (* check)(int action, char *table_name, int id, char *arg, struct sk_buff **skb);
};

//struct of chain table
struct netfw_chains_table{
	struct netfw_chains_table *prev;
	struct netfw_chains_table *next;

	char *table;
	int num_rules;
	struct netfw_rules_chain *list;
};
...
/*******************************************************************************
*****************/

/************************************netfw-bace.c*******************************
*************/
#include "netfw-bace.h"
...
void fill(struct netfw_module *m, char *table, int id, char *arg)
{
	...
}

int netfw_add_rule(char *table, int id, int it, char *par[], char *arg[], int num)
{
	struct netfw_table *t = netfw_get_table_by_name(table);
	if(!t) return NETFW_ERR_NO_SUCH_TABLE;
	struct netfw_rules_chain *chain_cach = kmalloc(sizeof(struct netfw_rules_chain),GFP_DMA);
	if(!chain_cach) return -1;
	chain_cach->next = chain_cach->prev = chain_cach;
	
	struct netfw_module *m;
	
	struct netfw_chains_table *ct = kmalloc(sizeof(struct netfw_chains_table),GFP_DMA);
	if(!ct) return -1;
	ct->next = ct->prev = ct;
	int k;
	for(k = 0; k <= num - 1; k++)
	{
		m = netfw_get_module_by_name(par[k]);
		if(m)
		{
			fill(m,table,netfw_num_rules,arg[k]);

			struct netfw_rules_chain *new = kmalloc(sizeof(struct netfw_rules_chain),GFP_DMA);
			if(!new) return -1;
			new->it = it;			
			new->m = m;
			new->check = m->check;

			struct netfw_rules_chain *next = chain_cach->next;
			struct netfw_rules_chain *prev = chain_cach;

			next->prev = new;
			new->next = next;
			new->prev = prev;
			prev->next = new;
		}
	}
	ct->table = table;
	ct->list = chain_cach;
	ct->num_rules = num;
	t->set_rule(NETFW_ADD_RULE,ct);
	
	netfw_num_rules++;
	
	return 0;
}

void netfw_add_chains_table(struct netfw_chains_table *new, struct netfw_chains_table *old,int first)
{
	if(first)
	{
	    old->table = new->table;
	    old->num_rules = new->num_rules;
	    old->list = new->list;
	}
	else
	{
    	    struct netfw_chains_table *next = old->next;
	    struct netfw_chains_table *prev = old;
	    next->prev = new;
	    new->next = next;
	    new->prev = prev;
	    prev->next = new;
        }
	
	printk("Table name in add_chains old->table: ");
	printk(old->table);
	printk("\n");
}
...
int netfw_check_rules(struct netfw_chains_table *chains_table, struct sk_buff **skb)
{
	printk("packet check was start\n");
	table = chains_table;
	int k,i,mach,it;
	it = 0;
	for(k = 0; k < netfw_num_rules; k++)
	{
		printk("change rule chain\n");
		mach = 0;
		chain = table->list;
		mod = chain->next;
		int b = 0;
		int tb = 0;
		for(i = 0; i < table->num_rules; i++)
		{
			if(b)
			{
			    printk("block is set\n");
			    mod->check(NETFW_CHK_RULE, 0, 0, 0, 0);
			}
			else
			{
				printk("block not set\n");
				printk("Table name table->table: ");
				printk(table->table);
				printk("\n");
				tb = mod->check(NETFW_CHK_RULE, table->table, 0, 0, skb);
				if(!tb)
				{
				    printk("missed chain block have been set\n");
				    b = 1;
				}
				else
				{
					if(tb == 1)
					{
					    printk("was match\n");
					    mach++;
					}
					if(tb == 2)
					{
					    printk("wrong table\n");
//					    i--;
					}
				}
				if(!mod->next) return 0;
				mod = mod->next;
			}
		}
		if(mach == table->num_rules)
		{
			printk("check was finish with set\n");
			it = chain->it;
			if(it == NETFW_ACCEPT)
			{
			    printk("packet was pass\n");
			    return 1;
			}
			if(it == NETFW_DROP)
			{
			    printk("packet was drop\n");
			    return 0;
			}
		}
		if(!table->next) return 0;
		table = table->next;
	}
	printk("check was finish with default\n");
	return 1;
}
...
ssize_t netfw_write (struct file *f, const char *ch, size_t size, loff_t *loff)
{
	if(num > 0)if(n < num*2)
	{
		if(par_accept)
		{
			par[n_par] = kmalloc(sizeof(char[strlen(ch)]),GFP_DMA);
			par[n_par] = ch;
			par_accept = 0;
			n_par++;
		}
		else
		{
			arg[n_arg] = kmalloc(sizeof(char[strlen(ch)]),GFP_DMA);
			arg[n_arg] = ch;
			par_accept = 1;
			n_arg++;
		}
		n++;
	}

	if(!strcmp(ch,"$"))
	{
		step = -1;
		n = n_par = n_arg = 0;
		if(act > 0)
		{
			switch(act)
			{
				case NETFW_ADD_RULE:
					netfw_add_rule(to_table,0,it,par,arg,num);
					break;
				case NETFW_DEL_RULE:
					break;
			}
		}
		num = 0;
	}
	
	step++;
	switch(step)
	{
		//Action
		case 1:
			if(!strcmp(ch,"add"))
			{
				act = NETFW_ADD_RULE;
			}
			if(!strcmp(ch,"del"))
			{
				act = NETFW_DEL_RULE;
			}
			break;
		//Table name
		case 2:
			to_table = ch;				<----- вот здесь она и записывается
			break;
		//What to do ( aka "it" )
		case 3:
			if(!strcmp(ch,"accept"))
			{
				it = NETFW_ACCEPT;
			}
			if(!strcmp(ch,"drop"))
			{
				it = NETFW_DROP;
			}
			break;
		//Num of elements
		case 4:
			num = netfw_char_to_int(ch);
			kfree(par);
			kfree(arg);
			par = kmalloc(sizeof(char[num]),GFP_DMA);
			arg = kmalloc(sizeof(char[num]),GFP_DMA);
			par_accept = 1;
			break;
	}

	return 0;
}
...
/*******************************************************************************
*****************/
★★★★★

/************************************netfw-table.c******************************
**************/
#include "netfw-bace.h"
...
//policy of table
int netfw_pre_hook_polcy, netfw_in_hook_polcy, netfw_forward_hook_polcy, netfw_out_hook_polcy, netfw_post_hook_polcy;

//num of rules
int netfw_pre_rules, netfw_in_rules, netfw_forward_rules, netfw_out_rules, netfw_post_rules;

struct netfw_chains_table *pre_table, *in_table, *forward_table, *out_table, *post_table;
...
//hook function in input table
unsigned int main_hook_in(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, 
			   const struct net_device *out, int (*okfn)(struct sk_buff*))
{
	switch(netfw_in_hook_polcy)
	{
		case NETFW_ACCEPT:
			printk("Hook IN in_table->name: ");
			printk(in_table->table);
			printk("\n");
			if(!skb) return NF_ACCEPT;
			if(!netfw_in_rules) return NF_ACCEPT;
			if(netfw_check_rules(in_table,skb)) return NF_ACCEPT;
			else return NF_DROP;
			break;
		case NETFW_DROP:
			if(!skb) return NF_DROP;
			if(!netfw_in_rules) return NF_DROP;
			if(!skb) return NF_ACCEPT;
			if(netfw_check_rules(in_table,skb)) return NF_ACCEPT;
			else return NF_DROP;
			break;
//		case NETFW_REJECT:
//			return NF_REJECT;
//			break;
		default:
			return NF_ACCEPT;
			break;
	}
	return NF_ACCEPT;
}
...
//function for set rule in input table
int set_rule_in(int action, struct netfw_chains_table *new)
{
	switch(action)
	{
		case NETFW_ADD_RULE:
			{
				// С помощью netfw_add_chains_table() записывам в список
				if(netfw_in_rules == 0) netfw_add_chains_table(new,in_table,1);
				else netfw_add_chains_table(new,in_table,0);
				printk("Table name in set_rule_in in_table->table: ");
				printk(in_table->table);
				printk("\n");
				netfw_in_rules++;
			}
			break;
		case NETFW_DEL_RULE:
			break;
		case NETFW_SET_POL:
			break;
		default:
			break;
	}
	return 0;
}
...
int netfw_init_base_tab(void)
{
	...	
	in_table = kmalloc(sizeof(struct netfw_chains_table),GFP_DMA);
	if(!in_table) return NETFW_ERR_CANT_KMALLOC;
	in_table->next = in_table->prev = in_table;
	...
	return 1;
}
...
/*******************************************************************************
*****************/

А теперь по порядку.
После 101-ого резета удалось выяснить в каком месте следует искать проблемму,
такое количество резетов связано с теми условиями при которых возникает трабла.
А именно при попытке воспользоваться любой тулзой посложнее пинга.  Дело в том
что именно пинг не вызывает такой проблеммы, а если заюзать что нибудь типа 
ssh или ftp, другого не имею, то система зависнет, как я уже отметил видимо сегфолт.

Расскажу что происходит. Добавление правила происходит через netfw_write() в котором
последовательно вводятся данные. Причина сегфолта как я понял связана с тем что теряется
строка *char. И далее переменная с потерянным массивом передаётся в функцию и вызывает
сегфолт при обращение к ней. Но что интересно сегфолт не происходит если юзать пинг,
причина такого поведения мне не понятна.  И вот благодаря тому что тут нет сегфолта
мне и удалось выяснить что не так.
Вот вырезка из /var/log/messages, в которой видно что переменная потеряна:

Jul 25 14:23:00 dell kernel: Table name tport add before new: input
Jul 25 14:23:00 dell kernel: Table name tport add after new: input
Jul 25 14:23:00 dell kernel: Table name in add_chains old->table: input
Jul 25 14:23:00 dell kernel: Table name in set_rule_in in_table->table: input
Jul 25 14:23:07 dell kernel: packet check was start
Jul 25 14:23:07 dell kernel: change rule chain
Jul 25 14:23:07 dell kernel: block not set
Jul 25 14:23:07 dell kernel: Table name table->table:	<--- тут должен быть input, но тут пусто(после ":")
Jul 25 14:23:07 dell kernel: check tport				<--- это показывает что ссылка на функцию жива
Jul 25 14:23:07 dell kernel: missed chain block have been set
Jul 25 14:23:07 dell kernel: check was finish with default
Jul 25 14:23:07 dell kernel: packet check was start
Jul 25 14:23:07 dell kernel: change rule chain
Jul 25 14:23:07 dell kernel: block not set
Jul 25 14:23:07 dell kernel: Table name table->table:	<--- тут должен быть input, но тут пусто(после ":")
Jul 25 14:23:07 dell kernel: check tport				<--- это показывает что ссылка на функцию жива
Jul 25 14:23:07 dell kernel: missed chain block have been set
Jul 25 14:23:07 dell kernel: check was finish with default

Порядок вызова функций таков:

1. netfw_write() считывание параметров, включая имя этой переменной
2. netfw_add_rule() параметры записываются в модули и в таблицы
3. set_rule_in() тут происходит добавление вызова модулей в таблицу
4. netfw_add_chains_table() добавляет в список новый элемент
...вот тут как раз стоит обратить внимание, что в этой функции видно 
добавленный элемент, а уже в main_hook_in() не видно ну и естественно нету 
её в netfw_check_rules(). 
5. main_hook_in() вызывается при получении пакета
6. netfw_check_rules() проверяются правила.

Вот собсно и вопрос, почему элемент char *table в структуре из списка 
не виден в main_hook_in(). При этом указатель на функцию mod->check()
остаётся жив, как и переменная it.

ВЫЗОВ ВСЕХ ФУНКЦИЙ ИДЁТ В НУЖНОМ ПОРЯДКЕ!!!

Заранее спасибо!!!

cyclon ★★★★★
() автор топика
Ответ на: комментарий от cyclon

В netfw_check_rules() это table->table в printk();

cyclon ★★★★★
() автор топика
Ответ на: комментарий от cyclon

Ну чего, cyclon, код ужасный. Не удивительно, что он работает неправильно. Первый принцип - плохой код не может работать правильно. Тем более, такой как у Вас. Я бы даже побоялся использовать такой в экране, там же дыр очень много будет.

Давайте устроим разбор полетов :)


1. 

	printk("Table name in add_chains old->table: ");
	printk(old->table);
	printk("\n");

Про %s когда-нибудь слышали?

2. 

void netfw_add_chains_table(struct netfw_chains_table *new, struct netfw_chains_table *old,int first)

Зачем нужен first? Нельзя использовать проверку old == NULL? Гораздо понятнее код будет выглядеть и читаться. Вобщем, найдите и почитайте нормальную реализацию списков.

3.

for(k = 0; k < netfw_num_rules; k++)

Когда есть список, естественнее в качестве итераторов использовать его 
переменные, не вводя целых локальных переменных

for (table = list; table; table = table->next)

вот так нужно писать.

4.
	mod = chain->next;
	int b = 0;
	int tb = 0;

Над этим думал минут десять, так и не понял, зачем они нужны, скорее всего, все это можно выкинуть.

5.

В документации ядра есть файлик - CodingStyle. Неплохо бы его прочесть и осознать. Для Вашей же пользы.

6. 
	    printk("packet was drop\n");

В учебник по английскому загляните.

Ну и так далее. Исправляйте сначала это, потом уже будем 
искать причину. Хотя в коде разобраться так и не удалось, кажется, что вы указатель копируете на строку, а она потом освобождается. Хотя из кусков кода это не совсем ясно. Может kmalloc + strcpy помогут?




anonymous
()
Ответ на: комментарий от anonymous

Всё что тут написано это черновой код, что то потом будет исправлено. Далее, %s.. ну можно и заменить, хотя дыр меньше не станет :) По второму пункту, мне так удобнее, а ввод глобальных переменных никому не мешает к тому же это не повлеяет на проблемму. По 4-ому, ну вот видишь, не разобрался а сразу говоришь выкинуть, переменным задавал но поскольку в поисках решения глюков в других местах, решил явно инициализировать всё подряд: b.tb, кошку, собаку.... ээ это уже не то. А mod=chain->next выкинуть нельзя. Про учебник по англицкому, ну это пишется для себя, просто отметил это место, ну не писать же тут какую нить хрень "ttyu453jm" а так мне это понятно.

А теперь по делу, попробовал заюзать независимую функцию void test(void) в netfw-table.c и вызывал её из main_hook_in и set_rule_in.

void test(void) { printk(in_table->table); }

при вызове её из первой функции печатается пустота а из второй то что надо.

cyclon ★★★★★
() автор топика
Ответ на: комментарий от cyclon

Млин а я ведь хотел ещё вчера попробовать strcpy и чёрт меня дёрнул не сделать это, а ща уже как бы два голоса (твой и мой, вместе мы сила, прим. втор. голоса) за это и ... Короче спасибо, а то я так и думал бы, хотя может ближе к обеду всё же попробвал от безвыходности. Ещё раз спасибо.

cyclon ★★★★★
() автор топика
Ответ на: комментарий от cyclon

И если не трудно, может ты в курсе с чем связана такая проблемма, 
когда я пытаюсь заблокировать ssh то ясным делом ставлю 22 порт, но 
при коннектте я проверяю с какого порта идёт  пакет и вот с каких портов:

Jul 26 09:13:30 dell kernel: packet to port 39688, set in rule 22
Jul 26 09:13:30 dell kernel: missed chain block have been set
Jul 26 09:13:30 dell kernel: check was finish with default
Jul 26 09:13:30 dell kernel: packet check was start
Jul 26 09:13:30 dell kernel: change rule chain
Jul 26 09:13:30 dell kernel: packet to port 5632, set in rule 22
Jul 26 09:13:30 dell kernel: missed chain block have been set
Jul 26 09:13:30 dell kernel: check was finish with default

но возникает вопрос а почему не с 22 и почему если iptables'у задать
22 порт то реально блокирует. Вот кусок функции проверки, взят из 
примера для netfiltra:

thead = (struct tcphdr *)(skb->data + (skb->nh.iph->ihl * 4));
printk("packet to port %d, set in rule %d\n",thead->dest,tport_temp->port);
if(tport_temp->port == thead->source) return 1;

cyclon ★★★★★
() автор топика
Ответ на: комментарий от cyclon

Слухай, а у тя нет желания присоединиться к проекту? Любая помощь будет очень полезна, а то одному скучно, ну и местами не просто!

cyclon ★★★★★
() автор топика
Ответ на: комментарий от cyclon

До тех пор пока пишется такой код, пусть даже и черновой, нет уж, спасибо :)

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.