diff --git a/src/creator.c b/src/creator.c index 24e49b5d..14d446a9 100644 --- a/src/creator.c +++ b/src/creator.c @@ -53,6 +53,7 @@ find_file(const char * const filepath, char **devicep, char **relpathp) linklen = strlen(filepath); if (linklen > PATH_MAX) { errno = ENAMETOOLONG; + efi_error("filepath length exceeds PATH_MAX"); return -1; } strcpy(linkbuf, filepath); @@ -67,8 +68,10 @@ find_file(const char * const filepath, char **devicep, char **relpathp) ssize_t l; l = readlink(linkbuf, tmp, PATH_MAX); - if (l < 0) + if (l < 0) { + efi_error("readlink failed"); return -1; + } tmp[l] = '\0'; linklen = l; strcpy(linkbuf, tmp); @@ -78,8 +81,10 @@ find_file(const char * const filepath, char **devicep, char **relpathp) } while (1); mounts = fopen("/proc/self/mounts", "r"); - if (mounts == NULL) - return rc; + if (mounts == NULL) { + efi_error("couldn not open /proc/self/mounts"); + return -1; + } struct mntent *me; while (1) { @@ -88,8 +93,10 @@ find_file(const char * const filepath, char **devicep, char **relpathp) errno = 0; me = getmntent(mounts); if (!me) { - if (feof(mounts)) + if (feof(mounts)) { errno = ENOENT; + efi_error("could not find mountpoint"); + } goto err; } @@ -100,6 +107,7 @@ find_file(const char * const filepath, char **devicep, char **relpathp) if (rc < 0) { if (errno == ENOENT) continue; + efi_error("could not stat mountpoint"); goto err; } @@ -113,12 +121,17 @@ find_file(const char * const filepath, char **devicep, char **relpathp) if (strncmp(linkbuf, me->mnt_dir, mntlen)) continue; *devicep = strdup(me->mnt_fsname); - if (!*devicep) + if (!*devicep) { + errno = ENOMEM; + efi_error("strdup failed"); goto err; + } *relpathp = strdup(linkbuf + mntlen); if (!*relpathp) { free(*devicep); *devicep = NULL; + errno = ENOMEM; + efi_error("strdup failed"); goto err; } ret = 0; @@ -138,10 +151,16 @@ open_disk(struct disk_info *info, int flags) int rc; rc = asprintfa(&diskpath, "/dev/%s", info->disk_name); - if (rc < 0) + if (rc < 0) { + efi_error("could not allocate buffer"); return -1; + } + + rc = open(diskpath, flags); + if (rc < 0) + efi_error("could not open disk"); - return open(diskpath, flags); + return rc; } static char * @@ -167,12 +186,16 @@ efi_va_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, int saved_errno; fd = open(devpath, O_RDONLY); - if (fd < 0) + if (fd < 0) { + efi_error("could not open device for ESP"); goto err; + } rc = eb_disk_info_from_fd(fd, &info); - if (rc < 0 && errno != ENOSYS) + if (rc < 0 && errno != ENOSYS) { + efi_error("could not get ESP disk info"); goto err; + } if (partition > 0) info.part = partition; @@ -190,8 +213,10 @@ efi_va_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, && (!(options & EFIBOOT_ABBREV_FILE) && !(options & EFIBOOT_ABBREV_HD))) { sz = efidp_make_edd10(buf, size, info.edd10_devicenum); - if (sz < 0) + if (sz < 0) { + efi_error("could not make EDD 1.0 device path"); return -1; + } off = sz; } else if (!(options & EFIBOOT_ABBREV_FILE) && !(options & EFIBOOT_ABBREV_HD)) { @@ -201,8 +226,10 @@ efi_va_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, * from there. */ sz = make_blockdev_path(buf, size, &info); - if (sz < 0) + if (sz < 0) { + efi_error("could not create device path"); return -1; + } off += sz; } @@ -212,33 +239,44 @@ efi_va_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, int rc; rc = set_disk_and_part_name(&info); - if (rc < 0) + if (rc < 0) { + efi_error("could not set disk and partition name"); goto err; + } disk_fd = open_disk(&info, - (options& EFIBOOT_OPTIONS_WRITE_SIGNATURE)?O_RDWR:O_RDONLY); - if (disk_fd < 0) + (options & EFIBOOT_OPTIONS_WRITE_SIGNATURE) + ? O_RDWR : O_RDONLY); + if (disk_fd < 0) { + efi_error("could not open disk"); goto err; + } sz = make_hd_dn(buf, size, off, disk_fd, info.part, options); saved_errno = errno; close(disk_fd); errno = saved_errno; - if (sz < 0) + if (sz < 0) { + efi_error("could not make HD() DP node"); goto err; + } off += sz; } char *filepath = strdupa(relpath); tilt_slashes(filepath); sz = efidp_make_file(buf+off, size?size-off:0, filepath); - if (sz < 0) + if (sz < 0) { + efi_error("could not make File() DP node"); goto err; + } off += sz; sz = efidp_make_end_entire(buf+off, size?size-off:0); - if (sz < 0) + if (sz < 0) { + efi_error("could not make EndEntire DP node"); goto err; + } off += sz; ret = off; err: @@ -278,6 +316,8 @@ efi_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, saved_errno = errno; va_end(ap); errno = saved_errno; + if (ret < 0) + efi_error("could not generate File DP from ESP"); return ret; } @@ -297,16 +337,22 @@ efi_generate_file_device_path(uint8_t *buf, ssize_t size, int saved_errno; rc = find_file(filepath, &child_devpath, &relpath); - if (rc < 0) + if (rc < 0) { + efi_error("could not canonicalize fs path"); return -1; + } rc = find_parent_devpath(child_devpath, &parent_devpath); - if (rc < 0) + if (rc < 0) { + efi_error("could not find parent device for file"); return -1; + } rc = get_partition_number(child_devpath); - if (rc < 0) + if (rc < 0) { + efi_error("could not get partition number for device"); goto err; + } va_start(ap, options); @@ -316,6 +362,8 @@ efi_generate_file_device_path(uint8_t *buf, ssize_t size, saved_errno = errno; va_end(ap); errno = saved_errno; + if (ret < 0) + efi_error("could not generate File DP from ESP"); err: saved_errno = errno; if (child_devpath) @@ -340,6 +388,8 @@ make_ipv4_path(uint8_t *buf, ssize_t size, uint16_t protocol __attribute__((unused)), uint8_t addr_origin __attribute__((unused))) { + ssize_t ret; + #if 0 if (local_addr == NULL || remote_addr == NULL || gateway_addr == NULL || netmask == NULL) { @@ -347,7 +397,10 @@ make_ipv4_path(uint8_t *buf, ssize_t size, return -1; } #endif - return efidp_make_ipv4(buf, size, 0, 0, 0, 0, 0, 0, 0, 0); + ret = efidp_make_ipv4(buf, size, 0, 0, 0, 0, 0, 0, 0, 0); + if (ret < 0) + efi_error("could not make ipv4 DP node"); + return ret; } ssize_t @@ -368,20 +421,26 @@ efi_generate_ipv4_device_path(uint8_t *buf, ssize_t size, ssize_t sz; sz = make_mac_path(buf, size, ifname); - if (sz < 0) + if (sz < 0) { + efi_error("could not make MAC DP node"); return -1; + } off += sz; sz = make_ipv4_path(buf+off, size?size-off:0, local_addr, remote_addr, gateway_addr, netmask, local_port, remote_port, protocol, addr_origin); - if (sz < 0) + if (sz < 0) { + efi_error("could not make IPV4 DP node"); return -1; + } off += sz; sz = efidp_make_end_entire(buf+off, size?size-off:0); - if (sz < 0) + if (sz < 0) { + efi_error("could not make EndEntire DP node"); return -1; + } off += sz; return off; diff --git a/src/disk.c b/src/disk.c index 261c6d33..91d636de 100644 --- a/src/disk.c +++ b/src/disk.c @@ -53,9 +53,15 @@ static int report_errors; static inline int is_mbr_valid(legacy_mbr *mbr) { + int ret; if (!mbr) return 0; - return (mbr->signature == MSDOS_MBR_SIGNATURE); + ret = (mbr->signature == MSDOS_MBR_SIGNATURE); + if (!ret) { + errno = ENOTTY; + efi_error("mbr signature is not MSDOS_MBR_SIGNATURE"); + } + return ret; } /************************************************************ @@ -78,6 +84,8 @@ msdos_disk_get_extended_partition_info (int fd __attribute__((unused)), { /* Until I can handle these... */ //fprintf(stderr, "Extended partition info not supported.\n"); + errno = ENOSYS; + efi_error("extended partition info is not supported"); return -1; } @@ -104,10 +112,16 @@ msdos_disk_get_partition_info (int fd, int write_signature, struct stat stat; struct timeval tv; - if (!mbr) + if (!mbr) { + errno = EINVAL; + efi_error("mbr argument must not be NULL"); return -1; - if (!is_mbr_valid(mbr)) + } + if (!is_mbr_valid(mbr)) { + errno = ENOENT; + efi_error("mbr is not valid"); return -1; + } *mbr_type = 0x01; *signature_type = 0x01; @@ -127,7 +141,8 @@ msdos_disk_get_partition_info (int fd, int write_signature, rc = fstat(fd, &stat); if (rc < 0) { if (report_errors) - perror("stat disk"); + perror("fstat disk"); + efi_error("could not fstat disk"); return rc; } @@ -135,6 +150,7 @@ msdos_disk_get_partition_info (int fd, int write_signature, if (rc < 0) { if (report_errors) perror("gettimeofday"); + efi_error("gettimeofday failed"); return rc; } @@ -146,13 +162,21 @@ msdos_disk_get_partition_info (int fd, int write_signature, /* Write it to the disk */ lseek(fd, 0, SEEK_SET); rc = write(fd, mbr, sizeof(*mbr)); + if (rc < 0) { + efi_error("could not write MBR signature"); + return rc; + } } *(uint32_t *)signature = mbr->unique_mbr_signature; if (num > 4) { /* Extended partition */ - return msdos_disk_get_extended_partition_info(fd, mbr, num, - start, size); + rc = msdos_disk_get_extended_partition_info(fd, mbr, num, + start, size); + if (rc < 0) { + efi_error("could not get extended partition info"); + return rc; + } } else if (num == 0) { /* Whole disk */ *start = 0; @@ -182,13 +206,16 @@ get_partition_info(int fd, uint32_t options, int sector_size = get_sector_size(fd); mbr_size = lcm(sizeof(*mbr), sector_size); - if ((rc = posix_memalign(&mbr_sector, sector_size, mbr_size)) != 0) + if ((rc = posix_memalign(&mbr_sector, sector_size, mbr_size)) != 0) { + efi_error("posix_memalign failed"); goto error; + } memset(mbr_sector, '\0', mbr_size); offset = lseek(fd, 0, SEEK_SET); this_bytes_read = read(fd, mbr_sector, mbr_size); if (this_bytes_read < (ssize_t)sizeof(*mbr)) { + efi_error("short read trying to read mbr data"); rc=1; goto error_free_mbr; } @@ -208,9 +235,11 @@ get_partition_info(int fd, uint32_t options, mbr_type, signature_type); if (mbr_invalid) { + efi_error("neither MBR nor GPT is valid"); rc=1; goto error_free_mbr; } + efi_error_clear(); } error_free_mbr: free(mbr_sector); @@ -233,12 +262,17 @@ _make_hd_dn(uint8_t *buf, ssize_t size, int fd, uint32_t partition, errno = 0; rc = get_partition_info(fd, options, - partition>0?partition:1, &part_start, + partition > 0 ? partition : 1, &part_start, &part_size, signature, &format, &signature_type); - if (rc < 0) + if (rc < 0) { + efi_error("could not get partition info"); return rc; + } - return efidp_make_hd(buf, size, partition>0?partition:1, part_start, - part_size, signature, format, signature_type); + rc = efidp_make_hd(buf, size, partition>0?partition:1, part_start, + part_size, signature, format, signature_type); + if (rc < 0) + efi_error("could not make HD DP node"); + return rc; } diff --git a/src/dp-acpi.c b/src/dp-acpi.c index 37c0b717..f23fbeb6 100644 --- a/src/dp-acpi.c +++ b/src/dp-acpi.c @@ -180,6 +180,9 @@ efidp_make_acpi_hid(uint8_t *buf, ssize_t size, uint32_t hid, uint32_t uid) acpi_hid->hid = hid; } + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } @@ -210,5 +213,8 @@ efidp_make_acpi_hid_ex(uint8_t *buf, ssize_t size, strcpy(next, cidstr); } + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } diff --git a/src/dp-hw.c b/src/dp-hw.c index 17784679..43a7f54a 100644 --- a/src/dp-hw.c +++ b/src/dp-hw.c @@ -94,6 +94,10 @@ efidp_make_pci(uint8_t *buf, ssize_t size, uint8_t device, uint8_t function) pci->device = device; pci->function = function; } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } @@ -111,5 +115,9 @@ efidp_make_edd10(uint8_t *buf, ssize_t size, uint32_t hardware_device) memcpy(&edd_dp->vendor_guid, &edd10_guid, sizeof (edd10_guid)); edd_dp->hardware_device = hardware_device; } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } diff --git a/src/dp-media.c b/src/dp-media.c index 287db1bf..cde2ad88 100644 --- a/src/dp-media.c +++ b/src/dp-media.c @@ -163,6 +163,10 @@ efidp_make_file(uint8_t *buf, ssize_t size, char *filepath) memset(buf+4, 0, req-4); utf8_to_ucs2(file->name, req-4, 1, lf); } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } @@ -187,5 +191,9 @@ efidp_make_hd(uint8_t *buf, ssize_t size, uint32_t num, uint64_t part_start, hd->format = format; hd->signature_type = signature_type; } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } diff --git a/src/dp-message.c b/src/dp-message.c index d2433a09..63ee291d 100644 --- a/src/dp-message.c +++ b/src/dp-message.c @@ -480,8 +480,10 @@ _format_message_dn(char *buf, size_t size, const_efidp dp) case EFIDP_MSG_ISCSI: { ssize_t sz = efidp_node_size(dp) - offsetof(efidp_iscsi, target_name); - if (sz < 0) + if (sz < 0) { + efi_error("bad DP node size"); return -1; + } if (sz > EFIDP_ISCSI_MAX_TARGET_NAME_LEN) sz = EFIDP_ISCSI_MAX_TARGET_NAME_LEN; @@ -521,8 +523,10 @@ _format_message_dn(char *buf, size_t size, const_efidp dp) break; case EFIDP_MSG_URI: { ssize_t sz = efidp_node_size(dp) - offsetof(efidp_uri, uri); - if (sz < 0) + if (sz < 0) { + efi_error("bad DP node size"); return -1; + } char uri[sz + 1]; memcpy(uri, dp->uri.uri, sz); @@ -562,6 +566,10 @@ efidp_make_mac_addr(uint8_t *buf, ssize_t size, uint8_t if_type, memcpy(mac->mac_addr, mac_addr, mac_addr_size > 32 ? 32 : mac_addr_size); } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } @@ -588,6 +596,10 @@ efidp_make_ipv4(uint8_t *buf, ssize_t size, uint32_t local, uint32_t remote, *((char *)ipv4->gateway) = htonl(gateway); *((char *)ipv4->netmask) = htonl(netmask); } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } @@ -603,6 +615,10 @@ efidp_make_scsi(uint8_t *buf, ssize_t size, uint16_t target, uint16_t lun) scsi->target = target; scsi->lun = lun; } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } @@ -626,6 +642,10 @@ efidp_make_nvme(uint8_t *buf, ssize_t size, uint32_t namespace_id, memset(nvme->ieee_eui_64, '\0', sizeof (nvme->ieee_eui_64)); } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } @@ -645,6 +665,10 @@ efidp_make_sata(uint8_t *buf, ssize_t size, uint16_t hba_port, sata->port_multiplier_port = port_multiplier_port; sata->lun = lun; } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } @@ -664,6 +688,10 @@ efidp_make_atapi(uint8_t *buf, ssize_t size, uint16_t primary, atapi->slave = slave; atapi->lun = lun; } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } @@ -687,5 +715,9 @@ efidp_make_sas(uint8_t *buf, ssize_t size, uint64_t sas_address) sas->drive_bay_id = 0; sas->rtp = 0; } + + if (sz < 0) + efi_error("efidp_make_generic failed"); + return sz; } diff --git a/src/dp.c b/src/dp.c index d280fe20..e9a257e1 100644 --- a/src/dp.c +++ b/src/dp.c @@ -37,6 +37,7 @@ efidp_data_address(const_efidp dp) { if (dp->length <= 4) { errno = ENOSPC; + efi_error("DP was smaller than DP header"); return NULL; } return (void *)((uint8_t *)dp + sizeof (dp)); @@ -48,11 +49,14 @@ efidp_set_node_data(const_efidp dn, void *buf, size_t bufsize) { if (dn->length < 4 || bufsize > (size_t)dn->length - 4) { errno = ENOSPC; + efi_error("DP was smaller than DP header"); return -1; } void *data = efidp_data_address(dn); - if (!data) + if (!data) { + efi_error("efidp_data_address failed"); return -1; + } memcpy(data, buf, bufsize); return 0; } @@ -66,17 +70,22 @@ efidp_duplicate_extra(const_efidp dp, efidp *out, size_t extra) efidp new; sz = efidp_size(dp); - if (sz < 0) + if (sz < 0) { + efi_error("efidp_size(dp) returned error"); return sz; + } if (add(sz, extra, &plus)) { errno = EOVERFLOW; + efi_error("arithmetic overflow computing allocation size"); return -1; } new = calloc(1, plus); - if (!new) + if (!new) { + efi_error("allocation failed"); return -1; + } memcpy(new, dp, sz); *out = new; @@ -87,7 +96,11 @@ int __attribute__((__visibility__ ("default"))) efidp_duplicate_path(const_efidp dp, efidp *out) { - return efidp_duplicate_extra(dp, out, 0); + int rc; + rc = efidp_duplicate_extra(dp, out, 0); + if (rc < 0) + efi_error("efi_duplicate_extra(dp, out, 0) returned error"); + return rc; } int @@ -98,47 +111,66 @@ efidp_append_path(const_efidp dp0, const_efidp dp1, efidp *out) const_efidp le; int rc; - if (!dp0 && !dp1) - return efidp_duplicate_path((const_efidp)&end_entire, out); + if (!dp0 && !dp1) { + rc = efidp_duplicate_path((const_efidp)&end_entire, out); + if (rc < 0) + efi_error("efidp_duplicate_path failed"); + return rc; + } - if (dp0 && !dp1) - return efidp_duplicate_path(dp0, out); + if (dp0 && !dp1) { + rc = efidp_duplicate_path(dp0, out); + if (rc < 0) + efi_error("efidp_duplicate_path failed"); + return rc; + } - if (!dp0 && dp1) - return efidp_duplicate_path(dp1, out); + if (!dp0 && dp1) { + rc = efidp_duplicate_path(dp1, out); + if (rc < 0) + efi_error("efidp_duplicate_path failed"); + return rc; + } lsz = efidp_size(dp0); - if (lsz < 0) + if (lsz < 0) { + efi_error("efidp_size(dp0) returned error"); return -1; + } rsz = efidp_size(dp1); - if (rsz < 0) + if (lsz < 0) { + efi_error("efidp_size(dp1) returned error"); return -1; + } le = dp0; while (1) { if (efidp_type(le) == EFIDP_END_TYPE && efidp_subtype(le) == EFIDP_END_ENTIRE) { ssize_t lesz = efidp_size(le); - if (lesz < 0) - return -1; lsz -= lesz; break; } rc = efidp_get_next_end(le, &le); - if (rc < 0) + if (rc < 0) { + efi_error("efidp_get_next_end() returned error"); return -1; + } } efidp new; if (add(lsz, rsz, &newsz)) { errno = EOVERFLOW; + efi_error("arithmetic overflow computing allocation size"); return -1; } new = malloc(newsz); - if (!new) + if (!new) { + efi_error("allocation failed"); return -1; + } *out = new; memcpy(new, dp0, lsz); @@ -154,16 +186,32 @@ efidp_append_node(const_efidp dp, const_efidp dn, efidp *out) ssize_t lsz, rsz, newsz; int rc; - if (!dp && !dn) - return efidp_duplicate_path((const_efidp)(const efidp_header * const)&end_entire, out); + if (!dp && !dn) { + rc = efidp_duplicate_path( + (const_efidp)(const efidp_header * const)&end_entire, + out); + if (rc < 0) + efi_error("efidp_duplicate_path() failed"); + return rc; + } lsz = efidp_size(dp); - if (lsz < 0) + if (lsz < 0) { + efi_error("efidp_size(dp) returned error"); return -1; + } + if (dp && !dn) { + rc = efidp_duplicate_path(dp, out); + if (rc < 0) + efi_error("efidp_duplicate_path() failed"); + return rc; + } + + lsz = efidp_size(dp); + if (lsz < 0) + return -1; - if (dp && !dn) - return efidp_duplicate_path(dp, out); rsz = efidp_node_size(dn); if (rsz < 0) @@ -172,11 +220,15 @@ efidp_append_node(const_efidp dp, const_efidp dn, efidp *out) if (!dp && dn) { if (add(rsz, sizeof(end_entire), &newsz)) { errno = EOVERFLOW; + efi_error( + "arithmetic overflow computing allocation size"); return -1; } efidp new = malloc(rsz + sizeof (end_entire)); - if (!new) + if (!new) { + efi_error("allocation failed"); return -1; + } memcpy(new, dn, dn->length); memcpy((uint8_t *)new + dn->length, &end_entire, @@ -185,14 +237,6 @@ efidp_append_node(const_efidp dp, const_efidp dn, efidp *out) return 0; } - lsz = efidp_size(dp); - if (lsz < 0) - return -1; - - rsz = efidp_node_size(dn); - if (rsz < 0) - return -1; - const_efidp le; le = dp; while (1) { @@ -204,18 +248,23 @@ efidp_append_node(const_efidp dp, const_efidp dn, efidp *out) } rc = efidp_get_next_end(le, &le); - if (rc < 0) + if (rc < 0) { + efi_error("efidp_get_next_end() returned error"); return -1; + } } if (add(lsz, rsz, &newsz) || add(newsz, sizeof(end_entire), &newsz)) { errno = EOVERFLOW; + efi_error("arithmetic overflow computing allocation size"); return -1; } efidp new = malloc(newsz); - if (!new) + if (!new) { + efi_error("allocation failed"); return -1; + } *out = new; memcpy(new, dp, lsz); @@ -370,8 +419,10 @@ efidp_format_device_path(char *buf, size_t size, const_efidp dp, ssize_t limit) limit -= efidp_node_size(dp); int rc = efidp_next_node(dp, &dp); - if (rc < 0) + if (rc < 0) { + efi_error("could not format DP"); return rc; + } } return off+1; } @@ -382,6 +433,7 @@ efidp_parse_device_node(char *path __attribute__((unused)), efidp out __attribute__((unused)), size_t size __attribute__((unused))) { + efi_error("not implented"); errno = -ENOSYS; return -1; } @@ -392,6 +444,7 @@ efidp_parse_device_path(char *path __attribute__((unused)), efidp out __attribute__((unused)), size_t size __attribute__((unused))) { + efi_error("not implented"); errno = -ENOSYS; return -1; } @@ -423,6 +476,7 @@ efidp_make_generic(uint8_t *buf, ssize_t size, uint8_t type, uint8_t subtype, if (!size) return total_size; if (size < total_size) { + efi_error("total size is bigger than size limit"); errno = ENOSPC; return -1; } diff --git a/src/dp.h b/src/dp.h index 6c5558cc..d6775a67 100644 --- a/src/dp.h +++ b/src/dp.h @@ -27,24 +27,30 @@ #include "ucs2.h" -#define format(buf, size, off, fmt, args...) ({ \ +#define format(buf, size, off, dp_type, fmt, args...) ({ \ ssize_t _x = 0; \ if ((off) >= 0) { \ _x = snprintf(((buf)+(off)), \ ((size)?((size)-(off)):0), \ fmt, ## args); \ - if (_x < 0) \ + if (_x < 0) { \ + efi_error( \ + "could not build %s DP string", \ + (dp_type)); \ return _x; \ + } \ (off) += _x; \ } \ off; \ }) -#define format_helper(fn, buf, size, off, args...) ({ \ +#define format_helper(fn, buf, size, off, dp_type, args...) ({ \ ssize_t _x; \ _x = (fn)(((buf)+(off)), \ - ((size)?((size)-(off)):0), ## args); \ + ((size)?((size)-(off)):0), dp_type, ## args); \ if (_x < 0) \ + efi_error("could not build %s DP string", \ + dp_type); \ (off) += _x; \ }) @@ -55,29 +61,38 @@ (void *)__newbuf; \ }) -#define format_guid(buf, size, off, guid) ({ \ +#define format_guid(buf, size, off, dp_type, guid) ({ \ int _rc; \ char *_guidstr = NULL; \ \ _rc = efi_guid_to_str(guid, &_guidstr); \ - format(buf, size, off, "%s", _guidstr); \ + if (_rc < 0) { \ + efi_error("could not build %s GUID DP string", \ + dp_type); \ + } else { \ + _guidstr = onstack(_guidstr, \ + strlen(_guidstr)+1); \ + _rc = format(buf, size, off, dp_type, "%s", \ + _guidstr); \ + } \ + _rc; \ }) static inline ssize_t __attribute__((__unused__)) -format_hex_helper(char *buf, size_t size, const void * const addr, - const size_t len) +format_hex_helper(char *buf, size_t size, const char *dp_type, + const void * const addr, const size_t len) { ssize_t off = 0; for (size_t i = 0; i < len; i++) { - format(buf, size, off, "%02x", + format(buf, size, off, dp_type, "%02x", *((const unsigned char * const )addr+i)); } return off; } -#define format_hex(buf, size, off, addr, len) \ - format_helper(format_hex_helper, buf, size, off, addr, len) +#define format_hex(buf, size, off, dp_type, addr, len) \ + format_helper(format_hex_helper, buf, size, off, dp_type, addr, len) static inline ssize_t __attribute__((__unused__)) @@ -99,10 +114,10 @@ format_vendor_helper(char *buf, size_t size, char *label, const_efidp dp) return off; } -#define format_vendor(buf, size, off, label, dp) \ +#define format_vendor(buf, size, off, label, dp) \ format_helper(format_vendor_helper, buf, size, off, label, dp) -#define format_ucs2(buf, size, off, str, len) ({ \ +#define format_ucs2(buf, size, off, dp_type, str, len) ({ \ uint16_t _ucs2buf[(len)]; \ memset(_ucs2buf, '\0', sizeof (_ucs2buf)); \ memcpy(_ucs2buf, str, sizeof (_ucs2buf) \ @@ -112,17 +127,17 @@ format_vendor_helper(char *buf, size_t size, char *label, const_efidp dp) if (_asciibuf == NULL) \ return -1; \ _asciibuf = onstack(_asciibuf, (len)); \ - format(buf, size, off, "%s", _asciibuf); \ + format(buf, size, off, dp_type, "%s", _asciibuf); \ }) -#define format_array(buf, size, off, fmt, type, addr, len) ({ \ +#define format_array(buf, size, off, dp_type, fmt, type, addr, len) ({ \ for (size_t _i = 0; _i < len; _i++) { \ if (_i != 0) \ - format(buf, size, off, ","); \ - format(buf, size, off, fmt, \ + format(buf, size, off, dp_type, ","); \ + format(buf, size, off, dp_type, fmt, \ ((type *)addr)[_i]); \ } \ - (off); \ + off; \ }) extern ssize_t _format_hw_dn(char *buf, size_t size, const_efidp dp); diff --git a/src/efivar.c b/src/efivar.c index c1c7424e..cbefe8b1 100644 --- a/src/efivar.c +++ b/src/efivar.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -55,6 +56,35 @@ static const char *attribute_names[] = { "" }; +static int verbose_errors = 0; + +static void +show_errors(void) +{ + int rc = 0; + + if (!verbose_errors) + return; + + printf("Error trace:\n"); + for (int i = 0; rc > 0; i++) { + char *filename = NULL; + char *function = NULL; + int line = 0; + char *message = NULL; + int error = 0; + + rc = efi_error_get(i, &filename, &function, &line, &message, + &error); + if (rc < 0) + err(1, "error fetching trace value"); + if (rc == 0) + break; + printf(" %s:%d %s(): %s: %s", filename, line, function, + strerror(error), message); + } +} + static void list_all_variables(void) { @@ -69,6 +99,7 @@ list_all_variables(void) if (rc < 0) { fprintf(stderr, "efivar: error listing variables: %m\n"); + show_errors(); exit(1); } } @@ -89,7 +120,9 @@ parse_name(const char *guid_name, char **name, efi_guid_t *guid) if (right[1] != '-' || right[2] == '\0') { bad_name: errno = -EINVAL; - fprintf(stderr, "efivar: invalid name \"%s\"\n", guid_name); + fprintf(stderr, "efivar: invalid name \"%s\"\n", + guid_name); + show_errors(); exit(1); } name_pos = right + 1 - guid_name; @@ -148,6 +181,7 @@ show_variable(char *guid_name, int display_type) rc = efi_get_variable(guid, name, &data, &data_size, &attributes); if (rc < 0) { fprintf(stderr, "efivar: show variable: %m\n"); + show_errors(); exit(1); } @@ -229,6 +263,7 @@ edit_variable(const char *guid_name, void *data, size_t data_size, int attrib, &old_attributes); if (rc < 0) { fprintf(stderr, "efivar: %m\n"); + show_errors(); exit(1); } @@ -248,6 +283,7 @@ edit_variable(const char *guid_name, void *data, size_t data_size, int attrib, if (rc < 0) { fprintf(stderr, "efivar: %m\n"); + show_errors(); exit(1); } } @@ -257,6 +293,7 @@ validate_name(const char *name) { if (name == NULL) { fprintf(stderr, "Invalid variable name\n"); + show_errors(); exit(1); } } diff --git a/src/efivarfs.c b/src/efivarfs.c index ac12faf6..426090f3 100644 --- a/src/efivarfs.c +++ b/src/efivarfs.c @@ -72,11 +72,19 @@ efivarfs_probe(void) typeof(buf.f_type) magic = EFIVARFS_MAGIC; if (!memcmp(&buf.f_type, &magic, sizeof (magic))) return 1; + else + efi_error("bad fs type for %s", path); tmp = getenv("EFIVARFS_PATH"); - if (tmp && !strcmp(tmp, path)) + if (tmp && !strcmp(tmp, path)) { + efi_error_clear(); return 1; + } + } else { + efi_error("statfs(%s) failed", path); } + } else { + efi_error("access(%s, F_OK) failed", path); } return 0; @@ -100,6 +108,8 @@ efivarfs_set_fd_immutable(int fd, int immutable) if (rc < 0) { if (errno == ENOTTY) rc = 0; + else + efi_error("ioctl(%d, FS_IOC_GETFLAGS) failed", fd); } else if ((immutable && !(flags & FS_IMMUTABLE_FL)) || (!immutable && (flags & FS_IMMUTABLE_FL))) { if (immutable) @@ -108,6 +118,8 @@ efivarfs_set_fd_immutable(int fd, int immutable) flags &= ~FS_IMMUTABLE_FL; rc = ioctl(fd, FS_IOC_SETFLAGS, &flags); + if (rc < 0) + efi_error("ioctl(%d, FS_IOC_SETFLAGS) failed", fd); } return rc; @@ -122,16 +134,21 @@ efivarfs_set_immutable(char *path, int immutable) fd = open(path, O_RDONLY); if (fd < 0) { - if (errno == ENOTTY) + if (errno == ENOTTY) { + efi_error("open(%s, O_RDONLY) failed", path); return 0; - else + } else { return fd; + } } rc = efivarfs_set_fd_immutable(fd, immutable); error = errno; close(fd); errno = error; + if (rc < 0) + efi_error("efivarfs_set_fd_immutable(%d, %d) on %s failed", + fd, immutable, path); return rc; } @@ -144,13 +161,17 @@ efivarfs_get_variable_size(efi_guid_t guid, const char *name, size_t *size) typeof(errno) errno_value; rc = make_efivarfs_path(&path, guid, name); - if (rc < 0) + if (rc < 0) { + efi_error("make_efivarfs_path failed"); goto err; + } struct stat statbuf = { 0, }; rc = stat(path, &statbuf); - if (rc < 0) + if (rc < 0) { + efi_error("stat(%s) failed", path); goto err; + } ret = 0; /* Compensate for the size of the Attributes field. */ @@ -176,8 +197,10 @@ efivarfs_get_variable_attributes(efi_guid_t guid, const char *name, uint32_t attribs; ret = efi_get_variable(guid, name, &data, &data_size, &attribs); - if (ret < 0) + if (ret < 0) { + efi_error("efi_get_variable failed"); return ret; + } *attributes = attribs; if (data) @@ -197,20 +220,28 @@ efivarfs_get_variable(efi_guid_t guid, const char *name, uint8_t **data, char *path; int rc = make_efivarfs_path(&path, guid, name); - if (rc < 0) + if (rc < 0) { + efi_error("make_efivarfs_path failed"); return -1; + } int fd = open(path, O_RDONLY); - if (fd < 0) + if (fd < 0) { + efi_error("open(%s)", path); goto err; + } rc = read(fd, &ret_attributes, sizeof (ret_attributes)); - if (rc < 0) + if (rc < 0) { + efi_error("read failed"); goto err; + } rc = read_file(fd, &ret_data, &size); - if (rc < 0) + if (rc < 0) { + efi_error("read_file failed"); goto err; + } *attributes = ret_attributes; *data = ret_data; @@ -235,11 +266,15 @@ efivarfs_del_variable(efi_guid_t guid, const char *name) { char *path; int rc = make_efivarfs_path(&path, guid, name); - if (rc < 0) + if (rc < 0) { + efi_error("make_efivarfs_path failed"); return -1; + } efivarfs_set_immutable(path, 0); rc = unlink(path); + if (rc < 0) + efi_error("unlink failed"); typeof(errno) errno_value = errno; free(path); @@ -257,35 +292,48 @@ efivarfs_set_variable(efi_guid_t guid, const char *name, uint8_t *data, int ret = -1; if (strlen(name) > 1024) { + efi_error("name too long (%zd of 1024)", strlen(name)); errno = EINVAL; return -1; } char *path; int rc = make_efivarfs_path(&path, guid, name); - if (rc < 0) + if (rc < 0) { + efi_error("make_efivarfs_path failed"); return -1; + } int fd = -1; if (!access(path, F_OK) && !(attributes & EFI_VARIABLE_APPEND_WRITE)) { rc = efi_del_variable(guid, name); - if (rc < 0) + if (rc < 0) { + efi_error("efi_del_variable failed"); goto err; + } } fd = open(path, O_WRONLY|O_CREAT, mode); - if (fd < 0) + if (fd < 0) { + efi_error("open(%s, O_WRONLY|O_CREAT, mode) failed", path); goto err; + } efivarfs_set_fd_immutable(fd, 0); memcpy(buf, &attributes, sizeof (attributes)); memcpy(buf + sizeof (attributes), data, data_size); - rc = write(fd, buf, sizeof (attributes) + data_size); +#if 0 + errno = ENOSPC; + rc = -1; +#else + rc = write(fd, buf, sizeof (attributes) + data_size); +#endif if (rc >= 0) { ret = 0; efivarfs_set_fd_immutable(fd, 1); } else { + efi_error("write failed"); efivarfs_set_fd_immutable(fd, 0); unlink(path); } @@ -306,14 +354,22 @@ static int efivarfs_append_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes) { + int rc; attributes |= EFI_VARIABLE_APPEND_WRITE; - return efivarfs_set_variable(guid, name, data, data_size, attributes, 0); + rc = efivarfs_set_variable(guid, name, data, data_size, attributes, 0); + if (rc < 0) + efi_error("efivarfs_set_variable failed"); + return rc; } static int efivarfs_get_next_variable_name(efi_guid_t **guid, char **name) { - return generic_get_next_variable_name(get_efivarfs_path(), guid, name); + int rc; + rc = generic_get_next_variable_name(get_efivarfs_path(), guid, name); + if (rc < 0) + efi_error("generic_get_next_variable_name failed"); + return rc; } static int @@ -321,11 +377,15 @@ efivarfs_chmod_variable(efi_guid_t guid, const char *name, mode_t mode) { char *path; int rc = make_efivarfs_path(&path, guid, name); - if (rc < 0) + if (rc < 0) { + efi_error("make_efivarfs_path failed"); return -1; + } rc = chmod(path, mode); int saved_errno = errno; + if (rc < 0) + efi_error("chmod(%s,0%o) failed", path, mode); free(path); errno = saved_errno; return -1; diff --git a/src/generics.h b/src/generics.h index 1b31b154..10f242fb 100644 --- a/src/generics.h +++ b/src/generics.h @@ -42,6 +42,7 @@ generic_get_next_variable_name(const char *path, efi_guid_t **guid, char **name) if (!guid || !name) { errno = EINVAL; + efi_error("invalid arguments"); return -1; } @@ -50,30 +51,33 @@ generic_get_next_variable_name(const char *path, efi_guid_t **guid, char **name) if ((*guid == NULL && *name != NULL) || (*guid != NULL && *name == NULL)) { errno = EINVAL; + efi_error("invalid arguments"); return -1; } /* if dir is NULL, we're also starting over */ if (!dir) { dir = opendir(path); - if (!dir) + if (!dir) { + efi_error("opendir(%s) failed", path); return -1; + } int fd = dirfd(dir); if (fd < 0) { typeof(errno) errno_value = errno; + efi_error("dirfd failed"); closedir(dir); errno = errno_value; return -1; } int flags = fcntl(fd, F_GETFD); if (flags < 0) { - warn("fcntl(fd, F_GETFD) failed"); + efi_error("fcntl(fd, F_GETFD) failed"); } else { flags |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, flags) < 0) - warn("fcntl(fd, F_SETFD, " - "flags | FD_CLOEXEC) failed"); + efi_error("fcntl(fd, F_SETFD, flags | FD_CLOEXEC) failed"); } *guid = NULL; @@ -102,6 +106,7 @@ generic_get_next_variable_name(const char *path, efi_guid_t **guid, char **name) closedir(dir); dir = NULL; errno = EINVAL; + efi_error("text_to_guid failed"); return -1; } @@ -155,6 +160,7 @@ generic_append_variable(efi_guid_t guid, const char *name, attributes &= ~EFI_VARIABLE_APPEND_WRITE; rc = efi_del_variable(guid, name); if (rc < 0) { + efi_error("efi_del_variable failed"); free(data); free(d); return rc; @@ -164,17 +170,19 @@ generic_append_variable(efi_guid_t guid, const char *name, * let our caller attempt to clean up :/ */ rc = efi_set_variable(guid, name, d, ds, attributes, 0600); + if (rc < 0) + efi_error("efi_set_variable failed"); free(d); free(data); - return rc; } else if (errno == ENOENT) { data = new_data; data_size = new_data_size; attributes = new_attributes & ~EFI_VARIABLE_APPEND_WRITE; rc = efi_set_variable(guid, name, data, data_size, attributes, 0600); - return rc; } + if (rc < 0) + efi_error("efi_set_variable failed"); return rc; } diff --git a/src/guid.c b/src/guid.c index 2f88d17c..7e0f2bee 100644 --- a/src/guid.c +++ b/src/guid.c @@ -54,7 +54,11 @@ __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_str_to_guid(const char *s, efi_guid_t *guid) { - return text_to_guid(s, guid); + int rc; + rc = text_to_guid(s, guid); + if (rc < 0) + efi_error("text_to_guid(\"%s\",...)", s); + return rc; } int @@ -66,7 +70,7 @@ efi_guid_to_str(const efi_guid_t *guid, char **sp) int rc = -1; if (!sp) { - return snprintf(NULL, 0, GUID_FORMAT, + rc = snprintf(NULL, 0, GUID_FORMAT, le32_to_cpu(guid->a), le16_to_cpu(guid->b), le16_to_cpu(guid->c), @@ -74,7 +78,7 @@ efi_guid_to_str(const efi_guid_t *guid, char **sp) guid->e[0], guid->e[1], guid->e[2], guid->e[3], guid->e[4], guid->e[5]); } else if (sp && *sp) { - return snprintf(*sp, GUID_LENGTH_WITH_NUL, GUID_FORMAT, + rc = snprintf(*sp, GUID_LENGTH_WITH_NUL, GUID_FORMAT, le32_to_cpu(guid->a), le16_to_cpu(guid->b), le16_to_cpu(guid->c), @@ -92,6 +96,8 @@ efi_guid_to_str(const efi_guid_t *guid, char **sp) if (rc >= 0) *sp = ret; } + if (rc < 0) + efi_error("Could not format guid"); return rc; } @@ -142,6 +148,7 @@ _get_common_guidname(const efi_guid_t *guid, struct guidname **result) if (!tmp) { *result = NULL; errno = ENOENT; + efi_error("GUID is not in common GUID list"); return -1; } @@ -160,7 +167,10 @@ efi_guid_to_name(efi_guid_t *guid, char **name) *name = strndup(result->name, sizeof (result->name) -1); return *name ? (int)strlen(*name) : -1; } - return efi_guid_to_str(guid, name); + rc = efi_guid_to_str(guid, name); + if (rc >= 0) + efi_error_clear(); + return rc; } int @@ -174,6 +184,7 @@ efi_guid_to_symbol(efi_guid_t *guid, char **symbol) *symbol = strndup(result->symbol, sizeof (result->symbol) -1); return *symbol ? (int)strlen(*symbol) : -1; } + efi_error_clear(); errno = EINVAL; return -1; } diff --git a/src/include/efivar/efivar-dp.h b/src/include/efivar/efivar-dp.h index a0395130..45186ea6 100644 --- a/src/include/efivar/efivar-dp.h +++ b/src/include/efivar/efivar-dp.h @@ -939,35 +939,55 @@ efidp_is_valid(const_efidp dp, ssize_t limit) switch (hdr->type) { case EFIDP_HARDWARE_TYPE: if (hdr->subtype != EFIDP_HW_VENDOR && - hdr->length > 1024) + hdr->length > 1024) { + errno = EINVAL; + efi_error("invalid hardware node"); return 0; + } break; case EFIDP_ACPI_TYPE: - if (hdr->length > 1024) + if (hdr->length > 1024) { + errno = EINVAL; + efi_error("invalid ACPI node"); return 0; + } break; case EFIDP_MESSAGE_TYPE: if (hdr->subtype != EFIDP_MSG_VENDOR && - hdr->length > 1024) + hdr->length > 1024) { + errno = EINVAL; + efi_error("invalid message node"); return 0; + } break; case EFIDP_MEDIA_TYPE: if (hdr->subtype != EFIDP_MEDIA_VENDOR && - hdr->length > 1024) + hdr->length > 1024) { + errno = EINVAL; + efi_error("invalid media node"); return 0; + } break; case EFIDP_BIOS_BOOT_TYPE: break; case EFIDP_END_TYPE: - if (hdr->length > 4) + if (hdr->length > 4) { + errno = EINVAL; + efi_error("invalid end node"); return 0; + } break; default: + errno = EINVAL; + efi_error("invalid device path node type"); return 0; } - if (limit < hdr->length) + if (limit < hdr->length) { + errno = EINVAL; + efi_error("device path node length overruns buffer"); return 0; + } limit -= hdr->length; if (hdr->type != EFIDP_END_TYPE && @@ -978,6 +998,7 @@ efidp_is_valid(const_efidp dp, ssize_t limit) } if (limit < 0) { errno = EINVAL; + efi_error("device path node length overruns buffer"); return 0; } return 1; diff --git a/src/lib.c b/src/lib.c index 6a9b3929..60709e31 100644 --- a/src/lib.c +++ b/src/lib.c @@ -47,7 +47,11 @@ __attribute__((__visibility__ ("default"))) _efi_set_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes) { - return ops->set_variable(guid, name, data, data_size, attributes, 0600); + int rc; + rc = ops->set_variable(guid, name, data, data_size, attributes, 0600); + if (rc < 0) + efi_error("ops->set_variable() failed"); + return rc; } __asm__(".symver _efi_set_variable,_efi_set_variable@"); @@ -57,7 +61,11 @@ __attribute__((__visibility__ ("default"))) _efi_set_variable_variadic(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, ...) { - return ops->set_variable(guid, name, data, data_size, attributes, 0600); + int rc; + rc = ops->set_variable(guid, name, data, data_size, attributes, 0600); + if (rc < 0) + efi_error("ops->set_variable() failed"); + return rc; } __asm__(".symver _efi_set_variable_variadic,efi_set_variable@"); @@ -67,7 +75,13 @@ __attribute__((__visibility__ ("default"))) efi_set_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes, mode_t mode) { - return ops->set_variable(guid, name, data, data_size, attributes, mode); + int rc; + rc = ops->set_variable(guid, name, data, data_size, attributes, mode); + if (rc < 0) + efi_error("ops->set_variable() failed"); + else + efi_error_clear(); + return rc; } __asm__(".symver efi_set_variable,efi_set_variable@@LIBEFIVAR_0.24"); @@ -77,10 +91,22 @@ __attribute__((__visibility__ ("default"))) efi_append_variable(efi_guid_t guid, const char *name, uint8_t *data, size_t data_size, uint32_t attributes) { - if (!ops->append_variable) - return generic_append_variable(guid, name, data, data_size, - attributes); - return ops->append_variable(guid, name, data, data_size, attributes); + int rc; + if (!ops->append_variable) { + rc = generic_append_variable(guid, name, data, data_size, + attributes); + if (rc < 0) + efi_error("generic_append_variable() failed"); + else + efi_error_clear(); + return rc; + } + rc = ops->append_variable(guid, name, data, data_size, attributes); + if (rc < 0) + efi_error("ops->append_variable() failed"); + else + efi_error_clear(); + return rc; } int @@ -88,11 +114,18 @@ __attribute__((__nonnull__ (2))) __attribute__((__visibility__ ("default"))) efi_del_variable(efi_guid_t guid, const char *name) { + int rc; if (!ops->del_variable) { + efi_error("del_variable() is not implemented"); errno = ENOSYS; return -1; } - return ops->del_variable(guid, name); + rc = ops->del_variable(guid, name); + if (rc < 0) + efi_error("ops->del_variable() failed"); + else + efi_error_clear(); + return rc; } int @@ -101,11 +134,18 @@ __attribute__((__visibility__ ("default"))) efi_get_variable(efi_guid_t guid, const char *name, uint8_t **data, size_t *data_size, uint32_t *attributes) { + int rc; if (!ops->get_variable) { + efi_error("get_variable() is not implemented"); errno = ENOSYS; return -1; } - return ops->get_variable(guid, name, data, data_size, attributes); + rc = ops->get_variable(guid, name, data, data_size, attributes); + if (rc < 0) + efi_error("ops->get_variable failed"); + else + efi_error_clear(); + return rc; } int @@ -114,11 +154,18 @@ __attribute__((__visibility__ ("default"))) efi_get_variable_attributes(efi_guid_t guid, const char *name, uint32_t *attributes) { + int rc; if (!ops->get_variable_attributes) { + efi_error("get_variable_attributes() is not implemented"); errno = ENOSYS; return -1; } - return ops->get_variable_attributes(guid, name, attributes); + rc = ops->get_variable_attributes(guid, name, attributes); + if (rc < 0) + efi_error("ops->get_variable_attributes() failed"); + else + efi_error_clear(); + return rc; } int @@ -126,11 +173,18 @@ __attribute__((__nonnull__ (2, 3))) __attribute__((__visibility__ ("default"))) efi_get_variable_size(efi_guid_t guid, const char *name, size_t *size) { + int rc; if (!ops->get_variable_size) { + efi_error("get_variable_size() is not implemented"); errno = ENOSYS; return -1; } - return ops->get_variable_size(guid, name, size); + rc = ops->get_variable_size(guid, name, size); + if (rc < 0) + efi_error("ops->get_variable_size() failed"); + else + efi_error_clear(); + return rc; } int @@ -138,11 +192,18 @@ __attribute__((__nonnull__ (1, 2))) __attribute__((__visibility__ ("default"))) efi_get_next_variable_name(efi_guid_t **guid, char **name) { + int rc; if (!ops->get_next_variable_name) { + efi_error("get_next_variable_name() is not implemented"); errno = ENOSYS; return -1; } - return ops->get_next_variable_name(guid, name); + rc = ops->get_next_variable_name(guid, name); + if (rc < 0) + efi_error("ops->get_next_variable_name() failed"); + else + efi_error_clear(); + return rc; } int @@ -150,11 +211,18 @@ __attribute__((__nonnull__ (2))) __attribute__((__visibility__ ("default"))) efi_chmod_variable(efi_guid_t guid, const char *name, mode_t mode) { + int rc; if (!ops->chmod_variable) { + efi_error("chmod_variable() is not implemented"); errno = ENOSYS; return -1; } - return ops->chmod_variable(guid, name, mode); + rc = ops->chmod_variable(guid, name, mode); + if (rc < 0) + efi_error("ops->chmod_variable() failed"); + else + efi_error_clear(); + return rc; } int @@ -186,7 +254,13 @@ libefivar_init(void) ops = ops_list[i]; break; } - } else if (ops_list[i]->probe()) { + } else { + int rc = ops_list[i]->probe(); + if (rc <= 0) + efi_error("ops_list[%d]->probe() failed", i); + else + efi_error_clear(); + ops = ops_list[i]; break; } diff --git a/src/linux.c b/src/linux.c index 994caf1f..87f22849 100644 --- a/src/linux.c +++ b/src/linux.c @@ -254,8 +254,10 @@ sysfs_sata_get_port_info(uint32_t print_id, struct disk_info *info) int rc; d = opendir("/sys/class/ata_device/"); - if (!d) + if (!d) { + efi_error("opendir failed on /sys/class/ata_device/"); return -1; + } while ((de = readdir(d)) != NULL) { uint32_t found_print_id; diff --git a/src/vars.c b/src/vars.c index 9e32d386..4b4e20f1 100644 --- a/src/vars.c +++ b/src/vars.c @@ -76,8 +76,10 @@ get_file_data_size(int dfd, char *name) strcat(raw_var, "/raw_var"); int fd = openat(dfd, raw_var, O_RDONLY); - if (fd < 0) + if (fd < 0) { + efi_error("openat failed"); return -1; + } char buf[4096]; ssize_t sz, total = 0; @@ -182,12 +184,16 @@ get_size_from_file(const char *filename, size_t *retsize) int errno_value; int ret = -1; int fd = open(filename, O_RDONLY); - if (fd < 0) + if (fd < 0) { + efi_error("open(%s, O_RDONLY) failed", filename); goto err; + } int rc = read_file(fd, &buf, &bufsize); - if (rc < 0) + if (rc < 0) { + efi_error("read_file(%s) failed", filename); goto err; + } long long size = strtoll((char *)buf, NULL, 0); if ((size == LLONG_MIN || size == LLONG_MAX) && errno == ERANGE) { @@ -218,12 +224,17 @@ vars_probe(void) char *newvar; /* If we can't tell if it's 64bit or not, this interface is no good. */ - if (is_64bit() < 0) + if (is_64bit() < 0) { + efi_error("is_64bit() failed"); return 0; - if (asprintfa(&newvar, "%s%s", get_vars_path(), "new_var") < 0) + } + if (asprintfa(&newvar, "%s%s", get_vars_path(), "new_var") < 0) { + efi_error("asprintfa failed"); return 0; + } if (!access(newvar, F_OK)) return 1; + efi_error("access(%s, F_OK) failed", newvar); return 0; } @@ -238,14 +249,18 @@ vars_get_variable_size(efi_guid_t guid, const char *name, size_t *size) name, guid.a, guid.b, guid.c, bswap_16(guid.d), guid.e[0], guid.e[1], guid.e[2], guid.e[3], guid.e[4], guid.e[5]); - if (rc < 0) + if (rc < 0) { + efi_error("asprintf failed"); goto err; + } size_t retsize = 0; rc = get_size_from_file(path, &retsize); if (rc >= 0) { ret = 0; *size = retsize; + } else if (rc < 0) { + efi_error("get_size_from_file(%s) failed", path); } err: errno_value = errno; @@ -268,8 +283,10 @@ vars_get_variable_attributes(efi_guid_t guid, const char *name, uint32_t attribs; ret = efi_get_variable(guid, name, &data, &data_size, &attribs); - if (ret < 0) + if (ret < 0) { + efi_error("efi_get_variable() failed"); return ret; + } *attributes = attribs; if (data) @@ -291,16 +308,22 @@ vars_get_variable(efi_guid_t guid, const char *name, uint8_t **data, name, guid.a, guid.b, guid.c, bswap_16(guid.d), guid.e[0], guid.e[1], guid.e[2], guid.e[3], guid.e[4], guid.e[5]); - if (rc < 0) + if (rc < 0) { + efi_error("asprintf failed"); return -1; + } int fd = open(path, O_RDONLY); - if (fd < 0) + if (fd < 0) { + efi_error("open(%s, O_RDONLY) failed", path); goto err; + } rc = read_file(fd, &buf, &bufsize); - if (rc < 0) + if (rc < 0) { + efi_error("read_file(%s) failed", path); goto err; + } bufsize -= 1; /* read_file pads out 1 extra byte to NUL it */ @@ -309,13 +332,17 @@ vars_get_variable(efi_guid_t guid, const char *name, uint8_t **data, if (bufsize != sizeof(efi_kernel_variable_64_t)) { errno = EFBIG; + efi_error("file size is wrong for 64-bit variable (%zd of %zd)", + bufsize, sizeof(efi_kernel_variable_64_t)); goto err; } var64 = (void *)buf; *data = malloc(var64->DataSize); - if (!*data) + if (!*data) { + efi_error("malloc failed"); goto err; + } memcpy(*data, var64->Data, var64->DataSize); *data_size = var64->DataSize; *attributes = var64->Attributes; @@ -323,14 +350,18 @@ vars_get_variable(efi_guid_t guid, const char *name, uint8_t **data, efi_kernel_variable_32_t *var32; if (bufsize != sizeof(efi_kernel_variable_32_t)) { + efi_error("file size is wrong for 32-bit variable (%zd of %zd)", + bufsize, sizeof(efi_kernel_variable_32_t)); errno = EFBIG; goto err; } var32 = (void *)buf; *data = malloc(var32->DataSize); - if (!*data) + if (!*data) { + efi_error("malloc failed"); goto err; + } memcpy(*data, var32->Data, var32->DataSize); *data_size = var32->DataSize; *attributes = var32->Attributes; @@ -364,39 +395,55 @@ vars_del_variable(efi_guid_t guid, const char *name) name, guid.a, guid.b, guid.c, bswap_16(guid.d), guid.e[0], guid.e[1], guid.e[2], guid.e[3], guid.e[4], guid.e[5]); - if (rc < 0) + if (rc < 0) { + efi_error("asprintf failed"); return -1; + } uint8_t *buf = NULL; size_t buf_size = 0; char *delvar; int fd = open(path, O_RDONLY); - if (fd < 0) + if (fd < 0) { + efi_error("open(%s, O_RDONLY) failed", path); goto err; + } rc = read_file(fd, &buf, &buf_size); buf_size -= 1; /* read_file pads out 1 extra byte to NUL it */ - if (rc < 0) + if (rc < 0) { + efi_error("read_file(%s) failed", path); goto err; + } if (buf_size != sizeof(efi_kernel_variable_64_t) && buf_size != sizeof(efi_kernel_variable_32_t)) { + efi_error("variable size %zd is not 32-bit (%zd) or 64-bit (%zd)", + buf_size, sizeof(efi_kernel_variable_32_t), + sizeof(efi_kernel_variable_64_t)); + errno = EFBIG; goto err; } - if (asprintfa(&delvar, "%s%s", get_vars_path(), "del_var") < 0) + if (asprintfa(&delvar, "%s%s", get_vars_path(), "del_var") < 0) { + efi_error("asprintfa() failed"); goto err; + } close(fd); fd = open(delvar, O_WRONLY); - if (fd < 0) + if (fd < 0) { + efi_error("open(%s, O_WRONLY) failed", delvar); goto err; + } rc = write(fd, buf, buf_size); if (rc >= 0) ret = 0; + else + efi_error("write() failed"); err: errno_value = errno; @@ -462,11 +509,14 @@ vars_chmod_variable(efi_guid_t guid, const char *name, mode_t mode) name, guid.a, guid.b, guid.c, bswap_16(guid.d), guid.e[0], guid.e[1], guid.e[2], guid.e[3], guid.e[4], guid.e[5]); - if (rc < 0) + if (rc < 0) { + efi_error("asprintf failed"); return -1; + } rc = _vars_chmod_variable(path, mode); int saved_errno = errno; + efi_error("_vars_chmod_variable() failed"); free(path); errno = saved_errno; return rc; @@ -481,10 +531,14 @@ vars_set_variable(efi_guid_t guid, const char *name, uint8_t *data, int ret = -1; if (strlen(name) > 1024) { + efi_error("variable name size is too large (%zd of 1024)", + strlen(name)); errno = EINVAL; return -1; } if (data_size > 1024) { + efi_error("variable data size is too large (%zd of 1024)", + data_size); errno = ENOSPC; return -1; } @@ -494,21 +548,26 @@ vars_set_variable(efi_guid_t guid, const char *name, uint8_t *data, name, guid.a, guid.b, guid.c, bswap_16(guid.d), guid.e[0], guid.e[1], guid.e[2], guid.e[3], guid.e[4], guid.e[5]); - if (rc < 0) + if (rc < 0) { + efi_error("asprintf failed"); return -1; + } len = rc; int fd = -1; if (!access(path, F_OK)) { rc = efi_del_variable(guid, name); - if (rc < 0) + if (rc < 0) { + efi_error("efi_del_variable failed"); goto err; + } } char *newvar; - if (asprintfa(&newvar, "%s%s", get_vars_path(), "new_var") < 0) + if (asprintfa(&newvar, "%s%s", get_vars_path(), "new_var") < 0) { + efi_error("asprintfa failed"); goto err; - + } if (is_64bit()) { efi_kernel_variable_64_t var64 = { @@ -523,8 +582,10 @@ vars_set_variable(efi_guid_t guid, const char *name, uint8_t *data, memcpy(var64.Data, data, data_size); fd = open(newvar, O_WRONLY); - if (fd < 0) + if (fd < 0) { + efi_error("open(%s, O_WRONLY) failed", newvar); goto err; + } rc = write(fd, &var64, sizeof(var64)); } else { @@ -539,14 +600,18 @@ vars_set_variable(efi_guid_t guid, const char *name, uint8_t *data, memcpy(var32.Data, data, data_size); fd = open(newvar, O_WRONLY); - if (fd < 0) + if (fd < 0) { + efi_error("open(%s, O_WRONLY) failed", newvar); goto err; + } rc = write(fd, &var32, sizeof(var32)); } if (rc >= 0) ret = 0; + else + efi_error("write() failed"); /* this is inherently racy, but there's no way to do it correctly with * this kernel API. Fortunately, all directory contents get created @@ -569,7 +634,12 @@ vars_set_variable(efi_guid_t guid, const char *name, uint8_t *data, static int vars_get_next_variable_name(efi_guid_t **guid, char **name) { - return generic_get_next_variable_name(get_vars_path(), guid, name); + int rc; + const char *vp = get_vars_path(); + rc = generic_get_next_variable_name(vp, guid, name); + if (rc < 0) + efi_error("generic_get_next_variable_name(%s,...) failed", vp); + return rc; } struct efi_var_operations vars_ops = {