referring a user address from ioctl entry point

From: yogeshwar sonawane
Date: Tue Mar 21 2006 - 09:41:23 EST


Hi all,

can we write directly to user virtual address from kernel space?
i.e. dereferencing a user address from driver entry point?

I am attaching my sample driver code with user application.

I tried to run this on RHEL4-U2. it is running fine.

But on FC3, its not working giving segmentation fault in user space.
The kernel messeges are:-

Mydevice: open
Mydevice: ioctl: GET_SIZE<1>Unable to handle kernel paging request at
virtual address fefd53a0
printing eip:
1282319d
*pde = 00000000
Oops: 0002 [#1]
Modules linked in: driver1(U) parport_pc lp parport autofs4 i2c_dev
i2c_core sunrpc md5 ipv6 dm_mod uhci_hcd snd_cs46xx snd_rawmidi
snd_seq_device snd_ac97_codec snd_pcm_oss snd_mixer_oss snd_pcm
snd_timer snd soundcore snd_page_alloc gameport 3c59x floppy ext3 jbd
aic7xxx sd_mod scsi_mod
CPU: 0
EIP: 0060:[<1282319d>] Not tainted VLI
EFLAGS: 00010246 (2.6.9-1.667)
EIP is at my_ioctl+0x67/0x72 [driver1]
eax: 0000001a ebx: fefd53a0 ecx: 128232aa edx: 090e2f90
esi: 80047a03 edi: 0a17bca0 ebp: ffffffe7 esp: 090e2f8c
ds: 007b es: 007b ss: 0068
Process a.out (pid: 3027, threadinfo=090e2000 task=0916d770)
Stack: 128232aa 12823960 0217a147 fefd53a0 0881c2e4 0a17bca0 00000003 090e2fc0
00000004 090e2fc4 fefd5434 fefd53c0 090e2000 ffff4200 00000003 80047a03
fefd53a0 fefd5434 fefd53c0 fefd53a8 00000036 0000007b 0000007b 00000036
Call Trace:
[<0217a147>] sys_ioctl+0x296/0x337
Code: <3>Debug: sleeping function called from invalid context at
include/linux/rwsem.h:43
in_atomic():0[expected: 0], irqs_disabled():1
[<0211c8b9>] __might_sleep+0x7d/0x88
[<0215e27e>] rw_vm+0x216/0x482
[<12823172>] my_ioctl+0x3c/0x72 [driver1]
[<12823172>] my_ioctl+0x3c/0x72 [driver1]
[<0215e9d0>] get_user_size+0x30/0x57
[<12823172>] my_ioctl+0x3c/0x72 [driver1]
[<0210682b>] show_registers+0x109/0x15e
[<02106a2f>] die+0x14a/0x241
[<0211937e>] do_page_fault+0x0/0x511
[<0211937e>] do_page_fault+0x0/0x511
[<02119733>] do_page_fault+0x3b5/0x511
[<1282319d>] my_ioctl+0x67/0x72 [driver1]
[<02153c78>] handle_mm_fault+0xe4/0x21e
[<0211953a>] do_page_fault+0x1bc/0x511
[<0222b4fe>] vt_console_print+0x64/0x2a3
[<0222b4fe>] vt_console_print+0x64/0x2a3
[<0222b49a>] vt_console_print+0x0/0x2a3
[<0211937e>] do_page_fault+0x0/0x511
[<1282319d>] my_ioctl+0x67/0x72 [driver1]
[<0217a147>] sys_ioctl+0x296/0x337
Bad EIP value.


help me out.
thanks in advance.
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/fs.h>
#include<linux/init.h>
#include<asm/uaccess.h>

#define MAGIC 'z'
#define GET_DATA _IOR(MAGIC, 1, int *)
#define SET_DATA _IOW(MAGIC, 2, int *)
#define GET_SIZE _IOR(MAGIC, 3, int *)

struct file_operations fops;
static char array[80] = "HelloWorld";
static int major;

int Mydevice_init_module(void)
{
printk("In init module");
major = register_chrdev(0,"Mydevice",&fops);
printk("\nThe device is registered by Major no: %d",major);
if(major == -1)
printk("\nError in registering the module");
else
printk("\n");
return 0;
}


void Mydevice_cleanup_module(void)
{
unregister_chrdev(major,"Mydevice");
printk("In cleanup module");
}


static int my_open(struct inode *inode, struct file *file)
{
printk("\nMydevice: open");
return 0;
}


static int my_release(struct inode *inode, struct file *file)
{
printk("\nMydevide: release");
return 0;
}

static ssize_t my_read(struct file *file, char *buff, size_t n,loff_t *offset)
{
int position = (long)*offset;
printk("\nMydevice: read");
copy_to_user(buff,array+position,n);
return 0;
}


static ssize_t my_write(struct file *file, const char *buff, size_t n, loff_t *offset)
{
int position = (long)*offset;
printk("\nMydevice: write");
copy_from_user(array+position,buff,n);
return 0;
}

static loff_t my_lseek(struct file *file,loff_t offset,int whence)
{
printk("\nMydevice: lseek");
switch(whence)
{
case 0: file->f_pos = offset; //SEEK_SET
break;
case 1: file->f_pos = (file->f_pos) + offset; //SEEK_CUR
break;
case 2: file->f_pos = sizeof(array) - offset; //SEEK_END
break;
}
return file->f_pos;
}


static int my_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case GET_DATA:
printk("\nMydevice: ioctl: GET_DATA");
copy_to_user((char *)arg, array, 80);
break;
case SET_DATA:
printk("\nMydevice: ioctl: SET_DATA");
copy_from_user(array, (char *)arg, 80);
break;
case GET_SIZE:
printk("\nMydevice: ioctl: GET_SIZE");
*(int *) arg = sizeof(array);
break;
}
return 0;
}


struct file_operations fops =
{
open: my_open,
release: my_release,
read: my_read,
write: my_write,
llseek: my_lseek,
ioctl: my_ioctl,
};


module_init(Mydevice_init_module);
module_exit(Mydevice_cleanup_module);
MODULE_LICENSE("GPL");


#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<sys/ioctl.h>
#include"myioctl.h"

int main(void)
{
int fd,size;

int result;

fd = open("mydevice",O_RDWR);
if(fd == -1)
{
printf("\nError in open");
return -1;
}

result = ioctl(fd, GET_SIZE, &size);
if(result == -1)
{
printf("\nError in ioctl");
return -1;
}
printf("\nThe result of GET_SIZE: %d",size);

printf("\n");
}



#define MAGIC 'z'
#define GET_DATA _IOR(MAGIC, 1, int *)
#define SET_DATA _IOW(MAGIC, 2, int *)
#define GET_SIZE _IOR(MAGIC, 3, int *)

Attachment: Makefile
Description: Binary data