diff --git a/llvm/test/tools/llvm-objcopy/ELF/execute-permissions.test b/llvm/test/tools/llvm-objcopy/ELF/execute-permissions.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/execute-permissions.test @@ -0,0 +1,25 @@ +# UNSUPPORTED: windows +# REQUIRES: shell + +# RUN: umask 0 +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy %t %t1 +# RUN: test -x %t1 + +# RUN: chmod 0666 %t +# RUN: llvm-objcopy %t %t1 +# RUN: test -x %t1 + +# RUN: llvm-objcopy %p/Inputs/alloc-symtab.o %t1 +# RUN: test ! -x %t1 + +# RUN: chmod 0777 %t1 +# RUN: llvm-objcopy %t1 %t1 +# RUN: test ! -x %t1 + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 diff --git a/llvm/test/tools/llvm-objcopy/ELF/respect-umask.test b/llvm/test/tools/llvm-objcopy/ELF/respect-umask.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/ELF/respect-umask.test @@ -0,0 +1,28 @@ +# UNSUPPORTED: windows + +# RUN: touch test +# RUN: chmod 0777 test +# RUN: ls -l test | cut -f 1 -d ' ' > %t.0777 +# RUN: chmod 0666 test +# RUN: ls -l test | cut -f 1 -d ' ' > %t.0666 +# RUN: chmod 0640 test +# RUN: ls -l test | cut -f 1 -d ' ' > %t.0640 +# RUN: chmod 0750 test +# RUN: ls -l test | cut -f 1 -d ' ' > %t.0750 +# RUN: rm test + +# RUN: umask 0 +# RUN: llvm-objcopy %p/Inputs/alloc-symtab.o %t +# RUN: ls -l %t | cut -f 1 -d ' ' > %t.perm +# RUN: cmp %t.0666 %t.perm +# RUN: llvm-objcopy %p/Inputs/dynrel.elf %t +# RUN: ls -l %t | cut -f 1 -d ' ' > %t.perm +# RUN: cmp %t.0777 %t.perm + +# RUN: umask 027 +# RUN: llvm-objcopy %p/Inputs/alloc-symtab.o %t +# RUN: ls -l %t | cut -f 1 -d ' ' > %t.perm +# RUN: cmp %t.0640 %t.perm +# RUN: llvm-objcopy %p/Inputs/dynrel.elf %t +# RUN: ls -l %t | cut -f 1 -d ' ' > %t.perm +# RUN: cmp %t.0750 %t.perm diff --git a/llvm/tools/llvm-objcopy/Buffer.h b/llvm/tools/llvm-objcopy/Buffer.h --- a/llvm/tools/llvm-objcopy/Buffer.h +++ b/llvm/tools/llvm-objcopy/Buffer.h @@ -37,6 +37,7 @@ class FileBuffer : public Buffer { std::unique_ptr<FileOutputBuffer> Buf; + unsigned Flags; // Indicates that allocate(0) was called, and commit() should create or // truncate a file instead of using a FileOutputBuffer. bool EmptyFile = false; @@ -46,7 +47,8 @@ uint8_t *getBufferStart() override; Error commit() override; - explicit FileBuffer(StringRef FileName) : Buffer(FileName) {} + explicit FileBuffer(StringRef FileName, unsigned Flags = 0) + : Buffer(FileName), Flags(Flags) {} }; class MemBuffer : public Buffer { diff --git a/llvm/tools/llvm-objcopy/Buffer.cpp b/llvm/tools/llvm-objcopy/Buffer.cpp --- a/llvm/tools/llvm-objcopy/Buffer.cpp +++ b/llvm/tools/llvm-objcopy/Buffer.cpp @@ -36,7 +36,7 @@ } Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = - FileOutputBuffer::create(getName(), Size, FileOutputBuffer::F_executable); + FileOutputBuffer::create(getName(), Size, Flags); // FileOutputBuffer::create() returns an Error that is just a wrapper around // std::error_code. Wrap it in FileError to include the actual filename. if (!BufferOrErr) diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -149,6 +149,17 @@ "Unsupported object file format"); } +static bool isExecutableObject(object::Binary &Binary) { + if (auto *ELFObj = dyn_cast<object::ELFObjectFileBase>(&Binary)) + return ELFObj->getEType() & ELF::ET_EXEC; + else if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(&Binary)) + return COFFObj->getCharacteristics() & COFF::IMAGE_FILE_EXECUTABLE_IMAGE; + else if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Binary)) + return MachOObj->getHeader().filetype == MachO::MH_EXECUTE; + + return false; +} + static Error executeObjcopyOnArchive(const CopyConfig &Config, const Archive &Ar) { std::vector<NewArchiveMember> NewArchiveMembers; @@ -164,7 +175,8 @@ ChildOrErr.takeError()); MemBuffer MB(ChildNameOrErr.get()); - if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MB)) + object::Binary &Binary = *ChildOrErr->get(); + if (Error E = executeObjcopyOnBinary(Config, Binary, MB)) return E; Expected<NewArchiveMember> Member = @@ -173,6 +185,7 @@ return createFileError(Ar.getFileName(), Member.takeError()); Member->Buf = MB.releaseMemoryBuffer(); Member->MemberName = Member->Buf->getBufferIdentifier(); + Member->Perms = isExecutableObject(Binary) ? 0777 : 0666; NewArchiveMembers.push_back(std::move(*Member)); } if (Err) @@ -227,9 +240,11 @@ if (Error E = executeObjcopyOnArchive(Config, *Ar)) return E; } else { - FileBuffer FB(Config.OutputFilename); - if (Error E = executeObjcopyOnBinary(Config, - *BinaryOrErr.get().getBinary(), FB)) + object::Binary &Binary = *BinaryOrErr.get().getBinary(); + FileBuffer FB(Config.OutputFilename, isExecutableObject(Binary) + ? FileOutputBuffer::F_executable + : 0); + if (Error E = executeObjcopyOnBinary(Config, Binary, FB)) return E; } }