aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsandeen@sandeen.net <sandeen@sandeen.net>2008-11-25 22:20:08 -0500
committerLachlan McIlroy <lachlan@redback.melbourne.sgi.com>2008-12-02 01:09:43 -0500
commitd5547f9feea459dfc9e7313bd1d561394e2c129f (patch)
tree70ef06acb6247176df74974794fcb039400b79cd
parentffae263a640b736a7206a0d7bd14ab44eb58cd28 (diff)
[XFS] Clean up some existing compat ioctl calls
Create a new xfs_ioctl.h file which has prototypes for ioctl helpers that may be called in compat mode. Change several compat ioctl cases which are IOW to simply copy in the userspace argument, then call the common ioctl helper. This also fixes xfs_compat_ioc_fsgeometry_v1(), which had it backwards before; it copied in an (empty) arg, then copied out the native result, which probably corrupted userspace. It should be translating on the copyout. Also, a bit of formatting cleanup for consistency, and conversion of all error returns to use XFS_ERROR(). Signed-off-by: Eric Sandeen <sandeen@sandeen.net> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c8
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.h47
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.c207
3 files changed, 171 insertions, 91 deletions
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index 03c55b8fa373..498d3e15843b 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -68,7 +68,7 @@
68 * XFS_IOC_PATH_TO_HANDLE 68 * XFS_IOC_PATH_TO_HANDLE
69 * returns full handle for a path 69 * returns full handle for a path
70 */ 70 */
71STATIC int 71int
72xfs_find_handle( 72xfs_find_handle(
73 unsigned int cmd, 73 unsigned int cmd,
74 xfs_fsop_handlereq_t *hreq) 74 xfs_fsop_handlereq_t *hreq)
@@ -245,7 +245,7 @@ xfs_vget_fsop_handlereq(
245 return 0; 245 return 0;
246} 246}
247 247
248STATIC int 248int
249xfs_open_by_handle( 249xfs_open_by_handle(
250 xfs_mount_t *mp, 250 xfs_mount_t *mp,
251 xfs_fsop_handlereq_t *hreq, 251 xfs_fsop_handlereq_t *hreq,
@@ -355,7 +355,7 @@ do_readlink(
355} 355}
356 356
357 357
358STATIC int 358int
359xfs_readlink_by_handle( 359xfs_readlink_by_handle(
360 xfs_mount_t *mp, 360 xfs_mount_t *mp,
361 xfs_fsop_handlereq_t *hreq, 361 xfs_fsop_handlereq_t *hreq,
@@ -651,7 +651,7 @@ xfs_attrmulti_by_handle(
651 return -error; 651 return -error;
652} 652}
653 653
654STATIC int 654int
655xfs_ioc_space( 655xfs_ioc_space(
656 struct xfs_inode *ip, 656 struct xfs_inode *ip,
657 struct inode *inode, 657 struct inode *inode,
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.h b/fs/xfs/linux-2.6/xfs_ioctl.h
new file mode 100644
index 000000000000..2df849f49a5e
--- /dev/null
+++ b/fs/xfs/linux-2.6/xfs_ioctl.h
@@ -0,0 +1,47 @@
1/*
2 * Copyright (c) 2008 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#ifndef __XFS_IOCTL_H__
19#define __XFS_IOCTL_H__
20
21extern int
22xfs_ioc_space(
23 struct xfs_inode *ip,
24 struct inode *inode,
25 struct file *filp,
26 int ioflags,
27 unsigned int cmd,
28 xfs_flock64_t *bf);
29
30extern int
31xfs_find_handle(
32 unsigned int cmd,
33 xfs_fsop_handlereq_t *hreq);
34
35extern int
36xfs_open_by_handle(
37 xfs_mount_t *mp,
38 xfs_fsop_handlereq_t *hreq,
39 struct file *parfilp,
40 struct inode *parinode);
41
42extern int
43xfs_readlink_by_handle(
44 xfs_mount_t *mp,
45 xfs_fsop_handlereq_t *hreq,
46 struct inode *parinode);
47#endif
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index 620bb2d6d26c..35edc054fb99 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -43,55 +43,62 @@
43#include "xfs_error.h" 43#include "xfs_error.h"
44#include "xfs_dfrag.h" 44#include "xfs_dfrag.h"
45#include "xfs_vnodeops.h" 45#include "xfs_vnodeops.h"
46#include "xfs_fsops.h"
47#include "xfs_ioctl.h"
46#include "xfs_ioctl32.h" 48#include "xfs_ioctl32.h"
47 49
48#define _NATIVE_IOC(cmd, type) \ 50#define _NATIVE_IOC(cmd, type) \
49 _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type)) 51 _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type))
50 52
51#ifdef BROKEN_X86_ALIGNMENT 53#ifdef BROKEN_X86_ALIGNMENT
52STATIC unsigned long 54STATIC int
53xfs_ioctl32_flock( 55xfs_compat_flock64_copyin(
54 unsigned long arg) 56 xfs_flock64_t *bf,
57 compat_xfs_flock64_t __user *arg32)
55{ 58{
56 compat_xfs_flock64_t __user *p32 = (void __user *)arg; 59 if (get_user(bf->l_type, &arg32->l_type) ||
57 xfs_flock64_t __user *p = compat_alloc_user_space(sizeof(*p)); 60 get_user(bf->l_whence, &arg32->l_whence) ||
58 61 get_user(bf->l_start, &arg32->l_start) ||
59 if (copy_in_user(&p->l_type, &p32->l_type, sizeof(s16)) || 62 get_user(bf->l_len, &arg32->l_len) ||
60 copy_in_user(&p->l_whence, &p32->l_whence, sizeof(s16)) || 63 get_user(bf->l_sysid, &arg32->l_sysid) ||
61 copy_in_user(&p->l_start, &p32->l_start, sizeof(s64)) || 64 get_user(bf->l_pid, &arg32->l_pid) ||
62 copy_in_user(&p->l_len, &p32->l_len, sizeof(s64)) || 65 copy_from_user(bf->l_pad, &arg32->l_pad, 4*sizeof(u32)))
63 copy_in_user(&p->l_sysid, &p32->l_sysid, sizeof(s32)) || 66 return -XFS_ERROR(EFAULT);
64 copy_in_user(&p->l_pid, &p32->l_pid, sizeof(u32)) || 67 return 0;
65 copy_in_user(&p->l_pad, &p32->l_pad, 4*sizeof(u32)))
66 return -EFAULT;
67
68 return (unsigned long)p;
69} 68}
70 69
71STATIC unsigned long xfs_ioctl32_geom_v1(unsigned long arg) 70STATIC int
71xfs_compat_ioc_fsgeometry_v1(
72 struct xfs_mount *mp,
73 compat_xfs_fsop_geom_v1_t __user *arg32)
72{ 74{
73 compat_xfs_fsop_geom_v1_t __user *p32 = (void __user *)arg; 75 xfs_fsop_geom_t fsgeo;
74 xfs_fsop_geom_v1_t __user *p = compat_alloc_user_space(sizeof(*p)); 76 int error;
75 77
76 if (copy_in_user(p, p32, sizeof(*p32))) 78 error = xfs_fs_geometry(mp, &fsgeo, 3);
77 return -EFAULT; 79 if (error)
78 return (unsigned long)p; 80 return -error;
81 /* The 32-bit variant simply has some padding at the end */
82 if (copy_to_user(arg32, &fsgeo, sizeof(struct compat_xfs_fsop_geom_v1)))
83 return -XFS_ERROR(EFAULT);
84 return 0;
79} 85}
80 86
81STATIC int xfs_inumbers_fmt_compat( 87STATIC int
82 void __user *ubuffer, 88xfs_inumbers_fmt_compat(
83 const xfs_inogrp_t *buffer, 89 void __user *ubuffer,
84 long count, 90 const xfs_inogrp_t *buffer,
85 long *written) 91 long count,
92 long *written)
86{ 93{
87 compat_xfs_inogrp_t __user *p32 = ubuffer; 94 compat_xfs_inogrp_t __user *p32 = ubuffer;
88 long i; 95 long i;
89 96
90 for (i = 0; i < count; i++) { 97 for (i = 0; i < count; i++) {
91 if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) || 98 if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) ||
92 put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) || 99 put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) ||
93 put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask)) 100 put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask))
94 return -EFAULT; 101 return -XFS_ERROR(EFAULT);
95 } 102 }
96 *written = count * sizeof(*p32); 103 *written = count * sizeof(*p32);
97 return 0; 104 return 0;
@@ -103,24 +110,26 @@ STATIC int xfs_inumbers_fmt_compat(
103 110
104/* XFS_IOC_FSBULKSTAT and friends */ 111/* XFS_IOC_FSBULKSTAT and friends */
105 112
106STATIC int xfs_bstime_store_compat( 113STATIC int
107 compat_xfs_bstime_t __user *p32, 114xfs_bstime_store_compat(
108 const xfs_bstime_t *p) 115 compat_xfs_bstime_t __user *p32,
116 const xfs_bstime_t *p)
109{ 117{
110 __s32 sec32; 118 __s32 sec32;
111 119
112 sec32 = p->tv_sec; 120 sec32 = p->tv_sec;
113 if (put_user(sec32, &p32->tv_sec) || 121 if (put_user(sec32, &p32->tv_sec) ||
114 put_user(p->tv_nsec, &p32->tv_nsec)) 122 put_user(p->tv_nsec, &p32->tv_nsec))
115 return -EFAULT; 123 return -XFS_ERROR(EFAULT);
116 return 0; 124 return 0;
117} 125}
118 126
119STATIC int xfs_bulkstat_one_fmt_compat( 127STATIC int
128xfs_bulkstat_one_fmt_compat(
120 void __user *ubuffer, 129 void __user *ubuffer,
121 const xfs_bstat_t *buffer) 130 const xfs_bstat_t *buffer)
122{ 131{
123 compat_xfs_bstat_t __user *p32 = ubuffer; 132 compat_xfs_bstat_t __user *p32 = ubuffer;
124 133
125 if (put_user(buffer->bs_ino, &p32->bs_ino) || 134 if (put_user(buffer->bs_ino, &p32->bs_ino) ||
126 put_user(buffer->bs_mode, &p32->bs_mode) || 135 put_user(buffer->bs_mode, &p32->bs_mode) ||
@@ -142,7 +151,7 @@ STATIC int xfs_bulkstat_one_fmt_compat(
142 put_user(buffer->bs_dmevmask, &p32->bs_dmevmask) || 151 put_user(buffer->bs_dmevmask, &p32->bs_dmevmask) ||
143 put_user(buffer->bs_dmstate, &p32->bs_dmstate) || 152 put_user(buffer->bs_dmstate, &p32->bs_dmstate) ||
144 put_user(buffer->bs_aextents, &p32->bs_aextents)) 153 put_user(buffer->bs_aextents, &p32->bs_aextents))
145 return -EFAULT; 154 return -XFS_ERROR(EFAULT);
146 return sizeof(*p32); 155 return sizeof(*p32);
147} 156}
148 157
@@ -165,20 +174,20 @@ xfs_ioc_bulkstat_compat(
165 /* should be called again (unused here, but used in dmapi) */ 174 /* should be called again (unused here, but used in dmapi) */
166 175
167 if (!capable(CAP_SYS_ADMIN)) 176 if (!capable(CAP_SYS_ADMIN))
168 return -EPERM; 177 return -XFS_ERROR(EPERM);
169 178
170 if (XFS_FORCED_SHUTDOWN(mp)) 179 if (XFS_FORCED_SHUTDOWN(mp))
171 return -XFS_ERROR(EIO); 180 return -XFS_ERROR(EIO);
172 181
173 if (get_user(addr, &p32->lastip)) 182 if (get_user(addr, &p32->lastip))
174 return -EFAULT; 183 return -XFS_ERROR(EFAULT);
175 bulkreq.lastip = compat_ptr(addr); 184 bulkreq.lastip = compat_ptr(addr);
176 if (get_user(bulkreq.icount, &p32->icount) || 185 if (get_user(bulkreq.icount, &p32->icount) ||
177 get_user(addr, &p32->ubuffer)) 186 get_user(addr, &p32->ubuffer))
178 return -EFAULT; 187 return -XFS_ERROR(EFAULT);
179 bulkreq.ubuffer = compat_ptr(addr); 188 bulkreq.ubuffer = compat_ptr(addr);
180 if (get_user(addr, &p32->ocount)) 189 if (get_user(addr, &p32->ocount))
181 return -EFAULT; 190 return -XFS_ERROR(EFAULT);
182 bulkreq.ocount = compat_ptr(addr); 191 bulkreq.ocount = compat_ptr(addr);
183 192
184 if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) 193 if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
@@ -216,38 +225,40 @@ xfs_ioc_bulkstat_compat(
216 return 0; 225 return 0;
217} 226}
218 227
219STATIC unsigned long xfs_ioctl32_fshandle(unsigned long arg) 228STATIC int
229xfs_compat_handlereq_copyin(
230 xfs_fsop_handlereq_t *hreq,
231 compat_xfs_fsop_handlereq_t __user *arg32)
220{ 232{
221 compat_xfs_fsop_handlereq_t __user *p32 = (void __user *)arg; 233 compat_xfs_fsop_handlereq_t hreq32;
222 xfs_fsop_handlereq_t __user *p = compat_alloc_user_space(sizeof(*p)); 234
223 u32 addr; 235 if (copy_from_user(&hreq32, arg32, sizeof(compat_xfs_fsop_handlereq_t)))
224 236 return -XFS_ERROR(EFAULT);
225 if (copy_in_user(&p->fd, &p32->fd, sizeof(__u32)) || 237
226 get_user(addr, &p32->path) || 238 hreq->fd = hreq32.fd;
227 put_user(compat_ptr(addr), &p->path) || 239 hreq->path = compat_ptr(hreq32.path);
228 copy_in_user(&p->oflags, &p32->oflags, sizeof(__u32)) || 240 hreq->oflags = hreq32.oflags;
229 get_user(addr, &p32->ihandle) || 241 hreq->ihandle = compat_ptr(hreq32.ihandle);
230 put_user(compat_ptr(addr), &p->ihandle) || 242 hreq->ihandlen = hreq32.ihandlen;
231 copy_in_user(&p->ihandlen, &p32->ihandlen, sizeof(__u32)) || 243 hreq->ohandle = compat_ptr(hreq32.ohandle);
232 get_user(addr, &p32->ohandle) || 244 hreq->ohandlen = compat_ptr(hreq32.ohandlen);
233 put_user(compat_ptr(addr), &p->ohandle) || 245
234 get_user(addr, &p32->ohandlen) || 246 return 0;
235 put_user(compat_ptr(addr), &p->ohandlen))
236 return -EFAULT;
237
238 return (unsigned long)p;
239} 247}
240 248
241STATIC long 249STATIC long
242xfs_compat_ioctl( 250xfs_compat_ioctl(
243 int mode, 251 xfs_inode_t *ip,
244 struct file *file, 252 struct file *filp,
253 int ioflags,
245 unsigned cmd, 254 unsigned cmd,
246 unsigned long arg) 255 void __user *arg)
247{ 256{
248 struct inode *inode = file->f_path.dentry->d_inode; 257 struct inode *inode = filp->f_path.dentry->d_inode;
258 xfs_mount_t *mp = ip->i_mount;
249 int error; 259 int error;
250 260
261 xfs_itrace_entry(XFS_I(inode));
251 switch (cmd) { 262 switch (cmd) {
252 case XFS_IOC_DIOINFO: 263 case XFS_IOC_DIOINFO:
253 case XFS_IOC_FSGEOMETRY: 264 case XFS_IOC_FSGEOMETRY:
@@ -290,14 +301,16 @@ xfs_compat_ioctl(
290 case XFS_IOC_RESVSP_32: 301 case XFS_IOC_RESVSP_32:
291 case XFS_IOC_UNRESVSP_32: 302 case XFS_IOC_UNRESVSP_32:
292 case XFS_IOC_RESVSP64_32: 303 case XFS_IOC_RESVSP64_32:
293 case XFS_IOC_UNRESVSP64_32: 304 case XFS_IOC_UNRESVSP64_32: {
294 arg = xfs_ioctl32_flock(arg); 305 struct xfs_flock64 bf;
306
307 if (xfs_compat_flock64_copyin(&bf, arg))
308 return -XFS_ERROR(EFAULT);
295 cmd = _NATIVE_IOC(cmd, struct xfs_flock64); 309 cmd = _NATIVE_IOC(cmd, struct xfs_flock64);
296 break; 310 return xfs_ioc_space(ip, inode, filp, ioflags, cmd, &bf);
311 }
297 case XFS_IOC_FSGEOMETRY_V1_32: 312 case XFS_IOC_FSGEOMETRY_V1_32:
298 arg = xfs_ioctl32_geom_v1(arg); 313 return xfs_compat_ioc_fsgeometry_v1(mp, arg);
299 cmd = _NATIVE_IOC(cmd, struct xfs_fsop_geom_v1);
300 break;
301#else /* These are handled fine if no alignment issues */ 314#else /* These are handled fine if no alignment issues */
302 case XFS_IOC_ALLOCSP: 315 case XFS_IOC_ALLOCSP:
303 case XFS_IOC_FREESP: 316 case XFS_IOC_FREESP:
@@ -323,35 +336,55 @@ xfs_compat_ioctl(
323 cmd, (void __user*)arg); 336 cmd, (void __user*)arg);
324 case XFS_IOC_FD_TO_HANDLE_32: 337 case XFS_IOC_FD_TO_HANDLE_32:
325 case XFS_IOC_PATH_TO_HANDLE_32: 338 case XFS_IOC_PATH_TO_HANDLE_32:
326 case XFS_IOC_PATH_TO_FSHANDLE_32: 339 case XFS_IOC_PATH_TO_FSHANDLE_32: {
327 case XFS_IOC_OPEN_BY_HANDLE_32: 340 struct xfs_fsop_handlereq hreq;
328 case XFS_IOC_READLINK_BY_HANDLE_32: 341
329 arg = xfs_ioctl32_fshandle(arg); 342 if (xfs_compat_handlereq_copyin(&hreq, arg))
343 return -XFS_ERROR(EFAULT);
330 cmd = _NATIVE_IOC(cmd, struct xfs_fsop_handlereq); 344 cmd = _NATIVE_IOC(cmd, struct xfs_fsop_handlereq);
331 break; 345 return xfs_find_handle(cmd, &hreq);
346 }
347 case XFS_IOC_OPEN_BY_HANDLE_32: {
348 struct xfs_fsop_handlereq hreq;
349
350 if (xfs_compat_handlereq_copyin(&hreq, arg))
351 return -XFS_ERROR(EFAULT);
352 return xfs_open_by_handle(mp, &hreq, filp, inode);
353 }
354 case XFS_IOC_READLINK_BY_HANDLE_32: {
355 struct xfs_fsop_handlereq hreq;
356
357 if (xfs_compat_handlereq_copyin(&hreq, arg))
358 return -XFS_ERROR(EFAULT);
359 return xfs_readlink_by_handle(mp, &hreq, inode);
360 }
332 default: 361 default:
333 return -ENOIOCTLCMD; 362 return -XFS_ERROR(ENOIOCTLCMD);
334 } 363 }
335 364
336 error = xfs_ioctl(XFS_I(inode), file, mode, cmd, (void __user *)arg); 365 error = xfs_ioctl(ip, filp, ioflags, cmd, arg);
337 xfs_iflags_set(XFS_I(inode), XFS_IMODIFIED);
338 return error; 366 return error;
339} 367}
340 368
341long 369long
342xfs_file_compat_ioctl( 370xfs_file_compat_ioctl(
343 struct file *file, 371 struct file *filp,
344 unsigned cmd, 372 unsigned int cmd,
345 unsigned long arg) 373 unsigned long p)
346{ 374{
347 return xfs_compat_ioctl(0, file, cmd, arg); 375 struct inode *inode = filp->f_path.dentry->d_inode;
376
377 return xfs_compat_ioctl(XFS_I(inode), filp, 0, cmd, (void __user *)p);
348} 378}
349 379
350long 380long
351xfs_file_compat_invis_ioctl( 381xfs_file_compat_invis_ioctl(
352 struct file *file, 382 struct file *filp,
353 unsigned cmd, 383 unsigned int cmd,
354 unsigned long arg) 384 unsigned long p)
355{ 385{
356 return xfs_compat_ioctl(IO_INVIS, file, cmd, arg); 386 struct inode *inode = filp->f_path.dentry->d_inode;
387
388 return xfs_compat_ioctl(XFS_I(inode), filp, IO_INVIS, cmd,
389 (void __user *)p);
357} 390}