mapping.c 27.8 KB
Newer Older
1 2 3 4
/*
 * Server-side file mapping management
 *
 * Copyright (C) 1999 Alexandre Julliard
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This 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.
 *
 * This 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 this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20
 */

21
#include "config.h"
22
#include "wine/port.h"
23

24
#include <assert.h>
25
#include <stdarg.h>
26 27
#include <stdio.h>
#include <stdlib.h>
28
#include <sys/stat.h>
29 30 31
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
32 33
#include <unistd.h>

34 35
#include "ntstatus.h"
#define WIN32_NO_STATUS
36
#include "windef.h"
37
#include "winternl.h"
38

39
#include "file.h"
40 41
#include "handle.h"
#include "thread.h"
42
#include "process.h"
43
#include "request.h"
44
#include "security.h"
45

46 47 48 49 50 51 52 53 54 55 56 57
/* list of memory ranges, used to store committed info */
struct ranges
{
    unsigned int count;
    unsigned int max;
    struct range
    {
        file_pos_t  start;
        file_pos_t  end;
    } ranges[1];
};

58 59
struct mapping
{
60
    struct object   obj;             /* object header */
61
    mem_size_t      size;            /* mapping size */
62
    unsigned int    flags;           /* SEC_* flags */
63
    int             protect;         /* protection flags */
64
    struct fd      *fd;              /* fd for mapped file */
65
    enum cpu_type   cpu;             /* client CPU (for PE image mapping) */
66
    pe_image_info_t image;           /* image info (for PE image mapping) */
67
    struct ranges  *committed;       /* list of committed ranges in this mapping */
68
    struct file    *shared_file;     /* temp file for shared PE mapping */
69
    struct list     shared_entry;    /* entry in global shared PE mappings list */
70 71 72
};

static void mapping_dump( struct object *obj, int verbose );
73
static struct object_type *mapping_get_type( struct object *obj );
74
static struct fd *mapping_get_fd( struct object *obj );
75
static unsigned int mapping_map_access( struct object *obj, unsigned int access );
76
static void mapping_destroy( struct object *obj );
77
static enum server_fd_type mapping_get_fd_type( struct fd *fd );
78 79 80

static const struct object_ops mapping_ops =
{
81 82
    sizeof(struct mapping),      /* size */
    mapping_dump,                /* dump */
83
    mapping_get_type,            /* get_type */
84 85 86 87
    no_add_queue,                /* add_queue */
    NULL,                        /* remove_queue */
    NULL,                        /* signaled */
    NULL,                        /* satisfied */
88
    no_signal,                   /* signal */
89
    mapping_get_fd,              /* get_fd */
90
    mapping_map_access,          /* map_access */
91 92
    default_get_sd,              /* get_sd */
    default_set_sd,              /* set_sd */
93
    no_lookup_name,              /* lookup_name */
94 95
    directory_link_name,         /* link_name */
    default_unlink_name,         /* unlink_name */
96
    no_open_file,                /* open_file */
97
    fd_close_handle,             /* close_handle */
98
    mapping_destroy              /* destroy */
99 100
};

101 102 103 104 105
static const struct fd_ops mapping_fd_ops =
{
    default_fd_get_poll_events,   /* get_poll_events */
    default_poll_event,           /* poll_event */
    mapping_get_fd_type,          /* get_fd_type */
106 107 108
    no_fd_read,                   /* read */
    no_fd_write,                  /* write */
    no_fd_flush,                  /* flush */
109 110
    no_fd_ioctl,                  /* ioctl */
    no_fd_queue_async,            /* queue_async */
111
    default_fd_reselect_async     /* reselect_async */
112 113
};

114
static struct list shared_list = LIST_INIT(shared_list);
115

116
static size_t page_mask;
117

118
#define ROUND_SIZE(size)  (((size) + page_mask) & ~page_mask)
119 120


121
/* extend a file beyond the current end of file */
122
static int grow_file( int unix_fd, file_pos_t new_size )
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
{
    static const char zero;
    off_t size = new_size;

    if (sizeof(new_size) > sizeof(size) && size != new_size)
    {
        set_error( STATUS_INVALID_PARAMETER );
        return 0;
    }
    /* extend the file one byte beyond the requested size and then truncate it */
    /* this should work around ftruncate implementations that can't extend files */
    if (pwrite( unix_fd, &zero, 1, size ) != -1)
    {
        ftruncate( unix_fd, size );
        return 1;
    }
    file_set_error();
    return 0;
}

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
/* check if the current directory allows exec mappings */
static int check_current_dir_for_exec(void)
{
    int fd;
    char tmpfn[] = "anonmap.XXXXXX";
    void *ret = MAP_FAILED;

    fd = mkstemps( tmpfn, 0 );
    if (fd == -1) return 0;
    if (grow_file( fd, 1 ))
    {
        ret = mmap( NULL, get_page_size(), PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0 );
        if (ret != MAP_FAILED) munmap( ret, get_page_size() );
    }
    close( fd );
    unlink( tmpfn );
    return (ret != MAP_FAILED);
}

162
/* create a temp file for anonymous mappings */
163
static int create_temp_file( file_pos_t size )
164
{
165 166
    static int temp_dir_fd = -1;
    char tmpfn[] = "anonmap.XXXXXX";
167 168
    int fd;

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
    if (temp_dir_fd == -1)
    {
        temp_dir_fd = server_dir_fd;
        if (!check_current_dir_for_exec())
        {
            /* the server dir is noexec, try the config dir instead */
            fchdir( config_dir_fd );
            if (check_current_dir_for_exec())
                temp_dir_fd = config_dir_fd;
            else  /* neither works, fall back to server dir */
                fchdir( server_dir_fd );
        }
    }
    else if (temp_dir_fd != server_dir_fd) fchdir( temp_dir_fd );

184
    fd = mkstemps( tmpfn, 0 );
185
    if (fd != -1)
186
    {
187 188 189 190 191 192
        if (!grow_file( fd, size ))
        {
            close( fd );
            fd = -1;
        }
        unlink( tmpfn );
193
    }
194
    else file_set_error();
195 196

    if (temp_dir_fd != server_dir_fd) fchdir( server_dir_fd );
197
    return fd;
198 199
}

200 201 202 203 204
/* find the shared PE mapping for a given mapping */
static struct file *get_shared_file( struct mapping *mapping )
{
    struct mapping *ptr;

205
    LIST_FOR_EACH_ENTRY( ptr, &shared_list, struct mapping, shared_entry )
206
        if (is_same_file_fd( ptr->fd, mapping->fd ))
207 208 209 210
            return (struct file *)grab_object( ptr->shared_file );
    return NULL;
}

211 212 213
/* return the size of the memory mapping and file range of a given section */
static inline void get_section_sizes( const IMAGE_SECTION_HEADER *sec, size_t *map_size,
                                      off_t *file_start, size_t *file_size )
214
{
215
    static const unsigned int sector_align = 0x1ff;
216

217 218 219 220 221 222
    if (!sec->Misc.VirtualSize) *map_size = ROUND_SIZE( sec->SizeOfRawData );
    else *map_size = ROUND_SIZE( sec->Misc.VirtualSize );

    *file_start = sec->PointerToRawData & ~sector_align;
    *file_size = (sec->SizeOfRawData + (sec->PointerToRawData & sector_align) + sector_align) & ~sector_align;
    if (*file_size > *map_size) *file_size = *map_size;
223 224
}

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
/* add a range to the committed list */
static void add_committed_range( struct mapping *mapping, file_pos_t start, file_pos_t end )
{
    unsigned int i, j;
    struct range *ranges;

    if (!mapping->committed) return;  /* everything committed already */

    for (i = 0, ranges = mapping->committed->ranges; i < mapping->committed->count; i++)
    {
        if (ranges[i].start > end) break;
        if (ranges[i].end < start) continue;
        if (ranges[i].start > start) ranges[i].start = start;   /* extend downwards */
        if (ranges[i].end < end)  /* extend upwards and maybe merge with next */
        {
            for (j = i + 1; j < mapping->committed->count; j++)
            {
                if (ranges[j].start > end) break;
                if (ranges[j].end > end) end = ranges[j].end;
            }
            if (j > i + 1)
            {
                memmove( &ranges[i + 1], &ranges[j], (mapping->committed->count - j) * sizeof(*ranges) );
                mapping->committed->count -= j - (i + 1);
            }
            ranges[i].end = end;
        }
        return;
    }

    /* now add a new range */

    if (mapping->committed->count == mapping->committed->max)
    {
        unsigned int new_size = mapping->committed->max * 2;
        struct ranges *new_ptr = realloc( mapping->committed, offsetof( struct ranges, ranges[new_size] ));
        if (!new_ptr) return;
        new_ptr->max = new_size;
        ranges = new_ptr->ranges;
        mapping->committed = new_ptr;
    }
    memmove( &ranges[i + 1], &ranges[i], (mapping->committed->count - i) * sizeof(*ranges) );
    ranges[i].start = start;
    ranges[i].end = end;
    mapping->committed->count++;
}

/* find the range containing start and return whether it's committed */
273
static int find_committed_range( struct mapping *mapping, file_pos_t start, mem_size_t *size )
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
{
    unsigned int i;
    struct range *ranges;

    if (!mapping->committed)  /* everything is committed */
    {
        *size = mapping->size - start;
        return 1;
    }
    for (i = 0, ranges = mapping->committed->ranges; i < mapping->committed->count; i++)
    {
        if (ranges[i].start > start)
        {
            *size = ranges[i].start - start;
            return 0;
        }
        if (ranges[i].end > start)
        {
            *size = ranges[i].end - start;
            return 1;
        }
    }
    *size = mapping->size - start;
    return 0;
}

300 301
/* allocate and fill the temp file for a shared PE image mapping */
static int build_shared_mapping( struct mapping *mapping, int fd,
302
                                 IMAGE_SECTION_HEADER *sec, unsigned int nb_sec )
303
{
304
    unsigned int i;
305
    mem_size_t total_size;
306
    size_t file_size, map_size, max_size;
307
    off_t shared_pos, read_pos, write_pos;
308 309
    char *buffer = NULL;
    int shared_fd;
310
    long toread;
311 312 313 314 315 316 317 318 319

    /* compute the total size of the shared mapping */

    total_size = max_size = 0;
    for (i = 0; i < nb_sec; i++)
    {
        if ((sec[i].Characteristics & IMAGE_SCN_MEM_SHARED) &&
            (sec[i].Characteristics & IMAGE_SCN_MEM_WRITE))
        {
320 321 322
            get_section_sizes( &sec[i], &map_size, &read_pos, &file_size );
            if (file_size > max_size) max_size = file_size;
            total_size += map_size;
323 324
        }
    }
325
    if (!total_size) return 1;  /* nothing to do */
326

327 328
    if ((mapping->shared_file = get_shared_file( mapping ))) return 1;

329 330
    /* create a temp file for the mapping */

331 332 333
    if ((shared_fd = create_temp_file( total_size )) == -1) return 0;
    if (!(mapping->shared_file = create_file_for_fd( shared_fd, FILE_GENERIC_READ|FILE_GENERIC_WRITE, 0 )))
        return 0;
334 335 336 337 338

    if (!(buffer = malloc( max_size ))) goto error;

    /* copy the shared sections data into the temp file */

339 340
    shared_pos = 0;
    for (i = 0; i < nb_sec; i++)
341 342 343
    {
        if (!(sec[i].Characteristics & IMAGE_SCN_MEM_SHARED)) continue;
        if (!(sec[i].Characteristics & IMAGE_SCN_MEM_WRITE)) continue;
344
        get_section_sizes( &sec[i], &map_size, &read_pos, &file_size );
345
        write_pos = shared_pos;
346 347 348
        shared_pos += map_size;
        if (!sec[i].PointerToRawData || !file_size) continue;
        toread = file_size;
349 350
        while (toread)
        {
351
            long res = pread( fd, buffer + file_size - toread, toread, read_pos );
352 353 354 355 356
            if (!res && toread < 0x200)  /* partial sector at EOF is not an error */
            {
                file_size -= toread;
                break;
            }
357 358
            if (res <= 0) goto error;
            toread -= res;
359
            read_pos += res;
360
        }
361
        if (pwrite( shared_fd, buffer, file_size, write_pos ) != file_size) goto error;
362 363 364 365 366
    }
    free( buffer );
    return 1;

 error:
367 368
    release_object( mapping->shared_file );
    mapping->shared_file = NULL;
369
    free( buffer );
370 371 372 373
    return 0;
}

/* retrieve the mapping parameters for an executable (PE) image */
374
static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_size, int unix_fd )
375 376 377
{
    IMAGE_DOS_HEADER dos;
    IMAGE_SECTION_HEADER *sec = NULL;
378 379 380 381 382 383 384 385 386 387
    struct
    {
        DWORD Signature;
        IMAGE_FILE_HEADER FileHeader;
        union
        {
            IMAGE_OPTIONAL_HEADER32 hdr32;
            IMAGE_OPTIONAL_HEADER64 hdr64;
        } opt;
    } nt;
388
    off_t pos;
389
    int size;
390 391 392

    /* load the headers */

393
    if (!file_size) return STATUS_INVALID_FILE_FOR_SECTION;
394 395
    if (pread( unix_fd, &dos, sizeof(dos), 0 ) != sizeof(dos)) return STATUS_INVALID_IMAGE_NOT_MZ;
    if (dos.e_magic != IMAGE_DOS_SIGNATURE) return STATUS_INVALID_IMAGE_NOT_MZ;
396
    pos = dos.e_lfanew;
397

398
    size = pread( unix_fd, &nt, sizeof(nt), pos );
399
    if (size < sizeof(nt.Signature) + sizeof(nt.FileHeader)) return STATUS_INVALID_IMAGE_FORMAT;
400
    /* zero out Optional header in the case it's not present or partial */
401
    size = min( size, sizeof(nt.Signature) + sizeof(nt.FileHeader) + nt.FileHeader.SizeOfOptionalHeader );
402
    if (size < sizeof(nt)) memset( (char *)&nt + size, 0, sizeof(nt) - size );
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
    if (nt.Signature != IMAGE_NT_SIGNATURE)
    {
        if (*(WORD *)&nt.Signature == IMAGE_OS2_SIGNATURE) return STATUS_INVALID_IMAGE_NE_FORMAT;
        return STATUS_INVALID_IMAGE_PROTECT;
    }

    mapping->cpu = current->process->cpu;
    switch (mapping->cpu)
    {
    case CPU_x86:
        if (nt.FileHeader.Machine != IMAGE_FILE_MACHINE_I386) return STATUS_INVALID_IMAGE_FORMAT;
        if (nt.opt.hdr32.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return STATUS_INVALID_IMAGE_FORMAT;
        break;
    case CPU_x86_64:
        if (nt.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) return STATUS_INVALID_IMAGE_FORMAT;
        if (nt.opt.hdr64.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) return STATUS_INVALID_IMAGE_FORMAT;
        break;
    case CPU_POWERPC:
        if (nt.FileHeader.Machine != IMAGE_FILE_MACHINE_POWERPC) return STATUS_INVALID_IMAGE_FORMAT;
        if (nt.opt.hdr32.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return STATUS_INVALID_IMAGE_FORMAT;
        break;
    case CPU_ARM:
        if (nt.FileHeader.Machine != IMAGE_FILE_MACHINE_ARM &&
            nt.FileHeader.Machine != IMAGE_FILE_MACHINE_THUMB &&
            nt.FileHeader.Machine != IMAGE_FILE_MACHINE_ARMNT) return STATUS_INVALID_IMAGE_FORMAT;
        if (nt.opt.hdr32.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return STATUS_INVALID_IMAGE_FORMAT;
        break;
    case CPU_ARM64:
        if (nt.FileHeader.Machine != IMAGE_FILE_MACHINE_ARM64) return STATUS_INVALID_IMAGE_FORMAT;
        if (nt.opt.hdr64.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) return STATUS_INVALID_IMAGE_FORMAT;
        break;
    default:
        return STATUS_INVALID_IMAGE_FORMAT;
    }
437 438 439 440

    switch (nt.opt.hdr32.Magic)
    {
    case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
441 442
        mapping->image.base           = nt.opt.hdr32.ImageBase;
        mapping->image.entry_point    = nt.opt.hdr32.ImageBase + nt.opt.hdr32.AddressOfEntryPoint;
443
        mapping->image.map_size       = ROUND_SIZE( nt.opt.hdr32.SizeOfImage );
444 445 446 447 448 449 450 451 452
        mapping->image.stack_size     = nt.opt.hdr32.SizeOfStackReserve;
        mapping->image.stack_commit   = nt.opt.hdr32.SizeOfStackCommit;
        mapping->image.subsystem      = nt.opt.hdr32.Subsystem;
        mapping->image.subsystem_low  = nt.opt.hdr32.MinorSubsystemVersion;
        mapping->image.subsystem_high = nt.opt.hdr32.MajorSubsystemVersion;
        mapping->image.dll_charact    = nt.opt.hdr32.DllCharacteristics;
        mapping->image.loader_flags   = nt.opt.hdr32.LoaderFlags;
        mapping->image.header_size    = nt.opt.hdr32.SizeOfHeaders;
        mapping->image.checksum       = nt.opt.hdr32.CheckSum;
453 454
        break;
    case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
455 456
        mapping->image.base           = nt.opt.hdr64.ImageBase;
        mapping->image.entry_point    = nt.opt.hdr64.ImageBase + nt.opt.hdr64.AddressOfEntryPoint;
457
        mapping->image.map_size       = ROUND_SIZE( nt.opt.hdr64.SizeOfImage );
458 459 460 461 462 463 464 465 466
        mapping->image.stack_size     = nt.opt.hdr64.SizeOfStackReserve;
        mapping->image.stack_commit   = nt.opt.hdr64.SizeOfStackCommit;
        mapping->image.subsystem      = nt.opt.hdr64.Subsystem;
        mapping->image.subsystem_low  = nt.opt.hdr64.MinorSubsystemVersion;
        mapping->image.subsystem_high = nt.opt.hdr64.MajorSubsystemVersion;
        mapping->image.dll_charact    = nt.opt.hdr64.DllCharacteristics;
        mapping->image.loader_flags   = nt.opt.hdr64.LoaderFlags;
        mapping->image.header_size    = nt.opt.hdr64.SizeOfHeaders;
        mapping->image.checksum       = nt.opt.hdr64.CheckSum;
467 468
        break;
    }
469 470 471 472 473 474 475
    mapping->image.image_charact = nt.FileHeader.Characteristics;
    mapping->image.machine       = nt.FileHeader.Machine;
    mapping->image.zerobits      = 0; /* FIXME */
    mapping->image.gp            = 0; /* FIXME */
    mapping->image.contains_code = 0; /* FIXME */
    mapping->image.image_flags   = 0; /* FIXME */
    mapping->image.file_size     = file_size;
476 477 478

    /* load the section headers */

479
    pos += sizeof(nt.Signature) + sizeof(nt.FileHeader) + nt.FileHeader.SizeOfOptionalHeader;
480
    size = sizeof(*sec) * nt.FileHeader.NumberOfSections;
481 482 483
    if (!mapping->size) mapping->size = mapping->image.map_size;
    else if (mapping->size > mapping->image.map_size) return STATUS_SECTION_TOO_BIG;
    if (pos + size > mapping->image.map_size) return STATUS_INVALID_FILE_FOR_SECTION;
484
    if (pos + size > mapping->image.header_size) mapping->image.header_size = pos + size;
485
    if (!(sec = malloc( size ))) goto error;
486
    if (pread( unix_fd, sec, size, pos ) != size) goto error;
487

488
    if (!build_shared_mapping( mapping, unix_fd, sec, nt.FileHeader.NumberOfSections )) goto error;
489

490
    if (mapping->shared_file) list_add_head( &shared_list, &mapping->shared_entry );
491

492
    free( sec );
493
    return 0;
494 495

 error:
496
    free( sec );
497
    return STATUS_INVALID_FILE_FOR_SECTION;
498 499
}

500
static struct object *create_mapping( struct object *root, const struct unicode_str *name,
501
                                      unsigned int attr, mem_size_t size, unsigned int flags, int protect,
502
                                      obj_handle_t handle, const struct security_descriptor *sd )
503 504
{
    struct mapping *mapping;
505 506
    struct file *file;
    struct fd *fd;
507
    int access = 0;
508 509
    int unix_fd;
    struct stat st;
510

511
    if (!page_mask) page_mask = sysconf( _SC_PAGESIZE ) - 1;
512

513
    if (!(mapping = create_named_object( root, &mapping_ops, name, attr, sd )))
514
        return NULL;
515
    if (get_error() == STATUS_OBJECT_NAME_EXISTS)
516 517
        return &mapping->obj;  /* Nothing else to do */

518
    mapping->size        = size;
519 520
    mapping->flags       = flags & (SEC_IMAGE | SEC_NOCACHE | SEC_WRITECOMBINE | SEC_LARGE_PAGES);
    mapping->protect     = protect;
521
    mapping->fd          = NULL;
522
    mapping->shared_file = NULL;
523
    mapping->committed   = NULL;
524

525 526
    if (protect & VPROT_READ) access |= FILE_READ_DATA;
    if (protect & VPROT_WRITE) access |= FILE_WRITE_DATA;
527

528
    if (handle)
529
    {
530
        const unsigned int sharing = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
531
        unsigned int mapping_access = FILE_MAPPING_ACCESS;
532

533
        if (flags & SEC_RESERVE)
534 535 536 537
        {
            set_error( STATUS_INVALID_PARAMETER );
            goto error;
        }
538 539
        if (!(file = get_file_obj( current->process, handle, access ))) goto error;
        fd = get_obj_fd( (struct object *)file );
540 541

        /* file sharing rules for mappings are different so we use magic the access rights */
542
        if (flags & SEC_IMAGE) mapping_access |= FILE_MAPPING_IMAGE;
543
        else if (protect & VPROT_WRITE) mapping_access |= FILE_MAPPING_WRITE;
544

545
        mapping->flags |= SEC_FILE;
546 547 548 549 550
        if (!(mapping->fd = get_fd_object_for_mapping( fd, mapping_access, sharing )))
        {
            mapping->fd = dup_fd_object( fd, mapping_access, sharing, FILE_SYNCHRONOUS_IO_NONALERT );
            if (mapping->fd) set_fd_user( mapping->fd, &mapping_fd_ops, NULL );
        }
551 552 553 554
        release_object( file );
        release_object( fd );
        if (!mapping->fd) goto error;

555
        if ((unix_fd = get_unix_fd( mapping->fd )) == -1) goto error;
556
        if (fstat( unix_fd, &st ) == -1)
557
        {
558
            file_set_error();
559
            goto error;
560
        }
561
        if (flags & SEC_IMAGE)
562
        {
563 564 565
            unsigned int err = get_image_params( mapping, st.st_size, unix_fd );
            if (!err) return &mapping->obj;
            set_error( err );
566 567
            goto error;
        }
568
        if (!mapping->size)
569
        {
570
            if (!(mapping->size = st.st_size))
571
            {
572
                set_error( STATUS_MAPPED_FILE_SIZE_ZERO );
573 574
                goto error;
            }
575
        }
576 577 578 579 580 581 582 583 584
        else if (st.st_size < mapping->size)
        {
            if (!(access & FILE_WRITE_DATA))
            {
                set_error( STATUS_SECTION_TOO_BIG );
                goto error;
            }
            if (!grow_file( unix_fd, mapping->size )) goto error;
        }
585
    }
586 587
    else  /* Anonymous mapping (no associated file) */
    {
588
        if (!mapping->size || (flags & SEC_IMAGE))
589
        {
590
            set_error( STATUS_INVALID_PARAMETER );
591 592
            goto error;
        }
593 594
        mapping->flags |= flags & (SEC_COMMIT | SEC_RESERVE);
        if (flags & SEC_RESERVE)
595 596 597 598 599
        {
            if (!(mapping->committed = mem_alloc( offsetof(struct ranges, ranges[8]) ))) goto error;
            mapping->committed->count = 0;
            mapping->committed->max   = 8;
        }
600 601
        mapping->size = (mapping->size + page_mask) & ~((mem_size_t)page_mask);
        if ((unix_fd = create_temp_file( mapping->size )) == -1) goto error;
602 603
        if (!(mapping->fd = create_anonymous_fd( &mapping_fd_ops, unix_fd, &mapping->obj,
                                                 FILE_SYNCHRONOUS_IO_NONALERT ))) goto error;
604
        allow_fd_caching( mapping->fd );
605
    }
606
    return &mapping->obj;
607 608 609 610

 error:
    release_object( mapping );
    return NULL;
611 612
}

613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
struct mapping *get_mapping_obj( struct process *process, obj_handle_t handle, unsigned int access )
{
    return (struct mapping *)get_handle_obj( process, handle, access, &mapping_ops );
}

/* open a new file handle to the file backing the mapping */
obj_handle_t open_mapping_file( struct process *process, struct mapping *mapping,
                                unsigned int access, unsigned int sharing )
{
    obj_handle_t handle;
    struct file *file = create_file_for_fd_obj( mapping->fd, access, sharing );

    if (!file) return 0;
    handle = alloc_handle( process, file, access, 0 );
    release_object( file );
    return handle;
}

631 632 633 634 635 636
struct mapping *grab_mapping_unless_removable( struct mapping *mapping )
{
    if (is_fd_removable( mapping->fd )) return NULL;
    return (struct mapping *)grab_object( mapping );
}

637 638 639 640
static void mapping_dump( struct object *obj, int verbose )
{
    struct mapping *mapping = (struct mapping *)obj;
    assert( obj->ops == &mapping_ops );
641
    fprintf( stderr, "Mapping size=%08x%08x flags=%08x prot=%08x fd=%p shared_file=%p\n",
642
             (unsigned int)(mapping->size >> 32), (unsigned int)mapping->size,
643
             mapping->flags, mapping->protect, mapping->fd, mapping->shared_file );
644 645
}

646 647 648 649 650 651 652
static struct object_type *mapping_get_type( struct object *obj )
{
    static const WCHAR name[] = {'S','e','c','t','i','o','n'};
    static const struct unicode_str str = { name, sizeof(name) };
    return get_object_type( &str );
}

653 654 655
static struct fd *mapping_get_fd( struct object *obj )
{
    struct mapping *mapping = (struct mapping *)obj;
656
    return (struct fd *)grab_object( mapping->fd );
657 658
}

659 660 661 662 663 664 665 666 667
static unsigned int mapping_map_access( struct object *obj, unsigned int access )
{
    if (access & GENERIC_READ)    access |= STANDARD_RIGHTS_READ | SECTION_QUERY | SECTION_MAP_READ;
    if (access & GENERIC_WRITE)   access |= STANDARD_RIGHTS_WRITE | SECTION_MAP_WRITE;
    if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE | SECTION_MAP_EXECUTE;
    if (access & GENERIC_ALL)     access |= SECTION_ALL_ACCESS;
    return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
}

668 669 670 671
static void mapping_destroy( struct object *obj )
{
    struct mapping *mapping = (struct mapping *)obj;
    assert( obj->ops == &mapping_ops );
672
    if (mapping->fd) release_object( mapping->fd );
673 674 675
    if (mapping->shared_file)
    {
        release_object( mapping->shared_file );
676
        list_remove( &mapping->shared_entry );
677
    }
678
    free( mapping->committed );
679
}
680

681 682 683 684 685
static enum server_fd_type mapping_get_fd_type( struct fd *fd )
{
    return FD_TYPE_FILE;
}

686 687
int get_page_size(void)
{
688
    if (!page_mask) page_mask = sysconf( _SC_PAGESIZE ) - 1;
689 690 691
    return page_mask + 1;
}

692 693 694
/* create a file mapping */
DECL_HANDLER(create_mapping)
{
695
    struct object *root, *obj;
696
    struct unicode_str name;
697
    const struct security_descriptor *sd;
698
    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
699

700
    if (!objattr) return;
701

702
    if ((obj = create_mapping( root, &name, objattr->attributes,
703
                               req->size, req->flags, req->protect, req->file_handle, sd )))
704
    {
705
        if (get_error() == STATUS_OBJECT_NAME_EXISTS)
706
            reply->handle = alloc_handle( current->process, obj, req->access, objattr->attributes );
707
        else
708 709
            reply->handle = alloc_handle_no_access_check( current->process, obj,
                                                          req->access, objattr->attributes );
710 711
        release_object( obj );
    }
712 713

    if (root) release_object( root );
714 715 716 717 718
}

/* open a handle to a mapping */
DECL_HANDLER(open_mapping)
{
719
    struct unicode_str name = get_req_unicode_str();
720

721 722
    reply->handle = open_object( current->process, req->rootdir, req->access,
                                 &mapping_ops, &name, req->attributes );
723 724 725 726 727
}

/* get a mapping information */
DECL_HANDLER(get_mapping_info)
{
728
    struct mapping *mapping;
729
    struct fd *fd;
730

731 732
    if (!(mapping = get_mapping_obj( current->process, req->handle, req->access ))) return;

733 734 735 736 737 738
    reply->size    = mapping->size;
    reply->flags   = mapping->flags;
    reply->protect = mapping->protect;

    if (mapping->flags & SEC_IMAGE)
        set_reply_data( &mapping->image, min( sizeof(mapping->image), get_reply_max_size() ));
739

740 741 742 743 744 745
    if (!(req->access & (SECTION_MAP_READ | SECTION_MAP_WRITE)))  /* query only */
    {
        release_object( mapping );
        return;
    }

746
    if ((mapping->flags & SEC_IMAGE) && mapping->cpu != current->process->cpu)
747
    {
748 749 750 751 752 753 754 755 756 757 758 759 760 761
        set_error( STATUS_INVALID_IMAGE_FORMAT );
        release_object( mapping );
        return;
    }

    if ((fd = get_obj_fd( &mapping->obj )))
    {
        if (!is_fd_removable(fd)) reply->mapping = alloc_handle( current->process, mapping, 0, 0 );
        release_object( fd );
    }
    if (mapping->shared_file)
    {
        if (!(reply->shared_file = alloc_handle( current->process, mapping->shared_file,
                                                 GENERIC_READ|GENERIC_WRITE, 0 )))
762
        {
763
            if (reply->mapping) close_handle( current->process, reply->mapping );
764
        }
765
    }
766
    release_object( mapping );
767
}
768 769 770 771 772 773

/* get a range of committed pages in a file mapping */
DECL_HANDLER(get_mapping_committed_range)
{
    struct mapping *mapping;

774
    if ((mapping = get_mapping_obj( current->process, req->handle, 0 )))
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
    {
        if (!(req->offset & page_mask) && req->offset < mapping->size)
            reply->committed = find_committed_range( mapping, req->offset, &reply->size );
        else
            set_error( STATUS_INVALID_PARAMETER );

        release_object( mapping );
    }
}

/* add a range to the committed pages in a file mapping */
DECL_HANDLER(add_mapping_committed_range)
{
    struct mapping *mapping;

790
    if ((mapping = get_mapping_obj( current->process, req->handle, 0 )))
791 792 793 794 795 796 797 798 799 800 801 802 803
    {
        if (!(req->size & page_mask) &&
            !(req->offset & page_mask) &&
            req->offset < mapping->size &&
            req->size > 0 &&
            req->size <= mapping->size - req->offset)
            add_committed_range( mapping, req->offset, req->offset + req->size );
        else
            set_error( STATUS_INVALID_PARAMETER );

        release_object( mapping );
    }
}