1
0

libluksmeta.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. /* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
  2. /*
  3. * Copyright (c) 2016 Red Hat, Inc.
  4. * Author: Nathaniel McCallum <npmccallum@redhat.com>
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation, either version 2.1 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "crc32c.h"
  20. #include "luksmeta.h"
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <errno.h>
  24. #include <fcntl.h>
  25. #include <stdbool.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #define ALIGN(s, up) (((s) + (up ? 4095 : 0)) & ~4095ULL)
  30. #define LUKS_NSLOTS 8
  31. #define LM_VERSION 1
  32. static const uint8_t LM_MAGIC[] = { 'L', 'U', 'K', 'S', 'M', 'E', 'T', 'A' };
  33. typedef struct __attribute__((packed)) {
  34. luksmeta_uuid_t uuid;
  35. uint32_t offset; /* Bytes from the start of the hole */
  36. uint32_t length; /* Bytes */
  37. uint32_t crc32c;
  38. uint32_t _reserved; /* Reserved */
  39. } lm_slot_t;
  40. typedef struct __attribute__((packed)) {
  41. uint8_t magic[sizeof(LM_MAGIC)];
  42. uint32_t version;
  43. uint32_t crc32c;
  44. lm_slot_t slots[LUKS_NSLOTS];
  45. } lm_t;
  46. static bool
  47. uuid_is_zero(const luksmeta_uuid_t uuid)
  48. {
  49. for (size_t i = 0; i < sizeof(luksmeta_uuid_t); i++) {
  50. if (uuid[i] != 0)
  51. return false;
  52. }
  53. return true;
  54. }
  55. static inline uint32_t
  56. checksum(lm_t lm)
  57. {
  58. lm.crc32c = 0;
  59. return crc32c(0, &lm, sizeof(lm_t));
  60. }
  61. static inline bool
  62. overlap(const lm_t *lm, uint32_t start, size_t end)
  63. {
  64. for (int i = 0; i < LUKS_NSLOTS; i++) {
  65. const lm_slot_t *s = &lm->slots[i];
  66. uint32_t e = s->offset + s->length;
  67. if (start <= s->offset && s->offset < end)
  68. return true;
  69. if (start < e && e <= end)
  70. return true;
  71. }
  72. return false;
  73. }
  74. static inline uint32_t
  75. find_gap(const lm_t *lm, uint32_t length, size_t size)
  76. {
  77. size = ALIGN(size, true);
  78. for (uint32_t off = ALIGN(1, true); off < length; off += ALIGN(1, true)) {
  79. if (!overlap(lm, off, off + size))
  80. return off;
  81. }
  82. return 0;
  83. }
  84. static int
  85. find_unused_slot(struct crypt_device *cd, const lm_t *lm)
  86. {
  87. for (int slot = 0; slot < LUKS_NSLOTS; slot++) {
  88. if (crypt_keyslot_status(cd, slot) == CRYPT_SLOT_INACTIVE &&
  89. uuid_is_zero(lm->slots[slot].uuid))
  90. return slot;
  91. }
  92. return -1;
  93. }
  94. static inline ssize_t
  95. readall(int fd, void *data, size_t size)
  96. {
  97. uint8_t *tmp = data;
  98. for (ssize_t r, t = 0; t < (ssize_t) size; t += r) {
  99. r = read(fd, &tmp[t], size - t);
  100. if (r < 0 && errno != EAGAIN)
  101. return -errno;
  102. if (r == 0)
  103. return -ENOENT;
  104. }
  105. return size;
  106. }
  107. static inline ssize_t
  108. writeall(int fd, const void *buf, size_t size)
  109. {
  110. const uint8_t *tmp = buf;
  111. for (ssize_t r, t = 0; t < (ssize_t) size; t += r) {
  112. r = write(fd, &tmp[t], size - t);
  113. if (r < 0) {
  114. if (errno != EAGAIN)
  115. return -errno;
  116. r = 0;
  117. }
  118. }
  119. return size;
  120. }
  121. /**
  122. * Opens the device with the specified flags.
  123. *
  124. * The length parameter is set to the amount of space in the gap between the
  125. * end of the last slot and the start of the encrypted data.
  126. *
  127. * The function returns either the file descriptor positioned to the start of
  128. * the hole or a negative errno.
  129. */
  130. static int
  131. open_hole(struct crypt_device *cd, int flags, uint32_t *length)
  132. {
  133. const char *name = NULL;
  134. const char *type = NULL;
  135. uint64_t hole = 0;
  136. uint64_t data = 0;
  137. int fd = 0;
  138. int r = 0;
  139. type = crypt_get_type(cd);
  140. if (!type || strcmp(CRYPT_LUKS1, type) != 0)
  141. return -ENOTSUP;
  142. data = crypt_get_data_offset(cd) * 512;
  143. if (data < 4096)
  144. return -ENOSPC;
  145. for (int slot = 0; slot < LUKS_NSLOTS; slot++) {
  146. uint64_t off = 0;
  147. uint64_t len = 0;
  148. r = crypt_keyslot_area(cd, slot, &off, &len);
  149. if (r < 0)
  150. return r;
  151. if (hole < off + len)
  152. hole = ALIGN(off + len, true);
  153. }
  154. if (hole == 0)
  155. return -ENOTSUP;
  156. if (hole >= data)
  157. return -ENOSPC;
  158. name = crypt_get_device_name(cd);
  159. if (!name)
  160. return -ENOTSUP;
  161. fd = open(name, flags);
  162. if (fd < 0)
  163. return -errno;
  164. if (lseek(fd, hole, SEEK_SET) == -1) {
  165. close(fd);
  166. return -errno;
  167. }
  168. *length = ALIGN(data - hole, false);
  169. return fd;
  170. }
  171. static int
  172. read_header(struct crypt_device *cd, int flags, uint32_t *length, lm_t *lm)
  173. {
  174. uint32_t maxlen;
  175. int fd = -1;
  176. int r = 0;
  177. fd = open_hole(cd, flags, length);
  178. if (fd < 0)
  179. return fd;
  180. r = *length >= sizeof(lm_t) ? 0 : -ENOENT;
  181. if (r < 0)
  182. goto error;
  183. r = readall(fd, lm, sizeof(lm_t));
  184. if (r < 0)
  185. goto error;
  186. r = memcmp(LM_MAGIC, lm->magic, sizeof(LM_MAGIC)) == 0 ? 0 : -ENOENT;
  187. if (r < 0)
  188. goto error;
  189. r = lm->version == htobe32(LM_VERSION) ? 0 : -ENOTSUP;
  190. if (r < 0)
  191. goto error;
  192. lm->crc32c = be32toh(lm->crc32c);
  193. r = checksum(*lm) == lm->crc32c ? 0 : -EINVAL;
  194. if (r < 0)
  195. goto error;
  196. lm->version = be32toh(lm->version);
  197. maxlen = *length - ALIGN(sizeof(lm_t), true);
  198. for (int slot = 0; slot < LUKS_NSLOTS; slot++) {
  199. lm_slot_t *s = &lm->slots[slot];
  200. s->offset = be32toh(s->offset);
  201. s->length = be32toh(s->length);
  202. s->crc32c = be32toh(s->crc32c);
  203. if (!uuid_is_zero(s->uuid)) {
  204. r = s->offset > sizeof(lm_t) ? 0 : -EINVAL;
  205. if (r < 0)
  206. goto error;
  207. r = s->length <= maxlen ? 0 : -EINVAL;
  208. if (r < 0)
  209. goto error;
  210. }
  211. }
  212. return fd;
  213. error:
  214. close(fd);
  215. return r;
  216. }
  217. static int
  218. write_header(int fd, lm_t lm)
  219. {
  220. for (int slot = 0; slot < LUKS_NSLOTS; slot++) {
  221. lm.slots[slot].offset = htobe32(lm.slots[slot].offset);
  222. lm.slots[slot].length = htobe32(lm.slots[slot].length);
  223. lm.slots[slot].crc32c = htobe32(lm.slots[slot].crc32c);
  224. }
  225. memcpy(lm.magic, LM_MAGIC, sizeof(LM_MAGIC));
  226. lm.version = htobe32(LM_VERSION);
  227. lm.crc32c = htobe32(checksum(lm));
  228. return writeall(fd, &lm, sizeof(lm));
  229. }
  230. int
  231. luksmeta_test(struct crypt_device *cd)
  232. {
  233. int fd = -1;
  234. fd = read_header(cd, O_RDONLY, &(uint32_t) {0}, &(lm_t) {});
  235. if (fd >= 0) {
  236. close(fd);
  237. return 0;
  238. }
  239. return fd;
  240. }
  241. int
  242. luksmeta_nuke(struct crypt_device *cd)
  243. {
  244. uint8_t zero[ALIGN(1, true)] = {};
  245. uint32_t length = 0;
  246. int fd = -1;
  247. int r = 0;
  248. fd = open_hole(cd, O_RDWR | O_SYNC, &length);
  249. if (fd < 0)
  250. return fd;
  251. for (size_t i = 0; r >= 0 && i < length; i += sizeof(zero))
  252. r = writeall(fd, zero, sizeof(zero));
  253. close(fd);
  254. return r < 0 ? r : 0;
  255. }
  256. int
  257. luksmeta_init(struct crypt_device *cd)
  258. {
  259. uint32_t length = 0;
  260. int fd = -1;
  261. int r = 0;
  262. r = luksmeta_test(cd);
  263. if (r == 0)
  264. return -EALREADY;
  265. else if (r != -ENOENT && r != -EINVAL)
  266. return r;
  267. fd = open_hole(cd, O_RDWR | O_SYNC, &length);
  268. if (fd < 0)
  269. return fd;
  270. if (length < ALIGN(sizeof(lm_t), true)) {
  271. close(fd);
  272. return -ENOSPC;
  273. }
  274. r = write_header(fd, (lm_t) {});
  275. close(fd);
  276. return r > 0 ? 0 : r;
  277. }
  278. int
  279. luksmeta_load(struct crypt_device *cd, int slot,
  280. luksmeta_uuid_t uuid, void *buf, size_t size)
  281. {
  282. uint32_t length = 0;
  283. lm_slot_t *s = NULL;
  284. lm_t lm = {};
  285. int fd = -1;
  286. int r = 0;
  287. if (slot < 0 || slot >= LUKS_NSLOTS)
  288. return -EBADSLT;
  289. s = &lm.slots[slot];
  290. fd = read_header(cd, O_RDONLY, &length, &lm);
  291. if (fd < 0)
  292. return fd;
  293. r = uuid_is_zero(s->uuid) ? -ENODATA : 0;
  294. if (r < 0)
  295. goto error;
  296. if (buf) {
  297. r = size >= s->length ? 0 : -E2BIG;
  298. if (r < 0)
  299. goto error;
  300. r = lseek(fd, s->offset - sizeof(lm), SEEK_CUR) == -1 ? -errno : 0;
  301. if (r < 0)
  302. goto error;
  303. r = readall(fd, buf, s->length);
  304. if (r < 0)
  305. goto error;
  306. r = crc32c(0, buf, s->length) == s->crc32c ? 0 : -EINVAL;
  307. if (r < 0)
  308. goto error;
  309. }
  310. memcpy(uuid, s->uuid, sizeof(luksmeta_uuid_t));
  311. close(fd);
  312. return s->length;
  313. error:
  314. close(fd);
  315. return r;
  316. }
  317. int
  318. luksmeta_save(struct crypt_device *cd, int slot,
  319. const luksmeta_uuid_t uuid, const void *buf, size_t size)
  320. {
  321. uint32_t length = 0;
  322. lm_slot_t *s = NULL;
  323. lm_t lm = {};
  324. int fd = -1;
  325. int r = 0;
  326. off_t off;
  327. if (uuid_is_zero(uuid))
  328. return -EKEYREJECTED;
  329. fd = read_header(cd, O_RDWR | O_SYNC, &length, &lm);
  330. if (fd < 0)
  331. return fd;
  332. if (slot == CRYPT_ANY_SLOT)
  333. slot = find_unused_slot(cd, &lm);
  334. r = slot >= 0 && slot < LUKS_NSLOTS ? 0 : -EBADSLT;
  335. if (r < 0)
  336. goto error;
  337. s = &lm.slots[slot];
  338. r = uuid_is_zero(s->uuid) ? 0 : -EALREADY;
  339. if (r < 0)
  340. goto error;
  341. s->offset = find_gap(&lm, length, size);
  342. r = s->offset >= ALIGN(sizeof(lm), true) ? 0 : -ENOSPC;
  343. if (r < 0)
  344. goto error;
  345. memcpy(s->uuid, uuid, sizeof(luksmeta_uuid_t));
  346. s->length = size;
  347. s->crc32c = crc32c(0, buf, size);
  348. off = s->offset - sizeof(lm);
  349. r = lseek(fd, off, SEEK_CUR) == -1 ? -errno : 0;
  350. if (r < 0)
  351. goto error;
  352. r = writeall(fd, buf, size);
  353. if (r < 0)
  354. goto error;
  355. off = s->offset + s->length;
  356. r = lseek(fd, -off, SEEK_CUR) == -1 ? -errno : 0;
  357. if (r < 0)
  358. goto error;
  359. r = write_header(fd, lm);
  360. error:
  361. close(fd);
  362. return r < 0 ? r : slot;
  363. }
  364. int
  365. luksmeta_wipe(struct crypt_device *cd, int slot, const luksmeta_uuid_t uuid)
  366. {
  367. uint8_t *zero = NULL;
  368. uint32_t length = 0;
  369. lm_slot_t *s = NULL;
  370. lm_t lm = {};
  371. int fd = -1;
  372. int r = 0;
  373. off_t off;
  374. if (slot < 0 || slot >= LUKS_NSLOTS)
  375. return -EBADSLT;
  376. s = &lm.slots[slot];
  377. fd = read_header(cd, O_RDWR | O_SYNC, &length, &lm);
  378. if (fd < 0)
  379. return fd;
  380. r = uuid_is_zero(s->uuid) ? -EALREADY : 0;
  381. if (r < 0)
  382. goto error;
  383. if (uuid && memcmp(uuid, s->uuid, sizeof(luksmeta_uuid_t)) != 0) {
  384. r = -EKEYREJECTED;
  385. goto error;
  386. }
  387. off = s->offset - sizeof(lm_t);
  388. r = lseek(fd, off, SEEK_CUR) == -1 ? -errno : 0;
  389. if (r < 0)
  390. goto error;
  391. r = (zero = calloc(1, s->length)) ? 0 : -errno;
  392. if (r < 0)
  393. goto error;
  394. r = writeall(fd, zero, s->length);
  395. free(zero);
  396. if (r < 0)
  397. goto error;
  398. off = s->offset + s->length;
  399. r = lseek(fd, -off, SEEK_CUR) == -1 ? -errno : 0;
  400. if (r < 0)
  401. goto error;
  402. memset(s, 0, sizeof(lm_slot_t));
  403. r = write_header(fd, lm);
  404. error:
  405. close(fd);
  406. return r < 0 ? r : 0;
  407. }