1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
From 6d0b7b443c9735672bb76d003c3f7263c5292d7d Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Wed, 29 Apr 2015 14:41:25 +0200
Subject: [PATCH 23/27] CVE-2014-8121: Do not close NSS files database during
iteration [BZ #18007]
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
(cherry picked from commit e871e19b5f19d2e6595e911b0a5b1c19cda20cc7)
Fixes:
CVE-2014-8121 - Unexpected closing of nss_files databases after lookups
causes denial of service.
Signed-off-by: Gustavo Zacarias <gustavo@zacarias.com.ar>
---
nss/Makefile | 2 +-
nss/nss_files/files-XXX.c | 2 +-
nss/tst-nss-getpwent.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 120 insertions(+), 2 deletions(-)
create mode 100644 nss/tst-nss-getpwent.c
diff --git a/nss/Makefile b/nss/Makefile
index d419baf..dc351dd 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -39,7 +39,7 @@ install-bin := getent makedb
makedb-modules = xmalloc hash-string
extra-objs += $(makedb-modules:=.o)
-tests = test-netdb tst-nss-test1 test-digits-dots
+tests = test-netdb tst-nss-test1 test-digits-dots tst-nss-getpwent
xtests = bug-erange
# Specify rules for the nss_* modules. We have some services.
diff --git a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c
index a7a45e5..a7ce5ea 100644
--- a/nss/nss_files/files-XXX.c
+++ b/nss/nss_files/files-XXX.c
@@ -134,7 +134,7 @@ CONCAT(_nss_files_set,ENTNAME) (int stayopen)
__libc_lock_lock (lock);
- status = internal_setent (stayopen);
+ status = internal_setent (1);
if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
{
diff --git a/nss/tst-nss-getpwent.c b/nss/tst-nss-getpwent.c
new file mode 100644
index 0000000..f2e8abc
--- /dev/null
+++ b/nss/tst-nss-getpwent.c
@@ -0,0 +1,118 @@
+/* Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <pwd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+do_test (void)
+{
+ /* Count the number of entries in the password database, and fetch
+ data from the first and last entries. */
+ size_t count = 0;
+ struct passwd * pw;
+ char *first_name = NULL;
+ uid_t first_uid = 0;
+ char *last_name = NULL;
+ uid_t last_uid = 0;
+ setpwent ();
+ while ((pw = getpwent ()) != NULL)
+ {
+ if (first_name == NULL)
+ {
+ first_name = strdup (pw->pw_name);
+ if (first_name == NULL)
+ {
+ printf ("strdup: %m\n");
+ return 1;
+ }
+ first_uid = pw->pw_uid;
+ }
+
+ free (last_name);
+ last_name = strdup (pw->pw_name);
+ if (last_name == NULL)
+ {
+ printf ("strdup: %m\n");
+ return 1;
+ }
+ last_uid = pw->pw_uid;
+ ++count;
+ }
+ endpwent ();
+
+ if (count == 0)
+ {
+ printf ("No entries in the password database.\n");
+ return 0;
+ }
+
+ /* Try again, this time interleaving with name-based and UID-based
+ lookup operations. The counts do not match if the interleaved
+ lookups affected the enumeration. */
+ size_t new_count = 0;
+ setpwent ();
+ while ((pw = getpwent ()) != NULL)
+ {
+ if (new_count == count)
+ {
+ printf ("Additional entry in the password database.\n");
+ return 1;
+ }
+ ++new_count;
+ struct passwd *pw2 = getpwnam (first_name);
+ if (pw2 == NULL)
+ {
+ printf ("getpwnam (%s) failed: %m\n", first_name);
+ return 1;
+ }
+ pw2 = getpwnam (last_name);
+ if (pw2 == NULL)
+ {
+ printf ("getpwnam (%s) failed: %m\n", last_name);
+ return 1;
+ }
+ pw2 = getpwuid (first_uid);
+ if (pw2 == NULL)
+ {
+ printf ("getpwuid (%llu) failed: %m\n",
+ (unsigned long long) first_uid);
+ return 1;
+ }
+ pw2 = getpwuid (last_uid);
+ if (pw2 == NULL)
+ {
+ printf ("getpwuid (%llu) failed: %m\n",
+ (unsigned long long) last_uid);
+ return 1;
+ }
+ }
+ endpwent ();
+ if (new_count < count)
+ {
+ printf ("Missing entry in the password database.\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
--
2.6.2
|