@@ -1010,10 +1010,10 @@ void ElfFile<ElfFileParamNames>::normalizeNoteSegments()
10101010
10111011
10121012template <ElfFileParams>
1013- void ElfFile<ElfFileParamNames>::rewriteSections()
1013+ void ElfFile<ElfFileParamNames>::rewriteSections(bool force )
10141014{
10151015
1016- if (replacedSections.empty ()) return ;
1016+ if (!force && replacedSections.empty ()) return ;
10171017
10181018 for (auto & i : replacedSections)
10191019 debug (" replacing section '%s' with size %d\n " ,
@@ -1890,6 +1890,96 @@ void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string>
18901890 this ->rewriteSections ();
18911891}
18921892
1893+ template <ElfFileParams>
1894+ void ElfFile<ElfFileParamNames>::modifyExecstack(ExecstackMode op)
1895+ {
1896+ if (op == ExecstackMode::clear || op == ExecstackMode::set) {
1897+ size_t nullhdr = (size_t )-1 ;
1898+
1899+ for (size_t i = 0 ; i < phdrs.size (); i++) {
1900+ auto & header = phdrs[i];
1901+ const auto type = rdi (header.p_type );
1902+ if (type != PT_GNU_STACK) {
1903+ if (!nullhdr && type == PT_NULL)
1904+ nullhdr = i;
1905+ continue ;
1906+ }
1907+
1908+ if (op == ExecstackMode::clear && (rdi (header.p_flags ) & PF_X) == PF_X) {
1909+ debug (" simple execstack clear of header %zu\n " , i);
1910+
1911+ wri (header.p_flags , rdi (header.p_flags ) & ~PF_X);
1912+
1913+ * ((Elf_Phdr *) (fileContents->data () + rdi (hdr ()->e_phoff )) + i) = header;
1914+ changed = true ;
1915+ } else if (op == ExecstackMode::set && (rdi (header.p_flags ) & PF_X) != PF_X) {
1916+ debug (" simple execstack set of header %zu\n " , i);
1917+
1918+ wri (header.p_flags , rdi (header.p_flags ) | PF_X);
1919+
1920+ * ((Elf_Phdr *) (fileContents->data () + rdi (hdr ()->e_phoff )) + i) = header;
1921+ changed = true ;
1922+ } else {
1923+ debug (" execstack already in requested state\n " );
1924+ }
1925+
1926+ return ;
1927+ }
1928+
1929+ if (nullhdr != (size_t )-1 ) {
1930+ debug (" replacement execstack of header %zu\n " , nullhdr);
1931+
1932+ auto & header = phdrs[nullhdr];
1933+ wri (header.p_type , PT_GNU_STACK);
1934+ wri (header.p_offset , 0 );
1935+ wri (header.p_vaddr , 0 );
1936+ wri (header.p_paddr , 0 );
1937+ wri (header.p_filesz , 0 );
1938+ wri (header.p_memsz , 0 );
1939+ wri (header.p_flags , PF_R | PF_W | (op == ExecstackMode::set ? PF_X : 0 ));
1940+ wri (header.p_align , getPageSize ());
1941+
1942+ * ((Elf_Phdr *) (fileContents->data () + rdi (hdr ()->e_phoff )) + nullhdr) = header;
1943+ changed = true ;
1944+ return ;
1945+ }
1946+
1947+ debug (" header addition for execstack\n " );
1948+
1949+ Elf_Phdr new_phdr;
1950+ wri (new_phdr.p_type , PT_GNU_STACK);
1951+ wri (new_phdr.p_offset , 0 );
1952+ wri (new_phdr.p_vaddr , 0 );
1953+ wri (new_phdr.p_paddr , 0 );
1954+ wri (new_phdr.p_filesz , 0 );
1955+ wri (new_phdr.p_memsz , 0 );
1956+ wri (new_phdr.p_flags , PF_R | PF_W | (op == ExecstackMode::set ? PF_X : 0 ));
1957+ wri (new_phdr.p_align , getPageSize ());
1958+ phdrs.push_back (new_phdr);
1959+
1960+ wri (hdr ()->e_phnum , rdi (hdr ()->e_phnum ) + 1 );
1961+
1962+ changed = true ;
1963+ rewriteSections (true );
1964+ return ;
1965+ }
1966+
1967+ char result = ' ?' ;
1968+
1969+ for (const auto & header : phdrs) {
1970+ if (rdi (header.p_type ) != PT_GNU_STACK)
1971+ continue ;
1972+
1973+ if ((rdi (header.p_flags ) & PF_X) == PF_X)
1974+ result = ' X' ;
1975+ else
1976+ result = ' -' ;
1977+ break ;
1978+ }
1979+
1980+ printf (" execstack: %c\n " , result);
1981+ }
1982+
18931983static bool printInterpreter = false ;
18941984static bool printOsAbi = false ;
18951985static bool setOsAbi = false ;
@@ -1912,6 +2002,9 @@ static std::set<std::string> neededLibsToAdd;
19122002static std::set<std::string> symbolsToClearVersion;
19132003static bool printNeeded = false ;
19142004static bool noDefaultLib = false ;
2005+ static bool printExecstack = false ;
2006+ static bool clearExecstack = false ;
2007+ static bool setExecstack = false ;
19152008
19162009template <class ElfFile >
19172010static void patchElf2 (ElfFile && elfFile, const FileContents & fileContents, const std::string & fileName)
@@ -1937,6 +2030,13 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
19372030 if (printRPath)
19382031 elfFile.modifyRPath (elfFile.rpPrint , {}, " " );
19392032
2033+ if (printExecstack)
2034+ elfFile.modifyExecstack (ElfFile::ExecstackMode::print);
2035+ else if (clearExecstack)
2036+ elfFile.modifyExecstack (ElfFile::ExecstackMode::clear);
2037+ else if (setExecstack)
2038+ elfFile.modifyExecstack (ElfFile::ExecstackMode::set);
2039+
19402040 if (shrinkRPath)
19412041 elfFile.modifyRPath (elfFile.rpShrink , allowedRpathPrefixes, " " );
19422042 else if (removeRPath)
@@ -2019,6 +2119,9 @@ void showHelp(const std::string & progName)
20192119 [--no-sort]\t\t Do not sort program+section headers; useful for debugging patchelf.\n \
20202120 [--clear-symbol-version SYMBOL]\n \
20212121 [--add-debug-tag]\n \
2122+ [--print-execstack]\t\t Prints whether the object requests an executable stack\n \
2123+ [--clear-execstack]\n \
2124+ [--set-execstack]\n \
20222125 [--output FILE]\n \
20232126 [--debug]\n \
20242127 [--version]\n \
@@ -2127,6 +2230,15 @@ int mainWrapped(int argc, char * * argv)
21272230 if (++i == argc) error (" missing argument" );
21282231 symbolsToClearVersion.insert (resolveArgument (argv[i]));
21292232 }
2233+ else if (arg == " --print-execstack" ) {
2234+ printExecstack = true ;
2235+ }
2236+ else if (arg == " --clear-execstack" ) {
2237+ clearExecstack = true ;
2238+ }
2239+ else if (arg == " --set-execstack" ) {
2240+ setExecstack = true ;
2241+ }
21302242 else if (arg == " --output" ) {
21312243 if (++i == argc) error (" missing argument" );
21322244 outputFileName = resolveArgument (argv[i]);
0 commit comments