aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorMichal Hocko <mhocko@suse.cz>2011-01-13 18:47:26 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 20:32:49 -0500
commit08d4a24659f1284f33e574211435aa12ce968477 (patch)
treea3bfdee153157acd502452635aa33f842c0f97eb /mm
parentcb9ef8d5e394f70db64bda79c20d3569a20d2574 (diff)
hugetlb: check the return value of string conversion in sysctl handler
proc_doulongvec_minmax may fail if the given buffer doesn't represent a valid number. If we provide something invalid we will initialize the resulting value (nr_overcommit_huge_pages in this case) to a random value from the stack. The issue was introduced by a3d0c6aa when the default handler has been replaced by the helper function where we do not check the return value. Reproducer: echo "" > /proc/sys/vm/nr_overcommit_hugepages [akpm@linux-foundation.org: correctly propagate proc_doulongvec_minmax return code] Signed-off-by: Michal Hocko <mhocko@suse.cz> Cc: CAI Qian <caiqian@redhat.com> Cc: Nishanth Aravamudan <nacc@us.ibm.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/hugetlb.c18
1 files changed, 12 insertions, 6 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 8e31cda6fc22..363c4d22602a 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1859,13 +1859,16 @@ static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
1859{ 1859{
1860 struct hstate *h = &default_hstate; 1860 struct hstate *h = &default_hstate;
1861 unsigned long tmp; 1861 unsigned long tmp;
1862 int ret;
1862 1863
1863 if (!write) 1864 if (!write)
1864 tmp = h->max_huge_pages; 1865 tmp = h->max_huge_pages;
1865 1866
1866 table->data = &tmp; 1867 table->data = &tmp;
1867 table->maxlen = sizeof(unsigned long); 1868 table->maxlen = sizeof(unsigned long);
1868 proc_doulongvec_minmax(table, write, buffer, length, ppos); 1869 ret = proc_doulongvec_minmax(table, write, buffer, length, ppos);
1870 if (ret)
1871 goto out;
1869 1872
1870 if (write) { 1873 if (write) {
1871 NODEMASK_ALLOC(nodemask_t, nodes_allowed, 1874 NODEMASK_ALLOC(nodemask_t, nodes_allowed,
@@ -1880,8 +1883,8 @@ static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
1880 if (nodes_allowed != &node_states[N_HIGH_MEMORY]) 1883 if (nodes_allowed != &node_states[N_HIGH_MEMORY])
1881 NODEMASK_FREE(nodes_allowed); 1884 NODEMASK_FREE(nodes_allowed);
1882 } 1885 }
1883 1886out:
1884 return 0; 1887 return ret;
1885} 1888}
1886 1889
1887int hugetlb_sysctl_handler(struct ctl_table *table, int write, 1890int hugetlb_sysctl_handler(struct ctl_table *table, int write,
@@ -1919,21 +1922,24 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write,
1919{ 1922{
1920 struct hstate *h = &default_hstate; 1923 struct hstate *h = &default_hstate;
1921 unsigned long tmp; 1924 unsigned long tmp;
1925 int ret;
1922 1926
1923 if (!write) 1927 if (!write)
1924 tmp = h->nr_overcommit_huge_pages; 1928 tmp = h->nr_overcommit_huge_pages;
1925 1929
1926 table->data = &tmp; 1930 table->data = &tmp;
1927 table->maxlen = sizeof(unsigned long); 1931 table->maxlen = sizeof(unsigned long);
1928 proc_doulongvec_minmax(table, write, buffer, length, ppos); 1932 ret = proc_doulongvec_minmax(table, write, buffer, length, ppos);
1933 if (ret)
1934 goto out;
1929 1935
1930 if (write) { 1936 if (write) {
1931 spin_lock(&hugetlb_lock); 1937 spin_lock(&hugetlb_lock);
1932 h->nr_overcommit_huge_pages = tmp; 1938 h->nr_overcommit_huge_pages = tmp;
1933 spin_unlock(&hugetlb_lock); 1939 spin_unlock(&hugetlb_lock);
1934 } 1940 }
1935 1941out:
1936 return 0; 1942 return ret;
1937} 1943}
1938 1944
1939#endif /* CONFIG_SYSCTL */ 1945#endif /* CONFIG_SYSCTL */