Re: Extension security improvement: Add support for extensions with an owned schema - Mailing list pgsql-hackers

From Rui Zhao
Subject Re: Extension security improvement: Add support for extensions with an owned schema
Date
Msg-id CAHWVJhERrZ0df6L8GaOL9RMi8+oTm=H0STa-XL-iD2pjjqPcfw@mail.gmail.com
Whole thread
In response to Re: Extension security improvement: Add support for extensions with an owned schema  ("Jelte Fennema-Nio" <postgres@jeltef.nl>)
List pgsql-hackers
Hi Jelte,

1. There is another dependency cycle reachable through CREATE EXTENSION
... SCHEMA ... CASCADE. Unlike the earlier two-object cycle, this one
produces a dump that fails to restore. A same-version pg_upgrade
completes but loses the prerequisite-extension dependency.

On v12 over 3c5d9d914fa, I used these SQL-only extensions:

os_base.control:
    default_version = '1.0'
    relocatable = true
    superuser = false

os_owned.control:
    default_version = '1.0'
    relocatable = true
    superuser = false
    owned_schema = true
    requires = 'os_base'

os_base--1.0.sql:
    CREATE FUNCTION os_base_value() RETURNS integer
    LANGUAGE SQL AS 'SELECT 1';

os_owned--1.0.sql:
    CREATE FUNCTION os_owned_value() RETURNS integer
    LANGUAGE SQL AS 'SELECT 1';

In a fresh database, this succeeds:

CREATE EXTENSION os_owned SCHEMA shared_schema CASCADE;

Both extensions end up in shared_schema. pg_depend then contains the
following cycle, where each arrow means "depends on":

    os_owned -> os_base -> shared_schema -> os_owned

In v12, getDependencies() already skips the direct dependency from
os_owned to shared_schema when ordering the dump. However, the longer
cycle above remains. Plain and directory dumps both warn:

pg_dump: warning: could not resolve dependency loop among these items:
pg_dump: detail: EXTENSION os_owned  (ID 2 OID 16389)
pg_dump: detail: EXTENSION os_base  (ID 3 OID 16387)
pg_dump: detail: SCHEMA shared_schema  (ID 9 OID 16386)

The plain dump and the SQL generated by pg_restore from the directory
archive contain these extension commands in this order:

CREATE EXTENSION IF NOT EXISTS os_owned WITH SCHEMA shared_schema;
CREATE EXTENSION IF NOT EXISTS os_base WITH SCHEMA shared_schema;

The first command requires os_base to be installed already, but it has
no CASCADE to install it. Plain restore with ON_ERROR_STOP and directory
restore with --exit-on-error --jobs=2 therefore fail at that command:

ERROR:  required extension "os_base" is not installed

However, pg_upgrade reports success but loses os_owned's dependency
on os_base.

I used the v12 build for both the old and new clusters. Before the
upgrade, pg_depend recorded that os_owned depends on os_base.
Both extensions still existed after the upgrade, but pg_depend
no longer recorded that os_owned depends on os_base.

Two possible approaches are:

a) Reject cross-extension dependency cycles involving an owned schema.
   Check CREATE EXTENSION, ALTER EXTENSION UPDATE and SET SCHEMA,
   including indirect dependencies. For this case, the error could
   suggest installing os_base in another schema first.

b) Support this layout in dump/restore and binary upgrade. Adding
   CASCADE to normal CREATE EXTENSION output might address ordinary
   restore, but binary upgrade needs its own handling, without running
   extension installation scripts or dropping prerequisite dependencies.

I'd prefer (b). It preserves the existing schema-placement rules and
keeps the reconstruction logic in the dump/upgrade path. Option (a)
would need checks across several DDL paths, including concurrent
changes, to avoid admitting the same cycle another way.
Binary upgrade still needs to preserve the original extension
dependencies, independently of any changes made for dump ordering.

2. In doc/src/sgml/ref/alter_extension.sgml:

> This form moves the extension's objects into another schema.

Could we replace that paragraph with:

    For an extension without an owned schema, this form moves its
    objects to an existing schema. If the extension owns its schema,
    this form instead renames that schema to new_schema, which must
    not already exist unless it is the current name. The extension
    must be relocatable.

3. In doc/src/sgml/catalogs.sgml, the pg_extension section is missing
extownedschema. Could we add the boolean column, for example with:

    True if the extension creates and owns the schema identified by
    extnamespace.

Regards,
Rui



pgsql-hackers by date:

Previous
From: Isaac Morland
Date:
Subject: Re: Logical Implication
Next
From: Tomas Vondra
Date:
Subject: Re: hashjoins vs. Bloom filters (yet again)