diff options
Diffstat (limited to 'fs/compat.c')
-rw-r--r-- | fs/compat.c | 128 |
1 files changed, 53 insertions, 75 deletions
diff --git a/fs/compat.c b/fs/compat.c index 4db6216e5266..15078ce4c04a 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -1257,6 +1257,7 @@ static int compat_copy_strings(int argc, compat_uptr_t __user *argv, | |||
1257 | { | 1257 | { |
1258 | struct page *kmapped_page = NULL; | 1258 | struct page *kmapped_page = NULL; |
1259 | char *kaddr = NULL; | 1259 | char *kaddr = NULL; |
1260 | unsigned long kpos = 0; | ||
1260 | int ret; | 1261 | int ret; |
1261 | 1262 | ||
1262 | while (argc-- > 0) { | 1263 | while (argc-- > 0) { |
@@ -1265,92 +1266,84 @@ static int compat_copy_strings(int argc, compat_uptr_t __user *argv, | |||
1265 | unsigned long pos; | 1266 | unsigned long pos; |
1266 | 1267 | ||
1267 | if (get_user(str, argv+argc) || | 1268 | if (get_user(str, argv+argc) || |
1268 | !(len = strnlen_user(compat_ptr(str), bprm->p))) { | 1269 | !(len = strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) { |
1269 | ret = -EFAULT; | 1270 | ret = -EFAULT; |
1270 | goto out; | 1271 | goto out; |
1271 | } | 1272 | } |
1272 | 1273 | ||
1273 | if (bprm->p < len) { | 1274 | if (len > MAX_ARG_STRLEN) { |
1274 | ret = -E2BIG; | 1275 | ret = -E2BIG; |
1275 | goto out; | 1276 | goto out; |
1276 | } | 1277 | } |
1277 | 1278 | ||
1278 | bprm->p -= len; | 1279 | /* We're going to work our way backwords. */ |
1279 | /* XXX: add architecture specific overflow check here. */ | ||
1280 | pos = bprm->p; | 1280 | pos = bprm->p; |
1281 | str += len; | ||
1282 | bprm->p -= len; | ||
1281 | 1283 | ||
1282 | while (len > 0) { | 1284 | while (len > 0) { |
1283 | int i, new, err; | ||
1284 | int offset, bytes_to_copy; | 1285 | int offset, bytes_to_copy; |
1285 | struct page *page; | ||
1286 | 1286 | ||
1287 | offset = pos % PAGE_SIZE; | 1287 | offset = pos % PAGE_SIZE; |
1288 | i = pos/PAGE_SIZE; | 1288 | if (offset == 0) |
1289 | page = bprm->page[i]; | 1289 | offset = PAGE_SIZE; |
1290 | new = 0; | 1290 | |
1291 | if (!page) { | 1291 | bytes_to_copy = offset; |
1292 | page = alloc_page(GFP_HIGHUSER); | 1292 | if (bytes_to_copy > len) |
1293 | bprm->page[i] = page; | 1293 | bytes_to_copy = len; |
1294 | if (!page) { | 1294 | |
1295 | ret = -ENOMEM; | 1295 | offset -= bytes_to_copy; |
1296 | pos -= bytes_to_copy; | ||
1297 | str -= bytes_to_copy; | ||
1298 | len -= bytes_to_copy; | ||
1299 | |||
1300 | if (!kmapped_page || kpos != (pos & PAGE_MASK)) { | ||
1301 | struct page *page; | ||
1302 | |||
1303 | #ifdef CONFIG_STACK_GROWSUP | ||
1304 | ret = expand_stack_downwards(bprm->vma, pos); | ||
1305 | if (ret < 0) { | ||
1306 | /* We've exceed the stack rlimit. */ | ||
1307 | ret = -E2BIG; | ||
1308 | goto out; | ||
1309 | } | ||
1310 | #endif | ||
1311 | ret = get_user_pages(current, bprm->mm, pos, | ||
1312 | 1, 1, 1, &page, NULL); | ||
1313 | if (ret <= 0) { | ||
1314 | /* We've exceed the stack rlimit. */ | ||
1315 | ret = -E2BIG; | ||
1296 | goto out; | 1316 | goto out; |
1297 | } | 1317 | } |
1298 | new = 1; | ||
1299 | } | ||
1300 | 1318 | ||
1301 | if (page != kmapped_page) { | 1319 | if (kmapped_page) { |
1302 | if (kmapped_page) | 1320 | flush_kernel_dcache_page(kmapped_page); |
1303 | kunmap(kmapped_page); | 1321 | kunmap(kmapped_page); |
1322 | put_page(kmapped_page); | ||
1323 | } | ||
1304 | kmapped_page = page; | 1324 | kmapped_page = page; |
1305 | kaddr = kmap(kmapped_page); | 1325 | kaddr = kmap(kmapped_page); |
1326 | kpos = pos & PAGE_MASK; | ||
1327 | flush_cache_page(bprm->vma, kpos, | ||
1328 | page_to_pfn(kmapped_page)); | ||
1306 | } | 1329 | } |
1307 | if (new && offset) | 1330 | if (copy_from_user(kaddr+offset, compat_ptr(str), |
1308 | memset(kaddr, 0, offset); | 1331 | bytes_to_copy)) { |
1309 | bytes_to_copy = PAGE_SIZE - offset; | ||
1310 | if (bytes_to_copy > len) { | ||
1311 | bytes_to_copy = len; | ||
1312 | if (new) | ||
1313 | memset(kaddr+offset+len, 0, | ||
1314 | PAGE_SIZE-offset-len); | ||
1315 | } | ||
1316 | err = copy_from_user(kaddr+offset, compat_ptr(str), | ||
1317 | bytes_to_copy); | ||
1318 | if (err) { | ||
1319 | ret = -EFAULT; | 1332 | ret = -EFAULT; |
1320 | goto out; | 1333 | goto out; |
1321 | } | 1334 | } |
1322 | |||
1323 | pos += bytes_to_copy; | ||
1324 | str += bytes_to_copy; | ||
1325 | len -= bytes_to_copy; | ||
1326 | } | 1335 | } |
1327 | } | 1336 | } |
1328 | ret = 0; | 1337 | ret = 0; |
1329 | out: | 1338 | out: |
1330 | if (kmapped_page) | 1339 | if (kmapped_page) { |
1340 | flush_kernel_dcache_page(kmapped_page); | ||
1331 | kunmap(kmapped_page); | 1341 | kunmap(kmapped_page); |
1332 | return ret; | 1342 | put_page(kmapped_page); |
1333 | } | ||
1334 | |||
1335 | #ifdef CONFIG_MMU | ||
1336 | |||
1337 | #define free_arg_pages(bprm) do { } while (0) | ||
1338 | |||
1339 | #else | ||
1340 | |||
1341 | static inline void free_arg_pages(struct linux_binprm *bprm) | ||
1342 | { | ||
1343 | int i; | ||
1344 | |||
1345 | for (i = 0; i < MAX_ARG_PAGES; i++) { | ||
1346 | if (bprm->page[i]) | ||
1347 | __free_page(bprm->page[i]); | ||
1348 | bprm->page[i] = NULL; | ||
1349 | } | 1343 | } |
1344 | return ret; | ||
1350 | } | 1345 | } |
1351 | 1346 | ||
1352 | #endif /* CONFIG_MMU */ | ||
1353 | |||
1354 | /* | 1347 | /* |
1355 | * compat_do_execve() is mostly a copy of do_execve(), with the exception | 1348 | * compat_do_execve() is mostly a copy of do_execve(), with the exception |
1356 | * that it processes 32 bit argv and envp pointers. | 1349 | * that it processes 32 bit argv and envp pointers. |
@@ -1363,7 +1356,6 @@ int compat_do_execve(char * filename, | |||
1363 | struct linux_binprm *bprm; | 1356 | struct linux_binprm *bprm; |
1364 | struct file *file; | 1357 | struct file *file; |
1365 | int retval; | 1358 | int retval; |
1366 | int i; | ||
1367 | 1359 | ||
1368 | retval = -ENOMEM; | 1360 | retval = -ENOMEM; |
1369 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); | 1361 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); |
@@ -1377,24 +1369,19 @@ int compat_do_execve(char * filename, | |||
1377 | 1369 | ||
1378 | sched_exec(); | 1370 | sched_exec(); |
1379 | 1371 | ||
1380 | bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); | ||
1381 | bprm->file = file; | 1372 | bprm->file = file; |
1382 | bprm->filename = filename; | 1373 | bprm->filename = filename; |
1383 | bprm->interp = filename; | 1374 | bprm->interp = filename; |
1384 | bprm->mm = mm_alloc(); | ||
1385 | retval = -ENOMEM; | ||
1386 | if (!bprm->mm) | ||
1387 | goto out_file; | ||
1388 | 1375 | ||
1389 | retval = init_new_context(current, bprm->mm); | 1376 | retval = bprm_mm_init(bprm); |
1390 | if (retval < 0) | 1377 | if (retval) |
1391 | goto out_mm; | 1378 | goto out_file; |
1392 | 1379 | ||
1393 | bprm->argc = compat_count(argv, bprm->p / sizeof(compat_uptr_t)); | 1380 | bprm->argc = compat_count(argv, MAX_ARG_STRINGS); |
1394 | if ((retval = bprm->argc) < 0) | 1381 | if ((retval = bprm->argc) < 0) |
1395 | goto out_mm; | 1382 | goto out_mm; |
1396 | 1383 | ||
1397 | bprm->envc = compat_count(envp, bprm->p / sizeof(compat_uptr_t)); | 1384 | bprm->envc = compat_count(envp, MAX_ARG_STRINGS); |
1398 | if ((retval = bprm->envc) < 0) | 1385 | if ((retval = bprm->envc) < 0) |
1399 | goto out_mm; | 1386 | goto out_mm; |
1400 | 1387 | ||
@@ -1421,8 +1408,6 @@ int compat_do_execve(char * filename, | |||
1421 | 1408 | ||
1422 | retval = search_binary_handler(bprm, regs); | 1409 | retval = search_binary_handler(bprm, regs); |
1423 | if (retval >= 0) { | 1410 | if (retval >= 0) { |
1424 | free_arg_pages(bprm); | ||
1425 | |||
1426 | /* execve success */ | 1411 | /* execve success */ |
1427 | security_bprm_free(bprm); | 1412 | security_bprm_free(bprm); |
1428 | acct_update_integrals(current); | 1413 | acct_update_integrals(current); |
@@ -1431,19 +1416,12 @@ int compat_do_execve(char * filename, | |||
1431 | } | 1416 | } |
1432 | 1417 | ||
1433 | out: | 1418 | out: |
1434 | /* Something went wrong, return the inode and free the argument pages*/ | ||
1435 | for (i = 0 ; i < MAX_ARG_PAGES ; i++) { | ||
1436 | struct page * page = bprm->page[i]; | ||
1437 | if (page) | ||
1438 | __free_page(page); | ||
1439 | } | ||
1440 | |||
1441 | if (bprm->security) | 1419 | if (bprm->security) |
1442 | security_bprm_free(bprm); | 1420 | security_bprm_free(bprm); |
1443 | 1421 | ||
1444 | out_mm: | 1422 | out_mm: |
1445 | if (bprm->mm) | 1423 | if (bprm->mm) |
1446 | mmdrop(bprm->mm); | 1424 | mmput(bprm->mm); |
1447 | 1425 | ||
1448 | out_file: | 1426 | out_file: |
1449 | if (bprm->file) { | 1427 | if (bprm->file) { |