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