Coverage Report

Created: 2025-11-09 06:34

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