efi_parser.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /* EFI signature/key/certificate list parser
  2. *
  3. * Copyright (C) 2012, 2016 Red Hat, Inc. All Rights Reserved.
  4. * Written by David Howells (dhowells@redhat.com)
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public Licence
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the Licence, or (at your option) any later version.
  10. */
  11. #define pr_fmt(fmt) "EFI: "fmt
  12. #include <linux/module.h>
  13. #include <linux/printk.h>
  14. #include <linux/err.h>
  15. #include <linux/efi.h>
  16. /**
  17. * parse_efi_signature_list - Parse an EFI signature list for certificates
  18. * @source: The source of the key
  19. * @data: The data blob to parse
  20. * @size: The size of the data blob
  21. * @get_handler_for_guid: Get the handler func for the sig type (or NULL)
  22. *
  23. * Parse an EFI signature list looking for elements of interest. A list is
  24. * made up of a series of sublists, where all the elements in a sublist are of
  25. * the same type, but sublists can be of different types.
  26. *
  27. * For each sublist encountered, the @get_handler_for_guid function is called
  28. * with the type specifier GUID and returns either a pointer to a function to
  29. * handle elements of that type or NULL if the type is not of interest.
  30. *
  31. * If the sublist is of interest, each element is passed to the handler
  32. * function in turn.
  33. *
  34. * Error EBADMSG is returned if the list doesn't parse correctly and 0 is
  35. * returned if the list was parsed correctly. No error can be returned from
  36. * the @get_handler_for_guid function or the element handler function it
  37. * returns.
  38. */
  39. int __init parse_efi_signature_list(
  40. const char *source,
  41. const void *data, size_t size,
  42. efi_element_handler_t (*get_handler_for_guid)(const efi_guid_t *))
  43. {
  44. efi_element_handler_t handler;
  45. unsigned offs = 0;
  46. pr_devel("-->%s(,%zu)\n", __func__, size);
  47. while (size > 0) {
  48. const efi_signature_data_t *elem;
  49. efi_signature_list_t list;
  50. size_t lsize, esize, hsize, elsize;
  51. if (size < sizeof(list))
  52. return -EBADMSG;
  53. memcpy(&list, data, sizeof(list));
  54. pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n",
  55. offs,
  56. list.signature_type.b, list.signature_list_size,
  57. list.signature_header_size, list.signature_size);
  58. lsize = list.signature_list_size;
  59. hsize = list.signature_header_size;
  60. esize = list.signature_size;
  61. elsize = lsize - sizeof(list) - hsize;
  62. if (lsize > size) {
  63. pr_devel("<--%s() = -EBADMSG [overrun @%x]\n",
  64. __func__, offs);
  65. return -EBADMSG;
  66. }
  67. if (lsize < sizeof(list) ||
  68. lsize - sizeof(list) < hsize ||
  69. esize < sizeof(*elem) ||
  70. elsize < esize ||
  71. elsize % esize != 0) {
  72. pr_devel("- bad size combo @%x\n", offs);
  73. return -EBADMSG;
  74. }
  75. handler = get_handler_for_guid(&list.signature_type);
  76. if (!handler) {
  77. data += lsize;
  78. size -= lsize;
  79. offs += lsize;
  80. continue;
  81. }
  82. data += sizeof(list) + hsize;
  83. size -= sizeof(list) + hsize;
  84. offs += sizeof(list) + hsize;
  85. for (; elsize > 0; elsize -= esize) {
  86. elem = data;
  87. pr_devel("ELEM[%04x]\n", offs);
  88. handler(source,
  89. &elem->signature_data,
  90. esize - sizeof(*elem));
  91. data += esize;
  92. size -= esize;
  93. offs += esize;
  94. }
  95. }
  96. return 0;
  97. }