lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 24 Mar 2017 18:34:19 +0100
From:   Jan Kiszka <jan.kiszka@...mens.com>
To:     Matt Fleming <matt@...eblueprint.co.uk>,
        Ard Biesheuvel <ard.biesheuvel@...aro.org>
Cc:     linux-efi@...r.kernel.org,
        Linux Kernel Mailing List <linux-kernel@...r.kernel.org>,
        Andy Shevchenko <andy.shevchenko@...il.com>,
        "Bryan O'Donoghue" <pure.logic@...us-software.ie>,
        Hock Leong Kweh <hock.leong.kweh@...el.com>,
        Borislav Petkov <bp@...en8.de>,
        Sascha Weisenberger <sascha.weisenberger@...mens.com>
Subject: [PATCH v2 6/7] efi/capsule: Factor out overloadable efi_capsule_identify_image

Another step to prepare Quark's CSH capsule format: Factor out the weak
efi_capsule_identify_image function which is supposed to tell standard-
conforming images apart from the special ones. The conforming version of
it is __efi_capsule_identify_image, and that is called unless
efi_capsule_identify_image is overloaded by an architecture-specific
quirk implementation.

efi_capsule_setup_info calls the image identification callback and is
prepared for the case, efi_hdr_displacement becomes > 0 and the total
image size > than what the standard EFI header reports.

Signed-off-by: Jan Kiszka <jan.kiszka@...mens.com>
---
 drivers/firmware/efi/capsule-loader.c | 89 ++++++++++++++++++++++-------------
 include/linux/efi.h                   | 18 +++++++
 2 files changed, 73 insertions(+), 34 deletions(-)

diff --git a/drivers/firmware/efi/capsule-loader.c b/drivers/firmware/efi/capsule-loader.c
index 59e2694..50cacd4 100644
--- a/drivers/firmware/efi/capsule-loader.c
+++ b/drivers/firmware/efi/capsule-loader.c
@@ -20,26 +20,15 @@
 
 #define NO_FURTHER_WRITE_ACTION -1
 
-struct capsule_info {
-	bool		header_obtained;
-	int		reset_type;
-	long		index;
-	size_t		count;
-	size_t		total_size;
-	unsigned int	efi_hdr_displacement;
-	struct page	**pages;
-	size_t		page_bytes_remain;
-};
-
 /**
  * efi_free_all_buff_pages - free all previous allocated buffer pages
- * @cap_info: pointer to current instance of capsule_info structure
+ * @cap_info: pointer to current instance of efi_capsule_info structure
  *
  *	In addition to freeing buffer pages, it flags NO_FURTHER_WRITE_ACTION
  *	to cease processing data in subsequent write(2) calls until close(2)
  *	is called.
  **/
-static void efi_free_all_buff_pages(struct capsule_info *cap_info)
+static void efi_free_all_buff_pages(struct efi_capsule_info *cap_info)
 {
 	while (cap_info->index > 0)
 		__free_page(cap_info->pages[--cap_info->index]);
@@ -47,28 +36,63 @@ static void efi_free_all_buff_pages(struct capsule_info *cap_info)
 	cap_info->index = NO_FURTHER_WRITE_ACTION;
 }
 
+int __efi_capsule_identify_image(struct efi_capsule_info *cap_info,
+				 void *header, size_t hdr_bytes)
+{
+	efi_capsule_header_t *cap_hdr = header;
+
+	/* Only process data block that is larger than efi header size */
+	if (hdr_bytes < sizeof(efi_capsule_header_t))
+		return 0;
+
+	cap_info->total_size = cap_hdr->imagesize;
+	cap_info->efi_hdr_displacement = 0;
+
+	return 1;
+}
+
+/**
+ * efi_capsule_identify_image - identify the capsule image layout and initialize
+ * 				efi_capsule_info fields accordingly
+ * @cap_info: pointer to current instance of efi_capsule_info structure
+ * @header: mapped image header
+ * @hdr_bytes: the total received number of bytes for header
+ *
+ * Return 1 on success, 0 if insufficient data was read so far, otherwise
+ * negative error code.
+ */
+int __weak efi_capsule_identify_image(struct efi_capsule_info *cap_info,
+				      void *header, size_t hdr_bytes)
+{
+	return __efi_capsule_identify_image(cap_info, header, hdr_bytes);
+}
+
 /**
  * efi_capsule_setup_info - obtain the efi capsule header in the binary and
- *			    setup capsule_info structure
- * @cap_info: pointer to current instance of capsule_info structure
+ *			    setup efi_capsule_info structure
+ * @cap_info: pointer to current instance of efi_capsule_info structure
  * @kbuff: a mapped first page buffer pointer
  * @hdr_bytes: the total received number of bytes for efi header
  **/
-static int efi_capsule_setup_info(struct capsule_info *cap_info,
+static int efi_capsule_setup_info(struct efi_capsule_info *cap_info,
 				  void *kbuff, size_t hdr_bytes)
 {
 	efi_capsule_header_t *cap_hdr;
 	size_t pages_needed;
-	int ret;
 	void *temp_page;
-
-	/* Only process data block that is larger than efi header size */
-	if (hdr_bytes < sizeof(efi_capsule_header_t))
-		return 0;
+	void *header;
+	int ret;
 
 	/* Reset back to the correct offset of header */
-	cap_hdr = kbuff - cap_info->count;
-	pages_needed = ALIGN(cap_hdr->imagesize, PAGE_SIZE) >> PAGE_SHIFT;
+	header = kbuff - cap_info->count;
+
+	ret = efi_capsule_identify_image(cap_info, header, hdr_bytes);
+	if (ret <= 0)
+		return ret;
+
+	cap_hdr = header + cap_info->efi_hdr_displacement;
+
+	pages_needed = ALIGN(cap_info->total_size, PAGE_SIZE) >> PAGE_SHIFT;
 
 	if (pages_needed == 0) {
 		pr_err("invalid capsule size");
@@ -77,16 +101,13 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info,
 
 	/* Check if the capsule binary supported */
 	ret = efi_capsule_supported(cap_hdr->guid, cap_hdr->flags,
-				    cap_hdr->imagesize,
+				    cap_info->total_size,
 				    &cap_info->reset_type);
 	if (ret) {
 		pr_err("capsule not supported\n");
 		return ret;
 	}
 
-	cap_info->efi_hdr_displacement = 0;
-
-	cap_info->total_size = cap_hdr->imagesize;
 	temp_page = krealloc(cap_info->pages,
 			     pages_needed * sizeof(void *),
 			     GFP_KERNEL | __GFP_ZERO);
@@ -102,9 +123,9 @@ static int efi_capsule_setup_info(struct capsule_info *cap_info,
 /**
  * efi_capsule_submit_update - invoke the efi_capsule_update API once binary
  *			       upload done
- * @cap_info: pointer to current instance of capsule_info structure
+ * @cap_info: pointer to current instance of efi_capsule_info structure
  **/
-static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info)
+static ssize_t efi_capsule_submit_update(struct efi_capsule_info *cap_info)
 {
 	efi_capsule_header_t *cap_hdr;
 	void *mapped_pages;
@@ -157,7 +178,7 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
 				 size_t count, loff_t *offp)
 {
 	int ret = 0;
-	struct capsule_info *cap_info = file->private_data;
+	struct efi_capsule_info *cap_info = file->private_data;
 	struct page *page;
 	void *kbuff = NULL;
 	size_t write_byte;
@@ -244,7 +265,7 @@ static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
 static int efi_capsule_flush(struct file *file, fl_owner_t id)
 {
 	int ret = 0;
-	struct capsule_info *cap_info = file->private_data;
+	struct efi_capsule_info *cap_info = file->private_data;
 
 	if (cap_info->index > 0) {
 		pr_err("capsule upload not complete\n");
@@ -265,7 +286,7 @@ static int efi_capsule_flush(struct file *file, fl_owner_t id)
  **/
 static int efi_capsule_release(struct inode *inode, struct file *file)
 {
-	struct capsule_info *cap_info = file->private_data;
+	struct efi_capsule_info *cap_info = file->private_data;
 
 	kfree(cap_info->pages);
 	kfree(file->private_data);
@@ -278,14 +299,14 @@ static int efi_capsule_release(struct inode *inode, struct file *file)
  * @inode: not used
  * @file: file pointer
  *
- *	Will allocate each capsule_info memory for each file open call.
+ *	Will allocate each efi_capsule_info memory for each file open call.
  *	This provided the capability to support multiple file open feature
  *	where user is not needed to wait for others to finish in order to
  *	upload their capsule binary.
  **/
 static int efi_capsule_open(struct inode *inode, struct file *file)
 {
-	struct capsule_info *cap_info;
+	struct efi_capsule_info *cap_info;
 
 	cap_info = kzalloc(sizeof(*cap_info), GFP_KERNEL);
 	if (!cap_info)
diff --git a/include/linux/efi.h b/include/linux/efi.h
index d83095c6..5561817 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1397,6 +1397,18 @@ int efivars_sysfs_init(void);
 #define EFIVARS_DATA_SIZE_MAX 1024
 
 #endif /* CONFIG_EFI_VARS */
+
+struct efi_capsule_info {
+	bool		header_obtained;
+	int		reset_type;
+	long		index;
+	size_t		count;
+	size_t		total_size;
+	unsigned int	efi_hdr_displacement;
+	struct page	**pages;
+	size_t		page_bytes_remain;
+};
+
 extern bool efi_capsule_pending(int *reset_type);
 
 extern int efi_capsule_supported(efi_guid_t guid, u32 flags,
@@ -1406,6 +1418,12 @@ extern int efi_capsule_update(efi_capsule_header_t *capsule,
 			      unsigned int efi_hdr_displacement,
 			      struct page **pages);
 
+int __efi_capsule_identify_image(struct efi_capsule_info *cap_info,
+				 void *header, size_t hdr_bytes);
+
+int efi_capsule_identify_image(struct efi_capsule_info *cap_info, void *header,
+			       size_t hdr_bytes);
+
 #ifdef CONFIG_EFI_RUNTIME_MAP
 int efi_runtime_map_init(struct kobject *);
 int efi_get_runtime_map_size(void);
-- 
2.10.2

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ