Coverage Report

Created: 2026-04-12 06:15

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
829k
{
45
829k
  size_t zsize, zalign;
46
829k
  void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign);
47
829k
  if (zdata == NULL)
48
828k
    return NULL;
49
50
715
  strscn->zdata_base = zdata;
51
715
  strscn->zdata_size = zsize;
52
715
  strscn->zdata_align = zalign;
53
54
715
  return zdata;
55
829k
}
56
57
char *
58
elf_strptr (Elf *elf, size_t idx, size_t offset)
59
5.87M
{
60
5.87M
  if (elf == NULL)
61
0
    return NULL;
62
63
5.87M
  if (elf->kind != ELF_K_ELF)
64
0
    {
65
0
      __libelf_seterrno (ELF_E_INVALID_HANDLE);
66
0
      return NULL;
67
0
    }
68
69
5.87M
  rwlock_rdlock (elf->lock);
70
71
5.87M
  char *result = NULL;
72
5.87M
  Elf_Scn *strscn;
73
74
  /* Find the section in the list.  */
75
5.87M
  Elf_ScnList *runp = (elf->class == ELFCLASS32
76
1.63M
           || (offsetof (struct Elf, state.elf32.scns)
77
1.63M
         == offsetof (struct Elf, state.elf64.scns))
78
5.87M
           ? &elf->state.elf32.scns : &elf->state.elf64.scns);
79
5.87M
  while (1)
80
5.87M
    {
81
5.87M
      if (idx < runp->max)
82
4.83M
  {
83
4.83M
    if (idx < runp->cnt)
84
4.83M
      strscn = &runp->data[idx];
85
0
    else
86
0
      {
87
0
        __libelf_seterrno (ELF_E_INVALID_INDEX);
88
0
        goto out;
89
0
      }
90
4.83M
    break;
91
4.83M
  }
92
93
1.04M
      idx -= runp->max;
94
95
1.04M
      runp = runp->next;
96
1.04M
      if (runp == NULL)
97
1.04M
  {
98
1.04M
    __libelf_seterrno (ELF_E_INVALID_INDEX);
99
1.04M
    goto out;
100
1.04M
  }
101
1.04M
    }
102
103
4.83M
  size_t sh_size = 0;
104
4.83M
  if (elf->class == ELFCLASS32)
105
3.33M
    {
106
3.33M
      Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn);
107
3.33M
      if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
108
1.17M
  {
109
    /* This is no string section.  */
110
1.17M
    __libelf_seterrno (ELF_E_INVALID_SECTION);
111
1.17M
    goto out;
112
1.17M
  }
113
114
2.15M
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
115
1.35M
  sh_size = shdr->sh_size;
116
803k
      else
117
803k
  {
118
803k
    if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
119
653k
      goto out;
120
150k
    sh_size = strscn->zdata_size;
121
150k
  }
122
123
1.50M
      if (unlikely (offset >= sh_size))
124
854k
  {
125
    /* The given offset is too big, it is beyond this section.  */
126
854k
    __libelf_seterrno (ELF_E_OFFSET_RANGE);
127
854k
    goto out;
128
854k
  }
129
1.50M
    }
130
1.49M
  else
131
1.49M
    {
132
1.49M
      Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn);
133
1.49M
      if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
134
518k
  {
135
    /* This is no string section.  */
136
518k
    __libelf_seterrno (ELF_E_INVALID_SECTION);
137
518k
    goto out;
138
518k
  }
139
140
980k
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
141
728k
  sh_size = shdr->sh_size;
142
252k
      else
143
252k
  {
144
252k
    if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
145
175k
      goto out;
146
77.0k
    sh_size = strscn->zdata_size;
147
77.0k
  }
148
149
805k
      if (unlikely (offset >= sh_size))
150
393k
  {
151
    /* The given offset is too big, it is beyond this section.  */
152
393k
    __libelf_seterrno (ELF_E_OFFSET_RANGE);
153
393k
    goto out;
154
393k
  }
155
805k
    }
156
157
1.05M
  if (strscn->rawdata_base == NULL && ! strscn->data_read)
158
459k
    {
159
459k
      rwlock_unlock (elf->lock);
160
459k
      rwlock_wrlock (elf->lock);
161
459k
      if (strscn->rawdata_base == NULL && ! strscn->data_read
162
  /* Read the section data.  */
163
459k
    && __libelf_set_rawdata_wrlock (strscn) != 0)
164
455k
  goto out;
165
459k
    }
166
167
603k
  if (unlikely (strscn->zdata_base != NULL))
168
32.2k
    {
169
      /* Make sure the string is NUL terminated.  Start from the end,
170
         which very likely is a NUL char.  */
171
32.2k
      if (likely (validate_str (strscn->zdata_base, offset, sh_size)))
172
31.9k
        result = &strscn->zdata_base[offset];
173
380
      else
174
380
        __libelf_seterrno (ELF_E_INVALID_INDEX);
175
32.2k
    }
176
570k
  else if (likely (strscn->data_list_rear == NULL))
177
429k
    {
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
429k
      if (unlikely (strscn->rawdata_base == NULL))
191
0
  __libelf_seterrno (ELF_E_INVALID_SECTION);
192
429k
      else if (likely (validate_str (strscn->rawdata_base, offset, sh_size)))
193
363k
  result = &strscn->rawdata_base[offset];
194
66.3k
      else
195
66.3k
  __libelf_seterrno (ELF_E_INVALID_INDEX);
196
429k
    }
197
141k
  else
198
141k
    {
199
      /* This is a file which is currently created.  Use the list of
200
   data blocks.  */
201
141k
      struct Elf_Data_List *dl = &strscn->data_list;
202
141k
      while (dl != NULL)
203
141k
  {
204
141k
    if (offset >= (size_t) dl->data.d.d_off
205
141k
        && offset < dl->data.d.d_off + dl->data.d.d_size)
206
141k
      {
207
        /* Make sure the string is NUL terminated.  Start from
208
     the end, which very likely is a NUL char.  */
209
141k
        if (likely (validate_str ((char *) dl->data.d.d_buf,
210
141k
          offset - dl->data.d.d_off,
211
141k
          dl->data.d.d_size)))
212
141k
    result = ((char *) dl->data.d.d_buf
213
141k
        + (offset - dl->data.d.d_off));
214
225
        else
215
225
    __libelf_seterrno (ELF_E_INVALID_INDEX);
216
141k
        break;
217
141k
      }
218
219
0
    dl = dl->next;
220
0
  }
221
141k
    }
222
223
5.87M
 out:
224
5.87M
  rwlock_unlock (elf->lock);
225
226
5.87M
  return result;
227
603k
}
228
INTDEF(elf_strptr)