Coverage Report

Created: 2026-01-17 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/elfutils/libelf/elf_strptr.c
Line
Count
Source
1
/* Return string pointer from string section.
2
   Copyright (C) 1998-2002, 2004, 2008, 2009, 2015 Red Hat, Inc.
3
   Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
4
   This file is part of elfutils.
5
   Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
6
7
   This file is free software; you can redistribute it and/or modify
8
   it under the terms of either
9
10
     * the GNU Lesser General Public License as published by the Free
11
       Software Foundation; either version 3 of the License, or (at
12
       your option) any later version
13
14
   or
15
16
     * the GNU General Public License as published by the Free
17
       Software Foundation; either version 2 of the License, or (at
18
       your option) any later version
19
20
   or both in parallel, as here.
21
22
   elfutils is distributed in the hope that it will be useful, but
23
   WITHOUT ANY WARRANTY; without even the implied warranty of
24
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25
   General Public License for more details.
26
27
   You should have received copies of the GNU General Public License and
28
   the GNU Lesser General Public License along with this program.  If
29
   not, see <http://www.gnu.org/licenses/>.  */
30
31
#ifdef HAVE_CONFIG_H
32
# include <config.h>
33
#endif
34
35
#include <libelf.h>
36
#include <stdbool.h>
37
#include <stddef.h>
38
39
#include "libelfP.h"
40
41
42
static void *
43
get_zdata (Elf_Scn *strscn)
44
392k
{
45
392k
  size_t zsize, zalign;
46
392k
  void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign);
47
392k
  if (zdata == NULL)
48
392k
    return NULL;
49
50
697
  strscn->zdata_base = zdata;
51
697
  strscn->zdata_size = zsize;
52
697
  strscn->zdata_align = zalign;
53
54
697
  return zdata;
55
392k
}
56
57
char *
58
elf_strptr (Elf *elf, size_t idx, size_t offset)
59
2.86M
{
60
2.86M
  if (elf == NULL)
61
0
    return NULL;
62
63
2.86M
  if (elf->kind != ELF_K_ELF)
64
0
    {
65
0
      __libelf_seterrno (ELF_E_INVALID_HANDLE);
66
0
      return NULL;
67
0
    }
68
69
2.86M
  rwlock_rdlock (elf->lock);
70
71
2.86M
  char *result = NULL;
72
2.86M
  Elf_Scn *strscn;
73
74
  /* Find the section in the list.  */
75
2.86M
  Elf_ScnList *runp = (elf->class == ELFCLASS32
76
449k
           || (offsetof (struct Elf, state.elf32.scns)
77
449k
         == offsetof (struct Elf, state.elf64.scns))
78
2.86M
           ? &elf->state.elf32.scns : &elf->state.elf64.scns);
79
2.86M
  while (1)
80
2.86M
    {
81
2.86M
      if (idx < runp->max)
82
2.15M
  {
83
2.15M
    if (idx < runp->cnt)
84
2.15M
      strscn = &runp->data[idx];
85
0
    else
86
0
      {
87
0
        __libelf_seterrno (ELF_E_INVALID_INDEX);
88
0
        goto out;
89
0
      }
90
2.15M
    break;
91
2.15M
  }
92
93
704k
      idx -= runp->max;
94
95
704k
      runp = runp->next;
96
704k
      if (runp == NULL)
97
704k
  {
98
704k
    __libelf_seterrno (ELF_E_INVALID_INDEX);
99
704k
    goto out;
100
704k
  }
101
704k
    }
102
103
2.15M
  size_t sh_size = 0;
104
2.15M
  if (elf->class == ELFCLASS32)
105
1.77M
    {
106
1.77M
      Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn);
107
1.77M
      if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
108
709k
  {
109
    /* This is no string section.  */
110
709k
    __libelf_seterrno (ELF_E_INVALID_SECTION);
111
709k
    goto out;
112
709k
  }
113
114
1.06M
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
115
626k
  sh_size = shdr->sh_size;
116
442k
      else
117
442k
  {
118
442k
    if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
119
297k
      goto out;
120
145k
    sh_size = strscn->zdata_size;
121
145k
  }
122
123
771k
      if (unlikely (offset >= sh_size))
124
541k
  {
125
    /* The given offset is too big, it is beyond this section.  */
126
541k
    __libelf_seterrno (ELF_E_OFFSET_RANGE);
127
541k
    goto out;
128
541k
  }
129
771k
    }
130
378k
  else
131
378k
    {
132
378k
      Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn);
133
378k
      if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
134
154k
  {
135
    /* This is no string section.  */
136
154k
    __libelf_seterrno (ELF_E_INVALID_SECTION);
137
154k
    goto out;
138
154k
  }
139
140
223k
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
141
50.2k
  sh_size = shdr->sh_size;
142
173k
      else
143
173k
  {
144
173k
    if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
145
94.7k
      goto out;
146
78.5k
    sh_size = strscn->zdata_size;
147
78.5k
  }
148
149
128k
      if (unlikely (offset >= sh_size))
150
104k
  {
151
    /* The given offset is too big, it is beyond this section.  */
152
104k
    __libelf_seterrno (ELF_E_OFFSET_RANGE);
153
104k
    goto out;
154
104k
  }
155
128k
    }
156
157
254k
  if (strscn->rawdata_base == NULL && ! strscn->data_read)
158
6.39k
    {
159
6.39k
      rwlock_unlock (elf->lock);
160
6.39k
      rwlock_wrlock (elf->lock);
161
6.39k
      if (strscn->rawdata_base == NULL && ! strscn->data_read
162
  /* Read the section data.  */
163
6.39k
    && __libelf_set_rawdata_wrlock (strscn) != 0)
164
3.55k
  goto out;
165
6.39k
    }
166
167
251k
  if (unlikely (strscn->zdata_base != NULL))
168
30.2k
    {
169
      /* Make sure the string is NUL terminated.  Start from the end,
170
         which very likely is a NUL char.  */
171
30.2k
      if (likely (validate_str (strscn->zdata_base, offset, sh_size)))
172
29.9k
        result = &strscn->zdata_base[offset];
173
380
      else
174
380
        __libelf_seterrno (ELF_E_INVALID_INDEX);
175
30.2k
    }
176
220k
  else if (likely (strscn->data_list_rear == NULL))
177
171k
    {
178
      // XXX The above is currently correct since elf_newdata will
179
      // make sure to convert the rawdata into the datalist if
180
      // necessary. But it would be more efficient to keep the rawdata
181
      // unconverted and only then iterate over the rest of the (newly
182
      // added data) list.  Note that when the ELF file is mmapped
183
      // rawdata_base can be set while rawdata.d hasn't been
184
      // initialized yet (when data_read is zero). So we cannot just
185
      // look at the rawdata.d.d_size.
186
187
      /* First check there actually is any data.  This could be a new
188
         section which hasn't had any data set yet.  Then make sure
189
         the string is at a valid offset and NUL terminated.  */
190
171k
      if (unlikely (strscn->rawdata_base == NULL))
191
0
  __libelf_seterrno (ELF_E_INVALID_SECTION);
192
171k
      else if (likely (validate_str (strscn->rawdata_base, offset, sh_size)))
193
170k
  result = &strscn->rawdata_base[offset];
194
610
      else
195
610
  __libelf_seterrno (ELF_E_INVALID_INDEX);
196
171k
    }
197
49.4k
  else
198
49.4k
    {
199
      /* This is a file which is currently created.  Use the list of
200
   data blocks.  */
201
49.4k
      struct Elf_Data_List *dl = &strscn->data_list;
202
49.4k
      while (dl != NULL)
203
49.4k
  {
204
49.4k
    if (offset >= (size_t) dl->data.d.d_off
205
49.4k
        && offset < dl->data.d.d_off + dl->data.d.d_size)
206
49.4k
      {
207
        /* Make sure the string is NUL terminated.  Start from
208
     the end, which very likely is a NUL char.  */
209
49.4k
        if (likely (validate_str ((char *) dl->data.d.d_buf,
210
49.4k
          offset - dl->data.d.d_off,
211
49.4k
          dl->data.d.d_size)))
212
49.2k
    result = ((char *) dl->data.d.d_buf
213
49.2k
        + (offset - dl->data.d.d_off));
214
236
        else
215
236
    __libelf_seterrno (ELF_E_INVALID_INDEX);
216
49.4k
        break;
217
49.4k
      }
218
219
0
    dl = dl->next;
220
0
  }
221
49.4k
    }
222
223
2.86M
 out:
224
2.86M
  rwlock_unlock (elf->lock);
225
226
2.86M
  return result;
227
251k
}
228
INTDEF(elf_strptr)