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), current_cred()); 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 const struct cred *cred) 137 { 138 struct ecryptfs_open_req *req; 139 int rc = 0; 140 141 /* Corresponding dput() and mntput() are done when the 142 * persistent file is fput() when the eCryptfs inode is 143 * destroyed. */ 144 dget(lower_dentry); 145 mntget(lower_mnt); 146 (*lower_file) = dentry_open(lower_dentry, lower_mnt, 147 (O_RDWR | O_LARGEFILE), cred); 148 if (!IS_ERR(*lower_file)) 149 goto out; 150 req = kmem_cache_alloc(ecryptfs_open_req_cache, GFP_KERNEL); 151 if (!req) { 152 rc = -ENOMEM; 153 goto out; 154 } 155 mutex_init(&req->mux); 156 req->lower_file = lower_file; 157 req->lower_dentry = lower_dentry; 158 req->lower_mnt = lower_mnt; 159 init_waitqueue_head(&req->wait); 160 req->flags = 0; 161 mutex_lock(&ecryptfs_kthread_ctl.mux); 162 if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) { 163 rc = -EIO; 164 mutex_unlock(&ecryptfs_kthread_ctl.mux); 165 printk(KERN_ERR "%s: We are in the middle of shutting down; " 166 "aborting privileged request to open lower file\n", 167 __func__); 168 goto out_free; 169 } 170 list_add_tail(&req->kthread_ctl_list, &ecryptfs_kthread_ctl.req_list); 171 mutex_unlock(&ecryptfs_kthread_ctl.mux); 172 wake_up(&ecryptfs_kthread_ctl.wait); 173 wait_event(req->wait, (req->flags != 0)); 174 mutex_lock(&req->mux); 175 BUG_ON(req->flags == 0); 176 if (req->flags & ECRYPTFS_REQ_DROPPED 177 || req->flags & ECRYPTFS_REQ_ZOMBIE) { 178 rc = -EIO; 179 printk(KERN_WARNING "%s: Privileged open request dropped\n", 180 __func__); 181 goto out_unlock; 182 } 183 if (IS_ERR(*req->lower_file)) { 184 rc = PTR_ERR(*req->lower_file); 185 dget(lower_dentry); 186 mntget(lower_mnt); 187 (*lower_file) = dentry_open(lower_dentry, lower_mnt, 188 (O_RDONLY | O_LARGEFILE), cred); 189 if (IS_ERR(*lower_file)) { 190 rc = PTR_ERR(*req->lower_file); 191 (*lower_file) = NULL; 192 printk(KERN_WARNING "%s: Error attempting privileged " 193 "open of lower file with either RW or RO " 194 "perms; rc = [%d]. Giving up.\n", 195 __func__, rc); 196 } 197 } 198 out_unlock: 199 mutex_unlock(&req->mux); 200 out_free: 201 kmem_cache_free(ecryptfs_open_req_cache, req); 202 out: 203 return rc; 204 } 205