Branch data Line data Source code
1 : : /* Update data structures for changes and write them out.
2 : : Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2015 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : : Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of either
8 : :
9 : : * the GNU Lesser General Public License as published by the Free
10 : : Software Foundation; either version 3 of the License, or (at
11 : : your option) any later version
12 : :
13 : : or
14 : :
15 : : * the GNU General Public License as published by the Free
16 : : Software Foundation; either version 2 of the License, or (at
17 : : your option) any later version
18 : :
19 : : or both in parallel, as here.
20 : :
21 : : elfutils is distributed in the hope that it will be useful, but
22 : : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : : General Public License for more details.
25 : :
26 : : You should have received copies of the GNU General Public License and
27 : : the GNU Lesser General Public License along with this program. If
28 : : not, see <http://www.gnu.org/licenses/>. */
29 : :
30 : : #ifdef HAVE_CONFIG_H
31 : : # include <config.h>
32 : : #endif
33 : :
34 : : #include <libelf.h>
35 : : #include <fcntl.h>
36 : : #include <unistd.h>
37 : : #include <sys/mman.h>
38 : : #include <sys/stat.h>
39 : :
40 : : #include "libelfP.h"
41 : :
42 : :
43 : : static int64_t
44 : 544 : write_file (Elf *elf, int64_t size, int change_bo, size_t shnum)
45 : : {
46 : 544 : int class = elf->class;
47 : :
48 : : /* Check the mode bits now, before modification might change them. */
49 : 544 : struct stat st;
50 [ - + ]: 544 : if (unlikely (fstat (elf->fildes, &st) != 0))
51 : : {
52 : 0 : __libelf_seterrno (ELF_E_WRITE_ERROR);
53 : 0 : return -1;
54 : : }
55 : :
56 : : /* Adjust the size in any case. We do this even if we use `write'.
57 : : We cannot do this if this file is in an archive. We also don't
58 : : do it *now* if we are shortening the file since this would
59 : : prevent programs to use the data of the file in generating the
60 : : new file. We truncate the file later in this case. */
61 [ + - ]: 544 : if (elf->parent == NULL
62 [ + - ]: 544 : && (elf->maximum_size == ~((size_t) 0)
63 [ + + ]: 544 : || (size_t) size > elf->maximum_size)
64 [ - + ]: 489 : && unlikely (ftruncate (elf->fildes, size) != 0))
65 : : {
66 : 0 : __libelf_seterrno (ELF_E_WRITE_ERROR);
67 : 0 : return -1;
68 : : }
69 : :
70 : : /* Try to map the file if this isn't done yet. */
71 [ + + + + ]: 544 : if (elf->map_address == NULL && elf->cmd == ELF_C_WRITE_MMAP)
72 : : {
73 : 123 : elf->map_address = mmap (NULL, size, PROT_READ | PROT_WRITE,
74 : : MAP_SHARED, elf->fildes, 0);
75 [ - + ]: 123 : if (unlikely (elf->map_address == MAP_FAILED))
76 : 0 : elf->map_address = NULL;
77 : : else
78 : 123 : elf->flags |= ELF_F_MMAPPED;
79 : : }
80 : :
81 [ + + ]: 544 : if (elf->map_address != NULL)
82 : : {
83 : : /* When using mmap we want to make sure the file content is
84 : : really there. Only using ftruncate might mean the file is
85 : : extended, but space isn't allocated yet. This might cause a
86 : : SIGBUS once we write into the mmapped space and the disk is
87 : : full. In glibc posix_fallocate is required to extend the
88 : : file and allocate enough space even if the underlying
89 : : filesystem would normally return EOPNOTSUPP. But other
90 : : implementations might not work as expected. And the glibc
91 : : fallback case might fail (with unexpected errnos) in some cases.
92 : : So we only report an error when the call fails and errno is
93 : : ENOSPC. Otherwise we ignore the error and treat it as just hint. */
94 [ + - ]: 139 : if (elf->parent == NULL
95 [ + - ]: 139 : && (elf->maximum_size == ~((size_t) 0)
96 [ + + ]: 139 : || (size_t) size > elf->maximum_size))
97 : : {
98 [ - + ]: 137 : if (unlikely (posix_fallocate (elf->fildes, 0, size) != 0))
99 [ # # ]: 0 : if (errno == ENOSPC)
100 : : {
101 : 0 : __libelf_seterrno (ELF_E_WRITE_ERROR);
102 : 0 : return -1;
103 : : }
104 : :
105 : : /* Extend the mmap address if needed. */
106 [ + + ]: 137 : if (elf->cmd == ELF_C_RDWR_MMAP
107 [ + - ]: 14 : && (size_t) size > elf->maximum_size)
108 : : {
109 : : #ifdef HAVE_MREMAP
110 [ - + ]: 14 : if (mremap (elf->map_address, elf->maximum_size,
111 : : size, 0) == MAP_FAILED)
112 : : #endif
113 : : {
114 : 0 : __libelf_seterrno (ELF_E_WRITE_ERROR);
115 : 0 : return -1;
116 : : }
117 : 14 : elf->maximum_size = size;
118 : : }
119 : :
120 : : }
121 : :
122 : : /* The file is mmaped. */
123 [ + - ]: 139 : if ((class == ELFCLASS32
124 : 64 : ? __elf32_updatemmap (elf, change_bo, shnum)
125 [ + + ]: 203 : : __elf64_updatemmap (elf, change_bo, shnum)) != 0)
126 : : /* Some problem while writing. */
127 : : size = -1;
128 : : }
129 : : else
130 : : {
131 : : /* The file is not mmaped. */
132 [ + - ]: 405 : if ((class == ELFCLASS32
133 : 159 : ? __elf32_updatefile (elf, change_bo, shnum)
134 [ + + ]: 564 : : __elf64_updatefile (elf, change_bo, shnum)) != 0)
135 : : /* Some problem while writing. */
136 : : size = -1;
137 : : }
138 : :
139 : : /* Reduce the file size if necessary. */
140 [ + - ]: 544 : if (size != -1
141 [ + - ]: 544 : && elf->parent == NULL
142 [ + - ]: 544 : && elf->maximum_size != ~((size_t) 0)
143 [ + + ]: 544 : && (size_t) size < elf->maximum_size
144 [ - + ]: 39 : && unlikely (ftruncate (elf->fildes, size) != 0))
145 : : {
146 : 0 : __libelf_seterrno (ELF_E_WRITE_ERROR);
147 : 0 : size = -1;
148 : : }
149 : :
150 : : /* POSIX says that ftruncate and write may clear the S_ISUID and S_ISGID
151 : : mode bits. So make sure we restore them afterwards if they were set.
152 : : This is not atomic if someone else chmod's the file while we operate. */
153 [ + - ]: 544 : if (size != -1
154 [ - + ]: 544 : && unlikely (st.st_mode & (S_ISUID | S_ISGID))
155 : : /* fchmod ignores the bits we cannot change. */
156 [ # # ]: 0 : && unlikely (fchmod (elf->fildes, st.st_mode) != 0))
157 : : {
158 : 0 : __libelf_seterrno (ELF_E_WRITE_ERROR);
159 : 0 : size = -1;
160 : : }
161 : :
162 [ + - + - ]: 544 : if (size != -1 && elf->parent == NULL)
163 : 544 : elf->maximum_size = size;
164 : :
165 : : return size;
166 : : }
167 : :
168 : :
169 : : int64_t
170 : 612 : elf_update (Elf *elf, Elf_Cmd cmd)
171 : : {
172 : 612 : size_t shnum;
173 : 612 : int64_t size;
174 : 612 : int change_bo = 0;
175 : :
176 : 612 : if (cmd != ELF_C_NULL
177 [ + + ]: 612 : && cmd != ELF_C_WRITE
178 [ - + ]: 9 : && unlikely (cmd != ELF_C_WRITE_MMAP))
179 : : {
180 : 0 : __libelf_seterrno (ELF_E_INVALID_CMD);
181 : 0 : return -1;
182 : : }
183 : :
184 [ + - ]: 612 : if (elf == NULL)
185 : : return -1;
186 : :
187 [ - + ]: 612 : if (elf->kind != ELF_K_ELF)
188 : : {
189 : 0 : __libelf_seterrno (ELF_E_INVALID_HANDLE);
190 : 0 : return -1;
191 : : }
192 : :
193 : 612 : rwlock_wrlock (elf->lock);
194 : :
195 : : /* Make sure we have an ELF header. */
196 [ - + ]: 612 : if (elf->state.elf.ehdr == NULL)
197 : : {
198 : 0 : __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
199 : 0 : size = -1;
200 : 0 : goto out;
201 : : }
202 : :
203 : : /* Determine the number of sections. */
204 : 1224 : shnum = (elf->state.elf.scns_last->cnt == 0
205 : : ? 0
206 [ + + ]: 612 : : 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt - 1].index);
207 : :
208 : : /* Update the ELF descriptor. First, place the program header. It
209 : : will come right after the ELF header. The count the size of all
210 : : sections and finally place the section table. */
211 : 1224 : size = (elf->class == ELFCLASS32
212 : 258 : ? __elf32_updatenull_wrlock (elf, &change_bo, shnum)
213 [ + + ]: 612 : : __elf64_updatenull_wrlock (elf, &change_bo, shnum));
214 [ - + ]: 612 : if (likely (size != -1)
215 : : /* See whether we actually have to write out the data. */
216 [ + + ]: 612 : && (cmd == ELF_C_WRITE || cmd == ELF_C_WRITE_MMAP))
217 : : {
218 : 544 : if (elf->cmd != ELF_C_RDWR
219 [ + + ]: 544 : && elf->cmd != ELF_C_RDWR_MMAP
220 [ + + ]: 437 : && elf->cmd != ELF_C_WRITE
221 [ - + ]: 123 : && unlikely (elf->cmd != ELF_C_WRITE_MMAP))
222 : : {
223 : 0 : __libelf_seterrno (ELF_E_UPDATE_RO);
224 : 0 : size = -1;
225 : : }
226 [ - + ]: 544 : else if (unlikely (elf->fildes == -1))
227 : : {
228 : : /* We closed the file already. */
229 : 0 : __libelf_seterrno (ELF_E_FD_DISABLED);
230 : 0 : size = -1;
231 : : }
232 : : else
233 : 544 : size = write_file (elf, size, change_bo, shnum);
234 : : }
235 : :
236 : 68 : out:
237 : : rwlock_unlock (elf->lock);
238 : :
239 : : return size;
240 : : }
|