Skip to content

Commit b4833f4

Browse files
committed
Validate external file path at metadata load time
External tables store the file path in RDB$EXTERNAL_FILE at CREATE TABLE time without any check against the ExternalFileAccess policy. The path was validated only later, when the table was actually opened, so a table pointing outside the allowed directories could be created and the malicious path remained in metadata. Move the validation into a shared checkExternalFileAccess() helper and call it both when the relation metadata is loaded (met.epp) and when the external file is opened (ExternalFile::open). Paths escaping the configured directory list are now rejected at CREATE TABLE time with isc_conf_access_denied, and existing databases with such tables fail on first access instead of silently carrying the bad path.
1 parent f0b0d0c commit b4833f4

3 files changed

Lines changed: 28 additions & 7 deletions

File tree

src/jrd/ext.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,27 @@ namespace Jrd
115115

116116
using namespace Jrd;
117117

118+
namespace Jrd {
119+
120+
// Validate that an external file path is allowed by the configured
121+
// ExternalFileAccess policy. Raises isc_conf_access_denied otherwise.
122+
// Used at metadata load time (met.epp) and at file open time so that
123+
// paths escaping the allowed directory list are rejected consistently,
124+
// regardless of whether the external table was just created or loaded
125+
// from an existing database.
126+
void checkExternalFileAccess(Database* dbb, const Firebird::PathName& fileName)
127+
{
128+
ExternalFileDirectoryList::create(dbb);
129+
130+
if (!dbb->dbb_external_file_directory_list->isPathInList(fileName))
131+
{
132+
ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("external file") <<
133+
Arg::Str(fileName.c_str()));
134+
}
135+
}
136+
137+
} // namespace Jrd
138+
118139
namespace {
119140

120141
#ifdef WIN_NT
@@ -131,13 +152,7 @@ void ExternalFile::open(Database* dbb)
131152
{
132153
fb_assert(ext_sync.locked());
133154

134-
ExternalFileDirectoryList::create(dbb);
135-
136-
if (!dbb->dbb_external_file_directory_list->isPathInList(ext_filename))
137-
{
138-
ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("external file") <<
139-
Arg::Str(ext_filename));
140-
}
155+
checkExternalFileAccess(dbb, Firebird::PathName(static_cast<const char*>(ext_filename)));
141156

142157
// If the database is updateable then try opening the external files in RW mode.
143158
ext_flags = 0;

src/jrd/ext_proto.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "fb_blk.h"
2828
#include "../common/classes/alloc.h"
2929
#include "../common/classes/locks.h"
30+
#include "../common/classes/fb_string.h"
3031

3132
#ifndef JRD_EXT_PROTO_H
3233
#define JRD_EXT_PROTO_H
@@ -43,6 +44,10 @@ class thread_db;
4344

4445
// External file access block
4546

47+
// Validate external file path against ExternalFileAccess policy,
48+
// raise isc_conf_access_denied if not allowed.
49+
void checkExternalFileAccess(Database* dbb, const Firebird::PathName& fileName);
50+
4651
class ExternalFile : public pool_alloc_rpt<SCHAR, type_ext>
4752
{
4853
private:

src/jrd/met.epp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3310,6 +3310,7 @@ ScanResult jrd_rel::scan(thread_db* tdbb, ObjectBase::Flag& flags)
33103310

33113311
if (REL.RDB$EXTERNAL_FILE[0] && !rel_perm->getExtFile())
33123312
{
3313+
checkExternalFileAccess(tdbb->getDatabase(), REL.RDB$EXTERNAL_FILE);
33133314
rel_perm->setExtFile(ExternalFile::create(getPool(), REL.RDB$EXTERNAL_FILE));
33143315
}
33153316

0 commit comments

Comments
 (0)