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

Commit 5759e94b authored by Victor Hsieh's avatar Victor Hsieh Committed by Android (Google) Code Review
Browse files

Merge "Add public API FileIntegrityManager.setupFsverity/getFsverityDigest" into main

parents 8eebe7c0 91ae4e39
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -39351,8 +39351,10 @@ package android.security {
  }
  public final class FileIntegrityManager {
    method @FlaggedApi(Flags.FLAG_FSVERITY_API) @Nullable public byte[] getFsverityDigest(@NonNull java.io.File) throws java.io.IOException;
    method public boolean isApkVeritySupported();
    method @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public boolean isAppSourceCertificateTrusted(@NonNull java.security.cert.X509Certificate) throws java.security.cert.CertificateEncodingException;
    method @FlaggedApi(Flags.FLAG_FSVERITY_API) public void setupFsverity(@NonNull java.io.File) throws java.io.IOException;
  }
  public final class KeyChain {
+16 −0
Original line number Diff line number Diff line
@@ -20,8 +20,11 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.UserInfo;
import android.os.IInstalld;
import android.os.IVold;
import android.os.ParcelFileDescriptor;

import java.io.IOException;
import java.util.List;
import java.util.Set;

@@ -185,4 +188,17 @@ public abstract class StorageManagerInternal {
    public abstract void prepareUserStorageForMove(String fromVolumeUuid, String toVolumeUuid,
            List<UserInfo> users);

    /**
     * A proxy call to the corresponding method in Installer.
     * @see com.android.server.pm.Installer#createFsveritySetupAuthToken()
     */
    public abstract IInstalld.IFsveritySetupAuthToken createFsveritySetupAuthToken(
            ParcelFileDescriptor authFd, int appUid, @UserIdInt int userId) throws IOException;

    /**
     * A proxy call to the corresponding method in Installer.
     * @see com.android.server.pm.Installer#enableFsverity()
     */
    public abstract int enableFsverity(IInstalld.IFsveritySetupAuthToken authToken, String filePath,
            String packageName) throws IOException;
}
+70 −0
Original line number Diff line number Diff line
@@ -16,12 +16,21 @@

package android.security;

import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
import android.os.IInstalld.IFsveritySetupAuthToken;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.system.ErrnoException;

import com.android.internal.security.VerityUtils;

import java.io.File;
import java.io.IOException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;

@@ -54,6 +63,67 @@ public final class FileIntegrityManager {
        }
    }

    /**
     * Enables fs-verity to the owned file under the calling app's private directory. It always uses
     * the common configuration, i.e. SHA-256 digest algorithm, 4K block size, and without salt.
     *
     * The operation can only succeed when the file is not opened as writable by any process.
     *
     * It takes O(file size) time to build the underlying data structure for continuous
     * verification. The operation is atomic, i.e. it's either enabled or not, even in case of
     * power failure during or after the call.
     *
     * Note for the API users: When the file's authenticity is crucial, the app typical needs to
     * perform a signature check by itself before using the file. The signature is often delivered
     * as a separate file and stored next to the targeting file in the filesystem. The public key of
     * the signer (normally the same app developer) can be put in the APK, and the app can use the
     * public key to verify the signature to the file's actual fs-verity digest (from {@link
     * #getFsverityDigest}) before using the file. The exact format is not prescribed by the
     * framework. App developers may choose to use common practices like JCA for the signing and
     * verification, or their own preferred approach.
     *
     * @param file The file to enable fs-verity. It should be an absolute path.
     *
     * @see <a href="https://www.kernel.org/doc/html/next/filesystems/fsverity.html">Kernel doc</a>
     */
    @FlaggedApi(Flags.FLAG_FSVERITY_API)
    public void setupFsverity(@NonNull File file) throws IOException {
        if (!file.isAbsolute()) {
            throw new IllegalArgumentException("Expect an absolute path");
        }
        IFsveritySetupAuthToken authToken;
        // fs-verity setup requires no writable fd to the file. Make sure it's closed before
        // continue.
        try (var authFd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE)) {
            authToken = mService.createAuthToken(authFd);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        try {
            int errno = mService.setupFsverity(authToken, file.getPath(),
                    mContext.getPackageName());
            if (errno != 0) {
                new ErrnoException("setupFsverity", errno).rethrowAsIOException();
            }
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns the fs-verity digest for the owned file under the calling app's
     * private directory, or null when the file does not have fs-verity enabled.
     *
     * @param file The file to measure the fs-verity digest.
     * @return The fs-verity digeset in byte[], null if none.
     * @see <a href="https://www.kernel.org/doc/html/next/filesystems/fsverity.html">Kernel doc</a>
     */
    @FlaggedApi(Flags.FLAG_FSVERITY_API)
    public @Nullable byte[] getFsverityDigest(@NonNull File file) throws IOException {
        return VerityUtils.getFsverityDigest(file.getPath());
    }

    /**
     * Returns whether the given certificate can be used to prove app's install source. Always
     * return false if the feature is not supported.
+7 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package android.security;

import android.os.ParcelFileDescriptor;
import android.os.IInstalld;

/**
 * Binder interface to communicate with FileIntegrityService.
 * @hide
@@ -23,4 +26,8 @@ package android.security;
interface IFileIntegrityService {
    boolean isApkVeritySupported();
    boolean isAppSourceCertificateTrusted(in byte[] certificateBytes, in String packageName);

    IInstalld.IFsveritySetupAuthToken createAuthToken(in ParcelFileDescriptor authFd);
    int setupFsverity(IInstalld.IFsveritySetupAuthToken authToken, in String filePath,
            in String packageName);
}
+20 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.IInstalld.IFsveritySetupAuthToken;
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT;
@@ -4994,5 +4995,24 @@ class StorageManagerService extends IStorageManager.Stub
            }
        }

        @Override
        public IFsveritySetupAuthToken createFsveritySetupAuthToken(ParcelFileDescriptor authFd,
                int appUid, @UserIdInt int userId) throws IOException {
            try {
                return mInstaller.createFsveritySetupAuthToken(authFd, appUid, userId);
            } catch (Installer.InstallerException e) {
                throw new IOException(e);
            }
        }

        @Override
        public int enableFsverity(IFsveritySetupAuthToken authToken, String filePath,
                String packageName) throws IOException {
            try {
                return mInstaller.enableFsverity(authToken, filePath, packageName);
            } catch (Installer.InstallerException e) {
                throw new IOException(e);
            }
        }
    }
}
Loading