Merge "Check signature of updated font during boot"
This commit is contained in:
@@ -198,6 +198,15 @@ public class FontManager {
|
|||||||
*/
|
*/
|
||||||
public static final int RESULT_ERROR_INVALID_XML = -10007;
|
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) {
|
private FontManager(@NonNull IFontManager iFontManager) {
|
||||||
mIFontManager = iFontManager;
|
mIFontManager = iFontManager;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5775,4 +5775,8 @@
|
|||||||
<string-array name="config_serviceStateLocationAllowedPackages">
|
<string-array name="config_serviceStateLocationAllowedPackages">
|
||||||
<item>"com.android.phone"</item>
|
<item>"com.android.phone"</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<!-- List of certificate to be used for font fs-verity integrity verification -->
|
||||||
|
<string-array translatable="false" name="config_fontManagerServiceCerts">
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -2273,6 +2273,7 @@
|
|||||||
<java-symbol type="id" name="media_actions" />
|
<java-symbol type="id" name="media_actions" />
|
||||||
|
|
||||||
<java-symbol type="dimen" name="config_mediaMetadataBitmapMaxSize" />
|
<java-symbol type="dimen" name="config_mediaMetadataBitmapMaxSize" />
|
||||||
|
<java-symbol type="array" name="config_fontManagerServiceCerts" />
|
||||||
|
|
||||||
<!-- From SystemUI -->
|
<!-- From SystemUI -->
|
||||||
<java-symbol type="anim" name="push_down_in" />
|
<java-symbol type="anim" name="push_down_in" />
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import android.graphics.fonts.FontFamily;
|
|||||||
import android.graphics.fonts.FontManager;
|
import android.graphics.fonts.FontManager;
|
||||||
import android.graphics.fonts.FontUpdateRequest;
|
import android.graphics.fonts.FontUpdateRequest;
|
||||||
import android.graphics.fonts.SystemFonts;
|
import android.graphics.fonts.SystemFonts;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.ResultReceiver;
|
import android.os.ResultReceiver;
|
||||||
import android.os.SharedMemory;
|
import android.os.SharedMemory;
|
||||||
@@ -35,8 +36,10 @@ import android.text.FontConfig;
|
|||||||
import android.util.AndroidException;
|
import android.util.AndroidException;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.IndentingPrintWriter;
|
import android.util.IndentingPrintWriter;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.internal.graphics.fonts.IFontManager;
|
import com.android.internal.graphics.fonts.IFontManager;
|
||||||
import com.android.internal.security.VerityUtils;
|
import com.android.internal.security.VerityUtils;
|
||||||
@@ -47,7 +50,9 @@ import com.android.server.SystemService;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.DirectByteBuffer;
|
import java.nio.DirectByteBuffer;
|
||||||
@@ -154,9 +159,30 @@ public final class FontManagerService extends IFontManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class FsverityUtilImpl implements UpdatableFontDir.FsverityUtil {
|
private static class FsverityUtilImpl implements UpdatableFontDir.FsverityUtil {
|
||||||
|
|
||||||
|
private final String[] mDerCertPaths;
|
||||||
|
|
||||||
|
FsverityUtilImpl(String[] derCertPaths) {
|
||||||
|
mDerCertPaths = derCertPaths;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasFsverity(String filePath) {
|
public boolean isFromTrustedProvider(String fontPath, byte[] pkcs7Signature) {
|
||||||
return VerityUtils.hasFsverity(filePath);
|
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
|
@Override
|
||||||
@@ -174,11 +200,15 @@ public final class FontManagerService extends IFontManager.Stub {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
|
private final boolean mIsSafeMode;
|
||||||
|
|
||||||
private final Object mUpdatableFontDirLock = new Object();
|
private final Object mUpdatableFontDirLock = new Object();
|
||||||
|
|
||||||
|
private String mDebugCertFilePath = null;
|
||||||
|
|
||||||
@GuardedBy("mUpdatableFontDirLock")
|
@GuardedBy("mUpdatableFontDirLock")
|
||||||
@Nullable
|
@Nullable
|
||||||
private final UpdatableFontDir mUpdatableFontDir;
|
private UpdatableFontDir mUpdatableFontDir;
|
||||||
|
|
||||||
// mSerializedFontMapLock can be acquired while holding mUpdatableFontDirLock.
|
// mSerializedFontMapLock can be acquired while holding mUpdatableFontDirLock.
|
||||||
// mUpdatableFontDirLock should not be newly acquired while holding mSerializedFontMapLock.
|
// 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));
|
UpdatableFontDir.deleteAllFiles(new File(FONT_FILES_DIR), new File(CONFIG_XML_FILE));
|
||||||
}
|
}
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mUpdatableFontDir = createUpdatableFontDir(safeMode);
|
mIsSafeMode = safeMode;
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static UpdatableFontDir createUpdatableFontDir(boolean safeMode) {
|
private UpdatableFontDir createUpdatableFontDir() {
|
||||||
// Never read updatable font files in safe mode.
|
// 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 apk verity is supported, fs-verity should be available.
|
||||||
if (!VerityUtils.isFsVeritySupported()) return null;
|
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(),
|
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() {
|
private void initialize() {
|
||||||
synchronized (mUpdatableFontDirLock) {
|
synchronized (mUpdatableFontDirLock) {
|
||||||
|
mUpdatableFontDir = createUpdatableFontDir();
|
||||||
if (mUpdatableFontDir == null) {
|
if (mUpdatableFontDir == null) {
|
||||||
setSerializedFontMap(serializeSystemServerFontMap());
|
setSerializedFontMap(serializeSystemServerFontMap());
|
||||||
return;
|
return;
|
||||||
@@ -232,12 +283,12 @@ public final class FontManagerService extends IFontManager.Stub {
|
|||||||
|
|
||||||
/* package */ void update(int baseVersion, List<FontUpdateRequest> requests)
|
/* package */ void update(int baseVersion, List<FontUpdateRequest> requests)
|
||||||
throws SystemFontException {
|
throws SystemFontException {
|
||||||
|
synchronized (mUpdatableFontDirLock) {
|
||||||
if (mUpdatableFontDir == null) {
|
if (mUpdatableFontDir == null) {
|
||||||
throw new SystemFontException(
|
throw new SystemFontException(
|
||||||
FontManager.RESULT_ERROR_FONT_UPDATER_DISABLED,
|
FontManager.RESULT_ERROR_FONT_UPDATER_DISABLED,
|
||||||
"The font updater is disabled.");
|
"The font updater is disabled.");
|
||||||
}
|
}
|
||||||
synchronized (mUpdatableFontDirLock) {
|
|
||||||
// baseVersion == -1 only happens from shell command. This is filtered and treated as
|
// baseVersion == -1 only happens from shell command. This is filtered and treated as
|
||||||
// error from SystemApi call.
|
// error from SystemApi call.
|
||||||
if (baseVersion != -1 && mUpdatableFontDir.getConfigVersion() != baseVersion) {
|
if (baseVersion != -1 && mUpdatableFontDir.getConfigVersion() != baseVersion) {
|
||||||
@@ -272,10 +323,10 @@ public final class FontManagerService extends IFontManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* package */ Map<String, File> getFontFileMap() {
|
/* package */ Map<String, File> getFontFileMap() {
|
||||||
|
synchronized (mUpdatableFontDirLock) {
|
||||||
if (mUpdatableFontDir == null) {
|
if (mUpdatableFontDir == null) {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
synchronized (mUpdatableFontDirLock) {
|
|
||||||
return mUpdatableFontDir.getPostScriptMap();
|
return mUpdatableFontDir.getPostScriptMap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,10 +352,10 @@ public final class FontManagerService extends IFontManager.Stub {
|
|||||||
* Returns an active system font configuration.
|
* Returns an active system font configuration.
|
||||||
*/
|
*/
|
||||||
public @NonNull FontConfig getSystemFontConfig() {
|
public @NonNull FontConfig getSystemFontConfig() {
|
||||||
|
synchronized (mUpdatableFontDirLock) {
|
||||||
if (mUpdatableFontDir == null) {
|
if (mUpdatableFontDir == null) {
|
||||||
return SystemFonts.getSystemPreinstalledFontConfig();
|
return SystemFonts.getSystemPreinstalledFontConfig();
|
||||||
}
|
}
|
||||||
synchronized (mUpdatableFontDirLock) {
|
|
||||||
return mUpdatableFontDir.getSystemFontConfig();
|
return mUpdatableFontDir.getSystemFontConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import android.graphics.fonts.FontUpdateRequest;
|
|||||||
import android.graphics.fonts.FontVariationAxis;
|
import android.graphics.fonts.FontVariationAxis;
|
||||||
import android.graphics.fonts.SystemFonts;
|
import android.graphics.fonts.SystemFonts;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.ShellCommand;
|
import android.os.ShellCommand;
|
||||||
@@ -103,6 +104,10 @@ public class FontManagerShellCommand extends ShellCommand {
|
|||||||
w.println("update-family [family definition XML path]");
|
w.println("update-family [family definition XML path]");
|
||||||
w.println(" Update font families with the new definitions.");
|
w.println(" Update font families with the new definitions.");
|
||||||
w.println();
|
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("clear");
|
||||||
w.println(" Remove all installed font files and reset to the initial state.");
|
w.println(" Remove all installed font files and reset to the initial state.");
|
||||||
w.println();
|
w.println();
|
||||||
@@ -322,6 +327,33 @@ public class FontManagerShellCommand extends ShellCommand {
|
|||||||
return 0;
|
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 {
|
private int update(ShellCommand shell) throws SystemFontException {
|
||||||
String fontPath = shell.getNextArg();
|
String fontPath = shell.getNextArg();
|
||||||
if (fontPath == null) {
|
if (fontPath == null) {
|
||||||
@@ -494,6 +526,8 @@ public class FontManagerShellCommand extends ShellCommand {
|
|||||||
return restart(shell);
|
return restart(shell);
|
||||||
case "status":
|
case "status":
|
||||||
return status(shell);
|
return status(shell);
|
||||||
|
case "install-debug-cert":
|
||||||
|
return installCert(shell);
|
||||||
default:
|
default:
|
||||||
return shell.handleDefaultCommands(cmd);
|
return shell.handleDefaultCommands(cmd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ import java.io.FileDescriptor;
|
|||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -59,6 +61,8 @@ final class UpdatableFontDir {
|
|||||||
private static final String TAG = "UpdatableFontDir";
|
private static final String TAG = "UpdatableFontDir";
|
||||||
private static final String RANDOM_DIR_PREFIX = "~~";
|
private static final String RANDOM_DIR_PREFIX = "~~";
|
||||||
|
|
||||||
|
private static final String FONT_SIGNATURE_FILE = "font.fsv_sig";
|
||||||
|
|
||||||
/** Interface to mock font file access in tests. */
|
/** Interface to mock font file access in tests. */
|
||||||
interface FontFileParser {
|
interface FontFileParser {
|
||||||
String getPostScriptName(File file) throws IOException;
|
String getPostScriptName(File file) throws IOException;
|
||||||
@@ -72,7 +76,7 @@ final class UpdatableFontDir {
|
|||||||
|
|
||||||
/** Interface to mock fs-verity in tests. */
|
/** Interface to mock fs-verity in tests. */
|
||||||
interface FsverityUtil {
|
interface FsverityUtil {
|
||||||
boolean hasFsverity(String path);
|
boolean isFromTrustedProvider(String path, byte[] pkcs7Signature);
|
||||||
|
|
||||||
void setUpFsverity(String path, byte[] pkcs7Signature) throws IOException;
|
void setUpFsverity(String path, byte[] pkcs7Signature) throws IOException;
|
||||||
|
|
||||||
@@ -188,12 +192,35 @@ final class UpdatableFontDir {
|
|||||||
FileUtils.deleteContentsAndDir(dir);
|
FileUtils.deleteContentsAndDir(dir);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File signatureFile = new File(dir, FONT_SIGNATURE_FILE);
|
||||||
|
if (!signatureFile.exists()) {
|
||||||
|
Slog.i(TAG, "The signature file is missing.");
|
||||||
|
FileUtils.deleteContentsAndDir(dir);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
byte[] signature;
|
||||||
|
try {
|
||||||
|
signature = Files.readAllBytes(Paths.get(signatureFile.getAbsolutePath()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
Slog.e(TAG, "Failed to read signature file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
File[] files = dir.listFiles();
|
File[] files = dir.listFiles();
|
||||||
if (files == null || files.length != 1) {
|
if (files == null || files.length != 2) {
|
||||||
Slog.e(TAG, "Unexpected files in dir: " + dir);
|
Slog.e(TAG, "Unexpected files in dir: " + dir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FontFileInfo fontFileInfo = validateFontFile(files[0]);
|
|
||||||
|
File fontFile;
|
||||||
|
if (files[0].equals(signatureFile)) {
|
||||||
|
fontFile = files[1];
|
||||||
|
} else {
|
||||||
|
fontFile = files[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
FontFileInfo fontFileInfo = validateFontFile(fontFile, signature);
|
||||||
if (fontConfig == null) {
|
if (fontConfig == null) {
|
||||||
fontConfig = getSystemFontConfig();
|
fontConfig = getSystemFontConfig();
|
||||||
}
|
}
|
||||||
@@ -359,9 +386,25 @@ final class UpdatableFontDir {
|
|||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
throw new SystemFontException(
|
throw new SystemFontException(
|
||||||
FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE,
|
FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE,
|
||||||
"Failed to change mode to 711", e);
|
"Failed to change font file mode to 644", e);
|
||||||
}
|
}
|
||||||
FontFileInfo fontFileInfo = validateFontFile(newFontFile);
|
File signatureFile = new File(newDir, FONT_SIGNATURE_FILE);
|
||||||
|
try (FileOutputStream out = new FileOutputStream(signatureFile)) {
|
||||||
|
out.write(pkcs7Signature);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO: Do we need new error code for signature write failure?
|
||||||
|
throw new SystemFontException(
|
||||||
|
FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE,
|
||||||
|
"Failed to write font signature file to storage.", e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Os.chmod(signatureFile.getAbsolutePath(), 0600);
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
throw new SystemFontException(
|
||||||
|
FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE,
|
||||||
|
"Failed to change the signature file mode to 600", e);
|
||||||
|
}
|
||||||
|
FontFileInfo fontFileInfo = validateFontFile(newFontFile, pkcs7Signature);
|
||||||
|
|
||||||
// Try to create Typeface and treat as failure something goes wrong.
|
// Try to create Typeface and treat as failure something goes wrong.
|
||||||
try {
|
try {
|
||||||
@@ -478,8 +521,9 @@ final class UpdatableFontDir {
|
|||||||
* is higher than the currently used font.
|
* is higher than the currently used font.
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private FontFileInfo validateFontFile(File file) throws SystemFontException {
|
private FontFileInfo validateFontFile(File file, byte[] pkcs7Signature)
|
||||||
if (!mFsverityUtil.hasFsverity(file.getAbsolutePath())) {
|
throws SystemFontException {
|
||||||
|
if (!mFsverityUtil.isFromTrustedProvider(file.getAbsolutePath(), pkcs7Signature)) {
|
||||||
throw new SystemFontException(
|
throw new SystemFontException(
|
||||||
FontManager.RESULT_ERROR_VERIFICATION_FAILURE,
|
FontManager.RESULT_ERROR_VERIFICATION_FAILURE,
|
||||||
"Font validation failed. Fs-verity is not enabled: " + file);
|
"Font validation failed. Fs-verity is not enabled: " + file);
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public final class UpdatableFontDirTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasFsverity(String path) {
|
public boolean isFromTrustedProvider(String path, byte[] signature) {
|
||||||
return mHasFsverityPaths.contains(path);
|
return mHasFsverityPaths.contains(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,6 +290,32 @@ public final class UpdatableFontDirTest {
|
|||||||
assertThat(dir.getFontFamilyMap()).isEmpty();
|
assertThat(dir.getFontFamilyMap()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void construct_missingSignatureFile() throws Exception {
|
||||||
|
UpdatableFontDir dirForPreparation = new UpdatableFontDir(
|
||||||
|
mUpdatableFontFilesDir, mParser, mFakeFsverityUtil,
|
||||||
|
mConfigFile, mCurrentTimeSupplier, mConfigSupplier);
|
||||||
|
dirForPreparation.loadFontFileMap();
|
||||||
|
dirForPreparation.update(Arrays.asList(
|
||||||
|
newFontUpdateRequest("foo.ttf,1,foo", GOOD_SIGNATURE)));
|
||||||
|
assertThat(mUpdatableFontFilesDir.list()).hasLength(1);
|
||||||
|
|
||||||
|
// Remove signature file next to the font file.
|
||||||
|
File fontDir = dirForPreparation.getPostScriptMap().get("foo");
|
||||||
|
File sigFile = new File(fontDir.getParentFile(), "font.fsv_sig");
|
||||||
|
assertThat(sigFile.exists()).isTrue();
|
||||||
|
sigFile.delete();
|
||||||
|
|
||||||
|
UpdatableFontDir dir = new UpdatableFontDir(
|
||||||
|
mUpdatableFontFilesDir, mParser, mFakeFsverityUtil,
|
||||||
|
mConfigFile, mCurrentTimeSupplier, mConfigSupplier);
|
||||||
|
dir.loadFontFileMap();
|
||||||
|
// The font file should be removed and should not be loaded.
|
||||||
|
assertThat(dir.getPostScriptMap()).isEmpty();
|
||||||
|
assertThat(mUpdatableFontFilesDir.list()).hasLength(0);
|
||||||
|
assertThat(dir.getFontFamilyMap()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void construct_olderThanPreinstalledFont() throws Exception {
|
public void construct_olderThanPreinstalledFont() throws Exception {
|
||||||
Function<Map<String, File>, FontConfig> configSupplier = (map) -> {
|
Function<Map<String, File>, FontConfig> configSupplier = (map) -> {
|
||||||
@@ -782,8 +808,8 @@ public final class UpdatableFontDirTest {
|
|||||||
UpdatableFontDir.FsverityUtil fakeFsverityUtil = new UpdatableFontDir.FsverityUtil() {
|
UpdatableFontDir.FsverityUtil fakeFsverityUtil = new UpdatableFontDir.FsverityUtil() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasFsverity(String path) {
|
public boolean isFromTrustedProvider(String path, byte[] signature) {
|
||||||
return mFakeFsverityUtil.hasFsverity(path);
|
return mFakeFsverityUtil.isFromTrustedProvider(path, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -373,6 +373,10 @@ public class UpdatableSystemFontTest {
|
|||||||
try (InputStream is = new FileInputStream(certPath)) {
|
try (InputStream is = new FileInputStream(certPath)) {
|
||||||
result = runShellCommand("mini-keyctl padd asymmetric fsv_test .fs-verity", is);
|
result = runShellCommand("mini-keyctl padd asymmetric fsv_test .fs-verity", is);
|
||||||
}
|
}
|
||||||
|
// /data/local/tmp is not readable by system server. Copy a cert file to /data/fonts
|
||||||
|
final String copiedCert = "/data/fonts/debug_cert.der";
|
||||||
|
runShellCommand("cp " + certPath + " " + copiedCert, null);
|
||||||
|
runShellCommand("cmd font install-debug-cert " + copiedCert, null);
|
||||||
// Assert that there are no errors.
|
// Assert that there are no errors.
|
||||||
assertThat(result.second).isEmpty();
|
assertThat(result.second).isEmpty();
|
||||||
String keyId = result.first.trim();
|
String keyId = result.first.trim();
|
||||||
|
|||||||
Reference in New Issue
Block a user