1 /* Test for bug 17079: heap overflow in NSS with small buffers.
2 Copyright (C) 2015-2018 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 #include <support/support.h>
28 /* Check if two passwd structs contain the same data. */
30 equal (const struct passwd
*a
, const struct passwd
*b
)
32 return strcmp (a
->pw_name
, b
->pw_name
) == 0
33 && strcmp (a
->pw_passwd
, b
->pw_passwd
) == 0
34 && a
->pw_uid
== b
->pw_uid
35 && a
->pw_gid
== b
->pw_gid
36 && strcmp (a
->pw_gecos
, b
->pw_gecos
) == 0
37 && strcmp (a
->pw_dir
, b
->pw_dir
) == 0
38 && strcmp (a
->pw_shell
, b
->pw_shell
) == 0;
41 enum { MAX_TEST_ITEMS
= 10 };
42 static struct passwd test_items
[MAX_TEST_ITEMS
];
43 static int test_count
;
45 /* Initialize test_items and test_count above, with data from the
48 init_test_items (void)
53 struct passwd
*pwd
= getpwent ();
56 struct passwd
*target
= test_items
+ test_count
;
57 target
->pw_name
= xstrdup (pwd
->pw_name
);
58 target
->pw_passwd
= xstrdup (pwd
->pw_passwd
);
59 target
->pw_uid
= pwd
->pw_uid
;
60 target
->pw_gid
= pwd
->pw_gid
;
61 target
->pw_gecos
= xstrdup (pwd
->pw_gecos
);
62 target
->pw_dir
= xstrdup (pwd
->pw_dir
);
63 target
->pw_shell
= xstrdup (pwd
->pw_shell
);
65 while (++test_count
< MAX_TEST_ITEMS
);
68 /* Filter out those test items which cannot be looked up by name or
71 for (int i
= 0; i
< test_count
; ++i
)
73 struct passwd
*pwd1
= getpwnam (test_items
[i
].pw_name
);
74 struct passwd
*pwd2
= getpwuid (test_items
[i
].pw_uid
);
75 if (pwd1
== NULL
|| !equal (pwd1
, test_items
+ i
)
76 || pwd2
== NULL
|| !equal (pwd2
, test_items
+ i
))
78 printf ("info: skipping user \"%s\", UID %ld due to inconsistency\n",
79 test_items
[i
].pw_name
, (long) test_items
[i
].pw_uid
);
80 test_items
[i
].pw_name
= NULL
;
87 puts ("error: no accounts found which can be looked up by name and UID.");
91 /* Set to true if an error is encountered. */
94 /* Return true if the padding has not been tampered with. */
96 check_padding (char *buffer
, size_t size
, char pad
)
98 char *end
= buffer
+ size
;
108 /* Test one buffer size and padding combination. */
110 test_one (const struct passwd
*item
, size_t buffer_size
,
111 char pad
, size_t padding_size
)
113 char *buffer
= xmalloc (buffer_size
+ padding_size
);
116 struct passwd
*result
;
119 /* Test getpwname_r. */
120 memset (buffer
, pad
, buffer_size
+ padding_size
);
121 pwd
= (struct passwd
) {};
122 ret
= getpwnam_r (item
->pw_name
, &pwd
, buffer
, buffer_size
, &result
);
123 if (!check_padding (buffer
+ buffer_size
, padding_size
, pad
))
125 printf ("error: padding change: "
126 "name \"%s\", buffer size %zu, padding size %zu, pad 0x%02x\n",
127 item
->pw_name
, buffer_size
, padding_size
, (unsigned char) pad
);
134 printf ("error: no data: name \"%s\", buffer size %zu\n",
135 item
->pw_name
, buffer_size
);
138 else if (!equal (item
, result
))
140 printf ("error: lookup mismatch: name \"%s\", buffer size %zu\n",
141 item
->pw_name
, buffer_size
);
145 else if (ret
!= ERANGE
)
148 printf ("error: lookup failure for name \"%s\": %m (%d)\n",
153 /* Test getpwuid_r. */
154 memset (buffer
, pad
, buffer_size
+ padding_size
);
155 pwd
= (struct passwd
) {};
156 ret
= getpwuid_r (item
->pw_uid
, &pwd
, buffer
, buffer_size
, &result
);
157 if (!check_padding (buffer
+ buffer_size
, padding_size
, pad
))
159 printf ("error: padding change: "
160 "UID %ld, buffer size %zu, padding size %zu, pad 0x%02x\n",
161 (long) item
->pw_uid
, buffer_size
, padding_size
,
162 (unsigned char) pad
);
169 printf ("error: no data: UID %ld, buffer size %zu\n",
170 (long) item
->pw_uid
, buffer_size
);
173 else if (!equal (item
, result
))
175 printf ("error: lookup mismatch: UID %ld, buffer size %zu\n",
176 (long) item
->pw_uid
, buffer_size
);
180 else if (ret
!= ERANGE
)
183 printf ("error: lookup failure for UID \"%ld\": %m (%d)\n",
184 (long) item
->pw_uid
, ret
);
191 /* Test one buffer size with different paddings. */
193 test_buffer_size (size_t buffer_size
)
195 for (int i
= 0; i
< test_count
; ++i
)
196 for (size_t padding_size
= 0; padding_size
< 3; ++padding_size
)
198 /* Skip entries with inconsistent name/UID lookups. */
199 if (test_items
[i
].pw_name
== NULL
)
202 test_one (test_items
+ i
, buffer_size
, '\0', padding_size
);
203 if (padding_size
> 0)
205 test_one (test_items
+ i
, buffer_size
, ':', padding_size
);
206 test_one (test_items
+ i
, buffer_size
, '\n', padding_size
);
207 test_one (test_items
+ i
, buffer_size
, '\xff', padding_size
);
208 test_one (test_items
+ i
, buffer_size
, '@', padding_size
);
216 if (!init_test_items ())
218 printf ("info: %d test items\n", test_count
);
220 for (size_t buffer_size
= 0; buffer_size
<= 65; ++buffer_size
)
221 test_buffer_size (buffer_size
);
222 for (size_t buffer_size
= 64 + 4; buffer_size
< 256; buffer_size
+= 4)
223 test_buffer_size (buffer_size
);
224 test_buffer_size (255);
225 test_buffer_size (257);
226 for (size_t buffer_size
= 256; buffer_size
< 512; buffer_size
+= 8)
227 test_buffer_size (buffer_size
);
228 test_buffer_size (511);
229 test_buffer_size (513);
230 test_buffer_size (1024);
231 test_buffer_size (2048);
239 #include <support/test-driver.c>