aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sysctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sysctl.c')
-rw-r--r--kernel/sysctl.c177
1 files changed, 156 insertions, 21 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 35a50db9b6ce..1bf369bd4423 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -118,10 +118,8 @@ extern char modprobe_path[];
118extern int sg_big_buff; 118extern int sg_big_buff;
119#endif 119#endif
120 120
121#ifdef __sparc__ 121#ifdef CONFIG_SPARC
122extern char reboot_command []; 122#include <asm/system.h>
123extern int stop_a_enabled;
124extern int scons_pwroff;
125#endif 123#endif
126 124
127#ifdef __hppa__ 125#ifdef __hppa__
@@ -159,13 +157,15 @@ static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *
159static struct ctl_table root_table[]; 157static struct ctl_table root_table[];
160static struct ctl_table_root sysctl_table_root; 158static struct ctl_table_root sysctl_table_root;
161static struct ctl_table_header root_table_header = { 159static struct ctl_table_header root_table_header = {
160 .count = 1,
162 .ctl_table = root_table, 161 .ctl_table = root_table,
163 .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.header_list), 162 .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),
164 .root = &sysctl_table_root, 163 .root = &sysctl_table_root,
164 .set = &sysctl_table_root.default_set,
165}; 165};
166static struct ctl_table_root sysctl_table_root = { 166static struct ctl_table_root sysctl_table_root = {
167 .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list), 167 .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list),
168 .header_list = LIST_HEAD_INIT(root_table_header.ctl_entry), 168 .default_set.list = LIST_HEAD_INIT(root_table_header.ctl_entry),
169}; 169};
170 170
171static struct ctl_table kern_table[]; 171static struct ctl_table kern_table[];
@@ -413,7 +413,7 @@ static struct ctl_table kern_table[] = {
413 .mode = 0644, 413 .mode = 0644,
414 .proc_handler = &proc_dointvec, 414 .proc_handler = &proc_dointvec,
415 }, 415 },
416#ifdef __sparc__ 416#ifdef CONFIG_SPARC
417 { 417 {
418 .ctl_name = KERN_SPARC_REBOOT, 418 .ctl_name = KERN_SPARC_REBOOT,
419 .procname = "reboot-cmd", 419 .procname = "reboot-cmd",
@@ -1386,6 +1386,9 @@ static void start_unregistering(struct ctl_table_header *p)
1386 spin_unlock(&sysctl_lock); 1386 spin_unlock(&sysctl_lock);
1387 wait_for_completion(&wait); 1387 wait_for_completion(&wait);
1388 spin_lock(&sysctl_lock); 1388 spin_lock(&sysctl_lock);
1389 } else {
1390 /* anything non-NULL; we'll never dereference it */
1391 p->unregistering = ERR_PTR(-EINVAL);
1389 } 1392 }
1390 /* 1393 /*
1391 * do not remove from the list until nobody holds it; walking the 1394 * do not remove from the list until nobody holds it; walking the
@@ -1394,6 +1397,32 @@ static void start_unregistering(struct ctl_table_header *p)
1394 list_del_init(&p->ctl_entry); 1397 list_del_init(&p->ctl_entry);
1395} 1398}
1396 1399
1400void sysctl_head_get(struct ctl_table_header *head)
1401{
1402 spin_lock(&sysctl_lock);
1403 head->count++;
1404 spin_unlock(&sysctl_lock);
1405}
1406
1407void sysctl_head_put(struct ctl_table_header *head)
1408{
1409 spin_lock(&sysctl_lock);
1410 if (!--head->count)
1411 kfree(head);
1412 spin_unlock(&sysctl_lock);
1413}
1414
1415struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head)
1416{
1417 if (!head)
1418 BUG();
1419 spin_lock(&sysctl_lock);
1420 if (!use_table(head))
1421 head = ERR_PTR(-ENOENT);
1422 spin_unlock(&sysctl_lock);
1423 return head;
1424}
1425
1397void sysctl_head_finish(struct ctl_table_header *head) 1426void sysctl_head_finish(struct ctl_table_header *head)
1398{ 1427{
1399 if (!head) 1428 if (!head)
@@ -1403,14 +1432,20 @@ void sysctl_head_finish(struct ctl_table_header *head)
1403 spin_unlock(&sysctl_lock); 1432 spin_unlock(&sysctl_lock);
1404} 1433}
1405 1434
1435static struct ctl_table_set *
1436lookup_header_set(struct ctl_table_root *root, struct nsproxy *namespaces)
1437{
1438 struct ctl_table_set *set = &root->default_set;
1439 if (root->lookup)
1440 set = root->lookup(root, namespaces);
1441 return set;
1442}
1443
1406static struct list_head * 1444static struct list_head *
1407lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces) 1445lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces)
1408{ 1446{
1409 struct list_head *header_list; 1447 struct ctl_table_set *set = lookup_header_set(root, namespaces);
1410 header_list = &root->header_list; 1448 return &set->list;
1411 if (root->lookup)
1412 header_list = root->lookup(root, namespaces);
1413 return header_list;
1414} 1449}
1415 1450
1416struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces, 1451struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
@@ -1480,9 +1515,9 @@ static int do_sysctl_strategy(struct ctl_table_root *root,
1480 int op = 0, rc; 1515 int op = 0, rc;
1481 1516
1482 if (oldval) 1517 if (oldval)
1483 op |= 004; 1518 op |= MAY_READ;
1484 if (newval) 1519 if (newval)
1485 op |= 002; 1520 op |= MAY_WRITE;
1486 if (sysctl_perm(root, table, op)) 1521 if (sysctl_perm(root, table, op))
1487 return -EPERM; 1522 return -EPERM;
1488 1523
@@ -1524,7 +1559,7 @@ repeat:
1524 if (n == table->ctl_name) { 1559 if (n == table->ctl_name) {
1525 int error; 1560 int error;
1526 if (table->child) { 1561 if (table->child) {
1527 if (sysctl_perm(root, table, 001)) 1562 if (sysctl_perm(root, table, MAY_EXEC))
1528 return -EPERM; 1563 return -EPERM;
1529 name++; 1564 name++;
1530 nlen--; 1565 nlen--;
@@ -1599,7 +1634,7 @@ static int test_perm(int mode, int op)
1599 mode >>= 6; 1634 mode >>= 6;
1600 else if (in_egroup_p(0)) 1635 else if (in_egroup_p(0))
1601 mode >>= 3; 1636 mode >>= 3;
1602 if ((mode & op & 0007) == op) 1637 if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)
1603 return 0; 1638 return 0;
1604 return -EACCES; 1639 return -EACCES;
1605} 1640}
@@ -1609,7 +1644,7 @@ int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
1609 int error; 1644 int error;
1610 int mode; 1645 int mode;
1611 1646
1612 error = security_sysctl(table, op); 1647 error = security_sysctl(table, op & (MAY_READ | MAY_WRITE | MAY_EXEC));
1613 if (error) 1648 if (error)
1614 return error; 1649 return error;
1615 1650
@@ -1644,6 +1679,54 @@ static __init int sysctl_init(void)
1644 1679
1645core_initcall(sysctl_init); 1680core_initcall(sysctl_init);
1646 1681
1682static struct ctl_table *is_branch_in(struct ctl_table *branch,
1683 struct ctl_table *table)
1684{
1685 struct ctl_table *p;
1686 const char *s = branch->procname;
1687
1688 /* branch should have named subdirectory as its first element */
1689 if (!s || !branch->child)
1690 return NULL;
1691
1692 /* ... and nothing else */
1693 if (branch[1].procname || branch[1].ctl_name)
1694 return NULL;
1695
1696 /* table should contain subdirectory with the same name */
1697 for (p = table; p->procname || p->ctl_name; p++) {
1698 if (!p->child)
1699 continue;
1700 if (p->procname && strcmp(p->procname, s) == 0)
1701 return p;
1702 }
1703 return NULL;
1704}
1705
1706/* see if attaching q to p would be an improvement */
1707static void try_attach(struct ctl_table_header *p, struct ctl_table_header *q)
1708{
1709 struct ctl_table *to = p->ctl_table, *by = q->ctl_table;
1710 struct ctl_table *next;
1711 int is_better = 0;
1712 int not_in_parent = !p->attached_by;
1713
1714 while ((next = is_branch_in(by, to)) != NULL) {
1715 if (by == q->attached_by)
1716 is_better = 1;
1717 if (to == p->attached_by)
1718 not_in_parent = 1;
1719 by = by->child;
1720 to = next->child;
1721 }
1722
1723 if (is_better && not_in_parent) {
1724 q->attached_by = by;
1725 q->attached_to = to;
1726 q->parent = p;
1727 }
1728}
1729
1647/** 1730/**
1648 * __register_sysctl_paths - register a sysctl hierarchy 1731 * __register_sysctl_paths - register a sysctl hierarchy
1649 * @root: List of sysctl headers to register on 1732 * @root: List of sysctl headers to register on
@@ -1720,10 +1803,10 @@ struct ctl_table_header *__register_sysctl_paths(
1720 struct nsproxy *namespaces, 1803 struct nsproxy *namespaces,
1721 const struct ctl_path *path, struct ctl_table *table) 1804 const struct ctl_path *path, struct ctl_table *table)
1722{ 1805{
1723 struct list_head *header_list;
1724 struct ctl_table_header *header; 1806 struct ctl_table_header *header;
1725 struct ctl_table *new, **prevp; 1807 struct ctl_table *new, **prevp;
1726 unsigned int n, npath; 1808 unsigned int n, npath;
1809 struct ctl_table_set *set;
1727 1810
1728 /* Count the path components */ 1811 /* Count the path components */
1729 for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath) 1812 for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath)
@@ -1765,6 +1848,7 @@ struct ctl_table_header *__register_sysctl_paths(
1765 header->unregistering = NULL; 1848 header->unregistering = NULL;
1766 header->root = root; 1849 header->root = root;
1767 sysctl_set_parent(NULL, header->ctl_table); 1850 sysctl_set_parent(NULL, header->ctl_table);
1851 header->count = 1;
1768#ifdef CONFIG_SYSCTL_SYSCALL_CHECK 1852#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
1769 if (sysctl_check_table(namespaces, header->ctl_table)) { 1853 if (sysctl_check_table(namespaces, header->ctl_table)) {
1770 kfree(header); 1854 kfree(header);
@@ -1772,8 +1856,20 @@ struct ctl_table_header *__register_sysctl_paths(
1772 } 1856 }
1773#endif 1857#endif
1774 spin_lock(&sysctl_lock); 1858 spin_lock(&sysctl_lock);
1775 header_list = lookup_header_list(root, namespaces); 1859 header->set = lookup_header_set(root, namespaces);
1776 list_add_tail(&header->ctl_entry, header_list); 1860 header->attached_by = header->ctl_table;
1861 header->attached_to = root_table;
1862 header->parent = &root_table_header;
1863 for (set = header->set; set; set = set->parent) {
1864 struct ctl_table_header *p;
1865 list_for_each_entry(p, &set->list, ctl_entry) {
1866 if (p->unregistering)
1867 continue;
1868 try_attach(p, header);
1869 }
1870 }
1871 header->parent->count++;
1872 list_add_tail(&header->ctl_entry, &header->set->list);
1777 spin_unlock(&sysctl_lock); 1873 spin_unlock(&sysctl_lock);
1778 1874
1779 return header; 1875 return header;
@@ -1828,8 +1924,37 @@ void unregister_sysctl_table(struct ctl_table_header * header)
1828 1924
1829 spin_lock(&sysctl_lock); 1925 spin_lock(&sysctl_lock);
1830 start_unregistering(header); 1926 start_unregistering(header);
1927 if (!--header->parent->count) {
1928 WARN_ON(1);
1929 kfree(header->parent);
1930 }
1931 if (!--header->count)
1932 kfree(header);
1831 spin_unlock(&sysctl_lock); 1933 spin_unlock(&sysctl_lock);
1832 kfree(header); 1934}
1935
1936int sysctl_is_seen(struct ctl_table_header *p)
1937{
1938 struct ctl_table_set *set = p->set;
1939 int res;
1940 spin_lock(&sysctl_lock);
1941 if (p->unregistering)
1942 res = 0;
1943 else if (!set->is_seen)
1944 res = 1;
1945 else
1946 res = set->is_seen(set);
1947 spin_unlock(&sysctl_lock);
1948 return res;
1949}
1950
1951void setup_sysctl_set(struct ctl_table_set *p,
1952 struct ctl_table_set *parent,
1953 int (*is_seen)(struct ctl_table_set *))
1954{
1955 INIT_LIST_HEAD(&p->list);
1956 p->parent = parent ? parent : &sysctl_table_root.default_set;
1957 p->is_seen = is_seen;
1833} 1958}
1834 1959
1835#else /* !CONFIG_SYSCTL */ 1960#else /* !CONFIG_SYSCTL */
@@ -1848,6 +1973,16 @@ void unregister_sysctl_table(struct ctl_table_header * table)
1848{ 1973{
1849} 1974}
1850 1975
1976void setup_sysctl_set(struct ctl_table_set *p,
1977 struct ctl_table_set *parent,
1978 int (*is_seen)(struct ctl_table_set *))
1979{
1980}
1981
1982void sysctl_head_put(struct ctl_table_header *head)
1983{
1984}
1985
1851#endif /* CONFIG_SYSCTL */ 1986#endif /* CONFIG_SYSCTL */
1852 1987
1853/* 1988/*