diff --git a/trustzone-awared-vm/Host/vtzb_proxy/Makefile b/trustzone-awared-vm/Host/vtzb_proxy/Makefile index 2ad103e68fb315bac8c7122ccd92823ae649f4af..b7d9df70b4b5516b55abab69ca325e9e648d7944 100644 --- a/trustzone-awared-vm/Host/vtzb_proxy/Makefile +++ b/trustzone-awared-vm/Host/vtzb_proxy/Makefile @@ -13,9 +13,10 @@ $(TARGET_LIBSEC): APP_CFLAGS += -DSECURITY_AUTH_ENHANCE APP_CFLAGS += -Ilibboundscheck/include +APP_CFLAGS += -I/usr/include/libxml2 APP_CFLAGS += -Iinclude -Iinclude/cloud APP_CFLAGS += -Werror -Wall -Wextra -fstack-protector-all -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie -D_FORTIFY_SOURCE=2 -O2 -APP_LDFLAGS += -lboundscheck -Llibboundscheck/lib -lpthread +APP_LDFLAGS += -lboundscheck -Llibboundscheck/lib -lpthread -lxml2 -lvirt APP_SOURCES := ./vtzb_proxy.c \ ./thread_pool.c \ @@ -26,6 +27,7 @@ APP_SOURCES := ./vtzb_proxy.c \ ./agent.c \ ./process_data.c \ ./tlogcat.c \ + ./libvirt_api_wrap.c APP_OBJECTS := $(APP_SOURCES:.c=.o) diff --git a/trustzone-awared-vm/Host/vtzb_proxy/libvirt_api_wrap.c b/trustzone-awared-vm/Host/vtzb_proxy/libvirt_api_wrap.c new file mode 100644 index 0000000000000000000000000000000000000000..19ca41ef980158d18a0f5aa948c1b0be0dbf77c6 --- /dev/null +++ b/trustzone-awared-vm/Host/vtzb_proxy/libvirt_api_wrap.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include "libvirt_api_wrap.h" + +#define PATH_SIZE 5 +#define SOCKET_SIZE 7 + +/* + parse xml +*/ + +static int match_chardev_socket_path(const char *value, const char *target_path) +{ + if ((value == NULL) || (target_path == NULL)) + return 0; + + // 必须是 socket 类型 + if (strncmp(value, "socket,", SOCKET_SIZE) != 0) + return -1; + + const char *p = strstr(value, "path="); + if (p == NULL) + return -1; + + p += PATH_SIZE; + const char *comma = strchr(p, ','); + size_t xml_value_len = (comma - p); + size_t target_length = strlen(target_path); + + if(target_length != xml_value_len){ + return -1; + } + + if (strncmp(p, target_path, target_length) != 0) { + return -1; + } + return 0; +} + +static int has_serial_socket_path(const char *xml, const char *target_path) +{ + if (!xml || !target_path) + return 0; + + xmlDocPtr doc = xmlReadMemory(xml, strlen(xml), "domain.xml", NULL, + XML_PARSE_NOBLANKS | XML_PARSE_NONET); + if (!doc) + return 0; + + int found = 0; + xmlNodePtr root = xmlDocGetRootElement(doc); + if (!root) + goto cleanup; + + xmlNodePtr node = root->children; + while (node) { + if (node->type == XML_ELEMENT_NODE && + xmlStrEqual(node->name, BAD_CAST "commandline")) { + // 检查命名空间是否为 QEMU + if (node->ns && node->ns->href && xmlStrEqual(node->ns->href, BAD_CAST QEMU_NS_URI)) { + // 遍历 子节点 + xmlNodePtr arg = node->children; + while (arg) { + if (arg->type == XML_ELEMENT_NODE && + xmlStrEqual(arg->name, BAD_CAST "arg")) { + xmlChar *value = xmlGetProp(arg, BAD_CAST "value"); + if (value) { + found = match_chardev_socket_path((const char *)value, target_path); + if(found == 0){ + tlogi("found ok ,domain name %s\n", value); + return 1; + } + xmlFree(value); + } + } + arg = arg->next; + } + } + } + node = node->next; + } +cleanup: + xmlFreeDoc(doc); + return -1; +} + +// 根据 socket 路径查找正在运行的 VM 名称(返回动态分配字符串) +char *find_domain_name_by_serial_socket(virConnectPtr conn, const char *socket_path) +{ + int n = virConnectNumOfDomains(conn); + if (n <= 0) + return NULL; + + int *ids = malloc(n * sizeof(int)); + if (ids == NULL) + return NULL; + + int actual = virConnectListDomains(conn, ids, n); + for (int i = 0; i < actual; i++) { + virDomainPtr dom = virDomainLookupByID(conn, ids[i]); + if (dom == NULL) + continue; + char *xml = virDomainGetXMLDesc(dom, 0); + if (xml) { + if (has_serial_socket_path(xml, socket_path) == 1) { + const char *name = virDomainGetName(dom); + char *result = name ? strdup(name) : NULL; + free(xml); + virDomainFree(dom); + free(ids); + return result; + } + free(xml); + } + virDomainFree(dom); + } + free(ids); + return NULL; +} + +virConnectPtr init_virt_conn() +{ + if (virEventRegisterDefaultImpl() < 0) { + tloge("Failed to register event impl\n"); + return NULL; + } + + virConnectPtr conn = virConnectOpen("qemu:///system"); + if (conn == NULL) { + tloge("Failed to connect open \n"); + return NULL; + } + return conn; +} + +void deinit_virt_conn(virConnectPtr conn_ptr) +{ + if (conn_ptr != NULL) { + virConnectClose(conn_ptr); + } +} + +virDomainPtr init_domain_by_socket_path(virConnectPtr conn, const char *socket_path) +{ + char *domain_name = find_domain_name_by_serial_socket(conn, socket_path); + if(domain_name == NULL){ + tloge("No VM found using socket: %s\n", socket_path); + virConnectClose(conn); + return NULL; + } + + virDomainPtr dom = virDomainLookupByName(conn, domain_name); + if (dom == NULL){ + tloge("Failed to lookup domain %s\n", domain_name); + virConnectClose(conn); + return NULL; + } + + if(domain_name){ + free(domain_name); + } + return dom; +} + +void deinit_domain(virDomainPtr dom) +{ + if(dom != NULL){ + virDomainFree(dom); + } +} diff --git a/trustzone-awared-vm/Host/vtzb_proxy/libvirt_api_wrap.h b/trustzone-awared-vm/Host/vtzb_proxy/libvirt_api_wrap.h new file mode 100644 index 0000000000000000000000000000000000000000..7c3477a06b9a64726b7483b488bfe89035cb236c --- /dev/null +++ b/trustzone-awared-vm/Host/vtzb_proxy/libvirt_api_wrap.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2012-2023. All rights reserved. + * Licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef __LIBVIRT_API_WRAP_H__ +#define __LIBVIRT_API_WRAP_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tlogcat.h" + +#define QEMU_NS_URI "http://libvirt.org/schemas/domain/qemu/1.0" + +virConnectPtr init_virt_conn(); +virDomainPtr init_domain_by_socket_path(virConnectPtr conn_ptr, const char *socket_path); + +void deinit_virt_conn(virConnectPtr conn_ptr); +void deinit_domain(virDomainPtr dom); + +#endif \ No newline at end of file diff --git a/trustzone-awared-vm/Host/vtzb_proxy/serial_port.c b/trustzone-awared-vm/Host/vtzb_proxy/serial_port.c index 023aaa23b7a728200eba0673a620e8afc8b3b3d0..b4e34d5e8fe53a2c3fed270676fc1b6f88a52da3 100644 --- a/trustzone-awared-vm/Host/vtzb_proxy/serial_port.c +++ b/trustzone-awared-vm/Host/vtzb_proxy/serial_port.c @@ -153,7 +153,7 @@ void release_vm_file(struct serial_port_file *serial_port, int i) serial_port->vm_file = NULL; } -static void do_check_stat_serial_port() +void do_check_stat_serial_port() { int ret; int i = 0; @@ -173,6 +173,7 @@ static void do_check_stat_serial_port() g_pollfd[i].fd = serial_port->sock; g_serial_array[i] = serial_port; create_reader_thread(serial_port, i); + create_rebootmonitor_thread(serial_port, i); } } } else { diff --git a/trustzone-awared-vm/Host/vtzb_proxy/serial_port.h b/trustzone-awared-vm/Host/vtzb_proxy/serial_port.h index 9181a3d9df7ed19d399e6555b42c7323c9a31c27..7b3da5164f1ea4d2d355eb2d89dd942a1e37de98 100644 --- a/trustzone-awared-vm/Host/vtzb_proxy/serial_port.h +++ b/trustzone-awared-vm/Host/vtzb_proxy/serial_port.h @@ -49,6 +49,7 @@ int send_to_vm(struct serial_port_file *serial_port, void *packet_rsp, size_t si void *get_rd_buf(int serial_port_fd); void *get_serial_port_file(int serial_port_fd); void check_stat_serial_port(); +void do_check_stat_serial_port(); int check_stat_serial_port_first(); void release_vm_file(struct serial_port_file *serial_port, int i); #endif diff --git a/trustzone-awared-vm/Host/vtzb_proxy/thread_pool.c b/trustzone-awared-vm/Host/vtzb_proxy/thread_pool.c index fe0844ca932c2836f35ce4b38ca6b67ef68c50df..b57ff788658da34fc3c14b29747d0deabf94fc11 100644 --- a/trustzone-awared-vm/Host/vtzb_proxy/thread_pool.c +++ b/trustzone-awared-vm/Host/vtzb_proxy/thread_pool.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "thread_pool.h" #include "serial_port.h" @@ -15,6 +16,7 @@ #include "vtzb_proxy.h" #include "debug.h" #include "vm.h" +#include "libvirt_api_wrap.h" extern ThreadPool g_pool; ThreadFuncArgs g_thd_args[THREAD_POOL_SIZE]; @@ -195,6 +197,149 @@ void *admin_thread(void *arg) return NULL; } +static __thread int reboot_flag = 0; +static int domain_reboot_callback(virConnectPtr conn, virDomainPtr dom, void *opaque) +{ + (void)conn; + const char *name = virDomainGetName(dom); + struct serial_port_file *file = (struct serial_port_file *)opaque; + shutdown(file->sock, SHUT_RDWR); + reboot_flag = 1; + tlogi("release_vm_file1, domain name is %s ,index is %d \n", name, file->index); + return 0; +} + +static void timeout_callback(int timer, void *opaque) +{ + (void)timer; + (void)opaque; + return; +} + +static int life_cycle_callback(virConnectPtr conn, + virDomainPtr dom, + int event, + int detail, + void *opaque) +{ + (void)conn; + (void)opaque; + const char *name = virDomainGetName(dom); + if (name == NULL) + return -1; + + switch (event) { + case VIR_DOMAIN_EVENT_STOPPED: + switch (detail) { + case VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN: + case VIR_DOMAIN_EVENT_STOPPED_DESTROYED: + case VIR_DOMAIN_EVENT_STOPPED_CRASHED: + reboot_flag = 1; + tlogi("Shutdown & Destroyed & Crashed happend\n"); + break; + default: + tlogw("Reason: Other (%d)\n", detail); + } + break; + } + return 0; +} + +static void *deal_rebootmonitor_thread(void *arg) +{ + struct serial_port_file *serial_port = (struct serial_port_file *)arg; + + virConnectPtr conn = init_virt_conn(); + if(conn == NULL){ + tloge("conn init failed \n"); + return NULL; + } + // domain ptr + virDomainPtr domain_ptr = init_domain_by_socket_path(conn, serial_port->path); + if(domain_ptr == NULL){ + tloge("domain ptr failed \n"); + return NULL; + } + + int lifecycleCallbackID = virConnectDomainEventRegisterAny( + conn, + domain_ptr, + VIR_DOMAIN_EVENT_ID_LIFECYCLE, + VIR_DOMAIN_EVENT_CALLBACK(life_cycle_callback), + NULL, NULL + ); + + int callbackID = virConnectDomainEventRegisterAny( + conn, + domain_ptr, + VIR_DOMAIN_EVENT_ID_REBOOT, + VIR_DOMAIN_EVENT_CALLBACK(domain_reboot_callback), + (void *)serial_port, + NULL + ); + tlogv("callback_id %d \n", callbackID); + if(callbackID < 0){ + tloge("callbackID error \n"); + return NULL; + } + + int timeout_id = virEventAddTimeout(10, timeout_callback, NULL, NULL); + tlogv("timeout_id %d \n", timeout_id); + if (timeout_id < 0) { + tloge("[Thread] Failed to add timeout\n"); + virConnectDomainEventDeregisterAny(conn, callbackID); + return NULL; + } + + while (1) { + if(reboot_flag == 1) { + if (virEventRemoveTimeout(timeout_id) == 0) { + tlogi("Timer %d removed successfully.\n", timeout_id); + } + if(virConnectDomainEventDeregisterAny(conn, callbackID) == 0) { + tlogi("Deregister reboot successfully %d \n", callbackID); + } + if(virConnectDomainEventDeregisterAny(conn, lifecycleCallbackID) == 0) { + tlogi("Deregister lifecycle successfully %d \n", lifecycleCallbackID); + } + if(virEventRunDefaultImpl() < 0){ + tloge("[Thread] Event loop error\n"); + } + tlogi("reboot succedd\n"); + break; + } + if(virEventRunDefaultImpl() < 0) { + tloge("[Thread] Event loop error\n"); + break; + } + } + reboot_flag = 0; + deinit_domain(domain_ptr); + deinit_virt_conn(conn); + tlogi("deinit thread \n"); + return NULL; +} + +int create_rebootmonitor_thread(struct serial_port_file *serial_port, int i) +{ + int ret; + char name[THREAD_NAME_LEN] = {0}; + if ((ret = pthread_create(&g_pool.rebootmonitor_threads[i], NULL, deal_rebootmonitor_thread, serial_port))) { + tloge("create reboot monitor thread failed\n"); + return ret; + } + sprintf(name, "reboot_%d", i); + if ((ret = pthread_setname_np(g_pool.rebootmonitor_threads[i], name))) { + tloge("set thread name failed\n"); + return ret; + } + if ((ret = pthread_detach(g_pool.rebootmonitor_threads[i]))) { + tloge("thread detach failed\n"); + } + return ret; +} + + static void *deal_packet_thread(void *arg) { int ret; @@ -211,15 +356,15 @@ static void *deal_packet_thread(void *arg) ret = read(serial_port->sock, serial_port->rd_buf + serial_port->offset, BUF_LEN_MAX_RD - serial_port->offset); if (ret < 0) { + tloge("read failed , serial_sock %d , ret %d \n", serial_port->sock, ret); if (errno == ECONNRESET || errno == EBADF) { goto end; } tloge("read domain socket failed, err: %s\n", strerror(errno)); continue; - } - // when vm destroy, has many zero read - if (ret == 0) { - continue; + } else if (ret == 0) { + tlogw("read domain socket return zero value \n" ); + goto end; } buf_len = ret + serial_port->offset; /* diff --git a/trustzone-awared-vm/Host/vtzb_proxy/thread_pool.h b/trustzone-awared-vm/Host/vtzb_proxy/thread_pool.h index 5b3a59facd199c1737857270294e59153cfbc18c..43c929f10e1d6bb5855ded64096f168372acb4f4 100644 --- a/trustzone-awared-vm/Host/vtzb_proxy/thread_pool.h +++ b/trustzone-awared-vm/Host/vtzb_proxy/thread_pool.h @@ -38,6 +38,7 @@ typedef struct { pthread_t admin_tid; pthread_t threads[THREAD_POOL_SIZE]; // Thread array pthread_t reader_threads[SERIAL_PORT_NUM]; + pthread_t rebootmonitor_threads[SERIAL_PORT_NUM]; unsigned int session_ids[THREAD_POOL_SIZE]; // Session ID of the ongoing command bool kill_flag[THREAD_POOL_SIZE]; void *task_args[THREAD_POOL_SIZE]; @@ -65,6 +66,7 @@ void thread_pool_destroy(ThreadPool *pool); void *thread_func(void *arg); void *admin_thread(void *arg); int create_reader_thread(struct serial_port_file *serial_port, int i); +int create_rebootmonitor_thread(struct serial_port_file *serial_port, int i); void thread_pool_submit(ThreadPool *pool, void *(*task_func)(void *), void *arg); void replenish_thread_pool(ThreadPool *pool, pthread_t thd, char *name); void restart_pool_thread(ThreadPool *pool, pthread_t tid); diff --git a/trustzone-awared-vm/Host/vtzb_proxy/vtzb_proxy.c b/trustzone-awared-vm/Host/vtzb_proxy/vtzb_proxy.c index 2388dbfcfdcbc9f07f7fbcf516779bb1b1efa0d8..4181baf6a8e360834d63da52822ae1498386cbf3 100644 --- a/trustzone-awared-vm/Host/vtzb_proxy/vtzb_proxy.c +++ b/trustzone-awared-vm/Host/vtzb_proxy/vtzb_proxy.c @@ -784,8 +784,8 @@ int main() { goto END1; while (1) { - check_stat_serial_port(); - ret = safepoll(g_pollfd, SERIAL_PORT_NUM, 20*1000); + do_check_stat_serial_port(); + ret = safepoll(g_pollfd, SERIAL_PORT_NUM, 2*1000); if (ret <= 0) { continue; } diff --git a/trustzone-awared-vm/docs/README.md b/trustzone-awared-vm/docs/README.md index 473f798b6c0914e44cd70f84d6290081afed49e7..7056bfa784d6c68f38a3888b7f9206942571c22b 100644 --- a/trustzone-awared-vm/docs/README.md +++ b/trustzone-awared-vm/docs/README.md @@ -4,6 +4,7 @@ yum install gcc patch make kernel-devel-$(uname -r) ninja-build yum install glib2 glib2-devel pixman-devel yum install openssl-devel + yum install libxml2-devel libvirt-devel ``` 2. `vtzb_proxy`编译 ```shell