1 /* Test for bug 17079: heap overflow in NSS with small buffers.
2 Copyright (C) 2015-2016 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
26 /* Check if two passwd structs contain the same data. */
28 equal (const struct passwd
*a
, const struct passwd
*b
)
30 return strcmp (a
->pw_name
, b
->pw_name
) == 0
31 && strcmp (a
->pw_passwd
, b
->pw_passwd
) == 0
32 && a
->pw_uid
== b
->pw_uid
33 && a
->pw_gid
== b
->pw_gid
34 && strcmp (a
->pw_gecos
, b
->pw_gecos
) == 0
35 && strcmp (a
->pw_dir
, b
->pw_dir
) == 0
36 && strcmp (a
->pw_shell
, b
->pw_shell
) == 0;
39 enum { MAX_TEST_ITEMS
= 10 };
40 static struct passwd test_items
[MAX_TEST_ITEMS
];
41 static int test_count
;
43 /* Initialize test_items and test_count above, with data from the
46 init_test_items (void)
51 struct passwd
*pwd
= getpwent ();
54 struct passwd
*target
= test_items
+ test_count
;
55 target
->pw_name
= strdup (pwd
->pw_name
);
56 target
->pw_passwd
= strdup (pwd
->pw_passwd
);
57 target
->pw_uid
= pwd
->pw_uid
;
58 target
->pw_gid
= pwd
->pw_gid
;
59 target
->pw_gecos
= strdup (pwd
->pw_gecos
);
60 target
->pw_dir
= strdup (pwd
->pw_dir
);
61 target
->pw_shell
= strdup (pwd
->pw_shell
);
63 while (++test_count
< MAX_TEST_ITEMS
);
66 /* Filter out those test items which cannot be looked up by name or
69 for (int i
= 0; i
< test_count
; ++i
)
71 struct passwd
*pwd1
= getpwnam (test_items
[i
].pw_name
);
72 struct passwd
*pwd2
= getpwuid (test_items
[i
].pw_uid
);
73 if (pwd1
== NULL
|| !equal (pwd1
, test_items
+ i
)
74 || pwd2
== NULL
|| !equal (pwd2
, test_items
+ i
))
76 printf ("info: skipping user \"%s\", UID %ld due to inconsistency\n",
77 test_items
[i
].pw_name
, (long) test_items
[i
].pw_uid
);
78 test_items
[i
].pw_name
= NULL
;
85 puts ("error: no accounts found which can be looked up by name and UID.");
89 /* Set to true if an error is encountered. */
92 /* Return true if the padding has not been tampered with. */
94 check_padding (char *buffer
, size_t size
, char pad
)
96 char *end
= buffer
+ size
;
106 /* Test one buffer size and padding combination. */
108 test_one (const struct passwd
*item
, size_t buffer_size
,
109 char pad
, size_t padding_size
)
111 char *buffer
= malloc (buffer_size
+ padding_size
);
114 puts ("error: malloc failure");
120 struct passwd
*result
;
123 /* Test getpwname_r. */
124 memset (buffer
, pad
, buffer_size
+ padding_size
);
125 pwd
= (struct passwd
) {};
126 ret
= getpwnam_r (item
->pw_name
, &pwd
, buffer
, buffer_size
, &result
);
127 if (!check_padding (buffer
+ buffer_size
, padding_size
, pad
))
129 printf ("error: padding change: "
130 "name \"%s\", buffer size %zu, padding size %zu, pad 0x%02x\n",
131 item
->pw_name
, buffer_size
, padding_size
, (unsigned char) pad
);
138 printf ("error: no data: name \"%s\", buffer size %zu\n",
139 item
->pw_name
, buffer_size
);
142 else if (!equal (item
, result
))
144 printf ("error: lookup mismatch: name \"%s\", buffer size %zu\n",
145 item
->pw_name
, buffer_size
);
149 else if (ret
!= ERANGE
)
152 printf ("error: lookup failure for name \"%s\": %m (%d)\n",
157 /* Test getpwuid_r. */
158 memset (buffer
, pad
, buffer_size
+ padding_size
);
159 pwd
= (struct passwd
) {};
160 ret
= getpwuid_r (item
->pw_uid
, &pwd
, buffer
, buffer_size
, &result
);
161 if (!check_padding (buffer
+ buffer_size
, padding_size
, pad
))
163 printf ("error: padding change: "
164 "UID %ld, buffer size %zu, padding size %zu, pad 0x%02x\n",
165 (long) item
->pw_uid
, buffer_size
, padding_size
,
166 (unsigned char) pad
);
173 printf ("error: no data: UID %ld, buffer size %zu\n",
174 (long) item
->pw_uid
, buffer_size
);
177 else if (!equal (item
, result
))
179 printf ("error: lookup mismatch: UID %ld, buffer size %zu\n",
180 (long) item
->pw_uid
, buffer_size
);
184 else if (ret
!= ERANGE
)
187 printf ("error: lookup failure for UID \"%ld\": %m (%d)\n",
188 (long) item
->pw_uid
, ret
);
195 /* Test one buffer size with different paddings. */
197 test_buffer_size (size_t buffer_size
)
199 for (int i
= 0; i
< test_count
; ++i
)
200 for (size_t padding_size
= 0; padding_size
< 3; ++padding_size
)
202 /* Skip entries with inconsistent name/UID lookups. */
203 if (test_items
[i
].pw_name
== NULL
)
206 test_one (test_items
+ i
, buffer_size
, '\0', padding_size
);
207 if (padding_size
> 0)
209 test_one (test_items
+ i
, buffer_size
, ':', padding_size
);
210 test_one (test_items
+ i
, buffer_size
, '\n', padding_size
);
211 test_one (test_items
+ i
, buffer_size
, '\xff', padding_size
);
212 test_one (test_items
+ i
, buffer_size
, '@', padding_size
);
220 if (!init_test_items ())
222 printf ("info: %d test items\n", test_count
);
224 for (size_t buffer_size
= 0; buffer_size
<= 65; ++buffer_size
)
225 test_buffer_size (buffer_size
);
226 for (size_t buffer_size
= 64 + 4; buffer_size
< 256; buffer_size
+= 4)
227 test_buffer_size (buffer_size
);
228 test_buffer_size (255);
229 test_buffer_size (257);
230 for (size_t buffer_size
= 256; buffer_size
< 512; buffer_size
+= 8)
231 test_buffer_size (buffer_size
);
232 test_buffer_size (511);
233 test_buffer_size (513);
234 test_buffer_size (1024);
235 test_buffer_size (2048);
243 #define TEST_FUNCTION do_test ()
244 #include "../test-skeleton.c"