I'm unsure what the threat and security model of SQLite's authorizer
callback is. I think it would only be an effective authorization
mechanism if the attacker was able to only execute SQL statements on a
database and the database was otherwise not accessible to the attacker.
So I'm not sure whether the following behaviour should be seen as a
vulnerability. Nonetheless, I wanted to point out SQLite's behaviour and
document it.

One of the parameters of the authorizer is the name of the database of
the operation that is to be authorized. The documentation gives you the
impression that "main" and "temp" are two reserved database names and
cannot be changed. However, the name of the main database can be changed
by sqlite3_db_config. So if the name of the main database is relevant to
the authorizer, it must be impossible to change it through
sqlite3_db_config (in the context of the application). The following
code demonstrates the "problem":

#include <assert.h>
#include <stddef.h>
#include <string.h>
#include <sqlite3.h>

int auth(void *p, int op, const char *name1, const char *name2,
       const char *dbname, const char *caller)
{
    return dbname != NULL && strcmp(dbname, "main") == 0 ?
        SQLITE_DENY : SQLITE_OK;
}

int main()
{
    int rc;
    sqlite3 *db;

    rc = sqlite3_open(":memory:", &db);
    assert(rc == SQLITE_OK);
    rc = sqlite3_exec(db, "CREATE TABLE t (i)", NULL, NULL, NULL);
    assert(rc == SQLITE_OK);
    rc = sqlite3_set_authorizer(db, &auth, NULL);
    assert(rc == SQLITE_OK);
    rc = sqlite3_exec(db, "SELECT * FROM t", NULL, NULL, NULL);
    assert(rc == SQLITE_AUTH);
    rc = sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "main2");
    assert(rc == SQLITE_OK);
    rc = sqlite3_exec(db, "SELECT * FROM t", NULL, NULL, NULL);
    assert(rc == SQLITE_OK);
    rc = sqlite3_close(db);
    assert(rc == SQLITE_OK);

    return 0;
}

It seems it is not possible to call sqlite3_db_config from SQL, so the
attacker would need to have access to the address space of the database
connection and the database file to bypass the authorizer.

Perhaps it makes sense to either always pass "main" as the database name
of the main database to the authorizer or to introduce an additional
function that allows to retrieve the main database name, for example
sqlite3_db_config_get.

- Matthias-Christian
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to