No Description

fuse_sideload.cpp 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. /*
  2. * Copyright (C) 2014 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. // This module creates a special filesystem containing two files.
  17. //
  18. // "/sideload/package.zip" appears to be a normal file, but reading
  19. // from it causes data to be fetched from the adb host. We can use
  20. // this to sideload packages over an adb connection without having to
  21. // store the entire package in RAM on the device.
  22. //
  23. // Because we may not trust the adb host, this filesystem maintains
  24. // the following invariant: each read of a given position returns the
  25. // same data as the first read at that position. That is, once a
  26. // section of the file is read, future reads of that section return
  27. // the same data. (Otherwise, a malicious adb host process could
  28. // return one set of bits when the package is read for signature
  29. // verification, and then different bits for when the package is
  30. // accessed by the installer.) If the adb host returns something
  31. // different than it did on the first read, the reader of the file
  32. // will see their read fail with EINVAL.
  33. //
  34. // The other file, "/sideload/exit", is used to control the subprocess
  35. // that creates this filesystem. Calling stat() on the exit file
  36. // causes the filesystem to be unmounted and the adb process on the
  37. // device shut down.
  38. //
  39. // Note that only the minimal set of file operations needed for these
  40. // two files is implemented. In particular, you can't opendir() or
  41. // readdir() on the "/sideload" directory; ls on it won't work.
  42. #include "fuse_sideload.h"
  43. #include <errno.h>
  44. #include <fcntl.h>
  45. #include <limits.h> // PATH_MAX
  46. #include <linux/fuse.h>
  47. #include <stdint.h>
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include <sys/mount.h>
  52. #include <sys/param.h> // MIN
  53. #include <sys/stat.h>
  54. #include <sys/uio.h>
  55. #include <unistd.h>
  56. #include <array>
  57. #include <string>
  58. #include <vector>
  59. #include <android-base/stringprintf.h>
  60. #include <android-base/unique_fd.h>
  61. #include <openssl/sha.h>
  62. static constexpr uint64_t PACKAGE_FILE_ID = FUSE_ROOT_ID + 1;
  63. static constexpr int NO_STATUS = 1;
  64. using SHA256Digest = std::array<uint8_t, SHA256_DIGEST_LENGTH>;
  65. #define INSTALL_REQUIRED_MEMORY (100*1024*1024)
  66. struct fuse_data {
  67. android::base::unique_fd ffd; // file descriptor for the fuse socket
  68. provider_vtab vtab;
  69. uint64_t file_size; // bytes
  70. uint32_t block_size; // block size that the adb host is using to send the file to us
  71. uint32_t file_blocks; // file size in block_size blocks
  72. uid_t uid;
  73. gid_t gid;
  74. uint32_t curr_block; // cache the block most recently used
  75. uint8_t* block_data;
  76. uint8_t* extra_block; // another block of storage for reads that span two blocks
  77. std::vector<SHA256Digest>
  78. hashes; // SHA-256 hash of each block (all zeros if block hasn't been read yet)
  79. // Block cache
  80. uint32_t block_cache_max_size; // Max allowed block cache size
  81. uint32_t block_cache_size; // Current block cache size
  82. uint8_t** block_cache; // Block cache data
  83. };
  84. static uint64_t free_memory() {
  85. uint64_t mem = 0;
  86. FILE* fp = fopen("/proc/meminfo", "r");
  87. if (fp) {
  88. char buf[256];
  89. char* linebuf = buf;
  90. size_t buflen = sizeof(buf);
  91. while (getline(&linebuf, &buflen, fp) > 0) {
  92. char* key = buf;
  93. char* val = strchr(buf, ':');
  94. *val = '\0';
  95. ++val;
  96. if (strcmp(key, "MemFree") == 0) {
  97. mem += strtoul(val, nullptr, 0) * 1024;
  98. }
  99. if (strcmp(key, "Buffers") == 0) {
  100. mem += strtoul(val, nullptr, 0) * 1024;
  101. }
  102. if (strcmp(key, "Cached") == 0) {
  103. mem += strtoul(val, nullptr, 0) * 1024;
  104. }
  105. }
  106. fclose(fp);
  107. }
  108. return mem;
  109. }
  110. static int block_cache_fetch(struct fuse_data* fd, uint32_t block) {
  111. if (fd->block_cache == nullptr) {
  112. return -1;
  113. }
  114. if (fd->block_cache[block] == nullptr) {
  115. return -1;
  116. }
  117. memcpy(fd->block_data, fd->block_cache[block], fd->block_size);
  118. return 0;
  119. }
  120. static void block_cache_enter(struct fuse_data* fd, uint32_t block) {
  121. if (!fd->block_cache)
  122. return;
  123. if (fd->block_cache_size == fd->block_cache_max_size) {
  124. // Evict a block from the cache. Since the file is typically read
  125. // sequentially, start looking from the block behind the current
  126. // block and proceed backward.
  127. int n;
  128. for (n = fd->curr_block - 1; n != (int)fd->curr_block; --n) {
  129. if (n < 0) {
  130. n = fd->file_blocks - 1;
  131. }
  132. if (fd->block_cache[n]) {
  133. free(fd->block_cache[n]);
  134. fd->block_cache[n] = nullptr;
  135. fd->block_cache_size--;
  136. break;
  137. }
  138. }
  139. }
  140. fd->block_cache[block] = (uint8_t*)malloc(fd->block_size);
  141. memcpy(fd->block_cache[block], fd->block_data, fd->block_size);
  142. fd->block_cache_size++;
  143. }
  144. static void fuse_reply(const fuse_data* fd, uint64_t unique, const void* data, size_t len) {
  145. fuse_out_header hdr;
  146. hdr.len = len + sizeof(hdr);
  147. hdr.error = 0;
  148. hdr.unique = unique;
  149. struct iovec vec[2];
  150. vec[0].iov_base = &hdr;
  151. vec[0].iov_len = sizeof(hdr);
  152. vec[1].iov_base = const_cast<void*>(data);
  153. vec[1].iov_len = len;
  154. int res = writev(fd->ffd, vec, 2);
  155. if (res == -1) {
  156. printf("*** REPLY FAILED *** %s\n", strerror(errno));
  157. }
  158. }
  159. static int handle_init(void* data, fuse_data* fd, const fuse_in_header* hdr) {
  160. const fuse_init_in* req = static_cast<const fuse_init_in*>(data);
  161. // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out defined (fuse version 7.6).
  162. // The structure is the same from 7.6 through 7.22. Beginning with 7.23, the structure increased
  163. // in size and added new parameters.
  164. if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
  165. printf("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6", req->major,
  166. req->minor, FUSE_KERNEL_VERSION);
  167. return -1;
  168. }
  169. fuse_init_out out;
  170. out.minor = MIN(req->minor, FUSE_KERNEL_MINOR_VERSION);
  171. size_t fuse_struct_size = sizeof(out);
  172. #if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
  173. /* FUSE_KERNEL_VERSION >= 23. */
  174. // If the kernel only works on minor revs older than or equal to 22, then use the older structure
  175. // size since this code only uses the 7.22 version of the structure.
  176. if (req->minor <= 22) {
  177. fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
  178. }
  179. #endif
  180. out.major = FUSE_KERNEL_VERSION;
  181. out.max_readahead = req->max_readahead;
  182. out.flags = 0;
  183. out.max_background = 32;
  184. out.congestion_threshold = 32;
  185. out.max_write = 4096;
  186. fuse_reply(fd, hdr->unique, &out, fuse_struct_size);
  187. return NO_STATUS;
  188. }
  189. static void fill_attr(fuse_attr* attr, const fuse_data* fd, uint64_t nodeid, uint64_t size,
  190. uint32_t mode) {
  191. *attr = {};
  192. attr->nlink = 1;
  193. attr->uid = fd->uid;
  194. attr->gid = fd->gid;
  195. attr->blksize = 4096;
  196. attr->ino = nodeid;
  197. attr->size = size;
  198. attr->blocks = (size == 0) ? 0 : (((size - 1) / attr->blksize) + 1);
  199. attr->mode = mode;
  200. }
  201. static int handle_getattr(void* /* data */, const fuse_data* fd, const fuse_in_header* hdr) {
  202. fuse_attr_out out = {};
  203. out.attr_valid = 10;
  204. if (hdr->nodeid == FUSE_ROOT_ID) {
  205. fill_attr(&(out.attr), fd, hdr->nodeid, 4096, S_IFDIR | 0555);
  206. } else if (hdr->nodeid == PACKAGE_FILE_ID) {
  207. fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444);
  208. } else {
  209. return -ENOENT;
  210. }
  211. fuse_reply(fd, hdr->unique, &out, sizeof(out));
  212. return NO_STATUS;
  213. }
  214. static int handle_lookup(void* data, const fuse_data* fd, const fuse_in_header* hdr) {
  215. if (data == nullptr) return -ENOENT;
  216. fuse_entry_out out = {};
  217. out.entry_valid = 10;
  218. out.attr_valid = 10;
  219. std::string filename(static_cast<const char*>(data));
  220. if (filename == FUSE_SIDELOAD_HOST_FILENAME) {
  221. out.nodeid = PACKAGE_FILE_ID;
  222. out.generation = PACKAGE_FILE_ID;
  223. fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444);
  224. } else {
  225. return -ENOENT;
  226. }
  227. fuse_reply(fd, hdr->unique, &out, sizeof(out));
  228. return NO_STATUS;
  229. }
  230. static int handle_open(void* /* data */, const fuse_data* fd, const fuse_in_header* hdr) {
  231. if (hdr->nodeid != PACKAGE_FILE_ID) return -ENOENT;
  232. fuse_open_out out = {};
  233. out.fh = 10; // an arbitrary number; we always use the same handle
  234. fuse_reply(fd, hdr->unique, &out, sizeof(out));
  235. return NO_STATUS;
  236. }
  237. static int handle_flush(void* /* data */, fuse_data* /* fd */, const fuse_in_header* /* hdr */) {
  238. return 0;
  239. }
  240. static int handle_release(void* /* data */, fuse_data* /* fd */, const fuse_in_header* /* hdr */) {
  241. return 0;
  242. }
  243. // Fetch a block from the host into fd->curr_block and fd->block_data.
  244. // Returns 0 on successful fetch, negative otherwise.
  245. static int fetch_block(fuse_data* fd, uint32_t block) {
  246. if (block == fd->curr_block) {
  247. return 0;
  248. }
  249. if (block >= fd->file_blocks) {
  250. memset(fd->block_data, 0, fd->block_size);
  251. fd->curr_block = block;
  252. return 0;
  253. }
  254. if (block_cache_fetch(fd, block) == 0) {
  255. fd->curr_block = block;
  256. return 0;
  257. }
  258. size_t fetch_size = fd->block_size;
  259. if (block * fd->block_size + fetch_size > fd->file_size) {
  260. // If we're reading the last (partial) block of the file, expect a shorter response from the
  261. // host, and pad the rest of the block with zeroes.
  262. fetch_size = fd->file_size - (block * fd->block_size);
  263. memset(fd->block_data + fetch_size, 0, fd->block_size - fetch_size);
  264. }
  265. int result = fd->vtab.read_block(block, fd->block_data, fetch_size);
  266. if (result < 0) return result;
  267. fd->curr_block = block;
  268. // Verify the hash of the block we just got from the host.
  269. //
  270. // - If the hash of the just-received data matches the stored hash for the block, accept it.
  271. // - If the stored hash is all zeroes, store the new hash and accept the block (this is the first
  272. // time we've read this block).
  273. // - Otherwise, return -EINVAL for the read.
  274. SHA256Digest hash;
  275. SHA256(fd->block_data, fd->block_size, hash.data());
  276. const SHA256Digest& blockhash = fd->hashes[block];
  277. if (hash == blockhash) {
  278. return 0;
  279. }
  280. for (uint8_t i : blockhash) {
  281. if (i != 0) {
  282. fd->curr_block = -1;
  283. return -EIO;
  284. }
  285. }
  286. fd->hashes[block] = hash;
  287. block_cache_enter(fd, block);
  288. return 0;
  289. }
  290. static int handle_read(void* data, fuse_data* fd, const fuse_in_header* hdr) {
  291. if (hdr->nodeid != PACKAGE_FILE_ID) return -ENOENT;
  292. const fuse_read_in* req = static_cast<const fuse_read_in*>(data);
  293. uint64_t offset = req->offset;
  294. uint32_t size = req->size;
  295. // The docs on the fuse kernel interface are vague about what to do when a read request extends
  296. // past the end of the file. We can return a short read -- the return structure does include a
  297. // length field -- but in testing that caused the program using the file to segfault. (I
  298. // speculate that this is due to the reading program accessing it via mmap; maybe mmap dislikes
  299. // when you return something short of a whole page?) To fix this we zero-pad reads that extend
  300. // past the end of the file so we're always returning exactly as many bytes as were requested.
  301. // (Users of the mapped file have to know its real length anyway.)
  302. fuse_out_header outhdr;
  303. outhdr.len = sizeof(outhdr) + size;
  304. outhdr.error = 0;
  305. outhdr.unique = hdr->unique;
  306. struct iovec vec[3];
  307. vec[0].iov_base = &outhdr;
  308. vec[0].iov_len = sizeof(outhdr);
  309. uint32_t block = offset / fd->block_size;
  310. int result = fetch_block(fd, block);
  311. if (result != 0) return result;
  312. // Two cases:
  313. //
  314. // - the read request is entirely within this block. In this case we can reply immediately.
  315. //
  316. // - the read request goes over into the next block. Note that since we mount the filesystem
  317. // with max_read=block_size, a read can never span more than two blocks. In this case we copy
  318. // the block to extra_block and issue a fetch for the following block.
  319. uint32_t block_offset = offset - (block * fd->block_size);
  320. int vec_used;
  321. if (size + block_offset <= fd->block_size) {
  322. // First case: the read fits entirely in the first block.
  323. vec[1].iov_base = fd->block_data + block_offset;
  324. vec[1].iov_len = size;
  325. vec_used = 2;
  326. } else {
  327. // Second case: the read spills over into the next block.
  328. memcpy(fd->extra_block, fd->block_data + block_offset, fd->block_size - block_offset);
  329. vec[1].iov_base = fd->extra_block;
  330. vec[1].iov_len = fd->block_size - block_offset;
  331. result = fetch_block(fd, block + 1);
  332. if (result != 0) return result;
  333. vec[2].iov_base = fd->block_data;
  334. vec[2].iov_len = size - vec[1].iov_len;
  335. vec_used = 3;
  336. }
  337. if (writev(fd->ffd, vec, vec_used) == -1) {
  338. printf("*** READ REPLY FAILED: %s ***\n", strerror(errno));
  339. }
  340. return NO_STATUS;
  341. }
  342. static volatile int terminated = 0;
  343. static void sig_term(int)
  344. {
  345. terminated = 1;
  346. }
  347. int run_fuse_sideload(const provider_vtab& vtab, uint64_t file_size, uint32_t block_size,
  348. const char* mount_point) {
  349. // If something's already mounted on our mountpoint, try to remove it. (Mostly in case of a
  350. // previous abnormal exit.)
  351. umount2(mount_point, MNT_FORCE);
  352. // fs/fuse/inode.c in kernel code uses the greater of 4096 and the passed-in max_read.
  353. if (block_size < 4096) {
  354. fprintf(stderr, "block size (%u) is too small\n", block_size);
  355. return -1;
  356. }
  357. if (block_size > (1 << 22)) { // 4 MiB
  358. fprintf(stderr, "block size (%u) is too large\n", block_size);
  359. return -1;
  360. }
  361. fuse_data fd = {};
  362. fd.vtab = vtab;
  363. fd.file_size = file_size;
  364. fd.block_size = block_size;
  365. fd.file_blocks = (file_size == 0) ? 0 : (((file_size - 1) / block_size) + 1);
  366. uint64_t mem = free_memory();
  367. uint64_t avail = mem - (INSTALL_REQUIRED_MEMORY + fd.file_blocks * sizeof(uint8_t*));
  368. int result;
  369. if (fd.file_blocks > (1 << 18)) {
  370. fprintf(stderr, "file has too many blocks (%u)\n", fd.file_blocks);
  371. result = -1;
  372. goto done;
  373. }
  374. // All hashes will be zero-initialized.
  375. fd.hashes.resize(fd.file_blocks);
  376. fd.uid = getuid();
  377. fd.gid = getgid();
  378. fd.curr_block = -1;
  379. fd.block_data = static_cast<uint8_t*>(malloc(block_size));
  380. if (fd.block_data == nullptr) {
  381. fprintf(stderr, "failed to allocate %d bites for block_data\n", block_size);
  382. result = -1;
  383. goto done;
  384. }
  385. fd.extra_block = static_cast<uint8_t*>(malloc(block_size));
  386. if (fd.extra_block == nullptr) {
  387. fprintf(stderr, "failed to allocate %d bites for extra_block\n", block_size);
  388. result = -1;
  389. goto done;
  390. }
  391. fd.block_cache_max_size = 0;
  392. fd.block_cache_size = 0;
  393. fd.block_cache = nullptr;
  394. if (mem > avail) {
  395. uint32_t max_size = avail / fd.block_size;
  396. if (max_size > fd.file_blocks) {
  397. max_size = fd.file_blocks;
  398. }
  399. // The cache must be at least 1% of the file size or two blocks,
  400. // whichever is larger.
  401. if (max_size >= fd.file_blocks/100 && max_size >= 2) {
  402. fd.block_cache_max_size = max_size;
  403. fd.block_cache = (uint8_t**)calloc(fd.file_blocks, sizeof(uint8_t*));
  404. }
  405. }
  406. signal(SIGTERM, sig_term);
  407. fd.ffd.reset(open("/dev/fuse", O_RDWR));
  408. if (!fd.ffd) {
  409. perror("open /dev/fuse");
  410. result = -1;
  411. goto done;
  412. }
  413. {
  414. std::string opts = android::base::StringPrintf(
  415. "fd=%d,user_id=%d,group_id=%d,max_read=%u,allow_other,rootmode=040000", fd.ffd.get(),
  416. fd.uid, fd.gid, block_size);
  417. result = mount("/dev/fuse", mount_point, "fuse", MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC,
  418. opts.c_str());
  419. if (result == -1) {
  420. perror("mount");
  421. goto done;
  422. }
  423. }
  424. uint8_t request_buffer[sizeof(fuse_in_header) + PATH_MAX * 8];
  425. while (!terminated) {
  426. fd_set fds;
  427. struct timeval tv;
  428. FD_ZERO(&fds);
  429. FD_SET(fd.ffd, &fds);
  430. tv.tv_sec = 1;
  431. tv.tv_usec = 0;
  432. int rc = select(fd.ffd+1, &fds, nullptr, nullptr, &tv);
  433. if (rc <= 0) {
  434. continue;
  435. }
  436. ssize_t len = TEMP_FAILURE_RETRY(read(fd.ffd, request_buffer, sizeof(request_buffer)));
  437. if (len == -1) {
  438. perror("read request");
  439. if (errno == ENODEV) {
  440. result = -1;
  441. break;
  442. }
  443. continue;
  444. }
  445. if (static_cast<size_t>(len) < sizeof(fuse_in_header)) {
  446. fprintf(stderr, "request too short: len=%zd\n", len);
  447. continue;
  448. }
  449. fuse_in_header* hdr = reinterpret_cast<fuse_in_header*>(request_buffer);
  450. void* data = request_buffer + sizeof(fuse_in_header);
  451. result = -ENOSYS;
  452. switch (hdr->opcode) {
  453. case FUSE_INIT:
  454. result = handle_init(data, &fd, hdr);
  455. break;
  456. case FUSE_LOOKUP:
  457. result = handle_lookup(data, &fd, hdr);
  458. break;
  459. case FUSE_GETATTR:
  460. result = handle_getattr(data, &fd, hdr);
  461. break;
  462. case FUSE_OPEN:
  463. result = handle_open(data, &fd, hdr);
  464. break;
  465. case FUSE_READ:
  466. result = handle_read(data, &fd, hdr);
  467. break;
  468. case FUSE_FLUSH:
  469. result = handle_flush(data, &fd, hdr);
  470. break;
  471. case FUSE_RELEASE:
  472. result = handle_release(data, &fd, hdr);
  473. break;
  474. default:
  475. fprintf(stderr, "unknown fuse request opcode %d\n", hdr->opcode);
  476. break;
  477. }
  478. if (result != NO_STATUS) {
  479. fuse_out_header outhdr;
  480. outhdr.len = sizeof(outhdr);
  481. outhdr.error = result;
  482. outhdr.unique = hdr->unique;
  483. TEMP_FAILURE_RETRY(write(fd.ffd, &outhdr, sizeof(outhdr)));
  484. }
  485. }
  486. done:
  487. fd.vtab.close();
  488. if (umount2(mount_point, MNT_DETACH) == -1) {
  489. fprintf(stderr, "fuse_sideload umount failed: %s\n", strerror(errno));
  490. }
  491. if (fd.block_cache) {
  492. uint32_t n;
  493. for (n = 0; n < fd.file_blocks; ++n) {
  494. free(fd.block_cache[n]);
  495. }
  496. free(fd.block_cache);
  497. }
  498. free(fd.block_data);
  499. free(fd.extra_block);
  500. return result;
  501. }