- Fixes a bug when the lower filesystem mount options include 'acl', but the
eCryptfs mount options do not - Cleanups in the messaging code - Better handling of empty files in the lower filesystem to improve usability. Failed file creations are now cleaned up and empty lower files are converted into eCryptfs during open(). - The write-through cache changes are being reverted due to bugs that are not easy to fix. Stability outweighs the performance enhancements here. - Improvement to the mount code to catch unsupported ciphers specified in the mount options -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABCgAGBQJQGhVWAAoJENaSAD2qAscKjvcQAMgF66sl8KjwzFCgojh30a4u 1hCXltxUCLjXxjXxyygUHb/pH0xdvC+Ss3FTtsPXAjgYm2lXjjoOmVG8WAvwHHx1 2ZjDo+8fQ4XA8Rl9kYuvt/abF0IssNRK3csTWplR7lpoQ8AWbkpkag1I4WZhibey cgs/zECl8ACTJ5zQ+AyRGnrssq4jI7xZAKWLK0+KKk7S9yIRI7K/xdz1xK39jGK6 N09Dw3VWY/bMcMq77ZXBtyHdP7KR7wKUtCeQttmCvdf20Ocy6AXzr1FRKvUxionF Sf31tJim0u9OO8hmy8cjCyWEy9LHnXnSd/5vn+Qd9ok9GvuiYmKw07rbXi/gjhBX ai5PKtl05WiQgp80BybUYfIY1Hq71MsppNi6h9Zgiid5rEvWWvCBWBWP95G8DTmC 6TwLaCG0rh8uuZyeiVrs3xZQ2IG5Zmu0CX3XGyfsaLvqmQWhtT5ZQVMeMQEEBxyQ ur9SSU2O/nC8ceLB7fzGmZPTLZUWOuYQnd24NJNK+7j0P+Km7pqmDYpCdwmFpx3C CQ0gGaJGHeycvBF327bwxPmsPdO4fy+nmEL8vrEXPTyQ3ZVAPvxZK9t8Jpk4UFOl JSTWFiK0mvgE+5dX2kB0nzN7iD7hcMgmozht50qQP3OUkI1kkBrEHgHVO3KzgUIA +aRAljeLdelq44JBxjiB =4vDd -----END PGP SIGNATURE----- Merge tag 'ecryptfs-3.6-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs Pull ecryptfs fixes from Tyler Hicks: - Fixes a bug when the lower filesystem mount options include 'acl', but the eCryptfs mount options do not - Cleanups in the messaging code - Better handling of empty files in the lower filesystem to improve usability. Failed file creations are now cleaned up and empty lower files are converted into eCryptfs during open(). - The write-through cache changes are being reverted due to bugs that are not easy to fix. Stability outweighs the performance enhancements here. - Improvement to the mount code to catch unsupported ciphers specified in the mount options * tag 'ecryptfs-3.6-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs: eCryptfs: check for eCryptfs cipher support at mount eCryptfs: Revert to a writethrough cache model eCryptfs: Initialize empty lower files when opening them eCryptfs: Unlink lower inode when ecryptfs_create() fails eCryptfs: Make all miscdev functions use daemon ptr in file private_data eCryptfs: Remove unused messaging declarations and function eCryptfs: Copy up POSIX ACL and read-only flags from lower mount
This commit is contained in:
Коммит
410fc4ce8a
|
@ -385,8 +385,6 @@ struct ecryptfs_msg_ctx {
|
||||||
struct mutex mux;
|
struct mutex mux;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ecryptfs_daemon;
|
|
||||||
|
|
||||||
struct ecryptfs_daemon {
|
struct ecryptfs_daemon {
|
||||||
#define ECRYPTFS_DAEMON_IN_READ 0x00000001
|
#define ECRYPTFS_DAEMON_IN_READ 0x00000001
|
||||||
#define ECRYPTFS_DAEMON_IN_POLL 0x00000002
|
#define ECRYPTFS_DAEMON_IN_POLL 0x00000002
|
||||||
|
@ -394,10 +392,7 @@ struct ecryptfs_daemon {
|
||||||
#define ECRYPTFS_DAEMON_MISCDEV_OPEN 0x00000008
|
#define ECRYPTFS_DAEMON_MISCDEV_OPEN 0x00000008
|
||||||
u32 flags;
|
u32 flags;
|
||||||
u32 num_queued_msg_ctx;
|
u32 num_queued_msg_ctx;
|
||||||
struct pid *pid;
|
struct file *file;
|
||||||
uid_t euid;
|
|
||||||
struct user_namespace *user_ns;
|
|
||||||
struct task_struct *task;
|
|
||||||
struct mutex mux;
|
struct mutex mux;
|
||||||
struct list_head msg_ctx_out_queue;
|
struct list_head msg_ctx_out_queue;
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
|
@ -554,6 +549,8 @@ extern struct kmem_cache *ecryptfs_key_tfm_cache;
|
||||||
struct inode *ecryptfs_get_inode(struct inode *lower_inode,
|
struct inode *ecryptfs_get_inode(struct inode *lower_inode,
|
||||||
struct super_block *sb);
|
struct super_block *sb);
|
||||||
void ecryptfs_i_size_init(const char *page_virt, struct inode *inode);
|
void ecryptfs_i_size_init(const char *page_virt, struct inode *inode);
|
||||||
|
int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
|
||||||
|
struct inode *ecryptfs_inode);
|
||||||
int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,
|
int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,
|
||||||
size_t *decrypted_name_size,
|
size_t *decrypted_name_size,
|
||||||
struct dentry *ecryptfs_dentry,
|
struct dentry *ecryptfs_dentry,
|
||||||
|
@ -607,13 +604,8 @@ int
|
||||||
ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
||||||
size_t size, int flags);
|
size_t size, int flags);
|
||||||
int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode);
|
int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode);
|
||||||
int ecryptfs_process_helo(uid_t euid, struct user_namespace *user_ns,
|
int ecryptfs_process_response(struct ecryptfs_daemon *daemon,
|
||||||
struct pid *pid);
|
struct ecryptfs_message *msg, u32 seq);
|
||||||
int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,
|
|
||||||
struct pid *pid);
|
|
||||||
int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
|
|
||||||
struct user_namespace *user_ns, struct pid *pid,
|
|
||||||
u32 seq);
|
|
||||||
int ecryptfs_send_message(char *data, int data_len,
|
int ecryptfs_send_message(char *data, int data_len,
|
||||||
struct ecryptfs_msg_ctx **msg_ctx);
|
struct ecryptfs_msg_ctx **msg_ctx);
|
||||||
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
|
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
|
||||||
|
@ -658,8 +650,7 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
|
||||||
struct inode *ecryptfs_inode);
|
struct inode *ecryptfs_inode);
|
||||||
struct page *ecryptfs_get_locked_page(struct inode *inode, loff_t index);
|
struct page *ecryptfs_get_locked_page(struct inode *inode, loff_t index);
|
||||||
int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon);
|
int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon);
|
||||||
int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid,
|
int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon);
|
||||||
struct user_namespace *user_ns);
|
|
||||||
int ecryptfs_parse_packet_length(unsigned char *data, size_t *size,
|
int ecryptfs_parse_packet_length(unsigned char *data, size_t *size,
|
||||||
size_t *length_size);
|
size_t *length_size);
|
||||||
int ecryptfs_write_packet_length(char *dest, size_t size,
|
int ecryptfs_write_packet_length(char *dest, size_t size,
|
||||||
|
@ -671,8 +662,7 @@ int ecryptfs_send_miscdev(char *data, size_t data_size,
|
||||||
u16 msg_flags, struct ecryptfs_daemon *daemon);
|
u16 msg_flags, struct ecryptfs_daemon *daemon);
|
||||||
void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx);
|
void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx);
|
||||||
int
|
int
|
||||||
ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,
|
ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, struct file *file);
|
||||||
struct user_namespace *user_ns, struct pid *pid);
|
|
||||||
int ecryptfs_init_kthread(void);
|
int ecryptfs_init_kthread(void);
|
||||||
void ecryptfs_destroy_kthread(void);
|
void ecryptfs_destroy_kthread(void);
|
||||||
int ecryptfs_privileged_open(struct file **lower_file,
|
int ecryptfs_privileged_open(struct file **lower_file,
|
||||||
|
|
|
@ -138,29 +138,50 @@ out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ecryptfs_vma_close(struct vm_area_struct *vma)
|
struct kmem_cache *ecryptfs_file_info_cache;
|
||||||
{
|
|
||||||
filemap_write_and_wait(vma->vm_file->f_mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct vm_operations_struct ecryptfs_file_vm_ops = {
|
static int read_or_initialize_metadata(struct dentry *dentry)
|
||||||
.close = ecryptfs_vma_close,
|
|
||||||
.fault = filemap_fault,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int ecryptfs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
|
||||||
{
|
{
|
||||||
|
struct inode *inode = dentry->d_inode;
|
||||||
|
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
|
||||||
|
struct ecryptfs_crypt_stat *crypt_stat;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = generic_file_mmap(file, vma);
|
crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
|
||||||
if (!rc)
|
mount_crypt_stat = &ecryptfs_superblock_to_private(
|
||||||
vma->vm_ops = &ecryptfs_file_vm_ops;
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct kmem_cache *ecryptfs_file_info_cache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ecryptfs_open
|
* ecryptfs_open
|
||||||
* @inode: inode speciying file to open
|
* @inode: inode speciying file to open
|
||||||
|
@ -236,32 +257,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
|
||||||
rc = 0;
|
rc = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
mutex_lock(&crypt_stat->cs_mutex);
|
rc = read_or_initialize_metadata(ecryptfs_dentry);
|
||||||
if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
|
if (rc)
|
||||||
|| !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) {
|
goto out_put;
|
||||||
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 = "
|
ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = "
|
||||||
"[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino,
|
"[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino,
|
||||||
(unsigned long long)i_size_read(inode));
|
(unsigned long long)i_size_read(inode));
|
||||||
|
@ -292,15 +290,7 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
|
||||||
static int
|
static int
|
||||||
ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
ecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
return vfs_fsync(ecryptfs_file_to_lower(file), datasync);
|
||||||
|
|
||||||
rc = generic_file_fsync(file, start, end, datasync);
|
|
||||||
if (rc)
|
|
||||||
goto out;
|
|
||||||
rc = vfs_fsync_range(ecryptfs_file_to_lower(file), start, end,
|
|
||||||
datasync);
|
|
||||||
out:
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ecryptfs_fasync(int fd, struct file *file, int flag)
|
static int ecryptfs_fasync(int fd, struct file *file, int flag)
|
||||||
|
@ -369,7 +359,7 @@ const struct file_operations ecryptfs_main_fops = {
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
.compat_ioctl = ecryptfs_compat_ioctl,
|
.compat_ioctl = ecryptfs_compat_ioctl,
|
||||||
#endif
|
#endif
|
||||||
.mmap = ecryptfs_file_mmap,
|
.mmap = generic_file_mmap,
|
||||||
.open = ecryptfs_open,
|
.open = ecryptfs_open,
|
||||||
.flush = ecryptfs_flush,
|
.flush = ecryptfs_flush,
|
||||||
.release = ecryptfs_release,
|
.release = ecryptfs_release,
|
||||||
|
|
|
@ -143,6 +143,31 @@ static int ecryptfs_interpose(struct dentry *lower_dentry,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry,
|
||||||
|
struct inode *inode)
|
||||||
|
{
|
||||||
|
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||||
|
struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
|
||||||
|
struct dentry *lower_dir_dentry;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
dget(lower_dentry);
|
||||||
|
lower_dir_dentry = lock_parent(lower_dentry);
|
||||||
|
rc = vfs_unlink(lower_dir_inode, lower_dentry);
|
||||||
|
if (rc) {
|
||||||
|
printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
fsstack_copy_attr_times(dir, lower_dir_inode);
|
||||||
|
set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink);
|
||||||
|
inode->i_ctime = dir->i_ctime;
|
||||||
|
d_drop(dentry);
|
||||||
|
out_unlock:
|
||||||
|
unlock_dir(lower_dir_dentry);
|
||||||
|
dput(lower_dentry);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ecryptfs_do_create
|
* ecryptfs_do_create
|
||||||
* @directory_inode: inode of the new file's dentry's parent in ecryptfs
|
* @directory_inode: inode of the new file's dentry's parent in ecryptfs
|
||||||
|
@ -182,8 +207,10 @@ ecryptfs_do_create(struct inode *directory_inode,
|
||||||
}
|
}
|
||||||
inode = __ecryptfs_get_inode(lower_dentry->d_inode,
|
inode = __ecryptfs_get_inode(lower_dentry->d_inode,
|
||||||
directory_inode->i_sb);
|
directory_inode->i_sb);
|
||||||
if (IS_ERR(inode))
|
if (IS_ERR(inode)) {
|
||||||
|
vfs_unlink(lower_dir_dentry->d_inode, lower_dentry);
|
||||||
goto out_lock;
|
goto out_lock;
|
||||||
|
}
|
||||||
fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode);
|
fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode);
|
||||||
fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode);
|
fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode);
|
||||||
out_lock:
|
out_lock:
|
||||||
|
@ -200,8 +227,8 @@ out:
|
||||||
*
|
*
|
||||||
* Returns zero on success
|
* Returns zero on success
|
||||||
*/
|
*/
|
||||||
static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
|
int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry,
|
||||||
struct inode *ecryptfs_inode)
|
struct inode *ecryptfs_inode)
|
||||||
{
|
{
|
||||||
struct ecryptfs_crypt_stat *crypt_stat =
|
struct ecryptfs_crypt_stat *crypt_stat =
|
||||||
&ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
|
&ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
|
||||||
|
@ -264,7 +291,9 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
|
||||||
* that this on disk file is prepared to be an ecryptfs file */
|
* that this on disk file is prepared to be an ecryptfs file */
|
||||||
rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode);
|
rc = ecryptfs_initialize_file(ecryptfs_dentry, ecryptfs_inode);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
drop_nlink(ecryptfs_inode);
|
ecryptfs_do_unlink(directory_inode, ecryptfs_dentry,
|
||||||
|
ecryptfs_inode);
|
||||||
|
make_bad_inode(ecryptfs_inode);
|
||||||
unlock_new_inode(ecryptfs_inode);
|
unlock_new_inode(ecryptfs_inode);
|
||||||
iput(ecryptfs_inode);
|
iput(ecryptfs_inode);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -466,27 +495,7 @@ out_lock:
|
||||||
|
|
||||||
static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
|
static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
return ecryptfs_do_unlink(dir, dentry, dentry->d_inode);
|
||||||
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
|
||||||
struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
|
|
||||||
struct dentry *lower_dir_dentry;
|
|
||||||
|
|
||||||
dget(lower_dentry);
|
|
||||||
lower_dir_dentry = lock_parent(lower_dentry);
|
|
||||||
rc = vfs_unlink(lower_dir_inode, lower_dentry);
|
|
||||||
if (rc) {
|
|
||||||
printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
fsstack_copy_attr_times(dir, lower_dir_inode);
|
|
||||||
set_nlink(dentry->d_inode,
|
|
||||||
ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink);
|
|
||||||
dentry->d_inode->i_ctime = dir->i_ctime;
|
|
||||||
d_drop(dentry);
|
|
||||||
out_unlock:
|
|
||||||
unlock_dir(lower_dir_dentry);
|
|
||||||
dput(lower_dentry);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
|
static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
|
||||||
|
@ -961,12 +970,6 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S_ISREG(inode->i_mode)) {
|
|
||||||
rc = filemap_write_and_wait(inode->i_mapping);
|
|
||||||
if (rc)
|
|
||||||
goto out;
|
|
||||||
fsstack_copy_attr_all(inode, lower_inode);
|
|
||||||
}
|
|
||||||
memcpy(&lower_ia, ia, sizeof(lower_ia));
|
memcpy(&lower_ia, ia, sizeof(lower_ia));
|
||||||
if (ia->ia_valid & ATTR_FILE)
|
if (ia->ia_valid & ATTR_FILE)
|
||||||
lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file);
|
lower_ia.ia_file = ecryptfs_file_to_lower(ia->ia_file);
|
||||||
|
|
|
@ -279,6 +279,7 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
|
||||||
char *fnek_src;
|
char *fnek_src;
|
||||||
char *cipher_key_bytes_src;
|
char *cipher_key_bytes_src;
|
||||||
char *fn_cipher_key_bytes_src;
|
char *fn_cipher_key_bytes_src;
|
||||||
|
u8 cipher_code;
|
||||||
|
|
||||||
*check_ruid = 0;
|
*check_ruid = 0;
|
||||||
|
|
||||||
|
@ -420,6 +421,18 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
|
||||||
&& !fn_cipher_key_bytes_set)
|
&& !fn_cipher_key_bytes_set)
|
||||||
mount_crypt_stat->global_default_fn_cipher_key_bytes =
|
mount_crypt_stat->global_default_fn_cipher_key_bytes =
|
||||||
mount_crypt_stat->global_default_cipher_key_size;
|
mount_crypt_stat->global_default_cipher_key_size;
|
||||||
|
|
||||||
|
cipher_code = ecryptfs_code_for_cipher_string(
|
||||||
|
mount_crypt_stat->global_default_cipher_name,
|
||||||
|
mount_crypt_stat->global_default_cipher_key_size);
|
||||||
|
if (!cipher_code) {
|
||||||
|
ecryptfs_printk(KERN_ERR,
|
||||||
|
"eCryptfs doesn't support cipher: %s",
|
||||||
|
mount_crypt_stat->global_default_cipher_name);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&key_tfm_list_mutex);
|
mutex_lock(&key_tfm_list_mutex);
|
||||||
if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name,
|
if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name,
|
||||||
NULL)) {
|
NULL)) {
|
||||||
|
@ -540,6 +553,15 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
|
||||||
}
|
}
|
||||||
|
|
||||||
ecryptfs_set_superblock_lower(s, path.dentry->d_sb);
|
ecryptfs_set_superblock_lower(s, path.dentry->d_sb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the POSIX ACL flag based on whether they're enabled in the lower
|
||||||
|
* mount. Force a read-only eCryptfs mount if the lower mount is ro.
|
||||||
|
* Allow a ro eCryptfs mount even when the lower mount is rw.
|
||||||
|
*/
|
||||||
|
s->s_flags = flags & ~MS_POSIXACL;
|
||||||
|
s->s_flags |= path.dentry->d_sb->s_flags & (MS_RDONLY | MS_POSIXACL);
|
||||||
|
|
||||||
s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
|
s->s_maxbytes = path.dentry->d_sb->s_maxbytes;
|
||||||
s->s_blocksize = path.dentry->d_sb->s_blocksize;
|
s->s_blocksize = path.dentry->d_sb->s_blocksize;
|
||||||
s->s_magic = ECRYPTFS_SUPER_MAGIC;
|
s->s_magic = ECRYPTFS_SUPER_MAGIC;
|
||||||
|
|
|
@ -32,8 +32,8 @@ static struct mutex ecryptfs_msg_ctx_lists_mux;
|
||||||
static struct hlist_head *ecryptfs_daemon_hash;
|
static struct hlist_head *ecryptfs_daemon_hash;
|
||||||
struct mutex ecryptfs_daemon_hash_mux;
|
struct mutex ecryptfs_daemon_hash_mux;
|
||||||
static int ecryptfs_hash_bits;
|
static int ecryptfs_hash_bits;
|
||||||
#define ecryptfs_uid_hash(uid) \
|
#define ecryptfs_current_euid_hash(uid) \
|
||||||
hash_long((unsigned long)uid, ecryptfs_hash_bits)
|
hash_long((unsigned long)current_euid(), ecryptfs_hash_bits)
|
||||||
|
|
||||||
static u32 ecryptfs_msg_counter;
|
static u32 ecryptfs_msg_counter;
|
||||||
static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
|
static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
|
||||||
|
@ -105,26 +105,24 @@ void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ecryptfs_find_daemon_by_euid
|
* ecryptfs_find_daemon_by_euid
|
||||||
* @euid: The effective user id which maps to the desired daemon id
|
|
||||||
* @user_ns: The namespace in which @euid applies
|
|
||||||
* @daemon: If return value is zero, points to the desired daemon pointer
|
* @daemon: If return value is zero, points to the desired daemon pointer
|
||||||
*
|
*
|
||||||
* Must be called with ecryptfs_daemon_hash_mux held.
|
* Must be called with ecryptfs_daemon_hash_mux held.
|
||||||
*
|
*
|
||||||
* Search the hash list for the given user id.
|
* Search the hash list for the current effective user id.
|
||||||
*
|
*
|
||||||
* Returns zero if the user id exists in the list; non-zero otherwise.
|
* Returns zero if the user id exists in the list; non-zero otherwise.
|
||||||
*/
|
*/
|
||||||
int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid,
|
int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon)
|
||||||
struct user_namespace *user_ns)
|
|
||||||
{
|
{
|
||||||
struct hlist_node *elem;
|
struct hlist_node *elem;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
hlist_for_each_entry(*daemon, elem,
|
hlist_for_each_entry(*daemon, elem,
|
||||||
&ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)],
|
&ecryptfs_daemon_hash[ecryptfs_current_euid_hash()],
|
||||||
euid_chain) {
|
euid_chain) {
|
||||||
if ((*daemon)->euid == euid && (*daemon)->user_ns == user_ns) {
|
if ((*daemon)->file->f_cred->euid == current_euid() &&
|
||||||
|
(*daemon)->file->f_cred->user_ns == current_user_ns()) {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -137,9 +135,7 @@ out:
|
||||||
/**
|
/**
|
||||||
* ecryptfs_spawn_daemon - Create and initialize a new daemon struct
|
* ecryptfs_spawn_daemon - Create and initialize a new daemon struct
|
||||||
* @daemon: Pointer to set to newly allocated daemon struct
|
* @daemon: Pointer to set to newly allocated daemon struct
|
||||||
* @euid: Effective user id for the daemon
|
* @file: File used when opening /dev/ecryptfs
|
||||||
* @user_ns: The namespace in which @euid applies
|
|
||||||
* @pid: Process id for the daemon
|
|
||||||
*
|
*
|
||||||
* Must be called ceremoniously while in possession of
|
* Must be called ceremoniously while in possession of
|
||||||
* ecryptfs_sacred_daemon_hash_mux
|
* ecryptfs_sacred_daemon_hash_mux
|
||||||
|
@ -147,8 +143,7 @@ out:
|
||||||
* Returns zero on success; non-zero otherwise
|
* Returns zero on success; non-zero otherwise
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,
|
ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, struct file *file)
|
||||||
struct user_namespace *user_ns, struct pid *pid)
|
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
@ -159,16 +154,13 @@ ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,
|
||||||
"GFP_KERNEL memory\n", __func__, sizeof(**daemon));
|
"GFP_KERNEL memory\n", __func__, sizeof(**daemon));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
(*daemon)->euid = euid;
|
(*daemon)->file = file;
|
||||||
(*daemon)->user_ns = get_user_ns(user_ns);
|
|
||||||
(*daemon)->pid = get_pid(pid);
|
|
||||||
(*daemon)->task = current;
|
|
||||||
mutex_init(&(*daemon)->mux);
|
mutex_init(&(*daemon)->mux);
|
||||||
INIT_LIST_HEAD(&(*daemon)->msg_ctx_out_queue);
|
INIT_LIST_HEAD(&(*daemon)->msg_ctx_out_queue);
|
||||||
init_waitqueue_head(&(*daemon)->wait);
|
init_waitqueue_head(&(*daemon)->wait);
|
||||||
(*daemon)->num_queued_msg_ctx = 0;
|
(*daemon)->num_queued_msg_ctx = 0;
|
||||||
hlist_add_head(&(*daemon)->euid_chain,
|
hlist_add_head(&(*daemon)->euid_chain,
|
||||||
&ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)]);
|
&ecryptfs_daemon_hash[ecryptfs_current_euid_hash()]);
|
||||||
out:
|
out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -188,9 +180,6 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
|
||||||
if ((daemon->flags & ECRYPTFS_DAEMON_IN_READ)
|
if ((daemon->flags & ECRYPTFS_DAEMON_IN_READ)
|
||||||
|| (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)) {
|
|| (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)) {
|
||||||
rc = -EBUSY;
|
rc = -EBUSY;
|
||||||
printk(KERN_WARNING "%s: Attempt to destroy daemon with pid "
|
|
||||||
"[0x%p], but it is in the midst of a read or a poll\n",
|
|
||||||
__func__, daemon->pid);
|
|
||||||
mutex_unlock(&daemon->mux);
|
mutex_unlock(&daemon->mux);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -203,55 +192,16 @@ int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
|
||||||
ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
|
ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
|
||||||
}
|
}
|
||||||
hlist_del(&daemon->euid_chain);
|
hlist_del(&daemon->euid_chain);
|
||||||
if (daemon->task)
|
|
||||||
wake_up_process(daemon->task);
|
|
||||||
if (daemon->pid)
|
|
||||||
put_pid(daemon->pid);
|
|
||||||
if (daemon->user_ns)
|
|
||||||
put_user_ns(daemon->user_ns);
|
|
||||||
mutex_unlock(&daemon->mux);
|
mutex_unlock(&daemon->mux);
|
||||||
kzfree(daemon);
|
kzfree(daemon);
|
||||||
out:
|
out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ecryptfs_process_quit
|
|
||||||
* @euid: The user ID owner of the message
|
|
||||||
* @user_ns: The namespace in which @euid applies
|
|
||||||
* @pid: The process ID for the userspace program that sent the
|
|
||||||
* message
|
|
||||||
*
|
|
||||||
* Deletes the corresponding daemon for the given euid and pid, if
|
|
||||||
* it is the registered that is requesting the deletion. Returns zero
|
|
||||||
* after deleting the desired daemon; non-zero otherwise.
|
|
||||||
*/
|
|
||||||
int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,
|
|
||||||
struct pid *pid)
|
|
||||||
{
|
|
||||||
struct ecryptfs_daemon *daemon;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
mutex_lock(&ecryptfs_daemon_hash_mux);
|
|
||||||
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, user_ns);
|
|
||||||
if (rc || !daemon) {
|
|
||||||
rc = -EINVAL;
|
|
||||||
printk(KERN_ERR "Received request from user [%d] to "
|
|
||||||
"unregister unrecognized daemon [0x%p]\n", euid, pid);
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
rc = ecryptfs_exorcise_daemon(daemon);
|
|
||||||
out_unlock:
|
|
||||||
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ecryptfs_process_reponse
|
* ecryptfs_process_reponse
|
||||||
* @msg: The ecryptfs message received; the caller should sanity check
|
* @msg: The ecryptfs message received; the caller should sanity check
|
||||||
* msg->data_len and free the memory
|
* msg->data_len and free the memory
|
||||||
* @pid: The process ID of the userspace application that sent the
|
|
||||||
* message
|
|
||||||
* @seq: The sequence number of the message; must match the sequence
|
* @seq: The sequence number of the message; must match the sequence
|
||||||
* number for the existing message context waiting for this
|
* number for the existing message context waiting for this
|
||||||
* response
|
* response
|
||||||
|
@ -270,16 +220,11 @@ out_unlock:
|
||||||
*
|
*
|
||||||
* Returns zero on success; non-zero otherwise
|
* Returns zero on success; non-zero otherwise
|
||||||
*/
|
*/
|
||||||
int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
|
int ecryptfs_process_response(struct ecryptfs_daemon *daemon,
|
||||||
struct user_namespace *user_ns, struct pid *pid,
|
struct ecryptfs_message *msg, u32 seq)
|
||||||
u32 seq)
|
|
||||||
{
|
{
|
||||||
struct ecryptfs_daemon *uninitialized_var(daemon);
|
|
||||||
struct ecryptfs_msg_ctx *msg_ctx;
|
struct ecryptfs_msg_ctx *msg_ctx;
|
||||||
size_t msg_size;
|
size_t msg_size;
|
||||||
struct nsproxy *nsproxy;
|
|
||||||
struct user_namespace *tsk_user_ns;
|
|
||||||
uid_t ctx_euid;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (msg->index >= ecryptfs_message_buf_len) {
|
if (msg->index >= ecryptfs_message_buf_len) {
|
||||||
|
@ -292,51 +237,6 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
|
||||||
}
|
}
|
||||||
msg_ctx = &ecryptfs_msg_ctx_arr[msg->index];
|
msg_ctx = &ecryptfs_msg_ctx_arr[msg->index];
|
||||||
mutex_lock(&msg_ctx->mux);
|
mutex_lock(&msg_ctx->mux);
|
||||||
mutex_lock(&ecryptfs_daemon_hash_mux);
|
|
||||||
rcu_read_lock();
|
|
||||||
nsproxy = task_nsproxy(msg_ctx->task);
|
|
||||||
if (nsproxy == NULL) {
|
|
||||||
rc = -EBADMSG;
|
|
||||||
printk(KERN_ERR "%s: Receiving process is a zombie. Dropping "
|
|
||||||
"message.\n", __func__);
|
|
||||||
rcu_read_unlock();
|
|
||||||
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
|
||||||
goto wake_up;
|
|
||||||
}
|
|
||||||
tsk_user_ns = __task_cred(msg_ctx->task)->user_ns;
|
|
||||||
ctx_euid = task_euid(msg_ctx->task);
|
|
||||||
rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns);
|
|
||||||
rcu_read_unlock();
|
|
||||||
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
|
||||||
if (rc) {
|
|
||||||
rc = -EBADMSG;
|
|
||||||
printk(KERN_WARNING "%s: User [%d] received a "
|
|
||||||
"message response from process [0x%p] but does "
|
|
||||||
"not have a registered daemon\n", __func__,
|
|
||||||
ctx_euid, pid);
|
|
||||||
goto wake_up;
|
|
||||||
}
|
|
||||||
if (ctx_euid != euid) {
|
|
||||||
rc = -EBADMSG;
|
|
||||||
printk(KERN_WARNING "%s: Received message from user "
|
|
||||||
"[%d]; expected message from user [%d]\n", __func__,
|
|
||||||
euid, ctx_euid);
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
if (tsk_user_ns != user_ns) {
|
|
||||||
rc = -EBADMSG;
|
|
||||||
printk(KERN_WARNING "%s: Received message from user_ns "
|
|
||||||
"[0x%p]; expected message from user_ns [0x%p]\n",
|
|
||||||
__func__, user_ns, tsk_user_ns);
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
if (daemon->pid != pid) {
|
|
||||||
rc = -EBADMSG;
|
|
||||||
printk(KERN_ERR "%s: User [%d] sent a message response "
|
|
||||||
"from an unrecognized process [0x%p]\n",
|
|
||||||
__func__, ctx_euid, pid);
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
|
if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
printk(KERN_WARNING "%s: Desired context element is not "
|
printk(KERN_WARNING "%s: Desired context element is not "
|
||||||
|
@ -359,9 +259,8 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
|
||||||
}
|
}
|
||||||
memcpy(msg_ctx->msg, msg, msg_size);
|
memcpy(msg_ctx->msg, msg, msg_size);
|
||||||
msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE;
|
msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE;
|
||||||
rc = 0;
|
|
||||||
wake_up:
|
|
||||||
wake_up_process(msg_ctx->task);
|
wake_up_process(msg_ctx->task);
|
||||||
|
rc = 0;
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&msg_ctx->mux);
|
mutex_unlock(&msg_ctx->mux);
|
||||||
out:
|
out:
|
||||||
|
@ -383,14 +282,11 @@ ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,
|
||||||
struct ecryptfs_msg_ctx **msg_ctx)
|
struct ecryptfs_msg_ctx **msg_ctx)
|
||||||
{
|
{
|
||||||
struct ecryptfs_daemon *daemon;
|
struct ecryptfs_daemon *daemon;
|
||||||
uid_t euid = current_euid();
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
|
rc = ecryptfs_find_daemon_by_euid(&daemon);
|
||||||
if (rc || !daemon) {
|
if (rc || !daemon) {
|
||||||
rc = -ENOTCONN;
|
rc = -ENOTCONN;
|
||||||
printk(KERN_ERR "%s: User [%d] does not have a daemon "
|
|
||||||
"registered\n", __func__, euid);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
|
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
|
||||||
|
|
|
@ -33,7 +33,7 @@ static atomic_t ecryptfs_num_miscdev_opens;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ecryptfs_miscdev_poll
|
* ecryptfs_miscdev_poll
|
||||||
* @file: dev file (ignored)
|
* @file: dev file
|
||||||
* @pt: dev poll table (ignored)
|
* @pt: dev poll table (ignored)
|
||||||
*
|
*
|
||||||
* Returns the poll mask
|
* Returns the poll mask
|
||||||
|
@ -41,20 +41,10 @@ static atomic_t ecryptfs_num_miscdev_opens;
|
||||||
static unsigned int
|
static unsigned int
|
||||||
ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
|
ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
|
||||||
{
|
{
|
||||||
struct ecryptfs_daemon *daemon;
|
struct ecryptfs_daemon *daemon = file->private_data;
|
||||||
unsigned int mask = 0;
|
unsigned int mask = 0;
|
||||||
uid_t euid = current_euid();
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
mutex_lock(&ecryptfs_daemon_hash_mux);
|
|
||||||
/* TODO: Just use file->private_data? */
|
|
||||||
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
|
|
||||||
if (rc || !daemon) {
|
|
||||||
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
mutex_lock(&daemon->mux);
|
mutex_lock(&daemon->mux);
|
||||||
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
|
||||||
if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
|
if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
|
||||||
printk(KERN_WARNING "%s: Attempt to poll on zombified "
|
printk(KERN_WARNING "%s: Attempt to poll on zombified "
|
||||||
"daemon\n", __func__);
|
"daemon\n", __func__);
|
||||||
|
@ -79,7 +69,7 @@ out_unlock_daemon:
|
||||||
/**
|
/**
|
||||||
* ecryptfs_miscdev_open
|
* ecryptfs_miscdev_open
|
||||||
* @inode: inode of miscdev handle (ignored)
|
* @inode: inode of miscdev handle (ignored)
|
||||||
* @file: file for miscdev handle (ignored)
|
* @file: file for miscdev handle
|
||||||
*
|
*
|
||||||
* Returns zero on success; non-zero otherwise
|
* Returns zero on success; non-zero otherwise
|
||||||
*/
|
*/
|
||||||
|
@ -87,7 +77,6 @@ static int
|
||||||
ecryptfs_miscdev_open(struct inode *inode, struct file *file)
|
ecryptfs_miscdev_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct ecryptfs_daemon *daemon = NULL;
|
struct ecryptfs_daemon *daemon = NULL;
|
||||||
uid_t euid = current_euid();
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
mutex_lock(&ecryptfs_daemon_hash_mux);
|
mutex_lock(&ecryptfs_daemon_hash_mux);
|
||||||
|
@ -98,30 +87,20 @@ ecryptfs_miscdev_open(struct inode *inode, struct file *file)
|
||||||
"count; rc = [%d]\n", __func__, rc);
|
"count; rc = [%d]\n", __func__, rc);
|
||||||
goto out_unlock_daemon_list;
|
goto out_unlock_daemon_list;
|
||||||
}
|
}
|
||||||
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
|
rc = ecryptfs_find_daemon_by_euid(&daemon);
|
||||||
if (rc || !daemon) {
|
if (!rc) {
|
||||||
rc = ecryptfs_spawn_daemon(&daemon, euid, current_user_ns(),
|
rc = -EINVAL;
|
||||||
task_pid(current));
|
goto out_unlock_daemon_list;
|
||||||
if (rc) {
|
}
|
||||||
printk(KERN_ERR "%s: Error attempting to spawn daemon; "
|
rc = ecryptfs_spawn_daemon(&daemon, file);
|
||||||
"rc = [%d]\n", __func__, rc);
|
if (rc) {
|
||||||
goto out_module_put_unlock_daemon_list;
|
printk(KERN_ERR "%s: Error attempting to spawn daemon; "
|
||||||
}
|
"rc = [%d]\n", __func__, rc);
|
||||||
|
goto out_module_put_unlock_daemon_list;
|
||||||
}
|
}
|
||||||
mutex_lock(&daemon->mux);
|
mutex_lock(&daemon->mux);
|
||||||
if (daemon->pid != task_pid(current)) {
|
|
||||||
rc = -EINVAL;
|
|
||||||
printk(KERN_ERR "%s: pid [0x%p] has registered with euid [%d], "
|
|
||||||
"but pid [0x%p] has attempted to open the handle "
|
|
||||||
"instead\n", __func__, daemon->pid, daemon->euid,
|
|
||||||
task_pid(current));
|
|
||||||
goto out_unlock_daemon;
|
|
||||||
}
|
|
||||||
if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
|
if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
|
||||||
rc = -EBUSY;
|
rc = -EBUSY;
|
||||||
printk(KERN_ERR "%s: Miscellaneous device handle may only be "
|
|
||||||
"opened once per daemon; pid [0x%p] already has this "
|
|
||||||
"handle open\n", __func__, daemon->pid);
|
|
||||||
goto out_unlock_daemon;
|
goto out_unlock_daemon;
|
||||||
}
|
}
|
||||||
daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
|
daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
|
||||||
|
@ -140,7 +119,7 @@ out_unlock_daemon_list:
|
||||||
/**
|
/**
|
||||||
* ecryptfs_miscdev_release
|
* ecryptfs_miscdev_release
|
||||||
* @inode: inode of fs/ecryptfs/euid handle (ignored)
|
* @inode: inode of fs/ecryptfs/euid handle (ignored)
|
||||||
* @file: file for fs/ecryptfs/euid handle (ignored)
|
* @file: file for fs/ecryptfs/euid handle
|
||||||
*
|
*
|
||||||
* This keeps the daemon registered until the daemon sends another
|
* This keeps the daemon registered until the daemon sends another
|
||||||
* ioctl to fs/ecryptfs/ctl or until the kernel module unregisters.
|
* ioctl to fs/ecryptfs/ctl or until the kernel module unregisters.
|
||||||
|
@ -150,20 +129,18 @@ out_unlock_daemon_list:
|
||||||
static int
|
static int
|
||||||
ecryptfs_miscdev_release(struct inode *inode, struct file *file)
|
ecryptfs_miscdev_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct ecryptfs_daemon *daemon = NULL;
|
struct ecryptfs_daemon *daemon = file->private_data;
|
||||||
uid_t euid = current_euid();
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
mutex_lock(&ecryptfs_daemon_hash_mux);
|
|
||||||
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
|
|
||||||
if (rc || !daemon)
|
|
||||||
daemon = file->private_data;
|
|
||||||
mutex_lock(&daemon->mux);
|
mutex_lock(&daemon->mux);
|
||||||
BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
|
BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
|
||||||
daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
|
daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
|
||||||
atomic_dec(&ecryptfs_num_miscdev_opens);
|
atomic_dec(&ecryptfs_num_miscdev_opens);
|
||||||
mutex_unlock(&daemon->mux);
|
mutex_unlock(&daemon->mux);
|
||||||
|
|
||||||
|
mutex_lock(&ecryptfs_daemon_hash_mux);
|
||||||
rc = ecryptfs_exorcise_daemon(daemon);
|
rc = ecryptfs_exorcise_daemon(daemon);
|
||||||
|
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_CRIT "%s: Fatal error whilst attempting to "
|
printk(KERN_CRIT "%s: Fatal error whilst attempting to "
|
||||||
"shut down daemon; rc = [%d]. Please report this "
|
"shut down daemon; rc = [%d]. Please report this "
|
||||||
|
@ -171,7 +148,6 @@ ecryptfs_miscdev_release(struct inode *inode, struct file *file)
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
module_put(THIS_MODULE);
|
module_put(THIS_MODULE);
|
||||||
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +224,7 @@ int ecryptfs_send_miscdev(char *data, size_t data_size,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ecryptfs_miscdev_read - format and send message from queue
|
* ecryptfs_miscdev_read - format and send message from queue
|
||||||
* @file: fs/ecryptfs/euid miscdevfs handle (ignored)
|
* @file: miscdevfs handle
|
||||||
* @buf: User buffer into which to copy the next message on the daemon queue
|
* @buf: User buffer into which to copy the next message on the daemon queue
|
||||||
* @count: Amount of space available in @buf
|
* @count: Amount of space available in @buf
|
||||||
* @ppos: Offset in file (ignored)
|
* @ppos: Offset in file (ignored)
|
||||||
|
@ -262,43 +238,27 @@ static ssize_t
|
||||||
ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
|
ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
|
||||||
loff_t *ppos)
|
loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct ecryptfs_daemon *daemon;
|
struct ecryptfs_daemon *daemon = file->private_data;
|
||||||
struct ecryptfs_msg_ctx *msg_ctx;
|
struct ecryptfs_msg_ctx *msg_ctx;
|
||||||
size_t packet_length_size;
|
size_t packet_length_size;
|
||||||
char packet_length[ECRYPTFS_MAX_PKT_LEN_SIZE];
|
char packet_length[ECRYPTFS_MAX_PKT_LEN_SIZE];
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t total_length;
|
size_t total_length;
|
||||||
uid_t euid = current_euid();
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
mutex_lock(&ecryptfs_daemon_hash_mux);
|
|
||||||
/* TODO: Just use file->private_data? */
|
|
||||||
rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
|
|
||||||
if (rc || !daemon) {
|
|
||||||
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
mutex_lock(&daemon->mux);
|
mutex_lock(&daemon->mux);
|
||||||
if (task_pid(current) != daemon->pid) {
|
|
||||||
mutex_unlock(&daemon->mux);
|
|
||||||
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
|
||||||
return -EPERM;
|
|
||||||
}
|
|
||||||
if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
|
if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
|
||||||
printk(KERN_WARNING "%s: Attempt to read from zombified "
|
printk(KERN_WARNING "%s: Attempt to read from zombified "
|
||||||
"daemon\n", __func__);
|
"daemon\n", __func__);
|
||||||
goto out_unlock_daemon;
|
goto out_unlock_daemon;
|
||||||
}
|
}
|
||||||
if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) {
|
if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) {
|
||||||
rc = 0;
|
rc = 0;
|
||||||
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
|
||||||
goto out_unlock_daemon;
|
goto out_unlock_daemon;
|
||||||
}
|
}
|
||||||
/* This daemon will not go away so long as this flag is set */
|
/* This daemon will not go away so long as this flag is set */
|
||||||
daemon->flags |= ECRYPTFS_DAEMON_IN_READ;
|
daemon->flags |= ECRYPTFS_DAEMON_IN_READ;
|
||||||
mutex_unlock(&ecryptfs_daemon_hash_mux);
|
|
||||||
check_list:
|
check_list:
|
||||||
if (list_empty(&daemon->msg_ctx_out_queue)) {
|
if (list_empty(&daemon->msg_ctx_out_queue)) {
|
||||||
mutex_unlock(&daemon->mux);
|
mutex_unlock(&daemon->mux);
|
||||||
|
@ -382,16 +342,12 @@ out_unlock_daemon:
|
||||||
* ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon
|
* ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon
|
||||||
* @data: Bytes comprising struct ecryptfs_message
|
* @data: Bytes comprising struct ecryptfs_message
|
||||||
* @data_size: sizeof(struct ecryptfs_message) + data len
|
* @data_size: sizeof(struct ecryptfs_message) + data len
|
||||||
* @euid: Effective user id of miscdevess sending the miscdev response
|
|
||||||
* @user_ns: The namespace in which @euid applies
|
|
||||||
* @pid: Miscdevess id of miscdevess sending the miscdev response
|
|
||||||
* @seq: Sequence number for miscdev response packet
|
* @seq: Sequence number for miscdev response packet
|
||||||
*
|
*
|
||||||
* Returns zero on success; non-zero otherwise
|
* Returns zero on success; non-zero otherwise
|
||||||
*/
|
*/
|
||||||
static int ecryptfs_miscdev_response(char *data, size_t data_size,
|
static int ecryptfs_miscdev_response(struct ecryptfs_daemon *daemon, char *data,
|
||||||
uid_t euid, struct user_namespace *user_ns,
|
size_t data_size, u32 seq)
|
||||||
struct pid *pid, u32 seq)
|
|
||||||
{
|
{
|
||||||
struct ecryptfs_message *msg = (struct ecryptfs_message *)data;
|
struct ecryptfs_message *msg = (struct ecryptfs_message *)data;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -403,7 +359,7 @@ static int ecryptfs_miscdev_response(char *data, size_t data_size,
|
||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
rc = ecryptfs_process_response(msg, euid, user_ns, pid, seq);
|
rc = ecryptfs_process_response(daemon, msg, seq);
|
||||||
if (rc)
|
if (rc)
|
||||||
printk(KERN_ERR
|
printk(KERN_ERR
|
||||||
"Error processing response message; rc = [%d]\n", rc);
|
"Error processing response message; rc = [%d]\n", rc);
|
||||||
|
@ -413,7 +369,7 @@ out:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ecryptfs_miscdev_write - handle write to daemon miscdev handle
|
* ecryptfs_miscdev_write - handle write to daemon miscdev handle
|
||||||
* @file: File for misc dev handle (ignored)
|
* @file: File for misc dev handle
|
||||||
* @buf: Buffer containing user data
|
* @buf: Buffer containing user data
|
||||||
* @count: Amount of data in @buf
|
* @count: Amount of data in @buf
|
||||||
* @ppos: Pointer to offset in file (ignored)
|
* @ppos: Pointer to offset in file (ignored)
|
||||||
|
@ -428,7 +384,6 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf,
|
||||||
u32 seq;
|
u32 seq;
|
||||||
size_t packet_size, packet_size_length;
|
size_t packet_size, packet_size_length;
|
||||||
char *data;
|
char *data;
|
||||||
uid_t euid = current_euid();
|
|
||||||
unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE];
|
unsigned char packet_size_peek[ECRYPTFS_MAX_PKT_LEN_SIZE];
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
|
|
||||||
|
@ -488,10 +443,9 @@ memdup:
|
||||||
}
|
}
|
||||||
memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE);
|
memcpy(&counter_nbo, &data[PKT_CTR_OFFSET], PKT_CTR_SIZE);
|
||||||
seq = be32_to_cpu(counter_nbo);
|
seq = be32_to_cpu(counter_nbo);
|
||||||
rc = ecryptfs_miscdev_response(
|
rc = ecryptfs_miscdev_response(file->private_data,
|
||||||
&data[PKT_LEN_OFFSET + packet_size_length],
|
&data[PKT_LEN_OFFSET + packet_size_length],
|
||||||
packet_size, euid, current_user_ns(),
|
packet_size, seq);
|
||||||
task_pid(current), seq);
|
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_WARNING "%s: Failed to deliver miscdev "
|
printk(KERN_WARNING "%s: Failed to deliver miscdev "
|
||||||
"response to requesting operation; rc = [%zd]\n",
|
"response to requesting operation; rc = [%zd]\n",
|
||||||
|
|
|
@ -66,18 +66,6 @@ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
rc = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ecryptfs_encrypt_page(page);
|
rc = ecryptfs_encrypt_page(page);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
ecryptfs_printk(KERN_WARNING, "Error encrypting "
|
ecryptfs_printk(KERN_WARNING, "Error encrypting "
|
||||||
|
@ -498,7 +486,6 @@ static int ecryptfs_write_end(struct file *file,
|
||||||
struct ecryptfs_crypt_stat *crypt_stat =
|
struct ecryptfs_crypt_stat *crypt_stat =
|
||||||
&ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
|
&ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;
|
||||||
int rc;
|
int rc;
|
||||||
int need_unlock_page = 1;
|
|
||||||
|
|
||||||
ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
|
ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
|
||||||
"(page w/ index = [0x%.16lx], to = [%d])\n", index, to);
|
"(page w/ index = [0x%.16lx], to = [%d])\n", index, to);
|
||||||
|
@ -519,26 +506,26 @@ static int ecryptfs_write_end(struct file *file,
|
||||||
"zeros in page with index = [0x%.16lx]\n", index);
|
"zeros in page with index = [0x%.16lx]\n", index);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
set_page_dirty(page);
|
rc = ecryptfs_encrypt_page(page);
|
||||||
unlock_page(page);
|
if (rc) {
|
||||||
need_unlock_page = 0;
|
ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
|
||||||
|
"index [0x%.16lx])\n", index);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (pos + copied > i_size_read(ecryptfs_inode)) {
|
if (pos + copied > i_size_read(ecryptfs_inode)) {
|
||||||
i_size_write(ecryptfs_inode, pos + copied);
|
i_size_write(ecryptfs_inode, pos + copied);
|
||||||
ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
|
ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
|
||||||
"[0x%.16llx]\n",
|
"[0x%.16llx]\n",
|
||||||
(unsigned long long)i_size_read(ecryptfs_inode));
|
(unsigned long long)i_size_read(ecryptfs_inode));
|
||||||
balance_dirty_pages_ratelimited(mapping);
|
|
||||||
rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);
|
|
||||||
if (rc) {
|
|
||||||
printk(KERN_ERR "Error writing inode size to metadata; "
|
|
||||||
"rc = [%d]\n", rc);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rc = copied;
|
rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);
|
||||||
|
if (rc)
|
||||||
|
printk(KERN_ERR "Error writing inode size to metadata; "
|
||||||
|
"rc = [%d]\n", rc);
|
||||||
|
else
|
||||||
|
rc = copied;
|
||||||
out:
|
out:
|
||||||
if (need_unlock_page)
|
unlock_page(page);
|
||||||
unlock_page(page);
|
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче