diff --git a/adb/Android.mk b/adb/Android.mk index b616256a5..62f012cb1 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -129,7 +129,7 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) -LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt +LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt libselinux include $(BUILD_EXECUTABLE) diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c index 0bb51f90f..c2401b866 100644 --- a/adb/file_sync_service.c +++ b/adb/file_sync_service.c @@ -22,19 +22,32 @@ #include #include #include +#include #include - +#include +#include #include "sysdeps.h" #define TRACE_TAG TRACE_SYNC #include "adb.h" #include "file_sync_service.h" +/* TODO: use fs_config to configure permissions on /data */ +static bool is_on_system(const char *name) { + const char *SYSTEM = "/system/"; + return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0); +} + static int mkdirs(char *name) { int ret; char *x = name + 1; + unsigned int uid, gid; + unsigned int mode = 0775; + uint64_t cap = 0; + uid = getuid(); + gid = getgid(); if(name[0] != '/') return -1; @@ -42,11 +55,21 @@ static int mkdirs(char *name) x = adb_dirstart(x); if(x == 0) return 0; *x = 0; - ret = adb_mkdir(name, 0775); + if (is_on_system(name)) { + fs_config(name, 1, &uid, &gid, &mode, &cap); + } + ret = adb_mkdir(name, mode); if((ret < 0) && (errno != EEXIST)) { D("mkdir(\"%s\") -> %s\n", name, strerror(errno)); *x = '/'; return ret; + } else if(ret == 0) { + ret = chown(name, uid, gid); + if (ret < 0) { + *x = '/'; + return ret; + } + selinux_android_restorecon(name); } *x++ = '/'; } @@ -149,7 +172,8 @@ static int fail_errno(int s) return fail_message(s, strerror(errno)); } -static int handle_send_file(int s, char *path, mode_t mode, char *buffer) +static int handle_send_file(int s, char *path, unsigned int uid, + unsigned int gid, mode_t mode, char *buffer) { syncmsg msg; unsigned int timestamp = 0; @@ -157,8 +181,13 @@ static int handle_send_file(int s, char *path, mode_t mode, char *buffer) fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); if(fd < 0 && errno == ENOENT) { - mkdirs(path); - fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); + if(mkdirs(path) != 0) { + if(fail_errno(s)) + return -1; + fd = -1; + } else { + fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode); + } } if(fd < 0 && errno == EEXIST) { fd = adb_open_mode(path, O_WRONLY, mode); @@ -167,6 +196,16 @@ static int handle_send_file(int s, char *path, mode_t mode, char *buffer) if(fail_errno(s)) return -1; fd = -1; + } else { + if(fchown(fd, uid, gid) != 0) { + fail_errno(s); + errno = 0; + } + /* fchown clears the setuid bit - restore it if present */ + if(fchmod(fd, mode) != 0) { + fail_errno(s); + errno = 0; + } } for(;;) { @@ -206,6 +245,7 @@ static int handle_send_file(int s, char *path, mode_t mode, char *buffer) if(fd >= 0) { struct utimbuf u; adb_close(fd); + selinux_android_restorecon(path); u.actime = timestamp; u.modtime = timestamp; utime(path, &u); @@ -249,7 +289,10 @@ static int handle_send_link(int s, char *path, char *buffer) ret = symlink(buffer, path); if(ret && errno == ENOENT) { - mkdirs(path); + if(mkdirs(path) != 0) { + fail_errno(s); + return -1; + } ret = symlink(buffer, path); } if(ret) { @@ -277,7 +320,7 @@ static int handle_send_link(int s, char *path, char *buffer) static int do_send(int s, char *path, char *buffer) { char *tmp; - mode_t mode; + unsigned int mode; int is_link, ret; tmp = strrchr(path,','); @@ -288,7 +331,7 @@ static int do_send(int s, char *path, char *buffer) #ifndef HAVE_SYMLINKS is_link = 0; #else - is_link = S_ISLNK(mode); + is_link = S_ISLNK((mode_t) mode); #endif mode &= 0777; } @@ -310,11 +353,23 @@ static int do_send(int s, char *path, char *buffer) #else { #endif + unsigned int uid, gid; + uint64_t cap = 0; + uid = getuid(); + gid = getgid(); + /* copy user permission bits to "group" and "other" permissions */ mode |= ((mode >> 3) & 0070); mode |= ((mode >> 3) & 0007); - ret = handle_send_file(s, path, mode, buffer); + tmp = path; + if(*tmp == '/') { + tmp++; + } + if (is_on_system(path)) { + fs_config(tmp, 0, &uid, &gid, &mode, &cap); + } + ret = handle_send_file(s, path, uid, gid, mode, buffer); } return ret;