1/** 2 * eCryptfs: Linux filesystem encryption layer 3 * 4 * Copyright (C) 2008 International Business Machines Corp. 5 * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of the 10 * License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 20 * 02111-1307, USA. 21 */ 22 23#include <linux/kthread.h> 24#include <linux/freezer.h> 25#include <linux/slab.h> 26#include <linux/wait.h> 27#include <linux/mount.h> 28#include <linux/file.h> 29#include "ecryptfs_kernel.h" 30 31struct ecryptfs_open_req { 32 struct file **lower_file; 33 struct path path; 34 struct completion done; 35 struct list_head kthread_ctl_list; 36}; 37 38static struct ecryptfs_kthread_ctl { 39#define ECRYPTFS_KTHREAD_ZOMBIE 0x00000001 40 u32 flags; 41 struct mutex mux; 42 struct list_head req_list; 43 wait_queue_head_t wait; 44} ecryptfs_kthread_ctl; 45 46static struct task_struct *ecryptfs_kthread; 47 48/** 49 * ecryptfs_threadfn 50 * @ignored: ignored 51 * 52 * The eCryptfs kernel thread that has the responsibility of getting 53 * the lower file with RW permissions. 54 * 55 * Returns zero on success; non-zero otherwise 56 */ 57static int ecryptfs_threadfn(void *ignored) 58{ 59 set_freezable(); 60 while (1) { 61 struct ecryptfs_open_req *req; 62 63 wait_event_freezable( 64 ecryptfs_kthread_ctl.wait, 65 (!list_empty(&ecryptfs_kthread_ctl.req_list) 66 || kthread_should_stop())); 67 mutex_lock(&ecryptfs_kthread_ctl.mux); 68 if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) { 69 mutex_unlock(&ecryptfs_kthread_ctl.mux); 70 goto out; 71 } 72 while (!list_empty(&ecryptfs_kthread_ctl.req_list)) { 73 req = list_first_entry(&ecryptfs_kthread_ctl.req_list, 74 struct ecryptfs_open_req, 75 kthread_ctl_list); 76 list_del(&req->kthread_ctl_list); 77 *req->lower_file = dentry_open(&req->path, 78 (O_RDWR | O_LARGEFILE), current_cred()); 79 complete(&req->done); 80 } 81 mutex_unlock(&ecryptfs_kthread_ctl.mux); 82 } 83out: 84 return 0; 85} 86 87int __init ecryptfs_init_kthread(void) 88{ 89 int rc = 0; 90 91 mutex_init(&ecryptfs_kthread_ctl.mux); 92 init_waitqueue_head(&ecryptfs_kthread_ctl.wait); 93 INIT_LIST_HEAD(&ecryptfs_kthread_ctl.req_list); 94 ecryptfs_kthread = kthread_run(&ecryptfs_threadfn, NULL, 95 "ecryptfs-kthread"); 96 if (IS_ERR(ecryptfs_kthread)) { 97 rc = PTR_ERR(ecryptfs_kthread); 98 printk(KERN_ERR "%s: Failed to create kernel thread; rc = [%d]" 99 "\n", __func__, rc); 100 } 101 return rc; 102} 103 104void ecryptfs_destroy_kthread(void) 105{ 106 struct ecryptfs_open_req *req, *tmp; 107 108 mutex_lock(&ecryptfs_kthread_ctl.mux); 109 ecryptfs_kthread_ctl.flags |= ECRYPTFS_KTHREAD_ZOMBIE; 110 list_for_each_entry_safe(req, tmp, &ecryptfs_kthread_ctl.req_list, 111 kthread_ctl_list) { 112 list_del(&req->kthread_ctl_list); 113 *req->lower_file = ERR_PTR(-EIO); 114 complete(&req->done); 115 } 116 mutex_unlock(&ecryptfs_kthread_ctl.mux); 117 kthread_stop(ecryptfs_kthread); 118 wake_up(&ecryptfs_kthread_ctl.wait); 119} 120 121/** 122 * ecryptfs_privileged_open 123 * @lower_file: Result of dentry_open by root on lower dentry 124 * @lower_dentry: Lower dentry for file to open 125 * @lower_mnt: Lower vfsmount for file to open 126 * 127 * This function gets a r/w file opened againt the lower dentry. 128 * 129 * Returns zero on success; non-zero otherwise 130 */ 131int ecryptfs_privileged_open(struct file **lower_file, 132 struct dentry *lower_dentry, 133 struct vfsmount *lower_mnt, 134 const struct cred *cred) 135{ 136 struct ecryptfs_open_req req; 137 int flags = O_LARGEFILE; 138 int rc = 0; 139 140 init_completion(&req.done); 141 req.lower_file = lower_file; 142 req.path.dentry = lower_dentry; 143 req.path.mnt = lower_mnt; 144 145 /* Corresponding dput() and mntput() are done when the 146 * lower file is fput() when all eCryptfs files for the inode are 147 * released. */ 148 flags |= IS_RDONLY(d_inode(lower_dentry)) ? O_RDONLY : O_RDWR; 149 (*lower_file) = dentry_open(&req.path, flags, cred); 150 if (!IS_ERR(*lower_file)) 151 goto have_file; 152 if ((flags & O_ACCMODE) == O_RDONLY) { 153 rc = PTR_ERR((*lower_file)); 154 goto out; 155 } 156 mutex_lock(&ecryptfs_kthread_ctl.mux); 157 if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) { 158 rc = -EIO; 159 mutex_unlock(&ecryptfs_kthread_ctl.mux); 160 printk(KERN_ERR "%s: We are in the middle of shutting down; " 161 "aborting privileged request to open lower file\n", 162 __func__); 163 goto out; 164 } 165 list_add_tail(&req.kthread_ctl_list, &ecryptfs_kthread_ctl.req_list); 166 mutex_unlock(&ecryptfs_kthread_ctl.mux); 167 wake_up(&ecryptfs_kthread_ctl.wait); 168 wait_for_completion(&req.done); 169 if (IS_ERR(*lower_file)) { 170 rc = PTR_ERR(*lower_file); 171 goto out; 172 } 173have_file: 174 if ((*lower_file)->f_op->mmap == NULL) { 175 fput(*lower_file); 176 *lower_file = NULL; 177 rc = -EMEDIUMTYPE; 178 } 179out: 180 return rc; 181} 182