https://bugs.openldap.org/show_bug.cgi?id=10562
Issue ID: 10562 Summary: Bug (and one possible fix) for MDB_RDONLY on a writable filesystem Product: LMDB Version: 1.0.1 Hardware: All OS: All Status: UNCONFIRMED Keywords: needs_review Severity: normal Priority: --- Component: liblmdb Assignee: bugs@openldap.org Reporter: dan@shearer.org Target Milestone: ---
Created attachment 1187 --> https://bugs.openldap.org/attachment.cgi?id=1187&action=edit Patch to fix docs in lmdb.h
I found this problem in LumoSQL when following the LMDB documentation.
From the MDB_RDONLY description of mdb_env_open:
"Open the environment in read-only mode. No write operations will be allowed. LMDB will still modify the lock file - except on read-only filesystems, where LMDB does not use locks."
Therefore, on writeable filesystems, MDB_RDONLY will still cause writes to a lockfile. This is a problem when a process wants read-only access to a database it has read permission on, but not write permission, such as unprivileged user reading a root-owned system database on an ordinary writable filesystem.
Because the filesystem is writable, the lock file is opened O_RDWR|O_CREAT. For an unprivileged reader this returns EACCES. mdb_env_setup_locks() only tests for EROFS, so the open fails with EACCES (13).
I suspect the minimal fix is to push the responsibility back onto the user (ie me in this case) and tell them in the documentation to add MDB_NOLOCK if they want read-only access on a writable filesystem. They also have to be very sure that there are no active writers, such as a root process somewhere else. I have attached a documentation patch for this. However, it's pretty harsh on the user because EACCES is a bit inscrutable, and fails the principle of least surprise.
A minimal change to LMDB code would be to return something other than EACCES in this case so that the user is informed about what is happening, and can then decide whether MDB_NOLOCK is safe, or something else.
Apart from that I can't think of what to do, due to safety issues. But this doesn't seem like an uncommon use pattern. I found it in LumoSQL when backing rpm with LMDB, where an unprivileged user can do a query while a root user is doing an update ( https://codeberg.org/LumoSQL/lumosql/src/branch/trunk/examples/rpm ).
Best,
-- Dan Shearer dan@shearer.org / https://shearer.org
https://bugs.openldap.org/show_bug.cgi?id=10562
--- Comment #1 from Dan Shearer dan@shearer.org --- I suppose a complete fix might be to add a new mode, something like MDB_RDONLY_CLIENT. This would not touch the lockfile at all, but unlike all other LMDB reads, it would check every time if a page it has just read could have been recycled and if so, tells the client who can then retry. This could be refined to be more efficient, but in principle it makes this new mode validate all reads. We aren't opening up security holes while also being less surprising.
Could this work?
-- Dan Shearer dan@shearer.org / https://shearer.org
https://bugs.openldap.org/show_bug.cgi?id=10562
Howard Chu hyc@openldap.org changed:
What |Removed |Added ---------------------------------------------------------------------------- Resolution|--- |INVALID Status|UNCONFIRMED |RESOLVED
--- Comment #2 from Howard Chu hyc@openldap.org --- There's no bug here, the behavior is already documented.
MDB_NOLOCK is not safe on a writable DB, but that's already documented as well.
"Open the environment in read-only mode. No write operations will be allowed. LMDB will still modify the lock file - except on read-only filesystems, where LMDB does not use locks."
Therefore, on writeable filesystems, MDB_RDONLY will still cause writes to a lockfile.
Yes, that is precisely what the documentation says.
Because the filesystem is writable, the lock file is opened O_RDWR|O_CREAT. For an unprivileged reader this returns EACCES. mdb_env_setup_locks() only tests for EROFS, so the open fails with EACCES (13).
Yes, EROFS means no changes are possible so it's safe to open the environment. EACCES means the filesystem is writable, so it's unsafe to proceed, which is why the open is failed.
A minimal change to LMDB code would be to return something other than EACCES in this case so that the user is informed about what is happening, and can then decide whether MDB_NOLOCK is safe, or something else.
That's not a decision an arbitrary user can make. Without coordination with any other software that may be using the DB, it is entirely unsafe.
There is no generic fix for this. The solution systems like Postfix uses is to impose their own flocks, so they use MDB_NOLOCK. That works for them because they don't need simultaneous reader+writer access, and every tool of theirs uses the same wrapper code so their locks are always honored.
In short, this is not an LMDB bug to fix, it's entirely the responsibility of the software built on top of it.
https://bugs.openldap.org/show_bug.cgi?id=10562
Quanah Gibson-Mount quanah@openldap.org changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |VERIFIED Keywords|needs_review |