Coverage Report

Created: 2025-07-18 06:08

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