diff options
Diffstat (limited to 'fs/compat.c')
-rw-r--r-- | fs/compat.c | 148 |
1 files changed, 131 insertions, 17 deletions
diff --git a/fs/compat.c b/fs/compat.c index d0145ca27572..3f84d5f15889 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/poll.h> | 51 | #include <linux/poll.h> |
52 | #include <linux/mm.h> | 52 | #include <linux/mm.h> |
53 | #include <linux/eventpoll.h> | 53 | #include <linux/eventpoll.h> |
54 | #include <linux/fs_struct.h> | ||
54 | 55 | ||
55 | #include <asm/uaccess.h> | 56 | #include <asm/uaccess.h> |
56 | #include <asm/mmu_context.h> | 57 | #include <asm/mmu_context.h> |
@@ -378,6 +379,34 @@ out: | |||
378 | return error; | 379 | return error; |
379 | } | 380 | } |
380 | 381 | ||
382 | /* | ||
383 | * This is a copy of sys_ustat, just dealing with a structure layout. | ||
384 | * Given how simple this syscall is that apporach is more maintainable | ||
385 | * than the various conversion hacks. | ||
386 | */ | ||
387 | asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u) | ||
388 | { | ||
389 | struct super_block *sb; | ||
390 | struct compat_ustat tmp; | ||
391 | struct kstatfs sbuf; | ||
392 | int err; | ||
393 | |||
394 | sb = user_get_super(new_decode_dev(dev)); | ||
395 | if (!sb) | ||
396 | return -EINVAL; | ||
397 | err = vfs_statfs(sb->s_root, &sbuf); | ||
398 | drop_super(sb); | ||
399 | if (err) | ||
400 | return err; | ||
401 | |||
402 | memset(&tmp, 0, sizeof(struct compat_ustat)); | ||
403 | tmp.f_tfree = sbuf.f_bfree; | ||
404 | tmp.f_tinode = sbuf.f_ffree; | ||
405 | if (copy_to_user(u, &tmp, sizeof(struct compat_ustat))) | ||
406 | return -EFAULT; | ||
407 | return 0; | ||
408 | } | ||
409 | |||
381 | static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) | 410 | static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl) |
382 | { | 411 | { |
383 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || | 412 | if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) || |
@@ -1167,16 +1196,12 @@ out: | |||
1167 | return ret; | 1196 | return ret; |
1168 | } | 1197 | } |
1169 | 1198 | ||
1170 | asmlinkage ssize_t | 1199 | static size_t compat_readv(struct file *file, |
1171 | compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen) | 1200 | const struct compat_iovec __user *vec, |
1201 | unsigned long vlen, loff_t *pos) | ||
1172 | { | 1202 | { |
1173 | struct file *file; | ||
1174 | ssize_t ret = -EBADF; | 1203 | ssize_t ret = -EBADF; |
1175 | 1204 | ||
1176 | file = fget(fd); | ||
1177 | if (!file) | ||
1178 | return -EBADF; | ||
1179 | |||
1180 | if (!(file->f_mode & FMODE_READ)) | 1205 | if (!(file->f_mode & FMODE_READ)) |
1181 | goto out; | 1206 | goto out; |
1182 | 1207 | ||
@@ -1184,25 +1209,56 @@ compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsign | |||
1184 | if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read)) | 1209 | if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read)) |
1185 | goto out; | 1210 | goto out; |
1186 | 1211 | ||
1187 | ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos); | 1212 | ret = compat_do_readv_writev(READ, file, vec, vlen, pos); |
1188 | 1213 | ||
1189 | out: | 1214 | out: |
1190 | if (ret > 0) | 1215 | if (ret > 0) |
1191 | add_rchar(current, ret); | 1216 | add_rchar(current, ret); |
1192 | inc_syscr(current); | 1217 | inc_syscr(current); |
1193 | fput(file); | ||
1194 | return ret; | 1218 | return ret; |
1195 | } | 1219 | } |
1196 | 1220 | ||
1197 | asmlinkage ssize_t | 1221 | asmlinkage ssize_t |
1198 | compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen) | 1222 | compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, |
1223 | unsigned long vlen) | ||
1199 | { | 1224 | { |
1200 | struct file *file; | 1225 | struct file *file; |
1201 | ssize_t ret = -EBADF; | 1226 | int fput_needed; |
1227 | ssize_t ret; | ||
1202 | 1228 | ||
1203 | file = fget(fd); | 1229 | file = fget_light(fd, &fput_needed); |
1204 | if (!file) | 1230 | if (!file) |
1205 | return -EBADF; | 1231 | return -EBADF; |
1232 | ret = compat_readv(file, vec, vlen, &file->f_pos); | ||
1233 | fput_light(file, fput_needed); | ||
1234 | return ret; | ||
1235 | } | ||
1236 | |||
1237 | asmlinkage ssize_t | ||
1238 | compat_sys_preadv(unsigned long fd, const struct compat_iovec __user *vec, | ||
1239 | unsigned long vlen, u32 pos_low, u32 pos_high) | ||
1240 | { | ||
1241 | loff_t pos = ((loff_t)pos_high << 32) | pos_low; | ||
1242 | struct file *file; | ||
1243 | int fput_needed; | ||
1244 | ssize_t ret; | ||
1245 | |||
1246 | if (pos < 0) | ||
1247 | return -EINVAL; | ||
1248 | file = fget_light(fd, &fput_needed); | ||
1249 | if (!file) | ||
1250 | return -EBADF; | ||
1251 | ret = compat_readv(file, vec, vlen, &pos); | ||
1252 | fput_light(file, fput_needed); | ||
1253 | return ret; | ||
1254 | } | ||
1255 | |||
1256 | static size_t compat_writev(struct file *file, | ||
1257 | const struct compat_iovec __user *vec, | ||
1258 | unsigned long vlen, loff_t *pos) | ||
1259 | { | ||
1260 | ssize_t ret = -EBADF; | ||
1261 | |||
1206 | if (!(file->f_mode & FMODE_WRITE)) | 1262 | if (!(file->f_mode & FMODE_WRITE)) |
1207 | goto out; | 1263 | goto out; |
1208 | 1264 | ||
@@ -1210,13 +1266,47 @@ compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsig | |||
1210 | if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write)) | 1266 | if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write)) |
1211 | goto out; | 1267 | goto out; |
1212 | 1268 | ||
1213 | ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos); | 1269 | ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos); |
1214 | 1270 | ||
1215 | out: | 1271 | out: |
1216 | if (ret > 0) | 1272 | if (ret > 0) |
1217 | add_wchar(current, ret); | 1273 | add_wchar(current, ret); |
1218 | inc_syscw(current); | 1274 | inc_syscw(current); |
1219 | fput(file); | 1275 | return ret; |
1276 | } | ||
1277 | |||
1278 | asmlinkage ssize_t | ||
1279 | compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, | ||
1280 | unsigned long vlen) | ||
1281 | { | ||
1282 | struct file *file; | ||
1283 | int fput_needed; | ||
1284 | ssize_t ret; | ||
1285 | |||
1286 | file = fget_light(fd, &fput_needed); | ||
1287 | if (!file) | ||
1288 | return -EBADF; | ||
1289 | ret = compat_writev(file, vec, vlen, &file->f_pos); | ||
1290 | fput_light(file, fput_needed); | ||
1291 | return ret; | ||
1292 | } | ||
1293 | |||
1294 | asmlinkage ssize_t | ||
1295 | compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec, | ||
1296 | unsigned long vlen, u32 pos_low, u32 pos_high) | ||
1297 | { | ||
1298 | loff_t pos = ((loff_t)pos_high << 32) | pos_low; | ||
1299 | struct file *file; | ||
1300 | int fput_needed; | ||
1301 | ssize_t ret; | ||
1302 | |||
1303 | if (pos < 0) | ||
1304 | return -EINVAL; | ||
1305 | file = fget_light(fd, &fput_needed); | ||
1306 | if (!file) | ||
1307 | return -EBADF; | ||
1308 | ret = compat_writev(file, vec, vlen, &pos); | ||
1309 | fput_light(file, fput_needed); | ||
1220 | return ret; | 1310 | return ret; |
1221 | } | 1311 | } |
1222 | 1312 | ||
@@ -1392,27 +1482,36 @@ int compat_do_execve(char * filename, | |||
1392 | { | 1482 | { |
1393 | struct linux_binprm *bprm; | 1483 | struct linux_binprm *bprm; |
1394 | struct file *file; | 1484 | struct file *file; |
1485 | struct files_struct *displaced; | ||
1395 | int retval; | 1486 | int retval; |
1396 | 1487 | ||
1488 | retval = unshare_files(&displaced); | ||
1489 | if (retval) | ||
1490 | goto out_ret; | ||
1491 | |||
1397 | retval = -ENOMEM; | 1492 | retval = -ENOMEM; |
1398 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); | 1493 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); |
1399 | if (!bprm) | 1494 | if (!bprm) |
1400 | goto out_ret; | 1495 | goto out_files; |
1401 | 1496 | ||
1402 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); | 1497 | retval = mutex_lock_interruptible(¤t->cred_exec_mutex); |
1403 | if (retval < 0) | 1498 | if (retval < 0) |
1404 | goto out_free; | 1499 | goto out_free; |
1500 | current->in_execve = 1; | ||
1405 | 1501 | ||
1406 | retval = -ENOMEM; | 1502 | retval = -ENOMEM; |
1407 | bprm->cred = prepare_exec_creds(); | 1503 | bprm->cred = prepare_exec_creds(); |
1408 | if (!bprm->cred) | 1504 | if (!bprm->cred) |
1409 | goto out_unlock; | 1505 | goto out_unlock; |
1410 | check_unsafe_exec(bprm, current->files); | 1506 | |
1507 | retval = check_unsafe_exec(bprm); | ||
1508 | if (retval) | ||
1509 | goto out_unlock; | ||
1411 | 1510 | ||
1412 | file = open_exec(filename); | 1511 | file = open_exec(filename); |
1413 | retval = PTR_ERR(file); | 1512 | retval = PTR_ERR(file); |
1414 | if (IS_ERR(file)) | 1513 | if (IS_ERR(file)) |
1415 | goto out_unlock; | 1514 | goto out_unmark; |
1416 | 1515 | ||
1417 | sched_exec(); | 1516 | sched_exec(); |
1418 | 1517 | ||
@@ -1454,9 +1553,15 @@ int compat_do_execve(char * filename, | |||
1454 | goto out; | 1553 | goto out; |
1455 | 1554 | ||
1456 | /* execve succeeded */ | 1555 | /* execve succeeded */ |
1556 | write_lock(¤t->fs->lock); | ||
1557 | current->fs->in_exec = 0; | ||
1558 | write_unlock(¤t->fs->lock); | ||
1559 | current->in_execve = 0; | ||
1457 | mutex_unlock(¤t->cred_exec_mutex); | 1560 | mutex_unlock(¤t->cred_exec_mutex); |
1458 | acct_update_integrals(current); | 1561 | acct_update_integrals(current); |
1459 | free_bprm(bprm); | 1562 | free_bprm(bprm); |
1563 | if (displaced) | ||
1564 | put_files_struct(displaced); | ||
1460 | return retval; | 1565 | return retval; |
1461 | 1566 | ||
1462 | out: | 1567 | out: |
@@ -1469,12 +1574,21 @@ out_file: | |||
1469 | fput(bprm->file); | 1574 | fput(bprm->file); |
1470 | } | 1575 | } |
1471 | 1576 | ||
1577 | out_unmark: | ||
1578 | write_lock(¤t->fs->lock); | ||
1579 | current->fs->in_exec = 0; | ||
1580 | write_unlock(¤t->fs->lock); | ||
1581 | |||
1472 | out_unlock: | 1582 | out_unlock: |
1583 | current->in_execve = 0; | ||
1473 | mutex_unlock(¤t->cred_exec_mutex); | 1584 | mutex_unlock(¤t->cred_exec_mutex); |
1474 | 1585 | ||
1475 | out_free: | 1586 | out_free: |
1476 | free_bprm(bprm); | 1587 | free_bprm(bprm); |
1477 | 1588 | ||
1589 | out_files: | ||
1590 | if (displaced) | ||
1591 | reset_files_struct(displaced); | ||
1478 | out_ret: | 1592 | out_ret: |
1479 | return retval; | 1593 | return retval; |
1480 | } | 1594 | } |