Coverage Report

Created: 2025-07-11 06:46

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