1 |
From bae7c7c764413b23e61cb099ce33be4c4ee259bb Mon Sep 17 00:00:00 2001 |
2 |
From: Florian Weimer <fweimer@redhat.com> |
3 |
Date: Thu, 28 Jan 2016 13:59:11 +0100 |
4 |
Subject: [PATCH] Improve check against integer wraparound in hcreate_r [BZ |
5 |
#18240] |
6 |
|
7 |
--- |
8 |
ChangeLog | 12 +++++++++ |
9 |
misc/Makefile | 2 +- |
10 |
misc/bug18240.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
11 |
misc/hsearch_r.c | 35 +++++++++++++------------- |
12 |
4 files changed, 105 insertions(+), 19 deletions(-) |
13 |
create mode 100644 misc/bug18240.c |
14 |
|
15 |
#diff --git a/ChangeLog b/ChangeLog |
16 |
#index 9cb8df3..a0fd225 100644 |
17 |
#--- a/ChangeLog |
18 |
#+++ b/ChangeLog |
19 |
#@@ -1,3 +1,15 @@ |
20 |
#+2016-01-27 Paul Eggert <eggert@cs.ucla.edu> |
21 |
#+ |
22 |
#+ [BZ #18240] |
23 |
#+ * misc/hsearch_r.c (isprime, __hcreate_r): Protect against |
24 |
#+ unsigned int wraparound. |
25 |
#+ |
26 |
#+2016-01-27 Florian Weimer <fweimer@redhat.com> |
27 |
#+ |
28 |
#+ [BZ #18240] |
29 |
#+ * misc/bug18240.c: New test. |
30 |
#+ * misc/Makefile (tests): Add it. |
31 |
#+ |
32 |
# 2016-01-28 Steve Ellcey <sellcey@imgtec.com> |
33 |
# Joseph Myers <joseph@codesourcery.com> |
34 |
# |
35 |
diff --git a/misc/Makefile b/misc/Makefile |
36 |
index b9f854e..d7bbc85 100644 |
37 |
--- a/misc/Makefile |
38 |
+++ b/misc/Makefile |
39 |
@@ -76,7 +76,7 @@ install-lib := libg.a |
40 |
gpl2lgpl := error.c error.h |
41 |
|
42 |
tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \ |
43 |
- tst-error1 tst-pselect tst-insremque tst-mntent2 bug-hsearch1 |
44 |
+ tst-error1 tst-pselect tst-insremque tst-mntent2 bug-hsearch1 bug18240 |
45 |
ifeq ($(run-built-tests),yes) |
46 |
tests-special += $(objpfx)tst-error1-mem.out |
47 |
endif |
48 |
diff --git a/misc/bug18240.c b/misc/bug18240.c |
49 |
new file mode 100644 |
50 |
index 0000000..4b26865 |
51 |
--- /dev/null |
52 |
+++ b/misc/bug18240.c |
53 |
@@ -0,0 +1,75 @@ |
54 |
+/* Test integer wraparound in hcreate. |
55 |
+ Copyright (C) 2016 Free Software Foundation, Inc. |
56 |
+ This file is part of the GNU C Library. |
57 |
+ |
58 |
+ The GNU C Library is free software; you can redistribute it and/or |
59 |
+ modify it under the terms of the GNU Lesser General Public |
60 |
+ License as published by the Free Software Foundation; either |
61 |
+ version 2.1 of the License, or (at your option) any later version. |
62 |
+ |
63 |
+ The GNU C Library is distributed in the hope that it will be useful, |
64 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
65 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
66 |
+ Lesser General Public License for more details. |
67 |
+ |
68 |
+ You should have received a copy of the GNU Lesser General Public |
69 |
+ License along with the GNU C Library; if not, see |
70 |
+ <http://www.gnu.org/licenses/>. */ |
71 |
+ |
72 |
+#include <errno.h> |
73 |
+#include <limits.h> |
74 |
+#include <search.h> |
75 |
+#include <stdbool.h> |
76 |
+#include <stdio.h> |
77 |
+#include <stdlib.h> |
78 |
+ |
79 |
+static void |
80 |
+test_size (size_t size) |
81 |
+{ |
82 |
+ int res = hcreate (size); |
83 |
+ if (res == 0) |
84 |
+ { |
85 |
+ if (errno == ENOMEM) |
86 |
+ return; |
87 |
+ printf ("error: hcreate (%zu): %m\n", size); |
88 |
+ exit (1); |
89 |
+ } |
90 |
+ char *keys[100]; |
91 |
+ for (int i = 0; i < 100; ++i) |
92 |
+ { |
93 |
+ if (asprintf (keys + i, "%d", i) < 0) |
94 |
+ { |
95 |
+ printf ("error: asprintf: %m\n"); |
96 |
+ exit (1); |
97 |
+ } |
98 |
+ ENTRY e = { keys[i], (char *) "value" }; |
99 |
+ if (hsearch (e, ENTER) == NULL) |
100 |
+ { |
101 |
+ printf ("error: hsearch (\"%s\"): %m\n", keys[i]); |
102 |
+ exit (1); |
103 |
+ } |
104 |
+ } |
105 |
+ hdestroy (); |
106 |
+ |
107 |
+ for (int i = 0; i < 100; ++i) |
108 |
+ free (keys[i]); |
109 |
+} |
110 |
+ |
111 |
+static int |
112 |
+do_test (void) |
113 |
+{ |
114 |
+ test_size (500); |
115 |
+ test_size (-1); |
116 |
+ test_size (-3); |
117 |
+ test_size (INT_MAX - 2); |
118 |
+ test_size (INT_MAX - 1); |
119 |
+ test_size (INT_MAX); |
120 |
+ test_size (((unsigned) INT_MAX) + 1); |
121 |
+ test_size (UINT_MAX - 2); |
122 |
+ test_size (UINT_MAX - 1); |
123 |
+ test_size (UINT_MAX); |
124 |
+ return 0; |
125 |
+} |
126 |
+ |
127 |
+#define TEST_FUNCTION do_test () |
128 |
+#include "../test-skeleton.c" |
129 |
diff --git a/misc/hsearch_r.c b/misc/hsearch_r.c |
130 |
index f6f16ed..1fca6b3 100644 |
131 |
--- a/misc/hsearch_r.c |
132 |
+++ b/misc/hsearch_r.c |
133 |
@@ -46,15 +46,12 @@ static int |
134 |
isprime (unsigned int number) |
135 |
{ |
136 |
/* no even number will be passed */ |
137 |
- unsigned int div = 3; |
138 |
- |
139 |
- while (div * div < number && number % div != 0) |
140 |
- div += 2; |
141 |
- |
142 |
- return number % div != 0; |
143 |
+ for (unsigned int div = 3; div <= number / div; div += 2) |
144 |
+ if (number % div == 0) |
145 |
+ return 0; |
146 |
+ return 1; |
147 |
} |
148 |
|
149 |
- |
150 |
/* Before using the hash table we must allocate memory for it. |
151 |
Test for an existing table are done. We allocate one element |
152 |
more as the found prime number says. This is done for more effective |
153 |
@@ -71,13 +68,6 @@ __hcreate_r (size_t nel, struct hsearch_data *htab) |
154 |
return 0; |
155 |
} |
156 |
|
157 |
- if (nel >= SIZE_MAX / sizeof (_ENTRY)) |
158 |
- { |
159 |
- __set_errno (ENOMEM); |
160 |
- return 0; |
161 |
- } |
162 |
- |
163 |
- |
164 |
/* There is still another table active. Return with error. */ |
165 |
if (htab->table != NULL) |
166 |
return 0; |
167 |
@@ -86,10 +76,19 @@ __hcreate_r (size_t nel, struct hsearch_data *htab) |
168 |
use will not work. */ |
169 |
if (nel < 3) |
170 |
nel = 3; |
171 |
- /* Change nel to the first prime number not smaller as nel. */ |
172 |
- nel |= 1; /* make odd */ |
173 |
- while (!isprime (nel)) |
174 |
- nel += 2; |
175 |
+ |
176 |
+ /* Change nel to the first prime number in the range [nel, UINT_MAX - 2], |
177 |
+ The '- 2' means 'nel += 2' cannot overflow. */ |
178 |
+ for (nel |= 1; ; nel += 2) |
179 |
+ { |
180 |
+ if (UINT_MAX - 2 < nel) |
181 |
+ { |
182 |
+ __set_errno (ENOMEM); |
183 |
+ return 0; |
184 |
+ } |
185 |
+ if (isprime (nel)) |
186 |
+ break; |
187 |
+ } |
188 |
|
189 |
htab->size = nel; |
190 |
htab->filled = 0; |
191 |
-- |
192 |
2.7.1 |