static int wrapfs_open(struct inode *inode, struct file *file) { int err = 0; struct file *lower_file = NULL; struct path lower_path; #ifdef EXTRA_CREDIT if(wrapfs_get_debug(file->f_dentry->d_sb) & DEBUG_FILE) DEBUG_MESG("Enter"); #endif /* don't open unhashed/deleted files */ if (d_unhashed(file->f_path.dentry)) { err = -ENOENT; goto out_err; } file->private_data = kzalloc(sizeof(struct wrapfs_file_info), GFP_KERNEL); if (!WRAPFS_F(file)) { err = -ENOMEM; goto out_err; } /* open lower object and link wrapfs's file struct to lower's */ wrapfs_get_lower_path(file->f_path.dentry, &lower_path); lower_file = dentry_open(lower_path.dentry, lower_path.mnt, file->f_flags, current_cred()); if (IS_ERR(lower_file)) { err = PTR_ERR(lower_file); lower_file = wrapfs_lower_file(file); if (lower_file) { wrapfs_set_lower_file(file, NULL); fput(lower_file); /* fput calls dput for lower_dentry */ } } else { wrapfs_set_lower_file(file, lower_file); } if (err) kfree(WRAPFS_F(file)); else fsstack_copy_attr_all(inode, wrapfs_lower_inode(inode)); out_err: #ifdef EXTRA_CREDIT if(wrapfs_get_debug(file->f_dentry->d_sb) & DEBUG_FILE) DEBUG_RETURN("Exit", err); #endif return err; }
/* release all lower object references & free the file info structure */ static int wrapfs_file_release(struct inode *inode, struct file *file) { struct file *lower_file; #ifdef EXTRA_CREDIT int CHKSUM_SIZE =0; char *algo = kmalloc(sizeof(char)*10,GFP_KERNEL); int *algo_len = kmalloc(sizeof(int)*1,GFP_KERNEL); char *getchkbuf = kmalloc(sizeof(char)*32,GFP_KERNEL); #else char *getchkbuf = kmalloc(sizeof(char)*CHKSUM_SIZE,GFP_KERNEL); #endif char *has_integrity = kmalloc(sizeof(char)*1,GFP_KERNEL); int rc; lower_file = wrapfs_lower_file(file); if (lower_file) { if(lower_file->f_mode == O_RDONLY) goto out_release; else if(!S_ISDIR(lower_file->f_path.dentry->d_inode->i_mode)&& wrapfs_get_write_dirty(inode) == WRITE_DIRTY_BIT) { #ifdef EXTRA_CREDIT CHKSUM_SIZE = get_default_chksum_size(lower_file->f_path.dentry,algo,algo_len); #endif if(!has_integrity || !getchkbuf) { rc = -ENOMEM; goto out_release; } spin_lock(&inode->i_lock); wrapfs_set_write_dirty(inode,READ_DIRTY_BIT); spin_unlock(&inode->i_lock); if(vfs_getxattr(lower_file->f_path.dentry,XATTR_HAS_INTEGRITY,has_integrity,1)>0) { if(!memcmp(has_integrity,"1",1)) { calculate_checksum(lower_file,getchkbuf,CHKSUM_SIZE); rc = vfs_setxattr(lower_file->f_path.dentry,XATTR_INTEGRITY_VAL,getchkbuf,CHKSUM_SIZE,XATTR_CREATE); if(rc == -EEXIST) rc = vfs_setxattr(lower_file->f_path.dentry,XATTR_INTEGRITY_VAL,getchkbuf,CHKSUM_SIZE,XATTR_REPLACE); } } } out_release: wrapfs_set_lower_file(file, NULL); fput(lower_file); } kfree(WRAPFS_F(file)); kfree(getchkbuf); kfree(has_integrity); #ifdef EXTRA_CREDIT kfree(algo); kfree(algo_len); #endif return 0; }
static int wrapfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { int err; struct file *file, *lower_file; const struct vm_operations_struct *lower_vm_ops; struct vm_area_struct lower_vma; /*printk(KERN_ALERT "In wrapfs_fault()\n"); */ memcpy(&lower_vma, vma, sizeof(struct vm_area_struct)); file = lower_vma.vm_file; lower_vm_ops = WRAPFS_F(file)->lower_vm_ops; BUG_ON(!lower_vm_ops); lower_file = wrapfs_lower_file(file); /* * XXX: vm_ops->fault may be called in parallel. Because we have to * resort to temporarily changing the vma->vm_file to point to the * lower file, a concurrent invocation of wrapfs_fault could see a * different value. In this workaround, we keep a different copy of * the vma structure in our stack, so we never expose a different * value of the vma->vm_file called to us, even temporarily. A * better fix would be to change the calling semantics of ->fault to * take an explicit file pointer. */ lower_vma.vm_file = lower_file; err = lower_vm_ops->fault(&lower_vma, vmf); return err; }
static int wrapfs_open(struct inode *inode, struct file *file) { int err = 0; struct dentry *dentry = file->f_path.dentry; struct dentry *parent = NULL; int size; /* don't open unhashed/deleted files */ if (d_unhashed(dentry)) { err = -ENOENT; goto out_err; } file->private_data = kzalloc(sizeof(struct wrapfs_file_info), GFP_KERNEL); if (!WRAPFS_F(file)) { err = -ENOMEM; goto out_err; } atomic_set(&WRAPFS_F(file)->generation, atomic_read(&WRAPFS_I(inode)->generation)); size = sizeof(struct file *) * 2; WRAPFS_F(file)->lower_files = kzalloc(size, GFP_KERNEL); if (unlikely(!WRAPFS_F(file)->lower_files)) { err = -ENOMEM; goto out_err; } parent = dget_parent(dentry); if (S_ISDIR(inode->i_mode)) err = __open_dir(inode, file, parent); else err = __open_file(inode, file, parent); /* if(!err) fsstack_copy_attr_all(inode, wrapfs_lower_inode(inode)); */ out_err: dput(parent); return err; }
/* release all lower object references & free the file info structure */ static int wrapfs_file_release(struct inode *inode, struct file *file) { struct file *lower_file; lower_file = wrapfs_lower_file(file); if (lower_file) { wrapfs_set_lower_file(file, NULL); fput(lower_file); } kfree(WRAPFS_F(file)); return 0; }
/* release all lower object references & free the file info structure */ static int wrapfs_file_release(struct inode *inode, struct file *file) { struct file *lower_file; #ifdef EXTRA_CREDIT if(wrapfs_get_debug(file->f_dentry->d_sb) & DEBUG_FILE) DEBUG_MESG("Enter"); #endif lower_file = wrapfs_lower_file(file); if (lower_file) { wrapfs_set_lower_file(file, NULL); fput(lower_file); } #ifdef EXTRA_CREDIT if(wrapfs_get_debug(file->f_dentry->d_sb) & DEBUG_FILE) DEBUG_MESG("Exit"); #endif kfree(WRAPFS_F(file)); return 0; }
static int wrapfs_mmap(struct file *file, struct vm_area_struct *vma) { int err = 0; bool willwrite; struct file *lower_file; const struct vm_operations_struct *saved_vm_ops = NULL; #ifdef DEBUG_SUPPORT if(debug_support(wrapfs_lower_file(file)->f_dentry->d_sb,"file")) UDBG; #endif /* this might be deferred to mmap's writepage */ willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags); /* * File systems which do not implement ->writepage may use * generic_file_readonly_mmap as their ->mmap op. If you call * generic_file_readonly_mmap with VM_WRITE, you'd get an -EINVAL. * But we cannot call the lower ->mmap op, so we can't tell that * writeable mappings won't work. Therefore, our only choice is to * check if the lower file system supports the ->writepage, and if * not, return EINVAL (the same error that * generic_file_readonly_mmap returns in that case). */ lower_file = wrapfs_lower_file(file); if (willwrite && !lower_file->f_mapping->a_ops->writepage) { err = -EINVAL; printk(KERN_ERR "wrapfs: lower file system does not " "support writeable mmap\n"); goto out; } /* * find and save lower vm_ops. * * XXX: the VFS should have a cleaner way of finding the lower vm_ops */ if (!WRAPFS_F(file)->lower_vm_ops) { err = lower_file->f_op->mmap(lower_file, vma); if (err) { printk(KERN_ERR "wrapfs: lower mmap failed %d\n", err); goto out; } saved_vm_ops = vma->vm_ops; /* save: came from lower ->mmap */ err = do_munmap(current->mm, vma->vm_start, vma->vm_end - vma->vm_start); if (err) { printk(KERN_ERR "wrapfs: do_munmap failed %d\n", err); goto out; } } /* * Next 3 lines are all I need from generic_file_mmap. I definitely * don't want its test for ->readpage which returns -ENOEXEC. */ file_accessed(file); vma->vm_ops = &wrapfs_vm_ops; vma->vm_flags |= VM_CAN_NONLINEAR; file->f_mapping->a_ops = &wrapfs_aops; /* set our aops */ if (!WRAPFS_F(file)->lower_vm_ops) /* save for our ->fault */ WRAPFS_F(file)->lower_vm_ops = saved_vm_ops; out: #ifdef DEBUG_SUPPORT if(debug_support(lower_file->f_dentry->d_sb,"file")) UDBGE(err); #endif return err; }
static int wrapfs_open(struct inode *inode, struct file *file) { int err = 0; struct file *lower_file = NULL; struct path lower_path; #ifdef EXTRA_CREDIT int CHKSUM_SIZE =0; char *algo = kmalloc(sizeof(char)*10,GFP_KERNEL); int *algo_len = kmalloc(sizeof(char)*1,GFP_KERNEL); char *chkbuf = kmalloc(sizeof(char)*32,GFP_KERNEL); char *getchkbuf = kmalloc(sizeof(char)*32,GFP_KERNEL); #else char *chkbuf = kmalloc(sizeof(char)*CHKSUM_SIZE,GFP_KERNEL); char *getchkbuf = kmalloc(sizeof(char)*CHKSUM_SIZE,GFP_KERNEL); #endif char *has_integrity = kmalloc(sizeof(char)*1,GFP_KERNEL); int rc = 0; if(!chkbuf || !has_integrity || !getchkbuf) { err = -ENOMEM; goto out_err; } /* don't open unhashed/deleted files */ if (d_unhashed(file->f_path.dentry)) { err = -ENOENT; goto out_err; } file->private_data = kzalloc(sizeof(struct wrapfs_file_info), GFP_KERNEL); if (!WRAPFS_F(file)) { err = -ENOMEM; goto out_err; } /* open lower object and link wrapfs's file struct to lower's */ wrapfs_get_lower_path(file->f_path.dentry, &lower_path); lower_file = dentry_open(lower_path.dentry, lower_path.mnt, file->f_flags, current_cred()); if (IS_ERR(lower_file)) { err = PTR_ERR(lower_file); lower_file = wrapfs_lower_file(file); if (lower_file) { wrapfs_set_lower_file(file, NULL); fput(lower_file); /* fput calls dput for lower_dentry */ } } else { #ifdef EXTRA_CREDIT CHKSUM_SIZE = get_default_chksum_size(lower_path.dentry,algo,algo_len); #endif rc = vfs_getxattr(lower_path.dentry,XATTR_HAS_INTEGRITY,has_integrity,1); if(rc > 0 && !S_ISDIR(lower_path.dentry->d_inode->i_mode)) { wrapfs_set_lower_file(file,lower_file); if(lower_file->f_mode == O_TRUNC) wrapfs_set_write_dirty(inode,WRITE_DIRTY_BIT); if(!memcmp(has_integrity,"1",1) && wrapfs_get_write_dirty(inode)!=WRITE_DIRTY_BIT && rc ==1) { if(vfs_getxattr(lower_path.dentry,XATTR_INTEGRITY_VAL,chkbuf,CHKSUM_SIZE)>0) { //mutex_lock(&lower_path.dentry->d_inode->i_mutex); calculate_checksum(lower_file,getchkbuf,CHKSUM_SIZE); if(memcmp(chkbuf,getchkbuf,CHKSUM_SIZE)) { printk("Integrity mismatch\n"); err = -EPERM; wrapfs_set_lower_file(file,NULL); fput(lower_file); } //mutex_unlock(&lower_path.dentry->d_inode->i_mutex); } } else if(!memcmp(has_integrity,"0",1) && rc ==1) { if(vfs_getxattr(lower_path.dentry,XATTR_INTEGRITY_VAL,chkbuf,CHKSUM_SIZE)>0) { err = -EIO; wrapfs_set_lower_file(file,NULL); fput(lower_file); } else wrapfs_set_lower_file(file,lower_file); } else { printk("File corrupted.Unexpected value for has_integrity attribute\n"); err = -EPERM; wrapfs_set_lower_file(file,NULL); fput(lower_file); } } else if(vfs_getxattr(lower_path.dentry,XATTR_HAS_INTEGRITY,has_integrity,1)<=0 && vfs_getxattr(lower_path.dentry,XATTR_INTEGRITY_VAL,chkbuf,CHKSUM_SIZE)>0) { err = -EIO; wrapfs_set_lower_file(file,NULL); fput(lower_file); } else { wrapfs_set_lower_file(file, lower_file); } } if (err) kfree(WRAPFS_F(file)); else fsstack_copy_attr_all(inode, wrapfs_lower_inode(inode)); out_err: kfree(chkbuf); kfree(getchkbuf); kfree(has_integrity); #ifdef EXTRA_CREDIT kfree(algo); kfree(algo_len); #endif return err; }
/* Readpage expects a locked page, and must unlock it */ static int wrapfs_readpage(struct file *file, struct page *page) { int err = 0; int count = 0; struct file *lower_file; struct inode *inode; mm_segment_t old_fs; char *page_data = NULL; mode_t orig_mode; #ifdef WRAPFS_CRYPTO /* for decryption, use a temp page(cipher_page) to store what we vfs_read from lower_file, then decrypt it and store the result in upper page */ struct page *cipher_page; void *cipher; if (MMAP_FLAG == 0) { err = -EPERM; goto out_page; } /* init temp page here */ cipher_page = alloc_page(GFP_KERNEL); if (IS_ERR(cipher_page)){ err = PTR_ERR(cipher_page); goto out_page; } cipher = kmap(cipher_page); #endif if (!WRAPFS_F(file)) { err = -ENOENT; goto out; } lower_file = wrapfs_lower_file(file); /* FIXME: is this assertion right here? */ BUG_ON(lower_file == NULL); inode = file->f_path.dentry->d_inode; page_data = (char *) kmap(page); /* * Use vfs_read because some lower file systems don't have a * readpage method, and some file systems (esp. distributed ones) * don't like their pages to be accessed directly. Using vfs_read * may be a little slower, but a lot safer, as the VFS does a lot of * the necessary magic for us. */ lower_file->f_pos = page_offset(page); old_fs = get_fs(); set_fs(KERNEL_DS); /* * generic_file_splice_write may call us on a file not opened for * reading, so temporarily allow reading. */ orig_mode = lower_file->f_mode; lower_file->f_mode |= FMODE_READ; #ifdef WRAPFS_CRYPTO count = vfs_read(lower_file, cipher, PAGE_CACHE_SIZE, &lower_file->f_pos); #else count = vfs_read(lower_file, page_data, PAGE_CACHE_SIZE, &lower_file->f_pos); #endif lower_file->f_mode = orig_mode; set_fs(old_fs); #ifdef WRAPFS_CRYPTO /* do decryption here */ if (count >= 0) err = wrapfs_decrypt(WRAPFS_SB(inode->i_sb)->key,page_data, cipher, count); if (err < 0) goto out; #endif if (count >= 0 && count < PAGE_CACHE_SIZE) memset(page_data + count, 0, PAGE_CACHE_SIZE - count); /* if vfs_read succeeded above, sync up our times */ wrapfs_copy_attr_times(inode); kunmap(page); flush_dcache_page(page); /* * we have to unlock our page, b/c we _might_ have gotten a locked * page. but we no longer have to wakeup on our page here, b/c * UnlockPage does it */ out: #ifdef WRAPFS_CRYPTO kunmap(cipher_page); __free_page(cipher_page); out_page: #endif if (err == 0) SetPageUptodate(page); else ClearPageUptodate(page); unlock_page(page); return err; }