Fix more buffer overruns.
Also add some tests.
Bug: 20323050
Change-Id: I9eaf3dc04efd85206663c4cca4f8c1208620a89a
diff --git a/Android.mk b/Android.mk
index c6b0084..3b8972e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -21,6 +21,7 @@
adb_auth.cpp \
adb_io.cpp \
adb_listeners.cpp \
+ adb_utils.cpp \
sockets.cpp \
transport.cpp \
transport_local.cpp \
@@ -82,6 +83,7 @@
LIBADB_TEST_SRCS := \
adb_io_test.cpp \
+ adb_utils_test.cpp \
transport_test.cpp \
include $(CLEAR_VARS)
diff --git a/adb_utils.cpp b/adb_utils.cpp
new file mode 100644
index 0000000..5a6ac33
--- /dev/null
+++ b/adb_utils.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb_utils.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+bool directory_exists(const std::string& path) {
+ struct stat sb;
+ return lstat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode);
+}
+
+static bool should_escape(const char c) {
+ return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')');
+}
+
+std::string escape_arg(const std::string& s) {
+ // Preserve empty arguments.
+ if (s.empty()) return "\"\"";
+
+ std::string result(s);
+ for (auto it = result.begin(); it != result.end(); ++it) {
+ if (should_escape(*it)) {
+ it = result.insert(it, '\\') + 1;
+ }
+ }
+ return result;
+}
diff --git a/adb_utils.h b/adb_utils.h
new file mode 100644
index 0000000..ec8e8b5
--- /dev/null
+++ b/adb_utils.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ADB_UTILS_H_
+#define _ADB_UTILS_H_
+
+#include <string>
+
+bool directory_exists(const std::string& path);
+
+std::string escape_arg(const std::string& s);
+
+#endif
diff --git a/adb_utils_test.cpp b/adb_utils_test.cpp
new file mode 100644
index 0000000..95e28a8
--- /dev/null
+++ b/adb_utils_test.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb_utils.h"
+
+#include <gtest/gtest.h>
+
+TEST(adb_utils, directory_exists) {
+ ASSERT_TRUE(directory_exists("/proc"));
+ ASSERT_FALSE(directory_exists("/proc/self")); // Symbolic link.
+ ASSERT_FALSE(directory_exists("/proc/does-not-exist"));
+}
+
+TEST(adb_utils, escape_arg) {
+ ASSERT_EQ(R"("")", escape_arg(""));
+
+ ASSERT_EQ(R"(abc)", escape_arg("abc"));
+
+ ASSERT_EQ(R"(\ abc)", escape_arg(" abc"));
+ ASSERT_EQ(R"(\'abc)", escape_arg("'abc"));
+ ASSERT_EQ(R"(\"abc)", escape_arg("\"abc"));
+ ASSERT_EQ(R"(\\abc)", escape_arg("\\abc"));
+ ASSERT_EQ(R"(\(abc)", escape_arg("(abc"));
+ ASSERT_EQ(R"(\)abc)", escape_arg(")abc"));
+
+ ASSERT_EQ(R"(abc\ abc)", escape_arg("abc abc"));
+ ASSERT_EQ(R"(abc\'abc)", escape_arg("abc'abc"));
+ ASSERT_EQ(R"(abc\"abc)", escape_arg("abc\"abc"));
+ ASSERT_EQ(R"(abc\\abc)", escape_arg("abc\\abc"));
+ ASSERT_EQ(R"(abc\(abc)", escape_arg("abc(abc"));
+ ASSERT_EQ(R"(abc\)abc)", escape_arg("abc)abc"));
+
+ ASSERT_EQ(R"(abc\ )", escape_arg("abc "));
+ ASSERT_EQ(R"(abc\')", escape_arg("abc'"));
+ ASSERT_EQ(R"(abc\")", escape_arg("abc\""));
+ ASSERT_EQ(R"(abc\\)", escape_arg("abc\\"));
+ ASSERT_EQ(R"(abc\()", escape_arg("abc("));
+ ASSERT_EQ(R"(abc\))", escape_arg("abc)"));
+}
diff --git a/commandline.cpp b/commandline.cpp
index 78d43e5..73569ff 100644
--- a/commandline.cpp
+++ b/commandline.cpp
@@ -43,49 +43,38 @@
#include "adb_auth.h"
#include "adb_client.h"
#include "adb_io.h"
+#include "adb_utils.h"
#include "file_sync_service.h"
static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...);
-int find_sync_dirs(const char *srcarg,
- char **system_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out,
- char **oem_srcdir_out);
-int install_app(transport_type transport, const char* serial, int argc,
- const char** argv);
-int install_multiple_app(transport_type transport, const char* serial, int argc,
+static int install_app(transport_type transport, const char* serial, int argc,
+ const char** argv);
+static int install_multiple_app(transport_type transport, const char* serial, int argc,
+ const char** argv);
+static int uninstall_app(transport_type transport, const char* serial, int argc,
const char** argv);
-int uninstall_app(transport_type transport, const char* serial, int argc,
- const char** argv);
-static const char *gProductOutPath = NULL;
+static std::string gProductOutPath;
extern int gListenAll;
-static char *product_file(const char *extra)
-{
- if (gProductOutPath == NULL) {
+static std::string product_file(const char *extra) {
+ if (gProductOutPath.empty()) {
fprintf(stderr, "adb: Product directory not specified; "
"use -p or define ANDROID_PRODUCT_OUT\n");
exit(1);
}
- int n = strlen(gProductOutPath) + strlen(extra) + 2;
- char* x = reinterpret_cast<char*>(malloc(n));
- if (x == 0) {
- fprintf(stderr, "adb: Out of memory (product_file())\n");
- exit(1);
- }
-
- snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
- return x;
+ return android::base::StringPrintf("%s%s%s",
+ gProductOutPath.c_str(), OS_PATH_SEPARATOR_STR, extra);
}
-void version(FILE * out) {
+static void version(FILE* out) {
fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
- ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
+ ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
}
-void help()
-{
+static void help() {
version(stderr);
fprintf(stderr,
@@ -245,8 +234,7 @@
);
}
-int usage()
-{
+static int usage() {
help();
return 1;
}
@@ -418,8 +406,7 @@
return 0;
}
-int interactive_shell(void)
-{
+static int interactive_shell() {
adb_thread_t thr;
int fdi, fd;
@@ -457,8 +444,8 @@
}
}
-int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
- unsigned progress)
+static int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
+ unsigned progress)
{
char buf[4096];
unsigned total;
@@ -516,23 +503,6 @@
return 0;
}
-
-int adb_download(const char *service, const char *fn, unsigned progress)
-{
- void *data;
- unsigned sz;
-
- data = load_file(fn, &sz);
- if(data == 0) {
- fprintf(stderr,"* cannot read '%s' *\n", fn);
- return -1;
- }
-
- int status = adb_download_buffer(service, fn, data, sz, progress);
- free(data);
- return status;
-}
-
#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
/*
@@ -554,7 +524,7 @@
* - When the other side sends "DONEDONE" instead of a block number,
* we hang up.
*/
-int adb_sideload_host(const char* fn) {
+static int adb_sideload_host(const char* fn) {
unsigned sz;
size_t xfer = 0;
int status;
@@ -685,24 +655,6 @@
}
}
-static int should_escape(const char c)
-{
- return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')');
-}
-
-static std::string escape_arg(const std::string& s) {
- // Preserve empty arguments.
- if (s.empty()) return "\"\"";
-
- std::string result(s);
- for (auto it = result.begin(); it != result.end(); ++it) {
- if (should_escape(*it)) {
- it = result.insert(it, '\\') + 1;
- }
- }
- return result;
-}
-
/**
* Run ppp in "notty" mode against a resource listed as the first parameter
* eg:
@@ -710,8 +662,7 @@
* ppp dev:/dev/omap_csmi_tty0 <ppp options>
*
*/
-int ppp(int argc, const char **argv)
-{
+static int ppp(int argc, const char** argv) {
#if defined(_WIN32)
fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
return -1;
@@ -1003,62 +954,52 @@
* Given <hint>, try to construct an absolute path to the
* ANDROID_PRODUCT_OUT dir.
*/
-static const char *find_product_out_path(const char *hint)
-{
- static char path_buf[PATH_MAX];
-
+static std::string find_product_out_path(const char* hint) {
if (hint == NULL || hint[0] == '\0') {
- return NULL;
+ return "";
}
- /* If it's already absolute, don't bother doing any work.
- */
+ // If it's already absolute, don't bother doing any work.
if (adb_is_absolute_host_path(hint)) {
- strcpy(path_buf, hint);
- return path_buf;
+ return hint;
}
- /* If there are any slashes in it, assume it's a relative path;
- * make it absolute.
- */
+ // If there are any slashes in it, assume it's a relative path;
+ // make it absolute.
if (adb_dirstart(hint) != NULL) {
- if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
+ char cwd[PATH_MAX];
+ if (getcwd(cwd, sizeof(cwd)) == NULL) {
fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
- return NULL;
+ return "";
}
- if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
- fprintf(stderr, "adb: Couldn't assemble path\n");
- return NULL;
- }
- strcat(path_buf, OS_PATH_SEPARATOR_STR);
- strcat(path_buf, hint);
- return path_buf;
+ return android::base::StringPrintf("%s%s%s", cwd, OS_PATH_SEPARATOR_STR, hint);
}
- /* It's a string without any slashes. Try to do something with it.
- *
- * Try to find the root of the build tree, and build a PRODUCT_OUT
- * path from there.
- */
+ // It's a string without any slashes. Try to do something with it.
+ //
+ // Try to find the root of the build tree, and build a PRODUCT_OUT
+ // path from there.
char top_buf[PATH_MAX];
- const char *top = find_top(top_buf);
- if (top == NULL) {
+ const char* top = find_top(top_buf);
+ if (top == nullptr) {
fprintf(stderr, "adb: Couldn't find top of build tree\n");
+ return "";
+ }
+ std::string path = top_buf;
+ path += OS_PATH_SEPARATOR_STR;
+ path += "out";
+ path += OS_PATH_SEPARATOR_STR;
+ path += "target";
+ path += OS_PATH_SEPARATOR_STR;
+ path += "product";
+ path += OS_PATH_SEPARATOR_STR;
+ path += hint;
+ if (!directory_exists(path)) {
+ fprintf(stderr, "adb: Couldn't find a product dir based on -p %s; "
+ "\"%s\" doesn't exist\n", hint, path.c_str());
return NULL;
}
-//TODO: if we have a way to indicate debug, look in out/debug/target/...
- snprintf(path_buf, sizeof(path_buf),
- "%s" OS_PATH_SEPARATOR_STR
- "out" OS_PATH_SEPARATOR_STR
- "target" OS_PATH_SEPARATOR_STR
- "product" OS_PATH_SEPARATOR_STR
- "%s", top_buf, hint);
- if (access(path_buf, F_OK) < 0) {
- fprintf(stderr, "adb: Couldn't find a product dir "
- "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
- return NULL;
- }
- return path_buf;
+ return path;
}
static void parse_push_pull_args(const char **arg, int narg, char const **path1,
@@ -1113,15 +1054,14 @@
const char* serial = NULL;
const char* server_port_str = NULL;
- /* If defined, this should be an absolute path to
- * the directory containing all of the various system images
- * for a particular product. If not defined, and the adb
- * command requires this information, then the user must
- * specify the path using "-p".
- */
- gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
- if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
- gProductOutPath = NULL;
+ // If defined, this should be an absolute path to
+ // the directory containing all of the various system images
+ // for a particular product. If not defined, and the adb
+ // command requires this information, then the user must
+ // specify the path using "-p".
+ char* ANDROID_PRODUCT_OUT = getenv("ANDROID_PRODUCT_OUT");
+ if (ANDROID_PRODUCT_OUT != nullptr) {
+ gProductOutPath = ANDROID_PRODUCT_OUT;
}
// TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
@@ -1162,9 +1102,8 @@
product = argv[0] + 2;
}
gProductOutPath = find_product_out_path(product);
- if (gProductOutPath == NULL) {
- fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
- product);
+ if (gProductOutPath.empty()) {
+ fprintf(stderr, "adb: could not resolve \"-p %s\"\n", product);
return usage();
}
} else if (argv[0][0]=='-' && argv[0][1]=='s') {
@@ -1595,46 +1534,55 @@
return uninstall_app(ttype, serial, argc, argv);
}
else if (!strcmp(argv[0], "sync")) {
- const char* srcarg;
- char *system_srcpath, *data_srcpath, *vendor_srcpath, *oem_srcpath;
-
- int listonly = 0;
-
- int ret;
+ std::string src_arg;
+ bool list_only = false;
if (argc < 2) {
- /* No local path was specified. */
- srcarg = NULL;
+ // No local path was specified.
+ src_arg = "";
} else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
- listonly = 1;
+ list_only = 1;
if (argc == 3) {
- srcarg = argv[2];
+ src_arg = argv[2];
} else {
- srcarg = NULL;
+ src_arg = "";
}
} else if (argc == 2) {
- /* A local path or "android"/"data" arg was specified. */
- srcarg = argv[1];
+ // A local path or "android"/"data" arg was specified.
+ src_arg = argv[1];
} else {
return usage();
}
- ret = find_sync_dirs(srcarg, &system_srcpath, &data_srcpath, &vendor_srcpath,
- &oem_srcpath);
- if (ret != 0) return usage();
- if (system_srcpath != NULL)
- ret = do_sync_sync(system_srcpath, "/system", listonly);
- if (ret == 0 && vendor_srcpath != NULL)
- ret = do_sync_sync(vendor_srcpath, "/vendor", listonly);
- if(ret == 0 && oem_srcpath != NULL)
- ret = do_sync_sync(oem_srcpath, "/oem", listonly);
- if (ret == 0 && data_srcpath != NULL)
- ret = do_sync_sync(data_srcpath, "/data", listonly);
+ if (src_arg != "" &&
+ src_arg != "system" && src_arg != "data" && src_arg != "vendor" && src_arg != "oem") {
+ return usage();
+ }
- free(system_srcpath);
- free(vendor_srcpath);
- free(oem_srcpath);
- free(data_srcpath);
- return ret;
+ std::string system_src_path = product_file("system");
+ std::string data_src_path = product_file("data");
+ std::string vendor_src_path = product_file("vendor");
+ std::string oem_src_path = product_file("oem");
+ if (!directory_exists(vendor_src_path)) {
+ vendor_src_path = "";
+ }
+ if (!directory_exists(oem_src_path)) {
+ oem_src_path = "";
+ }
+
+ int rc = 0;
+ if (rc == 0 && (src_arg.empty() || src_arg == "system")) {
+ rc = do_sync_sync(system_src_path.c_str(), "/system", list_only);
+ }
+ if (rc == 0 && (src_arg.empty() || src_arg == "vendor")) {
+ rc = do_sync_sync(vendor_src_path.c_str(), "/vendor", list_only);
+ }
+ if(rc == 0 && (src_arg.empty() || src_arg == "oem")) {
+ rc = do_sync_sync(oem_src_path.c_str(), "/oem", list_only);
+ }
+ if (rc == 0 && (src_arg.empty() || src_arg == "data")) {
+ rc = do_sync_sync(data_src_path.c_str(), "/data", list_only);
+ }
+ return rc;
}
/* passthrough commands */
else if (!strcmp(argv[0],"get-state") ||
@@ -1729,64 +1677,6 @@
return adb_commandline(argc, argv);
}
-int find_sync_dirs(const char *srcarg,
- char **system_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out,
- char **oem_srcdir_out)
-{
- char *system_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL, *oem_srcdir = NULL;
- struct stat st;
-
- if(srcarg == NULL) {
- system_srcdir = product_file("system");
- data_srcdir = product_file("data");
- vendor_srcdir = product_file("vendor");
- oem_srcdir = product_file("oem");
- // Check if vendor partition exists.
- if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
- vendor_srcdir = NULL;
- // Check if oem partition exists.
- if (lstat(oem_srcdir, &st) || !S_ISDIR(st.st_mode))
- oem_srcdir = NULL;
- } else {
- // srcarg may be "data", "system", "vendor", "oem" or NULL.
- // If srcarg is NULL, then all partitions are synced.
- if(strcmp(srcarg, "system") == 0) {
- system_srcdir = product_file("system");
- } else if(strcmp(srcarg, "data") == 0) {
- data_srcdir = product_file("data");
- } else if(strcmp(srcarg, "vendor") == 0) {
- vendor_srcdir = product_file("vendor");
- } else if(strcmp(srcarg, "oem") == 0) {
- oem_srcdir = product_file("oem");
- } else {
- // It's not "system", "data", "vendor", or "oem".
- return 1;
- }
- }
-
- if(system_srcdir_out != NULL)
- *system_srcdir_out = system_srcdir;
- else
- free(system_srcdir);
-
- if(vendor_srcdir_out != NULL)
- *vendor_srcdir_out = vendor_srcdir;
- else
- free(vendor_srcdir);
-
- if(oem_srcdir_out != NULL)
- *oem_srcdir_out = oem_srcdir;
- else
- free(oem_srcdir);
-
- if(data_srcdir_out != NULL)
- *data_srcdir_out = data_srcdir;
- else
- free(data_srcdir);
-
- return 0;
-}
-
static int pm_command(transport_type transport, const char* serial,
int argc, const char** argv)
{
@@ -1801,8 +1691,8 @@
return 0;
}
-int uninstall_app(transport_type transport, const char* serial, int argc,
- const char** argv)
+static int uninstall_app(transport_type transport, const char* serial, int argc,
+ const char** argv)
{
/* if the user choose the -k option, we refuse to do it until devices are
out with the option to uninstall the remaining data somehow (adb/ui) */
@@ -1838,8 +1728,8 @@
}
}
-int install_app(transport_type transport, const char* serial, int argc,
- const char** argv)
+static int install_app(transport_type transport, const char* serial, int argc,
+ const char** argv)
{
static const char *const DATA_DEST = "/data/local/tmp/%s";
static const char *const SD_DEST = "/sdcard/tmp/%s";
@@ -1892,8 +1782,8 @@
return err;
}
-int install_multiple_app(transport_type transport, const char* serial, int argc,
- const char** argv)
+static int install_multiple_app(transport_type transport, const char* serial, int argc,
+ const char** argv)
{
int i;
struct stat sb;
diff --git a/remount_service.cpp b/remount_service.cpp
index b150274..1eaee73 100644
--- a/remount_service.cpp
+++ b/remount_service.cpp
@@ -31,6 +31,7 @@
#include "adb.h"
#include "adb_io.h"
+#include "adb_utils.h"
#include "cutils/properties.h"
static int system_ro = 1;
@@ -56,11 +57,6 @@
return device;
}
-static bool has_partition(const char* path) {
- struct stat sb;
- return (lstat(path, &sb) == 0 && S_ISDIR(sb.st_mode));
-}
-
int make_block_device_writable(const std::string& dev) {
int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
@@ -90,7 +86,7 @@
}
static bool remount_partition(int fd, const char* partition, int* ro) {
- if (!has_partition(partition)) {
+ if (!directory_exists(partition)) {
return true;
}
if (remount(partition, ro)) {