LCOV - code coverage report
Current view: top level - kernel - kallsyms.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 94 248 37.9 %
Date: 2021-04-22 12:43:58 Functions: 8 25 32.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  * kallsyms.c: in-kernel printing of symbolic oopses and stack traces.
       4             :  *
       5             :  * Rewritten and vastly simplified by Rusty Russell for in-kernel
       6             :  * module loader:
       7             :  *   Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
       8             :  *
       9             :  * ChangeLog:
      10             :  *
      11             :  * (25/Aug/2004) Paulo Marques <pmarques@grupopie.com>
      12             :  *      Changed the compression method from stem compression to "table lookup"
      13             :  *      compression (see scripts/kallsyms.c for a more complete description)
      14             :  */
      15             : #include <linux/kallsyms.h>
      16             : #include <linux/init.h>
      17             : #include <linux/seq_file.h>
      18             : #include <linux/fs.h>
      19             : #include <linux/kdb.h>
      20             : #include <linux/err.h>
      21             : #include <linux/proc_fs.h>
      22             : #include <linux/sched.h>  /* for cond_resched */
      23             : #include <linux/ctype.h>
      24             : #include <linux/slab.h>
      25             : #include <linux/filter.h>
      26             : #include <linux/ftrace.h>
      27             : #include <linux/kprobes.h>
      28             : #include <linux/compiler.h>
      29             : 
      30             : /*
      31             :  * These will be re-linked against their real values
      32             :  * during the second link stage.
      33             :  */
      34             : extern const unsigned long kallsyms_addresses[] __weak;
      35             : extern const int kallsyms_offsets[] __weak;
      36             : extern const u8 kallsyms_names[] __weak;
      37             : 
      38             : /*
      39             :  * Tell the compiler that the count isn't in the small data section if the arch
      40             :  * has one (eg: FRV).
      41             :  */
      42             : extern const unsigned int kallsyms_num_syms
      43             : __section(".rodata") __attribute__((weak));
      44             : 
      45             : extern const unsigned long kallsyms_relative_base
      46             : __section(".rodata") __attribute__((weak));
      47             : 
      48             : extern const char kallsyms_token_table[] __weak;
      49             : extern const u16 kallsyms_token_index[] __weak;
      50             : 
      51             : extern const unsigned int kallsyms_markers[] __weak;
      52             : 
      53             : /*
      54             :  * Expand a compressed symbol data into the resulting uncompressed string,
      55             :  * if uncompressed string is too long (>= maxlen), it will be truncated,
      56             :  * given the offset to where the symbol is in the compressed stream.
      57             :  */
      58          80 : static unsigned int kallsyms_expand_symbol(unsigned int off,
      59             :                                            char *result, size_t maxlen)
      60             : {
      61          80 :         int len, skipped_first = 0;
      62          80 :         const char *tptr;
      63          80 :         const u8 *data;
      64             : 
      65             :         /* Get the compressed symbol length from the first symbol byte. */
      66          80 :         data = &kallsyms_names[off];
      67          80 :         len = *data;
      68          80 :         data++;
      69             : 
      70             :         /*
      71             :          * Update the offset to return the offset for the next symbol on
      72             :          * the compressed stream.
      73             :          */
      74          80 :         off += len + 1;
      75             : 
      76             :         /*
      77             :          * For every byte on the compressed symbol data, copy the table
      78             :          * entry for that byte.
      79             :          */
      80         874 :         while (len) {
      81         794 :                 tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
      82         794 :                 data++;
      83         794 :                 len--;
      84             : 
      85        2202 :                 while (*tptr) {
      86        1408 :                         if (skipped_first) {
      87        1328 :                                 if (maxlen <= 1)
      88           0 :                                         goto tail;
      89        1328 :                                 *result = *tptr;
      90        1328 :                                 result++;
      91        1328 :                                 maxlen--;
      92             :                         } else
      93             :                                 skipped_first = 1;
      94        1408 :                         tptr++;
      95             :                 }
      96             :         }
      97             : 
      98          80 : tail:
      99          80 :         if (maxlen)
     100          80 :                 *result = '\0';
     101             : 
     102             :         /* Return to offset to the next symbol. */
     103          80 :         return off;
     104             : }
     105             : 
     106             : /*
     107             :  * Get symbol type information. This is encoded as a single char at the
     108             :  * beginning of the symbol name.
     109             :  */
     110           0 : static char kallsyms_get_symbol_type(unsigned int off)
     111             : {
     112             :         /*
     113             :          * Get just the first code, look it up in the token table,
     114             :          * and return the first char from this token.
     115             :          */
     116           0 :         return kallsyms_token_table[kallsyms_token_index[kallsyms_names[off + 1]]];
     117             : }
     118             : 
     119             : 
     120             : /*
     121             :  * Find the offset on the compressed stream given and index in the
     122             :  * kallsyms array.
     123             :  */
     124          80 : static unsigned int get_symbol_offset(unsigned long pos)
     125             : {
     126          80 :         const u8 *name;
     127          80 :         int i;
     128             : 
     129             :         /*
     130             :          * Use the closest marker we have. We have markers every 256 positions,
     131             :          * so that should be close enough.
     132             :          */
     133          80 :         name = &kallsyms_names[kallsyms_markers[pos >> 8]];
     134             : 
     135             :         /*
     136             :          * Sequentially scan all the symbols up to the point we're searching
     137             :          * for. Every symbol is stored in a [<len>][<len> bytes of data] format,
     138             :          * so we just need to add the len to the current pointer for every
     139             :          * symbol we wish to skip.
     140             :          */
     141       12208 :         for (i = 0; i < (pos & 0xFF); i++)
     142       12128 :                 name = name + (*name) + 1;
     143             : 
     144          80 :         return name - kallsyms_names;
     145             : }
     146             : 
     147        1756 : static unsigned long kallsyms_sym_address(int idx)
     148             : {
     149        1756 :         if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
     150             :                 return kallsyms_addresses[idx];
     151             : 
     152             :         /* values are unsigned offsets if --absolute-percpu is not in effect */
     153        1756 :         if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
     154             :                 return kallsyms_relative_base + (u32)kallsyms_offsets[idx];
     155             : 
     156             :         /* ...otherwise, positive offsets are absolute values */
     157        1756 :         if (kallsyms_offsets[idx] >= 0)
     158           0 :                 return kallsyms_offsets[idx];
     159             : 
     160             :         /* ...and negative offsets are relative to kallsyms_relative_base - 1 */
     161        1676 :         return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
     162             : }
     163             : 
     164             : /* Lookup the address for this symbol. Returns 0 if not found. */
     165           0 : unsigned long kallsyms_lookup_name(const char *name)
     166             : {
     167           0 :         char namebuf[KSYM_NAME_LEN];
     168           0 :         unsigned long i;
     169           0 :         unsigned int off;
     170             : 
     171           0 :         for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
     172           0 :                 off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
     173             : 
     174           0 :                 if (strcmp(namebuf, name) == 0)
     175           0 :                         return kallsyms_sym_address(i);
     176             :         }
     177           0 :         return module_kallsyms_lookup_name(name);
     178             : }
     179             : 
     180             : #ifdef CONFIG_LIVEPATCH
     181             : /*
     182             :  * Iterate over all symbols in vmlinux.  For symbols from modules use
     183             :  * module_kallsyms_on_each_symbol instead.
     184             :  */
     185             : int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
     186             :                                       unsigned long),
     187             :                             void *data)
     188             : {
     189             :         char namebuf[KSYM_NAME_LEN];
     190             :         unsigned long i;
     191             :         unsigned int off;
     192             :         int ret;
     193             : 
     194             :         for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
     195             :                 off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));
     196             :                 ret = fn(data, namebuf, NULL, kallsyms_sym_address(i));
     197             :                 if (ret != 0)
     198             :                         return ret;
     199             :         }
     200             :         return 0;
     201             : }
     202             : #endif /* CONFIG_LIVEPATCH */
     203             : 
     204          80 : static unsigned long get_symbol_pos(unsigned long addr,
     205             :                                     unsigned long *symbolsize,
     206             :                                     unsigned long *offset)
     207             : {
     208          80 :         unsigned long symbol_start = 0, symbol_end = 0;
     209          80 :         unsigned long i, low, high, mid;
     210             : 
     211             :         /* This kernel should never had been booted. */
     212          80 :         if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
     213             :                 BUG_ON(!kallsyms_addresses);
     214             :         else
     215          80 :                 BUG_ON(!kallsyms_offsets);
     216             : 
     217             :         /* Do a binary search on the sorted kallsyms_addresses array. */
     218          80 :         low = 0;
     219          80 :         high = kallsyms_num_syms;
     220             : 
     221        1510 :         while (high - low > 1) {
     222        1350 :                 mid = low + (high - low) / 2;
     223        2700 :                 if (kallsyms_sym_address(mid) <= addr)
     224             :                         low = mid;
     225             :                 else
     226         856 :                         high = mid;
     227             :         }
     228             : 
     229             :         /*
     230             :          * Search for the first aliased symbol. Aliased
     231             :          * symbols are symbols with the same address.
     232             :          */
     233         246 :         while (low && kallsyms_sym_address(low-1) == kallsyms_sym_address(low))
     234           2 :                 --low;
     235             : 
     236          80 :         symbol_start = kallsyms_sym_address(low);
     237             : 
     238             :         /* Search for next non-aliased symbol. */
     239          82 :         for (i = low + 1; i < kallsyms_num_syms; i++) {
     240         164 :                 if (kallsyms_sym_address(i) > symbol_start) {
     241          80 :                         symbol_end = kallsyms_sym_address(i);
     242             :                         break;
     243             :                 }
     244             :         }
     245             : 
     246             :         /* If we found no next symbol, we use the end of the section. */
     247          80 :         if (!symbol_end) {
     248           0 :                 if (is_kernel_inittext(addr))
     249             :                         symbol_end = (unsigned long)_einittext;
     250           0 :                 else if (IS_ENABLED(CONFIG_KALLSYMS_ALL))
     251           0 :                         symbol_end = (unsigned long)_end;
     252             :                 else
     253             :                         symbol_end = (unsigned long)_etext;
     254             :         }
     255             : 
     256          80 :         if (symbolsize)
     257          80 :                 *symbolsize = symbol_end - symbol_start;
     258          80 :         if (offset)
     259          80 :                 *offset = addr - symbol_start;
     260             : 
     261          80 :         return low;
     262             : }
     263             : 
     264             : /*
     265             :  * Lookup an address but don't bother to find any names.
     266             :  */
     267           0 : int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
     268             :                                 unsigned long *offset)
     269             : {
     270           0 :         char namebuf[KSYM_NAME_LEN];
     271             : 
     272           0 :         if (is_ksym_addr(addr)) {
     273           0 :                 get_symbol_pos(addr, symbolsize, offset);
     274           0 :                 return 1;
     275             :         }
     276           0 :         return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf) ||
     277           0 :                !!__bpf_address_lookup(addr, symbolsize, offset, namebuf);
     278             : }
     279             : 
     280             : /*
     281             :  * Lookup an address
     282             :  * - modname is set to NULL if it's in the kernel.
     283             :  * - We guarantee that the returned name is valid until we reschedule even if.
     284             :  *   It resides in a module.
     285             :  * - We also guarantee that modname will be valid until rescheduled.
     286             :  */
     287          82 : const char *kallsyms_lookup(unsigned long addr,
     288             :                             unsigned long *symbolsize,
     289             :                             unsigned long *offset,
     290             :                             char **modname, char *namebuf)
     291             : {
     292          82 :         const char *ret;
     293             : 
     294          82 :         namebuf[KSYM_NAME_LEN - 1] = 0;
     295          82 :         namebuf[0] = 0;
     296             : 
     297          82 :         if (is_ksym_addr(addr)) {
     298          80 :                 unsigned long pos;
     299             : 
     300          80 :                 pos = get_symbol_pos(addr, symbolsize, offset);
     301             :                 /* Grab name */
     302          80 :                 kallsyms_expand_symbol(get_symbol_offset(pos),
     303             :                                        namebuf, KSYM_NAME_LEN);
     304          80 :                 if (modname)
     305          80 :                         *modname = NULL;
     306          80 :                 return namebuf;
     307             :         }
     308             : 
     309             :         /* See if it's in a module or a BPF JITed image. */
     310          82 :         ret = module_address_lookup(addr, symbolsize, offset,
     311             :                                     modname, namebuf);
     312             :         if (!ret)
     313          82 :                 ret = bpf_address_lookup(addr, symbolsize,
     314             :                                          offset, modname, namebuf);
     315             : 
     316             :         if (!ret)
     317          82 :                 ret = ftrace_mod_address_lookup(addr, symbolsize,
     318             :                                                 offset, modname, namebuf);
     319             :         return ret;
     320             : }
     321             : 
     322           0 : int lookup_symbol_name(unsigned long addr, char *symname)
     323             : {
     324           0 :         symname[0] = '\0';
     325           0 :         symname[KSYM_NAME_LEN - 1] = '\0';
     326             : 
     327           0 :         if (is_ksym_addr(addr)) {
     328           0 :                 unsigned long pos;
     329             : 
     330           0 :                 pos = get_symbol_pos(addr, NULL, NULL);
     331             :                 /* Grab name */
     332           0 :                 kallsyms_expand_symbol(get_symbol_offset(pos),
     333             :                                        symname, KSYM_NAME_LEN);
     334           0 :                 return 0;
     335             :         }
     336             :         /* See if it's in a module. */
     337           0 :         return lookup_module_symbol_name(addr, symname);
     338             : }
     339             : 
     340           0 : int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
     341             :                         unsigned long *offset, char *modname, char *name)
     342             : {
     343           0 :         name[0] = '\0';
     344           0 :         name[KSYM_NAME_LEN - 1] = '\0';
     345             : 
     346           0 :         if (is_ksym_addr(addr)) {
     347           0 :                 unsigned long pos;
     348             : 
     349           0 :                 pos = get_symbol_pos(addr, size, offset);
     350             :                 /* Grab name */
     351           0 :                 kallsyms_expand_symbol(get_symbol_offset(pos),
     352             :                                        name, KSYM_NAME_LEN);
     353           0 :                 modname[0] = '\0';
     354           0 :                 return 0;
     355             :         }
     356             :         /* See if it's in a module. */
     357           0 :         return lookup_module_symbol_attrs(addr, size, offset, modname, name);
     358             : }
     359             : 
     360             : /* Look up a kernel symbol and return it in a text buffer. */
     361          82 : static int __sprint_symbol(char *buffer, unsigned long address,
     362             :                            int symbol_offset, int add_offset)
     363             : {
     364          82 :         char *modname;
     365          82 :         const char *name;
     366          82 :         unsigned long offset, size;
     367          82 :         int len;
     368             : 
     369          82 :         address += symbol_offset;
     370          82 :         name = kallsyms_lookup(address, &size, &offset, &modname, buffer);
     371          82 :         if (!name)
     372           2 :                 return sprintf(buffer, "0x%lx", address - symbol_offset);
     373             : 
     374          80 :         if (name != buffer)
     375           0 :                 strcpy(buffer, name);
     376          80 :         len = strlen(buffer);
     377          80 :         offset -= symbol_offset;
     378             : 
     379          80 :         if (add_offset)
     380          80 :                 len += sprintf(buffer + len, "+%#lx/%#lx", offset, size);
     381             : 
     382          80 :         if (modname)
     383           0 :                 len += sprintf(buffer + len, " [%s]", modname);
     384             : 
     385             :         return len;
     386             : }
     387             : 
     388             : /**
     389             :  * sprint_symbol - Look up a kernel symbol and return it in a text buffer
     390             :  * @buffer: buffer to be stored
     391             :  * @address: address to lookup
     392             :  *
     393             :  * This function looks up a kernel symbol with @address and stores its name,
     394             :  * offset, size and module name to @buffer if possible. If no symbol was found,
     395             :  * just saves its @address as is.
     396             :  *
     397             :  * This function returns the number of bytes stored in @buffer.
     398             :  */
     399          14 : int sprint_symbol(char *buffer, unsigned long address)
     400             : {
     401          14 :         return __sprint_symbol(buffer, address, 0, 1);
     402             : }
     403             : EXPORT_SYMBOL_GPL(sprint_symbol);
     404             : 
     405             : /**
     406             :  * sprint_symbol_no_offset - Look up a kernel symbol and return it in a text buffer
     407             :  * @buffer: buffer to be stored
     408             :  * @address: address to lookup
     409             :  *
     410             :  * This function looks up a kernel symbol with @address and stores its name
     411             :  * and module name to @buffer if possible. If no symbol was found, just saves
     412             :  * its @address as is.
     413             :  *
     414             :  * This function returns the number of bytes stored in @buffer.
     415             :  */
     416           0 : int sprint_symbol_no_offset(char *buffer, unsigned long address)
     417             : {
     418           0 :         return __sprint_symbol(buffer, address, 0, 0);
     419             : }
     420             : EXPORT_SYMBOL_GPL(sprint_symbol_no_offset);
     421             : 
     422             : /**
     423             :  * sprint_backtrace - Look up a backtrace symbol and return it in a text buffer
     424             :  * @buffer: buffer to be stored
     425             :  * @address: address to lookup
     426             :  *
     427             :  * This function is for stack backtrace and does the same thing as
     428             :  * sprint_symbol() but with modified/decreased @address. If there is a
     429             :  * tail-call to the function marked "noreturn", gcc optimized out code after
     430             :  * the call so that the stack-saved return address could point outside of the
     431             :  * caller. This function ensures that kallsyms will find the original caller
     432             :  * by decreasing @address.
     433             :  *
     434             :  * This function returns the number of bytes stored in @buffer.
     435             :  */
     436          68 : int sprint_backtrace(char *buffer, unsigned long address)
     437             : {
     438          68 :         return __sprint_symbol(buffer, address, -1, 1);
     439             : }
     440             : 
     441             : /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
     442             : struct kallsym_iter {
     443             :         loff_t pos;
     444             :         loff_t pos_arch_end;
     445             :         loff_t pos_mod_end;
     446             :         loff_t pos_ftrace_mod_end;
     447             :         loff_t pos_bpf_end;
     448             :         unsigned long value;
     449             :         unsigned int nameoff; /* If iterating in core kernel symbols. */
     450             :         char type;
     451             :         char name[KSYM_NAME_LEN];
     452             :         char module_name[MODULE_NAME_LEN];
     453             :         int exported;
     454             :         int show_value;
     455             : };
     456             : 
     457           0 : int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value,
     458             :                             char *type, char *name)
     459             : {
     460           0 :         return -EINVAL;
     461             : }
     462             : 
     463           0 : static int get_ksymbol_arch(struct kallsym_iter *iter)
     464             : {
     465           0 :         int ret = arch_get_kallsym(iter->pos - kallsyms_num_syms,
     466             :                                    &iter->value, &iter->type,
     467           0 :                                    iter->name);
     468             : 
     469           0 :         if (ret < 0) {
     470           0 :                 iter->pos_arch_end = iter->pos;
     471           0 :                 return 0;
     472             :         }
     473             : 
     474             :         return 1;
     475             : }
     476             : 
     477           0 : static int get_ksymbol_mod(struct kallsym_iter *iter)
     478             : {
     479           0 :         int ret = module_get_kallsym(iter->pos - iter->pos_arch_end,
     480             :                                      &iter->value, &iter->type,
     481           0 :                                      iter->name, iter->module_name,
     482             :                                      &iter->exported);
     483           0 :         if (ret < 0) {
     484           0 :                 iter->pos_mod_end = iter->pos;
     485           0 :                 return 0;
     486             :         }
     487             : 
     488             :         return 1;
     489             : }
     490             : 
     491             : /*
     492             :  * ftrace_mod_get_kallsym() may also get symbols for pages allocated for ftrace
     493             :  * purposes. In that case "__builtin__ftrace" is used as a module name, even
     494             :  * though "__builtin__ftrace" is not a module.
     495             :  */
     496           0 : static int get_ksymbol_ftrace_mod(struct kallsym_iter *iter)
     497             : {
     498           0 :         int ret = ftrace_mod_get_kallsym(iter->pos - iter->pos_mod_end,
     499             :                                          &iter->value, &iter->type,
     500           0 :                                          iter->name, iter->module_name,
     501             :                                          &iter->exported);
     502           0 :         if (ret < 0) {
     503           0 :                 iter->pos_ftrace_mod_end = iter->pos;
     504           0 :                 return 0;
     505             :         }
     506             : 
     507             :         return 1;
     508             : }
     509             : 
     510           0 : static int get_ksymbol_bpf(struct kallsym_iter *iter)
     511             : {
     512           0 :         int ret;
     513             : 
     514           0 :         strlcpy(iter->module_name, "bpf", MODULE_NAME_LEN);
     515           0 :         iter->exported = 0;
     516           0 :         ret = bpf_get_kallsym(iter->pos - iter->pos_ftrace_mod_end,
     517             :                               &iter->value, &iter->type,
     518           0 :                               iter->name);
     519           0 :         if (ret < 0) {
     520           0 :                 iter->pos_bpf_end = iter->pos;
     521           0 :                 return 0;
     522             :         }
     523             : 
     524             :         return 1;
     525             : }
     526             : 
     527             : /*
     528             :  * This uses "__builtin__kprobes" as a module name for symbols for pages
     529             :  * allocated for kprobes' purposes, even though "__builtin__kprobes" is not a
     530             :  * module.
     531             :  */
     532           0 : static int get_ksymbol_kprobe(struct kallsym_iter *iter)
     533             : {
     534           0 :         strlcpy(iter->module_name, "__builtin__kprobes", MODULE_NAME_LEN);
     535           0 :         iter->exported = 0;
     536           0 :         return kprobe_get_kallsym(iter->pos - iter->pos_bpf_end,
     537             :                                   &iter->value, &iter->type,
     538           0 :                                   iter->name) < 0 ? 0 : 1;
     539             : }
     540             : 
     541             : /* Returns space to next name. */
     542           0 : static unsigned long get_ksymbol_core(struct kallsym_iter *iter)
     543             : {
     544           0 :         unsigned off = iter->nameoff;
     545             : 
     546           0 :         iter->module_name[0] = '\0';
     547           0 :         iter->value = kallsyms_sym_address(iter->pos);
     548             : 
     549           0 :         iter->type = kallsyms_get_symbol_type(off);
     550             : 
     551           0 :         off = kallsyms_expand_symbol(off, iter->name, ARRAY_SIZE(iter->name));
     552             : 
     553           0 :         return off - iter->nameoff;
     554             : }
     555             : 
     556           0 : static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
     557             : {
     558           0 :         iter->name[0] = '\0';
     559           0 :         iter->nameoff = get_symbol_offset(new_pos);
     560           0 :         iter->pos = new_pos;
     561           0 :         if (new_pos == 0) {
     562           0 :                 iter->pos_arch_end = 0;
     563           0 :                 iter->pos_mod_end = 0;
     564           0 :                 iter->pos_ftrace_mod_end = 0;
     565           0 :                 iter->pos_bpf_end = 0;
     566             :         }
     567           0 : }
     568             : 
     569             : /*
     570             :  * The end position (last + 1) of each additional kallsyms section is recorded
     571             :  * in iter->pos_..._end as each section is added, and so can be used to
     572             :  * determine which get_ksymbol_...() function to call next.
     573             :  */
     574           0 : static int update_iter_mod(struct kallsym_iter *iter, loff_t pos)
     575             : {
     576           0 :         iter->pos = pos;
     577             : 
     578           0 :         if ((!iter->pos_arch_end || iter->pos_arch_end > pos) &&
     579           0 :             get_ksymbol_arch(iter))
     580             :                 return 1;
     581             : 
     582           0 :         if ((!iter->pos_mod_end || iter->pos_mod_end > pos) &&
     583           0 :             get_ksymbol_mod(iter))
     584             :                 return 1;
     585             : 
     586           0 :         if ((!iter->pos_ftrace_mod_end || iter->pos_ftrace_mod_end > pos) &&
     587           0 :             get_ksymbol_ftrace_mod(iter))
     588             :                 return 1;
     589             : 
     590           0 :         if ((!iter->pos_bpf_end || iter->pos_bpf_end > pos) &&
     591           0 :             get_ksymbol_bpf(iter))
     592             :                 return 1;
     593             : 
     594           0 :         return get_ksymbol_kprobe(iter);
     595             : }
     596             : 
     597             : /* Returns false if pos at or past end of file. */
     598           0 : static int update_iter(struct kallsym_iter *iter, loff_t pos)
     599             : {
     600             :         /* Module symbols can be accessed randomly. */
     601           0 :         if (pos >= kallsyms_num_syms)
     602           0 :                 return update_iter_mod(iter, pos);
     603             : 
     604             :         /* If we're not on the desired position, reset to new position. */
     605           0 :         if (pos != iter->pos)
     606           0 :                 reset_iter(iter, pos);
     607             : 
     608           0 :         iter->nameoff += get_ksymbol_core(iter);
     609           0 :         iter->pos++;
     610             : 
     611           0 :         return 1;
     612             : }
     613             : 
     614           0 : static void *s_next(struct seq_file *m, void *p, loff_t *pos)
     615             : {
     616           0 :         (*pos)++;
     617             : 
     618           0 :         if (!update_iter(m->private, *pos))
     619           0 :                 return NULL;
     620             :         return p;
     621             : }
     622             : 
     623           0 : static void *s_start(struct seq_file *m, loff_t *pos)
     624             : {
     625           0 :         if (!update_iter(m->private, *pos))
     626             :                 return NULL;
     627           0 :         return m->private;
     628             : }
     629             : 
     630           0 : static void s_stop(struct seq_file *m, void *p)
     631             : {
     632           0 : }
     633             : 
     634           0 : static int s_show(struct seq_file *m, void *p)
     635             : {
     636           0 :         void *value;
     637           0 :         struct kallsym_iter *iter = m->private;
     638             : 
     639             :         /* Some debugging symbols have no name.  Ignore them. */
     640           0 :         if (!iter->name[0])
     641             :                 return 0;
     642             : 
     643           0 :         value = iter->show_value ? (void *)iter->value : NULL;
     644             : 
     645           0 :         if (iter->module_name[0]) {
     646           0 :                 char type;
     647             : 
     648             :                 /*
     649             :                  * Label it "global" if it is exported,
     650             :                  * "local" if not exported.
     651             :                  */
     652           0 :                 type = iter->exported ? toupper(iter->type) :
     653           0 :                                         tolower(iter->type);
     654           0 :                 seq_printf(m, "%px %c %s\t[%s]\n", value,
     655           0 :                            type, iter->name, iter->module_name);
     656             :         } else
     657           0 :                 seq_printf(m, "%px %c %s\n", value,
     658           0 :                            iter->type, iter->name);
     659             :         return 0;
     660             : }
     661             : 
     662             : static const struct seq_operations kallsyms_op = {
     663             :         .start = s_start,
     664             :         .next = s_next,
     665             :         .stop = s_stop,
     666             :         .show = s_show
     667             : };
     668             : 
     669           0 : static inline int kallsyms_for_perf(void)
     670             : {
     671             : #ifdef CONFIG_PERF_EVENTS
     672           0 :         extern int sysctl_perf_event_paranoid;
     673           0 :         if (sysctl_perf_event_paranoid <= 1)
     674             :                 return 1;
     675             : #endif
     676             :         return 0;
     677             : }
     678             : 
     679             : /*
     680             :  * We show kallsyms information even to normal users if we've enabled
     681             :  * kernel profiling and are explicitly not paranoid (so kptr_restrict
     682             :  * is clear, and sysctl_perf_event_paranoid isn't set).
     683             :  *
     684             :  * Otherwise, require CAP_SYSLOG (assuming kptr_restrict isn't set to
     685             :  * block even that).
     686             :  */
     687           0 : bool kallsyms_show_value(const struct cred *cred)
     688             : {
     689           0 :         switch (kptr_restrict) {
     690             :         case 0:
     691           0 :                 if (kallsyms_for_perf())
     692             :                         return true;
     693           0 :                 fallthrough;
     694             :         case 1:
     695           0 :                 if (security_capable(cred, &init_user_ns, CAP_SYSLOG,
     696             :                                      CAP_OPT_NOAUDIT) == 0)
     697           0 :                         return true;
     698             :                 fallthrough;
     699             :         default:
     700             :                 return false;
     701             :         }
     702             : }
     703             : 
     704           0 : static int kallsyms_open(struct inode *inode, struct file *file)
     705             : {
     706             :         /*
     707             :          * We keep iterator in m->private, since normal case is to
     708             :          * s_start from where we left off, so we avoid doing
     709             :          * using get_symbol_offset for every symbol.
     710             :          */
     711           0 :         struct kallsym_iter *iter;
     712           0 :         iter = __seq_open_private(file, &kallsyms_op, sizeof(*iter));
     713           0 :         if (!iter)
     714             :                 return -ENOMEM;
     715           0 :         reset_iter(iter, 0);
     716             : 
     717             :         /*
     718             :          * Instead of checking this on every s_show() call, cache
     719             :          * the result here at open time.
     720             :          */
     721           0 :         iter->show_value = kallsyms_show_value(file->f_cred);
     722           0 :         return 0;
     723             : }
     724             : 
     725             : #ifdef  CONFIG_KGDB_KDB
     726             : const char *kdb_walk_kallsyms(loff_t *pos)
     727             : {
     728             :         static struct kallsym_iter kdb_walk_kallsyms_iter;
     729             :         if (*pos == 0) {
     730             :                 memset(&kdb_walk_kallsyms_iter, 0,
     731             :                        sizeof(kdb_walk_kallsyms_iter));
     732             :                 reset_iter(&kdb_walk_kallsyms_iter, 0);
     733             :         }
     734             :         while (1) {
     735             :                 if (!update_iter(&kdb_walk_kallsyms_iter, *pos))
     736             :                         return NULL;
     737             :                 ++*pos;
     738             :                 /* Some debugging symbols have no name.  Ignore them. */
     739             :                 if (kdb_walk_kallsyms_iter.name[0])
     740             :                         return kdb_walk_kallsyms_iter.name;
     741             :         }
     742             : }
     743             : #endif  /* CONFIG_KGDB_KDB */
     744             : 
     745             : static const struct proc_ops kallsyms_proc_ops = {
     746             :         .proc_open      = kallsyms_open,
     747             :         .proc_read      = seq_read,
     748             :         .proc_lseek     = seq_lseek,
     749             :         .proc_release   = seq_release_private,
     750             : };
     751             : 
     752           1 : static int __init kallsyms_init(void)
     753             : {
     754           1 :         proc_create("kallsyms", 0444, NULL, &kallsyms_proc_ops);
     755           1 :         return 0;
     756             : }
     757             : device_initcall(kallsyms_init);

Generated by: LCOV version 1.14