• 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 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