Coverage Report

Created: 2025-04-11 06:16

/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
427k
{
45
427k
  size_t zsize, zalign;
46
427k
  void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign);
47
427k
  if (zdata == NULL)
48
427k
    return NULL;
49
50
19
  strscn->zdata_base = zdata;
51
19
  strscn->zdata_size = zsize;
52
19
  strscn->zdata_align = zalign;
53
54
19
  return zdata;
55
427k
}
56
57
char *
58
elf_strptr (Elf *elf, size_t idx, size_t offset)
59
7.71M
{
60
7.71M
  if (elf == NULL)
61
0
    return NULL;
62
63
7.71M
  if (elf->kind != ELF_K_ELF)
64
0
    {
65
0
      __libelf_seterrno (ELF_E_INVALID_HANDLE);
66
0
      return NULL;
67
0
    }
68
69
7.71M
  rwlock_rdlock (elf->lock);
70
71
7.71M
  char *result = NULL;
72
7.71M
  Elf_Scn *strscn;
73
74
  /* Find the section in the list.  */
75
7.71M
  Elf_ScnList *runp = (elf->class == ELFCLASS32
76
7.71M
           || (offsetof (struct Elf, state.elf32.scns)
77
849k
         == offsetof (struct Elf, state.elf64.scns))
78
7.71M
           ? &elf->state.elf32.scns : &elf->state.elf64.scns);
79
7.71M
  while (1)
80
7.71M
    {
81
7.71M
      if (idx < runp->max)
82
7.36M
  {
83
7.36M
    if (idx < runp->cnt)
84
7.36M
      strscn = &runp->data[idx];
85
0
    else
86
0
      {
87
0
        __libelf_seterrno (ELF_E_INVALID_INDEX);
88
0
        goto out;
89
0
      }
90
7.36M
    break;
91
7.36M
  }
92
93
345k
      idx -= runp->max;
94
95
345k
      runp = runp->next;
96
345k
      if (runp == NULL)
97
345k
  {
98
345k
    __libelf_seterrno (ELF_E_INVALID_INDEX);
99
345k
    goto out;
100
345k
  }
101
345k
    }
102
103
7.36M
  size_t sh_size = 0;
104
7.36M
  if (elf->class == ELFCLASS32)
105
6.65M
    {
106
6.65M
      Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn);
107
6.65M
      if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
108
195k
  {
109
    /* This is no string section.  */
110
195k
    __libelf_seterrno (ELF_E_INVALID_SECTION);
111
195k
    goto out;
112
195k
  }
113
114
18.4E
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
115
6.04M
  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
421k
      goto out;
120
18.4E
    sh_size = strscn->zdata_size;
121
18.4E
  }
122
123
18.4E
      if (unlikely (offset >= sh_size))
124
5.92M
  {
125
    /* The given offset is too big, it is beyond this section.  */
126
5.92M
    __libelf_seterrno (ELF_E_OFFSET_RANGE);
127
5.92M
    goto out;
128
5.92M
  }
129
18.4E
    }
130
710k
  else
131
710k
    {
132
710k
      Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn);
133
710k
      if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
134
261k
  {
135
    /* This is no string section.  */
136
261k
    __libelf_seterrno (ELF_E_INVALID_SECTION);
137
261k
    goto out;
138
261k
  }
139
140
18.4E
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
141
441k
  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
6.54k
      goto out;
146
18.4E
    sh_size = strscn->zdata_size;
147
18.4E
  }
148
149
18.4E
      if (unlikely (offset >= sh_size))
150
80.1k
  {
151
    /* The given offset is too big, it is beyond this section.  */
152
80.1k
    __libelf_seterrno (ELF_E_OFFSET_RANGE);
153
80.1k
    goto out;
154
80.1k
  }
155
18.4E
    }
156
157
18.4E
  if (strscn->rawdata_base == NULL && ! strscn->data_read)
158
47.5k
    {
159
47.5k
      rwlock_unlock (elf->lock);
160
47.5k
      rwlock_wrlock (elf->lock);
161
47.5k
      if (strscn->rawdata_base == NULL && ! strscn->data_read
162
  /* Read the section data.  */
163
47.5k
    && __libelf_set_rawdata_wrlock (strscn) != 0)
164
46.6k
  goto out;
165
47.5k
    }
166
167
18.4E
  if (unlikely (strscn->zdata_base != NULL))
168
0
    {
169
      /* Make sure the string is NUL terminated.  Start from the end,
170
         which very likely is a NUL char.  */
171
0
      if (likely (validate_str (strscn->zdata_base, offset, sh_size)))
172
0
        result = &strscn->zdata_base[offset];
173
0
      else
174
0
        __libelf_seterrno (ELF_E_INVALID_INDEX);
175
0
    }
176
18.4E
  else if (likely (strscn->data_list_rear == NULL))
177
400k
    {
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
400k
      if (unlikely (strscn->rawdata_base == NULL))
191
0
  __libelf_seterrno (ELF_E_INVALID_SECTION);
192
400k
      else if (likely (validate_str (strscn->rawdata_base, offset, sh_size)))
193
202k
  result = &strscn->rawdata_base[offset];
194
197k
      else
195
197k
  __libelf_seterrno (ELF_E_INVALID_INDEX);
196
400k
    }
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
28.0k
  {
204
28.0k
    if (offset >= (size_t) dl->data.d.d_off
205
28.0k
        && offset < dl->data.d.d_off + dl->data.d.d_size)
206
28.0k
      {
207
        /* Make sure the string is NUL terminated.  Start from
208
     the end, which very likely is a NUL char.  */
209
28.0k
        if (likely (validate_str ((char *) dl->data.d.d_buf,
210
28.0k
          offset - dl->data.d.d_off,
211
28.0k
          dl->data.d.d_size)))
212
28.0k
    result = ((char *) dl->data.d.d_buf
213
28.0k
        + (offset - dl->data.d.d_off));
214
7
        else
215
7
    __libelf_seterrno (ELF_E_INVALID_INDEX);
216
28.0k
        break;
217
28.0k
      }
218
219
0
    dl = dl->next;
220
0
  }
221
18.4E
    }
222
223
18.4E
 out:
224
7.71M
  rwlock_unlock (elf->lock);
225
226
7.71M
  return result;
227
18.4E
}
228
INTDEF(elf_strptr)