summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Sateler <fsateler@debian.org>2020-06-13 13:22:35 -0400
committerFelipe Sateler <fsateler@debian.org>2020-06-13 13:22:35 -0400
commita9bbb749708a9a95a3a47f9f8e0d821cb70b88c0 (patch)
tree0708aba20246b43b5378114cfbb53e4f4bcd5e96
parenta20084913c1ef6f29f5dceeaa57c2cdcc4f6281f (diff)
parent7e6baf40858df0000efe2227e2c29217e6e06389 (diff)
Update upstream source from tag 'upstream/0.11'
Update to upstream version '0.11' with Debian dir 7c62fdbfa53e69ee2f082ca3204e06e6951e53e9
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md27
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md20
-rw-r--r--.github/workflows/ci.yml13
-rw-r--r--Makefile.am4
-rw-r--r--README.md (renamed from README)35
-rw-r--r--flake.lock28
-rw-r--r--flake.nix41
-rw-r--r--patchelf.16
-rw-r--r--patchelf.spec.in2
-rw-r--r--release.nix21
-rw-r--r--src/patchelf.cc62
-rw-r--r--tests/Makefile.am4
-rwxr-xr-xtests/force-rpath.sh39
-rwxr-xr-xtests/output-flag.sh38
-rwxr-xr-xtests/set-rpath-library.sh1
-rw-r--r--version2
16 files changed, 280 insertions, 63 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..96872a0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,27 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: bug
+assignees: ''
+
+---
+
+**Describe the bug**
+
+A clear and concise description of what the bug is.
+
+**Steps To Reproduce**
+
+Please include exact steps with an attached binary so that
+another person can reproduce the problem.
+
+**Expected behavior**
+
+A clear and concise description of what you expected to happen.
+
+**`patchelf --version` output**
+
+**Additional context**
+
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..392ed30
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: improvement
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..a4c6829
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,13 @@
+name: "CI"
+on:
+ pull_request:
+ push:
+jobs:
+ tests:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: cachix/install-nix-action@v9
+ with:
+ skip_adding_nixpkgs_channel: true
+ - run: nix-build release.nix
diff --git a/Makefile.am b/Makefile.am
index aa0d513..188f898 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
SUBDIRS = src tests
-EXTRA_DIST = COPYING README patchelf.spec version $(man1_MANS)
+EXTRA_DIST = COPYING README.md patchelf.spec version $(man1_MANS)
man1_MANS = patchelf.1
-doc_DATA = README
+doc_DATA = README.md
diff --git a/README b/README.md
index 60441ec..5d2fd5c 100644
--- a/README
+++ b/README.md
@@ -52,22 +52,20 @@ libraries. In particular, it can do the following:
$ patchelf --set-soname libnewname.so.3.4.5 path/to/libmylibrary.so.1.2.3
-INSTALLING
+## COMPILING & TESTING
-You can download a pre-compiled binary from the releases or compile it by yourself:
+ ./bootstrap.sh
+ ./configure
+ make
+ sudo make install
+ make check
- ./bootstrap.sh
- ./configure
- make
- sudo make install
-
-
-AUTHOR
+## AUTHOR
Copyright 2004-2019 Eelco Dolstra <edolstra@gmail.com>.
-LICENSE
+## LICENSE
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -82,22 +80,13 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
+## RELEASE HISTORY
-HOMEPAGE
-
-http://nixos.org/patchelf.html
-
-
-BUGS
-
-The `strip' command from binutils generated broken executables when
-applied to the output of patchelf (if `--set-rpath' or
-`--set-interpreter' with a larger path than the original is used).
-This appears to be a bug in binutils
-(http://bugs.strategoxt.org/browse/NIXPKGS-85).
+0.11 (June 9, 2020):
+* New `--output` flag.
-RELEASE HISTORY
+* Some bug fixes.
0.10 (March 28, 2019):
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..5d516b4
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,28 @@
+{
+ "nodes": {
+ "nixpkgs": {
+ "info": {
+ "lastModified": 1590140420,
+ "narHash": "sha256-ozgGYyqGHoEKvgL00r6G0ht+ODXHuhpfW37IYxAda0A="
+ },
+ "locked": {
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "48723f48ab92381f0afd50143f38e45cf3080405",
+ "type": "github"
+ },
+ "original": {
+ "id": "nixpkgs",
+ "ref": "nixos-20.03",
+ "type": "indirect"
+ }
+ },
+ "root": {
+ "inputs": {
+ "nixpkgs": "nixpkgs"
+ }
+ }
+ },
+ "root": "root",
+ "version": 5
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..5ba87db
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,41 @@
+{
+ description = "A tool for modifying ELF executables and libraries";
+
+ inputs.nixpkgs.url = "nixpkgs/nixos-20.03";
+
+ outputs = { self, nixpkgs }:
+
+ let
+ supportedSystems = [ "x86_64-linux" "i686-linux" "aarch64-linux" ];
+ forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system);
+ in
+
+ rec {
+
+ overlay = final: prev: {
+
+ patchelf-new = final.stdenv.mkDerivation {
+ name = "patchelf-${hydraJobs.tarball.version}";
+ src = "${hydraJobs.tarball}/tarballs/*.tar.bz2";
+ };
+
+ };
+
+ hydraJobs = import ./release.nix {
+ patchelfSrc = self;
+ nixpkgs = nixpkgs;
+ };
+
+ checks = forAllSystems (system: {
+ build = hydraJobs.build.${system};
+ });
+
+ defaultPackage = forAllSystems (system:
+ (import nixpkgs {
+ inherit system;
+ overlays = [ self.overlay ];
+ }).patchelf-new
+ );
+
+ };
+}
diff --git a/patchelf.1 b/patchelf.1
index 43a5d24..8c998ad 100644
--- a/patchelf.1
+++ b/patchelf.1
@@ -10,6 +10,7 @@ patchelf - Modify ELF files
.I OPTION
.B
.I FILE
+.SM ...
.B
.SH DESCRIPTION
@@ -20,7 +21,7 @@ of executables and change the RPATH of executables and libraries.
.SH OPTIONS
-The single option given operates on a given FILE, editing in place.
+The single option given operates on each FILE, editing in place.
.IP "--page-size SIZE"
Uses the given page size instead of the default.
@@ -82,6 +83,9 @@ option can be given multiple times.
Marks the object that the search for dependencies of this object will ignore any
default library search paths.
+.IP "--output FILE"
+Set the output file name. If not specified, the input will be modified in place.
+
.IP --debug
Prints details of the changes made to the input file.
diff --git a/patchelf.spec.in b/patchelf.spec.in
index d0f326f..5569026 100644
--- a/patchelf.spec.in
+++ b/patchelf.spec.in
@@ -34,5 +34,5 @@ rm -rf $RPM_BUILD_ROOT
%files
%{_bindir}/patchelf
-%doc %{_docdir}/patchelf/README
+%doc %{_docdir}/patchelf/README.md
%{_mandir}/man1/patchelf.1.gz
diff --git a/release.nix b/release.nix
index 55bb37b..06bf91d 100644
--- a/release.nix
+++ b/release.nix
@@ -1,10 +1,11 @@
{ patchelfSrc ? { outPath = ./.; revCount = 1234; shortRev = "abcdef"; }
+, nixpkgs ? builtins.fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/nixos-20.03.tar.gz
, officialRelease ? false
}:
let
- pkgs = import <nixpkgs> { };
+ pkgs = import nixpkgs { system = builtins.currentSystem or "x86_64-linux"; };
jobs = rec {
@@ -13,13 +14,19 @@ let
tarball =
pkgs.releaseTools.sourceTarball rec {
name = "patchelf-tarball";
- version = builtins.readFile ./version + (if officialRelease then "" else "pre${toString patchelfSrc.revCount}_${patchelfSrc.shortRev}");
+ version = builtins.readFile ./version +
+ (if officialRelease then "" else
+ "." +
+ ((if patchelfSrc ? lastModifiedDate
+ then builtins.substring 0 8 patchelfSrc.lastModifiedDate
+ else toString patchelfSrc.revCount or 0)
+ + "." + patchelfSrc.shortRev));
versionSuffix = ""; # obsolete
src = patchelfSrc;
preAutoconf = "echo ${version} > version";
postDist = ''
- cp README $out/
- echo "doc readme $out/README" >> $out/nix-support/hydra-build-products
+ cp README.md $out/
+ echo "doc readme $out/README.md" >> $out/nix-support/hydra-build-products
'';
};
@@ -34,7 +41,7 @@ let
build = pkgs.lib.genAttrs [ "x86_64-linux" "i686-linux" "aarch64-linux" /* "x86_64-freebsd" "i686-freebsd" "x86_64-darwin" "i686-solaris" "i686-cygwin" */ ] (system:
- with import <nixpkgs> { inherit system; };
+ with import nixpkgs { inherit system; };
releaseTools.nixBuild {
name = "patchelf";
@@ -81,7 +88,7 @@ let
makeRPM =
system: diskImageFun:
- with import <nixpkgs> { inherit system; };
+ with import nixpkgs { inherit system; };
releaseTools.rpmBuild rec {
name = "patchelf-rpm";
@@ -97,7 +104,7 @@ let
makeDeb =
system: diskImageFun:
- with import <nixpkgs> { inherit system; };
+ with import nixpkgs { inherit system; };
releaseTools.debBuild {
name = "patchelf-deb";
diff --git a/src/patchelf.cc b/src/patchelf.cc
index 0b4965a..965686a 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -46,6 +46,8 @@ static bool debugMode = false;
static bool forceRPath = false;
static std::vector<std::string> fileNames;
+static std::string outputFileName;
+static bool alwaysWrite = false;
static int pageSize = PAGESIZE;
typedef std::shared_ptr<std::vector<unsigned char>> FileContents;
@@ -497,7 +499,9 @@ void ElfFile<ElfFileParamNames>::sortShdrs()
static void writeFile(std::string fileName, FileContents contents)
{
- int fd = open(fileName.c_str(), O_TRUNC | O_WRONLY);
+ debug("writing %s\n", fileName.c_str());
+
+ int fd = open(fileName.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0777);
if (fd == -1)
error("open");
@@ -742,14 +746,13 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
since DYN executables tend to start at virtual address 0, so
rewriteSectionsExecutable() won't work because it doesn't have
any virtual address space to grow downwards into. */
- if (isExecutable) {
- if (startOffset >= startPage) {
- debug("shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n", startOffset - startPage);
- }
+ if (isExecutable && startOffset > startPage) {
+ debug("shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n", startOffset - startPage);
startPage = startOffset;
}
/* Add a segment that maps the replaced sections into memory. */
+ wri(hdr->e_phoff, sizeof(Elf_Ehdr));
phdrs.resize(rdi(hdr->e_phnum) + 1);
wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1);
Elf_Phdr & phdr = phdrs[rdi(hdr->e_phnum) - 1];
@@ -1074,13 +1077,6 @@ void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string &
return;
}
- /* Zero out the previous SONAME */
- unsigned int sonameSize = 0;
- if (soname) {
- sonameSize = strlen(soname);
- memset(soname, 'X', sonameSize);
- }
-
debug("new SONAME is '%s'\n", newSoname.c_str());
/* Grow the .dynstr section to make room for the new SONAME. */
@@ -1255,7 +1251,17 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
}
- if (std::string(rpath ? rpath : "") == newRPath) return;
+ if (!forceRPath && dynRPath && !dynRunPath) { /* convert DT_RPATH to DT_RUNPATH */
+ dynRPath->d_tag = DT_RUNPATH;
+ dynRunPath = dynRPath;
+ dynRPath = 0;
+ } else if (forceRPath && dynRunPath) { /* convert DT_RUNPATH to DT_RPATH */
+ dynRunPath->d_tag = DT_RPATH;
+ dynRPath = dynRunPath;
+ dynRunPath = 0;
+ } else if (std::string(rpath ? rpath : "") == newRPath) {
+ return;
+ }
changed = true;
@@ -1269,15 +1275,6 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
debug("new rpath is '%s'\n", newRPath.c_str());
- if (!forceRPath && dynRPath && !dynRunPath) { /* convert DT_RPATH to DT_RUNPATH */
- dynRPath->d_tag = DT_RUNPATH;
- dynRunPath = dynRPath;
- dynRPath = 0;
- }
-
- if (forceRPath && dynRPath && dynRunPath) { /* convert DT_RUNPATH to DT_RPATH */
- dynRunPath->d_tag = DT_IGNORE;
- }
if (newRPath.size() <= rpathSize) {
strcpy(rpath, newRPath.c_str());
@@ -1567,7 +1564,7 @@ static bool printNeeded = false;
static bool noDefaultLib = false;
template<class ElfFile>
-static void patchElf2(ElfFile && elfFile, std::string fileName)
+static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, std::string fileName)
{
if (printInterpreter)
printf("%s\n", elfFile.getInterpreter().c_str());
@@ -1603,6 +1600,9 @@ static void patchElf2(ElfFile && elfFile, std::string fileName)
if (elfFile.isChanged()){
elfFile.rewriteSections();
writeFile(fileName, elfFile.fileContents);
+ } else if (alwaysWrite) {
+ debug("not modified, but alwaysWrite=true\n");
+ writeFile(fileName, fileContents);
}
}
@@ -1616,11 +1616,12 @@ static void patchElf()
debug("Kernel page size is %u bytes\n", getPageSize());
auto fileContents = readFile(fileName);
+ std::string outputFileName2 = outputFileName.empty() ? fileName : outputFileName;
if (getElfType(fileContents).is32Bit)
- patchElf2(ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed>(fileContents), fileName);
+ patchElf2(ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed>(fileContents), fileContents, outputFileName2);
else
- patchElf2(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed>(fileContents), fileName);
+ patchElf2(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed>(fileContents), fileContents, outputFileName2);
}
}
@@ -1644,9 +1645,10 @@ void showHelp(const std::string & progName)
[--replace-needed LIBRARY NEW_LIBRARY]\n\
[--print-needed]\n\
[--no-default-lib]\n\
+ [--output FILE]\n\
[--debug]\n\
[--version]\n\
- FILENAME\n", progName.c_str());
+ FILENAME...\n", progName.c_str());
}
@@ -1730,6 +1732,11 @@ int mainWrapped(int argc, char * * argv)
neededLibsToReplace[ argv[i+1] ] = argv[i+2];
i += 2;
}
+ else if (arg == "--output") {
+ if (++i == argc) error("missing argument");
+ outputFileName = argv[i];
+ alwaysWrite = true;
+ }
else if (arg == "--debug") {
debugMode = true;
}
@@ -1751,6 +1758,9 @@ int mainWrapped(int argc, char * * argv)
if (fileNames.empty()) error("missing filename");
+ if (!outputFileName.empty() && fileNames.size() != 1)
+ error("--output option only allowed with single input file");
+
patchElf();
return 0;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 32218e8..96339b3 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -21,7 +21,9 @@ no_rpath_arch_TESTS = \
src_TESTS = \
plain-fail.sh plain-run.sh shrink-rpath.sh set-interpreter-short.sh \
set-interpreter-long.sh set-rpath.sh no-rpath.sh big-dynstr.sh \
- set-rpath-library.sh soname.sh shrink-rpath-with-allowed-prefixes.sh
+ set-rpath-library.sh soname.sh shrink-rpath-with-allowed-prefixes.sh \
+ force-rpath.sh \
+ output-flag.sh
build_TESTS = \
$(no_rpath_arch_TESTS)
diff --git a/tests/force-rpath.sh b/tests/force-rpath.sh
new file mode 100755
index 0000000..9256905
--- /dev/null
+++ b/tests/force-rpath.sh
@@ -0,0 +1,39 @@
+#! /bin/sh -e
+SCRATCH=scratch/$(basename $0 .sh)
+
+rm -rf ${SCRATCH}
+mkdir -p ${SCRATCH}
+
+SCRATCHFILE=${SCRATCH}/libfoo.so
+cp libfoo.so $SCRATCHFILE
+
+doit() {
+ echo patchelf $*
+ ../src/patchelf $* $SCRATCHFILE
+}
+
+expect() {
+ out=$(echo $(objdump -x $SCRATCHFILE | grep PATH))
+
+ if [ "$out" != "$*" ]; then
+ echo "Expected '$*' but got '$out'"
+ exit 1
+ fi
+}
+
+doit --remove-rpath
+expect
+doit --set-rpath foo
+expect RUNPATH foo
+doit --force-rpath --set-rpath foo
+expect RPATH foo
+doit --force-rpath --set-rpath bar
+expect RPATH bar
+doit --remove-rpath
+expect
+doit --force-rpath --set-rpath foo
+expect RPATH foo
+doit --set-rpath foo
+expect RUNPATH foo
+doit --set-rpath bar
+expect RUNPATH bar
diff --git a/tests/output-flag.sh b/tests/output-flag.sh
new file mode 100755
index 0000000..5da26b5
--- /dev/null
+++ b/tests/output-flag.sh
@@ -0,0 +1,38 @@
+#! /bin/sh -e
+SCRATCH=scratch/$(basename $0 .sh)
+
+rm -rf ${SCRATCH}
+mkdir -p ${SCRATCH}
+mkdir -p ${SCRATCH}/libsA
+mkdir -p ${SCRATCH}/libsB
+
+cp main ${SCRATCH}/
+cp libfoo.so ${SCRATCH}/libsA/
+cp libbar.so ${SCRATCH}/libsB/
+
+oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main)
+if test -z "$oldRPath"; then oldRPath="/oops"; fi
+
+../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main --output ${SCRATCH}/main2
+# make sure it copies even when there is nothing to do (because rpath is already set)
+../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main2 --output ${SCRATCH}/main3
+
+if test "$(uname)" = FreeBSD; then
+ export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB
+fi
+
+exitCode=0
+(cd ${SCRATCH} && ./main2) || exitCode=$?
+
+if test "$exitCode" != 46; then
+ echo "bad exit code!"
+ exit 1
+fi
+
+exitCode=0
+(cd ${SCRATCH} && ./main3) || exitCode=$?
+
+if test "$exitCode" != 46; then
+ echo "bad exit code!"
+ exit 1
+fi
diff --git a/tests/set-rpath-library.sh b/tests/set-rpath-library.sh
index dd1381f..a5c8ca7 100755
--- a/tests/set-rpath-library.sh
+++ b/tests/set-rpath-library.sh
@@ -26,7 +26,6 @@ exitCode=0
if test "$exitCode" = 46; then
echo "expected failure"
- exit 1
fi
# So set an RUNPATH on libfoo as well.
diff --git a/version b/version
index 688abaa..0eb4182 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-0.10 \ No newline at end of file
+0.11 \ No newline at end of file