LINUX.ORG.RU

copy_to_user


0

0

Какие то невнятные проблемы с компированием в контекст пользователя. copy_from_user замечательно работает, а copy_to_user - нет в комбинации с getsockopt.

проверяю указатель на предмет того, что туда можно писать/читать с access_ok - говорит нельзя. В __user спейсе все выделено.

Какие могут быть причины такой незадачи?

> проверяю указатель на предмет того, что туда можно писать/читать с access_ok - говорит нельзя

access_ok проверяет только, не выходит ли буфер за границу юзер спейса.
Если он выдаёт ошибку, то, вероятно указатель неправильно передаётся.

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

Вобщем суть какая.

Сделал сейчас тесткейс. 

В общем и целом где то так:

Йузреспейс:

int main()
{
	int optname = NGW_GET_CHECK;
	int sockfd =  socket(AF_INET, SOCK_RAW, PF_INET);
	int ret;
	socklen_t cnt = 100;

	struct tlnl_minimal_data * rules = malloc(sizeof(struct tlnl_minimal_data) * cnt);
	memset(rules, 1, sizeof(struct tlnl_minimal_data) * cnt);
	printf("Get kernel rules [cnt = %d]\n", cnt);
	
	memset(rules, 0xff, sizeof(struct tlnl_minimal_data) * cnt);


	printf("GET SOCK OPT Waiting for rules at %p size: %d\n", rules, sizeof(struct tlnl_minimal_data) * cnt);
	
	ret = getsockopt(sockfd, IPPROTO_IP, optname, rules, (socklen_t *) &cnt);
	
	printf("Got kernel rules [cnt = %d]\n", cnt);

	printf("SET SOCK OPT Waiting for rules at %p size: %d\n", rules, sizeof(struct tlnl_minimal_data) * cnt);
	
	ret = setsockopt(sockfd, IPPROTO_IP, optname, rules, cnt);
	
	printf("Got kernel rules [cnt = %d]\n", cnt);


	printf("GET SOCK OPT Waiting for rules at %p size: %d\n", rules, sizeof(struct tlnl_minimal_data) * cnt);
	
	ret = getsockopt(sockfd, IPPROTO_IP, optname, rules, (socklen_t *) &cnt);
	
	printf("Got kernel rules [cnt = %d]\n", cnt);

	printf("SET SOCK OPT Waiting for rules at %p size: %d\n", rules, sizeof(struct tlnl_minimal_data) * cnt);
	
	ret = setsockopt(sockfd, IPPROTO_IP, optname, rules, cnt);
	
	printf("Got kernel rules [cnt = %d]\n", cnt);

	
	close(sockfd);

	return cnt;
}

Кернел спейс: 

static struct nf_sockopt_ops ngw_sockopts =
{
	.pf             = PF_INET,
	.set_optmin     = NGW_CTL,
	.set_optmax     = NGW_MAX_CTL,
	.set            = ctl_set,
	.get_optmin     = NGW_CTL,
	.get_optmax     = NGW_MAX_CTL,
	.get            = ctl_get,
	/* .owner          = THIS_MODULE, */
};


int ctl_get(struct sock *sk, int val, void __user *opt, int *len)
{

	int i,res;
	int retval = 0;
	struct hw_minimal_data dataList[MAX_MAC_COUNT];
	struct rules_list list;
	char * garbage_ptr;
	
	PDEBUG("baryer_ctl_get(%p, %d, %p, %d)", sk, val, opt, *len);
	
	switch (val)
		{

		case NGW_GET_CHECK:
			PDEBUG("SELF CHECK. LOADING GARBAGE FROM %p SIZE %d", opt, *len);
			garbage_ptr = kmalloc(*len, GFP_ATOMIC);
			if (! garbage_ptr)
				{
					PDEBUG("GARBAGE CTL FAILED");
					goto unlock;
				}
			
			res = copy_from_user(garbage_ptr, opt, *len);
			PDEBUG("NOT COPIED %d of GARBAGE", res);
			PDEBUG("COPY GARBAGE BACK TO USER");
			res = copy_to_user(opt, garbage_ptr, *len);
			kfree(garbage_ptr);
			PDEBUG("NOT COPIED TO USER %d", res);

			goto exit;
}


int ctl_set(struct sock *sk, int val, void __user *opt, int len)
{

	int i,res;
	int retval = 0;
	struct hw_minimal_data dataList[MAX_MAC_COUNT];
	struct rules_list list;
	char * garbage_ptr;
	
	PDEBUG("baryer_ctl_get(%p, %d, %p, %d)", sk, val, opt, *len);
	
	switch (val)
		{

		case NGW_GET_CHECK:
			PDEBUG("SELF CHECK. LOADING GARBAGE FROM %p SIZE %d", opt, *len);
			garbage_ptr = kmalloc(*len, GFP_ATOMIC);
			if (! garbage_ptr)
				{
					PDEBUG("GARBAGE CTL FAILED");
					goto unlock;
				}
			
			res = copy_from_user(garbage_ptr, opt, len);
			PDEBUG("NOT COPIED %d of GARBAGE", res);
			PDEBUG("COPY GARBAGE BACK TO USER");
			res = copy_to_user(opt, garbage_ptr, len);
			kfree(garbage_ptr);
			PDEBUG("NOT COPIED TO USER %d", res);

			goto exit;
}

Т.е. тот же самый код. За исключением len.
Только set_ctl работает, а  get_ctl - нет. 
Указатель тот же самый.
Что это за шутка такая?

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

Кстати в getsockopt ни from ни to не работают.
Если использовать копирование без проверки, то сколько то записывает,но не все.

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

> res = copy_from_user(garbage_ptr, opt, *len);

Для len тоже copy_from_user надо сделать. Нельзя же просто брать и разыменовывать указатель из юзер спейса.

> int ctl_set(struct sock *sk, int val, void __user *opt, int len) ... > garbage_ptr = kmalloc(*len, GFP_ATOMIC);

Разыменовывание не указателя.

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

Про len - в сырцах ядра так именно так и делают..

static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
{
...
if (copy_to_user(user, &info, *len) != 0)
ret = -EFAULT;
...
}

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

> Про len - в сырцах ядра так именно так и делают..

И неправильно делают. Пробовали перед getsockopt делать ставить printf?
Выводится то же самое, что и в PDEBUG()?

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

Разумеется пробывал.
Тоже самое. (=
А вот если сделать copy_from_user - то он скажет что не может его забрать.
Впрочем как раз вот с len все нормально. Он нормально и обратно возвращается. В отличие от. =\

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

Отбой тревоги. Нашел какую то мистическую закономерность.
Если тот же самый кусок set ^C ^V и переименовать в get, с заменой len на *len
все почему то работает (%

Буду смотреть детальнее. Тут явно дело не в copy_to_user :]

vasily_pupkin ★★★★★
() автор топика

Проблема решена.
Господа! Не забывайте, что стек ограничен 4-8Кб! (%

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