diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2008-02-23 06:46:49 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-05-01 13:08:50 -0400 |
commit | 2030a42cecd4dd1985a2ab03e25f3cd6106a5ca8 (patch) | |
tree | 7cb4710c3f7a4e034a20890f0df99bc42f9bbcee | |
parent | 9f3acc3140444a900ab280de942291959f0f615d (diff) |
[PATCH] sanitize anon_inode_getfd()
a) none of the callers even looks at inode or file returned by anon_inode_getfd()
b) any caller that would try to look at those would be racy, since by the time
it returns we might have raced with close() from another thread and that
file would be pining for fjords.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/anon_inodes.c | 13 | ||||
-rw-r--r-- | fs/eventfd.c | 15 | ||||
-rw-r--r-- | fs/eventpoll.c | 23 | ||||
-rw-r--r-- | fs/signalfd.c | 17 | ||||
-rw-r--r-- | fs/timerfd.c | 11 | ||||
-rw-r--r-- | include/linux/anon_inodes.h | 3 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 21 |
7 files changed, 29 insertions, 74 deletions
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index f42be069e085..977ef208c051 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c | |||
@@ -57,9 +57,6 @@ static struct dentry_operations anon_inodefs_dentry_operations = { | |||
57 | * anonymous inode, and a dentry that describe the "class" | 57 | * anonymous inode, and a dentry that describe the "class" |
58 | * of the file | 58 | * of the file |
59 | * | 59 | * |
60 | * @pfd: [out] pointer to the file descriptor | ||
61 | * @dpinode: [out] pointer to the inode | ||
62 | * @pfile: [out] pointer to the file struct | ||
63 | * @name: [in] name of the "class" of the new file | 60 | * @name: [in] name of the "class" of the new file |
64 | * @fops [in] file operations for the new file | 61 | * @fops [in] file operations for the new file |
65 | * @priv [in] private data for the new file (will be file's private_data) | 62 | * @priv [in] private data for the new file (will be file's private_data) |
@@ -68,10 +65,9 @@ static struct dentry_operations anon_inodefs_dentry_operations = { | |||
68 | * that do not need to have a full-fledged inode in order to operate correctly. | 65 | * that do not need to have a full-fledged inode in order to operate correctly. |
69 | * All the files created with anon_inode_getfd() will share a single inode, | 66 | * All the files created with anon_inode_getfd() will share a single inode, |
70 | * hence saving memory and avoiding code duplication for the file/inode/dentry | 67 | * hence saving memory and avoiding code duplication for the file/inode/dentry |
71 | * setup. | 68 | * setup. Returns new descriptor or -error. |
72 | */ | 69 | */ |
73 | int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, | 70 | int anon_inode_getfd(const char *name, const struct file_operations *fops, |
74 | const char *name, const struct file_operations *fops, | ||
75 | void *priv) | 71 | void *priv) |
76 | { | 72 | { |
77 | struct qstr this; | 73 | struct qstr this; |
@@ -125,10 +121,7 @@ int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, | |||
125 | 121 | ||
126 | fd_install(fd, file); | 122 | fd_install(fd, file); |
127 | 123 | ||
128 | *pfd = fd; | 124 | return fd; |
129 | *pinode = anon_inode_inode; | ||
130 | *pfile = file; | ||
131 | return 0; | ||
132 | 125 | ||
133 | err_dput: | 126 | err_dput: |
134 | dput(dentry); | 127 | dput(dentry); |
diff --git a/fs/eventfd.c b/fs/eventfd.c index a9f130cd50ac..343942deeec1 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c | |||
@@ -200,10 +200,8 @@ struct file *eventfd_fget(int fd) | |||
200 | 200 | ||
201 | asmlinkage long sys_eventfd(unsigned int count) | 201 | asmlinkage long sys_eventfd(unsigned int count) |
202 | { | 202 | { |
203 | int error, fd; | 203 | int fd; |
204 | struct eventfd_ctx *ctx; | 204 | struct eventfd_ctx *ctx; |
205 | struct file *file; | ||
206 | struct inode *inode; | ||
207 | 205 | ||
208 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | 206 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); |
209 | if (!ctx) | 207 | if (!ctx) |
@@ -216,12 +214,9 @@ asmlinkage long sys_eventfd(unsigned int count) | |||
216 | * When we call this, the initialization must be complete, since | 214 | * When we call this, the initialization must be complete, since |
217 | * anon_inode_getfd() will install the fd. | 215 | * anon_inode_getfd() will install the fd. |
218 | */ | 216 | */ |
219 | error = anon_inode_getfd(&fd, &inode, &file, "[eventfd]", | 217 | fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx); |
220 | &eventfd_fops, ctx); | 218 | if (fd < 0) |
221 | if (!error) | 219 | kfree(ctx); |
222 | return fd; | 220 | return fd; |
223 | |||
224 | kfree(ctx); | ||
225 | return error; | ||
226 | } | 221 | } |
227 | 222 | ||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 221086fef174..990c01d2d66b 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -1050,8 +1050,6 @@ asmlinkage long sys_epoll_create(int size) | |||
1050 | { | 1050 | { |
1051 | int error, fd = -1; | 1051 | int error, fd = -1; |
1052 | struct eventpoll *ep; | 1052 | struct eventpoll *ep; |
1053 | struct inode *inode; | ||
1054 | struct file *file; | ||
1055 | 1053 | ||
1056 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", | 1054 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", |
1057 | current, size)); | 1055 | current, size)); |
@@ -1061,29 +1059,24 @@ asmlinkage long sys_epoll_create(int size) | |||
1061 | * structure ( "struct eventpoll" ). | 1059 | * structure ( "struct eventpoll" ). |
1062 | */ | 1060 | */ |
1063 | error = -EINVAL; | 1061 | error = -EINVAL; |
1064 | if (size <= 0 || (error = ep_alloc(&ep)) != 0) | 1062 | if (size <= 0 || (error = ep_alloc(&ep)) < 0) { |
1063 | fd = error; | ||
1065 | goto error_return; | 1064 | goto error_return; |
1065 | } | ||
1066 | 1066 | ||
1067 | /* | 1067 | /* |
1068 | * Creates all the items needed to setup an eventpoll file. That is, | 1068 | * Creates all the items needed to setup an eventpoll file. That is, |
1069 | * a file structure, and inode and a free file descriptor. | 1069 | * a file structure and a free file descriptor. |
1070 | */ | 1070 | */ |
1071 | error = anon_inode_getfd(&fd, &inode, &file, "[eventpoll]", | 1071 | fd = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep); |
1072 | &eventpoll_fops, ep); | 1072 | if (fd < 0) |
1073 | if (error) | 1073 | ep_free(ep); |
1074 | goto error_free; | ||
1075 | 1074 | ||
1075 | error_return: | ||
1076 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", | 1076 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", |
1077 | current, size, fd)); | 1077 | current, size, fd)); |
1078 | 1078 | ||
1079 | return fd; | 1079 | return fd; |
1080 | |||
1081 | error_free: | ||
1082 | ep_free(ep); | ||
1083 | error_return: | ||
1084 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", | ||
1085 | current, size, error)); | ||
1086 | return error; | ||
1087 | } | 1080 | } |
1088 | 1081 | ||
1089 | /* | 1082 | /* |
diff --git a/fs/signalfd.c b/fs/signalfd.c index 8ead0db35933..619725644c75 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c | |||
@@ -207,11 +207,8 @@ static const struct file_operations signalfd_fops = { | |||
207 | 207 | ||
208 | asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask) | 208 | asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask) |
209 | { | 209 | { |
210 | int error; | ||
211 | sigset_t sigmask; | 210 | sigset_t sigmask; |
212 | struct signalfd_ctx *ctx; | 211 | struct signalfd_ctx *ctx; |
213 | struct file *file; | ||
214 | struct inode *inode; | ||
215 | 212 | ||
216 | if (sizemask != sizeof(sigset_t) || | 213 | if (sizemask != sizeof(sigset_t) || |
217 | copy_from_user(&sigmask, user_mask, sizeof(sigmask))) | 214 | copy_from_user(&sigmask, user_mask, sizeof(sigmask))) |
@@ -230,12 +227,11 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas | |||
230 | * When we call this, the initialization must be complete, since | 227 | * When we call this, the initialization must be complete, since |
231 | * anon_inode_getfd() will install the fd. | 228 | * anon_inode_getfd() will install the fd. |
232 | */ | 229 | */ |
233 | error = anon_inode_getfd(&ufd, &inode, &file, "[signalfd]", | 230 | ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx); |
234 | &signalfd_fops, ctx); | 231 | if (ufd < 0) |
235 | if (error) | 232 | kfree(ctx); |
236 | goto err_fdalloc; | ||
237 | } else { | 233 | } else { |
238 | file = fget(ufd); | 234 | struct file *file = fget(ufd); |
239 | if (!file) | 235 | if (!file) |
240 | return -EBADF; | 236 | return -EBADF; |
241 | ctx = file->private_data; | 237 | ctx = file->private_data; |
@@ -252,9 +248,4 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas | |||
252 | } | 248 | } |
253 | 249 | ||
254 | return ufd; | 250 | return ufd; |
255 | |||
256 | err_fdalloc: | ||
257 | kfree(ctx); | ||
258 | return error; | ||
259 | } | 251 | } |
260 | |||
diff --git a/fs/timerfd.c b/fs/timerfd.c index 5400524e9cb1..d87d354ec424 100644 --- a/fs/timerfd.c +++ b/fs/timerfd.c | |||
@@ -181,10 +181,8 @@ static struct file *timerfd_fget(int fd) | |||
181 | 181 | ||
182 | asmlinkage long sys_timerfd_create(int clockid, int flags) | 182 | asmlinkage long sys_timerfd_create(int clockid, int flags) |
183 | { | 183 | { |
184 | int error, ufd; | 184 | int ufd; |
185 | struct timerfd_ctx *ctx; | 185 | struct timerfd_ctx *ctx; |
186 | struct file *file; | ||
187 | struct inode *inode; | ||
188 | 186 | ||
189 | if (flags) | 187 | if (flags) |
190 | return -EINVAL; | 188 | return -EINVAL; |
@@ -200,12 +198,9 @@ asmlinkage long sys_timerfd_create(int clockid, int flags) | |||
200 | ctx->clockid = clockid; | 198 | ctx->clockid = clockid; |
201 | hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS); | 199 | hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS); |
202 | 200 | ||
203 | error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]", | 201 | ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx); |
204 | &timerfd_fops, ctx); | 202 | if (ufd < 0) |
205 | if (error) { | ||
206 | kfree(ctx); | 203 | kfree(ctx); |
207 | return error; | ||
208 | } | ||
209 | 204 | ||
210 | return ufd; | 205 | return ufd; |
211 | } | 206 | } |
diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h index b2e1ba325b9a..6129e58ca7c9 100644 --- a/include/linux/anon_inodes.h +++ b/include/linux/anon_inodes.h | |||
@@ -8,8 +8,7 @@ | |||
8 | #ifndef _LINUX_ANON_INODES_H | 8 | #ifndef _LINUX_ANON_INODES_H |
9 | #define _LINUX_ANON_INODES_H | 9 | #define _LINUX_ANON_INODES_H |
10 | 10 | ||
11 | int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, | 11 | int anon_inode_getfd(const char *name, const struct file_operations *fops, |
12 | const char *name, const struct file_operations *fops, | ||
13 | void *priv); | 12 | void *priv); |
14 | 13 | ||
15 | #endif /* _LINUX_ANON_INODES_H */ | 14 | #endif /* _LINUX_ANON_INODES_H */ |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index c82cf15730a1..e89338e2b043 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -834,16 +834,9 @@ static const struct file_operations kvm_vcpu_fops = { | |||
834 | */ | 834 | */ |
835 | static int create_vcpu_fd(struct kvm_vcpu *vcpu) | 835 | static int create_vcpu_fd(struct kvm_vcpu *vcpu) |
836 | { | 836 | { |
837 | int fd, r; | 837 | int fd = anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu); |
838 | struct inode *inode; | 838 | if (fd < 0) |
839 | struct file *file; | ||
840 | |||
841 | r = anon_inode_getfd(&fd, &inode, &file, | ||
842 | "kvm-vcpu", &kvm_vcpu_fops, vcpu); | ||
843 | if (r) { | ||
844 | kvm_put_kvm(vcpu->kvm); | 839 | kvm_put_kvm(vcpu->kvm); |
845 | return r; | ||
846 | } | ||
847 | return fd; | 840 | return fd; |
848 | } | 841 | } |
849 | 842 | ||
@@ -1168,19 +1161,15 @@ static const struct file_operations kvm_vm_fops = { | |||
1168 | 1161 | ||
1169 | static int kvm_dev_ioctl_create_vm(void) | 1162 | static int kvm_dev_ioctl_create_vm(void) |
1170 | { | 1163 | { |
1171 | int fd, r; | 1164 | int fd; |
1172 | struct inode *inode; | ||
1173 | struct file *file; | ||
1174 | struct kvm *kvm; | 1165 | struct kvm *kvm; |
1175 | 1166 | ||
1176 | kvm = kvm_create_vm(); | 1167 | kvm = kvm_create_vm(); |
1177 | if (IS_ERR(kvm)) | 1168 | if (IS_ERR(kvm)) |
1178 | return PTR_ERR(kvm); | 1169 | return PTR_ERR(kvm); |
1179 | r = anon_inode_getfd(&fd, &inode, &file, "kvm-vm", &kvm_vm_fops, kvm); | 1170 | fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm); |
1180 | if (r) { | 1171 | if (fd < 0) |
1181 | kvm_put_kvm(kvm); | 1172 | kvm_put_kvm(kvm); |
1182 | return r; | ||
1183 | } | ||
1184 | 1173 | ||
1185 | return fd; | 1174 | return fd; |
1186 | } | 1175 | } |