Coverage Report

Created: 2025-08-24 06:28

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