From 727ece331961c5a495350b38afa982f1598e5b82 Mon Sep 17 00:00:00 2001
From: renoseven <dev@renoseven.net>
Date: Fri, 22 Dec 2023 13:45:48 +0800
Subject: [PATCH 07/15] upatch: elf verification

Signed-off-by: renoseven <dev@renoseven.net>
---
 daemon/src/patch/manager/driver/upatch/mod.rs |   4 +-
 upatch/upatch-manage/upatch-elf.c             |   7 ++
 upatch/upatch-tool/log.h                      |   1 +
 upatch/upatch-tool/upatch-elf.c               | 102 ++++++++++--------
 upatch/upatch-tool/upatch-tool-lib.c          |   9 +-
 5 files changed, 72 insertions(+), 51 deletions(-)

diff --git a/daemon/src/patch/manager/driver/upatch/mod.rs b/daemon/src/patch/manager/driver/upatch/mod.rs
index e4a914b..4d06e84 100644
--- a/daemon/src/patch/manager/driver/upatch/mod.rs
+++ b/daemon/src/patch/manager/driver/upatch/mod.rs
@@ -7,7 +7,7 @@ use anyhow::{anyhow, bail, ensure, Result};
 
 use indexmap::IndexMap;
 use lazy_static::lazy_static;
-use libc::{c_char, EEXIST, EFAULT, ENOENT, EPERM};
+use libc::{c_char, EEXIST, EFAULT, ENOENT, ENOEXEC, EPERM};
 use log::{debug, info};
 use parking_lot::Mutex;
 use syscare_abi::PatchStatus;
@@ -182,7 +182,7 @@ impl PatchDriver for UserPatchDriver {
         match ret_val {
             0 => Ok(()),
             EPERM => bail!("Upatch: Operation not permitted"),
-            ENOENT => bail!("Upatch: Patch symbol is empty"),
+            ENOEXEC => bail!("Upatch: Patch format error"),
             EEXIST => bail!("Upatch: Patch is already exist"),
             _ => bail!("Upatch: {}", std::io::Error::from_raw_os_error(ret_val)),
         }
diff --git a/upatch/upatch-manage/upatch-elf.c b/upatch/upatch-manage/upatch-elf.c
index 2bd3175..31180b5 100644
--- a/upatch/upatch-manage/upatch-elf.c
+++ b/upatch/upatch-manage/upatch-elf.c
@@ -67,6 +67,13 @@ static int open_elf(struct elf_info *einfo, const char *name)
     einfo->shdrs = (void *)einfo->hdr + einfo->hdr->e_shoff;
     einfo->shstrtab = (void *)einfo->hdr + einfo->shdrs[einfo->hdr->e_shstrndx].sh_offset;
 
+    void *einfo_eof = einfo->hdr + einfo->patch_size;
+    if ((void *)einfo->shdrs > einfo_eof || (void *)einfo->shstrtab > einfo_eof) {
+        log_error("File '%s' is not a valid elf\n", name);
+        ret = -ENOEXEC;
+        goto out;
+    }
+
     for (i = 0; i < einfo->hdr->e_shnum; ++i) {
         sec_name = einfo->shstrtab + einfo->shdrs[i].sh_name;
         if (streql(sec_name, BUILD_ID_NAME) && einfo->shdrs[i].sh_type == SHT_NOTE) {
diff --git a/upatch/upatch-tool/log.h b/upatch/upatch-tool/log.h
index 75213d8..e42e290 100644
--- a/upatch/upatch-tool/log.h
+++ b/upatch/upatch-tool/log.h
@@ -11,5 +11,6 @@
 #define log_debug(format, ...) log(DEBUG, format, ##__VA_ARGS__)
 #define log_normal(format, ...) log(NORMAL, format, ##__VA_ARGS__)
 #define log_warn(format, ...) log(WARN, format, ##__VA_ARGS__)
+#define log_error(format, ...) log(ERR, format, ##__VA_ARGS__)
 
 #endif
diff --git a/upatch/upatch-tool/upatch-elf.c b/upatch/upatch-tool/upatch-elf.c
index 5b9b0bd..def536c 100644
--- a/upatch/upatch-tool/upatch-elf.c
+++ b/upatch/upatch-tool/upatch-elf.c
@@ -44,53 +44,65 @@ out:
 
 static int open_elf(struct elf_info *einfo, const char *name)
 {
-	int ret = 0, fd = -1, i;
-	char *sec_name;
-	struct stat st;
-
-	// TODO: check ELF
-	fd = open(name, O_RDONLY);
-	if (fd == -1)
-		log_warn("open %s failed with errno %d \n", name, errno);
+    int ret = 0, fd = -1, i;
+    char *sec_name;
+    struct stat st;
+
+    fd = open(name, O_RDONLY);
+    if (fd == -1) {
+        ret = -errno;
+        log_error("Failed to open file '%s', ret=%d\n", name, ret);
+        goto out;
+    }
+
+    ret = stat(name, &st);
+    if (ret != 0) {
+        ret = -errno;
+        log_error("Failed to stat file '%s', ret=%d\n", name, ret);
+        goto out;
+    }
+
+    ret = read_from_offset(fd, (void **)&einfo->patch_buff, st.st_size, 0);
+    if (ret != 0) {
+        log_error("Failed to read file '%s', ret=%d\n", name, ret);
+        goto out;
+    }
+
+    einfo->name = name;
+    einfo->inode = st.st_ino;
+    einfo->patch_size = st.st_size;
+    einfo->hdr = (void *)einfo->patch_buff;
+    einfo->shdrs = (void *)einfo->hdr + einfo->hdr->e_shoff;
+    einfo->shstrtab = (void *)einfo->hdr + einfo->shdrs[einfo->hdr->e_shstrndx].sh_offset;
+
+    void *einfo_eof = einfo->hdr + einfo->patch_size;
+    if ((void *)einfo->shdrs > einfo_eof || (void *)einfo->shstrtab > einfo_eof) {
+        log_error("File '%s' is not a valid elf\n", name);
+        ret = -ENOEXEC;
+        goto out;
+    }
+
+    for (i = 0; i < einfo->hdr->e_shnum; ++i) {
+        sec_name = einfo->shstrtab + einfo->shdrs[i].sh_name;
+        if (streql(sec_name, BUILD_ID_NAME) && einfo->shdrs[i].sh_type == SHT_NOTE) {
+            einfo->num_build_id = i;
+            break;
+        }
+    }
+
+    if (einfo->num_build_id == 0) {
+        ret = -EINVAL;
+        log_error("Cannot find section '%s'\n", BUILD_ID_NAME);
+        goto out;
+    }
+
+    ret = 0;
 
-	ret = stat(name, &st);
-	if (ret)
-		log_warn("get %s stat failed with errno %d \n", name, errno);
-
-	ret = read_from_offset(fd, (void **)&einfo->patch_buff, st.st_size, 0);
-	if (ret)
-		goto out;
-
-	einfo->name = name;
-	einfo->inode = st.st_ino;
-	einfo->patch_size = st.st_size;
-	einfo->hdr = (void *)einfo->patch_buff;
-	einfo->shdrs = (void *)einfo->hdr + einfo->hdr->e_shoff;
-	einfo->shstrtab = (void *)einfo->hdr +
-			  einfo->shdrs[einfo->hdr->e_shstrndx].sh_offset;
-
-	for (i = 0; i < einfo->hdr->e_shnum; ++i) {
-		sec_name = einfo->shstrtab + einfo->shdrs[i].sh_name;
-		if (streql(sec_name, BUILD_ID_NAME) &&
-		    einfo->shdrs[i].sh_type == SHT_NOTE) {
-			einfo->num_build_id = i;
-			break;
-		}
-	}
-
-	if (einfo->num_build_id == 0) {
-		ret = EINVAL;
-		log_warn("no %s found \n", BUILD_ID_NAME);
-		goto out;
-	}
-
-	log_warn("no %ld found \n", einfo->inode);
-
-	ret = 0;
 out:
-	if (fd != -1)
-		close(fd);
-	return ret;
+    if (fd > 0) {
+        close(fd);
+    }
+    return ret;
 }
 
 int upatch_init(struct upatch_elf *uelf, const char *name)
diff --git a/upatch/upatch-tool/upatch-tool-lib.c b/upatch/upatch-tool/upatch-tool-lib.c
index 4f816bb..4e5bda1 100644
--- a/upatch/upatch-tool/upatch-tool-lib.c
+++ b/upatch/upatch-tool/upatch-tool-lib.c
@@ -22,7 +22,8 @@ int upatch_check(const char *target_elf, const char *patch_file, char *err_msg,
 {
     struct list_head *patch_syms = patch_symbols_resolve(target_elf, patch_file);
     if (patch_syms == NULL) {
-        return ENOENT;
+        snprintf(err_msg, max_len, "Patch format error");
+        return ENOEXEC;
     }
 
     struct list_head *collision_list = meta_get_symbol_collision(target_elf, patch_syms);
@@ -30,7 +31,7 @@ int upatch_check(const char *target_elf, const char *patch_file, char *err_msg,
         return 0;
     }
 
-    int offset = snprintf(err_msg, max_len, "Upatch: Patch is conflicted with ");
+    int offset = snprintf(err_msg, max_len, "Patch is conflicted with ");
     symbol_collision *collision = NULL;
     list_for_each_entry(collision, collision_list, self) {
         err_msg += offset;
@@ -61,8 +62,8 @@ int upatch_load(const char *uuid, const char *target, const char *patch, bool fo
     // Resolve patch symbols
     struct list_head *patch_syms = patch_symbols_resolve(target, patch);
     if (patch_syms == NULL) {
-        log_warn("{%s}: Patch symbol is empty\n", uuid);
-        return ENOENT;
+        log_warn("{%s}: Patch format error\n", uuid);
+        return ENOEXEC;
     }
 
     // Check patch symbol collision
-- 
2.33.0

