All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Melnychenko <andrew@daynix.com>
To: mst@redhat.com, yuri.benditovich@daynix.com, jasowang@redhat.com,
	armbru@redhat.com, eblake@redhat.com, berrange@redhat.com
Cc: yan@daynix.com, qemu-devel@nongnu.org
Subject: [PATCH 3/5] qmp: Added the helper stamp check.
Date: Tue, 13 Jul 2021 18:37:56 +0300	[thread overview]
Message-ID: <20210713153758.323614-4-andrew@daynix.com> (raw)
In-Reply-To: <20210713153758.323614-1-andrew@daynix.com>

Added function to check the stamp in the helper.
eBPF helper should have a special symbol that generates during build.
QEMU checks the helper and determinates that it fits, so the helper
will produce proper output.

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 meson.build                       |  10 +
 monitor/meson.build               |   1 +
 monitor/qemu-helper-stamp-utils.c | 297 ++++++++++++++++++++++++++++++
 monitor/qemu-helper-stamp-utils.h |  24 +++
 4 files changed, 332 insertions(+)
 create mode 100644 monitor/qemu-helper-stamp-utils.c
 create mode 100644 monitor/qemu-helper-stamp-utils.h

diff --git a/meson.build b/meson.build
index 626cf932c1..257e51d91b 100644
--- a/meson.build
+++ b/meson.build
@@ -1757,6 +1757,16 @@ foreach d : hx_headers
 endforeach
 genh += hxdep
 
+helper_stamp = custom_target(
+    'qemu-helper-stamp.h',
+    output : 'qemu-helper-stamp.h',
+    input : 'ebpf/rss.bpf.skeleton.h',
+    command : [python, '-c', 'import hashlib; print(\'#define QEMU_HELPER_STAMP qemuHelperStamp_{}\'.format(hashlib.sha1(open(\'@INPUT@\', \'rb\').read()).hexdigest()))'],
+    capture: true,
+)
+
+genh += helper_stamp
+
 ###################
 # Collect sources #
 ###################
diff --git a/monitor/meson.build b/monitor/meson.build
index 6d00985ace..2b6b39549b 100644
--- a/monitor/meson.build
+++ b/monitor/meson.build
@@ -5,5 +5,6 @@ softmmu_ss.add(files(
   'hmp.c',
 ))
 softmmu_ss.add([spice_headers, files('qmp-cmds.c')])
+softmmu_ss.add(files('qemu-helper-stamp-utils.c'))
 
 specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: [files('misc.c'), spice])
diff --git a/monitor/qemu-helper-stamp-utils.c b/monitor/qemu-helper-stamp-utils.c
new file mode 100644
index 0000000000..d34c3b94c5
--- /dev/null
+++ b/monitor/qemu-helper-stamp-utils.c
@@ -0,0 +1,297 @@
+/*
+ * QEMU helper stamp check utils.
+ *
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ *  Andrew Melnychenko <andrew@daynix.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Description: This file mostly implements helper stamp checking.
+ *              The stamp is implemented in a similar way as in qemu modules.
+ *              The helper should contain a specific symbol.
+ *              Not in a similar way is symbol checking - here we parse
+ *              the ELF file. For now(10.07.2021), only eBPF helper contains
+ *              the stamp, and the stamp is generated from
+ *              sha1 ebpf/rss.bpf.skeleton.h (see meson.build).
+ */
+
+#include "qemu/osdep.h"
+#include "elf.h"
+#include "qemu-helper-stamp-utils.h"
+
+#include <glib/gstdio.h>
+
+#ifdef CONFIG_LINUX
+
+static void *file_allocate_and_read(int fd, off_t off, size_t size)
+{
+    void *data;
+    int err;
+
+    if (fd < 0) {
+        return NULL;
+    }
+
+    err = lseek(fd, off, SEEK_SET);
+    if (err < 0) {
+        return NULL;
+    }
+
+    data = g_new0(char, size);
+    if (data == NULL) {
+        return NULL;
+    }
+
+    err = read(fd, data, size);
+    if (err < 0) {
+        g_free(data);
+        return NULL;
+    }
+
+    return data;
+}
+
+static Elf64_Shdr *elf64_get_section_table(int fd, Elf64_Ehdr *elf_header)
+{
+    if (elf_header == NULL) {
+        return NULL;
+    }
+    return (Elf64_Shdr *)file_allocate_and_read(fd, elf_header->e_shoff,
+                             elf_header->e_shnum * elf_header->e_shentsize);
+}
+
+static Elf32_Shdr *elf32_get_section_table(int fd, Elf32_Ehdr *elf_header)
+{
+    if (elf_header == NULL) {
+        return NULL;
+    }
+    return (Elf32_Shdr *)file_allocate_and_read(fd, elf_header->e_shoff,
+                             elf_header->e_shnum * elf_header->e_shentsize);
+}
+
+static void *elf64_get_section_data(int fd, const Elf64_Shdr* section_header)
+{
+    if (fd < 0 || section_header == NULL) {
+        return NULL;
+    }
+    return file_allocate_and_read(fd, section_header->sh_offset,
+                                  section_header->sh_size);
+}
+
+static void *elf32_get_section_data(int fd, const Elf32_Shdr* section_header)
+{
+    if (fd < 0 || section_header == NULL) {
+        return NULL;
+    }
+    return file_allocate_and_read(fd, section_header->sh_offset,
+                                  section_header->sh_size);
+}
+
+static bool elf64_check_symbol_in_symbol_table(int fd,
+                                               Elf64_Shdr *section_table,
+                                               Elf64_Shdr *symbol_section,
+                                               const char *symbol)
+{
+    Elf64_Sym *symbol_table;
+    char *string_table;
+    uint32_t i;
+    bool ret = false;
+
+    symbol_table = (Elf64_Sym *) elf64_get_section_data(fd, symbol_section);
+    if (symbol_table == NULL) {
+        return false;
+    }
+
+    string_table = (char *) elf64_get_section_data(
+            fd, section_table + symbol_section->sh_link);
+    if (string_table == NULL) {
+        g_free(symbol_table);
+        return false;
+    }
+
+    for (i = 0; i < (symbol_section->sh_size / sizeof(Elf64_Sym)); ++i) {
+        if (strncmp((string_table + symbol_table[i].st_name),
+                     symbol, strlen(symbol)) == 0)
+        {
+            ret = true;
+            break;
+        }
+    }
+
+    g_free(string_table);
+    g_free(symbol_table);
+    return ret;
+}
+
+static bool elf32_check_symbol_in_symbol_table(int fd,
+                                               Elf32_Shdr *section_table,
+                                               Elf32_Shdr *symbol_section,
+                                               const char *symbol)
+{
+    Elf32_Sym *symbol_table;
+    char *string_table;
+    uint32_t i;
+    bool ret = false;
+
+    symbol_table = (Elf32_Sym *) elf32_get_section_data(fd, symbol_section);
+    if (symbol_table == NULL) {
+        return false;
+    }
+
+    string_table = (char *) elf32_get_section_data(fd,
+                                       section_table + symbol_section->sh_link);
+    if (string_table == NULL) {
+        g_free(symbol_table);
+        return false;
+    }
+
+    for (i = 0; i < (symbol_section->sh_size / sizeof(Elf32_Sym)); ++i) {
+        if (strncmp((string_table + symbol_table[i].st_name),
+                     symbol, strlen(symbol)) == 0)
+        {
+            ret = true;
+            break;
+        }
+    }
+
+    g_free(string_table);
+    g_free(symbol_table);
+    return ret;
+}
+
+static bool elf64_check_stamp(int fd, Elf64_Ehdr *elf_header, const char *stamp)
+{
+    Elf64_Shdr *section_table;
+    size_t i;
+    bool ret = false;
+
+    section_table = elf64_get_section_table(fd, elf_header);
+    if (section_table == NULL) {
+        return false;
+    }
+
+    for (i = 0; i < elf_header->e_shnum; ++i) {
+        if ((section_table[i].sh_type == SHT_SYMTAB)
+             || (section_table[i].sh_type == SHT_DYNSYM)) {
+            if (elf64_check_symbol_in_symbol_table(fd, section_table,
+                                                   section_table + i, stamp)) {
+                ret = true;
+                break;
+            }
+        }
+    }
+
+    g_free(section_table);
+    return ret;
+}
+
+static bool elf32_check_stamp(int fd, Elf32_Ehdr *elf_header, const char *stamp)
+{
+    Elf32_Shdr *section_table;
+    size_t i;
+    bool ret = false;
+
+    section_table = elf32_get_section_table(fd, elf_header);
+    if (section_table == NULL) {
+        return false;
+    }
+
+    for (i = 0; i < elf_header->e_shnum; ++i) {
+        if ((section_table[i].sh_type == SHT_SYMTAB)
+             || (section_table[i].sh_type == SHT_DYNSYM)) {
+            if (elf32_check_symbol_in_symbol_table(fd, section_table,
+                                                   section_table + i, stamp)) {
+                ret = true;
+                break;
+            }
+        }
+    }
+
+    g_free(section_table);
+    return ret;
+}
+
+bool qemu_check_helper_stamp(const char *path, const char *stamp)
+{
+    int fd;
+    bool ret = false;
+    Elf64_Ehdr *elf_header;
+
+    fd = open(path, O_RDONLY | O_SYNC);
+    if (fd < 0) {
+        return false;
+    }
+
+    elf_header = (Elf64_Ehdr *)file_allocate_and_read(
+            fd, 0, sizeof(Elf64_Ehdr));
+    if (elf_header == NULL) {
+        goto error;
+    }
+
+    if (strncmp((char *)elf_header->e_ident, ELFMAG, SELFMAG)) {
+        g_free(elf_header);
+        goto error;
+    }
+
+    if (elf_header->e_ident[EI_CLASS] == ELFCLASS64) {
+        ret = elf64_check_stamp(fd, elf_header, stamp);
+    } else if (elf_header->e_ident[EI_CLASS] == ELFCLASS32) {
+        ret = elf32_check_stamp(fd, (Elf32_Ehdr *)elf_header, stamp);
+    }
+
+    g_free(elf_header);
+error:
+    close(fd);
+    return ret;
+}
+
+#else
+
+bool qemu_check_helper_stamp(const char *path, const char *stamp)
+{
+    return false;
+}
+
+#endif
+
+char *qemu_find_helper(const char *name, bool check_stamp)
+{
+    char *qemu_exec = NULL;
+    char *qemu_dir = NULL;
+    char *helper = NULL;
+
+    if (name == NULL) {
+        return NULL;
+    }
+
+    helper = g_build_filename(CONFIG_QEMU_HELPERDIR, name, NULL);
+    if (g_access(helper, F_OK) == 0
+        && (!check_stamp
+            || qemu_check_helper_stamp(helper, QEMU_HELPER_STAMP_STR))) {
+        return helper;
+    }
+    g_free(helper);
+
+#ifdef CONFIG_LINUX
+    qemu_exec = g_file_read_link("/proc/self/exe", NULL);
+#else
+    qemu_exec = NULL;
+#endif
+    if (qemu_exec != NULL) {
+        qemu_dir = g_path_get_dirname(qemu_exec);
+        g_free(qemu_exec);
+        helper = g_build_filename(qemu_dir, name, NULL);
+        g_free(qemu_dir);
+        if (g_access(helper, F_OK) == 0
+           && (!check_stamp
+               || qemu_check_helper_stamp(helper, QEMU_HELPER_STAMP_STR))) {
+            return helper;
+        }
+        g_free(helper);
+    }
+
+    return NULL;
+}
diff --git a/monitor/qemu-helper-stamp-utils.h b/monitor/qemu-helper-stamp-utils.h
new file mode 100644
index 0000000000..e64cf96aa6
--- /dev/null
+++ b/monitor/qemu-helper-stamp-utils.h
@@ -0,0 +1,24 @@
+/*
+ * QEMU helper stamp check utils.
+ *
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ *  Andrew Melnychenko <andrew@daynix.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_QEMU_HELPER_STAMP_UTILS_H
+#define QEMU_QEMU_HELPER_STAMP_UTILS_H
+
+#include "qemu-helper-stamp.h" /* generated stamp per build */
+
+#define QEMU_HELPER_STAMP_STR     stringify(QEMU_HELPER_STAMP)
+
+bool qemu_check_helper_stamp(const char *path, const char *stamp);
+
+char *qemu_find_helper(const char *name, bool check_stamp);
+
+#endif /* QEMU_QEMU_HELPER_STAMP_UTILS_H */
-- 
2.31.1



  parent reply	other threads:[~2021-07-13 15:39 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-13 15:37 [PATCH 0/5] ebpf: Added ebpf helper for libvirtd Andrew Melnychenko
2021-07-13 15:37 ` [PATCH 1/5] ebpf: Added eBPF initialization by fds and map update Andrew Melnychenko
2021-08-20  3:34   ` Jason Wang
2021-08-25 18:13     ` Andrew Melnichenko
2021-07-13 15:37 ` [PATCH 2/5] virtio-net: Added property to load eBPF RSS with fds Andrew Melnychenko
2021-08-20  3:36   ` Jason Wang
2021-08-25 18:18     ` Andrew Melnichenko
2021-07-13 15:37 ` Andrew Melnychenko [this message]
2021-07-13 15:37 ` [PATCH 4/5] ebpf_rss_helper: Added helper for eBPF RSS Andrew Melnychenko
2021-08-20  3:40   ` Jason Wang
2021-08-25 18:24     ` Andrew Melnichenko
2021-09-01  6:37       ` Jason Wang
2021-08-30 17:07     ` Yuri Benditovich
2021-09-01  6:42       ` Jason Wang
2021-09-06 15:50         ` Andrew Melnichenko
2021-09-07  3:22           ` Jason Wang
2021-09-07 10:40         ` Yuri Benditovich
2021-09-08  3:45           ` Jason Wang
2021-09-09  0:00             ` Yuri Benditovich
2021-09-09  1:16               ` Jason Wang
2021-09-09 23:43                 ` Yuri Benditovich
2021-09-10  1:37                   ` Jason Wang
2021-07-13 15:37 ` [PATCH 5/5] qmp: Added qemu-ebpf-rss-path command Andrew Melnychenko
2021-08-07 12:54   ` Markus Armbruster
2021-08-10 11:58     ` Andrew Melnichenko
2021-08-24  6:41       ` Markus Armbruster
2021-08-25 18:45         ` Andrew Melnichenko
2021-08-26  4:53           ` Markus Armbruster
2021-08-29 20:13         ` Yuri Benditovich
2021-08-30  6:10           ` Markus Armbruster
2021-08-30  7:51             ` Yuri Benditovich
2021-08-30  8:13               ` Markus Armbruster
2021-08-30 16:56                 ` Yuri Benditovich
2021-08-31 15:00                   ` Markus Armbruster
2021-08-31 19:37                     ` Andrew Melnichenko
2021-09-01  7:16                       ` Markus Armbruster
     [not found]                         ` <CABcq3pGzs=RqLCuu70KyWt7W6T=qEhihK6v=iHJyfuGqiN_Q+A@mail.gmail.com>
     [not found]                           ` <CAOEp5Oc_uUn2nJq+B+SK-iQSo5udyUTirWHS5=8N0JxerRaz7A@mail.gmail.com>
2021-09-09 10:35                             ` Andrew Melnichenko
2021-09-02 16:06                   ` Markus Armbruster
2021-07-22  8:37 ` [PATCH 0/5] ebpf: Added ebpf helper for libvirtd Andrew Melnichenko
2021-08-16 11:57   ` Yuri Benditovich
2021-08-17  5:49     ` Jason Wang
2021-08-20  3:43 ` Jason Wang
2023-02-19 16:20 [PATCH 0/5] eBPF RSS Helper support Andrew Melnychenko
2023-02-19 16:20 ` [PATCH 3/5] qmp: Added the helper stamp check Andrew Melnychenko
2023-02-20  9:49   ` Daniel P. Berrangé
2023-02-27  3:45     ` Andrew Melnichenko
2023-02-27 14:06       ` Toke Høiland-Jørgensen
2023-02-28  9:56     ` Yuri Benditovich
2023-02-28 18:04       ` Daniel P. Berrangé
2023-02-28 19:01         ` Toke Høiland-Jørgensen
2023-02-28 19:03           ` Daniel P. Berrangé
2023-02-28 22:21             ` Toke Høiland-Jørgensen
2023-03-01  9:30               ` Daniel P. Berrangé
2023-03-01 14:53                 ` Toke Høiland-Jørgensen
2023-03-01 15:05                   ` Daniel P. Berrangé
2023-03-01 22:40                     ` Toke Høiland-Jørgensen
2023-03-22 13:26                       ` Andrew Melnichenko
2023-03-22 15:59                         ` Daniel P. Berrangé
2023-02-28 19:01         ` Daniel P. Berrangé
2023-03-01  6:49         ` Yuri Benditovich
2023-03-01  9:31           ` Daniel P. Berrangé

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210713153758.323614-4-andrew@daynix.com \
    --to=andrew@daynix.com \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=eblake@redhat.com \
    --cc=jasowang@redhat.com \
    --cc=mst@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=yan@daynix.com \
    --cc=yuri.benditovich@daynix.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.