Some programming 101 feedback below:
On Thu, Sep 23, 2010 at 12:47 PM, Bond <[email protected]> wrote:
> I wrote a small hello world type of character device driver.
> When I type echo -n "abcdef" > /dev/bond
> and do a cat /dev/bond
> then only last "f" of above input abcdef is displayed rest nothing is
> displayed.
> I asked this question earlier and some people suggested me some
> modifications
> I have done and experimented all that but I am unable to catch the error.
> Can some one point out the error?
> Here is the code
>
> /* Necessary includes for device drivers */
> #include <linux/init.h>
> //#include <linux/config.h>
> #include <linux/module.h>
> #include <linux/kernel.h> /* printk() */
> #include <linux/slab.h> /* kmalloc() */
> #include <linux/fs.h> /* everything... */
> #include <linux/errno.h> /* error codes */
> #include <linux/types.h> /* size_t */
> #include <linux/proc_fs.h>
> #include <linux/fcntl.h> /* O_ACCMODE */
> #include <asm/system.h> /* cli(), *_flags */
> #include <asm/uaccess.h> /* copy_from/to_user */
> MODULE_LICENSE("Dual BSD/GPL");
> /* Declaration of memory.c functions */
> int memory_open(struct inode *inode, struct file *filp);
> int memory_release(struct inode *inode, struct file *filp);
> ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t
> *f_pos);
> ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t
> *f_pos);
> void memory_exit(void);
> int memory_init(void);
> /* Structure that declares the usual file */
> /* access functions */
> struct file_operations memory_fops = {
> read: memory_read,
> write: memory_write,
> open: memory_open,
> release: memory_release
> };
> /* Declaration of the init and exit functions */
> module_init(memory_init);
> module_exit(memory_exit);
> /* Global variables of the driver */
> /* Major number */
> int memory_major = 60;
> /* Buffer to store data */
> char *memory_buffer;
> int memory_init(void) {
> int result;
> /* Registering device */
> result = register_chrdev(memory_major, "bond", &memory_fops);
> if (result < 0) {
> printk(KERN_ALERT "memory: cannot obtain major number %d\n",
> memory_major);
> return result;
> }
> /* Allocating memory for the buffer */
> memory_buffer = kmalloc(1, GFP_KERNEL);
1 is the number of bytes your allocating, it needs to be your max
buffer length. So are by design writing a buffer overflow the way you
have it. That is one of the typical security failures that can allow
a major breach.
Change it to:
#define MY_BUFFER_SIZE
memory_buffer = kmalloc(MY_BUFFER_SIZE, GFP_KERNEL);
> if (!memory_buffer) {
> result = -ENOMEM;
> goto fail;
> }
> memset(memory_buffer, 0, 10);
Never hard code a length. At least use a define. This becomes
memset(memory_buffer, 0, MY_BUFFER_SIZE);
> printk(KERN_ALERT "Inserting bond module\n");
> return 0;
> fail:
> memory_exit();
> return result;
> }
>
> void memory_exit(void) {
> /* Freeing the major number */
> unregister_chrdev(memory_major, "bond");
> /* Freeing buffer memory */
> if (memory_buffer) {
> kfree(memory_buffer);
> }
> printk( KERN_ALERT "Removing bond module\n");
> }
>
> int memory_open(struct inode *inode, struct file *filp) {
> /* Success */
> return 0;
> }
>
> int memory_release(struct inode *inode, struct file *filp) {
>
> /* Success */
> return 0;
> }
>
> ssize_t memory_read(struct file *filp, char *buf,
> size_t count, loff_t *f_pos) {
>
> /* Transfering data to user space */
> copy_to_user(buf,memory_buffer,10);
again, don't have 10 hardcoded, but the read should actually work as
is except if the userspace buffer is too small, then your going to
overflow it with untold damage.
You need:
copy_to_user(buf,memory_buffer,min(count, MY_BUFFER_SIZE));
> /* Changing reading position as best suits */
> if (*f_pos == 0) {
> *f_pos+=1;
> return 1;
> } else {
> return 0;
> }
Since you don't use f_pos, I have no idea why you're don this. Future
plans I assume. While troubleshooting I'm surprised you didn't
comment this out.
I would often just wrap it in a #ifdef until you get the basics working.
> }
> ssize_t memory_write( struct file *filp, char *buf,
> size_t count, loff_t *f_pos) {
> char *tmp;
> tmp=buf+count-1;
tmp now points at the last char in buf. Clearly not what you want.
I can't even think of a logical explanation for what you're trying to
do. I'd just delete tmp and its assignment. Those 2 lines offer no
value I see.
> copy_from_user(memory_buffer,tmp,10);
Try this instead
copy_from_user(memory_buffer, buf, min(count, MY_BUFFER_SIZE));
> return 1;
> }
It looks like you're just randomly cutting and pasting code from
various places and have no idea what it really does.
I'm putting you in my autodelete list, so I won't be responding to you again.
Greg
--
To unsubscribe from this list: send an email with
"unsubscribe kernelnewbies" to [email protected]
Please read the FAQ at http://kernelnewbies.org/FAQ