Merge changes Iab35b4fe,I387ff843,Ib706f0b8,I8f03864a,I0f9041ed, ...
* changes:
Fix bug in directory depth counting.
Otapreopt: Fix property handling
Enable clang-tidy for sensitive domain.
Skip children in fixupAppData() when parent shady.
Fix up error message in installd::prepare_app_cache_dir
Adjust the validation code for secondary dex paths
Drop capabilities in reconcileSecondaryDexFiles
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 33db6db..56470d6 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -4,6 +4,7 @@
cflags: [
"-Wall",
"-Werror",
+ "-Wextra",
],
srcs: [
"CacheItem.cpp",
@@ -25,6 +26,17 @@
],
clang: true,
+
+ tidy: true,
+ tidy_checks: [
+ "-*",
+ "clang-analyzer-security*",
+ "cert-*",
+ "-cert-err58-cpp",
+ ],
+ tidy_flags: [
+ "-warnings-as-errors=clang-analyzer-security*,cert-*"
+ ],
}
//
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 4a93b1f..4246536 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -714,6 +714,9 @@
// Ignore all other GID transitions, since they're kinda shady
LOG(WARNING) << "Ignoring " << p->fts_path << " with unexpected GID " << actual
<< " instead of " << expected;
+ if (!(flags & FLAG_FORCE)) {
+ fts_set(fts, p, FTS_SKIP);
+ }
}
}
}
@@ -1866,7 +1869,7 @@
char boot_marker_path[PKG_PATH_MAX];
sprintf(boot_marker_path,
"%s/%s/%s/.booting",
- android_data_dir.path,
+ android_data_dir.c_str(),
DALVIK_CACHE,
instruction_set);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 8c75ee5..6a7d845 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -41,6 +41,7 @@
#include <system/thread_defs.h>
#include "dexopt.h"
+#include "globals.h"
#include "installd_deps.h"
#include "otapreopt_utils.h"
#include "utils.h"
@@ -156,7 +157,7 @@
int count = 0;
char buf[kPropertyValueMax];
- strncpy(buf, str, sizeof(buf));
+ strlcpy(buf, str, sizeof(buf));
char *pBuf = buf;
while(strtok_r(pBuf, " ", &ctx) != NULL) {
@@ -333,7 +334,8 @@
bool have_dex2oat_compiler_filter_flag = false;
if (skip_compilation) {
- strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract");
+ strlcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract",
+ sizeof(dex2oat_compiler_filter_arg));
have_dex2oat_compiler_filter_flag = true;
have_dex2oat_relocation_skip_flag = true;
} else if (compiler_filter != nullptr) {
@@ -955,14 +957,6 @@
return replace_file_extension(oat_path, ".vdex");
}
-static bool add_extension_to_file_name(char* file_name, const char* extension) {
- if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) {
- return false;
- }
- strcat(file_name, extension);
- return true;
-}
-
static int open_output_file(const char* file_name, bool recreate, int permissions) {
int flags = O_RDWR | O_CREAT;
if (recreate) {
@@ -1198,21 +1192,16 @@
if (!ShouldUseSwapFileForDexopt()) {
return invalid_unique_fd();
}
- // Make sure there really is enough space.
- char swap_file_name[PKG_PATH_MAX];
- strcpy(swap_file_name, out_oat_path);
- if (!add_extension_to_file_name(swap_file_name, ".swap")) {
- return invalid_unique_fd();
- }
+ auto swap_file_name = std::string(out_oat_path) + ".swap";
unique_fd swap_fd(open_output_file(
- swap_file_name, /*recreate*/true, /*permissions*/0600));
+ swap_file_name.c_str(), /*recreate*/true, /*permissions*/0600));
if (swap_fd.get() < 0) {
// Could not create swap file. Optimistically go on and hope that we can compile
// without it.
- ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
+ ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name.c_str());
} else {
// Immediately unlink. We don't really want to hit flash.
- if (unlink(swap_file_name) < 0) {
+ if (unlink(swap_file_name.c_str()) < 0) {
PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
}
}
@@ -1805,8 +1794,14 @@
}
const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+
+ // Note that we cannot validate the package path here because the file might not exist
+ // and we cannot call realpath to resolve system symlinks. Since /data/user/0 symlinks to
+ // /data/data/ a lot of validations will fail if we attempt to check the package path.
+ // It is still ok to be more relaxed because any file removal is done after forking and
+ // dropping capabilities.
if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
- uid, storage_flag)) {
+ uid, storage_flag, /*validate_package_path*/ false)) {
LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
return false;
}
@@ -1820,42 +1815,56 @@
return false;
}
- // The secondary dex does not exist anymore. Clear any generated files.
- char oat_path[PKG_PATH_MAX];
- char oat_dir[PKG_PATH_MAX];
- char oat_isa_dir[PKG_PATH_MAX];
- bool result = true;
- for (size_t i = 0; i < isas.size(); i++) {
- if (!create_secondary_dex_oat_layout(dex_path, isas[i], oat_dir, oat_isa_dir, oat_path)) {
- LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
- result = false;
- continue;
- }
+ // As a security measure we want to unlink art artifacts with the reduced capabilities
+ // of the package user id. So we fork and drop capabilities in the child.
+ pid_t pid = fork();
+ if (pid == 0) {
+ // The secondary dex does not exist anymore. Clear any generated files.
+ char oat_path[PKG_PATH_MAX];
+ char oat_dir[PKG_PATH_MAX];
+ char oat_isa_dir[PKG_PATH_MAX];
+ bool result = true;
+ /* child -- drop privileges before continuing */
+ drop_capabilities(uid);
+ for (size_t i = 0; i < isas.size(); i++) {
+ if (!create_secondary_dex_oat_layout(dex_path,
+ isas[i],
+ oat_dir,
+ oat_isa_dir,
+ oat_path)) {
+ LOG(ERROR) << "Could not create secondary odex layout: "
+ << dex_path;
+ result = false;
+ continue;
+ }
- // Delete oat/vdex/art files.
- result = unlink_if_exists(oat_path) && result;
- result = unlink_if_exists(create_vdex_filename(oat_path)) && result;
- result = unlink_if_exists(create_image_filename(oat_path)) && result;
+ // Delete oat/vdex/art files.
+ result = unlink_if_exists(oat_path) && result;
+ result = unlink_if_exists(create_vdex_filename(oat_path)) && result;
+ result = unlink_if_exists(create_image_filename(oat_path)) && result;
- // Delete profiles.
- std::string current_profile = create_current_profile_path(
+ // Delete profiles.
+ std::string current_profile = create_current_profile_path(
multiuser_get_user_id(uid), dex_path, /*is_secondary*/true);
- std::string reference_profile = create_reference_profile_path(
+ std::string reference_profile = create_reference_profile_path(
dex_path, /*is_secondary*/true);
- result = unlink_if_exists(current_profile) && result;
- result = unlink_if_exists(reference_profile) && result;
+ result = unlink_if_exists(current_profile) && result;
+ result = unlink_if_exists(reference_profile) && result;
- // We upgraded once the location of current profile for secondary dex files.
- // Check for any previous left-overs and remove them as well.
- std::string old_current_profile = dex_path + ".prof";
- result = unlink_if_exists(old_current_profile);
+ // We upgraded once the location of current profile for secondary dex files.
+ // Check for any previous left-overs and remove them as well.
+ std::string old_current_profile = dex_path + ".prof";
+ result = unlink_if_exists(old_current_profile);
- // Try removing the directories as well, they might be empty.
- result = rmdir_if_empty(oat_isa_dir) && result;
- result = rmdir_if_empty(oat_dir) && result;
+ // Try removing the directories as well, they might be empty.
+ result = rmdir_if_empty(oat_isa_dir) && result;
+ result = rmdir_if_empty(oat_dir) && result;
+ }
+ result ? _exit(0) : _exit(1);
}
- return result;
+ int return_code = wait_child(pid);
+ return return_code == 0;
}
// Helper for move_ab, so that we can have common failure-case cleanup.
@@ -2020,5 +2029,98 @@
return return_value_oat && return_value_art && return_value_vdex;
}
+static bool is_absolute_path(const std::string& path) {
+ if (path.find('/') != 0 || path.find("..") != std::string::npos) {
+ LOG(ERROR) << "Invalid absolute path " << path;
+ return false;
+ } else {
+ return true;
+ }
+}
+
+static bool is_valid_instruction_set(const std::string& instruction_set) {
+ // TODO: add explicit whitelisting of instruction sets
+ if (instruction_set.find('/') != std::string::npos) {
+ LOG(ERROR) << "Invalid instruction set " << instruction_set;
+ return false;
+ } else {
+ return true;
+ }
+}
+
+bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
+ const char *apk_path, const char *instruction_set) {
+ std::string oat_dir_ = oat_dir;
+ std::string apk_path_ = apk_path;
+ std::string instruction_set_ = instruction_set;
+
+ if (!is_absolute_path(oat_dir_)) return false;
+ if (!is_absolute_path(apk_path_)) return false;
+ if (!is_valid_instruction_set(instruction_set_)) return false;
+
+ std::string::size_type end = apk_path_.rfind('.');
+ std::string::size_type start = apk_path_.rfind('/', end);
+ if (end == std::string::npos || start == std::string::npos) {
+ LOG(ERROR) << "Invalid apk_path " << apk_path_;
+ return false;
+ }
+
+ std::string res_ = oat_dir_ + '/' + instruction_set + '/'
+ + apk_path_.substr(start + 1, end - start - 1) + ".odex";
+ const char* res = res_.c_str();
+ if (strlen(res) >= PKG_PATH_MAX) {
+ LOG(ERROR) << "Result too large";
+ return false;
+ } else {
+ strlcpy(path, res, PKG_PATH_MAX);
+ return true;
+ }
+}
+
+bool calculate_odex_file_path_default(char path[PKG_PATH_MAX], const char *apk_path,
+ const char *instruction_set) {
+ std::string apk_path_ = apk_path;
+ std::string instruction_set_ = instruction_set;
+
+ if (!is_absolute_path(apk_path_)) return false;
+ if (!is_valid_instruction_set(instruction_set_)) return false;
+
+ std::string::size_type end = apk_path_.rfind('.');
+ std::string::size_type start = apk_path_.rfind('/', end);
+ if (end == std::string::npos || start == std::string::npos) {
+ LOG(ERROR) << "Invalid apk_path " << apk_path_;
+ return false;
+ }
+
+ std::string oat_dir = apk_path_.substr(0, start + 1) + "oat";
+ return calculate_oat_file_path_default(path, oat_dir.c_str(), apk_path, instruction_set);
+}
+
+bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src,
+ const char *instruction_set) {
+ std::string src_ = src;
+ std::string instruction_set_ = instruction_set;
+
+ if (!is_absolute_path(src_)) return false;
+ if (!is_valid_instruction_set(instruction_set_)) return false;
+
+ for (auto it = src_.begin() + 1; it < src_.end(); ++it) {
+ if (*it == '/') {
+ *it = '@';
+ }
+ }
+
+ std::string res_ = android_data_dir + DALVIK_CACHE + '/' + instruction_set_ + src_
+ + DALVIK_CACHE_POSTFIX;
+ const char* res = res_.c_str();
+ if (strlen(res) >= PKG_PATH_MAX) {
+ LOG(ERROR) << "Result too large";
+ return false;
+ } else {
+ strlcpy(path, res, PKG_PATH_MAX);
+ return true;
+ }
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 23446da..1f41e67 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -17,6 +17,8 @@
#ifndef DEXOPT_H_
#define DEXOPT_H_
+#include "installd_constants.h"
+
#include <sys/types.h>
#include <cutils/multiuser.h>
@@ -66,6 +68,15 @@
const char* volume_uuid, const char* class_loader_context, const char* se_info,
bool downgrade);
+bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
+ const char *apk_path, const char *instruction_set);
+
+bool calculate_odex_file_path_default(char path[PKG_PATH_MAX], const char *apk_path,
+ const char *instruction_set);
+
+bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src,
+ const char *instruction_set);
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index edcdb6a..b3a6daf 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -16,15 +16,15 @@
#define LOG_TAG "installd"
-#include <stdlib.h>
-#include <string.h>
-
-#include <log/log.h> // TODO: Move everything to base::logging.
-
#include <globals.h>
#include <installd_constants.h>
#include <utils.h>
+#include <android-base/logging.h>
+
+#include <stdlib.h>
+#include <string.h>
+
namespace android {
namespace installd {
@@ -44,106 +44,78 @@
static constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under
// ANDROID_DATA
-/* Directory records that are used in execution of commands. */
-dir_rec_t android_app_dir;
-dir_rec_t android_app_ephemeral_dir;
-dir_rec_t android_app_lib_dir;
-dir_rec_t android_app_private_dir;
-dir_rec_t android_asec_dir;
-dir_rec_t android_data_dir;
-dir_rec_t android_media_dir;
-dir_rec_t android_mnt_expand_dir;
-dir_rec_t android_profiles_dir;
+std::string android_app_dir;
+std::string android_app_ephemeral_dir;
+std::string android_app_lib_dir;
+std::string android_app_private_dir;
+std::string android_asec_dir;
+std::string android_data_dir;
+std::string android_media_dir;
+std::string android_mnt_expand_dir;
+std::string android_profiles_dir;
+std::string android_root_dir;
-dir_rec_array_t android_system_dirs;
+std::vector<std::string> android_system_dirs;
-/**
- * Initialize all the global variables that are used elsewhere. Returns 0 upon
- * success and -1 on error.
- */
-void free_globals() {
- size_t i;
-
- for (i = 0; i < android_system_dirs.count; i++) {
- if (android_system_dirs.dirs[i].path != NULL) {
- free(android_system_dirs.dirs[i].path);
- }
+bool init_globals_from_data_and_root() {
+ const char* data_path = getenv("ANDROID_DATA");
+ if (data_path == nullptr) {
+ LOG(ERROR) << "Could not find ANDROID_DATA";
+ return false;
}
+ const char* root_path = getenv("ANDROID_ROOT");
+ if (root_path == nullptr) {
+ LOG(ERROR) << "Could not find ANDROID_ROOT";
+ return false;
+ }
+ return init_globals_from_data_and_root(data_path, root_path);
+}
- free(android_system_dirs.dirs);
+static std::string ensure_trailing_slash(const std::string& path) {
+ if (path.rfind('/') != path.size() - 1) {
+ return path + '/';
+ } else {
+ return path;
+ }
}
bool init_globals_from_data_and_root(const char* data, const char* root) {
// Get the android data directory.
- if (get_path_from_string(&android_data_dir, data) < 0) {
- return false;
- }
+ android_data_dir = ensure_trailing_slash(data);
+
+ // Get the android root directory.
+ android_root_dir = ensure_trailing_slash(root);
// Get the android app directory.
- if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) {
- return false;
- }
+ android_app_dir = android_data_dir + APP_SUBDIR;
// Get the android protected app directory.
- if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) {
- return false;
- }
+ android_app_private_dir = android_data_dir + PRIVATE_APP_SUBDIR;
// Get the android ephemeral app directory.
- if (copy_and_append(&android_app_ephemeral_dir, &android_data_dir, EPHEMERAL_APP_SUBDIR) < 0) {
- return false;
- }
+ android_app_ephemeral_dir = android_data_dir + EPHEMERAL_APP_SUBDIR;
// Get the android app native library directory.
- if (copy_and_append(&android_app_lib_dir, &android_data_dir, APP_LIB_SUBDIR) < 0) {
- return false;
- }
+ android_app_lib_dir = android_data_dir + APP_LIB_SUBDIR;
// Get the sd-card ASEC mount point.
- if (get_path_from_env(&android_asec_dir, ASEC_MOUNTPOINT_ENV_NAME) < 0) {
- return false;
- }
+ android_asec_dir = ensure_trailing_slash(getenv(ASEC_MOUNTPOINT_ENV_NAME));
// Get the android media directory.
- if (copy_and_append(&android_media_dir, &android_data_dir, MEDIA_SUBDIR) < 0) {
- return false;
- }
+ android_media_dir = android_data_dir + MEDIA_SUBDIR;
// Get the android external app directory.
- if (get_path_from_string(&android_mnt_expand_dir, "/mnt/expand/") < 0) {
- return false;
- }
+ android_mnt_expand_dir = "/mnt/expand/";
// Get the android profiles directory.
- if (copy_and_append(&android_profiles_dir, &android_data_dir, PROFILES_SUBDIR) < 0) {
- return false;
- }
+ android_profiles_dir = android_data_dir + PROFILES_SUBDIR;
// Take note of the system and vendor directories.
- android_system_dirs.count = 4;
-
- android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
- if (android_system_dirs.dirs == NULL) {
- ALOGE("Couldn't allocate array for dirs; aborting\n");
- return false;
- }
-
- dir_rec_t android_root_dir;
- if (get_path_from_string(&android_root_dir, root) < 0) {
- return false;
- }
-
- android_system_dirs.dirs[0].path = build_string2(android_root_dir.path, APP_SUBDIR);
- android_system_dirs.dirs[0].len = strlen(android_system_dirs.dirs[0].path);
-
- android_system_dirs.dirs[1].path = build_string2(android_root_dir.path, PRIV_APP_SUBDIR);
- android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path);
-
- android_system_dirs.dirs[2].path = strdup("/vendor/app/");
- android_system_dirs.dirs[2].len = strlen(android_system_dirs.dirs[2].path);
-
- android_system_dirs.dirs[3].path = strdup("/oem/app/");
- android_system_dirs.dirs[3].len = strlen(android_system_dirs.dirs[3].path);
+ android_system_dirs.clear();
+ android_system_dirs.push_back(android_root_dir + APP_SUBDIR);
+ android_system_dirs.push_back(android_root_dir + PRIV_APP_SUBDIR);
+ android_system_dirs.push_back("/vendor/app/");
+ android_system_dirs.push_back("/oem/app/");
return true;
}
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index c90beec..633e33b 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -19,40 +19,29 @@
#define GLOBALS_H_
#include <inttypes.h>
+#include <string>
+#include <vector>
namespace android {
namespace installd {
-/* constants */
-
// Name of the environment variable that contains the asec mountpoint.
static constexpr const char* ASEC_MOUNTPOINT_ENV_NAME = "ASEC_MOUNTPOINT";
-/* data structures */
+extern std::string android_app_dir;
+extern std::string android_app_ephemeral_dir;
+extern std::string android_app_lib_dir;
+extern std::string android_app_private_dir;
+extern std::string android_asec_dir;
+extern std::string android_data_dir;
+extern std::string android_media_dir;
+extern std::string android_mnt_expand_dir;
+extern std::string android_profiles_dir;
+extern std::string android_root_dir;
-struct dir_rec_t {
- char* path;
- size_t len;
-};
+extern std::vector<std::string> android_system_dirs;
-struct dir_rec_array_t {
- size_t count;
- dir_rec_t* dirs;
-};
-
-extern dir_rec_t android_app_dir;
-extern dir_rec_t android_app_ephemeral_dir;
-extern dir_rec_t android_app_lib_dir;
-extern dir_rec_t android_app_private_dir;
-extern dir_rec_t android_asec_dir;
-extern dir_rec_t android_data_dir;
-extern dir_rec_t android_media_dir;
-extern dir_rec_t android_mnt_expand_dir;
-extern dir_rec_t android_profiles_dir;
-
-extern dir_rec_array_t android_system_dirs;
-
-void free_globals();
+bool init_globals_from_data_and_root();
bool init_globals_from_data_and_root(const char* data, const char* root);
} // namespace installd
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 35936a2..95ed2ff 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -30,6 +30,7 @@
#include <private/android_filesystem_config.h>
#include "InstalldNativeService.h"
+#include "dexopt.h"
#include "globals.h"
#include "installd_constants.h"
#include "installd_deps.h" // Need to fill in requirements of commands.
@@ -50,133 +51,22 @@
return property_get(key, value, default_value);
}
-// Compute the output path of
-bool calculate_oat_file_path(char path[PKG_PATH_MAX],
- const char *oat_dir,
- const char *apk_path,
- const char *instruction_set) {
- const char *file_name_start;
- const char *file_name_end;
-
- file_name_start = strrchr(apk_path, '/');
- if (file_name_start == NULL) {
- SLOGE("apk_path '%s' has no '/'s in it\n", apk_path);
- return false;
- }
- file_name_end = strrchr(apk_path, '.');
- if (file_name_end < file_name_start) {
- SLOGE("apk_path '%s' has no extension\n", apk_path);
- return false;
- }
-
- // Calculate file_name
- int file_name_len = file_name_end - file_name_start - 1;
- char file_name[file_name_len + 1];
- memcpy(file_name, file_name_start + 1, file_name_len);
- file_name[file_name_len] = '\0';
-
- // <apk_parent_dir>/oat/<isa>/<file_name>.odex
- snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex", oat_dir, instruction_set, file_name);
- return true;
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+ const char *instruction_set) {
+ return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
}
-/*
- * Computes the odex file for the given apk_path and instruction_set.
- * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex
- *
- * Returns false if it failed to determine the odex file path.
- */
-bool calculate_odex_file_path(char path[PKG_PATH_MAX],
- const char *apk_path,
- const char *instruction_set) {
- if (strlen(apk_path) + strlen("oat/") + strlen(instruction_set)
- + strlen("/") + strlen("odex") + 1 > PKG_PATH_MAX) {
- SLOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
- return false;
- }
-
- strcpy(path, apk_path);
- char *end = strrchr(path, '/');
- if (end == NULL) {
- SLOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
- return false;
- }
- const char *apk_end = apk_path + (end - path); // strrchr(apk_path, '/');
-
- strcpy(end + 1, "oat/"); // path = /system/framework/oat/\0
- strcat(path, instruction_set); // path = /system/framework/oat/<isa>\0
- strcat(path, apk_end); // path = /system/framework/oat/<isa>/whatever.jar\0
- end = strrchr(path, '.');
- if (end == NULL) {
- SLOGE("apk_path '%s' has no extension.\n", apk_path);
- return false;
- }
- strcpy(end + 1, "odex");
- return true;
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+ const char *instruction_set) {
+ return calculate_odex_file_path_default(path, apk_path, instruction_set);
}
-bool create_cache_path(char path[PKG_PATH_MAX],
- const char *src,
- const char *instruction_set) {
- /* demand that we are an absolute path */
- if ((src == nullptr) || (src[0] != '/') || strstr(src,"..")) {
- return false;
- }
-
- size_t srclen = strlen(src);
-
- if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
- return false;
- }
-
- size_t dstlen =
- android_data_dir.len +
- strlen(DALVIK_CACHE) +
- 1 +
- strlen(instruction_set) +
- srclen +
- strlen(DALVIK_CACHE_POSTFIX) + 2;
-
- if (dstlen > PKG_PATH_MAX) {
- return false;
- }
-
- sprintf(path,"%s%s/%s/%s",
- android_data_dir.path,
- DALVIK_CACHE,
- instruction_set,
- src + 1 /* skip the leading / */);
-
- char* tmp =
- path +
- android_data_dir.len +
- strlen(DALVIK_CACHE) +
- 1 +
- strlen(instruction_set) + 1;
-
- for(; *tmp; tmp++) {
- if (*tmp == '/') {
- *tmp = '@';
- }
- }
-
- strcat(path, DALVIK_CACHE_POSTFIX);
- return true;
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+ return create_cache_path_default(path, src, instruction_set);
}
static bool initialize_globals() {
- const char* data_path = getenv("ANDROID_DATA");
- if (data_path == nullptr) {
- SLOGE("Could not find ANDROID_DATA");
- return false;
- }
- const char* root_path = getenv("ANDROID_ROOT");
- if (root_path == nullptr) {
- SLOGE("Could not find ANDROID_ROOT");
- return false;
- }
-
- return init_globals_from_data_and_root(data_path, root_path);
+ return init_globals_from_data_and_root();
}
static int initialize_directories() {
@@ -184,7 +74,7 @@
// Read current filesystem layout version to handle upgrade paths
char version_path[PATH_MAX];
- snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path);
+ snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.c_str());
int oldVersion;
if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
@@ -206,7 +96,7 @@
SLOGD("Upgrading to /data/misc/user directories");
char misc_dir[PATH_MAX];
- snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.path);
+ snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.c_str());
char keychain_added_dir[PATH_MAX];
snprintf(keychain_added_dir, PATH_MAX, "%s/keychain/cacerts-added", misc_dir);
@@ -227,7 +117,7 @@
if ((name[1] == '.') && (name[2] == 0)) continue;
}
- uint32_t user_id = atoi(name);
+ uint32_t user_id = std::stoi(name);
// /data/misc/user/<user_id>
if (ensure_config_user_dirs(user_id) == -1) {
@@ -281,7 +171,7 @@
return res;
}
-static int log_callback(int type, const char *fmt, ...) {
+static int log_callback(int type, const char *fmt, ...) { // NOLINT
va_list ap;
int priority;
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 09e1a00..e0d23da 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -146,14 +146,13 @@
return 0;
}
// Copy in the default value.
- strncpy(value, default_value, kPropertyValueMax - 1);
+ strlcpy(value, default_value, kPropertyValueMax - 1);
value[kPropertyValueMax - 1] = 0;
return strlen(default_value);// TODO: Need to truncate?
}
- size_t size = std::min(kPropertyValueMax - 1, prop_value->length());
- strncpy(value, prop_value->data(), size);
- value[size] = 0;
- return static_cast<int>(size);
+ size_t size = std::min(kPropertyValueMax - 1, prop_value->length()) + 1;
+ strlcpy(value, prop_value->data(), size);
+ return static_cast<int>(size - 1);
}
std::string GetOTADataDirectory() const {
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index 34818f6..ca812bd 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -25,6 +25,7 @@
#include <gtest/gtest.h>
#include "InstalldNativeService.h"
+#include "dexopt.h"
#include "globals.h"
#include "utils.h"
@@ -41,25 +42,18 @@
return property_get(key, value, default_value);
}
-bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
- const char *oat_dir ATTRIBUTE_UNUSED,
- const char *apk_path ATTRIBUTE_UNUSED,
- const char *instruction_set ATTRIBUTE_UNUSED) {
- return false;
-}
-
-bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
- const char *apk_path ATTRIBUTE_UNUSED,
- const char *instruction_set ATTRIBUTE_UNUSED) {
- return false;
-}
-
-bool create_cache_path(char path[PKG_PATH_MAX],
- const char *src,
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
const char *instruction_set) {
- // Not really a valid path but it's good enough for testing.
- sprintf(path,"/data/dalvik-cache/%s/%s", instruction_set, src);
- return true;
+ return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char *apk_path,
+ const char *instruction_set) {
+ return calculate_odex_file_path_default(path, apk_path, instruction_set);
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set) {
+ return create_cache_path_default(path, src, instruction_set);
}
static void mkdir(const char* path, uid_t owner, gid_t group, mode_t mode) {
@@ -102,6 +96,8 @@
testUuid = std::make_unique<std::string>();
*testUuid = std::string(kTestUuid);
system("mkdir -p /data/local/tmp/user/0");
+
+ init_globals_from_data_and_root();
}
virtual void TearDown() {
@@ -153,12 +149,28 @@
EXPECT_EQ(10000, stat_gid("com.example/bar/file"));
}
-TEST_F(ServiceTest, RmDexNoDalvikCache) {
- LOG(INFO) << "RmDexNoDalvikCache";
+TEST_F(ServiceTest, CalculateOat) {
+ char buf[PKG_PATH_MAX];
- // Try to remove a non existing dalvik cache dex. The call should be
- // successful because there's nothing to remove.
- EXPECT_TRUE(service->rmdex("com.example", "arm").isOk());
+ EXPECT_TRUE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file.apk", "isa"));
+ EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
+
+ EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "/path/to/file", "isa"));
+ EXPECT_FALSE(calculate_oat_file_path(buf, "/path/to/oat", "file", "isa"));
+}
+
+TEST_F(ServiceTest, CalculateOdex) {
+ char buf[PKG_PATH_MAX];
+
+ EXPECT_TRUE(calculate_odex_file_path(buf, "/path/to/file.apk", "isa"));
+ EXPECT_EQ("/path/to/oat/isa/file.odex", std::string(buf));
+}
+
+TEST_F(ServiceTest, CalculateCache) {
+ char buf[PKG_PATH_MAX];
+
+ EXPECT_TRUE(create_cache_path(buf, "/path/to/file.apk", "isa"));
+ EXPECT_EQ("/data/dalvik-cache/isa/path@to@file.apk@classes.dex", std::string(buf));
}
} // namespace installd
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 46ed85f..2ca7ac2 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -17,6 +17,7 @@
#include <stdlib.h>
#include <string.h>
+#include <android-base/logging.h>
#include <gtest/gtest.h>
#include "InstalldNativeService.h"
@@ -27,6 +28,7 @@
#define LOG_TAG "utils_test"
#define TEST_DATA_DIR "/data/"
+#define TEST_ROOT_DIR "/system/"
#define TEST_APP_DIR "/data/app/"
#define TEST_APP_PRIVATE_DIR "/data/app-private/"
#define TEST_APP_EPHEMERAL_DIR "/data/app-ephemeral/"
@@ -44,39 +46,13 @@
class UtilsTest : public testing::Test {
protected:
virtual void SetUp() {
- android_app_dir.path = (char*) TEST_APP_DIR;
- android_app_dir.len = strlen(TEST_APP_DIR);
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(nullptr);
- android_app_private_dir.path = (char*) TEST_APP_PRIVATE_DIR;
- android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR);
-
- android_app_ephemeral_dir.path = (char*) TEST_APP_EPHEMERAL_DIR;
- android_app_ephemeral_dir.len = strlen(TEST_APP_EPHEMERAL_DIR);
-
- android_data_dir.path = (char*) TEST_DATA_DIR;
- android_data_dir.len = strlen(TEST_DATA_DIR);
-
- android_asec_dir.path = (char*) TEST_ASEC_DIR;
- android_asec_dir.len = strlen(TEST_ASEC_DIR);
-
- android_mnt_expand_dir.path = (char*) TEST_EXPAND_DIR;
- android_mnt_expand_dir.len = strlen(TEST_EXPAND_DIR);
-
- android_system_dirs.count = 2;
-
- android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
- android_system_dirs.dirs[0].path = (char*) TEST_SYSTEM_DIR1;
- android_system_dirs.dirs[0].len = strlen(TEST_SYSTEM_DIR1);
-
- android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2;
- android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2);
-
- android_profiles_dir.path = (char*) TEST_PROFILE_DIR;
- android_profiles_dir.len = strlen(TEST_PROFILE_DIR);
+ init_globals_from_data_and_root(TEST_DATA_DIR, TEST_ROOT_DIR);
}
virtual void TearDown() {
- free(android_system_dirs.dirs);
}
std::string create_too_long_path(const std::string& seed) {
@@ -192,12 +168,6 @@
<< badasec1 << " should be rejected as a invalid path";
}
-TEST_F(UtilsTest, IsValidApkPath_DoubleSlashFail) {
- const char *badasec2 = TEST_ASEC_DIR "com.example.asec//pkg.apk";
- EXPECT_EQ(-1, validate_apk_path(badasec2))
- << badasec2 << " should be rejected as a invalid path";
-}
-
TEST_F(UtilsTest, IsValidApkPath_SubdirEscapeFail) {
const char *badasec3 = TEST_ASEC_DIR "com.example.asec/../../../pkg.apk";
EXPECT_EQ(-1, validate_apk_path(badasec3))
@@ -276,184 +246,6 @@
<< badapp2 << " should be rejected not a system path";
}
-TEST_F(UtilsTest, GetPathFromString_NullPathFail) {
- dir_rec_t test1;
- EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL))
- << "Should not allow NULL as a path.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_EmptyPathFail) {
- dir_rec_t test1;
- EXPECT_EQ(-1, get_path_from_string(&test1, ""))
- << "Should not allow empty paths.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_RelativePathFail) {
- dir_rec_t test1;
- EXPECT_EQ(-1, get_path_from_string(&test1, "mnt/asec"))
- << "Should not allow relative paths.";
-}
-
-TEST_F(UtilsTest, GetPathFromString_NonCanonical) {
- dir_rec_t test1;
-
- EXPECT_EQ(0, get_path_from_string(&test1, "/mnt/asec"))
- << "Should be able to canonicalize directory /mnt/asec";
- EXPECT_STREQ("/mnt/asec/", test1.path)
- << "/mnt/asec should be canonicalized to /mnt/asec/";
- EXPECT_EQ(10, (ssize_t) test1.len)
- << "path len should be equal to the length of /mnt/asec/ (10)";
- free(test1.path);
-}
-
-TEST_F(UtilsTest, GetPathFromString_CanonicalPath) {
- dir_rec_t test3;
- EXPECT_EQ(0, get_path_from_string(&test3, "/data/app/"))
- << "Should be able to canonicalize directory /data/app/";
- EXPECT_STREQ("/data/app/", test3.path)
- << "/data/app/ should be canonicalized to /data/app/";
- EXPECT_EQ(10, (ssize_t) test3.len)
- << "path len should be equal to the length of /data/app/ (10)";
- free(test3.path);
-}
-
-TEST_F(UtilsTest, CreatePkgPath_LongPkgNameSuccess) {
- char path[PKG_PATH_MAX];
-
- // Create long packagename of "aaaaa..."
- size_t pkgnameSize = PKG_NAME_MAX;
- char pkgname[pkgnameSize + 1];
- memset(pkgname, 'a', pkgnameSize);
- pkgname[1] = '.';
- pkgname[pkgnameSize] = '\0';
-
- EXPECT_EQ(0, create_pkg_path(path, pkgname, "", 0))
- << "Should successfully be able to create package name.";
-
- std::string prefix = std::string(TEST_DATA_DIR) + PRIMARY_USER_PREFIX;
- size_t offset = prefix.length();
-
- EXPECT_STREQ(pkgname, path + offset)
- << "Package path should be a really long string of a's";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_LongPostfixFail) {
- char path[PKG_PATH_MAX];
-
- // Create long packagename of "aaaaa..."
- size_t postfixSize = PKG_PATH_MAX;
- char postfix[postfixSize + 1];
- memset(postfix, 'a', postfixSize);
- postfix[postfixSize] = '\0';
-
- EXPECT_EQ(-1, create_pkg_path(path, "com.example.package", postfix, 0))
- << "Should return error because postfix is too long.";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_PrimaryUser) {
- char path[PKG_PATH_MAX];
-
- EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 0))
- << "Should return error because postfix is too long.";
-
- std::string p = std::string(TEST_DATA_DIR)
- + PRIMARY_USER_PREFIX
- + "com.example.package";
- EXPECT_STREQ(p.c_str(), path)
- << "Package path should be in /data/data/";
-}
-
-TEST_F(UtilsTest, CreatePkgPath_SecondaryUser) {
- char path[PKG_PATH_MAX];
-
- EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 1))
- << "Should successfully create package path.";
-
- std::string p = std::string(TEST_DATA_DIR)
- + SECONDARY_USER_PREFIX
- + "1/com.example.package";
- EXPECT_STREQ(p.c_str(), path)
- << "Package path should be in /data/user/";
-}
-
-TEST_F(UtilsTest, CreateMovePath_Primary) {
- char path[PKG_PATH_MAX];
-
- EXPECT_EQ(0, create_move_path(path, "com.android.test", "shared_prefs", 0))
- << "Should be able to create move path for primary user";
-
- EXPECT_STREQ("/data/data/com.android.test/shared_prefs", path)
- << "Primary user package directory should be created correctly";
-}
-
-
-TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) {
- char path[PKG_PATH_MAX];
- std::string really_long_app_name = create_too_long_path("com.example");
- EXPECT_EQ(-1, create_move_path(path, really_long_app_name.c_str(), "shared_prefs", 0))
- << "Should fail to create move path for primary user";
-}
-
-TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) {
- char path[PKG_PATH_MAX];
- std::string really_long_leaf_name = create_too_long_path("leaf_");
- EXPECT_EQ(-1, create_move_path(path, "com.android.test", really_long_leaf_name.c_str(), 0))
- << "Should fail to create move path for primary user";
-}
-
-TEST_F(UtilsTest, CopyAndAppend_Normal) {
- //int copy_and_append(dir_rec_t* dst, dir_rec_t* src, char* suffix)
- dir_rec_t dst;
- dir_rec_t src;
-
- src.path = (char*) "/data/";
- src.len = strlen(src.path);
-
- EXPECT_EQ(0, copy_and_append(&dst, &src, "app/"))
- << "Should return error because postfix is too long.";
-
- EXPECT_STREQ("/data/app/", dst.path)
- << "Appended path should be correct";
-
- EXPECT_EQ(10, (ssize_t) dst.len)
- << "Appended path should be length of '/data/app/' (10)";
-}
-
-TEST_F(UtilsTest, AppendAndIncrement_Normal) {
- size_t dst_size = 10;
- char dst[dst_size];
- char *dstp = dst;
- const char* src = "FOO";
-
- EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
- << "String should append successfully";
-
- EXPECT_STREQ("FOO", dst)
- << "String should append correctly";
-
- EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
- << "String should append successfully again";
-
- EXPECT_STREQ("FOOFOO", dst)
- << "String should append correctly again";
-}
-
-TEST_F(UtilsTest, AppendAndIncrement_TooBig) {
- size_t dst_size = 5;
- char dst[dst_size];
- char *dstp = dst;
- const char* src = "FOO";
-
- EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
- << "String should append successfully";
-
- EXPECT_STREQ("FOO", dst)
- << "String should append correctly";
-
- EXPECT_EQ(-1, append_and_increment(&dstp, src, &dst_size))
- << "String should fail because it's too large to fit";
-}
-
TEST_F(UtilsTest, CreateDataPath) {
EXPECT_EQ("/data", create_data_path(nullptr));
EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b",
@@ -653,5 +445,29 @@
package_name, app_dir_ce_user_10 + "/" + too_long, app_uid_for_user_10, FLAG_STORAGE_CE);
}
+TEST_F(UtilsTest, ValidateApkPath) {
+ EXPECT_EQ(0, validate_apk_path("/data/app/com.example"));
+ EXPECT_EQ(0, validate_apk_path("/data/app/com.example/file"));
+ EXPECT_EQ(0, validate_apk_path("/data/app/com.example//file"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/file"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/file"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir//file"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/dir/file"));
+ EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/dir//file"));
+}
+
+TEST_F(UtilsTest, ValidateApkPathSubdirs) {
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/file"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example//file"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/file"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/file"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir//file"));
+ EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/file"));
+ EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir//file"));
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 462d004..ca0a82e 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -129,24 +129,6 @@
create_data_user_de_path(volume_uuid, user).c_str(), package_name);
}
-int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
- const char *postfix, userid_t userid) {
- if (!is_valid_package_name(pkgname)) {
- path[0] = '\0';
- return -1;
- }
-
- std::string _tmp(create_data_user_ce_package_path(nullptr, userid, pkgname) + postfix);
- const char* tmp = _tmp.c_str();
- if (strlen(tmp) >= PKG_PATH_MAX) {
- path[0] = '\0';
- return -1;
- } else {
- strcpy(path, tmp);
- return 0;
- }
-}
-
std::string create_data_path(const char* volume_uuid) {
if (volume_uuid == nullptr) {
return "/data";
@@ -213,7 +195,7 @@
}
std::string create_primary_cur_profile_dir_path(userid_t userid) {
- return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
+ return StringPrintf("%s/cur/%u", android_profiles_dir.c_str(), userid);
}
std::string create_primary_current_profile_package_dir_path(userid_t user,
@@ -224,12 +206,12 @@
}
std::string create_primary_ref_profile_dir_path() {
- return StringPrintf("%s/ref", android_profiles_dir.path);
+ return StringPrintf("%s/ref", android_profiles_dir.c_str());
}
std::string create_primary_reference_profile_package_dir_path(const std::string& package_name) {
check_package_name(package_name.c_str());
- return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name.c_str());
+ return StringPrintf("%s/ref/%s", android_profiles_dir.c_str(), package_name.c_str());
}
std::string create_data_dalvik_cache_path() {
@@ -378,20 +360,6 @@
return 0;
}
-int create_move_path(char path[PKG_PATH_MAX],
- const char* pkgname,
- const char* leaf,
- userid_t userid ATTRIBUTE_UNUSED)
-{
- if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
- >= PKG_PATH_MAX) {
- return -1;
- }
-
- sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
- return 0;
-}
-
/**
* Checks whether the package name is valid. Returns -1 on error and
* 0 on success.
@@ -767,22 +735,36 @@
* The path is allowed to have at most one subdirectory and no indirections
* to top level directories (i.e. have "..").
*/
-static int validate_path(const dir_rec_t* dir, const char* path, int maxSubdirs) {
- size_t dir_len = dir->len;
- const char* subdir = strchr(path + dir_len, '/');
-
- // Only allow the path to have at most one subdirectory.
- if (subdir != NULL) {
- ++subdir;
- if ((--maxSubdirs == 0) && strchr(subdir, '/') != NULL) {
- ALOGE("invalid apk path '%s' (subdir?)\n", path);
- return -1;
- }
+static int validate_path(const std::string& dir, const std::string& path, int maxSubdirs) {
+ // Argument sanity checking
+ if (dir.find('/') != 0 || dir.rfind('/') != dir.size() - 1
+ || dir.find("..") != std::string::npos) {
+ LOG(ERROR) << "Invalid directory " << dir;
+ return -1;
+ }
+ if (path.find("..") != std::string::npos) {
+ LOG(ERROR) << "Invalid path " << path;
+ return -1;
}
- // Directories can't have a period directly after the directory markers to prevent "..".
- if ((path[dir_len] == '.') || ((subdir != NULL) && (*subdir == '.'))) {
- ALOGE("invalid apk path '%s' (trickery)\n", path);
+ if (path.compare(0, dir.size(), dir) != 0) {
+ // Common case, path isn't under directory
+ return -1;
+ }
+
+ // Count number of subdirectories
+ auto pos = path.find('/', dir.size());
+ int count = 0;
+ while (pos != std::string::npos) {
+ auto next = path.find('/', pos + 1);
+ if (next > pos + 1) {
+ count++;
+ }
+ pos = next;
+ }
+
+ if (count > maxSubdirs) {
+ LOG(ERROR) << "Invalid path depth " << path << " when tested against " << dir;
return -1;
}
@@ -794,20 +776,17 @@
* if it is a system app or -1 if it is not.
*/
int validate_system_app_path(const char* path) {
- size_t i;
-
- for (i = 0; i < android_system_dirs.count; i++) {
- const size_t dir_len = android_system_dirs.dirs[i].len;
- if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) {
- return validate_path(android_system_dirs.dirs + i, path, 1);
+ std::string path_ = path;
+ for (const auto& dir : android_system_dirs) {
+ if (validate_path(dir, path, 1) == 0) {
+ return 0;
}
}
-
return -1;
}
bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
- const char* volume_uuid, int uid, int storage_flag) {
+ const char* volume_uuid, int uid, int storage_flag, bool validate_package_path) {
CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE);
// Empty paths are not allowed.
@@ -821,15 +800,18 @@
// The path should be at most PKG_PATH_MAX long.
if (dex_path.size() > PKG_PATH_MAX) { return false; }
- // The dex_path should be under the app data directory.
- std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
- ? create_data_user_ce_package_path(
- volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
- : create_data_user_de_package_path(
- volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
+ if (validate_package_path) {
+ // If we are asked to validate the package path check that
+ // the dex_path is under the app data directory.
+ std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
+ ? create_data_user_ce_package_path(
+ volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
+ : create_data_user_de_package_path(
+ volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
- if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) {
- return false;
+ if (strncmp(dex_path.c_str(), app_private_dir.c_str(), app_private_dir.size()) != 0) {
+ return false;
+ }
}
// If we got here we have a valid path.
@@ -837,116 +819,26 @@
}
/**
- * Get the contents of a environment variable that contains a path. Caller
- * owns the string that is inserted into the directory record. Returns
- * 0 on success and -1 on error.
- */
-int get_path_from_env(dir_rec_t* rec, const char* var) {
- const char* path = getenv(var);
- int ret = get_path_from_string(rec, path);
- if (ret < 0) {
- ALOGW("Problem finding value for environment variable %s\n", var);
- }
- return ret;
-}
-
-/**
- * Puts the string into the record as a directory. Appends '/' to the end
- * of all paths. Caller owns the string that is inserted into the directory
- * record. A null value will result in an error.
- *
- * Returns 0 on success and -1 on error.
- */
-int get_path_from_string(dir_rec_t* rec, const char* path) {
- if (path == NULL) {
- return -1;
- } else {
- const size_t path_len = strlen(path);
- if (path_len <= 0) {
- return -1;
- }
-
- // Make sure path is absolute.
- if (path[0] != '/') {
- return -1;
- }
-
- if (path[path_len - 1] == '/') {
- // Path ends with a forward slash. Make our own copy.
-
- rec->path = strdup(path);
- if (rec->path == NULL) {
- return -1;
- }
-
- rec->len = path_len;
- } else {
- // Path does not end with a slash. Generate a new string.
- char *dst;
-
- // Add space for slash and terminating null.
- size_t dst_size = path_len + 2;
-
- rec->path = (char*) malloc(dst_size);
- if (rec->path == NULL) {
- return -1;
- }
-
- dst = rec->path;
-
- if (append_and_increment(&dst, path, &dst_size) < 0
- || append_and_increment(&dst, "/", &dst_size)) {
- ALOGE("Error canonicalizing path");
- return -1;
- }
-
- rec->len = dst - rec->path;
- }
- }
- return 0;
-}
-
-int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
- dst->len = src->len + strlen(suffix);
- const size_t dstSize = dst->len + 1;
- dst->path = (char*) malloc(dstSize);
-
- if (dst->path == NULL
- || snprintf(dst->path, dstSize, "%s%s", src->path, suffix)
- != (ssize_t) dst->len) {
- ALOGE("Could not allocate memory to hold appended path; aborting\n");
- return -1;
- }
-
- return 0;
-}
-
-/**
* Check whether path points to a valid path for an APK file. The path must
* begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within
* that path. Returns -1 when an invalid path is encountered and 0 when a valid path
* is encountered.
*/
static int validate_apk_path_internal(const char *path, int maxSubdirs) {
- const dir_rec_t* dir = NULL;
- if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
- dir = &android_app_dir;
- } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
- dir = &android_app_private_dir;
- } else if (!strncmp(path, android_app_ephemeral_dir.path, android_app_ephemeral_dir.len)) {
- dir = &android_app_ephemeral_dir;
- } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) {
- dir = &android_asec_dir;
- } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) {
- dir = &android_mnt_expand_dir;
- if (maxSubdirs < 2) {
- maxSubdirs = 2;
- }
+ std::string path_ = path;
+ if (validate_path(android_app_dir, path_, maxSubdirs) == 0) {
+ return 0;
+ } else if (validate_path(android_app_private_dir, path_, maxSubdirs) == 0) {
+ return 0;
+ } else if (validate_path(android_app_ephemeral_dir, path_, maxSubdirs) == 0) {
+ return 0;
+ } else if (validate_path(android_asec_dir, path_, maxSubdirs) == 0) {
+ return 0;
+ } else if (validate_path(android_mnt_expand_dir, path_, std::max(maxSubdirs, 2)) == 0) {
+ return 0;
} else {
return -1;
}
-
- return validate_path(dir, path, maxSubdirs);
}
int validate_apk_path(const char* path) {
@@ -957,48 +849,6 @@
return validate_apk_path_internal(path, 3 /* maxSubdirs */);
}
-int append_and_increment(char** dst, const char* src, size_t* dst_size) {
- ssize_t ret = strlcpy(*dst, src, *dst_size);
- if (ret < 0 || (size_t) ret >= *dst_size) {
- return -1;
- }
- *dst += ret;
- *dst_size -= ret;
- return 0;
-}
-
-char *build_string2(const char *s1, const char *s2) {
- if (s1 == NULL || s2 == NULL) return NULL;
-
- int len_s1 = strlen(s1);
- int len_s2 = strlen(s2);
- int len = len_s1 + len_s2 + 1;
- char *result = (char *) malloc(len);
- if (result == NULL) return NULL;
-
- strcpy(result, s1);
- strcpy(result + len_s1, s2);
-
- return result;
-}
-
-char *build_string3(const char *s1, const char *s2, const char *s3) {
- if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL;
-
- int len_s1 = strlen(s1);
- int len_s2 = strlen(s2);
- int len_s3 = strlen(s3);
- int len = len_s1 + len_s2 + len_s3 + 1;
- char *result = (char *) malloc(len);
- if (result == NULL) return NULL;
-
- strcpy(result, s1);
- strcpy(result + len_s1, s2);
- strcpy(result + len_s1 + len_s2, s3);
-
- return result;
-}
-
int ensure_config_user_dirs(userid_t userid) {
// writable by system, readable by any app within the same user
const int uid = multiuser_get_uid(userid, AID_SYSTEM);
@@ -1071,7 +921,7 @@
} else {
// Mismatched GID/mode is recoverable; fall through to update
LOG(DEBUG) << "Mismatched cache GID/mode at " << path << ": found " << st.st_gid
- << " but expected " << gid;
+ << "/" << actual_mode << " but expected " << gid << "/" << target_mode;
}
// Directory is owned correctly, but GID or mode mismatch means it's
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 2a760d4..3e04af9 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -41,18 +41,11 @@
namespace android {
namespace installd {
-struct dir_rec_t;
-
constexpr const char* kXattrInodeCache = "user.inode_cache";
constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
constexpr const char* kXattrCacheGroup = "user.cache_group";
constexpr const char* kXattrCacheTombstone = "user.cache_tombstone";
-int create_pkg_path(char path[PKG_PATH_MAX],
- const char *pkgname,
- const char *postfix,
- userid_t userid);
-
std::string create_data_path(const char* volume_uuid);
std::string create_data_app_path(const char* volume_uuid);
@@ -96,11 +89,6 @@
int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
-int create_move_path(char path[PKG_PATH_MAX],
- const char* pkgname,
- const char* leaf,
- userid_t userid);
-
bool is_valid_filename(const std::string& name);
bool is_valid_package_name(const std::string& packageName);
@@ -126,22 +114,11 @@
int validate_system_app_path(const char* path);
bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
- const char* volume_uuid, int uid, int storage_flag);
-
-int get_path_from_env(dir_rec_t* rec, const char* var);
-
-int get_path_from_string(dir_rec_t* rec, const char* path);
-
-int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix);
+ const char* volume_uuid, int uid, int storage_flag, bool validate_package_path = true);
int validate_apk_path(const char *path);
int validate_apk_path_subdirs(const char *path);
-int append_and_increment(char** dst, const char* src, size_t* dst_size);
-
-char *build_string2(const char *s1, const char *s2);
-char *build_string3(const char *s1, const char *s2, const char *s3);
-
int ensure_config_user_dirs(userid_t userid);
int wait_child(pid_t pid);