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/wait.h> 26 #include <linux/mount.h> 27 #include "ecryptfs_kernel.h" 28 29 struct kmem_cache *ecryptfs_open_req_cache; 30 31 static struct ecryptfs_kthread_ctl { 32 #define ECRYPTFS_KTHREAD_ZOMBIE 0x00000001 33 u32 flags; 34 struct mutex mux; 35 struct list_head req_list; 36 wait_queue_head_t wait; 37 } ecryptfs_kthread_ctl; 38 39 static struct task_struct *ecryptfs_kthread; 40 41 /** 42 * ecryptfs_threadfn 43 * @ignored: ignored 44 * 45 * The eCryptfs kernel thread that has the responsibility of getting 46 * the lower persistent file with RW permissions. 47 * 48 * Returns zero on success; non-zero otherwise 49 */ 50 static int ecryptfs_threadfn(void *ignored) 51 { 52 set_freezable(); 53 while (1) { 54 struct ecryptfs_open_req *req; 55 56 wait_event_freezable( 57 ecryptfs_kthread_ctl.wait, 58 (!list_empty(&ecryptfs_kthread_ctl.req_list) 59 || kthread_should_stop())); 60 mutex_lock(&ecryptfs_kthread_ctl.mux); 61 if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) { 62 mutex_unlock(&ecryptfs_kthread_ctl.mux); 63 goto out; 64 } 65 while (!list_empty(&ecryptfs_kthread_ctl.req_list)) { 66 req = list_first_entry(&ecryptfs_kthread_ctl.req_list, 67 struct ecryptfs_open_req, 68 kthread_ctl_list); 69 mutex_lock(&req->mux); 70 list_del(&req->kthread_ctl_list); 71 if (!(req->flags & ECRYPTFS_REQ_ZOMBIE)) { 72 dget(req->lower_dentry); 73 mntget(req->lower_mnt); 74 (*req->lower_file) = dentry_open( 75 req->lower_dentry, req->lower_mnt, 76 (O_RDWR | O_LARGEFILE)); 77 req->flags |= ECRYPTFS_REQ_PROCESSED; 78 } 79 wake_up(&req->wait); 80 mutex_unlock(&req->mux); 81 } 82 mutex_unlock(&ecryptfs_kthread_ctl.mux); 83 } 84 out: 85 return 0; 86 } 87 88 int ecryptfs_init_kthread(void) 89 { 90 int rc = 0; 91 92 mutex_init(&ecryptfs_kthread_ctl.mux); 93 init_waitqueue_head(&ecryptfs_kthread_ctl.wait); 94 INIT_LIST_HEAD(&ecryptfs_kthread_ctl.req_list); 95 ecryptfs_kthread = kthread_run(&ecryptfs_threadfn, NULL, 96 "ecryptfs-kthread"); 97 if (IS_ERR(ecryptfs_kthread)) { 98 rc = PTR_ERR(ecryptfs_kthread); 99 printk(KERN_ERR "%s: Failed to create kernel thread; rc = [%d]" 100 "\n", __func__, rc); 101 } 102 return rc; 103 } 104 105 void ecryptfs_destroy_kthread(void) 106 { 107 struct ecryptfs_open_req *req; 108 109 mutex_lock(&ecryptfs_kthread_ctl.mux); 110 ecryptfs_kthread_ctl.flags |= ECRYPTFS_KTHREAD_ZOMBIE; 111 list_for_each_entry(req, &ecryptfs_kthread_ctl.req_list, 112 kthread_ctl_list) { 113 mutex_lock(&req->mux); 114 req->flags |= ECRYPTFS_REQ_ZOMBIE; 115 wake_up(&req->wait); 116 mutex_unlock(&req->mux); 117 } 118 mutex_unlock(&ecryptfs_kthread_ctl.mux); 119 kthread_stop(ecryptfs_kthread); 120 wake_up(&ecryptfs_kthread_ctl.wait); 121 } 122 123 /** 124 * ecryptfs_privileged_open 125 * @lower_file: Result of dentry_open by root on lower dentry 126 * @lower_dentry: Lower dentry for file to open 127 * @lower_mnt: Lower vfsmount for file to open 128 * 129 * This function gets a r/w file opened againt the lower dentry. 130 * 131 * Returns zero on success; non-zero otherwise 132 */ 133 int ecryptfs_privileged_open(struct file **lower_file, 134 struct dentry *lower_dentry, 135 struct vfsmount *lower_mnt) 136 { 137 struct ecryptfs_open_req *req; 138 int rc = 0; 139 140 /* Corresponding dput() and mntput() are done when the 141 * persistent file is fput() when the eCryptfs inode is 142 * destroyed. */ 143 dget(lower_dentry); 144 mntget(lower_mnt); 145 (*lower_file) = dentry_open(lower_dentry, lower_mnt, 146 (O_RDWR | O_LARGEFILE)); 147 if (!IS_ERR(*lower_file)) 148 goto out; 149 req = kmem_cache_alloc(ecryptfs_open_req_cache, GFP_KERNEL); 150 if (!req) { 151 rc = -ENOMEM; 152 goto out; 153 } 154 mutex_init(&req->mux); 155 req->lower_file = lower_file; 156 req->lower_dentry = lower_dentry; 157 req->lower_mnt = lower_mnt; 158 init_waitqueue_head(&req->wait); 159 req->flags = 0; 160 mutex_lock(&ecryptfs_kthread_ctl.mux); 161 if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) { 162 rc = -EIO; 163 mutex_unlock(&ecryptfs_kthread_ctl.mux); 164 printk(KERN_ERR "%s: We are in the middle of shutting down; " 165 "aborting privileged request to open lower file\n", 166 __func__); 167 goto out_free; 168 } 169 list_add_tail(&req->kthread_ctl_list, &ecryptfs_kthread_ctl.req_list); 170 mutex_unlock(&ecryptfs_kthread_ctl.mux); 171 wake_up(&ecryptfs_kthread_ctl.wait); 172 wait_event(req->wait, (req->flags != 0)); 173 mutex_lock(&req->mux); 174 BUG_ON(req->flags == 0); 175 if (req->flags & ECRYPTFS_REQ_DROPPED 176 || req->flags & ECRYPTFS_REQ_ZOMBIE) { 177 rc = -EIO; 178 printk(KERN_WARNING "%s: Privileged open request dropped\n", 179 __func__); 180 goto out_unlock; 181 } 182 if (IS_ERR(*req->lower_file)) { 183 rc = PTR_ERR(*req->lower_file); 184 dget(lower_dentry); 185 mntget(lower_mnt); 186 (*lower_file) = dentry_open(lower_dentry, lower_mnt, 187 (O_RDONLY | O_LARGEFILE)); 188 if (IS_ERR(*lower_file)) { 189 rc = PTR_ERR(*req->lower_file); 190 (*lower_file) = NULL; 191 printk(KERN_WARNING "%s: Error attempting privileged " 192 "open of lower file with either RW or RO " 193 "perms; rc = [%d]. Giving up.\n", 194 __func__, rc); 195 } 196 } 197 out_unlock: 198 mutex_unlock(&req->mux); 199 out_free: 200 kmem_cache_free(ecryptfs_open_req_cache, req); 201 out: 202 return rc; 203 } 204