• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <sys/stat.h>
37 
38 #include "libelfP.h"
39 
40 
41 static int64_t
write_file(Elf * elf,int64_t size,int change_bo,size_t shnum)42 write_file (Elf *elf, int64_t size, int change_bo, size_t shnum)
43 {
44   int class = elf->class;
45 
46   /* Check the mode bits now, before modification might change them.  */
47   struct stat st;
48   if (unlikely (fstat (elf->fildes, &st) != 0))
49     {
50       __libelf_seterrno (ELF_E_WRITE_ERROR);
51       return -1;
52     }
53 
54   /* Adjust the size in any case.  We do this even if we use `write'.
55      We cannot do this if this file is in an archive.  We also don't
56      do it *now* if we are shortening the file since this would
57      prevent programs to use the data of the file in generating the
58      new file.  We truncate the file later in this case.  */
59   if (elf->parent == NULL
60       && (elf->maximum_size == ~((size_t) 0)
61 	  || (size_t) size > elf->maximum_size)
62       && unlikely (ftruncate (elf->fildes, size) != 0))
63     {
64       __libelf_seterrno (ELF_E_WRITE_ERROR);
65       return -1;
66     }
67 
68   /* Try to map the file if this isn't done yet.  */
69   if (elf->map_address == NULL && elf->cmd == ELF_C_WRITE_MMAP)
70     {
71       elf->map_address = mmap (NULL, size, PROT_READ | PROT_WRITE,
72 			       MAP_SHARED, elf->fildes, 0);
73       if (unlikely (elf->map_address == MAP_FAILED))
74 	elf->map_address = NULL;
75       else
76 	elf->flags |= ELF_F_MMAPPED;
77     }
78 
79   if (elf->map_address != NULL)
80     {
81       /* When using mmap we want to make sure the file content is
82 	 really there. Only using ftruncate might mean the file is
83 	 extended, but space isn't allocated yet.  This might cause a
84 	 SIGBUS once we write into the mmapped space and the disk is
85 	 full.  In glibc posix_fallocate is required to extend the
86 	 file and allocate enough space even if the underlying
87 	 filesystem would normally return EOPNOTSUPP.  But other
88 	 implementations might not work as expected.  And the glibc
89 	 fallback case might fail (with unexpected errnos) in some cases.
90 	 So we only report an error when the call fails and errno is
91 	 ENOSPC. Otherwise we ignore the error and treat it as just hint.  */
92       if (elf->parent == NULL
93 	  && (elf->maximum_size == ~((size_t) 0)
94 	      || (size_t) size > elf->maximum_size))
95 	{
96 	  if (unlikely (posix_fallocate (elf->fildes, 0, size) != 0))
97 	    if (errno == ENOSPC)
98 	      {
99 		__libelf_seterrno (ELF_E_WRITE_ERROR);
100 		return -1;
101 	      }
102 
103 	  /* Extend the mmap address if needed.  */
104 	  if (elf->cmd == ELF_C_RDWR_MMAP
105 	      && (size_t) size > elf->maximum_size)
106 	    {
107 #ifdef HAVE_MREMAP
108 	      if (mremap (elf->map_address, elf->maximum_size,
109 			  size, 0) == MAP_FAILED)
110 #endif
111 		{
112 		  __libelf_seterrno (ELF_E_WRITE_ERROR);
113 		  return -1;
114 		}
115 	      elf->maximum_size = size;
116 	    }
117 
118 	}
119 
120       /* The file is mmaped.  */
121       if ((class == ELFCLASS32
122 	   ? __elf32_updatemmap (elf, change_bo, shnum)
123 	   : __elf64_updatemmap (elf, change_bo, shnum)) != 0)
124 	/* Some problem while writing.  */
125 	size = -1;
126     }
127   else
128     {
129       /* The file is not mmaped.  */
130       if ((class == ELFCLASS32
131 	   ? __elf32_updatefile (elf, change_bo, shnum)
132 	   : __elf64_updatefile (elf, change_bo, shnum)) != 0)
133 	/* Some problem while writing.  */
134 	size = -1;
135     }
136 
137   /* Reduce the file size if necessary.  */
138   if (size != -1
139       && elf->parent == NULL
140       && elf->maximum_size != ~((size_t) 0)
141       && (size_t) size < elf->maximum_size
142       && unlikely (ftruncate (elf->fildes, size) != 0))
143     {
144       __libelf_seterrno (ELF_E_WRITE_ERROR);
145       size = -1;
146     }
147 
148   /* POSIX says that ftruncate and write may clear the S_ISUID and S_ISGID
149      mode bits.  So make sure we restore them afterwards if they were set.
150      This is not atomic if someone else chmod's the file while we operate.  */
151   if (size != -1
152       && unlikely (st.st_mode & (S_ISUID | S_ISGID))
153       /* fchmod ignores the bits we cannot change.  */
154       && unlikely (fchmod (elf->fildes, st.st_mode) != 0))
155     {
156       __libelf_seterrno (ELF_E_WRITE_ERROR);
157       size = -1;
158     }
159 
160   if (size != -1 && elf->parent == NULL)
161     elf->maximum_size = size;
162 
163   return size;
164 }
165 
166 
167 int64_t
elf_update(Elf * elf,Elf_Cmd cmd)168 elf_update (Elf *elf, Elf_Cmd cmd)
169 {
170   size_t shnum;
171   int64_t size;
172   int change_bo = 0;
173 
174   if (cmd != ELF_C_NULL
175       && cmd != ELF_C_WRITE
176       && unlikely (cmd != ELF_C_WRITE_MMAP))
177     {
178       __libelf_seterrno (ELF_E_INVALID_CMD);
179       return -1;
180     }
181 
182   if (elf == NULL)
183     return -1;
184 
185   if (elf->kind != ELF_K_ELF)
186     {
187       __libelf_seterrno (ELF_E_INVALID_HANDLE);
188       return -1;
189     }
190 
191   rwlock_wrlock (elf->lock);
192 
193   /* Make sure we have an ELF header.  */
194   if (elf->state.elf.ehdr == NULL)
195     {
196       __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
197       size = -1;
198       goto out;
199     }
200 
201   /* Determine the number of sections.  */
202   shnum = (elf->state.elf.scns_last->cnt == 0
203 	   ? 0
204 	   : 1 + elf->state.elf.scns_last->data[elf->state.elf.scns_last->cnt - 1].index);
205 
206   /* Update the ELF descriptor.  First, place the program header.  It
207      will come right after the ELF header.  The count the size of all
208      sections and finally place the section table.  */
209   size = (elf->class == ELFCLASS32
210 	  ? __elf32_updatenull_wrlock (elf, &change_bo, shnum)
211 	  : __elf64_updatenull_wrlock (elf, &change_bo, shnum));
212   if (likely (size != -1)
213       /* See whether we actually have to write out the data.  */
214       && (cmd == ELF_C_WRITE || cmd == ELF_C_WRITE_MMAP))
215     {
216       if (elf->cmd != ELF_C_RDWR
217 	  && elf->cmd != ELF_C_RDWR_MMAP
218 	  && elf->cmd != ELF_C_WRITE
219 	  && unlikely (elf->cmd != ELF_C_WRITE_MMAP))
220 	{
221 	  __libelf_seterrno (ELF_E_UPDATE_RO);
222 	  size = -1;
223 	}
224       else if (unlikely (elf->fildes == -1))
225 	{
226 	  /* We closed the file already.  */
227 	  __libelf_seterrno (ELF_E_FD_DISABLED);
228 	  size = -1;
229 	}
230       else
231 	size = write_file (elf, size, change_bo, shnum);
232     }
233 
234  out:
235   rwlock_unlock (elf->lock);
236 
237   return size;
238 }
239