aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@redhat.com>2018-02-28 10:06:10 -0500
committerMichael S. Tsirkin <mst@redhat.com>2018-03-19 21:17:39 -0400
commitb1cc4097d15c29725060f86ecec20a1e635a541f (patch)
tree40378599986447c14047362ddbc37b71b4a4ed64
parent59ecab182faf84e76f4a07fee904d41e41f4780c (diff)
fw_cfg: handle fw_cfg_read_blob() error
fw_cfg_read_blob() may fail, but does not return error. This may lead to surprising behaviours, like populating zero file entries (in register_file() or during read). Return an error if ACPI locking failed. Also, the following DMA read/write extension will add more error paths that should be handled appropriately. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r--drivers/firmware/qemu_fw_cfg.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c
index 0cc71d028ae3..45bfc389b226 100644
--- a/drivers/firmware/qemu_fw_cfg.c
+++ b/drivers/firmware/qemu_fw_cfg.c
@@ -77,8 +77,8 @@ static void fw_cfg_sel_endianness(u16 key)
77} 77}
78 78
79/* read chunk of given fw_cfg blob (caller responsible for sanity-check) */ 79/* read chunk of given fw_cfg blob (caller responsible for sanity-check) */
80static void fw_cfg_read_blob(u16 key, 80static ssize_t fw_cfg_read_blob(u16 key,
81 void *buf, loff_t pos, size_t count) 81 void *buf, loff_t pos, size_t count)
82{ 82{
83 u32 glk = -1U; 83 u32 glk = -1U;
84 acpi_status status; 84 acpi_status status;
@@ -91,7 +91,7 @@ static void fw_cfg_read_blob(u16 key,
91 /* Should never get here */ 91 /* Should never get here */
92 WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n"); 92 WARN(1, "fw_cfg_read_blob: Failed to lock ACPI!\n");
93 memset(buf, 0, count); 93 memset(buf, 0, count);
94 return; 94 return -EINVAL;
95 } 95 }
96 96
97 mutex_lock(&fw_cfg_dev_lock); 97 mutex_lock(&fw_cfg_dev_lock);
@@ -102,6 +102,7 @@ static void fw_cfg_read_blob(u16 key,
102 mutex_unlock(&fw_cfg_dev_lock); 102 mutex_unlock(&fw_cfg_dev_lock);
103 103
104 acpi_release_global_lock(glk); 104 acpi_release_global_lock(glk);
105 return count;
105} 106}
106 107
107/* clean up fw_cfg device i/o */ 108/* clean up fw_cfg device i/o */
@@ -183,8 +184,9 @@ static int fw_cfg_do_platform_probe(struct platform_device *pdev)
183 } 184 }
184 185
185 /* verify fw_cfg device signature */ 186 /* verify fw_cfg device signature */
186 fw_cfg_read_blob(FW_CFG_SIGNATURE, sig, 0, FW_CFG_SIG_SIZE); 187 if (fw_cfg_read_blob(FW_CFG_SIGNATURE, sig,
187 if (memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) { 188 0, FW_CFG_SIG_SIZE) < 0 ||
189 memcmp(sig, "QEMU", FW_CFG_SIG_SIZE) != 0) {
188 fw_cfg_io_cleanup(); 190 fw_cfg_io_cleanup();
189 return -ENODEV; 191 return -ENODEV;
190 } 192 }
@@ -344,8 +346,7 @@ static ssize_t fw_cfg_sysfs_read_raw(struct file *filp, struct kobject *kobj,
344 if (count > entry->size - pos) 346 if (count > entry->size - pos)
345 count = entry->size - pos; 347 count = entry->size - pos;
346 348
347 fw_cfg_read_blob(entry->select, buf, pos, count); 349 return fw_cfg_read_blob(entry->select, buf, pos, count);
348 return count;
349} 350}
350 351
351static struct bin_attribute fw_cfg_sysfs_attr_raw = { 352static struct bin_attribute fw_cfg_sysfs_attr_raw = {
@@ -501,7 +502,11 @@ static int fw_cfg_register_dir_entries(void)
501 struct fw_cfg_file *dir; 502 struct fw_cfg_file *dir;
502 size_t dir_size; 503 size_t dir_size;
503 504
504 fw_cfg_read_blob(FW_CFG_FILE_DIR, &files_count, 0, sizeof(files_count)); 505 ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, &files_count,
506 0, sizeof(files_count));
507 if (ret < 0)
508 return ret;
509
505 count = be32_to_cpu(files_count); 510 count = be32_to_cpu(files_count);
506 dir_size = count * sizeof(struct fw_cfg_file); 511 dir_size = count * sizeof(struct fw_cfg_file);
507 512
@@ -509,7 +514,10 @@ static int fw_cfg_register_dir_entries(void)
509 if (!dir) 514 if (!dir)
510 return -ENOMEM; 515 return -ENOMEM;
511 516
512 fw_cfg_read_blob(FW_CFG_FILE_DIR, dir, sizeof(files_count), dir_size); 517 ret = fw_cfg_read_blob(FW_CFG_FILE_DIR, dir,
518 sizeof(files_count), dir_size);
519 if (ret < 0)
520 goto end;
513 521
514 for (i = 0; i < count; i++) { 522 for (i = 0; i < count; i++) {
515 ret = fw_cfg_register_file(&dir[i]); 523 ret = fw_cfg_register_file(&dir[i]);
@@ -517,6 +525,7 @@ static int fw_cfg_register_dir_entries(void)
517 break; 525 break;
518 } 526 }
519 527
528end:
520 kfree(dir); 529 kfree(dir);
521 return ret; 530 return ret;
522} 531}
@@ -557,7 +566,10 @@ static int fw_cfg_sysfs_probe(struct platform_device *pdev)
557 goto err_probe; 566 goto err_probe;
558 567
559 /* get revision number, add matching top-level attribute */ 568 /* get revision number, add matching top-level attribute */
560 fw_cfg_read_blob(FW_CFG_ID, &rev, 0, sizeof(rev)); 569 err = fw_cfg_read_blob(FW_CFG_ID, &rev, 0, sizeof(rev));
570 if (err < 0)
571 goto err_probe;
572
561 fw_cfg_rev = le32_to_cpu(rev); 573 fw_cfg_rev = le32_to_cpu(rev);
562 err = sysfs_create_file(fw_cfg_top_ko, &fw_cfg_rev_attr.attr); 574 err = sysfs_create_file(fw_cfg_top_ko, &fw_cfg_rev_attr.attr);
563 if (err) 575 if (err)