/
githubmirror
/
efivar
Обзор
Документация
Войти
/
githubmirror
/
efivar
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
39
src/creator.c
507 строк
10 KB
Sergii Dmytruk
creator.c: use setmntent(), not fopen()
30 янв 2024, 02:11
30 янв 2024, 02:11
63b6fed
Код
Авторство
О чём код?
// SPDX-License-Identifier: LGPL-2.1-or-later /* * libefiboot - library for the manipulation of EFI boot variables * Copyright 2012-2015 Red Hat, Inc. */ #include "fix_coverity.h" #include <fcntl.h> #include <inttypes.h> #include <limits.h> #include <mntent.h> #include <netinet/in.h> #include <netinet/ip.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/socket.h> #include "efiboot.h" static int NONNULL(1, 2, 3) find_file(const char * const filepath, char **devicep, char **relpathp) { struct stat fsb = { 0, }; int rc; int ret = -1; FILE *mounts = NULL; char linkbuf[PATH_MAX+1] = ""; ssize_t linklen = 0; linklen = strlen(filepath); if (linklen > PATH_MAX) { errno = ENAMETOOLONG; efi_error("filepath length exceeds PATH_MAX"); return -1; } strcpy(linkbuf, filepath); do { rc = stat(linkbuf, &fsb); if (rc < 0) return rc; if (S_ISLNK(fsb.st_mode)) { char tmp[PATH_MAX+1] = ""; ssize_t l; l = readlink(linkbuf, tmp, PATH_MAX); if (l < 0) { efi_error("readlink failed"); return -1; } tmp[l] = '\0'; linklen = l; strcpy(linkbuf, tmp); } else { break; } } while (1); mounts = setmntent("/proc/self/mounts", "r"); if (mounts == NULL) { efi_error("couldn not open /proc/self/mounts"); return -1; } struct mntent *me; while (1) { struct stat dsb = { 0, }; errno = 0; me = getmntent(mounts); if (!me) { if (feof(mounts)) { errno = ENOENT; efi_error("could not find mountpoint"); } goto err; } if (me->mnt_fsname[0] != '/') continue; rc = stat(me->mnt_fsname, &dsb); if (rc < 0) { if (errno == ENOENT) continue; efi_error("could not stat mountpoint"); goto err; } if (!S_ISBLK(dsb.st_mode)) continue; if (dsb.st_rdev == fsb.st_dev) { ssize_t mntlen = strlen(me->mnt_dir); if (mntlen >= linklen) continue; if (strncmp(linkbuf, me->mnt_dir, mntlen)) continue; *devicep = strdup(me->mnt_fsname); 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; break; } } err: if (mounts) endmntent(mounts); return ret; } static int open_disk(struct device *dev, int flags) { char *diskpath = NULL; int rc; rc = asprintfa(&diskpath, "/dev/%s", dev->disk_name); 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 rc; } static char * tilt_slashes(char *s) { char *p; for (p = s; *p; p++) if (*p == '/') *p = '\\'; return s; } ssize_t efi_va_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, const char *devpath, int partition, const char *relpath, uint32_t options, va_list ap) { ssize_t ret = -1, off = 0, sz; struct device *dev = NULL; int fd = -1; int saved_errno; debug("partition:%d", partition); if (buf && size) memset(buf, '\0', size); fd = open(devpath, O_RDONLY); if (fd < 0) { efi_error("could not open device for ESP"); goto err; } dev = device_get(fd, partition); if (dev == NULL) { efi_error("could not get ESP disk info"); goto err; } if (partition < 0) { int disk_fd; debug("partition: %d", partition); disk_fd = open_disk(dev, (options & EFIBOOT_OPTIONS_WRITE_SIGNATURE) ? O_RDWR : O_RDONLY); if (disk_fd < 0) { efi_error("could not open disk"); goto err; } if (is_partitioned(disk_fd)) partition = 1; else partition = 0; debug("is_partitioned(): partition -> %d", partition); close(disk_fd); } set_part(dev, partition); if (partition == 0) { options |= EFIBOOT_ABBREV_NONE; options &= ~(EFIBOOT_ABBREV_HD| EFIBOOT_ABBREV_FILE| EFIBOOT_ABBREV_EDD10); } if (options & EFIBOOT_ABBREV_NONE) debug("EFIBOOT_ABBREV_NONE"); if (options & EFIBOOT_ABBREV_HD) debug("EFIBOOT_ABBREV_HD"); if (options & EFIBOOT_ABBREV_FILE) debug("EFIBOOT_ABBREV_FILE"); if (options & EFIBOOT_ABBREV_EDD10) debug("EFIBOOT_ABBREV_EDD10"); if (options & EFIBOOT_ABBREV_EDD10) { va_list aq; va_copy(aq, ap); dev->edd10_devicenum = va_arg(aq, uint32_t); va_end(aq); } if (!(options & (EFIBOOT_ABBREV_FILE|EFIBOOT_ABBREV_HD)) && (dev->flags & DEV_ABBREV_ONLY)) { efi_error_clear(); errno = EINVAL; efi_error("Device must use File() or HD() device path"); goto err; } if ((options & EFIBOOT_ABBREV_EDD10) && (!(options & EFIBOOT_ABBREV_FILE) && !(options & EFIBOOT_ABBREV_HD))) { sz = efidp_make_edd10(buf, size, dev->edd10_devicenum); if (sz < 0) { efi_error("could not make EDD 1.0 device path"); goto err; } off = sz; } else if (!(options & EFIBOOT_ABBREV_FILE) && !(options & EFIBOOT_ABBREV_HD)) { /* * We're probably on a modern kernel, so just parse the * symlink from /sys/dev/block/$major:$minor and get it * from there. */ sz = make_blockdev_path(buf, size, dev); if (sz < 0) { efi_error("could not create device path"); goto err; } off += sz; } if ((!(options & EFIBOOT_ABBREV_FILE) && dev->part_name) || ((options & EFIBOOT_ABBREV_HD) && ! dev->part_name)) { int disk_fd; int saved_errno; disk_fd = open_disk(dev, (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+off, size?size-off:0, disk_fd, dev->part, options); saved_errno = errno; close(disk_fd); errno = saved_errno; 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) { 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) { efi_error("could not make EndEntire DP node"); goto err; } off += sz; ret = off; err: saved_errno = errno; if (dev) device_free(dev); if (fd >= 0) close(fd); errno = saved_errno; debug("= %zd", ret); return ret; } ssize_t NONNULL(3, 5) PUBLIC efi_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size, const char *devpath, int partition, const char *relpath, uint32_t options, ...) { ssize_t ret; int saved_errno; va_list ap; va_start(ap, options); ret = efi_va_generate_file_device_path_from_esp(buf, size, devpath, partition, relpath, options, ap); saved_errno = errno; va_end(ap); errno = saved_errno; if (ret < 0) efi_error("could not generate File DP from ESP"); return ret; } static int get_part(char *devpath) { int fd; int partition = -1; struct device *dev = NULL; fd = open(devpath, O_RDONLY); if (fd < 0) { efi_error("could not open device for ESP"); goto err; } dev = device_get(fd, -1); if (dev == NULL) { efi_error("could not get ESP disk info"); goto err; } partition = dev->part; if (partition < 0) partition = 0; err: if (dev) device_free(dev); if (fd >= 0) close(fd); return partition; } ssize_t NONNULL(3) PUBLIC efi_generate_file_device_path(uint8_t *buf, ssize_t size, const char * const filepath, uint32_t options, ...) { int rc; ssize_t ret = -1; char *child_devpath = NULL; char *parent_devpath = NULL; char *relpath = NULL; va_list ap; int saved_errno; rc = find_file(filepath, &child_devpath, &relpath); if (rc < 0) { efi_error("could not canonicalize fs path"); goto err; } rc = find_parent_devpath(child_devpath, &parent_devpath); if (rc < 0) { efi_error("could not find parent device for file"); goto err; } debug("child_devpath:%s", child_devpath); debug("parent_devpath:%s", parent_devpath); debug("child_devpath:%s", child_devpath); debug("rc:%d", rc); rc = get_part(child_devpath); if (rc < 0) { efi_error("Couldn't get partition number for %s", child_devpath); goto err; } debug("detected partition:%d", rc); va_start(ap, options); if (!strcmp(parent_devpath, "/dev/block")) ret = efi_va_generate_file_device_path_from_esp(buf, size, child_devpath, rc, relpath, options, ap); else ret = efi_va_generate_file_device_path_from_esp(buf, size, parent_devpath, rc, relpath, options, ap); 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) free(child_devpath); if (parent_devpath) free(parent_devpath); if (relpath) free(relpath); errno = saved_errno; return ret; } static ssize_t NONNULL(3, 4, 5, 6) make_ipv4_path(uint8_t *buf, ssize_t size, const char * const local_addr UNUSED, const char * const remote_addr UNUSED, const char * const gateway_addr UNUSED, const char * const netmask UNUSED, uint16_t local_port UNUSED, uint16_t remote_port UNUSED, uint16_t protocol UNUSED, uint8_t addr_origin UNUSED) { ssize_t ret; #if 0 if (local_addr == NULL || remote_addr == NULL || gateway_addr == NULL || netmask == NULL) { errno = EINVAL; return -1; } #endif 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 NONNULL(3, 4, 5, 6, 7) PUBLIC efi_generate_ipv4_device_path(uint8_t *buf, ssize_t size, const char * const ifname, const char * const local_addr, const char * const remote_addr, const char * const gateway_addr, const char * const netmask, uint16_t local_port, uint16_t remote_port, uint16_t protocol, uint8_t addr_origin) { ssize_t off = 0; ssize_t sz; sz = make_mac_path(buf, size, ifname); 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) { 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) { efi_error("could not make EndEntire DP node"); return -1; } off += sz; return off; } uint32_t PUBLIC efi_get_libefiboot_version(void) { return LIBEFIVAR_VERSION; } // vim:fenc=utf-8:tw=75:noet