Fix issue #6295373: "Package com.google.android.apps.authenticator2 has...
...mismatched uid: X on disk, Y in settings" errors on Froyo and Gingerbread Deal more gracefully with the uid changing in three ways: 1. If the uid on disk has become root, then have installd change it to the application's uid. This is to correct a potential case where installd was interrupted while linking or unlinking the libs dir, during which it temporarily changes the owner of the dir to root so that a malicious app can not get in its way. So if the uid on disk has become root, we assume we can safely just change it back to the correct uid. 2. When scaning packages at boot, use the same "delete and rebuild data directory" code for third party applications as we have for system applications. This allows us to at least end up in a state where the app will run, even if its data is lost. 3. But we really don't want to get in to case 2, so if an application update is being installed and we find that the uid we now have for the app is different than the one on disk, fail the update. This will protect against for example a developer changing the sharedUserId of their app and getting into this bad state. Bug: 6295373 Change-Id: Ic802fdd818ac62449ff3c61d1fff1aa4d4942f39
This commit is contained in:
@ -106,6 +106,43 @@ int renamepkg(const char *oldpkgname, const char *newpkgname)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
char pkgdir[PKG_PATH_MAX];
|
||||||
|
struct stat s;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
|
||||||
|
ALOGE("invalid uid/gid: %d %d\n", uid, gid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
|
||||||
|
ALOGE("cannot create package path\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat(pkgdir, &s) < 0) return -1;
|
||||||
|
|
||||||
|
if (s.st_uid != 0 || s.st_gid != 0) {
|
||||||
|
ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chmod(pkgdir, 0751) < 0) {
|
||||||
|
ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
|
||||||
|
unlink(pkgdir);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
if (chown(pkgdir, uid, gid) < 0) {
|
||||||
|
ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
|
||||||
|
unlink(pkgdir);
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int delete_user_data(const char *pkgname, uid_t persona)
|
int delete_user_data(const char *pkgname, uid_t persona)
|
||||||
{
|
{
|
||||||
char pkgdir[PKG_PATH_MAX];
|
char pkgdir[PKG_PATH_MAX];
|
||||||
@ -950,7 +987,7 @@ int linklib(const char* dataDir, const char* asecLibDir)
|
|||||||
out:
|
out:
|
||||||
if (chmod(dataDir, s.st_mode) < 0) {
|
if (chmod(dataDir, s.st_mode) < 0) {
|
||||||
ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
|
ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
|
||||||
return -errno;
|
rc = -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
|
if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
|
||||||
@ -1027,7 +1064,7 @@ int unlinklib(const char* dataDir)
|
|||||||
out:
|
out:
|
||||||
if (chmod(dataDir, s.st_mode) < 0) {
|
if (chmod(dataDir, s.st_mode) < 0) {
|
||||||
ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
|
ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
|
||||||
return -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
|
if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
|
||||||
|
@ -57,6 +57,11 @@ static int do_rename(char **arg, char reply[REPLY_MAX])
|
|||||||
return renamepkg(arg[0], arg[1]); /* oldpkgname, newpkgname */
|
return renamepkg(arg[0], arg[1]); /* oldpkgname, newpkgname */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int do_fixuid(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return fix_uid(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */
|
||||||
|
}
|
||||||
|
|
||||||
static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */
|
static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */
|
||||||
{
|
{
|
||||||
return free_cache((int64_t)atoll(arg[0])); /* free_size */
|
return free_cache((int64_t)atoll(arg[0])); /* free_size */
|
||||||
@ -141,6 +146,7 @@ struct cmdinfo cmds[] = {
|
|||||||
{ "rmdex", 1, do_rm_dex },
|
{ "rmdex", 1, do_rm_dex },
|
||||||
{ "remove", 2, do_remove },
|
{ "remove", 2, do_remove },
|
||||||
{ "rename", 2, do_rename },
|
{ "rename", 2, do_rename },
|
||||||
|
{ "fixuid", 3, do_fixuid },
|
||||||
{ "freecache", 1, do_free_cache },
|
{ "freecache", 1, do_free_cache },
|
||||||
{ "rmcache", 1, do_rm_cache },
|
{ "rmcache", 1, do_rm_cache },
|
||||||
{ "protect", 2, do_protect },
|
{ "protect", 2, do_protect },
|
||||||
|
@ -143,6 +143,7 @@ char *build_string3(char *s1, char *s2, char *s3);
|
|||||||
int install(const char *pkgname, uid_t uid, gid_t gid);
|
int install(const char *pkgname, uid_t uid, gid_t gid);
|
||||||
int uninstall(const char *pkgname, uid_t persona);
|
int uninstall(const char *pkgname, uid_t persona);
|
||||||
int renamepkg(const char *oldpkgname, const char *newpkgname);
|
int renamepkg(const char *oldpkgname, const char *newpkgname);
|
||||||
|
int fix_uid(const char *pkgname, uid_t uid, gid_t gid);
|
||||||
int delete_user_data(const char *pkgname, uid_t persona);
|
int delete_user_data(const char *pkgname, uid_t persona);
|
||||||
int make_user_data(const char *pkgname, uid_t uid, uid_t persona);
|
int make_user_data(const char *pkgname, uid_t uid, uid_t persona);
|
||||||
int delete_persona(uid_t persona);
|
int delete_persona(uid_t persona);
|
||||||
|
@ -519,6 +519,14 @@ public abstract class PackageManager {
|
|||||||
*/
|
*/
|
||||||
public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;
|
public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installation return code: this is passed to the {@link IPackageInstallObserver} by
|
||||||
|
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
|
||||||
|
* the new package is assigned a different UID than it previously held.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static final int INSTALL_FAILED_UID_CHANGED = -24;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
|
* Installation parse return code: this is passed to the {@link IPackageInstallObserver} by
|
||||||
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
|
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
|
||||||
|
@ -243,6 +243,17 @@ class Installer {
|
|||||||
return execute(builder.toString());
|
return execute(builder.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int fixUid(String name, int uid, int gid) {
|
||||||
|
StringBuilder builder = new StringBuilder("fixuid");
|
||||||
|
builder.append(' ');
|
||||||
|
builder.append(name);
|
||||||
|
builder.append(' ');
|
||||||
|
builder.append(uid);
|
||||||
|
builder.append(' ');
|
||||||
|
builder.append(gid);
|
||||||
|
return execute(builder.toString());
|
||||||
|
}
|
||||||
|
|
||||||
public int deleteCacheFiles(String name) {
|
public int deleteCacheFiles(String name) {
|
||||||
StringBuilder builder = new StringBuilder("rmcache");
|
StringBuilder builder = new StringBuilder("rmcache");
|
||||||
builder.append(' ');
|
builder.append(' ');
|
||||||
|
@ -191,6 +191,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
static final int SCAN_NO_PATHS = 1<<5;
|
static final int SCAN_NO_PATHS = 1<<5;
|
||||||
static final int SCAN_UPDATE_TIME = 1<<6;
|
static final int SCAN_UPDATE_TIME = 1<<6;
|
||||||
static final int SCAN_DEFER_DEX = 1<<7;
|
static final int SCAN_DEFER_DEX = 1<<7;
|
||||||
|
static final int SCAN_BOOTING = 1<<8;
|
||||||
|
|
||||||
static final int REMOVE_CHATTY = 1<<16;
|
static final int REMOVE_CHATTY = 1<<16;
|
||||||
|
|
||||||
@ -924,7 +925,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
|
|
||||||
// Set flag to monitor and not change apk file paths when
|
// Set flag to monitor and not change apk file paths when
|
||||||
// scanning install directories.
|
// scanning install directories.
|
||||||
int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX;
|
int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
|
||||||
if (mNoDexOpt) {
|
if (mNoDexOpt) {
|
||||||
Slog.w(TAG, "Running ENG build: no pre-dexopt!");
|
Slog.w(TAG, "Running ENG build: no pre-dexopt!");
|
||||||
scanMode |= SCAN_NO_DEX;
|
scanMode |= SCAN_NO_DEX;
|
||||||
@ -3750,17 +3751,34 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
} else {
|
} else {
|
||||||
// This is a normal package, need to make its data directory.
|
// This is a normal package, need to make its data directory.
|
||||||
dataPath = getDataPathForPackage(pkg.packageName, 0);
|
dataPath = getDataPathForPackage(pkg.packageName, 0);
|
||||||
|
|
||||||
boolean uidError = false;
|
boolean uidError = false;
|
||||||
|
|
||||||
if (dataPath.exists()) {
|
if (dataPath.exists()) {
|
||||||
|
// XXX should really do this check for each user.
|
||||||
mOutPermissions[1] = 0;
|
mOutPermissions[1] = 0;
|
||||||
FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
|
FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
|
||||||
|
|
||||||
// If we have mismatched owners for the data path, we have a problem.
|
// If we have mismatched owners for the data path, we have a problem.
|
||||||
if (mOutPermissions[1] != pkg.applicationInfo.uid) {
|
if (mOutPermissions[1] != pkg.applicationInfo.uid) {
|
||||||
boolean recovered = false;
|
boolean recovered = false;
|
||||||
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
|
if (mOutPermissions[1] == 0) {
|
||||||
|
// The directory somehow became owned by root. Wow.
|
||||||
|
// This is probably because the system was stopped while
|
||||||
|
// installd was in the middle of messing with its libs
|
||||||
|
// directory. Ask installd to fix that.
|
||||||
|
int ret = mInstaller.fixUid(pkgName, pkg.applicationInfo.uid,
|
||||||
|
pkg.applicationInfo.uid);
|
||||||
|
if (ret >= 0) {
|
||||||
|
recovered = true;
|
||||||
|
String msg = "Package " + pkg.packageName
|
||||||
|
+ " unexpectedly changed to uid 0; recovered to " +
|
||||||
|
+ pkg.applicationInfo.uid;
|
||||||
|
reportSettingsProblem(Log.WARN, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!recovered && ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
|
||||||
|
|| (scanMode&SCAN_BOOTING) != 0)) {
|
||||||
// If this is a system app, we can at least delete its
|
// If this is a system app, we can at least delete its
|
||||||
// current data so the application will still work.
|
// current data so the application will still work.
|
||||||
int ret = mInstaller.remove(pkgName, 0);
|
int ret = mInstaller.remove(pkgName, 0);
|
||||||
@ -3769,7 +3787,9 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
// Remove the data directories for all users
|
// Remove the data directories for all users
|
||||||
sUserManager.removePackageForAllUsers(pkgName);
|
sUserManager.removePackageForAllUsers(pkgName);
|
||||||
// Old data gone!
|
// Old data gone!
|
||||||
String msg = "System package " + pkg.packageName
|
String prefix = (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0
|
||||||
|
? "System package " : "Third party package ";
|
||||||
|
String msg = prefix + pkg.packageName
|
||||||
+ " has changed from uid: "
|
+ " has changed from uid: "
|
||||||
+ mOutPermissions[1] + " to "
|
+ mOutPermissions[1] + " to "
|
||||||
+ pkg.applicationInfo.uid + "; old data erased";
|
+ pkg.applicationInfo.uid + "; old data erased";
|
||||||
@ -3781,7 +3801,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
pkg.applicationInfo.uid);
|
pkg.applicationInfo.uid);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
// Ack should not happen!
|
// Ack should not happen!
|
||||||
msg = "System package " + pkg.packageName
|
msg = prefix + pkg.packageName
|
||||||
+ " could not have data directory re-created after delete.";
|
+ " could not have data directory re-created after delete.";
|
||||||
reportSettingsProblem(Log.WARN, msg);
|
reportSettingsProblem(Log.WARN, msg);
|
||||||
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||||
@ -3794,6 +3814,11 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
if (!recovered) {
|
if (!recovered) {
|
||||||
mHasSystemUidErrors = true;
|
mHasSystemUidErrors = true;
|
||||||
}
|
}
|
||||||
|
} else if (!recovered) {
|
||||||
|
// If we allow this install to proceed, we will be broken.
|
||||||
|
// Abort, abort!
|
||||||
|
mLastScanError = PackageManager.INSTALL_FAILED_UID_CHANGED;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
if (!recovered) {
|
if (!recovered) {
|
||||||
pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
|
pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
|
||||||
|
Reference in New Issue
Block a user