Fix adb backup for encrypted case
New behavior. Backup no longer uses the encryption password. This is in part because that is hard with patterns, in part because it is a security issue - the off line backup is much easier to brute force than the phone. Instead, we simply insist on an encryption password if your device is encrypted and locked. Bug: 17159330 Change-Id: Ia22f84722522abf0b569a3ef1e16ead5527c726d
This commit is contained in:
@@ -44,6 +44,8 @@
|
||||
<string name="backup_enc_password_text">Please enter a password to use for encrypting the full backup data. If this is left blank, your current backup password will be used:</string>
|
||||
<!-- Text for message to user that they may optionally supply an encryption password to use for a full backup operation. -->
|
||||
<string name="backup_enc_password_optional">If you wish to encrypt the full backup data, enter a password below:</string>
|
||||
<!-- Text for message to user that they must supply an encryption password to use for a full backup operation because their phone is locked. -->
|
||||
<string name="backup_enc_password_required">Since your device is encrypted, you are required to encrypt your backup. Please enter a password below:</string>
|
||||
|
||||
<!-- Text for message to user when performing a full restore operation, explaining that they must enter the password originally used to encrypt the full backup data. -->
|
||||
<string name="restore_enc_password_text">If the restore data is encrypted, please enter the password below:</string>
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.storage.IMountService;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.View;
|
||||
@@ -182,25 +183,14 @@ public class BackupRestoreConfirmation extends Activity {
|
||||
// We vary the password prompt depending on whether one is predefined, and whether
|
||||
// the device is encrypted.
|
||||
mIsEncrypted = deviceIsEncrypted();
|
||||
if (mIsEncrypted) {
|
||||
Log.d(TAG, "Device is encrypted: requiring encryption pw");
|
||||
TextView pwPrompt = (TextView) findViewById(R.id.password_desc);
|
||||
// this password is mandatory; we hide the other options during backup
|
||||
if (layoutId == R.layout.confirm_backup) {
|
||||
pwPrompt.setText(R.string.device_encryption_backup_text);
|
||||
TextView tv = (TextView) findViewById(R.id.enc_password);
|
||||
tv.setVisibility(View.GONE);
|
||||
tv = (TextView) findViewById(R.id.enc_password_desc);
|
||||
tv.setVisibility(View.GONE);
|
||||
} else {
|
||||
pwPrompt.setText(R.string.device_encryption_restore_text);
|
||||
}
|
||||
} else if (!haveBackupPassword()) {
|
||||
if (!haveBackupPassword()) {
|
||||
curPwDesc.setVisibility(View.GONE);
|
||||
mCurPassword.setVisibility(View.GONE);
|
||||
if (layoutId == R.layout.confirm_backup) {
|
||||
TextView encPwDesc = (TextView) findViewById(R.id.enc_password_desc);
|
||||
encPwDesc.setText(R.string.backup_enc_password_optional);
|
||||
encPwDesc.setText(mIsEncrypted
|
||||
? R.string.backup_enc_password_required
|
||||
: R.string.backup_enc_password_optional);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,8 +236,7 @@ public class BackupRestoreConfirmation extends Activity {
|
||||
mDidAcknowledge = true;
|
||||
|
||||
try {
|
||||
CharSequence encPassword = (mIsEncrypted)
|
||||
? mCurPassword.getText() : mEncPassword.getText();
|
||||
CharSequence encPassword = mEncPassword.getText();
|
||||
mBackupManager.acknowledgeFullBackupOrRestore(mToken,
|
||||
allow,
|
||||
String.valueOf(mCurPassword.getText()),
|
||||
@@ -261,7 +250,10 @@ public class BackupRestoreConfirmation extends Activity {
|
||||
|
||||
boolean deviceIsEncrypted() {
|
||||
try {
|
||||
return (mMountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE);
|
||||
return mMountService.getEncryptionState()
|
||||
!= IMountService.ENCRYPTION_STATE_NONE
|
||||
&& mMountService.getPasswordType()
|
||||
!= StorageManager.CRYPT_TYPE_DEFAULT;
|
||||
} catch (Exception e) {
|
||||
// If we can't talk to the mount service we have a serious problem; fail
|
||||
// "secure" i.e. assuming that the device is encrypted.
|
||||
|
||||
@@ -75,6 +75,7 @@ import android.os.UserHandle;
|
||||
import android.os.WorkSource;
|
||||
import android.os.Environment.UserEnvironment;
|
||||
import android.os.storage.IMountService;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.provider.Settings;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
@@ -1442,43 +1443,7 @@ public class BackupManagerService extends IBackupManager.Stub {
|
||||
return array;
|
||||
}
|
||||
|
||||
// Backup password management
|
||||
boolean passwordMatchesSaved(String algorithm, String candidatePw, int rounds) {
|
||||
// First, on an encrypted device we require matching the device pw
|
||||
final boolean isEncrypted;
|
||||
try {
|
||||
isEncrypted = (mMountService.getEncryptionState() !=
|
||||
IMountService.ENCRYPTION_STATE_NONE);
|
||||
if (isEncrypted) {
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "Device encrypted; verifying against device data pw");
|
||||
}
|
||||
// 0 means the password validated
|
||||
// -2 means device not encrypted
|
||||
// Any other result is either password failure or an error condition,
|
||||
// so we refuse the match
|
||||
final int result = mMountService.verifyEncryptionPassword(candidatePw);
|
||||
if (result == 0) {
|
||||
if (MORE_DEBUG) Slog.d(TAG, "Pw verifies");
|
||||
return true;
|
||||
} else if (result != -2) {
|
||||
if (MORE_DEBUG) Slog.d(TAG, "Pw mismatch");
|
||||
return false;
|
||||
} else {
|
||||
// ...else the device is supposedly not encrypted. HOWEVER, the
|
||||
// query about the encryption state said that the device *is*
|
||||
// encrypted, so ... we may have a problem. Log it and refuse
|
||||
// the backup.
|
||||
Slog.e(TAG, "verified encryption state mismatch against query; no match allowed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Something went wrong talking to the mount service. This is very bad;
|
||||
// assume that we fail password validation.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mPasswordHash == null) {
|
||||
// no current password case -- require that 'currentPw' be null or empty
|
||||
if (candidatePw == null || "".equals(candidatePw)) {
|
||||
@@ -1583,14 +1548,7 @@ public class BackupManagerService extends IBackupManager.Stub {
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
|
||||
"hasBackupPassword");
|
||||
|
||||
try {
|
||||
return (mMountService.getEncryptionState() != IMountService.ENCRYPTION_STATE_NONE)
|
||||
|| (mPasswordHash != null && mPasswordHash.length() > 0);
|
||||
} catch (Exception e) {
|
||||
// If we can't talk to the mount service we have a serious problem; fail
|
||||
// "secure" i.e. assuming that we require a password
|
||||
return true;
|
||||
}
|
||||
return mPasswordHash != null && mPasswordHash.length() > 0;
|
||||
}
|
||||
|
||||
private boolean backupPasswordMatches(String currentPw) {
|
||||
@@ -3321,6 +3279,20 @@ public class BackupManagerService extends IBackupManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
boolean deviceIsEncrypted() {
|
||||
try {
|
||||
return mMountService.getEncryptionState()
|
||||
!= IMountService.ENCRYPTION_STATE_NONE
|
||||
&& mMountService.getPasswordType()
|
||||
!= StorageManager.CRYPT_TYPE_DEFAULT;
|
||||
} catch (Exception e) {
|
||||
// If we can't talk to the mount service we have a serious problem; fail
|
||||
// "secure" i.e. assuming that the device is encrypted.
|
||||
Slog.e(TAG, "Unable to communicate with mount service: " + e.getMessage());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Full backup task variant used for adb backup
|
||||
class PerformAdbBackupTask extends FullBackupTask {
|
||||
FullBackupEngine mBackupEngine;
|
||||
@@ -3338,7 +3310,7 @@ public class BackupManagerService extends IBackupManager.Stub {
|
||||
ArrayList<String> mPackages;
|
||||
String mCurrentPassword;
|
||||
String mEncryptPassword;
|
||||
|
||||
|
||||
PerformAdbBackupTask(ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
|
||||
boolean includeApks, boolean includeObbs, boolean includeShared,
|
||||
boolean doWidgets, String curPassword, String encryptPassword, boolean doAllApps,
|
||||
@@ -3535,6 +3507,13 @@ public class BackupManagerService extends IBackupManager.Stub {
|
||||
PackageInfo pkg = null;
|
||||
try {
|
||||
boolean encrypting = (mEncryptPassword != null && mEncryptPassword.length() > 0);
|
||||
|
||||
// Only allow encrypted backups of encrypted devices
|
||||
if (deviceIsEncrypted() && !encrypting) {
|
||||
Slog.e(TAG, "Unencrypted backup of encrypted device; aborting");
|
||||
return;
|
||||
}
|
||||
|
||||
OutputStream finalOutput = ofstream;
|
||||
|
||||
// Verify that the given password matches the currently-active
|
||||
@@ -8315,17 +8294,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
|
||||
params.observer = observer;
|
||||
params.curPassword = curPassword;
|
||||
|
||||
boolean isEncrypted;
|
||||
try {
|
||||
isEncrypted = (mMountService.getEncryptionState() !=
|
||||
IMountService.ENCRYPTION_STATE_NONE);
|
||||
if (isEncrypted) Slog.w(TAG, "Device is encrypted; forcing enc password");
|
||||
} catch (RemoteException e) {
|
||||
// couldn't contact the mount service; fail "safe" and assume encryption
|
||||
Slog.e(TAG, "Unable to contact mount service!");
|
||||
isEncrypted = true;
|
||||
}
|
||||
params.encryptPassword = (isEncrypted) ? curPassword : encPpassword;
|
||||
params.encryptPassword = encPpassword;
|
||||
|
||||
if (DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb);
|
||||
mWakelock.acquire();
|
||||
|
||||
Reference in New Issue
Block a user