aboutsummaryrefslogtreecommitdiffstats
path: root/fs/compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/compat.c')
-rw-r--r--fs/compat.c307
1 files changed, 29 insertions, 278 deletions
diff --git a/fs/compat.c b/fs/compat.c
index f6fd0a00e6cc..0ea00832de23 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -262,35 +262,19 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
262 */ 262 */
263asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf) 263asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
264{ 264{
265 struct path path; 265 struct kstatfs tmp;
266 int error; 266 int error = user_statfs(pathname, &tmp);
267 267 if (!error)
268 error = user_path(pathname, &path); 268 error = put_compat_statfs(buf, &tmp);
269 if (!error) {
270 struct kstatfs tmp;
271 error = vfs_statfs(&path, &tmp);
272 if (!error)
273 error = put_compat_statfs(buf, &tmp);
274 path_put(&path);
275 }
276 return error; 269 return error;
277} 270}
278 271
279asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf) 272asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
280{ 273{
281 struct file * file;
282 struct kstatfs tmp; 274 struct kstatfs tmp;
283 int error; 275 int error = fd_statfs(fd, &tmp);
284
285 error = -EBADF;
286 file = fget(fd);
287 if (!file)
288 goto out;
289 error = vfs_statfs(&file->f_path, &tmp);
290 if (!error) 276 if (!error)
291 error = put_compat_statfs(buf, &tmp); 277 error = put_compat_statfs(buf, &tmp);
292 fput(file);
293out:
294 return error; 278 return error;
295} 279}
296 280
@@ -329,41 +313,29 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat
329 313
330asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf) 314asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf)
331{ 315{
332 struct path path; 316 struct kstatfs tmp;
333 int error; 317 int error;
334 318
335 if (sz != sizeof(*buf)) 319 if (sz != sizeof(*buf))
336 return -EINVAL; 320 return -EINVAL;
337 321
338 error = user_path(pathname, &path); 322 error = user_statfs(pathname, &tmp);
339 if (!error) { 323 if (!error)
340 struct kstatfs tmp; 324 error = put_compat_statfs64(buf, &tmp);
341 error = vfs_statfs(&path, &tmp);
342 if (!error)
343 error = put_compat_statfs64(buf, &tmp);
344 path_put(&path);
345 }
346 return error; 325 return error;
347} 326}
348 327
349asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf) 328asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf)
350{ 329{
351 struct file * file;
352 struct kstatfs tmp; 330 struct kstatfs tmp;
353 int error; 331 int error;
354 332
355 if (sz != sizeof(*buf)) 333 if (sz != sizeof(*buf))
356 return -EINVAL; 334 return -EINVAL;
357 335
358 error = -EBADF; 336 error = fd_statfs(fd, &tmp);
359 file = fget(fd);
360 if (!file)
361 goto out;
362 error = vfs_statfs(&file->f_path, &tmp);
363 if (!error) 337 if (!error)
364 error = put_compat_statfs64(buf, &tmp); 338 error = put_compat_statfs64(buf, &tmp);
365 fput(file);
366out:
367 return error; 339 return error;
368} 340}
369 341
@@ -1228,7 +1200,9 @@ compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec,
1228 file = fget_light(fd, &fput_needed); 1200 file = fget_light(fd, &fput_needed);
1229 if (!file) 1201 if (!file)
1230 return -EBADF; 1202 return -EBADF;
1231 ret = compat_readv(file, vec, vlen, &pos); 1203 ret = -ESPIPE;
1204 if (file->f_mode & FMODE_PREAD)
1205 ret = compat_readv(file, vec, vlen, &pos);
1232 fput_light(file, fput_needed); 1206 fput_light(file, fput_needed);
1233 return ret; 1207 return ret;
1234} 1208}
@@ -1285,7 +1259,9 @@ compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec,
1285 file = fget_light(fd, &fput_needed); 1259 file = fget_light(fd, &fput_needed);
1286 if (!file) 1260 if (!file)
1287 return -EBADF; 1261 return -EBADF;
1288 ret = compat_writev(file, vec, vlen, &pos); 1262 ret = -ESPIPE;
1263 if (file->f_mode & FMODE_PWRITE)
1264 ret = compat_writev(file, vec, vlen, &pos);
1289 fput_light(file, fput_needed); 1265 fput_light(file, fput_needed);
1290 return ret; 1266 return ret;
1291} 1267}
@@ -1330,241 +1306,6 @@ compat_sys_openat(unsigned int dfd, const char __user *filename, int flags, int
1330 return do_sys_open(dfd, filename, flags, mode); 1306 return do_sys_open(dfd, filename, flags, mode);
1331} 1307}
1332 1308
1333/*
1334 * compat_count() counts the number of arguments/envelopes. It is basically
1335 * a copy of count() from fs/exec.c, except that it works with 32 bit argv
1336 * and envp pointers.
1337 */
1338static int compat_count(compat_uptr_t __user *argv, int max)
1339{
1340 int i = 0;
1341
1342 if (argv != NULL) {
1343 for (;;) {
1344 compat_uptr_t p;
1345
1346 if (get_user(p, argv))
1347 return -EFAULT;
1348 if (!p)
1349 break;
1350 argv++;
1351 if (i++ >= max)
1352 return -E2BIG;
1353
1354 if (fatal_signal_pending(current))
1355 return -ERESTARTNOHAND;
1356 cond_resched();
1357 }
1358 }
1359 return i;
1360}
1361
1362/*
1363 * compat_copy_strings() is basically a copy of copy_strings() from fs/exec.c
1364 * except that it works with 32 bit argv and envp pointers.
1365 */
1366static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
1367 struct linux_binprm *bprm)
1368{
1369 struct page *kmapped_page = NULL;
1370 char *kaddr = NULL;
1371 unsigned long kpos = 0;
1372 int ret;
1373
1374 while (argc-- > 0) {
1375 compat_uptr_t str;
1376 int len;
1377 unsigned long pos;
1378
1379 if (get_user(str, argv+argc) ||
1380 !(len = strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) {
1381 ret = -EFAULT;
1382 goto out;
1383 }
1384
1385 if (len > MAX_ARG_STRLEN) {
1386 ret = -E2BIG;
1387 goto out;
1388 }
1389
1390 /* We're going to work our way backwords. */
1391 pos = bprm->p;
1392 str += len;
1393 bprm->p -= len;
1394
1395 while (len > 0) {
1396 int offset, bytes_to_copy;
1397
1398 if (fatal_signal_pending(current)) {
1399 ret = -ERESTARTNOHAND;
1400 goto out;
1401 }
1402 cond_resched();
1403
1404 offset = pos % PAGE_SIZE;
1405 if (offset == 0)
1406 offset = PAGE_SIZE;
1407
1408 bytes_to_copy = offset;
1409 if (bytes_to_copy > len)
1410 bytes_to_copy = len;
1411
1412 offset -= bytes_to_copy;
1413 pos -= bytes_to_copy;
1414 str -= bytes_to_copy;
1415 len -= bytes_to_copy;
1416
1417 if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
1418 struct page *page;
1419
1420 page = get_arg_page(bprm, pos, 1);
1421 if (!page) {
1422 ret = -E2BIG;
1423 goto out;
1424 }
1425
1426 if (kmapped_page) {
1427 flush_kernel_dcache_page(kmapped_page);
1428 kunmap(kmapped_page);
1429 put_page(kmapped_page);
1430 }
1431 kmapped_page = page;
1432 kaddr = kmap(kmapped_page);
1433 kpos = pos & PAGE_MASK;
1434 flush_cache_page(bprm->vma, kpos,
1435 page_to_pfn(kmapped_page));
1436 }
1437 if (copy_from_user(kaddr+offset, compat_ptr(str),
1438 bytes_to_copy)) {
1439 ret = -EFAULT;
1440 goto out;
1441 }
1442 }
1443 }
1444 ret = 0;
1445out:
1446 if (kmapped_page) {
1447 flush_kernel_dcache_page(kmapped_page);
1448 kunmap(kmapped_page);
1449 put_page(kmapped_page);
1450 }
1451 return ret;
1452}
1453
1454/*
1455 * compat_do_execve() is mostly a copy of do_execve(), with the exception
1456 * that it processes 32 bit argv and envp pointers.
1457 */
1458int compat_do_execve(char * filename,
1459 compat_uptr_t __user *argv,
1460 compat_uptr_t __user *envp,
1461 struct pt_regs * regs)
1462{
1463 struct linux_binprm *bprm;
1464 struct file *file;
1465 struct files_struct *displaced;
1466 bool clear_in_exec;
1467 int retval;
1468
1469 retval = unshare_files(&displaced);
1470 if (retval)
1471 goto out_ret;
1472
1473 retval = -ENOMEM;
1474 bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
1475 if (!bprm)
1476 goto out_files;
1477
1478 retval = prepare_bprm_creds(bprm);
1479 if (retval)
1480 goto out_free;
1481
1482 retval = check_unsafe_exec(bprm);
1483 if (retval < 0)
1484 goto out_free;
1485 clear_in_exec = retval;
1486 current->in_execve = 1;
1487
1488 file = open_exec(filename);
1489 retval = PTR_ERR(file);
1490 if (IS_ERR(file))
1491 goto out_unmark;
1492
1493 sched_exec();
1494
1495 bprm->file = file;
1496 bprm->filename = filename;
1497 bprm->interp = filename;
1498
1499 retval = bprm_mm_init(bprm);
1500 if (retval)
1501 goto out_file;
1502
1503 bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
1504 if ((retval = bprm->argc) < 0)
1505 goto out;
1506
1507 bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
1508 if ((retval = bprm->envc) < 0)
1509 goto out;
1510
1511 retval = prepare_binprm(bprm);
1512 if (retval < 0)
1513 goto out;
1514
1515 retval = copy_strings_kernel(1, &bprm->filename, bprm);
1516 if (retval < 0)
1517 goto out;
1518
1519 bprm->exec = bprm->p;
1520 retval = compat_copy_strings(bprm->envc, envp, bprm);
1521 if (retval < 0)
1522 goto out;
1523
1524 retval = compat_copy_strings(bprm->argc, argv, bprm);
1525 if (retval < 0)
1526 goto out;
1527
1528 retval = search_binary_handler(bprm, regs);
1529 if (retval < 0)
1530 goto out;
1531
1532 /* execve succeeded */
1533 current->fs->in_exec = 0;
1534 current->in_execve = 0;
1535 acct_update_integrals(current);
1536 free_bprm(bprm);
1537 if (displaced)
1538 put_files_struct(displaced);
1539 return retval;
1540
1541out:
1542 if (bprm->mm) {
1543 acct_arg_size(bprm, 0);
1544 mmput(bprm->mm);
1545 }
1546
1547out_file:
1548 if (bprm->file) {
1549 allow_write_access(bprm->file);
1550 fput(bprm->file);
1551 }
1552
1553out_unmark:
1554 if (clear_in_exec)
1555 current->fs->in_exec = 0;
1556 current->in_execve = 0;
1557
1558out_free:
1559 free_bprm(bprm);
1560
1561out_files:
1562 if (displaced)
1563 reset_files_struct(displaced);
1564out_ret:
1565 return retval;
1566}
1567
1568#define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t)) 1309#define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t))
1569 1310
1570static int poll_select_copy_remaining(struct timespec *end_time, void __user *p, 1311static int poll_select_copy_remaining(struct timespec *end_time, void __user *p,
@@ -1695,9 +1436,6 @@ int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
1695 * Update: ERESTARTSYS breaks at least the xview clock binary, so 1436 * Update: ERESTARTSYS breaks at least the xview clock binary, so
1696 * I'm trying ERESTARTNOHAND which restart only when you want to. 1437 * I'm trying ERESTARTNOHAND which restart only when you want to.
1697 */ 1438 */
1698#define MAX_SELECT_SECONDS \
1699 ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
1700
1701int compat_core_sys_select(int n, compat_ulong_t __user *inp, 1439int compat_core_sys_select(int n, compat_ulong_t __user *inp,
1702 compat_ulong_t __user *outp, compat_ulong_t __user *exp, 1440 compat_ulong_t __user *outp, compat_ulong_t __user *exp,
1703 struct timespec *end_time) 1441 struct timespec *end_time)
@@ -2308,3 +2046,16 @@ asmlinkage long compat_sys_timerfd_gettime(int ufd,
2308} 2046}
2309 2047
2310#endif /* CONFIG_TIMERFD */ 2048#endif /* CONFIG_TIMERFD */
2049
2050#ifdef CONFIG_FHANDLE
2051/*
2052 * Exactly like fs/open.c:sys_open_by_handle_at(), except that it
2053 * doesn't set the O_LARGEFILE flag.
2054 */
2055asmlinkage long
2056compat_sys_open_by_handle_at(int mountdirfd,
2057 struct file_handle __user *handle, int flags)
2058{
2059 return do_handle_open(mountdirfd, handle, flags);
2060}
2061#endif