static void fix_stat(const char *path, struct stat *s) { uint64_t capabilities; if (canned_config) { // Use the list of file uid/gid/modes loaded from the file // given with -f. struct fs_config_entry* empty_path_config = NULL; struct fs_config_entry* p; for (p = canned_config; p->name; ++p) { if (!p->name[0]) { empty_path_config = p; } if (strcmp(p->name, path) == 0) { s->st_uid = p->uid; s->st_gid = p->gid; s->st_mode = p->mode | (s->st_mode & ~07777); return; } } s->st_uid = empty_path_config->uid; s->st_gid = empty_path_config->gid; s->st_mode = empty_path_config->mode | (s->st_mode & ~07777); } else { // Use the compiled-in fs_config() function. unsigned st_mode = s->st_mode; fs_config(path, S_ISDIR(s->st_mode), target_out_path, &s->st_uid, &s->st_gid, &st_mode, &capabilities); s->st_mode = (typeof(s->st_mode)) st_mode; } }
static void* append_cpio_header_to_stream(struct stat s,char *filename, byte_p output_header){ static unsigned next_inode = 300000; size_t namesize= strlen(filename)+1; unsigned filesize = S_ISDIR(s.st_mode) ? 0 : s.st_size; unsigned long namealign = ((4 - ((CPIO_HEADER_SIZE+namesize) % 4)) % 4); uint64_t capabilities; fs_config(filename, S_ISDIR(s.st_mode),(unsigned*) &s.st_uid, (unsigned*)&s.st_gid, (unsigned*)&s.st_mode,&capabilities); sprintf((char*)output_header,"%06x%08x%08x%08x%08x%08x%08x" "%08x%08x%08x%08x%08x%08x%08x%s", 0x070701, next_inode++, // s.st_ino, s.st_mode, 0, // s.st_uid, 0, // s.st_gid, 1, // s.st_nlink, 0, // s.st_mtime, filesize , 0, // volmajor 0, // volminor 0, // devmajor 0, // devminor, namesize , 0,filename ); //fprintf(stderr,"namealign:%d %p %p\n",namealign,output_header,output_header); output_header+=(CPIO_HEADER_SIZE+namesize); strncat(output_header,"\0\0\0\0",namealign); //fprintf(stderr,"Out:%p\n", output_header); output_header+=namealign; return output_header; }
static int mkdirs(char *name) { int ret; char *x = name + 1; uid_t uid = -1; gid_t gid = -1; unsigned int mode = 0775; uint64_t cap = 0; if(name[0] != '/') return -1; for(;;) { x = adb_dirstart(x); if(x == 0) return 0; *x = 0; if (is_on_system(name) || is_on_vendor(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, 0); } *x++ = '/'; } return 0; }
void canned_fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) { Path key; key.path = path+1; // canned paths lack the leading '/' Path* p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare); if (p == NULL) { fprintf(stderr, "failed to find [%s] in canned fs_config\n", path); exit(1); } *uid = p->uid; *gid = p->gid; *mode = p->mode; *capabilities = p->capabilities; #if 0 // for debugging, run the built-in fs_config and compare the results. unsigned c_uid, c_gid, c_mode; uint64_t c_capabilities; fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities); if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid); if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid); if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode); if (c_capabilities != *capabilities) printf("%s capabilities %llx %llx\n", path, *capabilities, c_capabilities); #endif }
static bool secure_mkdirs(const std::string& path) { uid_t uid = -1; gid_t gid = -1; unsigned int mode = 0775; uint64_t cap = 0; if (path[0] != '/') return false; std::vector<std::string> path_components = android::base::Split(path, "/"); path_components.pop_back(); // For "/system/bin/sh", only create "/system/bin". std::string partial_path; for (const auto& path_component : path_components) { if (partial_path.back() != OS_PATH_SEPARATOR) partial_path += OS_PATH_SEPARATOR; partial_path += path_component; if (should_use_fs_config(partial_path)) { fs_config(partial_path.c_str(), 1, nullptr, &uid, &gid, &mode, &cap); } if (adb_mkdir(partial_path.c_str(), mode) == -1) { if (errno != EEXIST) { return false; } } else { if (chown(partial_path.c_str(), uid, gid) == -1) { return false; } // Not all filesystems support setting SELinux labels. http://b/23530370. selinux_android_restorecon(partial_path.c_str(), 0); } } return true; }
static bool do_send(int s, const std::string& spec, std::vector<char>& buffer) { // 'spec' is of the form "/some/path,0755". Break it up. size_t comma = spec.find_last_of(','); if (comma == std::string::npos) { SendFail(s, "missing , in ID_SEND"); return false; } std::string path = spec.substr(0, comma); errno = 0; mode_t mode = strtoul(spec.substr(comma + 1).c_str(), nullptr, 0); if (errno != 0) { SendFail(s, "bad mode"); return false; } // Don't delete files before copying if they are not "regular" or symlinks. struct stat st; bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode); if (do_unlink) { adb_unlink(path.c_str()); } if (S_ISLNK(mode)) { return handle_send_link(s, path.c_str(), buffer); } // Copy user permission bits to "group" and "other" permissions. mode &= 0777; mode |= ((mode >> 3) & 0070); mode |= ((mode >> 3) & 0007); uid_t uid = -1; gid_t gid = -1; uint64_t cap = 0; if (should_use_fs_config(path)) { unsigned int broken_api_hack = mode; fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &cap); mode = broken_api_hack; } return handle_send_file(s, path.c_str(), uid, gid, mode, buffer, do_unlink); }
static void fix_stat(const char *path, struct stat *s) { uint64_t capabilities; path += source_path_len; fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode, &capabilities); }
static void fix_stat(const char *path, struct stat *s) { path += source_path_len; fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode); }
int main(int argc, char** argv) { char buffer[1024]; const char* context_file = NULL; struct selabel_handle* sehnd = NULL; int print_capabilities = 0; int opt; while((opt = getopt(argc, argv, "CS:")) != -1) { switch(opt) { case 'C': print_capabilities = 1; break; case 'S': context_file = optarg; break; default: usage(); exit(EXIT_FAILURE); } } if (context_file != NULL) { sehnd = get_sehnd(context_file); } while (fgets(buffer, 1023, stdin) != NULL) { int is_dir = 0; int i; for (i = 0; i < 1024 && buffer[i]; ++i) { switch (buffer[i]) { case '\n': buffer[i-is_dir] = '\0'; i = 1025; break; case '/': is_dir = 1; break; default: is_dir = 0; break; } } unsigned uid = 0, gid = 0, mode = 0; uint64_t capabilities; fs_config(buffer, is_dir, &uid, &gid, &mode, &capabilities); printf("%s %d %d %o", buffer, uid, gid, mode); if (sehnd != NULL) { size_t buffer_strlen = strnlen(buffer, sizeof(buffer)); if (buffer_strlen >= sizeof(buffer)) { fprintf(stderr, "non null terminated buffer, aborting\n"); exit(EXIT_FAILURE); } size_t full_name_size = buffer_strlen + 2; char* full_name = (char*) malloc(full_name_size); if (full_name == NULL) { perror("malloc"); exit(EXIT_FAILURE); } full_name[0] = '/'; strncpy(full_name + 1, buffer, full_name_size - 1); full_name[full_name_size - 1] = '\0'; char* secontext; if (selabel_lookup(sehnd, &secontext, full_name, ( mode | (is_dir ? S_IFDIR : S_IFREG)))) { secontext = strdup("u:object_r:unlabeled:s0"); } printf(" selabel=%s", secontext); free(full_name); freecon(secontext); } if (print_capabilities) { printf(" capabilities=0x%" PRIx64, capabilities); } printf("\n"); } return 0; }
static int do_send(int s, char *path, char *buffer) { char *tmp; unsigned int mode; int is_link, ret; bool do_unlink; tmp = strrchr(path,','); if(tmp) { *tmp = 0; errno = 0; mode = strtoul(tmp + 1, NULL, 0); #ifndef HAVE_SYMLINKS is_link = 0; #else is_link = S_ISLNK((mode_t) mode); #endif mode &= 0777; } if(!tmp || errno) { mode = 0644; is_link = 0; do_unlink = true; } else { struct stat st; /* Don't delete files before copying if they are not "regular" */ do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode); if (do_unlink) { adb_unlink(path); } } #ifdef HAVE_SYMLINKS if(is_link) ret = handle_send_link(s, path, buffer); else { #else { #endif uid_t uid = -1; gid_t gid = -1; uint64_t cap = 0; /* copy user permission bits to "group" and "other" permissions */ mode |= ((mode >> 3) & 0070); mode |= ((mode >> 3) & 0007); tmp = path; if(*tmp == '/') { tmp++; } if (is_on_system(path) || is_on_vendor(path)) { fs_config(tmp, 0, &uid, &gid, &mode, &cap); } ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink); } return ret; } static int do_recv(int s, const char *path, char *buffer) { syncmsg msg; int fd, r; fd = adb_open(path, O_RDONLY | O_CLOEXEC); if(fd < 0) { if(fail_errno(s)) return -1; return 0; } msg.data.id = ID_DATA; for(;;) { if(syc_size_enabled == 1) { r = adb_read(fd, buffer, SYNC_DATA_MAX_CUSTOMIZE); } else { r = adb_read(fd, buffer, SYNC_DATA_MAX); } if(r <= 0) { if(r == 0) break; if(errno == EINTR) continue; r = fail_errno(s); adb_close(fd); return r; } msg.data.size = htoll(r); if(writex(s, &msg.data, sizeof(msg.data)) || writex(s, buffer, r)) { adb_close(fd); return -1; } } adb_close(fd); msg.data.id = ID_DONE; msg.data.size = 0; if(writex(s, &msg.data, sizeof(msg.data))) { return -1; } return 0; }
static void fix_stat(const char *path, struct stat *s) { fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &s->st_mode); }