Annotation of /trunk/glibc/patches/glibc-2.18-readdir_r-CVE-2013-4237.patch
Parent Directory | Revision Log
Revision 2283 -
(hide annotations)
(download)
Mon Sep 16 11:57:11 2013 UTC (11 years ago) by niro
File size: 10608 byte(s)
Mon Sep 16 11:57:11 2013 UTC (11 years ago) by niro
File size: 10608 byte(s)
-glibc-2.18 CVEs and fixes
1 | niro | 2283 | diff --git a/manual/conf.texi b/manual/conf.texi |
2 | index 7eb8b36..c720063 100644 | ||
3 | --- a/manual/conf.texi | ||
4 | +++ b/manual/conf.texi | ||
5 | @@ -1149,6 +1149,9 @@ typed ahead as input. @xref{I/O Queues}. | ||
6 | @deftypevr Macro int NAME_MAX | ||
7 | The uniform system limit (if any) for the length of a file name component, not | ||
8 | including the terminating null character. | ||
9 | + | ||
10 | +@strong{Portability Note:} On some systems, @theglibc{} defines | ||
11 | +@code{NAME_MAX}, but does not actually enforce this limit. | ||
12 | @end deftypevr | ||
13 | |||
14 | @comment limits.h | ||
15 | @@ -1157,6 +1160,9 @@ including the terminating null character. | ||
16 | The uniform system limit (if any) for the length of an entire file name (that | ||
17 | is, the argument given to system calls such as @code{open}), including the | ||
18 | terminating null character. | ||
19 | + | ||
20 | +@strong{Portability Note:} @Theglibc{} does not enforce this limit | ||
21 | +even if @code{PATH_MAX} is defined. | ||
22 | @end deftypevr | ||
23 | |||
24 | @cindex limits, pipe buffer size | ||
25 | @@ -1476,6 +1482,9 @@ Inquire about the value of @code{POSIX_REC_MIN_XFER_SIZE}. | ||
26 | Inquire about the value of @code{POSIX_REC_XFER_ALIGN}. | ||
27 | @end table | ||
28 | |||
29 | +@strong{Portability Note:} On some systems, @theglibc{} does not | ||
30 | +enforce @code{_PC_NAME_MAX} or @code{_PC_PATH_MAX} limits. | ||
31 | + | ||
32 | @node Utility Limits | ||
33 | @section Utility Program Capacity Limits | ||
34 | |||
35 | diff --git a/manual/filesys.texi b/manual/filesys.texi | ||
36 | index 1df9cf2..814c210 100644 | ||
37 | --- a/manual/filesys.texi | ||
38 | +++ b/manual/filesys.texi | ||
39 | @@ -444,9 +444,9 @@ symbols are declared in the header file @file{dirent.h}. | ||
40 | @comment POSIX.1 | ||
41 | @deftypefun {struct dirent *} readdir (DIR *@var{dirstream}) | ||
42 | This function reads the next entry from the directory. It normally | ||
43 | -returns a pointer to a structure containing information about the file. | ||
44 | -This structure is statically allocated and can be rewritten by a | ||
45 | -subsequent call. | ||
46 | +returns a pointer to a structure containing information about the | ||
47 | +file. This structure is associated with the @var{dirstream} handle | ||
48 | +and can be rewritten by a subsequent call. | ||
49 | |||
50 | @strong{Portability Note:} On some systems @code{readdir} may not | ||
51 | return entries for @file{.} and @file{..}, even though these are always | ||
52 | @@ -461,19 +461,61 @@ conditions are defined for this function: | ||
53 | The @var{dirstream} argument is not valid. | ||
54 | @end table | ||
55 | |||
56 | -@code{readdir} is not thread safe. Multiple threads using | ||
57 | -@code{readdir} on the same @var{dirstream} may overwrite the return | ||
58 | -value. Use @code{readdir_r} when this is critical. | ||
59 | +To distinguish between an end-of-directory condition or an error, you | ||
60 | +must set @code{errno} to zero before calling @code{readdir}. To avoid | ||
61 | +entering an infinite loop, you should stop reading from the directory | ||
62 | +after the first error. | ||
63 | + | ||
64 | +In POSIX.1-2008, @code{readdir} is not thread-safe. In @theglibc{} | ||
65 | +implementation, it is safe to call @code{readdir} concurrently on | ||
66 | +different @var{dirstream}s, but multiple threads accessing the same | ||
67 | +@var{dirstream} result in undefined behavior. @code{readdir_r} is a | ||
68 | +fully thread-safe alternative, but suffers from poor portability (see | ||
69 | +below). It is recommended that you use @code{readdir}, with external | ||
70 | +locking if multiple threads access the same @var{dirstream}. | ||
71 | @end deftypefun | ||
72 | |||
73 | @comment dirent.h | ||
74 | @comment GNU | ||
75 | @deftypefun int readdir_r (DIR *@var{dirstream}, struct dirent *@var{entry}, struct dirent **@var{result}) | ||
76 | -This function is the reentrant version of @code{readdir}. Like | ||
77 | -@code{readdir} it returns the next entry from the directory. But to | ||
78 | -prevent conflicts between simultaneously running threads the result is | ||
79 | -not stored in statically allocated memory. Instead the argument | ||
80 | -@var{entry} points to a place to store the result. | ||
81 | +This function is a version of @code{readdir} which performs internal | ||
82 | +locking. Like @code{readdir} it returns the next entry from the | ||
83 | +directory. To prevent conflicts between simultaneously running | ||
84 | +threads the result is stored inside the @var{entry} object. | ||
85 | + | ||
86 | +@strong{Portability Note:} It is recommended to use @code{readdir} | ||
87 | +instead of @code{readdir_r} for the following reasons: | ||
88 | + | ||
89 | +@itemize @bullet | ||
90 | +@item | ||
91 | +On systems which do not define @code{NAME_MAX}, it may not be possible | ||
92 | +to use @code{readdir_r} safely because the caller does not specify the | ||
93 | +length of the buffer for the directory entry. | ||
94 | + | ||
95 | +@item | ||
96 | +On some systems, @code{readdir_r} cannot read directory entries with | ||
97 | +very long names. If such a name is encountered, @theglibc{} | ||
98 | +implementation of @code{readdir_r} returns with an error code of | ||
99 | +@code{ENAMETOOLONG} after the final directory entry has been read. On | ||
100 | +other systems, @code{readdir_r} may return successfully, but the | ||
101 | +@code{d_name} member may not be NUL-terminated or may be truncated. | ||
102 | + | ||
103 | +@item | ||
104 | +POSIX-1.2008 does not guarantee that @code{readdir} is thread-safe, | ||
105 | +even when access to the same @var{dirstream} is serialized. But in | ||
106 | +current implementations (including @theglibc{}), it is safe to call | ||
107 | +@code{readdir} concurrently on different @var{dirstream}s, so there is | ||
108 | +no need to use @code{readdir_r} in most multi-threaded programs. In | ||
109 | +the rare case that multiple threads need to read from the same | ||
110 | +@var{dirstream}, it is still better to use @code{readdir} and external | ||
111 | +synchronization. | ||
112 | + | ||
113 | +@item | ||
114 | +It is expected that future versions of POSIX will obsolete | ||
115 | +@code{readdir_r} and mandate the level of thread safety for | ||
116 | +@code{readdir} which is provided by @theglibc{} and other | ||
117 | +implementations today. | ||
118 | +@end itemize | ||
119 | |||
120 | Normally @code{readdir_r} returns zero and sets @code{*@var{result}} | ||
121 | to @var{entry}. If there are no more entries in the directory or an | ||
122 | @@ -481,15 +523,6 @@ error is detected, @code{readdir_r} sets @code{*@var{result}} to a | ||
123 | null pointer and returns a nonzero error code, also stored in | ||
124 | @code{errno}, as described for @code{readdir}. | ||
125 | |||
126 | -@strong{Portability Note:} On some systems @code{readdir_r} may not | ||
127 | -return a NUL terminated string for the file name, even when there is no | ||
128 | -@code{d_reclen} field in @code{struct dirent} and the file | ||
129 | -name is the maximum allowed size. Modern systems all have the | ||
130 | -@code{d_reclen} field, and on old systems multi-threading is not | ||
131 | -critical. In any case there is no such problem with the @code{readdir} | ||
132 | -function, so that even on systems without the @code{d_reclen} member one | ||
133 | -could use multiple threads by using external locking. | ||
134 | - | ||
135 | It is also important to look at the definition of the @code{struct | ||
136 | dirent} type. Simply passing a pointer to an object of this type for | ||
137 | the second parameter of @code{readdir_r} might not be enough. Some | ||
138 | diff --git a/sysdeps/posix/dirstream.h b/sysdeps/posix/dirstream.h | ||
139 | index a7a074d..8e8570d 100644 | ||
140 | --- a/sysdeps/posix/dirstream.h | ||
141 | +++ b/sysdeps/posix/dirstream.h | ||
142 | @@ -39,6 +39,8 @@ struct __dirstream | ||
143 | |||
144 | off_t filepos; /* Position of next entry to read. */ | ||
145 | |||
146 | + int errcode; /* Delayed error code. */ | ||
147 | + | ||
148 | /* Directory block. */ | ||
149 | char data[0] __attribute__ ((aligned (__alignof__ (void*)))); | ||
150 | }; | ||
151 | diff --git a/sysdeps/posix/opendir.c b/sysdeps/posix/opendir.c | ||
152 | index ddfc3a7..fc05b0f 100644 | ||
153 | --- a/sysdeps/posix/opendir.c | ||
154 | +++ b/sysdeps/posix/opendir.c | ||
155 | @@ -231,6 +231,7 @@ __alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp) | ||
156 | dirp->size = 0; | ||
157 | dirp->offset = 0; | ||
158 | dirp->filepos = 0; | ||
159 | + dirp->errcode = 0; | ||
160 | |||
161 | return dirp; | ||
162 | } | ||
163 | diff --git a/sysdeps/posix/readdir_r.c b/sysdeps/posix/readdir_r.c | ||
164 | index b5a8e2e..8ed5c3f 100644 | ||
165 | --- a/sysdeps/posix/readdir_r.c | ||
166 | +++ b/sysdeps/posix/readdir_r.c | ||
167 | @@ -40,6 +40,7 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result) | ||
168 | DIRENT_TYPE *dp; | ||
169 | size_t reclen; | ||
170 | const int saved_errno = errno; | ||
171 | + int ret; | ||
172 | |||
173 | __libc_lock_lock (dirp->lock); | ||
174 | |||
175 | @@ -70,10 +71,10 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result) | ||
176 | bytes = 0; | ||
177 | __set_errno (saved_errno); | ||
178 | } | ||
179 | + if (bytes < 0) | ||
180 | + dirp->errcode = errno; | ||
181 | |||
182 | dp = NULL; | ||
183 | - /* Reclen != 0 signals that an error occurred. */ | ||
184 | - reclen = bytes != 0; | ||
185 | break; | ||
186 | } | ||
187 | dirp->size = (size_t) bytes; | ||
188 | @@ -106,29 +107,46 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result) | ||
189 | dirp->filepos += reclen; | ||
190 | #endif | ||
191 | |||
192 | - /* Skip deleted files. */ | ||
193 | +#ifdef NAME_MAX | ||
194 | + if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1) | ||
195 | + { | ||
196 | + /* The record is very long. It could still fit into the | ||
197 | + caller-supplied buffer if we can skip padding at the | ||
198 | + end. */ | ||
199 | + size_t namelen = _D_EXACT_NAMLEN (dp); | ||
200 | + if (namelen <= NAME_MAX) | ||
201 | + reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1; | ||
202 | + else | ||
203 | + { | ||
204 | + /* The name is too long. Ignore this file. */ | ||
205 | + dirp->errcode = ENAMETOOLONG; | ||
206 | + dp->d_ino = 0; | ||
207 | + continue; | ||
208 | + } | ||
209 | + } | ||
210 | +#endif | ||
211 | + | ||
212 | + /* Skip deleted and ignored files. */ | ||
213 | } | ||
214 | while (dp->d_ino == 0); | ||
215 | |||
216 | if (dp != NULL) | ||
217 | { | ||
218 | -#ifdef GETDENTS_64BIT_ALIGNED | ||
219 | - /* The d_reclen value might include padding which is not part of | ||
220 | - the DIRENT_TYPE data structure. */ | ||
221 | - reclen = MIN (reclen, | ||
222 | - offsetof (DIRENT_TYPE, d_name) + sizeof (dp->d_name)); | ||
223 | -#endif | ||
224 | *result = memcpy (entry, dp, reclen); | ||
225 | -#ifdef GETDENTS_64BIT_ALIGNED | ||
226 | +#ifdef _DIRENT_HAVE_D_RECLEN | ||
227 | entry->d_reclen = reclen; | ||
228 | #endif | ||
229 | + ret = 0; | ||
230 | } | ||
231 | else | ||
232 | - *result = NULL; | ||
233 | + { | ||
234 | + *result = NULL; | ||
235 | + ret = dirp->errcode; | ||
236 | + } | ||
237 | |||
238 | __libc_lock_unlock (dirp->lock); | ||
239 | |||
240 | - return dp != NULL ? 0 : reclen ? errno : 0; | ||
241 | + return ret; | ||
242 | } | ||
243 | |||
244 | #ifdef __READDIR_R_ALIAS | ||
245 | diff --git a/sysdeps/posix/rewinddir.c b/sysdeps/posix/rewinddir.c | ||
246 | index 2935a8e..d4991ad 100644 | ||
247 | --- a/sysdeps/posix/rewinddir.c | ||
248 | +++ b/sysdeps/posix/rewinddir.c | ||
249 | @@ -33,6 +33,7 @@ rewinddir (dirp) | ||
250 | dirp->filepos = 0; | ||
251 | dirp->offset = 0; | ||
252 | dirp->size = 0; | ||
253 | + dirp->errcode = 0; | ||
254 | #ifndef NOT_IN_libc | ||
255 | __libc_lock_unlock (dirp->lock); | ||
256 | #endif | ||
257 | diff --git a/sysdeps/unix/sysv/linux/i386/readdir64_r.c b/sysdeps/unix/sysv/linux/i386/readdir64_r.c | ||
258 | index 8ebbcfd..a7d114e 100644 | ||
259 | --- a/sysdeps/unix/sysv/linux/i386/readdir64_r.c | ||
260 | +++ b/sysdeps/unix/sysv/linux/i386/readdir64_r.c | ||
261 | @@ -18,7 +18,6 @@ | ||
262 | #define __READDIR_R __readdir64_r | ||
263 | #define __GETDENTS __getdents64 | ||
264 | #define DIRENT_TYPE struct dirent64 | ||
265 | -#define GETDENTS_64BIT_ALIGNED 1 | ||
266 | |||
267 | #include <sysdeps/posix/readdir_r.c> | ||
268 | |||
269 | diff --git a/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c b/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c | ||
270 | index 5ed8e95..290f2c8 100644 | ||
271 | --- a/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c | ||
272 | +++ b/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c | ||
273 | @@ -1,5 +1,4 @@ | ||
274 | #define readdir64_r __no_readdir64_r_decl | ||
275 | -#define GETDENTS_64BIT_ALIGNED 1 | ||
276 | #include <sysdeps/posix/readdir_r.c> | ||
277 | #undef readdir64_r | ||
278 | weak_alias (__readdir_r, readdir64_r) | ||
279 | -- | ||
280 | 1.8.3.4 | ||
281 |