c - Dealing with buf between user space and kernel -
i'm making simple device driver capable of receiving , sending characters using uart.
my read , write functions follows:
unsigned char uart_read(void){ unsigned int buf; while( ( ( inb(uart_lsr + uart) ) & uart_lsr_dr ) == 0 ){ schedule(); } buf = inb(uart); return (char)buf; } ssize_t serp_read(struct file *filep, char __user *buf, size_t count, loff_t *offp){ ssize_t cnt, ret; char *buffer; unsigned char data; int i; buffer = kmalloc(count * sizeof(char), gfp_kernel); printk("\nthis kernel, read called , count %zd\n", count); while(1){ buffer[i] = uart_read(); if(buffer[i] == '\n') break; i++; } buffer[strlen(buffer) - 1] = '\0'; if( (cnt = (copy_to_user(buf, buffer, strlen(buffer)))) != 0 ) printk("error in copy_to_user() cnt %d\n", cnt); ret = strlen(buffer); printk("\nthis kernel, read going away , buf %s\n", buf); return ret; } void uart_send(unsigned char data){ while( ( ( inb(uart_lsr + uart) ) & uart_lsr_thre ) == 0 ){ schedule(); } outb(data, (uart + uart_tx)); } ssize_t serp_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){ ssize_t cnt, ret; int i; char *buffer; buffer = kmalloc(count * sizeof(char), gfp_kernel); if( (cnt = (copy_from_user(buffer, buf, count))) != 0 ) printk("error in copy_from_user()\n"); buffer[count] = '\0'; for(i = 0; < strlen(buffer); i++){ uart_send(buffer[i]); } ret = strlen(buffer); return ret; }
and part of program i'm using test is:
char *str = "hello name is"; strcpy(buffer, str); printf("\nthe message [ %s ]\n", buffer); if ( (write(fd, buffer, strlen(buffer))) < 0) perror("error"); buffer[0] = '\0'; if ( (read(fd, buffer, sizeof(buffer))) < 0) perror("error"); //buffer[strlen(buffer)] = '\0'; printf("\nthe content of buffer after read() [ %s ]\n", buffer);
with have, have no issues writing "hello, name is" string, when read, let's "hey" uart, buf in read function appears "heylo, name is", , don't understand why overwrite happening. best guess right first write user space, kernel accesses, , read same user space, , ends overwriting what's there.
read
returns number of bytes read, , doesn't nul-terminate. further, line:
buffer[strlen(buffer)] = '\0';
does nothing, because strlen
of buffer offset of first '\0'
! try
ssize_t rb = read(fd, buffer, sizeof(buffer)); if ( rb < 0) perror("error"); else { buffer[rb] = '\0'; ...
re-reading serp_read
well, see broken use of strlen
everywhere. if don't have nul-terminated c string already, cannot use strlen
. looks nul!
ssize_t serp_read(struct file *filep, char __user *buf, size_t count, loff_t *offp) { ssize_t cnt, i; char *buffer; buffer = kmalloc(count, gfp_kernel); printk("\nthis kernel, read called , count %zd\n", count); /* while loop started uninitialized, * , didn't check overflow */ (i = 0; != count; ++i) { buffer[i] = uart_read(); if(buffer[i] == '\n') break; } /* incorrect because: * 1. strlen isn't useable unless buffer nul-terminated * 2. read(2) system call isn't expected nul-terminate buffers anyway buffer[strlen(buffer) - 1] = '\0'; */ /* use i+1 length if want include newline */ cnt = copy_to_user(buf, buffer, i); kfree(buffer); if(cnt) { printk("error in copy_to_user() cnt %d\n", cnt); -= cnt; /* bytes copied */ } printk("\nthis kernel, read going away , buf %.*s\n", i, buf); /* how print non-nul-terminated variable-length strings */ return i; /* nb. should return error above, printing */ }
Comments
Post a Comment