@@ -1890,6 +1890,104 @@ 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_Addr firstPage = 0 ;
1950+ for (const auto & phdr : phdrs) {
1951+ if (rdi (phdr.p_type ) == PT_PHDR) {
1952+ firstPage = rdi (phdr.p_vaddr ) - rdi (phdr.p_offset );
1953+ break ;
1954+ }
1955+ }
1956+
1957+ Elf_Phdr new_phdr;
1958+ wri (new_phdr.p_type , PT_GNU_STACK);
1959+ wri (new_phdr.p_offset , 0 );
1960+ wri (new_phdr.p_vaddr , 0 );
1961+ wri (new_phdr.p_paddr , 0 );
1962+ wri (new_phdr.p_filesz , 0 );
1963+ wri (new_phdr.p_memsz , 0 );
1964+ wri (new_phdr.p_flags , PF_R | PF_W | (op == ExecstackMode::set ? PF_X : 0 ));
1965+ wri (new_phdr.p_align , getPageSize ());
1966+ phdrs.push_back (new_phdr);
1967+
1968+ wri (hdr ()->e_phnum , rdi (hdr ()->e_phnum ) + 1 );
1969+
1970+ changed = true ;
1971+ rewriteHeaders (firstPage + rdi (hdr ()->e_phoff ));
1972+ return ;
1973+ }
1974+
1975+ char result = ' ?' ;
1976+
1977+ for (const auto & header : phdrs) {
1978+ if (rdi (header.p_type ) != PT_GNU_STACK)
1979+ continue ;
1980+
1981+ if ((rdi (header.p_flags ) & PF_X) == PF_X)
1982+ result = ' X' ;
1983+ else
1984+ result = ' -' ;
1985+ break ;
1986+ }
1987+
1988+ printf (" execstack: %c\n " , result);
1989+ }
1990+
18931991static bool printInterpreter = false ;
18941992static bool printOsAbi = false ;
18951993static bool setOsAbi = false ;
@@ -1912,6 +2010,9 @@ static std::set<std::string> neededLibsToAdd;
19122010static std::set<std::string> symbolsToClearVersion;
19132011static bool printNeeded = false ;
19142012static bool noDefaultLib = false ;
2013+ static bool printExecstack = false ;
2014+ static bool clearExecstack = false ;
2015+ static bool setExecstack = false ;
19152016
19162017template <class ElfFile >
19172018static void patchElf2 (ElfFile && elfFile, const FileContents & fileContents, const std::string & fileName)
@@ -1937,6 +2038,13 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
19372038 if (printRPath)
19382039 elfFile.modifyRPath (elfFile.rpPrint , {}, " " );
19392040
2041+ if (printExecstack)
2042+ elfFile.modifyExecstack (ElfFile::ExecstackMode::print);
2043+ else if (clearExecstack)
2044+ elfFile.modifyExecstack (ElfFile::ExecstackMode::clear);
2045+ else if (setExecstack)
2046+ elfFile.modifyExecstack (ElfFile::ExecstackMode::set);
2047+
19402048 if (shrinkRPath)
19412049 elfFile.modifyRPath (elfFile.rpShrink , allowedRpathPrefixes, " " );
19422050 else if (removeRPath)
@@ -2019,6 +2127,9 @@ void showHelp(const std::string & progName)
20192127 [--no-sort]\t\t Do not sort program+section headers; useful for debugging patchelf.\n \
20202128 [--clear-symbol-version SYMBOL]\n \
20212129 [--add-debug-tag]\n \
2130+ [--print-execstack]\t\t Prints whether the object requests an executable stack\n \
2131+ [--clear-execstack]\n \
2132+ [--set-execstack]\n \
20222133 [--output FILE]\n \
20232134 [--debug]\n \
20242135 [--version]\n \
@@ -2127,6 +2238,15 @@ int mainWrapped(int argc, char * * argv)
21272238 if (++i == argc) error (" missing argument" );
21282239 symbolsToClearVersion.insert (resolveArgument (argv[i]));
21292240 }
2241+ else if (arg == " --print-execstack" ) {
2242+ printExecstack = true ;
2243+ }
2244+ else if (arg == " --clear-execstack" ) {
2245+ clearExecstack = true ;
2246+ }
2247+ else if (arg == " --set-execstack" ) {
2248+ setExecstack = true ;
2249+ }
21302250 else if (arg == " --output" ) {
21312251 if (++i == argc) error (" missing argument" );
21322252 outputFileName = resolveArgument (argv[i]);
0 commit comments