Contents of /trunk/glibc/patches/glibc-2.18-readdir_r-CVE-2013-4237.patch
Parent Directory | Revision Log
Revision 2283 -
(show annotations)
(download)
Mon Sep 16 11:57:11 2013 UTC (11 years, 1 month ago) by niro
File size: 10608 byte(s)
Mon Sep 16 11:57:11 2013 UTC (11 years, 1 month ago) by niro
File size: 10608 byte(s)
-glibc-2.18 CVEs and fixes
1 | 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 |