diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 34 |
1 files changed, 24 insertions, 10 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 234d9454294e..0bc8fa3c2288 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1349,8 +1349,10 @@ asmlinkage long sys_sethostname(char __user *name, int len) | |||
1349 | down_write(&uts_sem); | 1349 | down_write(&uts_sem); |
1350 | errno = -EFAULT; | 1350 | errno = -EFAULT; |
1351 | if (!copy_from_user(tmp, name, len)) { | 1351 | if (!copy_from_user(tmp, name, len)) { |
1352 | memcpy(utsname()->nodename, tmp, len); | 1352 | struct new_utsname *u = utsname(); |
1353 | utsname()->nodename[len] = 0; | 1353 | |
1354 | memcpy(u->nodename, tmp, len); | ||
1355 | memset(u->nodename + len, 0, sizeof(u->nodename) - len); | ||
1354 | errno = 0; | 1356 | errno = 0; |
1355 | } | 1357 | } |
1356 | up_write(&uts_sem); | 1358 | up_write(&uts_sem); |
@@ -1362,15 +1364,17 @@ asmlinkage long sys_sethostname(char __user *name, int len) | |||
1362 | asmlinkage long sys_gethostname(char __user *name, int len) | 1364 | asmlinkage long sys_gethostname(char __user *name, int len) |
1363 | { | 1365 | { |
1364 | int i, errno; | 1366 | int i, errno; |
1367 | struct new_utsname *u; | ||
1365 | 1368 | ||
1366 | if (len < 0) | 1369 | if (len < 0) |
1367 | return -EINVAL; | 1370 | return -EINVAL; |
1368 | down_read(&uts_sem); | 1371 | down_read(&uts_sem); |
1369 | i = 1 + strlen(utsname()->nodename); | 1372 | u = utsname(); |
1373 | i = 1 + strlen(u->nodename); | ||
1370 | if (i > len) | 1374 | if (i > len) |
1371 | i = len; | 1375 | i = len; |
1372 | errno = 0; | 1376 | errno = 0; |
1373 | if (copy_to_user(name, utsname()->nodename, i)) | 1377 | if (copy_to_user(name, u->nodename, i)) |
1374 | errno = -EFAULT; | 1378 | errno = -EFAULT; |
1375 | up_read(&uts_sem); | 1379 | up_read(&uts_sem); |
1376 | return errno; | 1380 | return errno; |
@@ -1395,8 +1399,10 @@ asmlinkage long sys_setdomainname(char __user *name, int len) | |||
1395 | down_write(&uts_sem); | 1399 | down_write(&uts_sem); |
1396 | errno = -EFAULT; | 1400 | errno = -EFAULT; |
1397 | if (!copy_from_user(tmp, name, len)) { | 1401 | if (!copy_from_user(tmp, name, len)) { |
1398 | memcpy(utsname()->domainname, tmp, len); | 1402 | struct new_utsname *u = utsname(); |
1399 | utsname()->domainname[len] = 0; | 1403 | |
1404 | memcpy(u->domainname, tmp, len); | ||
1405 | memset(u->domainname + len, 0, sizeof(u->domainname) - len); | ||
1400 | errno = 0; | 1406 | errno = 0; |
1401 | } | 1407 | } |
1402 | up_write(&uts_sem); | 1408 | up_write(&uts_sem); |
@@ -1450,14 +1456,22 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim) | |||
1450 | return -EINVAL; | 1456 | return -EINVAL; |
1451 | if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) | 1457 | if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) |
1452 | return -EFAULT; | 1458 | return -EFAULT; |
1453 | if (new_rlim.rlim_cur > new_rlim.rlim_max) | ||
1454 | return -EINVAL; | ||
1455 | old_rlim = current->signal->rlim + resource; | 1459 | old_rlim = current->signal->rlim + resource; |
1456 | if ((new_rlim.rlim_max > old_rlim->rlim_max) && | 1460 | if ((new_rlim.rlim_max > old_rlim->rlim_max) && |
1457 | !capable(CAP_SYS_RESOURCE)) | 1461 | !capable(CAP_SYS_RESOURCE)) |
1458 | return -EPERM; | 1462 | return -EPERM; |
1459 | if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open) | 1463 | |
1460 | return -EPERM; | 1464 | if (resource == RLIMIT_NOFILE) { |
1465 | if (new_rlim.rlim_max == RLIM_INFINITY) | ||
1466 | new_rlim.rlim_max = sysctl_nr_open; | ||
1467 | if (new_rlim.rlim_cur == RLIM_INFINITY) | ||
1468 | new_rlim.rlim_cur = sysctl_nr_open; | ||
1469 | if (new_rlim.rlim_max > sysctl_nr_open) | ||
1470 | return -EPERM; | ||
1471 | } | ||
1472 | |||
1473 | if (new_rlim.rlim_cur > new_rlim.rlim_max) | ||
1474 | return -EINVAL; | ||
1461 | 1475 | ||
1462 | retval = security_task_setrlimit(resource, &new_rlim); | 1476 | retval = security_task_setrlimit(resource, &new_rlim); |
1463 | if (retval) | 1477 | if (retval) |