On Wed, Aug 20, 2008 at 11:05 AM, Sachin Gaikwad <[EMAIL PROTECTED]>wrote:

> Hi Prasad,
>
> On Wed, Aug 6, 2008 at 6:50 PM, Prasad Joshi <[EMAIL PROTECTED]>
> wrote:
> > Hi All,
> >
> > I want to encrypt the data before it is written to the disk and decrypt
> is
> > after it is being read from the disk. so copied the ext2 source code in
> my
> > directory.
> >
> > Then modified the ext2 file_operations structure to invoke my read and
> write
> > functions instead of do_sync_read/write
> >
> > const struct file_operations ext2_file_operations = {
> >     .llseek     = generic_file_llseek,
> >     .read       = my_read,                   /* do_sync_read  */
> > <<<<<<<<<<<<<<<<<<<<<<<<
> >     .write      = my_write,                  /* do_sync_write */
> > <<<<<<<<<<<<<<<<<<<<<<<<
> >     .aio_read   = generic_file_aio_read,
> >     .aio_write  = generic_file_aio_write,
> >     .unlocked_ioctl = ext2_ioctl,
> > #ifdef CONFIG_COMPAT
> >     .compat_ioctl   = ext2_compat_ioctl,
> > #endif
> >     .mmap       = generic_file_mmap,
> >     .open       = generic_file_open,
> >     .release    = ext2_release_file,
> >     .fsync      = ext2_sync_file,
> >     .splice_read    = generic_file_splice_read,
> >     .splice_write   = generic_file_splice_write,
> > };
> >
> >
> > For time being i used simplest encryption XOR 5
> > int encrypt_data(char *data, size_t len)
> > {
> >     int i;
> >     for(i=0; i < len; i++)
> >         data[i] ^= 5;
> >
> >     return 0;
> > }
> >
> > int decrypt_data(char *data, size_t len)
> > {
> >     int i;
> >     for(i=0; i < len; i++)
> >         data[i] ^= 5;
> >
> >     return 0;
> > }
> >
> > ssize_t my_read(struct file *filp, char __user *buf, size_t len, loff_t
> > *ppos)
> > {
> >     size_t ret;
> >     char *data = kmalloc(sizeof(char)*len, GFP_KERNEL);
> >
> >     ret = do_sync_read(filp, data, len, ppos);
> >     decrypt_data(data, len);
> >     copy_to_user(buf, data, len);
> >
> >     kfree(data);
> >     return ret;
> > }
> >
> > In write I am supposed to encrypt the data before it is written to the
> disk,
> > ie encrypt the data before it is passed to the do_sync_write.
> > But, the data is in the buf which is passed from the user process and has
> > the type             const char *buf       so      I can't modify the
> > buf
> >
> > I thought of  copying data from the      (userland)   buf     to some
> > variable in the kernelspace and then encrypt it and pass to
> do_sync_write()
> >
> > This is what I did
> >
> > ssize_t my_write(struct file *filp, const char __user *buf, size_t len,
> > loff_t *ppos)
> > {
> >     size_t ret;
> >     char *data = kmalloc(sizeof(char)*len, GFP_KERNEL);
> >
> >     copy_from_user(data, buf, len);
> >     encrypt_data(data, len);
> >     ret = do_sync_write(filp, data, len, ppos);
> >
> >     kfree(data);
> >     return ret;
> > }
> >
> > After running the code and writing data to the file using echo "test" >
> > /mnt_pt/file    I am getting bad address error
> >
> > Is it because do_sync_write() also expects buf pointer from the
> userspace?
> > ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t
> len,
> > loff_t *ppos)
>
> You are right. Thats exactly the reason for this.
>
> >
> > But, the only thing do_sync_write should be concerned with whether it can
> > access the data pointer or not. So, if the data pointer is valid and
> kernel
> > is able to access the location why so worry about userspace pointer?
>
> These are internl kernel functions(do_sync_read/write) and they expect
> __user user space pointer. Often it has been said that __user is just
> a documentation thing so that programmer is careful about copying it
> to kernel space. And same is done when you pass such user space
> pointer to these functions. For this case :
>
> do_sync_read  -----> filp->f_op->aio_read -----> generic_file_aio_read
> -----> generic_segment_checks ------> access_ok ------> __range_not_ok
>
> If you closing look at __range_not_ok macro, it is checking is address
> is with reach of current thread's segment limit (I am not good at
> reading assembly code), which is not the case in your code as it is a
> kernel pointer. Hence it says "bad address".
>
> What you can do ?
>
> ssize_t my_write(struct file *filp, const char __user *buf, size_t len,
>   loff_t *ppos)
> {
>     size_t ret;
>      mm_segment_t oldfs;
>      char *data = kmalloc(sizeof(char)*len, GFP_KERNEL);
>
>     copy_from_user(data, buf, len);
>     encrypt_data(data, len);
>
>      oldfs = get_fs();      /* Read comments in
> include/asm-x86/uaccess_64.h */
>     set_fs (KERNEL_DS);
>      ret = do_sync_write(filp, data, len, ppos);
>      set_fs(oldfs);
>

Thanks Sachin, this worked correctly.
As you said, with set_fs(KERNEL_DS) we are changing the address limit of the
process to 0-4G, which was previously 0-3G (USER_DS for user space). So, it
is very important to reset the current thread segment type to whatever it
was.

But, what if I failed/forgot to restore th.e segment type to USER_DS. So,
now the process is now capable of accessing whole 4G address space.
What does the extra capability a process will have if it has access to whole
4G address space, instead of 0-3G?
How does this harm my system?

someone please explain.......

Thanks and Regards,
Prasad.


>     kfree(data);
>     return ret;
>  }
>
> I wonder why you got that error for just write and not read. You are
> passing kernel pointer to do_sync_read also.
>
> Hope this helps,
> Sachin
>
>
> >
> > Thanks and Regards,
> > Prasad
> >
>

Reply via email to