/** * ecryptfs_miscdev_write - handle write to daemon miscdev handle * @file: File for misc dev handle (ignored) * @buf: Buffer containing user data * @count: Amount of data in @buf * @ppos: Pointer to offset in file (ignored) * * miscdevfs packet format: * Octet 0: Type * Octets 1-4: network byte order msg_ctx->counter (0's for non-response) * Octets 5-N0: Size of struct ecryptfs_message to follow * Octets N0-N1: struct ecryptfs_message (including data) * * Returns the number of bytes read from @buf */ static ssize_t ecryptfs_miscdev_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { __be32 counter_nbo; u32 seq; size_t packet_size, packet_size_length, i; ssize_t sz = 0; char *data; int rc; if (count == 0) goto out; data = kmalloc(count, GFP_KERNEL); if (!data) { printk(KERN_ERR "%s: Out of memory whilst attempting to " "kmalloc([%Zd], GFP_KERNEL)\n", __func__, count); goto out; } rc = copy_from_user(data, buf, count); if (rc) { printk(KERN_ERR "%s: copy_from_user returned error [%d]\n", __func__, rc); goto out_free; } sz = count; i = 0; switch (data[i++]) { case ECRYPTFS_MSG_RESPONSE: if (count < (1 + 4 + 1 + sizeof(struct ecryptfs_message))) { printk(KERN_WARNING "%s: Minimum acceptable packet " "size is [%Zd], but amount of data written is " "only [%Zd]. Discarding response packet.\n", __func__, (1 + 4 + 1 + sizeof(struct ecryptfs_message)), count); goto out_free; } memcpy(&counter_nbo, &data[i], 4); seq = be32_to_cpu(counter_nbo); i += 4; rc = ecryptfs_parse_packet_length(&data[i], &packet_size, &packet_size_length); if (rc) { printk(KERN_WARNING "%s: Error parsing packet length; " "rc = [%d]\n", __func__, rc); goto out_free; } i += packet_size_length; if ((1 + 4 + packet_size_length + packet_size) != count) { printk(KERN_WARNING "%s: (1 + packet_size_length([%Zd])" " + packet_size([%Zd]))([%Zd]) != " "count([%Zd]). Invalid packet format.\n", __func__, packet_size_length, packet_size, (1 + packet_size_length + packet_size), count); goto out_free; } rc = ecryptfs_miscdev_response(&data[i], packet_size, current->euid, current->nsproxy->user_ns, task_pid(current), seq); if (rc) printk(KERN_WARNING "%s: Failed to deliver miscdev " "response to requesting operation; rc = [%d]\n", __func__, rc); break; case ECRYPTFS_MSG_HELO: rc = ecryptfs_miscdev_helo(current->euid, current->nsproxy->user_ns, task_pid(current)); if (rc) { printk(KERN_ERR "%s: Error attempting to process " "helo from pid [0x%p]; rc = [%d]\n", __func__, task_pid(current), rc); goto out_free; } break; case ECRYPTFS_MSG_QUIT: rc = ecryptfs_miscdev_quit(current->euid, current->nsproxy->user_ns, task_pid(current)); if (rc) { printk(KERN_ERR "%s: Error attempting to process " "quit from pid [0x%p]; rc = [%d]\n", __func__, task_pid(current), rc); goto out_free; } break; default: ecryptfs_printk(KERN_WARNING, "Dropping miscdev " "message of unrecognized type [%d]\n", data[0]); break; } out_free: kfree(data); out: return sz; }
/** * ecryptfs_readdir * @file: The eCryptfs directory file * @ctx: The actor to feed the entries to */ static int ecryptfs_readdir(struct file *file, struct dir_context *ctx) { int rc; struct file *lower_file; struct inode *inode = file_inode(file); struct ecryptfs_getdents_callback buf = { .ctx.actor = ecryptfs_filldir, .caller = ctx, .sb = inode->i_sb, }; lower_file = ecryptfs_file_to_lower(file); lower_file->f_pos = ctx->pos; rc = iterate_dir(lower_file, &buf.ctx); ctx->pos = buf.ctx.pos; if (rc < 0) goto out; if (buf.filldir_called && !buf.entries_written) goto out; if (rc >= 0) fsstack_copy_attr_atime(inode, file_inode(lower_file)); out: return rc; } struct kmem_cache *ecryptfs_file_info_cache; static int read_or_initialize_metadata(struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct ecryptfs_crypt_stat *crypt_stat; int rc; crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mount_crypt_stat = &ecryptfs_superblock_to_private( inode->i_sb)->mount_crypt_stat; mutex_lock(&crypt_stat->cs_mutex); if (crypt_stat->flags & ECRYPTFS_POLICY_APPLIED && crypt_stat->flags & ECRYPTFS_KEY_VALID) { rc = 0; goto out; } rc = ecryptfs_read_metadata(dentry); if (!rc) goto out; if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED) { crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED | ECRYPTFS_ENCRYPTED); rc = 0; goto out; } if (!(mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) && !i_size_read(ecryptfs_inode_to_lower(inode))) { rc = ecryptfs_initialize_file(dentry, inode); if (!rc) goto out; } rc = -EIO; out: mutex_unlock(&crypt_stat->cs_mutex); return rc; } /** * ecryptfs_open * @inode: inode speciying file to open * @file: Structure to return filled in * * Opens the file specified by inode. * * Returns zero on success; non-zero otherwise */ static int ecryptfs_open(struct inode *inode, struct file *file) { int rc = 0; struct ecryptfs_crypt_stat *crypt_stat = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct dentry *ecryptfs_dentry = file->f_path.dentry; /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ struct ecryptfs_file_info *file_info; mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; if ((mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) && ((file->f_flags & O_WRONLY) || (file->f_flags & O_RDWR) || (file->f_flags & O_CREAT) || (file->f_flags & O_TRUNC) || (file->f_flags & O_APPEND))) { printk(KERN_WARNING "Mount has encrypted view enabled; " "files may only be read\n"); rc = -EPERM; goto out; } /* Released in ecryptfs_release or end of function if failure */ file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); if (!file_info) { ecryptfs_printk(KERN_ERR, "Error attempting to allocate memory\n"); rc = -ENOMEM; goto out; } crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mutex_lock(&crypt_stat->cs_mutex); if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) { ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); /* Policy code enabled in future release */ crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED | ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); rc = ecryptfs_get_lower_file(ecryptfs_dentry, inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out_free; } if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) { rc = -EPERM; printk(KERN_WARNING "%s: Lower file is RO; eCryptfs " "file must hence be opened RO\n", __func__); goto out_put; } ecryptfs_set_file_lower( file, ecryptfs_inode_to_private(inode)->lower_file); if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); mutex_lock(&crypt_stat->cs_mutex); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); rc = 0; goto out; } rc = read_or_initialize_metadata(ecryptfs_dentry); if (rc) goto out_put; ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = " "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, (unsigned long long)i_size_read(inode)); goto out; out_put: ecryptfs_put_lower_file(inode); out_free: kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); out: return rc; }
/** * ecryptfs_lookup * @ecryptfs_dir_inode: The eCryptfs directory inode * @ecryptfs_dentry: The eCryptfs dentry that we are looking up * @ecryptfs_nd: nameidata; may be NULL * * Find a file on disk. If the file does not exist, then we'll add it to the * dentry cache and continue on to read it from the disk. */ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, struct dentry *ecryptfs_dentry, unsigned int flags) { char *encrypted_and_encoded_name = NULL; size_t encrypted_and_encoded_name_size; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; struct dentry *lower_dir_dentry, *lower_dentry; int rc = 0; lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); mutex_lock(&lower_dir_dentry->d_inode->i_mutex); lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name, lower_dir_dentry, ecryptfs_dentry->d_name.len); mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " "[%d] on lower_dentry = [%s]\n", __func__, rc, ecryptfs_dentry->d_name.name); goto out; } if (lower_dentry->d_inode) goto interpose; mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; if (!(mount_crypt_stat && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES))) goto interpose; dput(lower_dentry); rc = ecryptfs_encrypt_and_encode_filename( &encrypted_and_encoded_name, &encrypted_and_encoded_name_size, NULL, mount_crypt_stat, ecryptfs_dentry->d_name.name, ecryptfs_dentry->d_name.len); if (rc) { printk(KERN_ERR "%s: Error attempting to encrypt and encode " "filename; rc = [%d]\n", __func__, rc); goto out; } mutex_lock(&lower_dir_dentry->d_inode->i_mutex); #ifdef CONFIG_SDP if(!strncmp(lower_dir_dentry->d_sb->s_type->name, "sdcardfs", 8)) { struct sdcardfs_dentry_info *dinfo = SDCARDFS_D(lower_dir_dentry); int len = strlen(ecryptfs_dentry->d_name.name); int i, numeric = 1; dinfo->under_knox = 1; dinfo->userid = -1; if(IS_UNDER_ROOT(ecryptfs_dentry)) { for(i=0 ; i < len ; i++) if(!isdigit(ecryptfs_dentry->d_name.name[i])) { numeric = 0; break; } if(numeric) { dinfo->userid = simple_strtoul(ecryptfs_dentry->d_name.name, NULL, 10); } } } #endif lower_dentry = lookup_one_len(encrypted_and_encoded_name, lower_dir_dentry, encrypted_and_encoded_name_size); #ifdef CONFIG_SDP if(!strncmp(lower_dir_dentry->d_sb->s_type->name, "sdcardfs", 8)) { struct sdcardfs_dentry_info *dinfo = SDCARDFS_D(lower_dir_dentry); dinfo->under_knox = 0; dinfo->userid = -1; } #endif mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " "[%d] on lower_dentry = [%s]\n", __func__, rc, encrypted_and_encoded_name); goto out; } interpose: rc = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry, ecryptfs_dir_inode); out: kfree(encrypted_and_encoded_name); return ERR_PTR(rc); }
/** * ecryptfs_open * @inode: inode speciying file to open * @file: Structure to return filled in * * Opens the file specified by inode. * * Returns zero on success; non-zero otherwise */ static int ecryptfs_open(struct inode *inode, struct file *file) { int rc = 0; struct ecryptfs_crypt_stat *crypt_stat = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct dentry *ecryptfs_dentry = file->f_path.dentry; /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ struct dentry *lower_dentry; struct ecryptfs_file_info *file_info; mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; if ((mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) && ((file->f_flags & O_WRONLY) || (file->f_flags & O_RDWR) || (file->f_flags & O_CREAT) || (file->f_flags & O_TRUNC) || (file->f_flags & O_APPEND))) { printk(KERN_WARNING "Mount has encrypted view enabled; " "files may only be read\n"); rc = -EPERM; goto out; } /* Released in ecryptfs_release or end of function if failure */ file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); if (!file_info) { ecryptfs_printk(KERN_ERR, "Error attempting to allocate memory\n"); rc = -ENOMEM; goto out; } lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mutex_lock(&crypt_stat->cs_mutex); if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) { ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); /* Policy code enabled in future release */ crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED | ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); rc = ecryptfs_get_lower_file(ecryptfs_dentry, inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out_free; } if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) { rc = -EPERM; printk(KERN_WARNING "%s: Lower file is RO; eCryptfs " "file must hence be opened RO\n", __func__); goto out_put; } ecryptfs_set_file_lower( file, ecryptfs_inode_to_private(inode)->lower_file); if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); mutex_lock(&crypt_stat->cs_mutex); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); rc = 0; goto out; } #ifdef CONFIG_WTL_ENCRYPTION_FILTER if (crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED && crypt_stat->flags & ECRYPTFS_POLICY_APPLIED && crypt_stat->flags & ECRYPTFS_ENCRYPTED && !(crypt_stat->flags & ECRYPTFS_KEY_VALID) && !(crypt_stat->flags & ECRYPTFS_KEY_SET) && crypt_stat->flags & ECRYPTFS_I_SIZE_INITIALIZED) { crypt_stat->flags |= ECRYPTFS_ENCRYPTED_OTHER_DEVICE; } mutex_lock(&crypt_stat->cs_mutex); if ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_NEW_PASSTHROUGH) && (crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { if (ecryptfs_read_metadata(ecryptfs_dentry)) { crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED | ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); goto out; } } else if ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_FILTERING) && (crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { struct dentry *fp_dentry = ecryptfs_inode_to_private(inode)->lower_file->f_dentry; char filename[NAME_MAX+1] = {0}; if (fp_dentry->d_name.len <= NAME_MAX) memcpy(filename, fp_dentry->d_name.name, fp_dentry->d_name.len + 1); if (is_file_name_match(mount_crypt_stat, fp_dentry) || is_file_ext_match(mount_crypt_stat, filename)) { if (ecryptfs_read_metadata(ecryptfs_dentry)) crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED | ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); goto out; } } mutex_unlock(&crypt_stat->cs_mutex); #endif mutex_lock(&crypt_stat->cs_mutex); if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { rc = ecryptfs_read_metadata(ecryptfs_dentry); if (rc) { ecryptfs_printk(KERN_DEBUG, "Valid headers not found\n"); if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; printk(KERN_WARNING "Either the lower file " "is not in a valid eCryptfs format, " "or the key could not be retrieved. " "Plaintext passthrough mode is not " "enabled; returning -EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); goto out_put; } rc = 0; crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED | ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); goto out; } } mutex_unlock(&crypt_stat->cs_mutex); ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = " "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, (unsigned long long)i_size_read(inode)); goto out; out_put: ecryptfs_put_lower_file(inode); out_free: kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); out: return rc; }
/** * ecryptfs_miscdev_write - handle write to daemon miscdev handle * @file: File for misc dev handle (ignored) * @buf: Buffer containing user data * @count: Amount of data in @buf * @ppos: Pointer to offset in file (ignored) * * miscdevfs packet format: * Octet 0: Type * Octets 1-4: network byte order msg_ctx->counter (0's for non-response) * Octets 5-N0: Size of struct ecryptfs_message to follow * Octets N0-N1: struct ecryptfs_message (including data) * * Returns the number of bytes read from @buf */ static ssize_t ecryptfs_miscdev_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { __be32 counter_nbo; u32 seq; size_t packet_size, packet_size_length, i; ssize_t sz = 0; char *data; uid_t euid = current_euid(); unsigned char packet_size_peek[3]; int rc; if (count == 0) { goto out; } else if (count == (1 + 4)) { /* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */ goto memdup; } else if (count < (1 + 4 + 1) || count > (1 + 4 + 2 + sizeof(struct ecryptfs_message) + 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES)) { printk(KERN_WARNING "%s: Acceptable packet size range is " "[%d-%u], but amount of data written is [%zu].", __func__, (1 + 4 + 1), (1 + 4 + 2 + sizeof(struct ecryptfs_message) + 4 + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES), count); return -EINVAL; } if (copy_from_user(packet_size_peek, (buf + 1 + 4), sizeof(packet_size_peek))) { printk(KERN_WARNING "%s: Error while inspecting packet size\n", __func__); return -EFAULT; } rc = ecryptfs_parse_packet_length(packet_size_peek, &packet_size, &packet_size_length); if (rc) { printk(KERN_WARNING "%s: Error parsing packet length; " "rc = [%d]\n", __func__, rc); return rc; } if ((1 + 4 + packet_size_length + packet_size) != count) { printk(KERN_WARNING "%s: Invalid packet size [%zu]\n", __func__, packet_size); return -EINVAL; } memdup: data = memdup_user(buf, count); if (IS_ERR(data)) { printk(KERN_ERR "%s: memdup_user returned error [%ld]\n", __func__, PTR_ERR(data)); goto out; } sz = count; i = 0; switch (data[i++]) { case ECRYPTFS_MSG_RESPONSE: if (count < (1 + 4 + 1 + sizeof(struct ecryptfs_message))) { printk(KERN_WARNING "%s: Minimum acceptable packet " "size is [%zd], but amount of data written is " "only [%zd]. Discarding response packet.\n", __func__, (1 + 4 + 1 + sizeof(struct ecryptfs_message)), count); goto out_free; } memcpy(&counter_nbo, &data[i], 4); seq = be32_to_cpu(counter_nbo); i += 4 + packet_size_length; rc = ecryptfs_miscdev_response(&data[i], packet_size, euid, current_user_ns(), task_pid(current), seq); if (rc) printk(KERN_WARNING "%s: Failed to deliver miscdev " "response to requesting operation; rc = [%d]\n", __func__, rc); break; case ECRYPTFS_MSG_HELO: case ECRYPTFS_MSG_QUIT: break; default: ecryptfs_printk(KERN_WARNING, "Dropping miscdev " "message of unrecognized type [%d]\n", data[0]); break; } out_free: kfree(data); out: return sz; }
/** * ecryptfs_lookup * @ecryptfs_dir_inode: The eCryptfs directory inode * @ecryptfs_dentry: The eCryptfs dentry that we are looking up * @ecryptfs_nd: nameidata; may be NULL * * Find a file on disk. If the file does not exist, then we'll add it to the * dentry cache and continue on to read it from the disk. */ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, struct dentry *ecryptfs_dentry, struct nameidata *ecryptfs_nd) { char *encrypted_and_encoded_name = NULL; size_t encrypted_and_encoded_name_size; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; struct dentry *lower_dir_dentry, *lower_dentry; int rc = 0; if ((ecryptfs_dentry->d_name.len == 1 && !strcmp(ecryptfs_dentry->d_name.name, ".")) || (ecryptfs_dentry->d_name.len == 2 && !strcmp(ecryptfs_dentry->d_name.name, ".."))) { goto out_d_drop; } lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); mutex_lock(&lower_dir_dentry->d_inode->i_mutex); lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name, lower_dir_dentry, ecryptfs_dentry->d_name.len); mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " "[%d] on lower_dentry = [%s]\n", __func__, rc, encrypted_and_encoded_name); goto out_d_drop; } if (lower_dentry->d_inode) goto interpose; mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; if (!(mount_crypt_stat && (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES))) goto interpose; dput(lower_dentry); rc = ecryptfs_encrypt_and_encode_filename( &encrypted_and_encoded_name, &encrypted_and_encoded_name_size, NULL, mount_crypt_stat, ecryptfs_dentry->d_name.name, ecryptfs_dentry->d_name.len); if (rc) { printk(KERN_ERR "%s: Error attempting to encrypt and encode " "filename; rc = [%d]\n", __func__, rc); goto out_d_drop; } mutex_lock(&lower_dir_dentry->d_inode->i_mutex); lower_dentry = lookup_one_len(encrypted_and_encoded_name, lower_dir_dentry, encrypted_and_encoded_name_size); mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " "[%d] on lower_dentry = [%s]\n", __func__, rc, encrypted_and_encoded_name); goto out_d_drop; } interpose: rc = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry, ecryptfs_dir_inode); goto out; out_d_drop: d_drop(ecryptfs_dentry); out: kfree(encrypted_and_encoded_name); return ERR_PTR(rc); }
/** * ecryptfs_writepage * @page: Page that is locked before this call is made * * Returns zero on success; non-zero otherwise * * This is where we encrypt the data and pass the encrypted data to * the lower filesystem. In OpenPGP-compatible mode, we operate on * entire underlying packets. */ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) { #ifndef CONFIG_CRYPTO_DEV_KFIPS int rc; #else struct ecryptfs_page_crypt_req *page_crypt_req; int rc = 0; #endif #if 1 // FEATURE_SDCARD_ENCRYPTION struct inode *ecryptfs_inode; struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(page->mapping->host)->crypt_stat; ecryptfs_inode = page->mapping->host; #endif /* * Refuse to write the page out if we are called from reclaim context * since our writepage() path may potentially allocate memory when * calling into the lower fs vfs_write() which may in turn invoke * us again. */ if (current->flags & PF_MEMALLOC) { redirty_page_for_writepage(wbc, page); #ifndef CONFIG_CRYPTO_DEV_KFIPS rc = 0; #endif goto out; } #if 1 // FEATURE_SDCARD_ENCRYPTION if (!crypt_stat || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { ecryptfs_printk(KERN_DEBUG, "Passing through unencrypted page\n"); rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, page, 0, PAGE_CACHE_SIZE); if (rc) { ClearPageUptodate(page); goto out; } SetPageUptodate(page); } else { #ifndef CONFIG_CRYPTO_DEV_KFIPS rc = ecryptfs_encrypt_page(page); if (rc) { ecryptfs_printk(KERN_WARNING, "Error encrypting " "page (upper index [0x%.16lx])\n", page->index); ClearPageUptodate(page); #else // rc = ecryptfs_encrypt_page(page); // if (rc) { // ecryptfs_printk(KERN_WARNING, "Error encrypting " // "page (upper index [0x%.16lx])\n", page->index); // ClearPageUptodate(page); page_crypt_req = ecryptfs_alloc_page_crypt_req( page, ecryptfs_writepage_complete); if (unlikely(!page_crypt_req)) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Failed to allocate page crypt request " "for encryption\n"); #endif goto out; } #ifndef CONFIG_CRYPTO_DEV_KFIPS SetPageUptodate(page); #else // SetPageUptodate(page); set_page_writeback(page); ecryptfs_encrypt_page_async(page_crypt_req); #endif } #else rc = ecryptfs_encrypt_page(page); if (rc) { ecryptfs_printk(KERN_WARNING, "Error encrypting " "page (upper index [0x%.16lx])\n", page->index); ClearPageUptodate(page); goto out; } SetPageUptodate(page); #endif out: unlock_page(page); return rc; } static void strip_xattr_flag(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { size_t written; crypt_stat->flags &= ~ECRYPTFS_METADATA_IN_XATTR; ecryptfs_write_crypt_stat_flags(page_virt, crypt_stat, &written); crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; } } /** * Header Extent: * Octets 0-7: Unencrypted file size (big-endian) * Octets 8-15: eCryptfs special marker * Octets 16-19: Flags * Octet 16: File format version number (between 0 and 255) * Octets 17-18: Reserved * Octet 19: Bit 1 (lsb): Reserved * Bit 2: Encrypted? * Bits 3-8: Reserved * Octets 20-23: Header extent size (big-endian) * Octets 24-25: Number of header extents at front of file * (big-endian) * Octet 26: Begin RFC 2440 authentication token packet set */ /** * ecryptfs_copy_up_encrypted_with_header * @page: Sort of a ``virtual'' representation of the encrypted lower * file. The actual lower file does not have the metadata in * the header. This is locked. * @crypt_stat: The eCryptfs inode's cryptographic context * * The ``view'' is the version of the file that userspace winds up * seeing, with the header information inserted. */ static int ecryptfs_copy_up_encrypted_with_header(struct page *page, struct ecryptfs_crypt_stat *crypt_stat) { loff_t extent_num_in_page = 0; loff_t num_extents_per_page = (PAGE_CACHE_SIZE / crypt_stat->extent_size); int rc = 0; while (extent_num_in_page < num_extents_per_page) { loff_t view_extent_num = ((((loff_t)page->index) * num_extents_per_page) + extent_num_in_page); size_t num_header_extents_at_front = (crypt_stat->metadata_size / crypt_stat->extent_size); if (view_extent_num < num_header_extents_at_front) { /* This is a header extent */ char *page_virt; page_virt = kmap_atomic(page); memset(page_virt, 0, PAGE_CACHE_SIZE); /* TODO: Support more than one header extent */ if (view_extent_num == 0) { size_t written; rc = ecryptfs_read_xattr_region( page_virt, page->mapping->host); strip_xattr_flag(page_virt + 16, crypt_stat); ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written); } kunmap_atomic(page_virt); flush_dcache_page(page); if (rc) { printk(KERN_ERR "%s: Error reading xattr " "region; rc = [%d]\n", __func__, rc); goto out; } } else { /* This is an encrypted data extent */ loff_t lower_offset = ((view_extent_num * crypt_stat->extent_size) - crypt_stat->metadata_size); rc = ecryptfs_read_lower_page_segment( page, (lower_offset >> PAGE_CACHE_SHIFT), (lower_offset & ~PAGE_CACHE_MASK), crypt_stat->extent_size, page->mapping->host); if (rc) { printk(KERN_ERR "%s: Error attempting to read " "extent at offset [%lld] in the lower " "file; rc = [%d]\n", __func__, lower_offset, rc); goto out; } } extent_num_in_page++; } out: return rc; }
/** * ecryptfs_open * @inode: inode speciying file to open * @file: Structure to return filled in * * Opens the file specified by inode. * * Returns zero on success; non-zero otherwise */ static int ecryptfs_open(struct inode *inode, struct file *file) { int rc = 0; struct ecryptfs_crypt_stat *crypt_stat = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct dentry *ecryptfs_dentry = file->f_path.dentry; /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); struct inode *lower_inode = NULL; struct file *lower_file = NULL; struct vfsmount *lower_mnt; struct ecryptfs_file_info *file_info; int lower_flags; /* Released in ecryptfs_release or end of function if failure */ file_info = kmem_cache_alloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); if (!file_info) { ecryptfs_printk(KERN_ERR, "Error attempting to allocate memory\n"); rc = -ENOMEM; goto out; } memset(file_info, 0, sizeof(*file_info)); lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; mutex_lock(&crypt_stat->cs_mutex); if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) { ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); /* Policy code enabled in future release */ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED); ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); lower_flags = file->f_flags; if ((lower_flags & O_ACCMODE) == O_WRONLY) lower_flags = (lower_flags & O_ACCMODE) | O_RDWR; if (file->f_flags & O_APPEND) lower_flags &= ~O_APPEND; lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry); /* Corresponding fput() in ecryptfs_release() */ if ((rc = ecryptfs_open_lower_file(&lower_file, lower_dentry, lower_mnt, lower_flags))) { ecryptfs_printk(KERN_ERR, "Error opening lower file\n"); goto out_puts; } ecryptfs_set_file_lower(file, lower_file); /* Isn't this check the same as the one in lookup? */ lower_inode = lower_dentry->d_inode; if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); rc = 0; goto out; } mutex_lock(&crypt_stat->cs_mutex); if (i_size_read(lower_inode) < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) { if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; printk(KERN_WARNING "Attempt to read file that is " "not in a valid eCryptfs format, and plaintext " "passthrough mode is not enabled; returning " "-EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); goto out_puts; } crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); rc = 0; mutex_unlock(&crypt_stat->cs_mutex); goto out; } else if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED) || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID)) { rc = ecryptfs_read_headers(ecryptfs_dentry, lower_file); if (rc) { ecryptfs_printk(KERN_DEBUG, "Valid headers not found\n"); if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; printk(KERN_WARNING "Attempt to read file that " "is not in a valid eCryptfs format, " "and plaintext passthrough mode is not " "enabled; returning -EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); goto out_puts; } ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); rc = 0; mutex_unlock(&crypt_stat->cs_mutex); goto out; } } mutex_unlock(&crypt_stat->cs_mutex); ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] " "size: [0x%.16x]\n", inode, inode->i_ino, i_size_read(inode)); ecryptfs_set_file_lower(file, lower_file); goto out; out_puts: mntput(lower_mnt); dput(lower_dentry); kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); out: return rc; }
long ecryptfs_do_sdp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { char filename[NAME_MAX+1] = {0}; void __user *ubuf = (void __user *)arg; struct dentry *ecryptfs_dentry = file->f_path.dentry; struct inode *inode = ecryptfs_dentry->d_inode; struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; struct dentry *fp_dentry = ecryptfs_inode_to_private(inode)->lower_file->f_dentry; if (fp_dentry->d_name.len <= NAME_MAX) memcpy(filename, fp_dentry->d_name.name, fp_dentry->d_name.len + 1); DEK_LOGD("ecryptfs_do_sdp_ioctl\n"); if (!(crypt_stat->flags & ECRYPTFS_DEK_SDP_ENABLED)) { DEK_LOGE("SDP not enabled, skip sdp ioctl\n"); return -ENOTTY; } switch (cmd) { case ECRYPTFS_IOCTL_GET_SDP_INFO: { dek_arg_get_sdp_info req; DEK_LOGD("ECRYPTFS_IOCTL_GET_SDP_INFO\n"); memset(&req, 0, sizeof(dek_arg_get_sdp_info)); if(copy_from_user(&req, ubuf, sizeof(req))) { DEK_LOGE("can't copy from user\n"); return -EFAULT; } else { mutex_lock(&crypt_stat->cs_mutex); if (crypt_stat->flags & ECRYPTFS_DEK_SDP_ENABLED) { req.sdp_enabled = 1; } else { req.sdp_enabled = 0; } if (crypt_stat->flags & ECRYPTFS_DEK_IS_SENSITIVE) { req.is_sensitive = 1; } else { req.is_sensitive = 0; } req.type = crypt_stat->sdp_dek.type; mutex_unlock(&crypt_stat->cs_mutex); } if(copy_to_user(ubuf, &req, sizeof(req))) { DEK_LOGE("can't copy to user\n"); return -EFAULT; } break; } case ECRYPTFS_IOCTL_GET_FEK: { dek_arg_get_fek req; DEK_LOGD("ECRYPTFS_IOCTL_GET_FEK\n"); if (crypt_stat->flags & ECRYPTFS_DEK_IS_SENSITIVE) { DEK_LOGE("don't return FEK of sensitive file\n"); return -EFAULT; } memset(&req, 0, sizeof(dek_arg_get_fek)); if(copy_from_user(&req, ubuf, sizeof(req))) { DEK_LOGE("can't copy from user\n"); memset(&req, 0, sizeof(dek_arg_get_fek)); return -EFAULT; } else { mutex_lock(&crypt_stat->cs_mutex); memcpy(req.dek.buf, crypt_stat->key, crypt_stat->key_size); req.dek.len = crypt_stat->key_size; req.dek.type = DEK_TYPE_PLAIN; mutex_unlock(&crypt_stat->cs_mutex); } if(copy_to_user(ubuf, &req, sizeof(req))) { DEK_LOGE("can't copy to user\n"); memset(&req, 0, sizeof(dek_arg_get_fek)); return -EFAULT; } memset(&req, 0, sizeof(dek_arg_get_fek)); break; } case ECRYPTFS_IOCTL_GET_EFEK: { dek_arg_get_efek req; DEK_LOGD("ECRYPTFS_IOCTL_GET_EFEK\n"); memset(&req, 0, sizeof(dek_arg_get_efek)); if(copy_from_user(&req, ubuf, sizeof(req))) { DEK_LOGE("can't copy from user\n"); memset(&req, 0, sizeof(dek_arg_get_efek)); return -EFAULT; } else { mutex_lock(&crypt_stat->cs_mutex); memcpy(req.dek.buf, crypt_stat->sdp_dek.buf, crypt_stat->sdp_dek.len); req.dek.len = crypt_stat->sdp_dek.len; req.dek.type = crypt_stat->sdp_dek.type; mutex_unlock(&crypt_stat->cs_mutex); } if(copy_to_user(ubuf, &req, sizeof(req))) { DEK_LOGE("can't copy to user\n"); memset(&req, 0, sizeof(dek_arg_get_efek)); return -EFAULT; } memset(&req, 0, sizeof(dek_arg_get_efek)); break; } case ECRYPTFS_IOCTL_SET_EFEK: { dek_arg_set_efek req; DEK_LOGD("ECRYPTFS_IOCTL_SET_EFEK\n"); memset(&req, 0, sizeof(dek_arg_set_efek)); if(copy_from_user(&req, ubuf, sizeof(req))) { DEK_LOGE("can't copy from user\n"); memset(&req, 0, sizeof(dek_arg_set_efek)); return -EFAULT; } else { if(req.dek.len > DEK_MAXLEN) { DEK_LOGE("ECRYPTFS_IOCTL_SET_EFEK invalid EFEK len %d\n", req.dek.len); memset(&req, 0, sizeof(dek_arg_set_efek)); return -EINVAL; } if (req.dek.type != DEK_TYPE_PLAIN) { mutex_lock(&crypt_stat->cs_mutex); memcpy(crypt_stat->sdp_dek.buf, req.dek.buf, req.dek.len); crypt_stat->sdp_dek.len = req.dek.len; crypt_stat->sdp_dek.type = req.dek.type; memset(crypt_stat->key, 0, crypt_stat->key_size); crypt_stat->flags &= ~(ECRYPTFS_KEY_SET); mutex_unlock(&crypt_stat->cs_mutex); ecryptfs_update_crypt_flag(ecryptfs_dentry, 1); } else { DEK_LOGE("failed to set EFEK\n"); memset(&req, 0, sizeof(dek_arg_set_efek)); return -EFAULT; } } memset(&req, 0, sizeof(dek_arg_set_efek)); break; } case ECRYPTFS_IOCTL_SET_SENSITIVE: { dek_arg_set_sensitive req; ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_IOCTL_SET_SENSITIVE\n"); if (crypt_stat->flags & ECRYPTFS_DEK_IS_SENSITIVE) { DEK_LOGE("already sensitive file\n"); return 0; } memset(&req, 0, sizeof(dek_arg_set_sensitive)); if(copy_from_user(&req, ubuf, sizeof(req))) { DEK_LOGE("can't copy from user\n"); memset(&req, 0, sizeof(dek_arg_set_sensitive)); return -EFAULT; } else { if (ecryptfs_sdp_set_sensitive(ecryptfs_dentry)) { DEK_LOGE("failed to set sensitive\n"); memset(&req, 0, sizeof(dek_arg_set_sensitive)); return -EFAULT; } } memset(&req, 0, sizeof(dek_arg_set_sensitive)); break; } default: { return -EINVAL; break; } } return 0; }
/** * ecryptfs_readpage * @file: An eCryptfs file * @page: Page from eCryptfs inode mapping into which to stick the read data * * Read in a page, decrypting if necessary. * * Returns zero on success; non-zero on error. */ static int ecryptfs_readpage(struct file *file, struct page *page) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(page->mapping->host)->crypt_stat; #ifdef CONFIG_CRYPTO_DEV_KFIPS struct ecryptfs_page_crypt_req *page_crypt_req = NULL; #endif int rc = 0; if (!crypt_stat || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_read_lower_page_segment(page, page->index, 0, PAGE_CACHE_SIZE, page->mapping->host); } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { rc = ecryptfs_copy_up_encrypted_with_header(page, crypt_stat); if (rc) { printk(KERN_ERR "%s: Error attempting to copy " "the encrypted content from the lower " "file whilst inserting the metadata " "from the xattr into the header; rc = " "[%d]\n", __func__, rc); goto out; } } else { rc = ecryptfs_read_lower_page_segment( page, page->index, 0, PAGE_CACHE_SIZE, page->mapping->host); if (rc) { printk(KERN_ERR "Error reading page; rc = " "[%d]\n", rc); goto out; } } } else { #ifndef CONFIG_CRYPTO_DEV_KFIPS rc = ecryptfs_decrypt_page(page); if (rc) { ecryptfs_printk(KERN_ERR, "Error decrypting page; " "rc = [%d]\n", rc); #else page_crypt_req = ecryptfs_alloc_page_crypt_req( page, ecryptfs_readpage_complete); if (!page_crypt_req) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Failed to allocate page crypt request " "for decryption\n"); #endif goto out; } #ifdef CONFIG_CRYPTO_DEV_KFIPS ecryptfs_decrypt_page_async(page_crypt_req); goto out_async_started; #endif } out: #ifndef CONFIG_CRYPTO_DEV_KFIPS if (rc) #else if (unlikely(rc)) #endif ClearPageUptodate(page); else SetPageUptodate(page); ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16lx]\n", page->index); unlock_page(page); #ifdef CONFIG_CRYPTO_DEV_KFIPS out_async_started: #endif return rc; } /** * Called with lower inode mutex held. */ static int fill_zeros_to_end_of_page(struct page *page, unsigned int to) { struct inode *inode = page->mapping->host; int end_byte_in_page; if ((i_size_read(inode) / PAGE_CACHE_SIZE) != page->index) goto out; end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE; if (to > end_byte_in_page) end_byte_in_page = to; zero_user_segment(page, end_byte_in_page, PAGE_CACHE_SIZE); out: return 0; } /** * ecryptfs_write_begin * @file: The eCryptfs file * @mapping: The eCryptfs object * @pos: The file offset at which to start writing * @len: Length of the write * @flags: Various flags * @pagep: Pointer to return the page * @fsdata: Pointer to return fs data (unused) * * This function must zero any hole we create * * Returns zero on success; non-zero otherwise */ static int ecryptfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { pgoff_t index = pos >> PAGE_CACHE_SHIFT; struct page *page; loff_t prev_page_end_size; int rc = 0; page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; *pagep = page; prev_page_end_size = ((loff_t)index << PAGE_CACHE_SHIFT); if (!PageUptodate(page)) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(mapping->host)->crypt_stat; if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_read_lower_page_segment( page, index, 0, PAGE_CACHE_SIZE, mapping->host); if (rc) { printk(KERN_ERR "%s: Error attemping to read " "lower page segment; rc = [%d]\n", __func__, rc); ClearPageUptodate(page); goto out; } else SetPageUptodate(page); } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { rc = ecryptfs_copy_up_encrypted_with_header( page, crypt_stat); if (rc) { printk(KERN_ERR "%s: Error attempting " "to copy the encrypted content " "from the lower file whilst " "inserting the metadata from " "the xattr into the header; rc " "= [%d]\n", __func__, rc); ClearPageUptodate(page); goto out; } SetPageUptodate(page); } else { rc = ecryptfs_read_lower_page_segment( page, index, 0, PAGE_CACHE_SIZE, mapping->host); if (rc) { printk(KERN_ERR "%s: Error reading " "page; rc = [%d]\n", __func__, rc); ClearPageUptodate(page); goto out; } SetPageUptodate(page); } } else { if (prev_page_end_size >= i_size_read(page->mapping->host)) { zero_user(page, 0, PAGE_CACHE_SIZE); } else { rc = ecryptfs_decrypt_page(page); if (rc) { printk(KERN_ERR "%s: Error decrypting " "page at index [%ld]; " "rc = [%d]\n", __func__, page->index, rc); ClearPageUptodate(page); goto out; } } SetPageUptodate(page); } } /* If creating a page or more of holes, zero them out via truncate. * Note, this will increase i_size. */ if (index != 0) { if (prev_page_end_size > i_size_read(page->mapping->host)) { rc = ecryptfs_truncate(file->f_path.dentry, prev_page_end_size); if (rc) { printk(KERN_ERR "%s: Error on attempt to " "truncate to (higher) offset [%lld];" " rc = [%d]\n", __func__, prev_page_end_size, rc); goto out; } } } /* Writing to a new page, and creating a small hole from start * of page? Zero it out. */ if ((i_size_read(mapping->host) == prev_page_end_size) && (pos != 0)) zero_user(page, 0, PAGE_CACHE_SIZE); out: if (unlikely(rc)) { unlock_page(page); page_cache_release(page); *pagep = NULL; } return rc; }
/** * ecryptfs_miscdev_write - handle write to daemon miscdev handle * @file: File for misc dev handle (ignored) * @buf: Buffer containing user data * @count: Amount of data in @buf * @ppos: Pointer to offset in file (ignored) * * miscdevfs packet format: * Octet 0: Type * Octets 1-4: network byte order msg_ctx->counter (0's for non-response) * Octets 5-N0: Size of struct ecryptfs_message to follow * Octets N0-N1: struct ecryptfs_message (including data) * * Returns the number of bytes read from @buf */ static ssize_t ecryptfs_miscdev_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { __be32 counter_nbo; u32 seq; size_t packet_size, packet_size_length, i; ssize_t sz = 0; char *data; uid_t euid = current_euid(); int rc; if (count == 0) goto out; data = memdup_user(buf, count); if (IS_ERR(data)) { printk(KERN_ERR "%s: memdup_user returned error [%ld]\n", __func__, PTR_ERR(data)); goto out; } sz = count; i = 0; switch (data[i++]) { case ECRYPTFS_MSG_RESPONSE: if (count < (1 + 4 + 1 + sizeof(struct ecryptfs_message))) { printk(KERN_WARNING "%s: Minimum acceptable packet " "size is [%zd], but amount of data written is " "only [%zd]. Discarding response packet.\n", __func__, (1 + 4 + 1 + sizeof(struct ecryptfs_message)), count); goto out_free; } memcpy(&counter_nbo, &data[i], 4); seq = be32_to_cpu(counter_nbo); i += 4; rc = ecryptfs_parse_packet_length(&data[i], &packet_size, &packet_size_length); if (rc) { printk(KERN_WARNING "%s: Error parsing packet length; " "rc = [%d]\n", __func__, rc); goto out_free; } i += packet_size_length; if ((1 + 4 + packet_size_length + packet_size) != count) { printk(KERN_WARNING "%s: (1 + packet_size_length([%zd])" " + packet_size([%zd]))([%zd]) != " "count([%zd]). Invalid packet format.\n", __func__, packet_size_length, packet_size, (1 + packet_size_length + packet_size), count); goto out_free; } rc = ecryptfs_miscdev_response(&data[i], packet_size, euid, current_user_ns(), task_pid(current), seq); if (rc) printk(KERN_WARNING "%s: Failed to deliver miscdev " "response to requesting operation; rc = [%d]\n", __func__, rc); break; case ECRYPTFS_MSG_CLEARMASTER_BLACK: printk(KERN_DEBUG "Clear the master key with blacklist"); break; case ECRYPTFS_MSG_HELO: case ECRYPTFS_MSG_QUIT: break; default: ecryptfs_printk(KERN_WARNING, "Dropping miscdev " "message of unrecognized type [%d]\n", data[0]); break; } out_free: kfree(data); out: return sz; }
/** * ecryptfs_readdir * @file: The eCryptfs directory file * @ctx: The actor to feed the entries to */ static int ecryptfs_readdir(struct file *file, struct dir_context *ctx) { int rc; struct file *lower_file; struct inode *inode = file_inode(file); struct ecryptfs_getdents_callback buf = { .ctx.actor = ecryptfs_filldir, .caller = ctx, .sb = inode->i_sb, }; lower_file = ecryptfs_file_to_lower(file); lower_file->f_pos = ctx->pos; rc = iterate_dir(lower_file, &buf.ctx); ctx->pos = buf.ctx.pos; if (rc < 0) goto out; if (buf.filldir_called && !buf.entries_written) goto out; if (rc >= 0) fsstack_copy_attr_atime(inode, file_inode(lower_file)); out: return rc; } struct kmem_cache *ecryptfs_file_info_cache; static int read_or_initialize_metadata(struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct ecryptfs_crypt_stat *crypt_stat; int rc; crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mount_crypt_stat = &ecryptfs_superblock_to_private( inode->i_sb)->mount_crypt_stat; #ifdef CONFIG_WTL_ENCRYPTION_FILTER if (crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED && crypt_stat->flags & ECRYPTFS_POLICY_APPLIED && crypt_stat->flags & ECRYPTFS_ENCRYPTED && !(crypt_stat->flags & ECRYPTFS_KEY_VALID) && !(crypt_stat->flags & ECRYPTFS_KEY_SET) && crypt_stat->flags & ECRYPTFS_I_SIZE_INITIALIZED) { crypt_stat->flags |= ECRYPTFS_ENCRYPTED_OTHER_DEVICE; } mutex_lock(&crypt_stat->cs_mutex); if ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_NEW_PASSTHROUGH) && (crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { if (ecryptfs_read_metadata(dentry)) { crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED | ECRYPTFS_ENCRYPTED); rc = 0; goto out; } } else if ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_FILTERING) && (crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { struct dentry *fp_dentry = ecryptfs_inode_to_private(inode)->lower_file->f_dentry; char filename[NAME_MAX+1] = {0}; if (fp_dentry->d_name.len <= NAME_MAX) memcpy(filename, fp_dentry->d_name.name, fp_dentry->d_name.len + 1); if (is_file_name_match(mount_crypt_stat, fp_dentry) || is_file_ext_match(mount_crypt_stat, filename)) { if (ecryptfs_read_metadata(dentry)) crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED | ECRYPTFS_ENCRYPTED); rc = 0; goto out; } } mutex_unlock(&crypt_stat->cs_mutex); #endif mutex_lock(&crypt_stat->cs_mutex); if (crypt_stat->flags & ECRYPTFS_POLICY_APPLIED && crypt_stat->flags & ECRYPTFS_KEY_VALID) { rc = 0; goto out; } rc = ecryptfs_read_metadata(dentry); if (!rc) goto out; #ifdef CONFIG_SDP /* * no passthrough/xattr for sensitive files */ if ((rc) && crypt_stat->flags & ECRYPTFS_DEK_IS_SENSITIVE) goto out; #endif if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED) { crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED | ECRYPTFS_ENCRYPTED); rc = 0; goto out; } if (!(mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) && !i_size_read(ecryptfs_inode_to_lower(inode))) { rc = ecryptfs_initialize_file(dentry, inode); if (!rc) goto out; } rc = -EIO; out: mutex_unlock(&crypt_stat->cs_mutex); #ifdef CONFIG_SDP if(!rc) { /* * SDP v2.0 : sensitive directory (SDP vault) * Files under sensitive directory automatically becomes sensitive */ struct dentry *p = dentry->d_parent; struct inode *parent_inode = p->d_inode; struct ecryptfs_crypt_stat *parent_crypt_stat = &ecryptfs_inode_to_private(parent_inode)->crypt_stat; if (!(crypt_stat->flags & ECRYPTFS_DEK_IS_SENSITIVE) && ((S_ISDIR(parent_inode->i_mode)) && (parent_crypt_stat->flags & ECRYPTFS_DEK_IS_SENSITIVE))) { rc = ecryptfs_sdp_set_sensitive(parent_crypt_stat->engine_id, dentry); } } #endif return rc; } #if defined(CONFIG_MMC_DW_FMP_ECRYPT_FS) || defined(CONFIG_UFS_FMP_ECRYPT_FS) static void ecryptfs_set_rapages(struct file *file, unsigned int flag) { if (!flag) file->f_ra.ra_pages = 0; else file->f_ra.ra_pages = (unsigned int)file->f_mapping->backing_dev_info->ra_pages; } static int ecryptfs_set_fmpinfo(struct file *file, struct inode *inode, unsigned int set_flag) { struct address_space *mapping = file->f_mapping; if (set_flag) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private(inode->i_sb)->mount_crypt_stat; if (strncmp(crypt_stat->cipher, "aesxts", sizeof("aesxts")) && strncmp(crypt_stat->cipher, "aes", sizeof("aes"))) { if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { mapping->plain_text = 1; return 0; } else { ecryptfs_printk(KERN_ERR, "%s: Error invalid file encryption algorithm, inode %lu, filename %s alg %s\n" , __func__, inode->i_ino, file->f_dentry->d_name.name, crypt_stat->cipher); return -EINVAL; } } mapping->iv = crypt_stat->root_iv; mapping->key = crypt_stat->key; mapping->sensitive_data_index = crypt_stat->metadata_size/4096; if (mount_crypt_stat->cipher_code == RFC2440_CIPHER_AES_XTS_256) { mapping->key_length = crypt_stat->key_size * 2; mapping->alg = "aesxts"; } else { mapping->key_length = crypt_stat->key_size; mapping->alg = crypt_stat->cipher; } mapping->hash_tfm = crypt_stat->hash_tfm; #ifdef CONFIG_CRYPTO_FIPS mapping->cc_enable = (mount_crypt_stat->flags & ECRYPTFS_ENABLE_CC)?1:0; #endif } else { mapping->iv = NULL; mapping->key = NULL; mapping->key_length = 0; mapping->sensitive_data_index = 0; mapping->alg = NULL; mapping->hash_tfm = NULL; #ifdef CONFIG_CRYPTO_FIPS mapping->cc_enable = 0; #endif mapping->plain_text = 0; } return 0; } void ecryptfs_propagate_rapages(struct file *file, unsigned int flag) { struct file *f = file; do { if (!f) return; ecryptfs_set_rapages(f, flag); } while(f->f_op->get_lower_file && (f = f->f_op->get_lower_file(f))); } int ecryptfs_propagate_fmpinfo(struct inode *inode, unsigned int flag) { struct file *f = ecryptfs_inode_to_private(inode)->lower_file; do { if (!f) return 0; if (ecryptfs_set_fmpinfo(f, inode, flag)) return -EINVAL; } while(f->f_op->get_lower_file && (f = f->f_op->get_lower_file(f))); return 0; } #endif /** * ecryptfs_open * @inode: inode speciying file to open * @file: Structure to return filled in * * Opens the file specified by inode. * * Returns zero on success; non-zero otherwise */ static int ecryptfs_open(struct inode *inode, struct file *file) { int rc = 0; struct ecryptfs_crypt_stat *crypt_stat = NULL; struct dentry *ecryptfs_dentry = file->f_path.dentry; /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ struct ecryptfs_file_info *file_info; #ifdef CONFIG_DLP sdp_fs_command_t *cmd = NULL; ssize_t dlp_len = 0; struct knox_dlp_data dlp_data; struct timespec ts; #endif #if defined(CONFIG_MMC_DW_FMP_ECRYPT_FS) || defined(CONFIG_UFS_FMP_ECRYPT_FS) || defined(CONFIG_SDP) struct ecryptfs_mount_crypt_stat *mount_crypt_stat; mount_crypt_stat = &ecryptfs_superblock_to_private( inode->i_sb)->mount_crypt_stat; #endif /* Released in ecryptfs_release or end of function if failure */ file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); if (!file_info) { ecryptfs_printk(KERN_ERR, "Error attempting to allocate memory\n"); rc = -ENOMEM; goto out; } crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mutex_lock(&crypt_stat->cs_mutex); if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) { ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); /* Policy code enabled in future release */ crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED | ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); rc = ecryptfs_get_lower_file(ecryptfs_dentry, inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%pd]; rc = [%d]\n", __func__, ecryptfs_dentry, rc); goto out_free; } if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) { rc = -EPERM; printk(KERN_WARNING "%s: Lower file is RO; eCryptfs " "file must hence be opened RO\n", __func__); goto out_put; } ecryptfs_set_file_lower( file, ecryptfs_inode_to_private(inode)->lower_file); if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { #ifdef CONFIG_SDP /* * it's possible to have a sensitive directory. (vault) */ if (mount_crypt_stat->flags & ECRYPTFS_MOUNT_SDP_ENABLED) crypt_stat->flags |= ECRYPTFS_DEK_SDP_ENABLED; #endif ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); mutex_lock(&crypt_stat->cs_mutex); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); rc = 0; goto out; } rc = read_or_initialize_metadata(ecryptfs_dentry); if (rc) { #ifdef CONFIG_SDP if(file->f_flags & O_SDP){ printk("Failed to initialize metadata, " "but let it continue cause current call is from SDP API\n"); mutex_lock(&crypt_stat->cs_mutex); crypt_stat->flags &= ~(ECRYPTFS_KEY_VALID); mutex_unlock(&crypt_stat->cs_mutex); rc = 0; /* * Letting this continue doesn't mean to allow read/writing. It will anyway fail later. * * 1. In this stage, ecryptfs_stat won't have key/iv and encryption ctx. * 2. ECRYPTFS_KEY_VALID bit is off, next attempt will try reading metadata again. * 3. Skip DEK conversion. it cannot be done anyway. */ goto out; } #endif goto out_put; } #if defined(CONFIG_MMC_DW_FMP_ECRYPT_FS) || defined(CONFIG_UFS_FMP_ECRYPT_FS) if (mount_crypt_stat->flags & ECRYPTFS_USE_FMP) rc = ecryptfs_propagate_fmpinfo(inode, FMPINFO_SET); else rc = ecryptfs_propagate_fmpinfo(inode, FMPINFO_CLEAR); #endif if (rc) goto out_put; #ifdef CONFIG_SDP if (crypt_stat->flags & ECRYPTFS_DEK_IS_SENSITIVE) { #ifdef CONFIG_SDP_KEY_DUMP if (S_ISREG(ecryptfs_dentry->d_inode->i_mode)) { if(get_sdp_sysfs_key_dump()) { printk("FEK[%s] : ", ecryptfs_dentry->d_name.name); key_dump(crypt_stat->key, 32); } } #endif /* * Need to update sensitive mapping on file open */ if (S_ISREG(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_set_mapping_sensitive(inode, mount_crypt_stat->userid, TO_SENSITIVE); } if (ecryptfs_is_sdp_locked(crypt_stat->engine_id)) { ecryptfs_printk(KERN_INFO, "ecryptfs_open: persona is locked, rc=%d\n", rc); } else { int dek_type = crypt_stat->sdp_dek.type; ecryptfs_printk(KERN_INFO, "ecryptfs_open: persona is unlocked, rc=%d\n", rc); if(dek_type != DEK_TYPE_AES_ENC) { ecryptfs_printk(KERN_DEBUG, "converting dek...\n"); rc = ecryptfs_sdp_convert_dek(ecryptfs_dentry); ecryptfs_printk(KERN_DEBUG, "conversion ready, rc=%d\n", rc); rc = 0; // TODO: Do we need to return error if conversion fails? } } } #if ECRYPTFS_DEK_DEBUG else { ecryptfs_printk(KERN_INFO, "ecryptfs_open: dek_file_type is protected\n"); } #endif #endif #ifdef CONFIG_DLP if(crypt_stat->flags & ECRYPTFS_DLP_ENABLED) { #if DLP_DEBUG printk("DLP %s: try to open %s with crypt_stat->flags %d\n", __func__, ecryptfs_dentry->d_name.name, crypt_stat->flags); #endif if (dlp_is_locked(mount_crypt_stat->userid)) { printk("%s: DLP locked\n", __func__); rc = -EPERM; goto out_put; } if(in_egroup_p(AID_KNOX_DLP) || in_egroup_p(AID_KNOX_DLP_RESTRICTED)) { dlp_len = ecryptfs_getxattr_lower( ecryptfs_dentry_to_lower(ecryptfs_dentry), KNOX_DLP_XATTR_NAME, &dlp_data, sizeof(dlp_data)); if (dlp_len == sizeof(dlp_data)) { getnstimeofday(&ts); #if DLP_DEBUG printk("DLP %s: current time [%ld/%ld] %s\n", __func__, (long)ts.tv_sec, (long)dlp_data.expiry_time.tv_sec, ecryptfs_dentry->d_name.name); #endif if ((ts.tv_sec > dlp_data.expiry_time.tv_sec) && dlp_isInterestedFile(ecryptfs_dentry->d_name.name)==0) { /* Command to delete expired file */ cmd = sdp_fs_command_alloc(FSOP_DLP_FILE_REMOVE, current->tgid, mount_crypt_stat->userid, mount_crypt_stat->partition_id, inode->i_ino, GFP_KERNEL); rc = -ENOENT; goto out_put; } } else if (dlp_len == -ENODATA) { /* DLP flag is set, but no DLP data. Let it continue, xattr will be set later */ printk("DLP %s: normal file [%s]\n", __func__, ecryptfs_dentry->d_name.name); } else { printk("DLP %s: Error, len [%ld], [%s]\n", __func__, (long)dlp_len, ecryptfs_dentry->d_name.name); rc = -EFAULT; goto out_put; } #if DLP_DEBUG printk("DLP %s: DLP file [%s] opened with tgid %d, %d\n" , __func__, ecryptfs_dentry->d_name.name, current->tgid, in_egroup_p(AID_KNOX_DLP_RESTRICTED)); #endif if(in_egroup_p(AID_KNOX_DLP_RESTRICTED)) { cmd = sdp_fs_command_alloc(FSOP_DLP_FILE_OPENED, current->tgid, mount_crypt_stat->userid, mount_crypt_stat->partition_id, inode->i_ino, GFP_KERNEL); } } else { printk("DLP %s: not DLP app [%s]\n", __func__, current->comm); rc = -EPERM; goto out_put; } } #endif ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = " "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, (unsigned long long)i_size_read(inode)); goto out; out_put: ecryptfs_put_lower_file(inode); out_free: kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); out: #ifdef CONFIG_DLP if(cmd) { sdp_fs_request(cmd, NULL); sdp_fs_command_free(cmd); } #endif return rc; }
/** * ecryptfs_miscdev_write - handle write to daemon miscdev handle * @file: File for misc dev handle * @buf: Buffer containing user data * @count: Amount of data in @buf * @ppos: Pointer to offset in file (ignored) * * Returns the number of bytes read from @buf */ static ssize_t ecryptfs_miscdev_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { __be32 counter_nbo; u32 seq; size_t packet_size, packet_size_length; char *data; unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE]; ssize_t rc; if (count == 0) { return 0; } else if (count == MIN_NON_MSG_PKT_SIZE) { /* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */ goto memdup; } else if (count < MIN_MSG_PKT_SIZE || count > MAX_MSG_PKT_SIZE) { printk(KERN_WARNING "%s: Acceptable packet size range is " "[%d-%zu], but amount of data written is [%zu].", __func__, MIN_MSG_PKT_SIZE, MAX_MSG_PKT_SIZE, count); return -EINVAL; } if (copy_from_user(packet_size_peek, &buf[PKT_LEN_OFFSET], sizeof(packet_size_peek))) { printk(KERN_WARNING "%s: Error while inspecting packet size\n", __func__); return -EFAULT; } rc = ecryptfs_parse_packet_length(packet_size_peek, &packet_size, &packet_size_length); if (rc) { printk(KERN_WARNING "%s: Error parsing packet length; " "rc = [%zd]\n", __func__, rc); return rc; } if ((PKT_TYPE_SIZE + PKT_CTR_SIZE + packet_size_length + packet_size) != count) { printk(KERN_WARNING "%s: Invalid packet size [%zu]\n", __func__, packet_size); return -EINVAL; } memdup: data = memdup_user(buf, count); if (IS_ERR(data)) { printk(KERN_ERR "%s: memdup_user returned error [%ld]\n", __func__, PTR_ERR(data)); return PTR_ERR(data); } switch (data[PKT_TYPE_OFFSET]) { case ECRYPTFS_MSG_RESPONSE: if (count < (MIN_MSG_PKT_SIZE + sizeof(struct ecryptfs_message))) { printk(KERN_WARNING "%s: Minimum acceptable packet " "size is [%zd], but amount of data written is " "only [%zd]. Discarding response packet.\n", __func__, (MIN_MSG_PKT_SIZE + sizeof(struct ecryptfs_message)), count); rc = -EINVAL; goto out_free; } memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE); seq = be32_to_cpu(counter_nbo); rc = ecryptfs_miscdev_response(file->private_data, &data[PKT_LEN_OFFSET + packet_size_length], packet_size, seq); if (rc) { printk(KERN_WARNING "%s: Failed to deliver miscdev " "response to requesting operation; rc = [%zd]\n", __func__, rc); goto out_free; } break; case ECRYPTFS_MSG_HELO: case ECRYPTFS_MSG_QUIT: break; default: ecryptfs_printk(KERN_WARNING, "Dropping miscdev " "message of unrecognized type [%d]\n", data[0]); rc = -EINVAL; goto out_free; } rc = count; out_free: kfree(data); return rc; }
/** * ecryptfs_open * @inode: inode speciying file to open * @file: Structure to return filled in * * Opens the file specified by inode. * * Returns zero on success; non-zero otherwise */ static int ecryptfs_open(struct inode *inode, struct file *file) { int rc = 0; struct ecryptfs_crypt_stat *crypt_stat = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct dentry *ecryptfs_dentry = file->f_path.dentry; /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ struct ecryptfs_file_info *file_info; mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; if ((mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) && ((file->f_flags & O_WRONLY) || (file->f_flags & O_RDWR) || (file->f_flags & O_CREAT) || (file->f_flags & O_TRUNC) || (file->f_flags & O_APPEND))) { printk(KERN_WARNING "Mount has encrypted view enabled; " "files may only be read\n"); rc = -EPERM; goto out; } /* Released in ecryptfs_release or end of function if failure */ file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); if (!file_info) { ecryptfs_printk(KERN_ERR, "Error attempting to allocate memory\n"); rc = -ENOMEM; goto out; } crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mutex_lock(&crypt_stat->cs_mutex); if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) { ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); /* Policy code enabled in future release */ crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED | ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); rc = ecryptfs_get_lower_file(ecryptfs_dentry, inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out_free; } if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) { rc = -EPERM; printk(KERN_WARNING "%s: Lower file is RO; eCryptfs " "file must hence be opened RO\n", __func__); goto out_put; } ecryptfs_set_file_lower( file, ecryptfs_inode_to_private(inode)->lower_file); if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { #ifdef CONFIG_SDP /* * it's possible to have a sensitive directory. (vault) */ if (mount_crypt_stat->flags & ECRYPTFS_MOUNT_SDP_ENABLED) crypt_stat->flags |= ECRYPTFS_DEK_SDP_ENABLED; #endif ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); mutex_lock(&crypt_stat->cs_mutex); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); rc = 0; goto out; } rc = read_or_initialize_metadata(ecryptfs_dentry); if (rc) goto out_put; #ifdef CONFIG_SDP if (crypt_stat->flags & ECRYPTFS_DEK_IS_SENSITIVE) { if (ecryptfs_is_persona_locked(crypt_stat->userid)) { ecryptfs_printk(KERN_INFO, "ecryptfs_open: persona is locked, rc=%d\n", rc); #if 0 if (file->f_flags & O_SDP) { ecryptfs_printk(KERN_INFO, "ecryptfs_open: O_SDP is set, allow open, rc=%d\n", rc); mutex_lock(&crypt_stat->cs_mutex); crypt_stat->flags &= ~(ECRYPTFS_KEY_VALID); mutex_unlock(&crypt_stat->cs_mutex); } else { mutex_lock(&crypt_stat->cs_mutex); crypt_stat->flags &= ~(ECRYPTFS_KEY_VALID); mutex_unlock(&crypt_stat->cs_mutex); rc = -EACCES; goto out_put; } #endif } else { int dek_type = crypt_stat->sdp_dek.type; ecryptfs_printk(KERN_INFO, "ecryptfs_open: persona is unlocked, rc=%d\n", rc); if(dek_type != DEK_TYPE_AES_ENC) { ecryptfs_printk(KERN_DEBUG, "converting dek...\n"); rc = ecryptfs_sdp_convert_dek(ecryptfs_dentry); ecryptfs_printk(KERN_DEBUG, "conversion ready, rc=%d\n", rc); rc = 0; // TODO: Do we need to return error if conversion fails? /* if(!(file->f_flags & O_SDP)){ ecryptfs_printk(KERN_WARNING, "Busy sensitive file (try again later)\n"); rc = -EBUSY; goto out_put; } */ } } } #if ECRYPTFS_DEK_DEBUG else { ecryptfs_printk(KERN_INFO, "ecryptfs_open: dek_file_type is protected"); } #endif #endif ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = " "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, (unsigned long long)i_size_read(inode)); goto out; out_put: ecryptfs_put_lower_file(inode); out_free: kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); out: return rc; }
/** * ecryptfs_open * @inode: inode speciying file to open * @file: Structure to return filled in * * Opens the file specified by inode. * * Returns zero on success; non-zero otherwise */ static int ecryptfs_open(struct inode *inode, struct file *file) { int rc = 0; struct ecryptfs_crypt_stat *crypt_stat = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct dentry *ecryptfs_dentry = file->f_path.dentry; /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); struct ecryptfs_file_info *file_info; mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; if ((mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) && ((file->f_flags & O_WRONLY) || (file->f_flags & O_RDWR) || (file->f_flags & O_CREAT) || (file->f_flags & O_TRUNC) || (file->f_flags & O_APPEND))) { printk(KERN_WARNING "Mount has encrypted view enabled; " "files may only be read\n"); rc = -EPERM; goto out; } /* Released in ecryptfs_release or end of function if failure */ file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); if (!file_info) { ecryptfs_printk(KERN_ERR, "Error attempting to allocate memory\n"); rc = -ENOMEM; goto out; } lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mutex_lock(&crypt_stat->cs_mutex); if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) { ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); /* Policy code enabled in future release */ crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED | ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); if (!ecryptfs_inode_to_private(inode)->lower_file) { rc = ecryptfs_init_persistent_file(ecryptfs_dentry); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the persistent file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out_free; } } if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_RDONLY) && !(file->f_flags & O_RDONLY)) { rc = -EPERM; printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs " "file must hence be opened RO\n", __func__); goto out_free; } ecryptfs_set_file_lower( file, ecryptfs_inode_to_private(inode)->lower_file); if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); mutex_lock(&crypt_stat->cs_mutex); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); rc = 0; goto out; } rc = read_or_initialize_metadata(ecryptfs_dentry); if (rc) goto out_free; ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] " "size: [0x%.16x]\n", inode, inode->i_ino, i_size_read(inode)); goto out; out_free: kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); out: return rc; }
/** * ecryptfs_lookup * @dir: inode * @dentry: The dentry * @nd: nameidata, may be NULL * * Find a file on disk. If the file does not exist, then we'll add it to the * dentry cache and continue on to read it from the disk. */ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { int rc = 0; struct dentry *lower_dir_dentry; struct dentry *lower_dentry; struct vfsmount *lower_mnt; char *encoded_name; int encoded_namelen; struct ecryptfs_crypt_stat *crypt_stat = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; char *page_virt = NULL; struct inode *lower_inode; u64 file_size; lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent); dentry->d_op = &ecryptfs_dops; if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, ".")) || (dentry->d_name.len == 2 && !strcmp(dentry->d_name.name, ".."))) { d_drop(dentry); goto out; } encoded_namelen = ecryptfs_encode_filename(crypt_stat, dentry->d_name.name, dentry->d_name.len, &encoded_name); if (encoded_namelen < 0) { rc = encoded_namelen; d_drop(dentry); goto out; } ecryptfs_printk(KERN_DEBUG, "encoded_name = [%s]; encoded_namelen " "= [%d]\n", encoded_name, encoded_namelen); lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry, encoded_namelen - 1); kfree(encoded_name); if (IS_ERR(lower_dentry)) { ecryptfs_printk(KERN_ERR, "ERR from lower_dentry\n"); rc = PTR_ERR(lower_dentry); d_drop(dentry); goto out; } lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent)); ecryptfs_printk(KERN_DEBUG, "lower_dentry = [%p]; lower_dentry->" "d_name.name = [%s]\n", lower_dentry, lower_dentry->d_name.name); lower_inode = lower_dentry->d_inode; fsstack_copy_attr_atime(dir, lower_dir_dentry->d_inode); BUG_ON(!atomic_read(&lower_dentry->d_count)); ecryptfs_set_dentry_private(dentry, kmem_cache_alloc(ecryptfs_dentry_info_cache, GFP_KERNEL)); if (!ecryptfs_dentry_to_private(dentry)) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Out of memory whilst attempting " "to allocate ecryptfs_dentry_info struct\n"); goto out_dput; } ecryptfs_set_dentry_lower(dentry, lower_dentry); ecryptfs_set_dentry_lower_mnt(dentry, lower_mnt); if (!lower_dentry->d_inode) { /* We want to add because we couldn't find in lower */ d_add(dentry, NULL); goto out; } rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, ECRYPTFS_INTERPOSE_FLAG_D_ADD); if (rc) { ecryptfs_printk(KERN_ERR, "Error interposing\n"); goto out; } if (S_ISDIR(lower_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "Is a directory; returning\n"); goto out; } if (S_ISLNK(lower_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "Is a symlink; returning\n"); goto out; } if (special_file(lower_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "Is a special file; returning\n"); goto out; } if (!nd) { ecryptfs_printk(KERN_DEBUG, "We have a NULL nd, just leave" "as we *think* we are about to unlink\n"); goto out; } /* Released in this function */ page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, GFP_USER); if (!page_virt) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Cannot ecryptfs_kmalloc a page\n"); goto out; } crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) ecryptfs_set_default_sizes(crypt_stat); if (!ecryptfs_inode_to_private(dentry->d_inode)->lower_file) { rc = ecryptfs_init_persistent_file(dentry); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the persistent file for the dentry with name " "[%s]; rc = [%d]\n", __func__, dentry->d_name.name, rc); goto out; } } rc = ecryptfs_read_and_validate_header_region(page_virt, dentry->d_inode); if (rc) { rc = ecryptfs_read_and_validate_xattr_region(page_virt, dentry); if (rc) { printk(KERN_DEBUG "Valid metadata not found in header " "region or xattr region; treating file as " "unencrypted\n"); rc = 0; kmem_cache_free(ecryptfs_header_cache_2, page_virt); goto out; } crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; } mount_crypt_stat = &ecryptfs_superblock_to_private( dentry->d_sb)->mount_crypt_stat; if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) file_size = (crypt_stat->num_header_bytes_at_front + i_size_read(lower_dentry->d_inode)); else file_size = i_size_read(lower_dentry->d_inode); } else { file_size = get_unaligned_be64(page_virt); } i_size_write(dentry->d_inode, (loff_t)file_size); kmem_cache_free(ecryptfs_header_cache_2, page_virt); goto out; out_dput: dput(lower_dentry); d_drop(dentry); out: return ERR_PTR(rc); }
/** * ecryptfs_initialize_file * * Cause the file to be changed from a basic empty file to an ecryptfs * file with a header and first data page. * * Returns zero on success */ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, struct inode *ecryptfs_inode) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; #if 1 // FEATURE_SDCARD_ENCRYPTION struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; char dentry_name[MAX_FILE_NAME_LENGTH] = {0,}; #endif int rc = 0; if (S_ISDIR(ecryptfs_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); goto out; } #if defined (FEATURE_SDCARD_MEDIAEXN_SYSTEMCALL_ENCRYPTION) memcpy (dentry_name, ecryptfs_dentry->d_name.name, ecryptfs_dentry->d_name.len); if (getMediaProperty() == 1) { if(ecryptfs_mediaFileSearch(dentry_name)) { crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); goto out; } } if(ecryptfs_asecFileSearch(dentry_name)) { crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); goto out; } #endif //FEATURE_SDCARD_MEDIAEXN_SYSTEMCALL_ENCRYPTION #if 1 // FEATURE_SDCARD_ENCRYPTION if (mount_crypt_stat && (mount_crypt_stat->flags & ECRYPTFS_DECRYPTION_ONLY)) { crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); goto out; } #endif ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); rc = ecryptfs_new_file_context(ecryptfs_inode); if (rc) { ecryptfs_printk(KERN_ERR, "Error creating new file " "context; rc = [%d]\n", rc); goto out; } rc = ecryptfs_get_lower_file(ecryptfs_dentry, ecryptfs_inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out; } rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); if (rc) printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); ecryptfs_put_lower_file(ecryptfs_inode); out: return rc; }
/** * ecryptfs_open * @inode: inode speciying file to open * @file: Structure to return filled in * * Opens the file specified by inode. * * Returns zero on success; non-zero otherwise */ static int ecryptfs_open(struct inode *inode, struct file *file) { int rc = 0; struct ecryptfs_crypt_stat *crypt_stat = NULL; struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct dentry *ecryptfs_dentry = file->f_path.dentry; /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); struct ecryptfs_file_info *file_info; mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; if ((mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) && ((file->f_flags & O_WRONLY) || (file->f_flags & O_RDWR) || (file->f_flags & O_CREAT) || (file->f_flags & O_TRUNC) || (file->f_flags & O_APPEND))) { printk(KERN_WARNING "Mount has encrypted view enabled; " "files may only be read\n"); rc = -EPERM; goto out; } /* Released in ecryptfs_release or end of function if failure */ file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); if (!file_info) { ecryptfs_printk(KERN_ERR, "Error attempting to allocate memory\n"); rc = -ENOMEM; goto out; } lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mutex_lock(&crypt_stat->cs_mutex); if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) { ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); /* Policy code enabled in future release */ crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED | ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); ecryptfs_set_file_lower( file, ecryptfs_inode_to_private(inode)->lower_file); if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); mutex_lock(&crypt_stat->cs_mutex); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); rc = 0; goto out; } mutex_lock(&crypt_stat->cs_mutex); if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { rc = ecryptfs_read_metadata(ecryptfs_dentry); if (rc) { ecryptfs_printk(KERN_DEBUG, "Valid headers not found\n"); if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; printk(KERN_WARNING "Either the lower file " "is not in a valid eCryptfs format, " "or the key could not be retrieved. " "Plaintext passthrough mode is not " "enabled; returning -EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); goto out_free; } rc = 0; crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); goto out; } } mutex_unlock(&crypt_stat->cs_mutex); ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] " "size: [0x%.16x]\n", inode, inode->i_ino, i_size_read(inode)); goto out; out_free: kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); out: return rc; }
/** * ecryptfs_dump_auth_tok - debug function to print auth toks * * This function will print the contents of an ecryptfs authentication * token. */ void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok) { char salt[ECRYPTFS_SALT_SIZE * 2 + 1]; char sig[ECRYPTFS_SIG_SIZE_HEX + 1]; ecryptfs_printk(KERN_DEBUG, "Auth tok at mem loc [%p]:\n", auth_tok); if (auth_tok->flags & ECRYPTFS_PRIVATE_KEY) { ecryptfs_printk(KERN_DEBUG, " * private key type\n"); } else { ecryptfs_printk(KERN_DEBUG, " * passphrase type\n"); ecryptfs_to_hex(salt, auth_tok->token.password.salt, ECRYPTFS_SALT_SIZE); salt[ECRYPTFS_SALT_SIZE * 2] = '\0'; ecryptfs_printk(KERN_DEBUG, " * salt = [%s]\n", salt); if (auth_tok->token.password.flags & ECRYPTFS_PERSISTENT_PASSWORD) { ecryptfs_printk(KERN_DEBUG, " * persistent\n"); } memcpy(sig, auth_tok->token.password.signature, ECRYPTFS_SIG_SIZE_HEX); sig[ECRYPTFS_SIG_SIZE_HEX] = '\0'; ecryptfs_printk(KERN_DEBUG, " * signature = [%s]\n", sig); } ecryptfs_printk(KERN_DEBUG, " * session_key.flags = [0x%x]\n", auth_tok->session_key.flags); if (auth_tok->session_key.flags & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT) ecryptfs_printk(KERN_DEBUG, " * Userspace decrypt request set\n"); if (auth_tok->session_key.flags & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT) ecryptfs_printk(KERN_DEBUG, " * Userspace encrypt request set\n"); if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_DECRYPTED_KEY) { ecryptfs_printk(KERN_DEBUG, " * Contains decrypted key\n"); ecryptfs_printk(KERN_DEBUG, " * session_key.decrypted_key_size = [0x%x]\n", auth_tok->session_key.decrypted_key_size); ecryptfs_printk(KERN_DEBUG, " * Decrypted session key " "dump:\n"); if (ecryptfs_verbosity > 0) ecryptfs_dump_hex(auth_tok->session_key.decrypted_key, ECRYPTFS_DEFAULT_KEY_BYTES); } if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_ENCRYPTED_KEY) { ecryptfs_printk(KERN_DEBUG, " * Contains encrypted key\n"); ecryptfs_printk(KERN_DEBUG, " * session_key.encrypted_key_size = [0x%x]\n", auth_tok->session_key.encrypted_key_size); ecryptfs_printk(KERN_DEBUG, " * Encrypted session key " "dump:\n"); if (ecryptfs_verbosity > 0) ecryptfs_dump_hex(auth_tok->session_key.encrypted_key, auth_tok->session_key. encrypted_key_size); } }
/** * ecryptfs_initialize_file * * Cause the file to be changed from a basic empty file to an ecryptfs * file with a header and first data page. * * Returns zero on success */ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; int rc = 0; if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); goto out; } crypt_stat->flags |= ECRYPTFS_NEW_FILE; ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); rc = ecryptfs_new_file_context(ecryptfs_dentry); if (rc) { ecryptfs_printk(KERN_ERR, "Error creating new file " "context; rc = [%d]\n", rc); goto out; } if (!ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->lower_file) { rc = ecryptfs_init_persistent_file(ecryptfs_dentry); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the persistent file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out; } } /* [email protected] encryption filter */ #ifdef WTL_ENCRYPTION_FILTER /* fzhang, TODO, should not change flags for existing encrypted files even through their ext match filter rule */ if (crypt_stat->flags & ECRYPTFS_ENCRYPTED) { struct dentry *fp_dentry = ecryptfs_inode_to_private(ecryptfs_dentry->d_inode) ->lower_file->f_dentry; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; char filename[256]; strcpy(filename, fp_dentry->d_name.name); if ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_NEW_PASSTHROUGH) || ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_FILTERING) && (is_file_name_match(mount_crypt_stat, fp_dentry) || is_file_ext_match(mount_crypt_stat, filename)))) { /*printk(KERN_ERR "fzhang %s will not be encrypted.\n", fp_dentry->d_iname); */ crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); } else { rc = ecryptfs_write_metadata(ecryptfs_dentry); if (rc) { printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); goto out; } rc = grow_file(ecryptfs_dentry); if (rc) printk(KERN_ERR "Error growing file; rc = [%d]\n", rc); } } #else rc = ecryptfs_write_metadata(ecryptfs_dentry); if (rc) { printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); goto out; } rc = grow_file(ecryptfs_dentry); if (rc) printk(KERN_ERR "Error growing file; rc = [%d]\n", rc); #endif out: return rc; }
/** * ecryptfs_initialize_file * * Cause the file to be changed from a basic empty file to an ecryptfs * file with a header and first data page. * * Returns zero on success */ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, struct inode *ecryptfs_inode) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; int rc = 0; if (S_ISDIR(ecryptfs_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); goto out; } ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); rc = ecryptfs_new_file_context(ecryptfs_inode); if (rc) { ecryptfs_printk(KERN_ERR, "Error creating new file " "context; rc = [%d]\n", rc); goto out; } rc = ecryptfs_get_lower_file(ecryptfs_dentry, ecryptfs_inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out; } #ifdef CONFIG_WTL_ENCRYPTION_FILTER mutex_lock(&crypt_stat->cs_mutex); if (crypt_stat->flags & ECRYPTFS_ENCRYPTED) { struct dentry *fp_dentry = ecryptfs_inode_to_private(ecryptfs_inode) ->lower_file->f_dentry; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private(ecryptfs_dentry->d_sb) ->mount_crypt_stat; char filename[NAME_MAX+1] = {0}; if (fp_dentry->d_name.len <= NAME_MAX) memcpy(filename, fp_dentry->d_name.name, fp_dentry->d_name.len + 1); if ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_NEW_PASSTHROUGH) || ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_FILTERING) && (is_file_name_match(mount_crypt_stat, fp_dentry) || is_file_ext_match(mount_crypt_stat, filename)))) { crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED | ECRYPTFS_ENCRYPTED); ecryptfs_put_lower_file(ecryptfs_inode); } else { rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); if (rc) printk( KERN_ERR "Error writing headers; rc = [%d]\n" , rc); ecryptfs_put_lower_file(ecryptfs_inode); } } mutex_unlock(&crypt_stat->cs_mutex); #else rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); if (rc) printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); ecryptfs_put_lower_file(ecryptfs_inode); #endif out: return rc; }
/** * ecryptfs_open * @inode: inode speciying file to open * @file: Structure to return filled in * * Opens the file specified by inode. * * Returns zero on success; non-zero otherwise */ static int ecryptfs_open(struct inode *inode, struct file *file) { int rc = 0; struct ecryptfs_crypt_stat *crypt_stat = NULL; struct dentry *ecryptfs_dentry = file->f_path.dentry; /* Private value of ecryptfs_dentry allocated in * ecryptfs_lookup() */ struct dentry *lower_dentry; struct ecryptfs_file_info *file_info; /* Released in ecryptfs_release or end of function if failure */ file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); if (!file_info) { ecryptfs_printk(KERN_ERR, "Error attempting to allocate memory\n"); rc = -ENOMEM; goto out; } lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; mutex_lock(&crypt_stat->cs_mutex); if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) { ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); /* Policy code enabled in future release */ crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED | ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); rc = ecryptfs_get_lower_file(ecryptfs_dentry, inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out_free; } if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) { rc = -EPERM; printk(KERN_WARNING "%s: Lower file is RO; eCryptfs " "file must hence be opened RO\n", __func__); goto out_put; } ecryptfs_set_file_lower( file, ecryptfs_inode_to_private(inode)->lower_file); if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); mutex_lock(&crypt_stat->cs_mutex); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); rc = 0; goto out; } rc = read_or_initialize_metadata(ecryptfs_dentry); if (rc) goto out_put; ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = " "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, (unsigned long long)i_size_read(inode)); goto out; out_put: ecryptfs_put_lower_file(inode); out_free: kmem_cache_free(ecryptfs_file_info_cache, ecryptfs_file_to_private(file)); out: return rc; }
/** * ecryptfs_initialize_file * * Cause the file to be changed from a basic empty file to an ecryptfs * file with a header and first data page. * * Returns zero on success */ int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry, struct inode *ecryptfs_inode) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat; int rc = 0; #ifdef CONFIG_DLP sdp_fs_command_t *cmd = NULL; #endif if (S_ISDIR(ecryptfs_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); goto out; } ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); rc = ecryptfs_new_file_context(ecryptfs_inode); if (rc) { ecryptfs_printk(KERN_ERR, "Error creating new file " "context; rc = [%d]\n", rc); goto out; } rc = ecryptfs_get_lower_file(ecryptfs_dentry, ecryptfs_inode); if (rc) { printk(KERN_ERR "%s: Error attempting to initialize " "the lower file for the dentry with name " "[%s]; rc = [%d]\n", __func__, ecryptfs_dentry->d_name.name, rc); goto out; } #ifdef CONFIG_DLP if(crypt_stat->mount_crypt_stat->flags & ECRYPTFS_MOUNT_DLP_ENABLED) { #if DLP_DEBUG printk(KERN_ERR "DLP %s: file name: [%s], userid: [%d]\n", __func__, ecryptfs_dentry->d_iname, crypt_stat->mount_crypt_stat->userid); #endif if(!rc && (in_egroup_p(AID_KNOX_DLP) || in_egroup_p(AID_KNOX_DLP_RESTRICTED))) { /* TODO: Can DLP files be created while in locked state? */ struct timespec ts; crypt_stat->flags |= ECRYPTFS_DLP_ENABLED; getnstimeofday(&ts); crypt_stat->expiry.expiry_time.tv_sec = (int64_t)ts.tv_sec + 600; crypt_stat->expiry.expiry_time.tv_nsec = (int64_t)ts.tv_nsec; #if DLP_DEBUG printk(KERN_ERR "DLP %s: current->pid : %d\n", __func__, current->tgid); printk(KERN_ERR "DLP %s: crypt_stat->mount_crypt_stat->userid : %d\n", __func__, crypt_stat->mount_crypt_stat->userid); printk(KERN_ERR "DLP %s: crypt_stat->mount_crypt_stat->partition_id : %d\n", __func__, crypt_stat->mount_crypt_stat->partition_id); #endif if(in_egroup_p(AID_KNOX_DLP)) { cmd = sdp_fs_command_alloc(FSOP_DLP_FILE_INIT, current->tgid, crypt_stat->mount_crypt_stat->userid, crypt_stat->mount_crypt_stat->partition_id, ecryptfs_inode->i_ino, GFP_KERNEL); } else if(in_egroup_p(AID_KNOX_DLP_RESTRICTED)) { cmd = sdp_fs_command_alloc(FSOP_DLP_FILE_INIT_RESTRICTED, current->tgid, crypt_stat->mount_crypt_stat->userid, crypt_stat->mount_crypt_stat->partition_id, ecryptfs_inode->i_ino, GFP_KERNEL); } } else { printk(KERN_ERR "DLP %s: not in group\n", __func__); } } #endif #ifdef CONFIG_WTL_ENCRYPTION_FILTER mutex_lock(&crypt_stat->cs_mutex); if (crypt_stat->flags & ECRYPTFS_ENCRYPTED) { struct dentry *fp_dentry = ecryptfs_inode_to_private(ecryptfs_inode) ->lower_file->f_dentry; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private(ecryptfs_dentry->d_sb) ->mount_crypt_stat; char filename[NAME_MAX+1] = {0}; if (fp_dentry->d_name.len <= NAME_MAX) memcpy(filename, fp_dentry->d_name.name, fp_dentry->d_name.len + 1); if ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_NEW_PASSTHROUGH) || ((mount_crypt_stat->flags & ECRYPTFS_ENABLE_FILTERING) && (is_file_name_match(mount_crypt_stat, fp_dentry) || is_file_ext_match(mount_crypt_stat, filename)))) { crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED | ECRYPTFS_ENCRYPTED); ecryptfs_put_lower_file(ecryptfs_inode); } else { rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); if (rc) printk( KERN_ERR "Error writing headers; rc = [%d]\n" , rc); ecryptfs_put_lower_file(ecryptfs_inode); } } mutex_unlock(&crypt_stat->cs_mutex); #else rc = ecryptfs_write_metadata(ecryptfs_dentry, ecryptfs_inode); if (rc) printk(KERN_ERR "Error writing headers; rc = [%d]\n", rc); ecryptfs_put_lower_file(ecryptfs_inode); #endif out: #ifdef CONFIG_DLP if(cmd) { sdp_fs_request(cmd, NULL); sdp_fs_command_free(cmd); } #endif return rc; }