~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/backend/access/nbtree/nbtxlog.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2013-02-05 18:13:52 UTC
  • mfrom: (1.1.10) (10.1.5 oneiric-proposed)
  • Revision ID: package-import@ubuntu.com-20130205181352-3kw4f94ilqklzm7c
Tags: 9.1.8-0ubuntu11.10
* New upstream security/bug fix release: (LP: #1116336)
  - Prevent execution of enum_recv from SQL
    The function was misdeclared, allowing a simple SQL command to crash the
    server.  In principle an attacker might be able to use it to examine the
    contents of server memory.  Our thanks to Sumit Soni (via Secunia SVCRP)
    for reporting this issue. (CVE-2013-0255)
  - See HISTORY/changelog.gz for the other bug fixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
220
220
                datalen -= sizeof(xl_btree_metadata);
221
221
        }
222
222
 
223
 
        if ((record->xl_info & XLR_BKP_BLOCK_1) && !ismeta && isleaf)
224
 
                return;                                 /* nothing to do */
225
 
 
226
 
        if (!(record->xl_info & XLR_BKP_BLOCK_1))
 
223
        if (record->xl_info & XLR_BKP_BLOCK(0))
 
224
                (void) RestoreBackupBlock(lsn, record, 0, false, false);
 
225
        else
227
226
        {
228
227
                buffer = XLogReadBuffer(xlrec->target.node,
229
228
                                                         ItemPointerGetBlockNumber(&(xlrec->target.tid)),
251
250
                }
252
251
        }
253
252
 
 
253
        /*
 
254
         * Note: in normal operation, we'd update the metapage while still holding
 
255
         * lock on the page we inserted into.  But during replay it's not
 
256
         * necessary to hold that lock, since no other index updates can be
 
257
         * happening concurrently, and readers will cope fine with following an
 
258
         * obsolete link from the metapage.
 
259
         */
254
260
        if (ismeta)
255
261
                _bt_restore_meta(xlrec->target.node, lsn,
256
262
                                                 md.root, md.level,
292
298
                forget_matching_split(xlrec->node, downlink, false);
293
299
 
294
300
                /* Extract left hikey and its size (still assuming 16-bit alignment) */
295
 
                if (!(record->xl_info & XLR_BKP_BLOCK_1))
 
301
                if (!(record->xl_info & XLR_BKP_BLOCK(0)))
296
302
                {
297
303
                        /* We assume 16-bit alignment is enough for IndexTupleSize */
298
304
                        left_hikey = (Item) datapos;
312
318
                datalen -= sizeof(OffsetNumber);
313
319
        }
314
320
 
315
 
        if (onleft && !(record->xl_info & XLR_BKP_BLOCK_1))
 
321
        if (onleft && !(record->xl_info & XLR_BKP_BLOCK(0)))
316
322
        {
317
323
                /*
318
324
                 * We assume that 16-bit alignment is enough to apply IndexTupleSize
325
331
                datalen -= newitemsz;
326
332
        }
327
333
 
328
 
        /* Reconstruct right (new) sibling from scratch */
 
334
        /* Reconstruct right (new) sibling page from scratch */
329
335
        rbuf = XLogReadBuffer(xlrec->node, xlrec->rightsib, true);
330
336
        Assert(BufferIsValid(rbuf));
331
337
        rpage = (Page) BufferGetPage(rbuf);
359
365
 
360
366
        /* don't release the buffer yet; we touch right page's first item below */
361
367
 
362
 
        /*
363
 
         * Reconstruct left (original) sibling if needed.  Note that this code
364
 
         * ensures that the items remaining on the left page are in the correct
365
 
         * item number order, but it does not reproduce the physical order they
366
 
         * would have had.      Is this worth changing?  See also _bt_restore_page().
367
 
         */
368
 
        if (!(record->xl_info & XLR_BKP_BLOCK_1))
 
368
        /* Now reconstruct left (original) sibling page */
 
369
        if (record->xl_info & XLR_BKP_BLOCK(0))
 
370
                (void) RestoreBackupBlock(lsn, record, 0, false, false);
 
371
        else
369
372
        {
370
373
                Buffer          lbuf = XLogReadBuffer(xlrec->node, xlrec->leftsib, false);
371
374
 
372
375
                if (BufferIsValid(lbuf))
373
376
                {
 
377
                        /*
 
378
                         * Note that this code ensures that the items remaining on the
 
379
                         * left page are in the correct item number order, but it does not
 
380
                         * reproduce the physical order they would have had.  Is this
 
381
                         * worth changing?  See also _bt_restore_page().
 
382
                         */
374
383
                        Page            lpage = (Page) BufferGetPage(lbuf);
375
384
                        BTPageOpaque lopaque = (BTPageOpaque) PageGetSpecialPointer(lpage);
376
385
 
434
443
        /* We no longer need the right buffer */
435
444
        UnlockReleaseBuffer(rbuf);
436
445
 
437
 
        /* Fix left-link of the page to the right of the new right sibling */
438
 
        if (xlrec->rnext != P_NONE && !(record->xl_info & XLR_BKP_BLOCK_2))
 
446
        /*
 
447
         * Fix left-link of the page to the right of the new right sibling.
 
448
         *
 
449
         * Note: in normal operation, we do this while still holding lock on the
 
450
         * two split pages.  However, that's not necessary for correctness in WAL
 
451
         * replay, because no other index update can be in progress, and readers
 
452
         * will cope properly when following an obsolete left-link.
 
453
         */
 
454
        if (record->xl_info & XLR_BKP_BLOCK(1))
 
455
                (void) RestoreBackupBlock(lsn, record, 1, false, false);
 
456
        else if (xlrec->rnext != P_NONE)
439
457
        {
440
458
                Buffer          buffer = XLogReadBuffer(xlrec->node, xlrec->rnext, false);
441
459
 
465
483
static void
466
484
btree_xlog_vacuum(XLogRecPtr lsn, XLogRecord *record)
467
485
{
468
 
        xl_btree_vacuum *xlrec;
 
486
        xl_btree_vacuum *xlrec = (xl_btree_vacuum *) XLogRecGetData(record);
469
487
        Buffer          buffer;
470
488
        Page            page;
471
489
        BTPageOpaque opaque;
472
490
 
473
 
        xlrec = (xl_btree_vacuum *) XLogRecGetData(record);
474
 
 
475
491
        /*
476
492
         * If queries might be active then we need to ensure every block is
477
493
         * unpinned between the lastBlockVacuumed and the current block, if there
504
520
        }
505
521
 
506
522
        /*
507
 
         * If the block was restored from a full page image, nothing more to do.
508
 
         * The RestoreBkpBlocks() call already pinned and took cleanup lock on it.
509
 
         * XXX: Perhaps we should call RestoreBkpBlocks() *after* the loop above,
510
 
         * to make the disk access more sequential.
 
523
         * If we have a full-page image, restore it (using a cleanup lock) and
 
524
         * we're done.
511
525
         */
512
 
        if (record->xl_info & XLR_BKP_BLOCK_1)
 
526
        if (record->xl_info & XLR_BKP_BLOCK(0))
 
527
        {
 
528
                (void) RestoreBackupBlock(lsn, record, 0, true, false);
513
529
                return;
 
530
        }
514
531
 
515
532
        /*
516
533
         * Like in btvacuumpage(), we need to take a cleanup lock on every leaf
565
582
 * XXX optimise later with something like XLogPrefetchBuffer()
566
583
 */
567
584
static TransactionId
568
 
btree_xlog_delete_get_latestRemovedXid(XLogRecord *record)
 
585
btree_xlog_delete_get_latestRemovedXid(xl_btree_delete *xlrec)
569
586
{
570
 
        xl_btree_delete *xlrec = (xl_btree_delete *) XLogRecGetData(record);
571
587
        OffsetNumber *unused;
572
588
        Buffer          ibuffer,
573
589
                                hbuffer;
687
703
static void
688
704
btree_xlog_delete(XLogRecPtr lsn, XLogRecord *record)
689
705
{
690
 
        xl_btree_delete *xlrec;
 
706
        xl_btree_delete *xlrec = (xl_btree_delete *) XLogRecGetData(record);
691
707
        Buffer          buffer;
692
708
        Page            page;
693
709
        BTPageOpaque opaque;
694
710
 
695
 
        if (record->xl_info & XLR_BKP_BLOCK_1)
 
711
        /*
 
712
         * If we have any conflict processing to do, it must happen before we
 
713
         * update the page.
 
714
         *
 
715
         * Btree delete records can conflict with standby queries.  You might
 
716
         * think that vacuum records would conflict as well, but we've handled
 
717
         * that already.  XLOG_HEAP2_CLEANUP_INFO records provide the highest xid
 
718
         * cleaned by the vacuum of the heap and so we can resolve any conflicts
 
719
         * just once when that arrives.  After that we know that no conflicts
 
720
         * exist from individual btree vacuum records on that index.
 
721
         */
 
722
        if (InHotStandby)
 
723
        {
 
724
                TransactionId latestRemovedXid = btree_xlog_delete_get_latestRemovedXid(xlrec);
 
725
 
 
726
                ResolveRecoveryConflictWithSnapshot(latestRemovedXid, xlrec->node);
 
727
        }
 
728
 
 
729
        /* If we have a full-page image, restore it and we're done */
 
730
        if (record->xl_info & XLR_BKP_BLOCK(0))
 
731
        {
 
732
                (void) RestoreBackupBlock(lsn, record, 0, false, false);
696
733
                return;
697
 
 
698
 
        xlrec = (xl_btree_delete *) XLogRecGetData(record);
 
734
        }
699
735
 
700
736
        /*
701
737
         * We don't need to take a cleanup lock to apply these changes. See
751
787
        leftsib = xlrec->leftblk;
752
788
        rightsib = xlrec->rightblk;
753
789
 
 
790
        /*
 
791
         * In normal operation, we would lock all the pages this WAL record
 
792
         * touches before changing any of them.  In WAL replay, it should be okay
 
793
         * to lock just one page at a time, since no concurrent index updates can
 
794
         * be happening, and readers should not care whether they arrive at the
 
795
         * target page or not (since it's surely empty).
 
796
         */
 
797
 
754
798
        /* parent page */
755
 
        if (!(record->xl_info & XLR_BKP_BLOCK_1))
 
799
        if (record->xl_info & XLR_BKP_BLOCK(0))
 
800
                (void) RestoreBackupBlock(lsn, record, 0, false, false);
 
801
        else
756
802
        {
757
803
                buffer = XLogReadBuffer(xlrec->target.node, parent, false);
758
804
                if (BufferIsValid(buffer))
798
844
        }
799
845
 
800
846
        /* Fix left-link of right sibling */
801
 
        if (!(record->xl_info & XLR_BKP_BLOCK_2))
 
847
        if (record->xl_info & XLR_BKP_BLOCK(1))
 
848
                (void) RestoreBackupBlock(lsn, record, 1, false, false);
 
849
        else
802
850
        {
803
851
                buffer = XLogReadBuffer(xlrec->target.node, rightsib, false);
804
852
                if (BufferIsValid(buffer))
822
870
        }
823
871
 
824
872
        /* Fix right-link of left sibling, if any */
825
 
        if (!(record->xl_info & XLR_BKP_BLOCK_3))
 
873
        if (record->xl_info & XLR_BKP_BLOCK(2))
 
874
                (void) RestoreBackupBlock(lsn, record, 2, false, false);
 
875
        else
826
876
        {
827
877
                if (leftsib != P_NONE)
828
878
                {
896
946
        BTPageOpaque pageop;
897
947
        BlockNumber downlink = 0;
898
948
 
 
949
        /* Backup blocks are not used in newroot records */
 
950
        Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
 
951
 
899
952
        buffer = XLogReadBuffer(xlrec->node, xlrec->rootblk, true);
900
953
        Assert(BufferIsValid(buffer));
901
954
        page = (Page) BufferGetPage(buffer);
937
990
                forget_matching_split(xlrec->node, downlink, true);
938
991
}
939
992
 
 
993
static void
 
994
btree_xlog_reuse_page(XLogRecPtr lsn, XLogRecord *record)
 
995
{
 
996
        xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) XLogRecGetData(record);
 
997
 
 
998
        /*
 
999
         * Btree reuse_page records exist to provide a conflict point when we
 
1000
         * reuse pages in the index via the FSM.  That's all they do though.
 
1001
         *
 
1002
         * latestRemovedXid was the page's btpo.xact.  The btpo.xact <
 
1003
         * RecentGlobalXmin test in _bt_page_recyclable() conceptually mirrors the
 
1004
         * pgxact->xmin > limitXmin test in GetConflictingVirtualXIDs().
 
1005
         * Consequently, one XID value achieves the same exclusion effect on
 
1006
         * master and standby.
 
1007
         */
 
1008
        if (InHotStandby)
 
1009
        {
 
1010
                ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid,
 
1011
                                                                                        xlrec->node);
 
1012
        }
 
1013
 
 
1014
        /* Backup blocks are not used in reuse_page records */
 
1015
        Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));
 
1016
}
 
1017
 
940
1018
 
941
1019
void
942
1020
btree_redo(XLogRecPtr lsn, XLogRecord *record)
943
1021
{
944
1022
        uint8           info = record->xl_info & ~XLR_INFO_MASK;
945
1023
 
946
 
        if (InHotStandby)
947
 
        {
948
 
                switch (info)
949
 
                {
950
 
                        case XLOG_BTREE_DELETE:
951
 
 
952
 
                                /*
953
 
                                 * Btree delete records can conflict with standby queries. You
954
 
                                 * might think that vacuum records would conflict as well, but
955
 
                                 * we've handled that already. XLOG_HEAP2_CLEANUP_INFO records
956
 
                                 * provide the highest xid cleaned by the vacuum of the heap
957
 
                                 * and so we can resolve any conflicts just once when that
958
 
                                 * arrives. After that any we know that no conflicts exist
959
 
                                 * from individual btree vacuum records on that index.
960
 
                                 */
961
 
                                {
962
 
                                        TransactionId latestRemovedXid = btree_xlog_delete_get_latestRemovedXid(record);
963
 
                                        xl_btree_delete *xlrec = (xl_btree_delete *) XLogRecGetData(record);
964
 
 
965
 
                                        ResolveRecoveryConflictWithSnapshot(latestRemovedXid, xlrec->node);
966
 
                                }
967
 
                                break;
968
 
 
969
 
                        case XLOG_BTREE_REUSE_PAGE:
970
 
 
971
 
                                /*
972
 
                                 * Btree reuse page records exist to provide a conflict point
973
 
                                 * when we reuse pages in the index via the FSM. That's all it
974
 
                                 * does though. latestRemovedXid was the page's btpo.xact. The
975
 
                                 * btpo.xact < RecentGlobalXmin test in _bt_page_recyclable()
976
 
                                 * conceptually mirrors the pgxact->xmin > limitXmin test in
977
 
                                 * GetConflictingVirtualXIDs().  Consequently, one XID value
978
 
                                 * achieves the same exclusion effect on master and standby.
979
 
                                 */
980
 
                                {
981
 
                                        xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) XLogRecGetData(record);
982
 
 
983
 
                                        ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid, xlrec->node);
984
 
                                }
985
 
                                return;
986
 
 
987
 
                        default:
988
 
                                break;
989
 
                }
990
 
        }
991
 
 
992
 
        /*
993
 
         * Vacuum needs to pin and take cleanup lock on every leaf page, a regular
994
 
         * exclusive lock is enough for all other purposes.
995
 
         */
996
 
        RestoreBkpBlocks(lsn, record, (info == XLOG_BTREE_VACUUM));
997
 
 
998
1024
        switch (info)
999
1025
        {
1000
1026
                case XLOG_BTREE_INSERT_LEAF:
1033
1059
                        btree_xlog_newroot(lsn, record);
1034
1060
                        break;
1035
1061
                case XLOG_BTREE_REUSE_PAGE:
1036
 
                        /* Handled above before restoring bkp block */
 
1062
                        btree_xlog_reuse_page(lsn, record);
1037
1063
                        break;
1038
1064
                default:
1039
1065
                        elog(PANIC, "btree_redo: unknown op code %u", info);