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

Commit 30695521 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Check signature of updated font during boot"

parents af61e073 06345f24
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -198,6 +198,15 @@ public class FontManager {
     */
    public static final int RESULT_ERROR_INVALID_XML = -10007;

    /**
     * Indicates a failure due to invalid debug certificate file.
     *
     * This error code is only used with the shell command interaction.
     *
     * @hide
     */
    public static final int RESULT_ERROR_INVALID_DEBUG_CERTIFICATE = -10008;

    private FontManager(@NonNull IFontManager iFontManager) {
        mIFontManager = iFontManager;
    }
+4 −0
Original line number Diff line number Diff line
@@ -5775,4 +5775,8 @@
    <string-array name="config_serviceStateLocationAllowedPackages">
        <item>"com.android.phone"</item>
    </string-array>

    <!-- List of certificate to be used for font fs-verity integrity verification -->
    <string-array translatable="false" name="config_fontManagerServiceCerts">
    </string-array>
</resources>
+1 −0
Original line number Diff line number Diff line
@@ -2273,6 +2273,7 @@
  <java-symbol type="id" name="media_actions" />

  <java-symbol type="dimen" name="config_mediaMetadataBitmapMaxSize" />
  <java-symbol type="array" name="config_fontManagerServiceCerts" />

    <!-- From SystemUI -->
  <java-symbol type="anim" name="push_down_in" />
+69 −18
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.graphics.fonts.FontFamily;
import android.graphics.fonts.FontManager;
import android.graphics.fonts.FontUpdateRequest;
import android.graphics.fonts.SystemFonts;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.ResultReceiver;
import android.os.SharedMemory;
@@ -35,8 +36,10 @@ import android.text.FontConfig;
import android.util.AndroidException;
import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.graphics.fonts.IFontManager;
import com.android.internal.security.VerityUtils;
@@ -47,7 +50,9 @@ import com.android.server.SystemService;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.DirectByteBuffer;
@@ -154,9 +159,30 @@ public final class FontManagerService extends IFontManager.Stub {
    }

    private static class FsverityUtilImpl implements UpdatableFontDir.FsverityUtil {

        private final String[] mDerCertPaths;

        FsverityUtilImpl(String[] derCertPaths) {
            mDerCertPaths = derCertPaths;
        }

        @Override
        public boolean hasFsverity(String filePath) {
            return VerityUtils.hasFsverity(filePath);
        public boolean isFromTrustedProvider(String fontPath, byte[] pkcs7Signature) {
            final byte[] digest = VerityUtils.getFsverityDigest(fontPath);
            if (digest == null) {
                Log.w(TAG, "Failed to get fs-verity digest for " + fontPath);
                return false;
            }
            for (String certPath : mDerCertPaths) {
                try (InputStream is = new FileInputStream(certPath)) {
                    if (VerityUtils.verifyPkcs7DetachedSignature(pkcs7Signature, digest, is)) {
                        return true;
                    }
                } catch (IOException e) {
                    Log.w(TAG, "Failed to read certificate file: " + certPath);
                }
            }
            return false;
        }

        @Override
@@ -174,11 +200,15 @@ public final class FontManagerService extends IFontManager.Stub {
    @NonNull
    private final Context mContext;

    private final boolean mIsSafeMode;

    private final Object mUpdatableFontDirLock = new Object();

    private String mDebugCertFilePath = null;

    @GuardedBy("mUpdatableFontDirLock")
    @Nullable
    private final UpdatableFontDir mUpdatableFontDir;
    private UpdatableFontDir mUpdatableFontDir;

    // mSerializedFontMapLock can be acquired while holding mUpdatableFontDirLock.
    // mUpdatableFontDirLock should not be newly acquired while holding mSerializedFontMapLock.
@@ -194,22 +224,43 @@ public final class FontManagerService extends IFontManager.Stub {
            UpdatableFontDir.deleteAllFiles(new File(FONT_FILES_DIR), new File(CONFIG_XML_FILE));
        }
        mContext = context;
        mUpdatableFontDir = createUpdatableFontDir(safeMode);
        mIsSafeMode = safeMode;
        initialize();
    }

    @Nullable
    private static UpdatableFontDir createUpdatableFontDir(boolean safeMode) {
    private UpdatableFontDir createUpdatableFontDir() {
        // Never read updatable font files in safe mode.
        if (safeMode) return null;
        if (mIsSafeMode) return null;
        // If apk verity is supported, fs-verity should be available.
        if (!VerityUtils.isFsVeritySupported()) return null;

        String[] certs = mContext.getResources().getStringArray(
                R.array.config_fontManagerServiceCerts);

        if (mDebugCertFilePath != null && (Build.IS_USERDEBUG || Build.IS_ENG)) {
            String[] tmp = new String[certs.length + 1];
            System.arraycopy(certs, 0, tmp, 0, certs.length);
            tmp[certs.length] = mDebugCertFilePath;
            certs = tmp;
        }

        return new UpdatableFontDir(new File(FONT_FILES_DIR), new OtfFontFileParser(),
                new FsverityUtilImpl(), new File(CONFIG_XML_FILE));
                new FsverityUtilImpl(certs), new File(CONFIG_XML_FILE));
    }

    /**
     * Add debug certificate to the cert list. This must be called only on userdebug/eng
     * build.
     * @param debugCertPath a debug certificate file path
     */
    public void addDebugCertificate(@Nullable String debugCertPath) {
        mDebugCertFilePath = debugCertPath;
    }

    private void initialize() {
        synchronized (mUpdatableFontDirLock) {
            mUpdatableFontDir = createUpdatableFontDir();
            if (mUpdatableFontDir == null) {
                setSerializedFontMap(serializeSystemServerFontMap());
                return;
@@ -232,12 +283,12 @@ public final class FontManagerService extends IFontManager.Stub {

    /* package */ void update(int baseVersion, List<FontUpdateRequest> requests)
            throws SystemFontException {
        synchronized (mUpdatableFontDirLock) {
            if (mUpdatableFontDir == null) {
                throw new SystemFontException(
                        FontManager.RESULT_ERROR_FONT_UPDATER_DISABLED,
                        "The font updater is disabled.");
            }
        synchronized (mUpdatableFontDirLock) {
            // baseVersion == -1 only happens from shell command. This is filtered and treated as
            // error from SystemApi call.
            if (baseVersion != -1 && mUpdatableFontDir.getConfigVersion() != baseVersion) {
@@ -272,10 +323,10 @@ public final class FontManagerService extends IFontManager.Stub {
    }

    /* package */ Map<String, File> getFontFileMap() {
        synchronized (mUpdatableFontDirLock) {
            if (mUpdatableFontDir == null) {
                return Collections.emptyMap();
            }
        synchronized (mUpdatableFontDirLock) {
            return mUpdatableFontDir.getPostScriptMap();
        }
    }
@@ -301,10 +352,10 @@ public final class FontManagerService extends IFontManager.Stub {
     * Returns an active system font configuration.
     */
    public @NonNull FontConfig getSystemFontConfig() {
        synchronized (mUpdatableFontDirLock) {
            if (mUpdatableFontDir == null) {
                return SystemFonts.getSystemPreinstalledFontConfig();
            }
        synchronized (mUpdatableFontDirLock) {
            return mUpdatableFontDir.getSystemFontConfig();
        }
    }
+34 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.graphics.fonts.FontUpdateRequest;
import android.graphics.fonts.FontVariationAxis;
import android.graphics.fonts.SystemFonts;
import android.os.Binder;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.ShellCommand;
@@ -103,6 +104,10 @@ public class FontManagerShellCommand extends ShellCommand {
        w.println("update-family [family definition XML path]");
        w.println("    Update font families with the new definitions.");
        w.println();
        w.println("install-debug-cert [cert file path]");
        w.println("    Install debug certificate file. This command can be used only on userdebug");
        w.println("    or eng device with root user.");
        w.println();
        w.println("clear");
        w.println("    Remove all installed font files and reset to the initial state.");
        w.println();
@@ -322,6 +327,33 @@ public class FontManagerShellCommand extends ShellCommand {
        return 0;
    }

    private int installCert(ShellCommand shell) throws SystemFontException {
        if (!(Build.IS_USERDEBUG || Build.IS_ENG)) {
            throw new SecurityException("Only userdebug/eng device can add debug certificate");
        }
        if (Binder.getCallingUid() != Process.ROOT_UID) {
            throw new SecurityException("Only root can add debug certificate");
        }

        String certPath = shell.getNextArg();
        if (certPath == null) {
            throw new SystemFontException(
                    FontManager.RESULT_ERROR_INVALID_DEBUG_CERTIFICATE,
                    "Cert file path argument is required.");
        }
        File file = new File(certPath);
        if (!file.isFile()) {
            throw new SystemFontException(
                    FontManager.RESULT_ERROR_INVALID_DEBUG_CERTIFICATE,
                    "Cert file (" + file + ") is not found");
        }

        mService.addDebugCertificate(certPath);
        mService.restart();
        shell.getOutPrintWriter().println("Success");
        return 0;
    }

    private int update(ShellCommand shell) throws SystemFontException {
        String fontPath = shell.getNextArg();
        if (fontPath == null) {
@@ -494,6 +526,8 @@ public class FontManagerShellCommand extends ShellCommand {
                    return restart(shell);
                case "status":
                    return status(shell);
                case "install-debug-cert":
                    return installCert(shell);
                default:
                    return shell.handleDefaultCommands(cmd);
            }
Loading