Commit 9fe79d7600497ed8a95c3981cbe5b73ab98222f0

Authored by Tyler Hicks
1 parent ff826b2b5b

eCryptfs: Properly check for O_RDONLY flag before doing privileged open

If the first attempt at opening the lower file read/write fails,
eCryptfs will retry using a privileged kthread. However, the privileged
retry should not happen if the lower file's inode is read-only because a
read/write open will still be unsuccessful.

The check for determining if the open should be retried was intended to
be based on the access mode of the lower file's open flags being
O_RDONLY, but the check was incorrectly performed. This would cause the
open to be retried by the privileged kthread, resulting in a second
failed open of the lower file. This patch corrects the check to
determine if the open request should be handled by the privileged
kthread.

Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Acked-by: Dan Carpenter <dan.carpenter@oracle.com>

Showing 1 changed file with 1 additions and 1 deletions Inline Diff

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