I added Noah in CC.

On Fri, Sep 11, 2026 at 12:46 AM Corey Huinker <[email protected]> wrote:
> On Thu, Sep 10, 2026 at 11:02 AM Etsuro Fujita <[email protected]> 
> wrote:
>> On Thu, Sep 10, 2026 at 3:59 PM Fujii Masao <[email protected]> wrote:
>> > postgres_fdw stats import seems to have several potential issues.
>>
>> > (1) User-defined functions may be executed with unexpected privileges
>> >
>> > ANALYZE on a foreign table with import_stats disabled invokes
>> > user-defined functions (e.g., domain constraints) as the foreign table's
>> > owner. But, with import_stats enabled, they are invoked as the user
>> > running ANALYZE. So, if that user is a superuser, those functions would
>> > be run with superuser privileges. Could this be a security issue?
>>
>> Sorry, I don't follow this.  Could you elaborate on it using an example?
>
> Me either. I think he's referring to generated columns, in which case the 
> generated column wouldn't have a corresponding source column, hence would 
> fail match_attrmap() and already falls back to sampling.

Here is an example provided by Noah, which doesn't involve
user-defined functions, but causes a security issue:

CREATE SERVER loopback FOREIGN DATA WRAPPER postgres_fdw OPTIONS
(dbname 'postgres');
CREATE USER MAPPING FOR CURRENT_USER SERVER loopback;
DROP ROLE IF EXISTS regress_ftowner;
CREATE ROLE regress_ftowner NOSUPERUSER;
GRANT USAGE ON FOREIGN SERVER loopback TO regress_ftowner;
GRANT CREATE ON SCHEMA public TO regress_ftowner;
CREATE TABLE secret (s text);
REVOKE ALL ON secret FROM PUBLIC;
INSERT INTO secret SELECT 'hunter2' FROM generate_series(1, 10);
ANALYZE secret;
SET ROLE regress_ftowner;
CREATE FOREIGN TABLE ft_secret (s text) SERVER loopback
    OPTIONS (table_name 'secret', import_stats 'true');

-- the owner can neither read secret nor reach the remote server
SELECT * FROM ft_secret;
ERROR:  user mapping not found for user "regress_ftowner", server "loopback"

-- which is good, BUT import_stats discloses data the owner cannot read
RESET ROLE;
ANALYZE ft_secret;
SET ROLE regress_ftowner;
SELECT most_common_vals FROM pg_stats WHERE tablename = 'ft_secret';
 most_common_vals
------------------
 {hunter2}
(1 row)

He provided a fix for this as well, which I'm attaching.  The fix
addresses it by switching the userid to the foreign-table owner's
userid in analyze.c before calling ImportForeignStatistics().  I think
the fix is also reasonable in that it makes the identity handling
consistent between the sampling/import methods.  So I will push and
back-patch the fix if no objections from others.

Best regards,
Etsuro Fujita

Attachment: fix-stats-import-priv-handling.patch
Description: Binary data

Reply via email to