diff --git a/include/cutils/files.h b/include/cutils/android_get_control_file.h similarity index 87% rename from include/cutils/files.h rename to include/cutils/android_get_control_file.h index 0210e3084..ed8fbf830 100644 --- a/include/cutils/files.h +++ b/include/cutils/android_get_control_file.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef __CUTILS_FILES_H -#define __CUTILS_FILES_H +#ifndef __CUTILS_ANDROID_GET_CONTROL_FILE_H +#define __CUTILS_ANDROID_GET_CONTROL_FILE_H #define ANDROID_FILE_ENV_PREFIX "ANDROID_FILE_" @@ -34,4 +34,4 @@ int android_get_control_file(const char* path); } #endif -#endif /* __CUTILS_FILES_H */ +#endif /* __CUTILS_ANDROID_GET_CONTROL_FILE_H */ diff --git a/include/cutils/sockets.h b/include/cutils/sockets.h index 4626e7acd..d724dd6a5 100644 --- a/include/cutils/sockets.h +++ b/include/cutils/sockets.h @@ -35,6 +35,7 @@ typedef SOCKET cutils_socket_t; #else #include +#include typedef int cutils_socket_t; #define INVALID_SOCKET (-1) diff --git a/init/descriptors.cpp b/init/descriptors.cpp index 10aae8882..429a76e19 100644 --- a/init/descriptors.cpp +++ b/init/descriptors.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include "init.h" diff --git a/init/util_test.cpp b/init/util_test.cpp index 6ecbf908c..e9f164d82 100644 --- a/init/util_test.cpp +++ b/init/util_test.cpp @@ -16,6 +16,7 @@ #include "util.h" +#include #include #include #include @@ -23,7 +24,9 @@ #include #include -#include +#include +#include +#include #include #include @@ -55,45 +58,48 @@ struct selabel_handle *sehandle; TEST(util, create_file) { if (!sehandle) sehandle = selinux_android_file_context_handle(); - static const char path[] = "/data/local/tmp/util.create_file.test"; - static const char key[] = ANDROID_FILE_ENV_PREFIX "_data_local_tmp_util_create_file_test"; - EXPECT_EQ(unsetenv(key), 0); - unlink(path); + TemporaryFile tf; + close(tf.fd); + EXPECT_GE(unlink(tf.path), 0); + + std::string key(ANDROID_FILE_ENV_PREFIX); + key += tf.path; + + std::for_each(key.begin(), key.end(), [] (char& c) { c = isalnum(c) ? c : '_'; }); + + EXPECT_EQ(unsetenv(key.c_str()), 0); - int fd; uid_t uid = decode_uid("logd"); gid_t gid = decode_uid("system"); mode_t perms = S_IRWXU | S_IWGRP | S_IRGRP | S_IROTH; static const char context[] = "u:object_r:misc_logd_file:s0"; - EXPECT_GE(fd = create_file(path, O_RDWR | O_CREAT, perms, uid, gid, context), 0); - if (fd < 0) return; + EXPECT_GE(tf.fd = create_file(tf.path, O_RDWR | O_CREAT, perms, uid, gid, context), 0); + if (tf.fd < 0) return; static const char hello[] = "hello world\n"; static const ssize_t len = strlen(hello); - EXPECT_EQ(write(fd, hello, len), len); - char buffer[sizeof(hello)]; + EXPECT_EQ(write(tf.fd, hello, len), len); + char buffer[sizeof(hello) + 1]; memset(buffer, 0, sizeof(buffer)); - EXPECT_GE(lseek(fd, 0, SEEK_SET), 0); - EXPECT_EQ(read(fd, buffer, sizeof(buffer)), len); - EXPECT_EQ(strcmp(hello, buffer), 0); - char val[32]; - snprintf(val, sizeof(val), "%d", fd); - EXPECT_EQ(android_get_control_file(path), -1); - setenv(key, val, true); - EXPECT_EQ(android_get_control_file(path), fd); - close(fd); - EXPECT_EQ(android_get_control_file(path), -1); - EXPECT_EQ(unsetenv(key), 0); + EXPECT_GE(lseek(tf.fd, 0, SEEK_SET), 0); + EXPECT_EQ(read(tf.fd, buffer, sizeof(buffer)), len); + EXPECT_EQ(std::string(hello), buffer); + EXPECT_EQ(android_get_control_file(tf.path), -1); + EXPECT_EQ(setenv(key.c_str(), android::base::StringPrintf("%d", tf.fd).c_str(), true), 0); + EXPECT_EQ(android_get_control_file(tf.path), tf.fd); + close(tf.fd); + EXPECT_EQ(android_get_control_file(tf.path), -1); + EXPECT_EQ(unsetenv(key.c_str()), 0); struct stat st; - EXPECT_EQ(stat(path, &st), 0); + EXPECT_EQ(stat(tf.path, &st), 0); EXPECT_EQ(st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO), perms); EXPECT_EQ(st.st_uid, uid); EXPECT_EQ(st.st_gid, gid); security_context_t con; - EXPECT_GE(getfilecon(path, &con), 0); + EXPECT_GE(getfilecon(tf.path, &con), 0); EXPECT_NE(con, static_cast(NULL)); if (con) { EXPECT_EQ(context, std::string(con)); } freecon(con); - EXPECT_EQ(unlink(path), 0); + EXPECT_EQ(unlink(tf.path), 0); } diff --git a/libcutils/Android.bp b/libcutils/Android.bp index f7b497d9d..39f8aba8e 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -18,6 +18,7 @@ // they correspond to features not used by our host development tools // which are also hard or even impossible to port to native Win32 libcutils_nonwindows_sources = [ + "android_get_control_file.cpp", "fs.c", "multiuser.c", "socket_inaddr_any_server_unix.c", @@ -34,7 +35,6 @@ cc_library { host_supported: true, srcs: [ "config_utils.c", - "files.cpp", "fs_config.c", "canned_fs_config.c", "hashmap.c", diff --git a/libcutils/android_get_control_env.h b/libcutils/android_get_control_env.h new file mode 100644 index 000000000..638c8318a --- /dev/null +++ b/libcutils/android_get_control_env.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 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 __CUTILS_ANDROID_GET_CONTROL_ENV_H +#define __CUTILS_ANDROID_GET_CONTROL_ENV_H + +/* To declare library function hidden and internal */ +#define LIBCUTILS_HIDDEN __attribute__((visibility("hidden"))) + +#ifdef __cplusplus +extern "C" { +#endif + +LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix, + const char* name); +#ifdef __cplusplus +} +#endif + +#endif /* __CUTILS_ANDROID_GET_CONTROL_ENV_H */ diff --git a/libcutils/files.cpp b/libcutils/android_get_control_file.cpp similarity index 74% rename from libcutils/files.cpp rename to libcutils/android_get_control_file.cpp index bf15b4283..496fbbfe6 100644 --- a/libcutils/files.cpp +++ b/libcutils/android_get_control_file.cpp @@ -25,11 +25,6 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ - -// This file contains files implementation that can be shared between -// platforms as long as the correct headers are included. -#define _GNU_SOURCE 1 // for asprintf - #include #include #include @@ -41,17 +36,16 @@ #include #include -#include +#include -#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define -#define TEMP_FAILURE_RETRY(exp) (exp) -#endif +#include "android_get_control_env.h" -int android_get_control_file(const char* path) { - if (!path) return -1; +LIBCUTILS_HIDDEN int __android_get_control_from_env(const char* prefix, + const char* name) { + if (!prefix || !name) return -1; char *key = NULL; - if (asprintf(&key, ANDROID_FILE_ENV_PREFIX "%s", path) < 0) return -1; + if (asprintf(&key, "%s%s", prefix, name) < 0) return -1; if (!key) return -1; char *cp = key; @@ -70,29 +64,33 @@ int android_get_control_file(const char* path) { // validity checking if ((fd < 0) || (fd > INT_MAX)) return -1; -#if defined(_SC_OPEN_MAX) - if (fd >= sysconf(_SC_OPEN_MAX)) return -1; -#elif defined(OPEN_MAX) - if (fd >= OPEN_MAX) return -1; -#elif defined(_POSIX_OPEN_MAX) - if (fd >= _POSIX_OPEN_MAX) return -1; + + // Since we are inheriting an fd, it could legitimately exceed _SC_OPEN_MAX + + // Still open? +#if defined(F_GETFD) // Linux lowest overhead + if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1; +#elif defined(F_GETFL) // Mac host lowest overhead + if (fcntl(fd, F_GETFL) < 0) return -1; +#else // Hail Mary pass + struct stat s; + if (fstat(fd, &s) < 0) return -1; #endif -#if defined(F_GETFD) - if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1; -#elif defined(F_GETFL) - if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1; -#else - struct stat s; - if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1; -#endif + return static_cast(fd); +} + +int android_get_control_file(const char* path) { + int fd = __android_get_control_from_env(ANDROID_FILE_ENV_PREFIX, path); #if defined(__linux__) + // Find file path from /proc and make sure it is correct char *proc = NULL; - if (asprintf(&proc, "/proc/self/fd/%ld", fd) < 0) return -1; + if (asprintf(&proc, "/proc/self/fd/%d", fd) < 0) return -1; if (!proc) return -1; size_t len = strlen(path); + // readlink() does not guarantee a nul byte, len+2 so we catch truncation. char *buf = static_cast(calloc(1, len + 2)); if (!buf) { free(proc); @@ -104,8 +102,8 @@ int android_get_control_file(const char* path) { free(buf); if (ret < 0) return -1; if (cmp != 0) return -1; + // It is what we think it is #endif - // It is what we think it is - return static_cast(fd); + return fd; } diff --git a/libcutils/klog.cpp b/libcutils/klog.cpp index 9d823cfae..4bad28a57 100644 --- a/libcutils/klog.cpp +++ b/libcutils/klog.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include static int klog_level = KLOG_DEFAULT_LEVEL; diff --git a/libcutils/sockets.cpp b/libcutils/sockets.cpp index 63761a2c5..23a447be8 100644 --- a/libcutils/sockets.cpp +++ b/libcutils/sockets.cpp @@ -28,33 +28,9 @@ // This file contains socket implementation that can be shared between // platforms as long as the correct headers are included. -#define _GNU_SOURCE 1 // For asprintf - -#include -#include -#include -#include -#if !defined(_WIN32) -#include -#endif -#include -#include -#include -#include -#include -#if !defined(_WIN32) -#include -#endif -#include - -#include #include -#ifndef TEMP_FAILURE_RETRY // _WIN32 does not define -#define TEMP_FAILURE_RETRY(exp) (exp) -#endif - int socket_get_local_port(cutils_socket_t sock) { sockaddr_storage addr; socklen_t addr_size = sizeof(addr); @@ -65,58 +41,3 @@ int socket_get_local_port(cutils_socket_t sock) { } return -1; } - -int android_get_control_socket(const char* name) { - char *key = NULL; - if (asprintf(&key, ANDROID_SOCKET_ENV_PREFIX "%s", name) < 0) return -1; - if (!key) return -1; - - char *cp = key; - while (*cp) { - if (!isalnum(*cp)) *cp = '_'; - ++cp; - } - - const char* val = getenv(key); - free(key); - if (!val) return -1; - - errno = 0; - long fd = strtol(val, NULL, 10); - if (errno) return -1; - - // validity checking - if ((fd < 0) || (fd > INT_MAX)) return -1; -#if defined(_SC_OPEN_MAX) - if (fd >= sysconf(_SC_OPEN_MAX)) return -1; -#elif defined(OPEN_MAX) - if (fd >= OPEN_MAX) return -1; -#elif defined(_POSIX_OPEN_MAX) - if (fd >= _POSIX_OPEN_MAX) return -1; -#endif - -#if defined(F_GETFD) - if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)) < 0) return -1; -#elif defined(F_GETFL) - if (TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)) < 0) return -1; -#else - struct stat s; - if (TEMP_FAILURE_RETRY(fstat(fd, &s)) < 0) return -1; -#endif - -#if !defined(_WIN32) - struct sockaddr_un addr; - socklen_t addrlen = sizeof(addr); - int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen)); - if (ret < 0) return -1; - char *path = NULL; - if (asprintf(&path, ANDROID_SOCKET_DIR"/%s", name) < 0) return -1; - if (!path) return -1; - int cmp = strcmp(addr.sun_path, path); - free(path); - if (cmp != 0) return -1; -#endif - - // It is what we think it is - return static_cast(fd); -} diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp index 3545403aa..948d09c60 100644 --- a/libcutils/sockets_unix.cpp +++ b/libcutils/sockets_unix.cpp @@ -16,13 +16,21 @@ #define LOG_TAG "socket-unix" +#include +#include +#include +#include #include +#include #include #include #include +#include #include +#include "android_get_control_env.h" + #if defined(__ANDROID__) /* For the socket trust (credentials) check */ #include @@ -80,3 +88,24 @@ ssize_t socket_send_buffers(cutils_socket_t sock, return writev(sock, iovec_buffers, num_buffers); } + +int android_get_control_socket(const char* name) { + int fd = __android_get_control_from_env(ANDROID_SOCKET_ENV_PREFIX, name); + + if (fd < 0) return fd; + + // Compare to UNIX domain socket name, must match! + struct sockaddr_un addr; + socklen_t addrlen = sizeof(addr); + int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen)); + if (ret < 0) return -1; + char *path = NULL; + if (asprintf(&path, ANDROID_SOCKET_DIR "/%s", name) < 0) return -1; + if (!path) return -1; + int cmp = strcmp(addr.sun_path, path); + free(path); + if (cmp != 0) return -1; + + // It is what we think it is + return fd; +} diff --git a/libcutils/sockets_windows.cpp b/libcutils/sockets_windows.cpp index ed6b1a781..3064c70e5 100644 --- a/libcutils/sockets_windows.cpp +++ b/libcutils/sockets_windows.cpp @@ -84,3 +84,7 @@ ssize_t socket_send_buffers(cutils_socket_t sock, return -1; } + +int android_get_control_socket(const char* name) { + return -1; +} diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp index bd354129d..72e2eace5 100644 --- a/libcutils/tests/Android.bp +++ b/libcutils/tests/Android.bp @@ -14,7 +14,7 @@ cc_defaults { name: "libcutils_test_default", - srcs: ["sockets_test.cpp", "files_test.cpp"], + srcs: ["sockets_test.cpp"], target: { android: { @@ -28,7 +28,11 @@ cc_defaults { }, not_windows: { - srcs: ["test_str_parms.cpp"], + srcs: [ + "test_str_parms.cpp", + "android_get_control_socket_test.cpp", + "android_get_control_file_test.cpp" + ], }, }, diff --git a/libcutils/tests/files_test.cpp b/libcutils/tests/android_get_control_file_test.cpp similarity index 50% rename from libcutils/tests/files_test.cpp rename to libcutils/tests/android_get_control_file_test.cpp index 1a7d67386..6c6fd2ad2 100644 --- a/libcutils/tests/files_test.cpp +++ b/libcutils/tests/android_get_control_file_test.cpp @@ -14,33 +14,37 @@ * limitations under the License. */ +#include #include #include #include #include #include -#include +#include + +#include +#include +#include #include TEST(FilesTest, android_get_control_file) { - static const char key[] = ANDROID_FILE_ENV_PREFIX "_dev_kmsg"; - static const char name[] = "/dev/kmsg"; + TemporaryFile tf; + ASSERT_GE(tf.fd, 0); - EXPECT_EQ(unsetenv(key), 0); - EXPECT_EQ(android_get_control_file(name), -1); + std::string key(ANDROID_FILE_ENV_PREFIX); + key += tf.path; - int fd; - ASSERT_GE(fd = open(name, O_RDONLY | O_CLOEXEC), 0); - EXPECT_EQ(android_get_control_file(name), -1); + std::for_each(key.begin(), key.end(), [] (char& c) { c = isalnum(c) ? c : '_'; }); - char val[32]; - snprintf(val, sizeof(val), "%d", fd); - EXPECT_EQ(setenv(key, val, true), 0); + EXPECT_EQ(unsetenv(key.c_str()), 0); + EXPECT_EQ(android_get_control_file(tf.path), -1); - EXPECT_EQ(android_get_control_file(name), fd); - close(fd); - EXPECT_EQ(android_get_control_file(name), -1); - EXPECT_EQ(unsetenv(key), 0); - EXPECT_EQ(android_get_control_file(name), -1); + EXPECT_EQ(setenv(key.c_str(), android::base::StringPrintf("%d", tf.fd).c_str(), true), 0); + + EXPECT_EQ(android_get_control_file(tf.path), tf.fd); + close(tf.fd); + EXPECT_EQ(android_get_control_file(tf.path), -1); + EXPECT_EQ(unsetenv(key.c_str()), 0); + EXPECT_EQ(android_get_control_file(tf.path), -1); } diff --git a/libcutils/tests/android_get_control_socket_test.cpp b/libcutils/tests/android_get_control_socket_test.cpp new file mode 100644 index 000000000..e58674864 --- /dev/null +++ b/libcutils/tests/android_get_control_socket_test.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 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 +#include +#include +#include +#include +#include + +#include +#include + +#ifndef SOCK_NONBLOCK +#define SOCK_NONBLOCK 0 +#endif + +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 0 +#endif + +TEST(SocketsTest, android_get_control_socket) { + static const char key[] = ANDROID_SOCKET_ENV_PREFIX "SocketsTest_android_get_control_socket"; + static const char* name = key + strlen(ANDROID_SOCKET_ENV_PREFIX); + + EXPECT_EQ(unsetenv(key), 0); + EXPECT_EQ(android_get_control_socket(name), -1); + + int fd; + ASSERT_GE(fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0), 0); +#ifdef F_GETFL + int flags; + ASSERT_GE(flags = fcntl(fd, F_GETFL), 0); + ASSERT_GE(fcntl(fd, F_SETFL, flags | O_NONBLOCK), 0); +#endif + EXPECT_EQ(android_get_control_socket(name), -1); + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name); + unlink(addr.sun_path); + + EXPECT_EQ(bind(fd, (struct sockaddr*)&addr, sizeof(addr)), 0); + EXPECT_EQ(android_get_control_socket(name), -1); + + char val[32]; + snprintf(val, sizeof(val), "%d", fd); + EXPECT_EQ(setenv(key, val, true), 0); + + EXPECT_EQ(android_get_control_socket(name), fd); + socket_close(fd); + EXPECT_EQ(android_get_control_socket(name), -1); + EXPECT_EQ(unlink(addr.sun_path), 0); + EXPECT_EQ(android_get_control_socket(name), -1); + EXPECT_EQ(unsetenv(key), 0); + EXPECT_EQ(android_get_control_socket(name), -1); +} diff --git a/libcutils/tests/sockets_test.cpp b/libcutils/tests/sockets_test.cpp index adfbf4ad3..0441fb636 100644 --- a/libcutils/tests/sockets_test.cpp +++ b/libcutils/tests/sockets_test.cpp @@ -18,11 +18,9 @@ // IPv6 capabilities. These tests assume that no UDP packets are lost, which // should be the case for loopback communication, but is not guaranteed. -#include -#include +#include #include #include -#include #include #include @@ -189,49 +187,3 @@ TEST(SocketsTest, TestTcpReceiveTimeout) { TEST(SocketsTest, TestSocketSendBuffersFailure) { EXPECT_EQ(-1, socket_send_buffers(INVALID_SOCKET, nullptr, 0)); } - -#ifndef SOCK_NONBLOCK -#define SOCK_NONBLOCK 0 -#endif - -#ifndef SOCK_CLOEXEC -#define SOCK_CLOEXEC 0 -#endif - -TEST(SocketsTest, android_get_control_socket) { - static const char key[] = ANDROID_SOCKET_ENV_PREFIX "SocketsTest_android_get_control_socket"; - static const char* name = key + strlen(ANDROID_SOCKET_ENV_PREFIX); - - EXPECT_EQ(unsetenv(key), 0); - EXPECT_EQ(android_get_control_socket(name), -1); - - int fd; - ASSERT_GE(fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0), 0); -#ifdef F_GETFL - int flags; - ASSERT_GE(flags = fcntl(fd, F_GETFL), 0); - ASSERT_GE(fcntl(fd, F_SETFL, flags | O_NONBLOCK), 0); -#endif - EXPECT_EQ(android_get_control_socket(name), -1); - - struct sockaddr_un addr; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s", name); - unlink(addr.sun_path); - - EXPECT_EQ(bind(fd, (struct sockaddr*)&addr, sizeof(addr)), 0); - EXPECT_EQ(android_get_control_socket(name), -1); - - char val[32]; - snprintf(val, sizeof(val), "%d", fd); - EXPECT_EQ(setenv(key, val, true), 0); - - EXPECT_EQ(android_get_control_socket(name), fd); - socket_close(fd); - EXPECT_EQ(android_get_control_socket(name), -1); - EXPECT_EQ(unlink(addr.sun_path), 0); - EXPECT_EQ(android_get_control_socket(name), -1); - EXPECT_EQ(unsetenv(key), 0); - EXPECT_EQ(android_get_control_socket(name), -1); -} diff --git a/logd/main.cpp b/logd/main.cpp index d698976d0..7550c41a5 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -37,9 +37,9 @@ #include #include +#include #include #include -#include #include #include #include