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

« back to all changes in this revision

Viewing changes to contrib/pageinspect/heapfuncs.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * heapfuncs.c
 
4
 *        Functions to investigate heap pages
 
5
 *
 
6
 * We check the input to these functions for corrupt pointers etc. that
 
7
 * might cause crashes, but at the same time we try to print out as much
 
8
 * information as possible, even if it's nonsense. That's because if a
 
9
 * page is corrupt, we don't know why and how exactly it is corrupt, so we
 
10
 * let the user judge it.
 
11
 *
 
12
 * These functions are restricted to superusers for the fear of introducing
 
13
 * security holes if the input checking isn't as water-tight as it should be.
 
14
 * You'd need to be superuser to obtain a raw page image anyway, so
 
15
 * there's hardly any use case for using these without superuser-rights
 
16
 * anyway.
 
17
 *
 
18
 * Copyright (c) 2007-2011, PostgreSQL Global Development Group
 
19
 *
 
20
 * IDENTIFICATION
 
21
 *        contrib/pageinspect/heapfuncs.c
 
22
 *
 
23
 *-------------------------------------------------------------------------
 
24
 */
 
25
 
 
26
#include "postgres.h"
 
27
 
 
28
#include "fmgr.h"
 
29
#include "funcapi.h"
 
30
#include "access/heapam.h"
 
31
#include "access/transam.h"
 
32
#include "catalog/namespace.h"
 
33
#include "catalog/pg_type.h"
 
34
#include "utils/builtins.h"
 
35
#include "miscadmin.h"
 
36
 
 
37
Datum           heap_page_items(PG_FUNCTION_ARGS);
 
38
 
 
39
 
 
40
/*
 
41
 * bits_to_text
 
42
 *
 
43
 * Converts a bits8-array of 'len' bits to a human-readable
 
44
 * c-string representation.
 
45
 */
 
46
static char *
 
47
bits_to_text(bits8 *bits, int len)
 
48
{
 
49
        int                     i;
 
50
        char       *str;
 
51
 
 
52
        str = palloc(len + 1);
 
53
 
 
54
        for (i = 0; i < len; i++)
 
55
                str[i] = (bits[(i / 8)] & (1 << (i % 8))) ? '1' : '0';
 
56
 
 
57
        str[i] = '\0';
 
58
 
 
59
        return str;
 
60
}
 
61
 
 
62
 
 
63
/*
 
64
 * heap_page_items
 
65
 *
 
66
 * Allows inspection of line pointers and tuple headers of a heap page.
 
67
 */
 
68
PG_FUNCTION_INFO_V1(heap_page_items);
 
69
 
 
70
typedef struct heap_page_items_state
 
71
{
 
72
        TupleDesc       tupd;
 
73
        Page            page;
 
74
        uint16          offset;
 
75
} heap_page_items_state;
 
76
 
 
77
Datum
 
78
heap_page_items(PG_FUNCTION_ARGS)
 
79
{
 
80
        bytea      *raw_page = PG_GETARG_BYTEA_P(0);
 
81
        heap_page_items_state *inter_call_data = NULL;
 
82
        FuncCallContext *fctx;
 
83
        int                     raw_page_size;
 
84
 
 
85
        if (!superuser())
 
86
                ereport(ERROR,
 
87
                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
88
                                 (errmsg("must be superuser to use raw page functions"))));
 
89
 
 
90
        raw_page_size = VARSIZE(raw_page) - VARHDRSZ;
 
91
 
 
92
        if (SRF_IS_FIRSTCALL())
 
93
        {
 
94
                TupleDesc       tupdesc;
 
95
                MemoryContext mctx;
 
96
 
 
97
                if (raw_page_size < SizeOfPageHeaderData)
 
98
                        ereport(ERROR,
 
99
                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
100
                                  errmsg("input page too small (%d bytes)", raw_page_size)));
 
101
 
 
102
                fctx = SRF_FIRSTCALL_INIT();
 
103
                mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
 
104
 
 
105
                inter_call_data = palloc(sizeof(heap_page_items_state));
 
106
 
 
107
                /* Build a tuple descriptor for our result type */
 
108
                if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
 
109
                        elog(ERROR, "return type must be a row type");
 
110
 
 
111
                inter_call_data->tupd = tupdesc;
 
112
 
 
113
                inter_call_data->offset = FirstOffsetNumber;
 
114
                inter_call_data->page = VARDATA(raw_page);
 
115
 
 
116
                fctx->max_calls = PageGetMaxOffsetNumber(inter_call_data->page);
 
117
                fctx->user_fctx = inter_call_data;
 
118
 
 
119
                MemoryContextSwitchTo(mctx);
 
120
        }
 
121
 
 
122
        fctx = SRF_PERCALL_SETUP();
 
123
        inter_call_data = fctx->user_fctx;
 
124
 
 
125
        if (fctx->call_cntr < fctx->max_calls)
 
126
        {
 
127
                Page            page = inter_call_data->page;
 
128
                HeapTuple       resultTuple;
 
129
                Datum           result;
 
130
                ItemId          id;
 
131
                Datum           values[13];
 
132
                bool            nulls[13];
 
133
                uint16          lp_offset;
 
134
                uint16          lp_flags;
 
135
                uint16          lp_len;
 
136
 
 
137
                memset(nulls, 0, sizeof(nulls));
 
138
 
 
139
                /* Extract information from the line pointer */
 
140
 
 
141
                id = PageGetItemId(page, inter_call_data->offset);
 
142
 
 
143
                lp_offset = ItemIdGetOffset(id);
 
144
                lp_flags = ItemIdGetFlags(id);
 
145
                lp_len = ItemIdGetLength(id);
 
146
 
 
147
                values[0] = UInt16GetDatum(inter_call_data->offset);
 
148
                values[1] = UInt16GetDatum(lp_offset);
 
149
                values[2] = UInt16GetDatum(lp_flags);
 
150
                values[3] = UInt16GetDatum(lp_len);
 
151
 
 
152
                /*
 
153
                 * We do just enough validity checking to make sure we don't reference
 
154
                 * data outside the page passed to us. The page could be corrupt in
 
155
                 * many other ways, but at least we won't crash.
 
156
                 */
 
157
                if (ItemIdHasStorage(id) &&
 
158
                        lp_len >= sizeof(HeapTupleHeader) &&
 
159
                        lp_offset == MAXALIGN(lp_offset) &&
 
160
                        lp_offset + lp_len <= raw_page_size)
 
161
                {
 
162
                        HeapTupleHeader tuphdr;
 
163
                        int                     bits_len;
 
164
 
 
165
                        /* Extract information from the tuple header */
 
166
 
 
167
                        tuphdr = (HeapTupleHeader) PageGetItem(page, id);
 
168
 
 
169
                        values[4] = UInt32GetDatum(HeapTupleHeaderGetXmin(tuphdr));
 
170
                        values[5] = UInt32GetDatum(HeapTupleHeaderGetXmax(tuphdr));
 
171
                        values[6] = UInt32GetDatum(HeapTupleHeaderGetRawCommandId(tuphdr)); /* shared with xvac */
 
172
                        values[7] = PointerGetDatum(&tuphdr->t_ctid);
 
173
                        values[8] = UInt32GetDatum(tuphdr->t_infomask2);
 
174
                        values[9] = UInt32GetDatum(tuphdr->t_infomask);
 
175
                        values[10] = UInt8GetDatum(tuphdr->t_hoff);
 
176
 
 
177
                        /*
 
178
                         * We already checked that the item as is completely within the
 
179
                         * raw page passed to us, with the length given in the line
 
180
                         * pointer.. Let's check that t_hoff doesn't point over lp_len,
 
181
                         * before using it to access t_bits and oid.
 
182
                         */
 
183
                        if (tuphdr->t_hoff >= sizeof(HeapTupleHeader) &&
 
184
                                tuphdr->t_hoff <= lp_len)
 
185
                        {
 
186
                                if (tuphdr->t_infomask & HEAP_HASNULL)
 
187
                                {
 
188
                                        bits_len = tuphdr->t_hoff -
 
189
                                                (((char *) tuphdr->t_bits) -((char *) tuphdr));
 
190
 
 
191
                                        values[11] = CStringGetTextDatum(
 
192
                                                                 bits_to_text(tuphdr->t_bits, bits_len * 8));
 
193
                                }
 
194
                                else
 
195
                                        nulls[11] = true;
 
196
 
 
197
                                if (tuphdr->t_infomask & HEAP_HASOID)
 
198
                                        values[12] = HeapTupleHeaderGetOid(tuphdr);
 
199
                                else
 
200
                                        nulls[12] = true;
 
201
                        }
 
202
                        else
 
203
                        {
 
204
                                nulls[11] = true;
 
205
                                nulls[12] = true;
 
206
                        }
 
207
                }
 
208
                else
 
209
                {
 
210
                        /*
 
211
                         * The line pointer is not used, or it's invalid. Set the rest of
 
212
                         * the fields to NULL
 
213
                         */
 
214
                        int                     i;
 
215
 
 
216
                        for (i = 4; i <= 12; i++)
 
217
                                nulls[i] = true;
 
218
                }
 
219
 
 
220
                /* Build and return the result tuple. */
 
221
                resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls);
 
222
                result = HeapTupleGetDatum(resultTuple);
 
223
 
 
224
                inter_call_data->offset++;
 
225
 
 
226
                SRF_RETURN_NEXT(fctx, result);
 
227
        }
 
228
        else
 
229
                SRF_RETURN_DONE(fctx);
 
230
}