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