Coverage Report

Created: 2025-11-06 06:34

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
399k
{
45
399k
  size_t zsize, zalign;
46
399k
  void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign);
47
399k
  if (zdata == NULL)
48
398k
    return NULL;
49
50
740
  strscn->zdata_base = zdata;
51
740
  strscn->zdata_size = zsize;
52
740
  strscn->zdata_align = zalign;
53
54
740
  return zdata;
55
399k
}
56
57
char *
58
elf_strptr (Elf *elf, size_t idx, size_t offset)
59
2.75M
{
60
2.75M
  if (elf == NULL)
61
0
    return NULL;
62
63
2.75M
  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.75M
  rwlock_rdlock (elf->lock);
70
71
2.75M
  char *result = NULL;
72
2.75M
  Elf_Scn *strscn;
73
74
  /* Find the section in the list.  */
75
2.75M
  Elf_ScnList *runp = (elf->class == ELFCLASS32
76
394k
           || (offsetof (struct Elf, state.elf32.scns)
77
394k
         == offsetof (struct Elf, state.elf64.scns))
78
2.75M
           ? &elf->state.elf32.scns : &elf->state.elf64.scns);
79
2.75M
  while (1)
80
2.75M
    {
81
2.75M
      if (idx < runp->max)
82
2.04M
  {
83
2.04M
    if (idx < runp->cnt)
84
2.04M
      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.04M
    break;
91
2.04M
  }
92
93
713k
      idx -= runp->max;
94
95
713k
      runp = runp->next;
96
713k
      if (runp == NULL)
97
713k
  {
98
713k
    __libelf_seterrno (ELF_E_INVALID_INDEX);
99
713k
    goto out;
100
713k
  }
101
713k
    }
102
103
2.04M
  size_t sh_size = 0;
104
2.04M
  if (elf->class == ELFCLASS32)
105
1.81M
    {
106
1.81M
      Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn);
107
1.81M
      if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
108
583k
  {
109
    /* This is no string section.  */
110
583k
    __libelf_seterrno (ELF_E_INVALID_SECTION);
111
583k
    goto out;
112
583k
  }
113
114
1.22M
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
115
689k
  sh_size = shdr->sh_size;
116
539k
      else
117
539k
  {
118
539k
    if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
119
356k
      goto out;
120
183k
    sh_size = strscn->zdata_size;
121
183k
  }
122
123
872k
      if (unlikely (offset >= sh_size))
124
596k
  {
125
    /* The given offset is too big, it is beyond this section.  */
126
596k
    __libelf_seterrno (ELF_E_OFFSET_RANGE);
127
596k
    goto out;
128
596k
  }
129
872k
    }
130
228k
  else
131
228k
    {
132
228k
      Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn);
133
228k
      if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
134
93.2k
  {
135
    /* This is no string section.  */
136
93.2k
    __libelf_seterrno (ELF_E_INVALID_SECTION);
137
93.2k
    goto out;
138
93.2k
  }
139
140
135k
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
141
56.3k
  sh_size = shdr->sh_size;
142
78.7k
      else
143
78.7k
  {
144
78.7k
    if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
145
42.5k
      goto out;
146
36.1k
    sh_size = strscn->zdata_size;
147
36.1k
  }
148
149
92.4k
      if (unlikely (offset >= sh_size))
150
66.2k
  {
151
    /* The given offset is too big, it is beyond this section.  */
152
66.2k
    __libelf_seterrno (ELF_E_OFFSET_RANGE);
153
66.2k
    goto out;
154
66.2k
  }
155
92.4k
    }
156
157
302k
  if (strscn->rawdata_base == NULL && ! strscn->data_read)
158
5.01k
    {
159
5.01k
      rwlock_unlock (elf->lock);
160
5.01k
      rwlock_wrlock (elf->lock);
161
5.01k
      if (strscn->rawdata_base == NULL && ! strscn->data_read
162
  /* Read the section data.  */
163
5.01k
    && __libelf_set_rawdata_wrlock (strscn) != 0)
164
1.73k
  goto out;
165
5.01k
    }
166
167
300k
  if (unlikely (strscn->zdata_base != NULL))
168
32.4k
    {
169
      /* Make sure the string is NUL terminated.  Start from the end,
170
         which very likely is a NUL char.  */
171
32.4k
      if (likely (validate_str (strscn->zdata_base, offset, sh_size)))
172
31.9k
        result = &strscn->zdata_base[offset];
173
406
      else
174
406
        __libelf_seterrno (ELF_E_INVALID_INDEX);
175
32.4k
    }
176
268k
  else if (likely (strscn->data_list_rear == NULL))
177
184k
    {
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
184k
      if (unlikely (strscn->rawdata_base == NULL))
191
0
  __libelf_seterrno (ELF_E_INVALID_SECTION);
192
184k
      else if (likely (validate_str (strscn->rawdata_base, offset, sh_size)))
193
183k
  result = &strscn->rawdata_base[offset];
194
818
      else
195
818
  __libelf_seterrno (ELF_E_INVALID_INDEX);
196
184k
    }
197
83.7k
  else
198
83.7k
    {
199
      /* This is a file which is currently created.  Use the list of
200
   data blocks.  */
201
83.7k
      struct Elf_Data_List *dl = &strscn->data_list;
202
83.7k
      while (dl != NULL)
203
83.7k
  {
204
83.7k
    if (offset >= (size_t) dl->data.d.d_off
205
83.7k
        && offset < dl->data.d.d_off + dl->data.d.d_size)
206
83.7k
      {
207
        /* Make sure the string is NUL terminated.  Start from
208
     the end, which very likely is a NUL char.  */
209
83.7k
        if (likely (validate_str ((char *) dl->data.d.d_buf,
210
83.7k
          offset - dl->data.d.d_off,
211
83.7k
          dl->data.d.d_size)))
212
83.4k
    result = ((char *) dl->data.d.d_buf
213
83.4k
        + (offset - dl->data.d.d_off));
214
330
        else
215
330
    __libelf_seterrno (ELF_E_INVALID_INDEX);
216
83.7k
        break;
217
83.7k
      }
218
219
0
    dl = dl->next;
220
0
  }
221
83.7k
    }
222
223
2.75M
 out:
224
2.75M
  rwlock_unlock (elf->lock);
225
226
2.75M
  return result;
227
300k
}
228
INTDEF(elf_strptr)