blob: 31ba25375fc74b121fd7a243507bdc8bf245d7c5 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Update data structures for changes and write them out.
Ulrich Drepper697d8d22006-04-04 21:07:28 +00002 Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004 Contributed by Ulrich Drepper <drepper@redhat.com>, 1999.
5
Mark Wielaardde2ed972012-06-05 17:15:16 +02006 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00008
Mark Wielaardde2ed972012-06-05 17:15:16 +02009 * 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
Ulrich Drepper361df7d2006-04-04 21:38:57 +000022 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.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000025
Mark Wielaardde2ed972012-06-05 17:15:16 +020026 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/>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000029
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>
Roland McGrath89757442005-09-11 09:05:20 +000037#include <sys/stat.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000038
39#include "libelfP.h"
40
41
42static off_t
43write_file (Elf *elf, off_t size, int change_bo, size_t shnum)
44{
45 int class = elf->class;
46
Roland McGrath89757442005-09-11 09:05:20 +000047 /* 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
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000055 /* 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#if _MUDFLAP
73 /* Mudflap doesn't grok that our mmap'd data is ok. */
74#else
75 elf->map_address = mmap (NULL, size, PROT_READ | PROT_WRITE,
76 MAP_SHARED, elf->fildes, 0);
77 if (unlikely (elf->map_address == MAP_FAILED))
78 elf->map_address = NULL;
79#endif
80 }
81
82 if (elf->map_address != NULL)
83 {
84 /* The file is mmaped. */
85 if ((class == ELFCLASS32
86 ? __elf32_updatemmap (elf, change_bo, shnum)
87 : __elf64_updatemmap (elf, change_bo, shnum)) != 0)
88 /* Some problem while writing. */
89 size = -1;
90 }
91 else
92 {
93 /* The file is not mmaped. */
94 if ((class == ELFCLASS32
95 ? __elf32_updatefile (elf, change_bo, shnum)
96 : __elf64_updatefile (elf, change_bo, shnum)) != 0)
97 /* Some problem while writing. */
98 size = -1;
99 }
100
101 if (size != -1
102 && elf->parent == NULL
103 && elf->maximum_size != ~((size_t) 0)
104 && (size_t) size < elf->maximum_size
105 && unlikely (ftruncate (elf->fildes, size) != 0))
106 {
107 __libelf_seterrno (ELF_E_WRITE_ERROR);
108 size = -1;
109 }
110
Roland McGrath89757442005-09-11 09:05:20 +0000111 /* POSIX says that ftruncate and write may clear the S_ISUID and S_ISGID
112 mode bits. So make sure we restore them afterwards if they were set.
113 This is not atomic if someone else chmod's the file while we operate. */
114 if (size != -1
115 && unlikely (st.st_mode & (S_ISUID | S_ISGID))
116 /* fchmod ignores the bits we cannot change. */
117 && unlikely (fchmod (elf->fildes, st.st_mode) != 0))
118 {
119 __libelf_seterrno (ELF_E_WRITE_ERROR);
120 size = -1;
121 }
122
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000123 if (size != -1 && elf->parent == NULL)
124 elf->maximum_size = size;
125
126 return size;
127}
128
129
130off_t
131elf_update (elf, cmd)
132 Elf *elf;
133 Elf_Cmd cmd;
134{
135 size_t shnum;
136 off_t size;
137 int change_bo = 0;
138
139 if (cmd != ELF_C_NULL
140 && cmd != ELF_C_WRITE
141 && unlikely (cmd != ELF_C_WRITE_MMAP))
142 {
143 __libelf_seterrno (ELF_E_INVALID_CMD);
144 return -1;
145 }
146
147 if (elf == NULL)
148 return -1;
149
150 if (elf->kind != ELF_K_ELF)
151 {
152 __libelf_seterrno (ELF_E_INVALID_HANDLE);
153 return -1;
154 }
155
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000156 rwlock_wrlock (elf->lock);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000157
158 /* Make sure we have an ELF header. */
159 if (elf->state.elf.ehdr == NULL)
160 {
161 __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
162 size = -1;
163 goto out;
164 }
165
166 /* Determine the number of sections. */
167 shnum = (elf->state.elf.scns_last->cnt == 0
168 ? 0
169 : 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt - 1].index);
170
171 /* Update the ELF descriptor. First, place the program header. It
172 will come right after the ELF header. The count the size of all
173 sections and finally place the section table. */
174 size = (elf->class == ELFCLASS32
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000175 ? __elf32_updatenull_wrlock (elf, &change_bo, shnum)
176 : __elf64_updatenull_wrlock (elf, &change_bo, shnum));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000177 if (likely (size != -1)
178 /* See whether we actually have to write out the data. */
179 && (cmd == ELF_C_WRITE || cmd == ELF_C_WRITE_MMAP))
180 {
181 if (elf->cmd != ELF_C_RDWR
182 && elf->cmd != ELF_C_RDWR_MMAP
183 && elf->cmd != ELF_C_WRITE
184 && unlikely (elf->cmd != ELF_C_WRITE_MMAP))
185 {
186 __libelf_seterrno (ELF_E_UPDATE_RO);
187 size = -1;
188 }
189 else if (unlikely (elf->fildes == -1))
190 {
191 /* We closed the file already. */
192 __libelf_seterrno (ELF_E_FD_DISABLED);
193 size = -1;
194 }
195 else
Ulrich Drepper697d8d22006-04-04 21:07:28 +0000196 size = write_file (elf, size, change_bo, shnum);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000197 }
198
199 out:
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000200 rwlock_unlock (elf->lock);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000201
202 return size;
203}