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

Commit a3e90798 authored by Kenny Root's avatar Kenny Root
Browse files

Robustly add symlink and add for non-primary users

Amazingly, some apps still don't use the nativeLibraryPath. So add a lib
symlink for non-primary users to fix that.

Also, there was an error when the symlink existed that it would give up.
This shouldn't really happen, but in that case, just remove it and
create a new one to be safe.

Also, move the downgrade code to the appropriate place. This downgrade
case triggered the above symlink existing bug.

Bug: 7318366
Bug: 7371571
Change-Id: Ia175b36d98f00bdc2f2433b909aafd524eb34d15
parent 341aa8e0
Loading
Loading
Loading
Loading
+104 −42
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ int install(const char *pkgname, uid_t uid, gid_t gid)
    char pkgdir[PKG_PATH_MAX];
    char libsymlink[PKG_PATH_MAX];
    char applibdir[PKG_PATH_MAX];
    struct stat libStat;

    if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
        ALOGE("invalid uid/gid: %d %d\n", uid, gid);
@@ -67,6 +68,25 @@ int install(const char *pkgname, uid_t uid, gid_t gid)
        return -1;
    }

    if (lstat(libsymlink, &libStat) < 0) {
        if (errno != ENOENT) {
            ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
            return -1;
        }
    } else {
        if (S_ISDIR(libStat.st_mode)) {
            if (delete_dir_contents(libsymlink, 1, 0) < 0) {
                ALOGE("couldn't delete lib directory during install for: %s", libsymlink);
                return -1;
            }
        } else if (S_ISLNK(libStat.st_mode)) {
            if (unlink(libsymlink) < 0) {
                ALOGE("couldn't unlink lib directory during install for: %s", libsymlink);
                return -1;
            }
        }
    }

    if (symlink(applibdir, libsymlink) < 0) {
        ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, applibdir,
                strerror(errno));
@@ -140,7 +160,7 @@ int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
    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);
        ALOGE("fixing uid of non-root pkg: %s %lu %lu\n", pkgdir, s.st_uid, s.st_gid);
        return -1;
    }

@@ -165,18 +185,30 @@ int delete_user_data(const char *pkgname, uid_t persona)
    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
        return -1;

    /* delete contents, excluding "lib", but not the directory itself */
    return delete_dir_contents(pkgdir, 0, "lib");
    /* delete contents AND directory, no exceptions */
    return delete_dir_contents(pkgdir, 1, NULL);
}

int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
{
    char pkgdir[PKG_PATH_MAX];
    char applibdir[PKG_PATH_MAX];
    char libsymlink[PKG_PATH_MAX];
    struct stat libStat;

    // Create the data dir for the package
    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
        return -1;
    }
    if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, persona)) {
        ALOGE("cannot create package lib symlink origin path\n");
        return -1;
    }
    if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) {
        ALOGE("cannot create package lib symlink dest path\n");
        return -1;
    }

    if (mkdir(pkgdir, 0751) < 0) {
        ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
        return -errno;
@@ -186,8 +218,41 @@ int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
        unlink(pkgdir);
        return -errno;
    }

    if (lstat(libsymlink, &libStat) < 0) {
        if (errno != ENOENT) {
            ALOGE("couldn't stat lib dir for non-primary: %s\n", strerror(errno));
            unlink(pkgdir);
            return -1;
        }
    } else {
        if (S_ISDIR(libStat.st_mode)) {
            if (delete_dir_contents(libsymlink, 1, 0) < 0) {
                ALOGE("couldn't delete lib directory during install for non-primary: %s",
                        libsymlink);
                unlink(pkgdir);
                return -1;
            }
        } else if (S_ISLNK(libStat.st_mode)) {
            if (unlink(libsymlink) < 0) {
                ALOGE("couldn't unlink lib directory during install for non-primary: %s",
                        libsymlink);
                unlink(pkgdir);
                return -1;
            }
        }
    }

    if (symlink(applibdir, libsymlink) < 0) {
        ALOGE("couldn't symlink directory for non-primary '%s' -> '%s': %s\n", libsymlink,
                applibdir, strerror(errno));
        unlink(pkgdir);
        return -1;
    }

    if (chown(pkgdir, uid, uid) < 0) {
        ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
        unlink(libsymlink);
        unlink(pkgdir);
        return -errno;
    }
@@ -195,6 +260,7 @@ int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
#ifdef HAVE_SELINUX
    if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
        ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
        unlink(libsymlink);
        unlink(pkgdir);
        return -errno;
    }
@@ -254,7 +320,7 @@ int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
                /* Get the file stat */
                if (stat(pkg_path, &s) < 0) continue;
                /* Get the uid of the package */
                ALOGI("Adding datadir for uid = %d\n", s.st_uid);
                ALOGI("Adding datadir for uid = %lu\n", s.st_uid);
                uid = (uid_t) s.st_uid % PER_USER_RANGE;
                /* Create the directory for the target */
                make_user_data(name, uid + target_persona * PER_USER_RANGE,
@@ -991,75 +1057,71 @@ done:
    return 0;
}

int linklib(const char* dataDir, const char* asecLibDir)
int linklib(const char* pkgname, const char* asecLibDir, int userId)
{
    char libdir[PKG_PATH_MAX];
    char pkgdir[PKG_PATH_MAX];
    char libsymlink[PKG_PATH_MAX];
    struct stat s, libStat;
    int rc = 0;

    const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
    if (libdirLen >= PKG_PATH_MAX) {
        ALOGE("library dir len too large");
    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userId)) {
        ALOGE("cannot create package path\n");
        return -1;
    }

    if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
        ALOGE("library dir not written successfully: %s\n", strerror(errno));
    if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userId)) {
        ALOGE("cannot create package lib symlink origin path\n");
        return -1;
    }

    if (stat(dataDir, &s) < 0) return -1;
    if (stat(pkgdir, &s) < 0) return -1;

    if (chown(dataDir, AID_INSTALL, AID_INSTALL) < 0) {
        ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
    if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
        ALOGE("failed to chown '%s': %s\n", pkgdir, strerror(errno));
        return -1;
    }

    if (chmod(dataDir, 0700) < 0) {
        ALOGE("linklib() 1: failed to chmod '%s': %s\n", dataDir, strerror(errno));
    if (chmod(pkgdir, 0700) < 0) {
        ALOGE("linklib() 1: failed to chmod '%s': %s\n", pkgdir, strerror(errno));
        rc = -1;
        goto out;
    }

    if (lstat(libdir, &libStat) < 0) {
    if (lstat(libsymlink, &libStat) < 0) {
        if (errno != ENOENT) {
            ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
            rc = -1;
            goto out;
        }

    } else {
        if (S_ISDIR(libStat.st_mode)) {
        if (delete_dir_contents(libdir, 1, 0) < 0) {
            if (delete_dir_contents(libsymlink, 1, 0) < 0) {
                rc = -1;
                goto out;
            }
        } else if (S_ISLNK(libStat.st_mode)) {
        if (unlink(libdir) < 0) {
            if (unlink(libsymlink) < 0) {
                ALOGE("couldn't unlink lib dir: %s\n", strerror(errno));
                rc = -1;
                goto out;
            }
        }

    if (symlink(asecLibDir, libdir) < 0) {
        ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
        rc = -errno;
        goto out;
    }

    if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
        ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
        unlink(libdir);
    if (symlink(asecLibDir, libsymlink) < 0) {
        ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, asecLibDir,
                strerror(errno));
        rc = -errno;
        goto out;
    }

out:
    if (chmod(dataDir, s.st_mode) < 0) {
        ALOGE("linklib() 2: failed to chmod '%s': %s\n", dataDir, strerror(errno));
    if (chmod(pkgdir, s.st_mode) < 0) {
        ALOGE("linklib() 2: failed to chmod '%s': %s\n", pkgdir, strerror(errno));
        rc = -errno;
    }

    if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
        ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
    if (chown(pkgdir, s.st_uid, s.st_gid) < 0) {
        ALOGE("failed to chown '%s' : %s\n", pkgdir, strerror(errno));
        return -errno;
    }

+2 −2
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ static int do_movefiles(char **arg, char reply[REPLY_MAX])

static int do_linklib(char **arg, char reply[REPLY_MAX])
{
    return linklib(arg[0], arg[1]);
    return linklib(arg[0], arg[1], atoi(arg[2]));
}

struct cmdinfo {
@@ -146,7 +146,7 @@ struct cmdinfo cmds[] = {
    { "getsize",              5, do_get_size },
    { "rmuserdata",           2, do_rm_user_data },
    { "movefiles",            0, do_movefiles },
    { "linklib",              2, do_linklib },
    { "linklib",              3, do_linklib },
    { "mkuserdata",           3, do_mk_user_data },
    { "rmuser",               1, do_rm_user },
    { "cloneuserdata",        3, do_clone_user_data },
+2 −1
Original line number Diff line number Diff line
@@ -188,6 +188,7 @@ char *build_string2(char *s1, char *s2);
char *build_string3(char *s1, char *s2, char *s3);

int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
int ensure_media_user_dirs(userid_t userid);

/* commands.c */

@@ -209,4 +210,4 @@ int get_size(const char *pkgname, int persona, const char *apkpath, const char *
int free_cache(int64_t free_size);
int dexopt(const char *apk_path, uid_t uid, int is_public);
int movefiles();
int linklib(const char* target, const char* source);
int linklib(const char* target, const char* source, int userId);
+1 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
     limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.frameworks.coretests.install_loc">
        package="com.android.frameworks.coretests.install_bad_dex">

    <application android:hasCode="true">
        <activity
+15 −12
Original line number Diff line number Diff line
@@ -981,12 +981,14 @@ public class PackageManagerTests extends AndroidTestCase {
        try {
            DeleteObserver observer = new DeleteObserver(pkgName);

            getPm().deletePackage(pkgName, observer, flags);
            getPm().deletePackage(pkgName, observer, flags | PackageManager.DELETE_ALL_USERS);
            observer.waitForCompletion(MAX_WAIT_TIME);

            assertUninstalled(info);

            // Verify we received the broadcast
            // TODO replace this with a CountDownLatch
            synchronized (receiver) {
                long waitTime = 0;
                while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
                    receiver.wait(WAIT_TIME_INCR);
@@ -995,6 +997,7 @@ public class PackageManagerTests extends AndroidTestCase {
                if (!receiver.isDone()) {
                    throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
                }
            }
            return receiver.received;
        } finally {
            mContext.unregisterReceiver(receiver);
@@ -1331,7 +1334,7 @@ public class PackageManagerTests extends AndroidTestCase {
        }

        DeleteObserver observer = new DeleteObserver(packageName);
        getPm().deletePackage(packageName, observer, 0);
        getPm().deletePackage(packageName, observer, PackageManager.DELETE_ALL_USERS);
        observer.waitForCompletion(MAX_WAIT_TIME);

        try {
@@ -1357,7 +1360,7 @@ public class PackageManagerTests extends AndroidTestCase {

            if (info != null) {
                DeleteObserver observer = new DeleteObserver(pkgName);
                getPm().deletePackage(pkgName, observer, 0);
                getPm().deletePackage(pkgName, observer, PackageManager.DELETE_ALL_USERS);
                observer.waitForCompletion(MAX_WAIT_TIME);
                assertUninstalled(info);
            }
@@ -3126,7 +3129,7 @@ public class PackageManagerTests extends AndroidTestCase {
            int rawResId = apk2;
            Uri packageURI = getInstallablePackage(rawResId, outFile);
            PackageParser.Package pkg = parsePackage(packageURI);
            getPm().deletePackage(pkg.packageName, null, 0);
            getPm().deletePackage(pkg.packageName, null, PackageManager.DELETE_ALL_USERS);
            // Check signatures now
            int match = mContext.getPackageManager().checkSignatures(
                    ip1.pkg.packageName, pkg.packageName);
@@ -3265,7 +3268,7 @@ public class PackageManagerTests extends AndroidTestCase {
            PackageManager pm = mContext.getPackageManager();
            // Delete app2
            PackageParser.Package pkg = getParsedPackage(apk2Name, apk2);
            getPm().deletePackage(pkg.packageName, null, 0);
            getPm().deletePackage(pkg.packageName, null, PackageManager.DELETE_ALL_USERS);
            // Check signatures now
            int match = mContext.getPackageManager().checkSignatures(
                    ip1.pkg.packageName, pkg.packageName);
Loading