aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sysctl_binary.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sysctl_binary.c')
-rw-r--r--kernel/sysctl_binary.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index 112533d5fc0..8cd50d8f9bd 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -1331,7 +1331,7 @@ static ssize_t binary_sysctl(const int *name, int nlen,
1331 ssize_t result; 1331 ssize_t result;
1332 char *pathname; 1332 char *pathname;
1333 int flags; 1333 int flags;
1334 int acc_mode, fmode; 1334 int acc_mode;
1335 1335
1336 pathname = sysctl_getname(name, nlen, &table); 1336 pathname = sysctl_getname(name, nlen, &table);
1337 result = PTR_ERR(pathname); 1337 result = PTR_ERR(pathname);
@@ -1342,15 +1342,12 @@ static ssize_t binary_sysctl(const int *name, int nlen,
1342 if (oldval && oldlen && newval && newlen) { 1342 if (oldval && oldlen && newval && newlen) {
1343 flags = O_RDWR; 1343 flags = O_RDWR;
1344 acc_mode = MAY_READ | MAY_WRITE; 1344 acc_mode = MAY_READ | MAY_WRITE;
1345 fmode = FMODE_READ | FMODE_WRITE;
1346 } else if (newval && newlen) { 1345 } else if (newval && newlen) {
1347 flags = O_WRONLY; 1346 flags = O_WRONLY;
1348 acc_mode = MAY_WRITE; 1347 acc_mode = MAY_WRITE;
1349 fmode = FMODE_WRITE;
1350 } else if (oldval && oldlen) { 1348 } else if (oldval && oldlen) {
1351 flags = O_RDONLY; 1349 flags = O_RDONLY;
1352 acc_mode = MAY_READ; 1350 acc_mode = MAY_READ;
1353 fmode = FMODE_READ;
1354 } else { 1351 } else {
1355 result = 0; 1352 result = 0;
1356 goto out_putname; 1353 goto out_putname;
@@ -1361,7 +1358,7 @@ static ssize_t binary_sysctl(const int *name, int nlen,
1361 if (result) 1358 if (result)
1362 goto out_putname; 1359 goto out_putname;
1363 1360
1364 result = may_open(&nd.path, acc_mode, fmode); 1361 result = may_open(&nd.path, acc_mode, flags);
1365 if (result) 1362 if (result)
1366 goto out_putpath; 1363 goto out_putpath;
1367 1364
@@ -1417,6 +1414,35 @@ static void deprecated_sysctl_warning(const int *name, int nlen)
1417 return; 1414 return;
1418} 1415}
1419 1416
1417#define WARN_ONCE_HASH_BITS 8
1418#define WARN_ONCE_HASH_SIZE (1<<WARN_ONCE_HASH_BITS)
1419
1420static DECLARE_BITMAP(warn_once_bitmap, WARN_ONCE_HASH_SIZE);
1421
1422#define FNV32_OFFSET 2166136261U
1423#define FNV32_PRIME 0x01000193
1424
1425/*
1426 * Print each legacy sysctl (approximately) only once.
1427 * To avoid making the tables non-const use a external
1428 * hash-table instead.
1429 * Worst case hash collision: 6, but very rarely.
1430 * NOTE! We don't use the SMP-safe bit tests. We simply
1431 * don't care enough.
1432 */
1433static void warn_on_bintable(const int *name, int nlen)
1434{
1435 int i;
1436 u32 hash = FNV32_OFFSET;
1437
1438 for (i = 0; i < nlen; i++)
1439 hash = (hash ^ name[i]) * FNV32_PRIME;
1440 hash %= WARN_ONCE_HASH_SIZE;
1441 if (__test_and_set_bit(hash, warn_once_bitmap))
1442 return;
1443 deprecated_sysctl_warning(name, nlen);
1444}
1445
1420static ssize_t do_sysctl(int __user *args_name, int nlen, 1446static ssize_t do_sysctl(int __user *args_name, int nlen,
1421 void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) 1447 void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
1422{ 1448{
@@ -1431,7 +1457,7 @@ static ssize_t do_sysctl(int __user *args_name, int nlen,
1431 if (get_user(name[i], args_name + i)) 1457 if (get_user(name[i], args_name + i))
1432 return -EFAULT; 1458 return -EFAULT;
1433 1459
1434 deprecated_sysctl_warning(name, nlen); 1460 warn_on_bintable(name, nlen);
1435 1461
1436 return binary_sysctl(name, nlen, oldval, oldlen, newval, newlen); 1462 return binary_sysctl(name, nlen, oldval, oldlen, newval, newlen);
1437} 1463}