~ubuntu-branches/debian/squeeze/ntp/squeeze-201010051545

« back to all changes in this revision

Viewing changes to libopts/text_mmap.c

  • Committer: Bazaar Package Importer
  • Author(s): Kurt Roeckx
  • Date: 2009-01-05 21:10:03 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20090105211003-mh6zc3um4k1uhsj7
Tags: 1:4.2.4p4+dfsg-8
It did not properly check the return value of EVP_VerifyFinal
which results in an malformed DSA signature being treated as
a good signature rather than as an error.  (CVE-2009-0021)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: text_mmap.c,v 4.15 2006/11/27 01:52:23 bkorb Exp $
 
3
 *
 
4
 * Time-stamp:      "2006-09-10 14:50:04 bkorb"
 
5
 */
 
6
 
 
7
#ifndef MAP_ANONYMOUS
 
8
#  ifdef   MAP_ANON
 
9
#  define  MAP_ANONYMOUS   MAP_ANON
 
10
#  endif
 
11
#endif
 
12
 
 
13
/*
 
14
 *  Some weird systems require that a specifically invalid FD number
 
15
 *  get passed in as an argument value.  Which value is that?  Well,
 
16
 *  as everybody knows, if open(2) fails, it returns -1, so that must
 
17
 *  be the value.  :)
 
18
 */
 
19
#define AO_INVALID_FD  -1
 
20
 
 
21
#define FILE_WRITABLE(_prt,_flg) \
 
22
        (   (_prt & PROT_WRITE) \
 
23
         && ((_flg & (MAP_SHARED|MAP_PRIVATE)) == MAP_SHARED))
 
24
#define MAP_FAILED_PTR ((void*)MAP_FAILED)
 
25
 
 
26
/*=export_func  text_mmap
 
27
 * private:
 
28
 *
 
29
 * what:  map a text file with terminating NUL
 
30
 *
 
31
 * arg:   char const*,  pzFile,  name of the file to map
 
32
 * arg:   int,          prot,    mmap protections (see mmap(2))
 
33
 * arg:   int,          flags,   mmap flags (see mmap(2))
 
34
 * arg:   tmap_info_t*, mapinfo, returned info about the mapping
 
35
 *
 
36
 * ret-type:   void*
 
37
 * ret-desc:   The mmaped data address
 
38
 *
 
39
 * doc:
 
40
 *
 
41
 * This routine will mmap a file into memory ensuring that there is at least
 
42
 * one @file{NUL} character following the file data.  It will return the
 
43
 * address where the file contents have been mapped into memory.  If there is a
 
44
 * problem, then it will return @code{MAP_FAILED} and set @file{errno}
 
45
 * appropriately.
 
46
 *
 
47
 * The named file does not exist, @code{stat(2)} will set @file{errno} as it
 
48
 * will.  If the file is not a regular file, @file{errno} will be
 
49
 * @code{EINVAL}.  At that point, @code{open(2)} is attempted with the access
 
50
 * bits set appropriately for the requested @code{mmap(2)} protections and flag
 
51
 * bits.  On failure, @file{errno} will be set according to the documentation
 
52
 * for @code{open(2)}.  If @code{mmap(2)} fails, @file{errno} will be set as
 
53
 * that routine sets it.  If @code{text_mmap} works to this point, a valid
 
54
 * address will be returned, but there may still be ``issues''.
 
55
 *
 
56
 * If the file size is not an even multiple of the system page size, then
 
57
 * @code{text_map} will return at this point and @file{errno} will be zero.
 
58
 * Otherwise, an anonymous map is attempted.  If not available, then an attempt
 
59
 * is made to @code{mmap(2)} @file{/dev/zero}.  If any of these fail, the
 
60
 * address of the file's data is returned, bug @code{no} @file{NUL} characters
 
61
 * are mapped after the end of the data.
 
62
 *
 
63
 * see: mmap(2), open(2), stat(2)
 
64
 *
 
65
 * err: Any error code issued by mmap(2), open(2), stat(2) is possible.
 
66
 *      Additionally, if the specified file is not a regular file, then
 
67
 *      errno will be set to @code{EINVAL}.
 
68
 *
 
69
 * example:
 
70
 * #include <mylib.h>
 
71
 * tmap_info_t mi;
 
72
 * int no_nul;
 
73
 * void* data = text_mmap( "file", PROT_WRITE, MAP_PRIVATE, &mi );
 
74
 * if (data == MAP_FAILED) return;
 
75
 * no_nul = (mi.txt_size == mi.txt_full_size);
 
76
 * << use the data >>
 
77
 * text_munmap( &mi );
 
78
=*/
 
79
void*
 
80
text_mmap( char const* pzFile, int prot, int flags, tmap_info_t* pMI )
 
81
{
 
82
    memset( pMI, 0, sizeof(*pMI) );
 
83
#ifdef HAVE_MMAP
 
84
    pMI->txt_zero_fd = -1;
 
85
#endif
 
86
    pMI->txt_fd = -1;
 
87
 
 
88
    /*
 
89
     *  Make sure we can stat the regular file.  Save the file size.
 
90
     */
 
91
    {
 
92
        struct stat sb;
 
93
        if (stat( pzFile, &sb ) != 0) {
 
94
            pMI->txt_errno = errno;
 
95
            return MAP_FAILED_PTR;
 
96
        }
 
97
 
 
98
        if (! S_ISREG( sb.st_mode )) {
 
99
            pMI->txt_errno = errno = EINVAL;
 
100
            return MAP_FAILED_PTR;
 
101
        }
 
102
 
 
103
        pMI->txt_size = sb.st_size;
 
104
    }
 
105
 
 
106
    /*
 
107
     *  Map mmap flags and protections into open flags and do the open.
 
108
     */
 
109
    {
 
110
        int o_flag;
 
111
        /*
 
112
         *  See if we will be updating the file.  If we can alter the memory
 
113
         *  and if we share the data and we are *not* copy-on-writing the data,
 
114
         *  then our updates will show in the file, so we must open with
 
115
         *  write access.
 
116
         */
 
117
        if (FILE_WRITABLE(prot,flags))
 
118
            o_flag = O_RDWR;
 
119
        else
 
120
            o_flag = O_RDONLY;
 
121
 
 
122
        /*
 
123
         *  If you're not sharing the file and you are writing to it,
 
124
         *  then don't let anyone else have access to the file.
 
125
         */
 
126
        if (((flags & MAP_SHARED) == 0) && (prot & PROT_WRITE))
 
127
            o_flag |= O_EXCL;
 
128
 
 
129
        pMI->txt_fd = open( pzFile, o_flag );
 
130
    }
 
131
 
 
132
    if (pMI->txt_fd == AO_INVALID_FD) {
 
133
        pMI->txt_errno = errno;
 
134
        return MAP_FAILED_PTR;
 
135
    }
 
136
 
 
137
#ifdef HAVE_MMAP /* * * * * WITH MMAP * * * * * */
 
138
    /*
 
139
     *  do the mmap.  If we fail, then preserve errno, close the file and
 
140
     *  return the failure.
 
141
     */
 
142
    pMI->txt_data =
 
143
        mmap(NULL, pMI->txt_size+1, prot, flags, pMI->txt_fd, (size_t)0);
 
144
    if (pMI->txt_data == MAP_FAILED_PTR) {
 
145
        pMI->txt_errno = errno;
 
146
        goto fail_return;
 
147
    }
 
148
 
 
149
    /*
 
150
     *  Most likely, everything will turn out fine now.  The only difficult
 
151
     *  part at this point is coping with files with sizes that are a multiple
 
152
     *  of the page size.  Handling that is what this whole thing is about.
 
153
     */
 
154
    pMI->txt_zero_fd = -1;
 
155
    pMI->txt_errno   = 0;
 
156
 
 
157
    {
 
158
        void* pNuls;
 
159
#ifdef _SC_PAGESIZE
 
160
        size_t pgsz = sysconf(_SC_PAGESIZE);
 
161
#else
 
162
        size_t pgsz = getpagesize();
 
163
#endif
 
164
        /*
 
165
         *  Compute the pagesize rounded mapped memory size.
 
166
         *  IF this is not the same as the file size, then there are NUL's
 
167
         *  at the end of the file mapping and all is okay.
 
168
         */
 
169
        pMI->txt_full_size = (pMI->txt_size + (pgsz - 1)) & ~(pgsz - 1);
 
170
        if (pMI->txt_size != pMI->txt_full_size)
 
171
            return pMI->txt_data;
 
172
 
 
173
        /*
 
174
         *  Still here?  We have to remap the trailing inaccessible page
 
175
         *  either anonymously or to /dev/zero.
 
176
         */
 
177
        pMI->txt_full_size += pgsz;
 
178
#if defined(MAP_ANONYMOUS)
 
179
        pNuls = mmap(
 
180
                (void*)(((char*)pMI->txt_data) + pMI->txt_size),
 
181
                pgsz, PROT_READ|PROT_WRITE,
 
182
                MAP_ANONYMOUS|MAP_FIXED|MAP_PRIVATE, AO_INVALID_FD, (size_t)0);
 
183
 
 
184
        if (pNuls != MAP_FAILED_PTR)
 
185
            return pMI->txt_data;
 
186
 
 
187
        pMI->txt_errno = errno;
 
188
 
 
189
#elif defined(HAVE_DEV_ZERO)
 
190
        pMI->txt_zero_fd = open( "/dev/zero", O_RDONLY );
 
191
 
 
192
        if (pMI->txt_zero_fd == AO_INVALID_FD) {
 
193
            pMI->txt_errno = errno;
 
194
 
 
195
        } else {
 
196
            pNuls = mmap(
 
197
                    (void*)(((char*)pMI->txt_data) + pMI->txt_size), pgsz,
 
198
                    PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED,
 
199
                    pMI->txt_zero_fd, 0 );
 
200
 
 
201
            if (pNuls != MAP_FAILED_PTR)
 
202
                return pMI->txt_data;
 
203
 
 
204
            pMI->txt_errno = errno;
 
205
            close( pMI->txt_zero_fd );
 
206
            pMI->txt_zero_fd = -1;
 
207
        }
 
208
#endif
 
209
 
 
210
        pMI->txt_full_size = pMI->txt_size;
 
211
    }
 
212
 
 
213
    {
 
214
        void* p = AGALOC( pMI->txt_size+1, "file text" );
 
215
        memcpy( p, pMI->txt_data, pMI->txt_size );
 
216
        ((char*)p)[pMI->txt_size] = NUL;
 
217
        munmap(pMI->txt_data, pMI->txt_size );
 
218
        pMI->txt_data = p;
 
219
    }
 
220
    pMI->txt_alloc = 1;
 
221
    return pMI->txt_data;
 
222
 
 
223
#else /* * * * * * no HAVE_MMAP * * * * * */
 
224
 
 
225
    pMI->txt_data = AGALOC( pMI->txt_size+1, "file text" );
 
226
    if (pMI->txt_data == NULL) {
 
227
        pMI->txt_errno = ENOMEM;
 
228
        goto fail_return;
 
229
    }
 
230
 
 
231
    {
 
232
        size_t sz = pMI->txt_size;
 
233
        char*  pz = pMI->txt_data;
 
234
 
 
235
        while (sz > 0) {
 
236
            ssize_t rdct = read( pMI->txt_fd, pz, sz );
 
237
            if (rdct <= 0) {
 
238
                pMI->txt_errno = errno;
 
239
                fprintf( stderr, zFSErrReadFile,
 
240
                         errno, strerror( errno ), pzFile );
 
241
                free( pMI->txt_data );
 
242
                goto fail_return;
 
243
            }
 
244
 
 
245
            pz += rdct;
 
246
            sz -= rdct;
 
247
        }
 
248
 
 
249
        *pz = NUL;
 
250
    }
 
251
 
 
252
    /*
 
253
     *  We never need a dummy page mapped in
 
254
     */
 
255
    pMI->txt_zero_fd = -1;
 
256
    pMI->txt_errno   = 0;
 
257
 
 
258
    return pMI->txt_data;
 
259
 
 
260
#endif /* * * * * * no HAVE_MMAP * * * * * */
 
261
 
 
262
 fail_return:
 
263
    if (pMI->txt_fd >= 0) {
 
264
        close( pMI->txt_fd );
 
265
        pMI->txt_fd = -1;
 
266
    }
 
267
    errno = pMI->txt_errno;
 
268
    pMI->txt_data = MAP_FAILED_PTR;
 
269
    return pMI->txt_data;
 
270
}
 
271
 
 
272
 
 
273
/*=export_func  text_munmap
 
274
 * private:
 
275
 *
 
276
 * what:  unmap the data mapped in by text_mmap
 
277
 *
 
278
 * arg:   tmap_info_t*, mapinfo, info about the mapping
 
279
 *
 
280
 * ret-type:   int
 
281
 * ret-desc:   -1 or 0.  @file{errno} will have the error code.
 
282
 *
 
283
 * doc:
 
284
 *
 
285
 * This routine will unmap the data mapped in with @code{text_mmap} and close
 
286
 * the associated file descriptors opened by that function.
 
287
 *
 
288
 * see: munmap(2), close(2)
 
289
 *
 
290
 * err: Any error code issued by munmap(2) or close(2) is possible.
 
291
=*/
 
292
int
 
293
text_munmap( tmap_info_t* pMI )
 
294
{
 
295
#ifdef HAVE_MMAP
 
296
    int res = 0;
 
297
    if (pMI->txt_alloc) {
 
298
        /*
 
299
         *  IF the user has write permission and the text is not mapped private,
 
300
         *  then write back any changes.  Hopefully, nobody else has modified
 
301
         *  the file in the mean time.
 
302
         */
 
303
        if (   ((pMI->txt_prot & PROT_WRITE) != 0)
 
304
            && ((pMI->txt_flags & MAP_PRIVATE) == 0))  {
 
305
 
 
306
            if (lseek(pMI->txt_fd, (size_t)0, SEEK_SET) != 0)
 
307
                goto error_return;
 
308
 
 
309
            res = (write( pMI->txt_fd, pMI->txt_data, pMI->txt_size ) < 0)
 
310
                ? errno : 0;
 
311
        }
 
312
 
 
313
        AGFREE( pMI->txt_data );
 
314
        errno = res;
 
315
    } else {
 
316
        res = munmap( pMI->txt_data, pMI->txt_full_size );
 
317
    }
 
318
    if (res != 0)
 
319
        goto error_return;
 
320
 
 
321
    res = close( pMI->txt_fd );
 
322
    if (res != 0)
 
323
        goto error_return;
 
324
 
 
325
    pMI->txt_fd = -1;
 
326
    errno = 0;
 
327
    if (pMI->txt_zero_fd != -1) {
 
328
        res = close( pMI->txt_zero_fd );
 
329
        pMI->txt_zero_fd = -1;
 
330
    }
 
331
 
 
332
 error_return:
 
333
    pMI->txt_errno = errno;
 
334
    return res;
 
335
#else  /* HAVE_MMAP */
 
336
 
 
337
    errno = 0;
 
338
    /*
 
339
     *  IF the memory is writable *AND* it is not private (copy-on-write)
 
340
     *     *AND* the memory is "sharable" (seen by other processes)
 
341
     *  THEN rewrite the data.
 
342
     */
 
343
    if (   FILE_WRITABLE(pMI->txt_prot, pMI->txt_flags)
 
344
        && (lseek( pMI->txt_fd, 0, SEEK_SET ) >= 0) ) {
 
345
        write( pMI->txt_fd, pMI->txt_data, pMI->txt_size );
 
346
    }
 
347
 
 
348
    close( pMI->txt_fd );
 
349
    pMI->txt_fd = -1;
 
350
    pMI->txt_errno = errno;
 
351
    free( pMI->txt_data );
 
352
 
 
353
    return pMI->txt_errno;
 
354
#endif /* HAVE_MMAP */
 
355
}
 
356
 
 
357
/*
 
358
 * Local Variables:
 
359
 * mode: C
 
360
 * c-file-style: "stroustrup"
 
361
 * indent-tabs-mode: nil
 
362
 * End:
 
363
 * end of autoopts/text_mmap.c */