Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Making DBI with SQLite3 truly read-only

by mldvx4 (Hermit)
on Nov 04, 2025 at 14:25 UTC ( [id://11166644]=perlquestion: print w/replies, xml ) Need Help??

mldvx4 has asked for the wisdom of the Perl Monks concerning the following question:

Greetings, wise monks,

I am trying to crank down restrictions on an FCGI script. I have DBI opening an SQLite3 database as read-only. This is how I am currently connecting to the database:

my $dbh = DBI->connect("dbi:SQLite:dbname=$database", undef, undef, { AutoCommit => 0, RaiseError => 1, on_connect_do => "PRAGMA foreign_keys = ON", sqlite_open_flags => "DBD::SQLite::OPEN_READONLY", }) or die("Could not open database '$database': $!\n");

However, AppArmor still gives the following error about needing write access, even though the error and restrictions causing it do not impair the script from appearing to work as expected:

2025-11-04T14:02:51.130580+00:00 ID28399 kernel: [5084204.347595] audi +t: type=1400 audit(1762264971.124:63): apparmor="DENIED" operation="o +pen" profile="/var/www/fcgi/foo.fcgi" name="/var/www/db/foo.sqlite3" +pid=377569 comm="search.fcgi" requested_mask="wc" denied_mask="wc" fs +uid=1002 ouid=1002

and in the AppArmor profile:

/var/www/db/foo.sqlite3 kr,

If I add w to that, the errors go away. However, I don't want to do that because the script's access is supposed to remain read-only. Yet it appears that DBI is somehow still requesting some kind of write access, even if it does not use it. What can I change in the DBI connection to ensure that it is purely read-only as far as the database goes?

Replies are listed 'Best First'.
Re: Making DBI with SQLite3 truly read-only
by Anonymous Monk on Nov 04, 2025 at 15:28 UTC
    sqlite_open_flags => "DBD::SQLite::OPEN_READONLY",
    You're passing a string to sqlite_open_flags, while the documented way is an exported constant:
    use DBD::SQLite::Constants qw/:file_open/; my $dbh = DBI->connect("dbi:SQLite:$dbfile", undef, undef, { sqlite_open_flags => SQLITE_OPEN_READONLY, });
    Experiment shows that it's currently 1, but we shouldn't be relying on that value. Following the documented way, I see DBD::SQLite trying to open the file read-only:
    $ strace -e trace=%file perl -MDBI -MDBD::SQLite::Constants=:file_open + -E' DBI->connect("dbi:SQLite:foo.sqlite", undef, undef, { sqlite_open_flags => SQLITE_OPEN_READONLY }); ' <...> openat(AT_FDCWD, "REDACTED/foo.sqlite", O_RDONLY|O_NOFOLLOW|O_CLOEXEC) + <...>

      The following should also do the trick if you don't want to import constants you don't use:

      use DBD::SQLite::Constants qw( SQLITE_OPEN_READONLY );

      Thanks. All set. Somehow I missed the use DBD::SQLite::Constants qw/:file_open/; part of the documentation, that led to a series of errors. With that in place, I can now use the constant as I am supposed to and the database is indeed read only at that point!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11166644]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2025-11-12 11:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    What's your view on AI coding assistants?





    Results (68 votes). Check out past polls.

    Notices?
    hippoepoptai's answer Re: how do I set a cookie and redirect was blessed by hippo!
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.