Skip to content

Commit e0e8040

Browse files
committed
[pgmoneta#883] Replace WAL parser assertion with validation for compressed/encrypted file detection
check the return value of fread add compress and encrypt file before check magic value support directories in interactive and non-interactive modes add pgmoneta prefix Fix missing file argument message in interactive mode remove extra hints from invalid WAL
1 parent 2a55f3c commit e0e8040

3 files changed

Lines changed: 164 additions & 11 deletions

File tree

src/include/walfile/wal_reader.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,15 @@ extern struct server* server_config;
394394

395395
/* Function definitions */
396396

397+
/**
398+
* Validate and extract base WAL filename from path
399+
* @param path The full path to the WAL file
400+
* @param base_filename Output parameter for the base WAL filename
401+
* @return 0 on success, 1 on error
402+
*/
403+
int
404+
pgmoneta_validate_wal_filename(char* path, char** base_filename);
405+
397406
/**
398407
* Parses a WAL file and populates server information.
399408
*

src/libpgmoneta/walfile/wal_reader.c

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,84 @@ read_all_page_headers(FILE* file, struct xlog_long_page_header_data* long_header
184184
return;
185185
}
186186

187+
int
188+
pgmoneta_validate_wal_filename(char* path, char** base_filename)
189+
{
190+
char* wal_filename = NULL;
191+
char* temp = NULL;
192+
timeline_id test_tli = 0;
193+
xlog_seg_no test_logSegNo = 0;
194+
195+
wal_filename = strdup(basename(path));
196+
if (wal_filename == NULL)
197+
{
198+
return 1;
199+
}
200+
201+
if (pgmoneta_ends_with(wal_filename, ".partial"))
202+
{
203+
temp = pgmoneta_remove_suffix(wal_filename, ".partial");
204+
free(wal_filename);
205+
wal_filename = temp;
206+
}
207+
208+
if (pgmoneta_is_encrypted(wal_filename))
209+
{
210+
temp = pgmoneta_remove_suffix(wal_filename, ".aes");
211+
free(wal_filename);
212+
wal_filename = temp;
213+
}
214+
215+
if (pgmoneta_is_compressed(wal_filename))
216+
{
217+
if (pgmoneta_ends_with(wal_filename, ".gz"))
218+
{
219+
temp = pgmoneta_remove_suffix(wal_filename, ".gz");
220+
free(wal_filename);
221+
wal_filename = temp;
222+
}
223+
else if (pgmoneta_ends_with(wal_filename, ".zstd"))
224+
{
225+
temp = pgmoneta_remove_suffix(wal_filename, ".zstd");
226+
free(wal_filename);
227+
wal_filename = temp;
228+
}
229+
else if (pgmoneta_ends_with(wal_filename, ".lz4"))
230+
{
231+
temp = pgmoneta_remove_suffix(wal_filename, ".lz4");
232+
free(wal_filename);
233+
wal_filename = temp;
234+
}
235+
else if (pgmoneta_ends_with(wal_filename, ".bz2"))
236+
{
237+
temp = pgmoneta_remove_suffix(wal_filename, ".bz2");
238+
free(wal_filename);
239+
wal_filename = temp;
240+
}
241+
}
242+
243+
if (xlog_from_file_name(wal_filename, &test_tli, &test_logSegNo, DEFAULT_WAL_SEGZ_BYTES))
244+
{
245+
pgmoneta_log_trace("Invalid WAL file name: %s", path);
246+
free(wal_filename);
247+
return 1;
248+
}
249+
250+
pgmoneta_log_trace("Valid WAL file name: %s (timeline: %u, segment: %lu)",
251+
wal_filename, test_tli, test_logSegNo);
252+
253+
if (base_filename != NULL)
254+
{
255+
*base_filename = wal_filename;
256+
}
257+
else
258+
{
259+
free(wal_filename);
260+
}
261+
262+
return 0;
263+
}
264+
187265
int
188266
pgmoneta_wal_parse_wal_file(char* path, int server, struct walfile* wal_file)
189267
{
@@ -239,6 +317,12 @@ pgmoneta_wal_parse_wal_file(char* path, int server, struct walfile* wal_file)
239317

240318
config = (struct walinfo_configuration*)shmem;
241319

320+
if (pgmoneta_validate_wal_filename(path, NULL))
321+
{
322+
pgmoneta_log_error("Error: Invalid WAL file name: %s", path);
323+
goto error;
324+
}
325+
242326
file = fopen(path, "rb");
243327
if (file == NULL)
244328
{
@@ -260,11 +344,22 @@ pgmoneta_wal_parse_wal_file(char* path, int server, struct walfile* wal_file)
260344
goto error;
261345
}
262346

263-
assert(magic_value_to_postgres_version(long_header->std.xlp_magic) != -1);
347+
int pg_version = magic_value_to_postgres_version(long_header->std.xlp_magic);
348+
349+
if (pg_version == -1)
350+
{
351+
pgmoneta_log_error("Invalid PostgreSQL WAL magic number: 0x%04X in file %s",
352+
long_header->std.xlp_magic, path);
353+
354+
goto error;
355+
}
356+
357+
pgmoneta_log_trace("Valid PostgreSQL WAL magic number: 0x%04X (PostgreSQL %d) in file %s",
358+
long_header->std.xlp_magic, pg_version, path);
264359

265360
if (server == -1)
266361
{
267-
config->common.servers[0].version = magic_value_to_postgres_version(long_header->std.xlp_magic);
362+
config->common.servers[0].version = pg_version;
268363
server_config = &config->common.servers[0];
269364
}
270365
else

src/walinfo.c

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2740,8 +2740,6 @@ main(int argc, char** argv)
27402740
goto error;
27412741
}
27422742

2743-
ui_state.wal_filename = strdup(cwd);
2744-
27452743
show_wal_file_selector(&ui_state);
27462744

27472745
if (ui_state.record_count == 0)
@@ -2763,10 +2761,45 @@ main(int argc, char** argv)
27632761
/* Check if file exists before initializing ncurses */
27642762
if (!pgmoneta_exists(filepath))
27652763
{
2766-
fprintf(stderr, "Error: File <%s> doesn't exist\n", filepath);
2764+
fprintf(stderr, "Error: <%s> doesn't exist\n", filepath);
27672765
goto error;
27682766
}
27692767

2768+
if (pgmoneta_is_directory(filepath))
2769+
{
2770+
if (wal_interactive_init(&ui_state, filepath) != 0)
2771+
{
2772+
fprintf(stderr, "Error: Failed to initialize UI\n");
2773+
goto error;
2774+
}
2775+
2776+
show_wal_file_selector(&ui_state);
2777+
2778+
if (ui_state.record_count == 0)
2779+
{
2780+
wal_interactive_cleanup(&ui_state);
2781+
pgmoneta_destroy_shared_memory(shmem, size);
2782+
if (logfile)
2783+
{
2784+
pgmoneta_stop_logging();
2785+
}
2786+
return 0;
2787+
}
2788+
2789+
wal_interactive_run(&ui_state);
2790+
wal_interactive_cleanup(&ui_state);
2791+
2792+
return 0;
2793+
}
2794+
else
2795+
{
2796+
if (pgmoneta_validate_wal_filename(filepath, NULL) != 0)
2797+
{
2798+
fprintf(stderr, "Error: %s is not a valid WAL file\n", filepath);
2799+
goto error;
2800+
}
2801+
}
2802+
27702803
if (wal_interactive_init(&ui_state, filepath) != 0)
27712804
{
27722805
fprintf(stderr, "Error: Failed to initialize UI\n");
@@ -2801,6 +2834,13 @@ main(int argc, char** argv)
28012834
partial_record->xlog_record_bytes_read = 0;
28022835
partial_record->xlog_record = NULL;
28032836
partial_record->data_buffer = NULL;
2837+
2838+
if (!pgmoneta_exists(filepath))
2839+
{
2840+
fprintf(stderr, "Error: <%s> doesn't exist\n", filepath);
2841+
goto error;
2842+
}
2843+
28042844
if (pgmoneta_is_directory(filepath))
28052845
{
28062846
if (describe_walfiles_in_directory(filepath, type, out, quiet, color,
@@ -2810,13 +2850,22 @@ main(int argc, char** argv)
28102850
goto error;
28112851
}
28122852
}
2813-
2814-
else if (describe_walfile(filepath, type, out, quiet, color,
2815-
rms, start_lsn, end_lsn, xids, limit, summary, included_objects))
2853+
else
28162854
{
2817-
fprintf(stderr, "Error while reading/describing WAL file\n");
2818-
goto error;
2855+
if (pgmoneta_validate_wal_filename(filepath, NULL) != 0)
2856+
{
2857+
fprintf(stderr, "Error: %s is not a valid WAL file\n", filepath);
2858+
goto error;
2859+
}
2860+
2861+
if (describe_walfile(filepath, type, out, quiet, color,
2862+
rms, start_lsn, end_lsn, xids, limit, summary, included_objects))
2863+
{
2864+
fprintf(stderr, "Error while reading/describing WAL file\n");
2865+
goto error;
2866+
}
28192867
}
2868+
28202869
if (partial_record->xlog_record != NULL)
28212870
{
28222871
free(partial_record->xlog_record);
@@ -2828,7 +2877,7 @@ main(int argc, char** argv)
28282877
free(partial_record);
28292878
partial_record = NULL;
28302879
}
2831-
else
2880+
else if (!interactive)
28322881
{
28332882
fprintf(stderr, "Missing <file> argument\n");
28342883
usage();

0 commit comments

Comments
 (0)