Skip to content

Commit 5095aa7

Browse files
authored
Merge pull request #11138 from rouault/sqlite_gpkg_secure_delete
SQLite/GPKG: turn on SQLite 'PRAGMA secure_delete=1' by default
2 parents c089ee9 + 5e84b2d commit 5095aa7

File tree

4 files changed

+83
-1
lines changed

4 files changed

+83
-1
lines changed

autotest/ogr/ogr_gpkg.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10540,3 +10540,49 @@ def test_gpkg_create_more_than_2000_fields(tmp_vsimem):
1054010540
with pytest.raises(Exception, match="Limit of 2000 columns reached"):
1054110541
lyr.CreateField(ogr.FieldDefn("foo"))
1054210542
assert lyr.GetLayerDefn().GetFieldCount() == 2000 - 2
10543+
10544+
10545+
###############################################################################
10546+
# Test that secure_delete is turned on
10547+
10548+
10549+
@gdaltest.enable_exceptions()
10550+
def test_gpkg_secure_delete(tmp_vsimem):
10551+
10552+
filename = str(tmp_vsimem / "secure_delete.gpkg")
10553+
with ogr.GetDriverByName("GPKG").CreateDataSource(filename) as ds:
10554+
10555+
with ds.ExecuteSQL("PRAGMA secure_delete") as sql_lyr:
10556+
f = sql_lyr.GetNextFeature()
10557+
assert f.GetField(0) == 1
10558+
10559+
lyr = ds.CreateLayer("test")
10560+
lyr.CreateField(ogr.FieldDefn("foo"))
10561+
f = ogr.Feature(lyr.GetLayerDefn())
10562+
f["foo"] = "very_secret"
10563+
lyr.CreateFeature(f)
10564+
10565+
f = gdal.VSIFOpenL(filename, "rb")
10566+
data = gdal.VSIFReadL(1, 100000, f)
10567+
gdal.VSIFCloseL(f)
10568+
assert b"very_secret" in data
10569+
10570+
with ogr.Open(filename, update=1) as ds:
10571+
10572+
with ds.ExecuteSQL("PRAGMA secure_delete") as sql_lyr:
10573+
f = sql_lyr.GetNextFeature()
10574+
assert f.GetField(0) == 1
10575+
10576+
lyr = ds.GetLayer(0)
10577+
lyr.DeleteFeature(1)
10578+
10579+
f = gdal.VSIFOpenL(filename, "rb")
10580+
data = gdal.VSIFReadL(1, 100000, f)
10581+
gdal.VSIFCloseL(f)
10582+
assert b"very_secret" not in data
10583+
10584+
with gdaltest.config_option("OGR_SQLITE_PRAGMA", "secure_delete=0"):
10585+
with ogr.Open(filename, update=1) as ds:
10586+
with ds.ExecuteSQL("PRAGMA secure_delete") as sql_lyr:
10587+
f = sql_lyr.GetNextFeature()
10588+
assert f.GetField(0) == 0

doc/source/drivers/vector/gpkg.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,18 @@ Examples
809809
-sql "SELECT poly.id, other.foo FROM poly JOIN other_schema.other USING (id)" \
810810
-oo PRELUDE_STATEMENTS="ATTACH DATABASE 'other.gpkg' AS other_schema"
811811

812+
Secure deletion
813+
---------------
814+
815+
Depending on how SQLite3 is built, `secure deletion <https://www.sqlite.org/pragma.html#pragma_secure_delete>`__
816+
might or might not be enabled.
817+
Starting with GDAL 3.10, secure deletion is always enabled, unless
818+
``SECURE_DELETE`` is specified through the :config:`OGR_SQLITE_PRAGMA`
819+
configuration option.
820+
Note that secure deletion does not recover potential lost space, so running
821+
a `VACUUM <https://sqlite.org/lang_vacuum.html>`__ query is recommended to fully
822+
optimized a database that has been subject to updates or deletions.
823+
812824
See Also
813825
--------
814826

doc/source/drivers/vector/sqlite.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,17 @@ and optimize it.
556556

557557
ogrinfo db.sqlite -sql "VACUUM"
558558

559+
Secure deletion
560+
---------------
561+
562+
Depending on how SQLite3 is built, `secure deletion <https://www.sqlite.org/pragma.html#pragma_secure_delete>`__
563+
might or might not be enabled.
564+
Starting with GDAL 3.10, secure deletion is always enabled, unless
565+
``SECURE_DELETE`` is specified through the :config:`OGR_SQLITE_PRAGMA`
566+
configuration option.
567+
Note that secure deletion does not recover potential lost space, so running
568+
a `VACUUM <https://sqlite.org/lang_vacuum.html>`__ query is recommended to fully
569+
optimized a database that has been subject to updates or deletions.
559570

560571
Example
561572
-------

ogr/ogrsf_frmts/sqlite/ogrsqlitedatasource.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1372,6 +1372,7 @@ bool OGRSQLiteBaseDataSource::OpenOrCreateDB(int flagsIn,
13721372
#endif
13731373

13741374
bool bPageSizeFound = false;
1375+
bool bSecureDeleteFound = false;
13751376

13761377
const char *pszSqlitePragma =
13771378
CPLGetConfigOption("OGR_SQLITE_PRAGMA", nullptr);
@@ -1456,7 +1457,7 @@ bool OGRSQLiteBaseDataSource::OpenOrCreateDB(int flagsIn,
14561457
{
14571458
if (STARTS_WITH_CI(papszTokens[i], "PAGE_SIZE"))
14581459
bPageSizeFound = true;
1459-
if (STARTS_WITH_CI(papszTokens[i], "JOURNAL_MODE"))
1460+
else if (STARTS_WITH_CI(papszTokens[i], "JOURNAL_MODE"))
14601461
{
14611462
const char *pszEqual = strchr(papszTokens[i], '=');
14621463
if (pszEqual)
@@ -1467,6 +1468,8 @@ bool OGRSQLiteBaseDataSource::OpenOrCreateDB(int flagsIn,
14671468
continue;
14681469
}
14691470
}
1471+
else if (STARTS_WITH_CI(papszTokens[i], "SECURE_DELETE"))
1472+
bSecureDeleteFound = true;
14701473

14711474
const char *pszSQL = CPLSPrintf("PRAGMA %s", papszTokens[i]);
14721475

@@ -1646,6 +1649,16 @@ bool OGRSQLiteBaseDataSource::OpenOrCreateDB(int flagsIn,
16461649
sqlite3_exec(hDB, pszSQL, nullptr, nullptr, nullptr));
16471650
}
16481651

1652+
if (!bSecureDeleteFound)
1653+
{
1654+
// Turn on secure_delete by default (unless the user specifies a
1655+
// value of this pragma through OGR_SQLITE_PRAGMA)
1656+
// For example, Debian and Conda-Forge SQLite3 builds already turn on
1657+
// secure_delete.
1658+
CPL_IGNORE_RET_VAL(sqlite3_exec(hDB, "PRAGMA secure_delete = 1",
1659+
nullptr, nullptr, nullptr));
1660+
}
1661+
16491662
SetCacheSize();
16501663
SetSynchronous();
16511664
if (bLoadExtensions)

0 commit comments

Comments
 (0)