1 /* Update data structures for changes and write them out.
2 Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006 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 <unistd.h>
36 #include <sys/mman.h>
37 #include <sys/stat.h>
38
39 #include "libelfP.h"
40
41
42 static off_t
write_file(Elf * elf,off_t size,int change_bo,size_t shnum)43 write_file (Elf *elf, off_t size, int change_bo, size_t shnum)
44 {
45 int class = elf->class;
46
47 /* Check the mode bits now, before modification might change them. */
48 struct stat st;
49 if (unlikely (fstat (elf->fildes, &st) != 0))
50 {
51 __libelf_seterrno (ELF_E_WRITE_ERROR);
52 return -1;
53 }
54
55 /* Adjust the size in any case. We do this even if we use `write'.
56 We cannot do this if this file is in an archive. We also don't
57 do it *now* if we are shortening the file since this would
58 prevent programs to use the data of the file in generating the
59 new file. We truncate the file later in this case. */
60 if (elf->parent == NULL
61 && (elf->maximum_size == ~((size_t) 0)
62 || (size_t) size > elf->maximum_size)
63 && unlikely (ftruncate (elf->fildes, size) != 0))
64 {
65 __libelf_seterrno (ELF_E_WRITE_ERROR);
66 return -1;
67 }
68
69 /* Try to map the file if this isn't done yet. */
70 if (elf->map_address == NULL && elf->cmd == ELF_C_WRITE_MMAP)
71 {
72 elf->map_address = mmap (NULL, size, PROT_READ | PROT_WRITE,
73 MAP_SHARED, elf->fildes, 0);
74 if (unlikely (elf->map_address == MAP_FAILED))
75 elf->map_address = NULL;
76 }
77
78 if (elf->map_address != NULL)
79 {
80 /* The file is mmaped. */
81 if ((class == ELFCLASS32
82 ? __elf32_updatemmap (elf, change_bo, shnum)
83 : __elf64_updatemmap (elf, change_bo, shnum)) != 0)
84 /* Some problem while writing. */
85 size = -1;
86 }
87 else
88 {
89 /* The file is not mmaped. */
90 if ((class == ELFCLASS32
91 ? __elf32_updatefile (elf, change_bo, shnum)
92 : __elf64_updatefile (elf, change_bo, shnum)) != 0)
93 /* Some problem while writing. */
94 size = -1;
95 }
96
97 if (size != -1
98 && elf->parent == NULL
99 && elf->maximum_size != ~((size_t) 0)
100 && (size_t) size < elf->maximum_size
101 && unlikely (ftruncate (elf->fildes, size) != 0))
102 {
103 __libelf_seterrno (ELF_E_WRITE_ERROR);
104 size = -1;
105 }
106
107 /* POSIX says that ftruncate and write may clear the S_ISUID and S_ISGID
108 mode bits. So make sure we restore them afterwards if they were set.
109 This is not atomic if someone else chmod's the file while we operate. */
110 if (size != -1
111 && unlikely (st.st_mode & (S_ISUID | S_ISGID))
112 /* fchmod ignores the bits we cannot change. */
113 && unlikely (fchmod (elf->fildes, st.st_mode) != 0))
114 {
115 __libelf_seterrno (ELF_E_WRITE_ERROR);
116 size = -1;
117 }
118
119 if (size != -1 && elf->parent == NULL)
120 elf->maximum_size = size;
121
122 return size;
123 }
124
125
126 off_t
elf_update(elf,cmd)127 elf_update (elf, cmd)
128 Elf *elf;
129 Elf_Cmd cmd;
130 {
131 size_t shnum;
132 off_t size;
133 int change_bo = 0;
134
135 if (cmd != ELF_C_NULL
136 && cmd != ELF_C_WRITE
137 && unlikely (cmd != ELF_C_WRITE_MMAP))
138 {
139 __libelf_seterrno (ELF_E_INVALID_CMD);
140 return -1;
141 }
142
143 if (elf == NULL)
144 return -1;
145
146 if (elf->kind != ELF_K_ELF)
147 {
148 __libelf_seterrno (ELF_E_INVALID_HANDLE);
149 return -1;
150 }
151
152 rwlock_wrlock (elf->lock);
153
154 /* Make sure we have an ELF header. */
155 if (elf->state.elf.ehdr == NULL)
156 {
157 __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
158 size = -1;
159 goto out;
160 }
161
162 /* Determine the number of sections. */
163 shnum = (elf->state.elf.scns_last->cnt == 0
164 ? 0
165 : 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt - 1].index);
166
167 /* Update the ELF descriptor. First, place the program header. It
168 will come right after the ELF header. The count the size of all
169 sections and finally place the section table. */
170 size = (elf->class == ELFCLASS32
171 ? __elf32_updatenull_wrlock (elf, &change_bo, shnum)
172 : __elf64_updatenull_wrlock (elf, &change_bo, shnum));
173 if (likely (size != -1)
174 /* See whether we actually have to write out the data. */
175 && (cmd == ELF_C_WRITE || cmd == ELF_C_WRITE_MMAP))
176 {
177 if (elf->cmd != ELF_C_RDWR
178 && elf->cmd != ELF_C_RDWR_MMAP
179 && elf->cmd != ELF_C_WRITE
180 && unlikely (elf->cmd != ELF_C_WRITE_MMAP))
181 {
182 __libelf_seterrno (ELF_E_UPDATE_RO);
183 size = -1;
184 }
185 else if (unlikely (elf->fildes == -1))
186 {
187 /* We closed the file already. */
188 __libelf_seterrno (ELF_E_FD_DISABLED);
189 size = -1;
190 }
191 else
192 size = write_file (elf, size, change_bo, shnum);
193 }
194
195 out:
196 rwlock_unlock (elf->lock);
197
198 return size;
199 }
200