Commit 9fe79d7600497ed8a95c3981cbe5b73ab98222f0
1 parent
ff826b2b5b
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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 |