aboutsummaryrefslogtreecommitdiffstats
path: root/fs/compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/compat.c')
-rw-r--r--fs/compat.c128
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;
1329out: 1338out:
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
1341static 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
1433out: 1418out:
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
1444out_mm: 1422out_mm:
1445 if (bprm->mm) 1423 if (bprm->mm)
1446 mmdrop(bprm->mm); 1424 mmput(bprm->mm);
1447 1425
1448out_file: 1426out_file:
1449 if (bprm->file) { 1427 if (bprm->file) {