ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc) { struct fs_path_config_from_file *p = (struct fs_path_config_from_file *)buffer; size_t len = ALIGN(sizeof(*p) + strlen(pc->prefix) + 1, sizeof(uint64_t)); if ((length < len) || (len > UINT16_MAX)) { return -ENOSPC; } memset(p, 0, len); uint16_t host_len = len; p->len = get2LE((const uint8_t *)&host_len); p->mode = get2LE((const uint8_t *)&(pc->mode)); p->uid = get2LE((const uint8_t *)&(pc->uid)); p->gid = get2LE((const uint8_t *)&(pc->gid)); p->capabilities = get8LE((const uint8_t *)&(pc->capabilities)); strcpy(p->prefix, pc->prefix); return len; }
/* * Recursively convert binary log data to printable form. * * This needs to be recursive because you can have lists of lists. * * If we run out of room, we stop processing immediately. It's important * for us to check for space on every output element to avoid producing * garbled output. * * Returns 0 on success, 1 on buffer full, -1 on failure. */ static int android_log_printBinaryEvent(const unsigned char** pEventData, size_t* pEventDataLen, char** pOutBuf, size_t* pOutBufLen) { const unsigned char* eventData = *pEventData; size_t eventDataLen = *pEventDataLen; char* outBuf = *pOutBuf; size_t outBufLen = *pOutBufLen; unsigned char type; size_t outCount; int result = 0; if (eventDataLen < 1) return -1; type = *eventData++; eventDataLen--; //fprintf(stderr, "--- type=%d (rem len=%d)\n", type, eventDataLen); switch (type) { case EVENT_TYPE_INT: /* 32-bit signed int */ { int ival; if (eventDataLen < 4) return -1; ival = get4LE(eventData); eventData += 4; eventDataLen -= 4; outCount = snprintf(outBuf, outBufLen, "%d", ival); if (outCount < outBufLen) { outBuf += outCount; outBufLen -= outCount; } else { /* halt output */ goto no_room; } } break; case EVENT_TYPE_LONG: /* 64-bit signed long */ { long long lval; if (eventDataLen < 8) return -1; lval = get8LE(eventData); eventData += 8; eventDataLen -= 8; outCount = snprintf(outBuf, outBufLen, "%lld", lval); if (outCount < outBufLen) { outBuf += outCount; outBufLen -= outCount; } else { /* halt output */ goto no_room; } } break; case EVENT_TYPE_STRING: /* UTF-8 chars, not NULL-terminated */ { unsigned int strLen; if (eventDataLen < 4) return -1; strLen = get4LE(eventData); eventData += 4; eventDataLen -= 4; if (eventDataLen < strLen) return -1; if (strLen < outBufLen) { memcpy(outBuf, eventData, strLen); outBuf += strLen; outBufLen -= strLen; } else if (outBufLen > 0) { /* copy what we can */ memcpy(outBuf, eventData, outBufLen); outBuf += outBufLen; outBufLen -= outBufLen; goto no_room; } eventData += strLen; eventDataLen -= strLen; break; } case EVENT_TYPE_LIST: /* N items, all different types */ { unsigned char count; int i; if (eventDataLen < 1) return -1; count = *eventData++; eventDataLen--; if (outBufLen > 0) { *outBuf++ = '['; outBufLen--; } else { goto no_room; } for (i = 0; i < count; i++) { result = android_log_printBinaryEvent(&eventData, &eventDataLen, &outBuf, &outBufLen); if (result != 0) goto bail; if (i < count-1) { if (outBufLen > 0) { *outBuf++ = ','; outBufLen--; } else { goto no_room; } } } if (outBufLen > 0) { *outBuf++ = ']'; outBufLen--; } else { goto no_room; } } break; default: fprintf(stderr, "Unknown binary event type %d\n", type); return -1; } bail: *pEventData = eventData; *pEventDataLen = eventDataLen; *pOutBuf = outBuf; *pOutBufLen = outBufLen; return result; no_room: result = 1; goto bail; }
void fs_config(const char *path, int dir, const char *target_out_path, unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities) { const struct fs_path_config *pc; int fd, plen; if (path[0] == '/') { path++; } plen = strlen(path); fd = fs_config_open(dir, target_out_path); if (fd >= 0) { struct fs_path_config_from_file header; while (TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header))) == sizeof(header)) { char *prefix; uint16_t host_len = get2LE((const uint8_t *)&header.len); ssize_t len, remainder = host_len - sizeof(header); if (remainder <= 0) { ALOGE("%s len is corrupted", dir ? conf_dir : conf_file); break; } prefix = calloc(1, remainder); if (!prefix) { ALOGE("%s out of memory", dir ? conf_dir : conf_file); break; } if (TEMP_FAILURE_RETRY(read(fd, prefix, remainder)) != remainder) { free(prefix); ALOGE("%s prefix is truncated", dir ? conf_dir : conf_file); break; } len = strnlen(prefix, remainder); if (len >= remainder) { /* missing a terminating null */ free(prefix); ALOGE("%s is corrupted", dir ? conf_dir : conf_file); break; } if (fs_config_cmp(dir, prefix, len, path, plen)) { free(prefix); close(fd); *uid = get2LE((const uint8_t *)&(header.uid)); *gid = get2LE((const uint8_t *)&(header.gid)); *mode = (*mode & (~07777)) | get2LE((const uint8_t *)&(header.mode)); *capabilities = get8LE((const uint8_t *)&(header.capabilities)); return; } free(prefix); } close(fd); } pc = dir ? android_dirs : android_files; for(; pc->prefix; pc++) { if (fs_config_cmp(dir, pc->prefix, strlen(pc->prefix), path, plen)) { break; } } *uid = pc->uid; *gid = pc->gid; *mode = (*mode & (~07777)) | pc->mode; *capabilities = pc->capabilities; }