Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9db459b4 authored by Ahmed Ibrahim's avatar Ahmed Ibrahim
Browse files

Add API support for sqlite3_set_authorizer().

Authorizers can be consulted during compilation of a SQL statement
to determine if each action requested by the SQL statement is allowed.

This can be useful to dynamically block interaction with private,
internal, or otherwise sensitive columns or tables inside a database,
such as when compiling an untrusted SQL statement.

This change adds the ability for developers to provide a custom
authorizer on a per-statement basis.  Since statements using a custom
authorizer are typically untrusted SQL, they're likely to have low
cache hit ratios, so we don't attempt to cache compiled statements.

Upstream SQLite is likely to continue adding new actions over
time, so our API design is a simple mirror of the underlying
callback.  Mapping of this underlying callback into higher-level
concepts is left to a Jetpack library.

Bug: 231636192
Test: atest CtsDatabaseTestCases
Change-Id: I06fa30e30c58961c9b05628e576a6f5f80fdf550
parent 1c450b40
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
@@ -14204,6 +14204,46 @@ package android.database.sqlite {
    ctor public SQLiteAccessPermException(String);
  }
  public interface SQLiteAuthorizer {
    method public int onAuthorize(int, @Nullable String, @Nullable String, @Nullable String, @Nullable String);
    field public static final int SQLITE_ACTION_ALTER_TABLE = 26; // 0x1a
    field public static final int SQLITE_ACTION_ANALYZE = 28; // 0x1c
    field public static final int SQLITE_ACTION_ATTACH = 24; // 0x18
    field public static final int SQLITE_ACTION_CREATE_INDEX = 1; // 0x1
    field public static final int SQLITE_ACTION_CREATE_TABLE = 2; // 0x2
    field public static final int SQLITE_ACTION_CREATE_TEMP_INDEX = 3; // 0x3
    field public static final int SQLITE_ACTION_CREATE_TEMP_TABLE = 4; // 0x4
    field public static final int SQLITE_ACTION_CREATE_TEMP_TRIGGER = 5; // 0x5
    field public static final int SQLITE_ACTION_CREATE_TEMP_VIEW = 6; // 0x6
    field public static final int SQLITE_ACTION_CREATE_TRIGGER = 7; // 0x7
    field public static final int SQLITE_ACTION_CREATE_VIEW = 8; // 0x8
    field public static final int SQLITE_ACTION_CREATE_VTABLE = 29; // 0x1d
    field public static final int SQLITE_ACTION_DELETE = 9; // 0x9
    field public static final int SQLITE_ACTION_DETACH = 25; // 0x19
    field public static final int SQLITE_ACTION_DROP_INDEX = 10; // 0xa
    field public static final int SQLITE_ACTION_DROP_TABLE = 11; // 0xb
    field public static final int SQLITE_ACTION_DROP_TEMP_INDEX = 12; // 0xc
    field public static final int SQLITE_ACTION_DROP_TEMP_TABLE = 13; // 0xd
    field public static final int SQLITE_ACTION_DROP_TEMP_TRIGGER = 14; // 0xe
    field public static final int SQLITE_ACTION_DROP_TEMP_VIEW = 15; // 0xf
    field public static final int SQLITE_ACTION_DROP_TRIGGER = 16; // 0x10
    field public static final int SQLITE_ACTION_DROP_VIEW = 17; // 0x11
    field public static final int SQLITE_ACTION_DROP_VTABLE = 30; // 0x1e
    field public static final int SQLITE_ACTION_FUNCTION = 31; // 0x1f
    field public static final int SQLITE_ACTION_INSERT = 18; // 0x12
    field public static final int SQLITE_ACTION_PRAGMA = 19; // 0x13
    field public static final int SQLITE_ACTION_READ = 20; // 0x14
    field public static final int SQLITE_ACTION_RECURSIVE = 33; // 0x21
    field public static final int SQLITE_ACTION_REINDEX = 27; // 0x1b
    field public static final int SQLITE_ACTION_SAVEPOINT = 32; // 0x20
    field public static final int SQLITE_ACTION_SELECT = 21; // 0x15
    field public static final int SQLITE_ACTION_TRANSACTION = 22; // 0x16
    field public static final int SQLITE_ACTION_UPDATE = 23; // 0x17
    field public static final int SQLITE_AUTHORIZER_RESULT_DENY = 1; // 0x1
    field public static final int SQLITE_AUTHORIZER_RESULT_IGNORE = 2; // 0x2
    field public static final int SQLITE_AUTHORIZER_RESULT_OK = 0; // 0x0
  }
  public class SQLiteBindOrColumnIndexOutOfRangeException extends android.database.sqlite.SQLiteException {
    ctor public SQLiteBindOrColumnIndexOutOfRangeException();
    ctor public SQLiteBindOrColumnIndexOutOfRangeException(String);
@@ -14260,6 +14300,7 @@ package android.database.sqlite {
    method public void beginTransactionWithListenerNonExclusive(@Nullable android.database.sqlite.SQLiteTransactionListener);
    method public void beginTransactionWithListenerReadOnly(@Nullable android.database.sqlite.SQLiteTransactionListener);
    method public android.database.sqlite.SQLiteStatement compileStatement(String) throws android.database.SQLException;
    method @NonNull public android.database.sqlite.SQLiteStatement compileStatement(@NonNull String, @NonNull android.database.sqlite.SQLiteAuthorizer) throws android.database.SQLException;
    method @NonNull public static android.database.sqlite.SQLiteDatabase create(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
    method @NonNull public static android.database.sqlite.SQLiteDatabase createInMemory(@NonNull android.database.sqlite.SQLiteDatabase.OpenParams);
    method public int delete(String, String, String[]);
@@ -14270,6 +14311,7 @@ package android.database.sqlite {
    method public void execPerConnectionSQL(@NonNull String, @Nullable Object[]) throws android.database.SQLException;
    method public void execSQL(String) throws android.database.SQLException;
    method public void execSQL(String, Object[]) throws android.database.SQLException;
    method public void execSQL(@NonNull String, @Nullable Object[], @NonNull android.database.sqlite.SQLiteAuthorizer) throws android.database.SQLException;
    method public static String findEditTable(String);
    method public java.util.List<android.util.Pair<java.lang.String,java.lang.String>> getAttachedDbs();
    method public long getMaximumSize();
@@ -14281,6 +14323,7 @@ package android.database.sqlite {
    method public long insert(String, String, android.content.ContentValues);
    method public long insertOrThrow(String, String, android.content.ContentValues) throws android.database.SQLException;
    method public long insertWithOnConflict(String, String, android.content.ContentValues, int);
    method public boolean isAuthorizerSupportEnabled();
    method public boolean isDatabaseIntegrityOk();
    method public boolean isDbLockedByCurrentThread();
    method @Deprecated public boolean isDbLockedByOtherThreads();
@@ -14307,6 +14350,7 @@ package android.database.sqlite {
    method public android.database.Cursor rawQuery(String, String[], android.os.CancellationSignal);
    method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, String, String[], String);
    method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, String, String[], String, android.os.CancellationSignal);
    method @NonNull public android.database.Cursor rawQueryWithFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory, @NonNull String, @Nullable String[], @Nullable String, @Nullable android.os.CancellationSignal, @NonNull android.database.sqlite.SQLiteAuthorizer);
    method public static int releaseMemory();
    method public long replace(String, String, android.content.ContentValues);
    method public long replaceOrThrow(String, String, android.content.ContentValues) throws android.database.SQLException;
@@ -14323,6 +14367,7 @@ package android.database.sqlite {
    method public int update(String, android.content.ContentValues, String, String[]);
    method public int updateWithOnConflict(String, android.content.ContentValues, String, String[], int);
    method public void validateSql(@NonNull String, @Nullable android.os.CancellationSignal);
    method public void validateSql(@NonNull String, @Nullable android.os.CancellationSignal, @NonNull android.database.sqlite.SQLiteAuthorizer);
    method @Deprecated public boolean yieldIfContended();
    method public boolean yieldIfContendedSafely();
    method public boolean yieldIfContendedSafely(long);
@@ -14371,7 +14416,9 @@ package android.database.sqlite {
    ctor public SQLiteDatabase.OpenParams.Builder(android.database.sqlite.SQLiteDatabase.OpenParams);
    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder addOpenFlags(int);
    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams build();
    method public boolean isAuthorizerSupportEnabled();
    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder removeOpenFlags(int);
    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setAuthorizerSupportEnabled(boolean);
    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setCursorFactory(@Nullable android.database.sqlite.SQLiteDatabase.CursorFactory);
    method @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setErrorHandler(@Nullable android.database.DatabaseErrorHandler);
    method @Deprecated @NonNull public android.database.sqlite.SQLiteDatabase.OpenParams.Builder setIdleConnectionTimeout(@IntRange(from=0) long);
+1 −0
Original line number Diff line number Diff line
@@ -1303,6 +1303,7 @@ package android.database.sqlite {

  public final class SQLiteDirectCursorDriver implements android.database.sqlite.SQLiteCursorDriver {
    ctor public SQLiteDirectCursorDriver(android.database.sqlite.SQLiteDatabase, String, String, android.os.CancellationSignal);
    ctor public SQLiteDirectCursorDriver(@NonNull android.database.sqlite.SQLiteDatabase, @Nullable android.database.sqlite.SQLiteAuthorizer, @NonNull String, @Nullable String, @Nullable android.os.CancellationSignal);
    method public void cursorClosed();
    method public void cursorDeactivated();
    method public void cursorRequeried(android.database.Cursor);
+178 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.database.sqlite;

import android.annotation.IntDef;
import android.annotation.Nullable;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Authorizer which is consulted during compilation of a SQL statement.
 * <p>
 * During compilation, this callback will be invoked to determine if each action
 * requested by the SQL statement is allowed.
 * <p>
 * This can be useful to dynamically block interaction with private, internal,
 * or otherwise sensitive columns or tables inside a database, such as when
 * compiling an untrusted SQL statement.
 */
public interface SQLiteAuthorizer {
    /** @hide */
    @IntDef(prefix = { "SQLITE_AUTHORIZER_RESULT_" }, value = {
            SQLITE_AUTHORIZER_RESULT_OK,
            SQLITE_AUTHORIZER_RESULT_DENY,
            SQLITE_AUTHORIZER_RESULT_IGNORE,
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface AuthorizerResult {}

    /** @hide */
    @IntDef(prefix = { "SQLITE_ACTION_" }, value = {
            SQLITE_ACTION_CREATE_INDEX,
            SQLITE_ACTION_CREATE_TABLE,
            SQLITE_ACTION_CREATE_TEMP_INDEX,
            SQLITE_ACTION_CREATE_TEMP_TABLE,
            SQLITE_ACTION_CREATE_TEMP_TRIGGER,
            SQLITE_ACTION_CREATE_TEMP_VIEW,
            SQLITE_ACTION_CREATE_TRIGGER,
            SQLITE_ACTION_CREATE_VIEW,
            SQLITE_ACTION_DELETE,
            SQLITE_ACTION_DROP_INDEX,
            SQLITE_ACTION_DROP_TABLE,
            SQLITE_ACTION_DROP_TEMP_INDEX,
            SQLITE_ACTION_DROP_TEMP_TABLE,
            SQLITE_ACTION_DROP_TEMP_TRIGGER,
            SQLITE_ACTION_DROP_TEMP_VIEW,
            SQLITE_ACTION_DROP_TRIGGER,
            SQLITE_ACTION_DROP_VIEW,
            SQLITE_ACTION_INSERT,
            SQLITE_ACTION_PRAGMA,
            SQLITE_ACTION_READ,
            SQLITE_ACTION_SELECT,
            SQLITE_ACTION_TRANSACTION,
            SQLITE_ACTION_UPDATE,
            SQLITE_ACTION_ATTACH,
            SQLITE_ACTION_DETACH,
            SQLITE_ACTION_ALTER_TABLE,
            SQLITE_ACTION_REINDEX,
            SQLITE_ACTION_ANALYZE,
            SQLITE_ACTION_CREATE_VTABLE,
            SQLITE_ACTION_DROP_VTABLE,
            SQLITE_ACTION_FUNCTION,
            SQLITE_ACTION_SAVEPOINT,
            SQLITE_ACTION_RECURSIVE,
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface AuthorizerAction {}

    /** Successful result */
    int SQLITE_AUTHORIZER_RESULT_OK = 0;
    /** Abort the SQL statement with an error */
    int SQLITE_AUTHORIZER_RESULT_DENY = 1;
    /** Don't allow access, but don't generate an error */
    int SQLITE_AUTHORIZER_RESULT_IGNORE = 2;

    /** Authorizer action for {@code CREATE INDEX} */
    int SQLITE_ACTION_CREATE_INDEX          = 1;
    /** Authorizer action for {@code CREATE TABLE} */
    int SQLITE_ACTION_CREATE_TABLE          = 2;
    /** Authorizer action for {@code CREATE TEMP INDEX} */
    int SQLITE_ACTION_CREATE_TEMP_INDEX     = 3;
    /** Authorizer action for {@code CREATE TEMP TABLE} */
    int SQLITE_ACTION_CREATE_TEMP_TABLE     = 4;
    /** Authorizer action for {@code CREATE TEMP TRIGGER} */
    int SQLITE_ACTION_CREATE_TEMP_TRIGGER   = 5;
    /** Authorizer action for {@code CREATE TEMP VIEW} */
    int SQLITE_ACTION_CREATE_TEMP_VIEW      = 6;
    /** Authorizer action for {@code CREATE TRIGGER} */
    int SQLITE_ACTION_CREATE_TRIGGER        = 7;
    /** Authorizer action for {@code CREATE VIEW} */
    int SQLITE_ACTION_CREATE_VIEW           = 8;
    /** Authorizer action for {@code DELETE} */
    int SQLITE_ACTION_DELETE                = 9;
    /** Authorizer action for {@code DROP INDEX} */
    int SQLITE_ACTION_DROP_INDEX           = 10;
    /** Authorizer action for {@code DROP TABLE} */
    int SQLITE_ACTION_DROP_TABLE           = 11;
    /** Authorizer action for {@code DROP TEMP INDEX} */
    int SQLITE_ACTION_DROP_TEMP_INDEX      = 12;
    /** Authorizer action for {@code DROP TEMP TABLE} */
    int SQLITE_ACTION_DROP_TEMP_TABLE      = 13;
    /** Authorizer action for {@code DROP TEMP TRIGGER} */
    int SQLITE_ACTION_DROP_TEMP_TRIGGER    = 14;
    /** Authorizer action for {@code DROP TEMP VIEW} */
    int SQLITE_ACTION_DROP_TEMP_VIEW       = 15;
    /** Authorizer action for {@code DROP TRIGGER} */
    int SQLITE_ACTION_DROP_TRIGGER         = 16;
    /** Authorizer action for {@code DROP VIEW} */
    int SQLITE_ACTION_DROP_VIEW            = 17;
    /** Authorizer action for {@code INSERT} */
    int SQLITE_ACTION_INSERT               = 18;
    /** Authorizer action for {@code PRAGMA} */
    int SQLITE_ACTION_PRAGMA               = 19;
    /** Authorizer action for read access on a specific table and column */
    int SQLITE_ACTION_READ                 = 20;
    /** Authorizer action for {@code SELECT} */
    int SQLITE_ACTION_SELECT               = 21;
    /** Authorizer action for transaction operations */
    int SQLITE_ACTION_TRANSACTION          = 22;
    /** Authorizer action for {@code UPDATE} */
    int SQLITE_ACTION_UPDATE               = 23;
    /** Authorizer action for {@code ATTACH} */
    int SQLITE_ACTION_ATTACH               = 24;
    /** Authorizer action for {@code DETACH} */
    int SQLITE_ACTION_DETACH               = 25;
    /** Authorizer action for {@code ALTER TABLE} */
    int SQLITE_ACTION_ALTER_TABLE          = 26;
    /** Authorizer action for {@code REINDEX} */
    int SQLITE_ACTION_REINDEX              = 27;
    /** Authorizer action for {@code ANALYZE} */
    int SQLITE_ACTION_ANALYZE              = 28;
    /** Authorizer action for {@code CREATE VIRTUAL TABLE} */
    int SQLITE_ACTION_CREATE_VTABLE        = 29;
    /** Authorizer action for {@code DROP VIRTUAL TABLE} */
    int SQLITE_ACTION_DROP_VTABLE          = 30;
    /** Authorizer action for invocation of a function */
    int SQLITE_ACTION_FUNCTION             = 31;
    /** Authorizer action for savepoint operations */
    int SQLITE_ACTION_SAVEPOINT            = 32;
    /** Authorizer action for recursive operations */
    int SQLITE_ACTION_RECURSIVE            = 33;

    /**
     * Test if the given action should be allowed.
     *
     * @param action The action requested by the SQL statement currently being
     *            compiled.
     * @param arg3 Optional argument relevant to the given action.
     * @param arg4 Optional argument relevant to the given action.
     * @param arg5 Optional argument relevant to the given action.
     * @param arg6 Optional argument relevant to the given action.
     * @return {@link SQLiteConstants#SQLITE_AUTHORIZER_RESULT_OK} to allow the action,
     *         {@link SQLiteConstants#SQLITE_AUTHORIZER_RESULT_IGNORE} to disallow the specific
     *         action but allow the SQL statement to continue to be compiled, or
     *         {@link SQLiteConstants#SQLITE_AUTHORIZER_RESULT_DENY} to cause the entire SQL
     *         statement to be rejected with an error.
     * @see <a href="https://www.sqlite.org/c3ref/c_alter_table.html">Upstream
     *      SQLite documentation</a> that describes possible actions and their
     *      arguments.
     */
    @AuthorizerResult int onAuthorize(@AuthorizerAction int action, @Nullable String arg3,
            @Nullable String arg4, @Nullable String arg5, @Nullable String arg6);
}
+90 −65

File changed.

Preview size limit exceeded, changes collapsed.

+254 −19

File changed.

Preview size limit exceeded, changes collapsed.

Loading