The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=95c20faf11a1af6924f97ec4aafc32d899fea8b0

commit 95c20faf11a1af6924f97ec4aafc32d899fea8b0
Author:     Konstantin Belousov <k...@freebsd.org>
AuthorDate: 2021-11-07 08:37:48 +0000
Commit:     Konstantin Belousov <k...@freebsd.org>
CommitDate: 2021-12-08 21:32:29 +0000

    kernel linker: do not read debug symbol tables for non-debug symbols
    
    In particular, this prevents resolving locals from other files.
    To access debug symbol tables, add LINKER_LOOKUP_DEBUG_SYMBOL and
    LINKER_DEBUG_SYMBOL_VALUES kobj methods, which are allowed to use
    any types of present symbols in all tables.
    
    PR:     207898
    Reviewed by:    emaste, markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D32878
---
 sys/kern/kern_linker.c  |  2 +-
 sys/kern/link_elf.c     | 79 +++++++++++++++++++++++++++++++++++++++----------
 sys/kern/link_elf_obj.c | 61 +++++++++++++++++++++++++++++++-------
 sys/kern/linker_if.m    | 12 ++++++++
 4 files changed, 126 insertions(+), 28 deletions(-)

diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index b34131604fef..2e4c95f16c8f 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -912,7 +912,7 @@ linker_debug_lookup(const char *symstr, c_linker_sym_t *sym)
        linker_file_t lf;
 
        TAILQ_FOREACH(lf, &linker_files, link) {
-               if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0)
+               if (LINKER_LOOKUP_DEBUG_SYMBOL(lf, symstr, sym) == 0)
                        return (0);
        }
        return (ENOENT);
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index 075238b91d95..dc8002be0e89 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -144,8 +144,12 @@ static int link_elf_load_file(linker_class_t, const char *,
                    linker_file_t *);
 static int     link_elf_lookup_symbol(linker_file_t, const char *,
                    c_linker_sym_t *);
+static int     link_elf_lookup_debug_symbol(linker_file_t, const char *,
+                   c_linker_sym_t *);
 static int     link_elf_symbol_values(linker_file_t, c_linker_sym_t,
                    linker_symval_t *);
+static int     link_elf_debug_symbol_values(linker_file_t, c_linker_sym_t,
+                   linker_symval_t*);
 static int     link_elf_search_symbol(linker_file_t, caddr_t,
                    c_linker_sym_t *, long *);
 
@@ -164,7 +168,9 @@ static int  elf_lookup(linker_file_t, Elf_Size, int, 
Elf_Addr *);
 
 static kobj_method_t link_elf_methods[] = {
        KOBJMETHOD(linker_lookup_symbol,        link_elf_lookup_symbol),
+       KOBJMETHOD(linker_lookup_debug_symbol,  link_elf_lookup_debug_symbol),
        KOBJMETHOD(linker_symbol_values,        link_elf_symbol_values),
+       KOBJMETHOD(linker_debug_symbol_values,  link_elf_debug_symbol_values),
        KOBJMETHOD(linker_search_symbol,        link_elf_search_symbol),
        KOBJMETHOD(linker_unload,               link_elf_unload_file),
        KOBJMETHOD(linker_load_file,            link_elf_load_file),
@@ -1490,14 +1496,14 @@ elf_hash(const char *name)
 }
 
 static int
-link_elf_lookup_symbol(linker_file_t lf, const char *name, c_linker_sym_t *sym)
+link_elf_lookup_symbol1(linker_file_t lf, const char *name, c_linker_sym_t 
*sym,
+    bool see_local)
 {
        elf_file_t ef = (elf_file_t) lf;
        unsigned long symnum;
        const Elf_Sym* symp;
        const char *strp;
        unsigned long hash;
-       int i;
 
        /* If we don't have a hash, bail. */
        if (ef->buckets == NULL || ef->nbuckets == 0) {
@@ -1528,8 +1534,11 @@ link_elf_lookup_symbol(linker_file_t lf, const char 
*name, c_linker_sym_t *sym)
                            (symp->st_value != 0 &&
                            (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
                            ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC))) {
-                               *sym = (c_linker_sym_t) symp;
-                               return (0);
+                               if (see_local ||
+                                   ELF_ST_BIND(symp->st_info) != STB_LOCAL) {
+                                       *sym = (c_linker_sym_t) symp;
+                                       return (0);
+                               }
                        }
                        return (ENOENT);
                }
@@ -1537,11 +1546,27 @@ link_elf_lookup_symbol(linker_file_t lf, const char 
*name, c_linker_sym_t *sym)
                symnum = ef->chains[symnum];
        }
 
-       /* If we have not found it, look at the full table (if loaded) */
-       if (ef->symtab == ef->ddbsymtab)
-               return (ENOENT);
+       return (ENOENT);
+}
+
+static int
+link_elf_lookup_symbol(linker_file_t lf, const char *name, c_linker_sym_t *sym)
+{
+       return (link_elf_lookup_symbol1(lf, name, sym, false));
+}
+
+static int
+link_elf_lookup_debug_symbol(linker_file_t lf, const char *name,
+    c_linker_sym_t *sym)
+{
+       elf_file_t ef = (elf_file_t)lf;
+       const Elf_Sym* symp;
+       const char *strp;
+       int i;
+
+       if (link_elf_lookup_symbol1(lf, name, sym, true) == 0)
+               return (0);
 
-       /* Exhaustive search */
        for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
                strp = ef->ddbstrtab + symp->st_name;
                if (strcmp(name, strp) == 0) {
@@ -1560,8 +1585,8 @@ link_elf_lookup_symbol(linker_file_t lf, const char 
*name, c_linker_sym_t *sym)
 }
 
 static int
-link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
-    linker_symval_t *symval)
+link_elf_symbol_values1(linker_file_t lf, c_linker_sym_t sym,
+    linker_symval_t *symval, bool see_local)
 {
        elf_file_t ef;
        const Elf_Sym *es;
@@ -1569,7 +1594,9 @@ link_elf_symbol_values(linker_file_t lf, c_linker_sym_t 
sym,
 
        ef = (elf_file_t)lf;
        es = (const Elf_Sym *)sym;
-       if (es >= ef->symtab && es < (ef->symtab + ef->nchains)) {
+       if (es >= ef->symtab && es < ef->symtab + ef->nchains) {
+               if (!see_local && ELF_ST_BIND(es->st_info) == STB_LOCAL)
+                       return (ENOENT);
                symval->name = ef->strtab + es->st_name;
                val = (caddr_t)ef->address + es->st_value;
                if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
@@ -1578,8 +1605,29 @@ link_elf_symbol_values(linker_file_t lf, c_linker_sym_t 
sym,
                symval->size = es->st_size;
                return (0);
        }
+       return (ENOENT);
+}
+
+static int
+link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
+    linker_symval_t *symval)
+{
+       return (link_elf_symbol_values1(lf, sym, symval, false));
+}
+
+static int
+link_elf_debug_symbol_values(linker_file_t lf, c_linker_sym_t sym,
+    linker_symval_t *symval)
+{
+       elf_file_t ef = (elf_file_t)lf;
+       const Elf_Sym *es = (const Elf_Sym *)sym;
+       caddr_t val;
+
+       if (link_elf_symbol_values1(lf, sym, symval, true) == 0)
+               return (0);
        if (ef->symtab == ef->ddbsymtab)
                return (ENOENT);
+
        if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
                symval->name = ef->ddbstrtab + es->st_name;
                val = (caddr_t)ef->address + es->st_value;
@@ -1597,7 +1645,7 @@ link_elf_search_symbol(linker_file_t lf, caddr_t value,
     c_linker_sym_t *sym, long *diffp)
 {
        elf_file_t ef = (elf_file_t)lf;
-       u_long off = (uintptr_t) (void *)value;
+       u_long off = (uintptr_t)(void *)value;
        u_long diff = off;
        u_long st_value;
        const Elf_Sym *es;
@@ -1719,11 +1767,10 @@ link_elf_each_function_nameval(linker_file_t file,
                if (symp->st_value != 0 &&
                    (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
                    ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
-                       error = link_elf_symbol_values(file,
+                       error = link_elf_debug_symbol_values(file,
                            (c_linker_sym_t) symp, &symval);
-                       if (error != 0)
-                               return (error);
-                       error = callback(file, i, &symval, opaque);
+                       if (error == 0)
+                               error = callback(file, i, &symval, opaque);
                        if (error != 0)
                                return (error);
                }
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index fbefd0f8d7ca..ec2319ffad47 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -131,8 +131,12 @@ static int link_elf_link_preload_finish(linker_file_t);
 static int     link_elf_load_file(linker_class_t, const char *, linker_file_t 
*);
 static int     link_elf_lookup_symbol(linker_file_t, const char *,
                    c_linker_sym_t *);
+static int     link_elf_lookup_debug_symbol(linker_file_t, const char *,
+                   c_linker_sym_t *);
 static int     link_elf_symbol_values(linker_file_t, c_linker_sym_t,
                    linker_symval_t *);
+static int     link_elf_debug_symbol_values(linker_file_t, c_linker_sym_t,
+                   linker_symval_t *);
 static int     link_elf_search_symbol(linker_file_t, caddr_t value,
                    c_linker_sym_t *sym, long *diffp);
 
@@ -153,7 +157,9 @@ static int  elf_obj_lookup(linker_file_t lf, Elf_Size 
symidx, int deps,
 
 static kobj_method_t link_elf_methods[] = {
        KOBJMETHOD(linker_lookup_symbol,        link_elf_lookup_symbol),
+       KOBJMETHOD(linker_lookup_debug_symbol,  link_elf_lookup_debug_symbol),
        KOBJMETHOD(linker_symbol_values,        link_elf_symbol_values),
+       KOBJMETHOD(linker_debug_symbol_values,  link_elf_debug_symbol_values),
        KOBJMETHOD(linker_search_symbol,        link_elf_search_symbol),
        KOBJMETHOD(linker_unload,               link_elf_unload_file),
        KOBJMETHOD(linker_load_file,            link_elf_load_file),
@@ -1424,9 +1430,10 @@ relocate_file(elf_file_t ef)
 }
 
 static int
-link_elf_lookup_symbol(linker_file_t lf, const char *name, c_linker_sym_t *sym)
+link_elf_lookup_symbol1(linker_file_t lf, const char *name, c_linker_sym_t 
*sym,
+    bool see_local)
 {
-       elf_file_t ef = (elf_file_t) lf;
+       elf_file_t ef = (elf_file_t)lf;
        const Elf_Sym *symp;
        const char *strp;
        int i;
@@ -1434,16 +1441,33 @@ link_elf_lookup_symbol(linker_file_t lf, const char 
*name, c_linker_sym_t *sym)
        for (i = 0, symp = ef->ddbsymtab; i < ef->ddbsymcnt; i++, symp++) {
                strp = ef->ddbstrtab + symp->st_name;
                if (symp->st_shndx != SHN_UNDEF && strcmp(name, strp) == 0) {
-                       *sym = (c_linker_sym_t) symp;
-                       return 0;
+                       if (see_local ||
+                           ELF_ST_BIND(symp->st_info) == STB_GLOBAL) {
+                               *sym = (c_linker_sym_t) symp;
+                               return (0);
+                       }
+                       return (ENOENT);
                }
        }
        return (ENOENT);
 }
 
 static int
-link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
-    linker_symval_t *symval)
+link_elf_lookup_symbol(linker_file_t lf, const char *name, c_linker_sym_t *sym)
+{
+       return (link_elf_lookup_symbol1(lf, name, sym, false));
+}
+
+static int
+link_elf_lookup_debug_symbol(linker_file_t lf, const char *name,
+    c_linker_sym_t *sym)
+{
+       return (link_elf_lookup_symbol1(lf, name, sym, true));
+}
+
+static int
+link_elf_symbol_values1(linker_file_t lf, c_linker_sym_t sym,
+    linker_symval_t *symval, bool see_local)
 {
        elf_file_t ef;
        const Elf_Sym *es;
@@ -1453,6 +1477,8 @@ link_elf_symbol_values(linker_file_t lf, c_linker_sym_t 
sym,
        es = (const Elf_Sym*) sym;
        val = (caddr_t)es->st_value;
        if (es >= ef->ddbsymtab && es < (ef->ddbsymtab + ef->ddbsymcnt)) {
+               if (!see_local && ELF_ST_BIND(es->st_info) == STB_LOCAL)
+                       return (ENOENT);
                symval->name = ef->ddbstrtab + es->st_name;
                val = (caddr_t)es->st_value;
                if (ELF_ST_TYPE(es->st_info) == STT_GNU_IFUNC)
@@ -1464,6 +1490,20 @@ link_elf_symbol_values(linker_file_t lf, c_linker_sym_t 
sym,
        return (ENOENT);
 }
 
+static int
+link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym,
+    linker_symval_t *symval)
+{
+       return (link_elf_symbol_values1(lf, sym, symval, false));
+}
+
+static int
+link_elf_debug_symbol_values(linker_file_t lf, c_linker_sym_t sym,
+    linker_symval_t *symval)
+{
+       return (link_elf_symbol_values1(lf, sym, symval, true));
+}
+
 static int
 link_elf_search_symbol(linker_file_t lf, caddr_t value,
     c_linker_sym_t *sym, long *diffp)
@@ -1566,12 +1606,11 @@ link_elf_each_function_nameval(linker_file_t file,
                if (symp->st_value != 0 &&
                    (ELF_ST_TYPE(symp->st_info) == STT_FUNC ||
                    ELF_ST_TYPE(symp->st_info) == STT_GNU_IFUNC)) {
-                       error = link_elf_symbol_values(file,
+                       error = link_elf_debug_symbol_values(file,
                            (c_linker_sym_t)symp, &symval);
-                       if (error)
-                               return (error);
-                       error = callback(file, i, &symval, opaque);
-                       if (error)
+                       if (error == 0)
+                               error = callback(file, i, &symval, opaque);
+                       if (error != 0)
                                return (error);
                }
        }
diff --git a/sys/kern/linker_if.m b/sys/kern/linker_if.m
index a583a0369ebc..524f786ccac8 100644
--- a/sys/kern/linker_if.m
+++ b/sys/kern/linker_if.m
@@ -40,12 +40,24 @@ METHOD int lookup_symbol {
     c_linker_sym_t*    symp;
 };
 
+METHOD int lookup_debug_symbol {
+    linker_file_t      file;
+    const char*                name;
+    c_linker_sym_t*    symp;
+};
+
 METHOD int symbol_values {
     linker_file_t      file;
     c_linker_sym_t     sym;
     linker_symval_t*   valp;
 };
 
+METHOD int debug_symbol_values {
+    linker_file_t      file;
+    c_linker_sym_t     sym;
+    linker_symval_t*   valp;
+};
+
 METHOD int search_symbol {
     linker_file_t      file;
     caddr_t            value;

Reply via email to