Coverage Report

Created: 2025-11-09 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
426k
{
45
426k
  size_t zsize, zalign;
46
426k
  void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign);
47
426k
  if (zdata == NULL)
48
425k
    return NULL;
49
50
730
  strscn->zdata_base = zdata;
51
730
  strscn->zdata_size = zsize;
52
730
  strscn->zdata_align = zalign;
53
54
730
  return zdata;
55
426k
}
56
57
char *
58
elf_strptr (Elf *elf, size_t idx, size_t offset)
59
2.81M
{
60
2.81M
  if (elf == NULL)
61
0
    return NULL;
62
63
2.81M
  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.81M
  rwlock_rdlock (elf->lock);
70
71
2.81M
  char *result = NULL;
72
2.81M
  Elf_Scn *strscn;
73
74
  /* Find the section in the list.  */
75
2.81M
  Elf_ScnList *runp = (elf->class == ELFCLASS32
76
427k
           || (offsetof (struct Elf, state.elf32.scns)
77
427k
         == offsetof (struct Elf, state.elf64.scns))
78
2.81M
           ? &elf->state.elf32.scns : &elf->state.elf64.scns);
79
2.81M
  while (1)
80
2.81M
    {
81
2.81M
      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
658k
      idx -= runp->max;
94
95
658k
      runp = runp->next;
96
658k
      if (runp == NULL)
97
658k
  {
98
658k
    __libelf_seterrno (ELF_E_INVALID_INDEX);
99
658k
    goto out;
100
658k
  }
101
658k
    }
102
103
2.15M
  size_t sh_size = 0;
104
2.15M
  if (elf->class == ELFCLASS32)
105
1.89M
    {
106
1.89M
      Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn);
107
1.89M
      if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
108
591k
  {
109
    /* This is no string section.  */
110
591k
    __libelf_seterrno (ELF_E_INVALID_SECTION);
111
591k
    goto out;
112
591k
  }
113
114
1.30M
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
115
741k
  sh_size = shdr->sh_size;
116
564k
      else
117
564k
  {
118
564k
    if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
119
365k
      goto out;
120
199k
    sh_size = strscn->zdata_size;
121
199k
  }
122
123
941k
      if (unlikely (offset >= sh_size))
124
637k
  {
125
    /* The given offset is too big, it is beyond this section.  */
126
637k
    __libelf_seterrno (ELF_E_OFFSET_RANGE);
127
637k
    goto out;
128
637k
  }
129
941k
    }
130
258k
  else
131
258k
    {
132
258k
      Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn);
133
258k
      if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
134
88.9k
  {
135
    /* This is no string section.  */
136
88.9k
    __libelf_seterrno (ELF_E_INVALID_SECTION);
137
88.9k
    goto out;
138
88.9k
  }
139
140
169k
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
141
59.9k
  sh_size = shdr->sh_size;
142
109k
      else
143
109k
  {
144
109k
    if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
145
60.6k
      goto out;
146
48.5k
    sh_size = strscn->zdata_size;
147
48.5k
  }
148
149
108k
      if (unlikely (offset >= sh_size))
150
80.6k
  {
151
    /* The given offset is too big, it is beyond this section.  */
152
80.6k
    __libelf_seterrno (ELF_E_OFFSET_RANGE);
153
80.6k
    goto out;
154
80.6k
  }
155
108k
    }
156
157
331k
  if (strscn->rawdata_base == NULL && ! strscn->data_read)
158
4.78k
    {
159
4.78k
      rwlock_unlock (elf->lock);
160
4.78k
      rwlock_wrlock (elf->lock);
161
4.78k
      if (strscn->rawdata_base == NULL && ! strscn->data_read
162
  /* Read the section data.  */
163
4.78k
    && __libelf_set_rawdata_wrlock (strscn) != 0)
164
1.46k
  goto out;
165
4.78k
    }
166
167
330k
  if (unlikely (strscn->zdata_base != NULL))
168
41.4k
    {
169
      /* Make sure the string is NUL terminated.  Start from the end,
170
         which very likely is a NUL char.  */
171
41.4k
      if (likely (validate_str (strscn->zdata_base, offset, sh_size)))
172
40.8k
        result = &strscn->zdata_base[offset];
173
601
      else
174
601
        __libelf_seterrno (ELF_E_INVALID_INDEX);
175
41.4k
    }
176
288k
  else if (likely (strscn->data_list_rear == NULL))
177
206k
    {
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
206k
      if (unlikely (strscn->rawdata_base == NULL))
191
0
  __libelf_seterrno (ELF_E_INVALID_SECTION);
192
206k
      else if (likely (validate_str (strscn->rawdata_base, offset, sh_size)))
193
205k
  result = &strscn->rawdata_base[offset];
194
977
      else
195
977
  __libelf_seterrno (ELF_E_INVALID_INDEX);
196
206k
    }
197
82.7k
  else
198
82.7k
    {
199
      /* This is a file which is currently created.  Use the list of
200
   data blocks.  */
201
82.7k
      struct Elf_Data_List *dl = &strscn->data_list;
202
82.7k
      while (dl != NULL)
203
82.7k
  {
204
82.7k
    if (offset >= (size_t) dl->data.d.d_off
205
82.7k
        && offset < dl->data.d.d_off + dl->data.d.d_size)
206
82.7k
      {
207
        /* Make sure the string is NUL terminated.  Start from
208
     the end, which very likely is a NUL char.  */
209
82.7k
        if (likely (validate_str ((char *) dl->data.d.d_buf,
210
82.7k
          offset - dl->data.d.d_off,
211
82.7k
          dl->data.d.d_size)))
212
82.4k
    result = ((char *) dl->data.d.d_buf
213
82.4k
        + (offset - dl->data.d.d_off));
214
230
        else
215
230
    __libelf_seterrno (ELF_E_INVALID_INDEX);
216
82.7k
        break;
217
82.7k
      }
218
219
0
    dl = dl->next;
220
0
  }
221
82.7k
    }
222
223
2.81M
 out:
224
2.81M
  rwlock_unlock (elf->lock);
225
226
2.81M
  return result;
227
330k
}
228
INTDEF(elf_strptr)