~ubuntu-branches/ubuntu/trusty/postgresql-9.3/trusty-security

« back to all changes in this revision

Viewing changes to src/backend/storage/file/fd.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2016-08-17 16:37:41 UTC
  • mfrom: (1.2.5) (18.1.5 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20160817163741-qe6axor32fd1qu2y
Tags: 9.3.14-0ubuntu0.14.04
* New upstream security/bug fix release (LP: #1614113):
  - Fix possible mis-evaluation of nested CASE-WHEN expressions
    A CASE expression appearing within the test value subexpression of
    another CASE could become confused about whether its own test value was
    null or not.  Also, inlining of a SQL function implementing the equality
    operator used by a CASE expression could result in passing the wrong
    test value to functions called within a CASE expression in the SQL
    function's body.  If the test values were of different data types, a
    crash might result; moreover such situations could be abused to allow
    disclosure of portions of server memory.  (CVE-2016-5423)

  - Fix client programs' handling of special characters in database and role
    names
    Numerous places in vacuumdb and other client programs could become
    confused by database and role names containing double quotes or
    backslashes.  Tighten up quoting rules to make that safe. Also, ensure
    that when a conninfo string is used as a database name parameter to
    these programs, it is correctly treated as such throughout.

    Fix handling of paired double quotes in psql's \connect and \password
    commands to match the documentation.

    Introduce a new -reuse-previous option in psql's \connect command to
    allow explicit control of whether to re-use connection parameters from a
    previous connection.  (Without this, the choice is based on whether the
    database name looks like a conninfo string, as before.)  This allows
    secure handling of database names containing special characters in
    pg_dumpall scripts.

    pg_dumpall now refuses to deal with database and role names containing
    carriage returns or newlines, as it seems impractical to quote those
    characters safely on Windows.  In future we may reject such names on the
    server side, but that step has not been taken yet.

    These are considered security fixes because crafted object names
    containing special characters could have been used to execute commands
    with superuser privileges the next time a superuser executes pg_dumpall
    or other routine maintenance operations.  (CVE-2016-5424)

  - Details: http://www.postgresql.org/docs/9.3/static/release-9-3-14.html

Show diffs side-by-side

added added

removed removed

Lines of Context:
306
306
#ifdef PG_FLUSH_DATA_WORKS
307
307
static void pre_sync_fname(const char *fname, bool isdir, int elevel);
308
308
#endif
309
 
static void fsync_fname_ext(const char *fname, bool isdir, int elevel);
 
309
static void datadir_fsync_fname(const char *fname, bool isdir, int elevel);
 
310
 
 
311
static int      fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel);
 
312
static int      fsync_parent_path(const char *fname, int elevel);
310
313
 
311
314
 
312
315
/*
413
416
 * indicate the OS just doesn't allow/require fsyncing directories.
414
417
 */
415
418
void
416
 
fsync_fname(char *fname, bool isdir)
 
419
fsync_fname(const char *fname, bool isdir)
 
420
{
 
421
        fsync_fname_ext(fname, isdir, false, ERROR);
 
422
}
 
423
 
 
424
/*
 
425
 * durable_rename -- rename(2) wrapper, issuing fsyncs required for durability
 
426
 *
 
427
 * This routine ensures that, after returning, the effect of renaming file
 
428
 * persists in case of a crash. A crash while this routine is running will
 
429
 * leave you with either the pre-existing or the moved file in place of the
 
430
 * new file; no mixed state or truncated files are possible.
 
431
 *
 
432
 * It does so by using fsync on the old filename and the possibly existing
 
433
 * target filename before the rename, and the target file and directory after.
 
434
 *
 
435
 * Note that rename() cannot be used across arbitrary directories, as they
 
436
 * might not be on the same filesystem. Therefore this routine does not
 
437
 * support renaming across directories.
 
438
 *
 
439
 * Log errors with the caller specified severity.
 
440
 *
 
441
 * Returns 0 if the operation succeeded, -1 otherwise. Note that errno is not
 
442
 * valid upon return.
 
443
 */
 
444
int
 
445
durable_rename(const char *oldfile, const char *newfile, int elevel)
417
446
{
418
447
        int                     fd;
419
 
        int                     returncode;
420
448
 
421
449
        /*
422
 
         * Some OSs require directories to be opened read-only whereas other
423
 
         * systems don't allow us to fsync files opened read-only; so we need both
424
 
         * cases here
 
450
         * First fsync the old and target path (if it exists), to ensure that they
 
451
         * are properly persistent on disk. Syncing the target file is not
 
452
         * strictly necessary, but it makes it easier to reason about crashes;
 
453
         * because it's then guaranteed that either source or target file exists
 
454
         * after a crash.
425
455
         */
426
 
        if (!isdir)
427
 
                fd = OpenTransientFile(fname,
428
 
                                                           O_RDWR | PG_BINARY,
429
 
                                                           S_IRUSR | S_IWUSR);
 
456
        if (fsync_fname_ext(oldfile, false, false, elevel) != 0)
 
457
                return -1;
 
458
 
 
459
        fd = OpenTransientFile((char *) newfile, PG_BINARY | O_RDWR, 0);
 
460
        if (fd < 0)
 
461
        {
 
462
                if (errno != ENOENT)
 
463
                {
 
464
                        ereport(elevel,
 
465
                                        (errcode_for_file_access(),
 
466
                                         errmsg("could not open file \"%s\": %m", newfile)));
 
467
                        return -1;
 
468
                }
 
469
        }
430
470
        else
431
 
                fd = OpenTransientFile(fname,
432
 
                                                           O_RDONLY | PG_BINARY,
433
 
                                                           S_IRUSR | S_IWUSR);
434
 
 
435
 
        /*
436
 
         * Some OSs don't allow us to open directories at all (Windows returns
437
 
         * EACCES)
438
 
         */
439
 
        if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES))
440
 
                return;
441
 
 
442
 
        else if (fd < 0)
443
 
                ereport(ERROR,
444
 
                                (errcode_for_file_access(),
445
 
                                 errmsg("could not open file \"%s\": %m", fname)));
446
 
 
447
 
        returncode = pg_fsync(fd);
448
 
 
449
 
        /* Some OSs don't allow us to fsync directories at all */
450
 
        if (returncode != 0 && isdir && errno == EBADF)
451
471
        {
 
472
                if (pg_fsync(fd) != 0)
 
473
                {
 
474
                        int                     save_errno;
 
475
 
 
476
                        /* close file upon error, might not be in transaction context */
 
477
                        save_errno = errno;
 
478
                        CloseTransientFile(fd);
 
479
                        errno = save_errno;
 
480
 
 
481
                        ereport(elevel,
 
482
                                        (errcode_for_file_access(),
 
483
                                         errmsg("could not fsync file \"%s\": %m", newfile)));
 
484
                        return -1;
 
485
                }
452
486
                CloseTransientFile(fd);
453
 
                return;
454
 
        }
455
 
 
456
 
        if (returncode != 0)
457
 
                ereport(ERROR,
458
 
                                (errcode_for_file_access(),
459
 
                                 errmsg("could not fsync file \"%s\": %m", fname)));
460
 
 
461
 
        CloseTransientFile(fd);
462
 
}
463
 
 
 
487
        }
 
488
 
 
489
        /* Time to do the real deal... */
 
490
        if (rename(oldfile, newfile) < 0)
 
491
        {
 
492
                ereport(elevel,
 
493
                                (errcode_for_file_access(),
 
494
                                 errmsg("could not rename file \"%s\" to \"%s\": %m",
 
495
                                                oldfile, newfile)));
 
496
                return -1;
 
497
        }
 
498
 
 
499
        /*
 
500
         * To guarantee renaming the file is persistent, fsync the file with its
 
501
         * new name, and its containing directory.
 
502
         */
 
503
        if (fsync_fname_ext(newfile, false, false, elevel) != 0)
 
504
                return -1;
 
505
 
 
506
        if (fsync_parent_path(newfile, elevel) != 0)
 
507
                return -1;
 
508
 
 
509
        return 0;
 
510
}
 
511
 
 
512
/*
 
513
 * durable_link_or_rename -- rename a file in a durable manner.
 
514
 *
 
515
 * Similar to durable_rename(), except that this routine tries (but does not
 
516
 * guarantee) not to overwrite the target file.
 
517
 *
 
518
 * Note that a crash in an unfortunate moment can leave you with two links to
 
519
 * the target file.
 
520
 *
 
521
 * Log errors with the caller specified severity.
 
522
 *
 
523
 * Returns 0 if the operation succeeded, -1 otherwise. Note that errno is not
 
524
 * valid upon return.
 
525
 */
 
526
int
 
527
durable_link_or_rename(const char *oldfile, const char *newfile, int elevel)
 
528
{
 
529
        /*
 
530
         * Ensure that, if we crash directly after the rename/link, a file with
 
531
         * valid contents is moved into place.
 
532
         */
 
533
        if (fsync_fname_ext(oldfile, false, false, elevel) != 0)
 
534
                return -1;
 
535
 
 
536
#if HAVE_WORKING_LINK
 
537
        if (link(oldfile, newfile) < 0)
 
538
        {
 
539
                ereport(elevel,
 
540
                                (errcode_for_file_access(),
 
541
                                 errmsg("could not link file \"%s\" to \"%s\": %m",
 
542
                                                oldfile, newfile)));
 
543
                return -1;
 
544
        }
 
545
        unlink(oldfile);
 
546
#else
 
547
        /* XXX: Add racy file existence check? */
 
548
        if (rename(oldfile, newfile) < 0)
 
549
        {
 
550
                ereport(elevel,
 
551
                                (errcode_for_file_access(),
 
552
                                 errmsg("could not rename file \"%s\" to \"%s\": %m",
 
553
                                                oldfile, newfile)));
 
554
                return -1;
 
555
        }
 
556
#endif
 
557
 
 
558
        /*
 
559
         * Make change persistent in case of an OS crash, both the new entry and
 
560
         * its parent directory need to be flushed.
 
561
         */
 
562
        if (fsync_fname_ext(newfile, false, false, elevel) != 0)
 
563
                return -1;
 
564
 
 
565
        /* Same for parent directory */
 
566
        if (fsync_parent_path(newfile, elevel) != 0)
 
567
                return -1;
 
568
 
 
569
        return 0;
 
570
}
464
571
 
465
572
/*
466
573
 * InitFileAccess --- initialize this module during backend startup
2553
2660
         * in pg_tblspc, they'll get fsync'd twice.  That's not an expected case
2554
2661
         * so we don't worry about optimizing it.
2555
2662
         */
2556
 
        walkdir(".", fsync_fname_ext, false, LOG);
 
2663
        walkdir(".", datadir_fsync_fname, false, LOG);
2557
2664
        if (xlog_is_symlink)
2558
 
                walkdir("pg_xlog", fsync_fname_ext, false, LOG);
2559
 
        walkdir("pg_tblspc", fsync_fname_ext, true, LOG);
 
2665
                walkdir("pg_xlog", datadir_fsync_fname, false, LOG);
 
2666
        walkdir("pg_tblspc", datadir_fsync_fname, true, LOG);
2560
2667
}
2561
2668
 
2562
2669
/*
2670
2777
 
2671
2778
#endif   /* PG_FLUSH_DATA_WORKS */
2672
2779
 
 
2780
static void
 
2781
datadir_fsync_fname(const char *fname, bool isdir, int elevel)
 
2782
{
 
2783
        /*
 
2784
         * We want to silently ignoring errors about unreadable files.  Pass that
 
2785
         * desire on to fsync_fname_ext().
 
2786
         */
 
2787
        fsync_fname_ext(fname, isdir, true, elevel);
 
2788
}
 
2789
 
2673
2790
/*
2674
2791
 * fsync_fname_ext -- Try to fsync a file or directory
2675
2792
 *
2676
 
 * Ignores errors trying to open unreadable files, or trying to fsync
2677
 
 * directories on systems where that isn't allowed/required, and logs other
2678
 
 * errors at a caller-specified level.
 
2793
 * If ignore_perm is true, ignore errors upon trying to open unreadable
 
2794
 * files. Logs other errors at a caller-specified level.
 
2795
 *
 
2796
 * Returns 0 if the operation succeeded, -1 otherwise.
2679
2797
 */
2680
 
static void
2681
 
fsync_fname_ext(const char *fname, bool isdir, int elevel)
 
2798
static int
 
2799
fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel)
2682
2800
{
2683
2801
        int                     fd;
2684
2802
        int                     flags;
2696
2814
        else
2697
2815
                flags |= O_RDONLY;
2698
2816
 
2699
 
        /*
2700
 
         * Open the file, silently ignoring errors about unreadable files (or
2701
 
         * unsupported operations, e.g. opening a directory under Windows), and
2702
 
         * logging others.
2703
 
         */
2704
2817
        fd = OpenTransientFile((char *) fname, flags, 0);
2705
 
        if (fd < 0)
 
2818
 
 
2819
        /*
 
2820
         * Some OSs don't allow us to open directories at all (Windows returns
 
2821
         * EACCES), just ignore the error in that case.  If desired also silently
 
2822
         * ignoring errors about unreadable files. Log others.
 
2823
         */
 
2824
        if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES))
 
2825
                return 0;
 
2826
        else if (fd < 0 && ignore_perm && errno == EACCES)
 
2827
                return 0;
 
2828
        else if (fd < 0)
2706
2829
        {
2707
 
                if (errno == EACCES || (isdir && errno == EISDIR))
2708
 
                        return;
2709
2830
                ereport(elevel,
2710
2831
                                (errcode_for_file_access(),
2711
2832
                                 errmsg("could not open file \"%s\": %m", fname)));
2712
 
                return;
 
2833
                return -1;
2713
2834
        }
2714
2835
 
2715
2836
        returncode = pg_fsync(fd);
2719
2840
         * those errors. Anything else needs to be logged.
2720
2841
         */
2721
2842
        if (returncode != 0 && !(isdir && errno == EBADF))
 
2843
        {
 
2844
                int                     save_errno;
 
2845
 
 
2846
                /* close file upon error, might not be in transaction context */
 
2847
                save_errno = errno;
 
2848
                (void) CloseTransientFile(fd);
 
2849
                errno = save_errno;
 
2850
 
2722
2851
                ereport(elevel,
2723
2852
                                (errcode_for_file_access(),
2724
2853
                                 errmsg("could not fsync file \"%s\": %m", fname)));
 
2854
                return -1;
 
2855
        }
2725
2856
 
2726
2857
        (void) CloseTransientFile(fd);
 
2858
 
 
2859
        return 0;
 
2860
}
 
2861
 
 
2862
/*
 
2863
 * fsync_parent_path -- fsync the parent path of a file or directory
 
2864
 *
 
2865
 * This is aimed at making file operations persistent on disk in case of
 
2866
 * an OS crash or power failure.
 
2867
 */
 
2868
static int
 
2869
fsync_parent_path(const char *fname, int elevel)
 
2870
{
 
2871
        char            parentpath[MAXPGPATH];
 
2872
 
 
2873
        strlcpy(parentpath, fname, MAXPGPATH);
 
2874
        get_parent_directory(parentpath);
 
2875
 
 
2876
        /*
 
2877
         * get_parent_directory() returns an empty string if the input argument is
 
2878
         * just a file name (see comments in path.c), so handle that as being the
 
2879
         * current directory.
 
2880
         */
 
2881
        if (strlen(parentpath) == 0)
 
2882
                strlcpy(parentpath, ".", MAXPGPATH);
 
2883
 
 
2884
        if (fsync_fname_ext(parentpath, true, false, elevel) != 0)
 
2885
                return -1;
 
2886
 
 
2887
        return 0;
2727
2888
}