summaryrefslogtreecommitdiffstats
path: root/libelf/elf_update.c
diff options
context:
space:
mode:
authorRoland McGrath <[email protected]>2005-09-11 08:49:19 +0000
committerRoland McGrath <[email protected]>2005-09-11 08:49:19 +0000
commit843f6f57d7c89a49479ee4567aedd0d5069f102e (patch)
tree031caa0042377bde8ead8836a00570146446df43 /libelf/elf_update.c
parent7690fe2db71092a07d2c76169303d72ca4d9518c (diff)
2005-09-09 Roland McGrath <[email protected]>
* elf_update.c (write_file): Stat the file and fchmod it after update if its mode had S_ISUID or S_ISGID bits set.
Diffstat (limited to 'libelf/elf_update.c')
-rw-r--r--libelf/elf_update.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/libelf/elf_update.c b/libelf/elf_update.c
index 5d6c6b7a..f380e2b9 100644
--- a/libelf/elf_update.c
+++ b/libelf/elf_update.c
@@ -22,6 +22,7 @@
#include <libelf.h>
#include <unistd.h>
#include <sys/mman.h>
+#include <sys/stat.h>
#include "libelfP.h"
@@ -31,6 +32,14 @@ write_file (Elf *elf, off_t size, int change_bo, size_t shnum)
{
int class = elf->class;
+ /* Check the mode bits now, before modification might change them. */
+ struct stat st;
+ if (unlikely (fstat (elf->fildes, &st) != 0))
+ {
+ __libelf_seterrno (ELF_E_WRITE_ERROR);
+ return -1;
+ }
+
/* Adjust the size in any case. We do this even if we use `write'.
We cannot do this if this file is in an archive. We also don't
do it *now* if we are shortening the file since this would
@@ -87,6 +96,18 @@ write_file (Elf *elf, off_t size, int change_bo, size_t shnum)
size = -1;
}
+ /* POSIX says that ftruncate and write may clear the S_ISUID and S_ISGID
+ mode bits. So make sure we restore them afterwards if they were set.
+ This is not atomic if someone else chmod's the file while we operate. */
+ if (size != -1
+ && unlikely (st.st_mode & (S_ISUID | S_ISGID))
+ /* fchmod ignores the bits we cannot change. */
+ && unlikely (fchmod (elf->fildes, st.st_mode) != 0))
+ {
+ __libelf_seterrno (ELF_E_WRITE_ERROR);
+ size = -1;
+ }
+
if (size != -1 && elf->parent == NULL)
elf->maximum_size = size;