1 |
Let's start with the code: :) |
2 |
|
3 |
|
4 |
[ra:/var/tmp] % cat test.c |
5 |
#include <openssl/opensslv.h> |
6 |
#include <openssl/md5.h> |
7 |
#include <stdio.h> |
8 |
|
9 |
int main() { |
10 |
MD5_CTX c; |
11 |
unsigned char md[MD5_DIGEST_LENGTH]; |
12 |
|
13 |
printf("%s\n", OPENSSL_VERSION_TEXT); |
14 |
MD5_Init(&c); |
15 |
MD5_Update(&c, "test", 4); |
16 |
MD5_Final(md, &c); |
17 |
} |
18 |
[ra:/var/tmp] % gcc -o test test.c -lssl |
19 |
[ra:/var/tmp] % ldd test |
20 |
libssl.so.0.9.8 => /export/scratch0/GentooPrefix/usr/lib/libssl.so.0.9.8 |
21 |
[ra:/var/tmp] % ./test |
22 |
OpenSSL 0.9.8e 23 Feb 2007 |
23 |
|
24 |
Ok, working binary, linked to openssl 0.9.8 in |
25 |
/export/scratch0/GentooPrefix/usr/lib. Now check this little utility I |
26 |
just checked in: |
27 |
|
28 |
[ra:/var/tmp] % chrpath test |
29 |
test: RPATH=/export/scratch0/GentooPrefix/usr/lib/gcc/i386-pc-solaris2.10/4.1.2:/export/scratch0/GentooPrefix/lib:/export/scratch0/GentooPrefix/usr/lib |
30 |
|
31 |
Ok, this is the rpath that our wrapper injects. |
32 |
|
33 |
[ra:/var/tmp] % chrpath -r /usr/lib/gcc/i386-pc-solaris2.10/4.1.2:/lib:/usr/lib |
34 |
test |
35 |
test: RPATH=/export/scratch0/GentooPrefix/usr/lib/gcc/i386-pc-solaris2.10/4.1.2:/export/scratch0/GentooPrefix/lib:/export/scratch0/GentooPrefix/usr/lib |
36 |
test: new RPATH: /usr/lib/gcc/i386-pc-solaris2.10/4.1.2:/lib:/usr/lib |
37 |
|
38 |
So, we changed the rpath record. Let's see if it's for real: |
39 |
|
40 |
[ra:/var/tmp] % ldd test |
41 |
libssl.so.0.9.8 => (file not found) |
42 |
|
43 |
Don't believe it? |
44 |
|
45 |
[ra:/var/tmp] % ./test |
46 |
libc.so.1: test: fatal: libssl.so.0.9.8: open failed: No such file or |
47 |
directory |
48 |
Killed |
49 |
|
50 |
So, can we fix it also again? |
51 |
|
52 |
[ra:/var/tmp] % chrpath -r /export/scratch0/GentooPrefix/usr/lib/gcc/i386-pc-solaris2.10/4.1.2:/export/scratch0/GentooPrefix/lib:/export/scratch0/GentooPrefix/usr/lib |
53 |
test |
54 |
test: RPATH=/usr/lib/gcc/i386-pc-solaris2.10/4.1.2:/lib:/usr/lib |
55 |
test: new RPATH: /export/scratch0/GentooPrefix/usr/lib/gcc/i386-pc-solaris2.10/4.1.2:/export/scratch0/GentooPrefix/lib:/export/scratch0/GentooPrefix/usr/lib |
56 |
|
57 |
[ra:/var/tmp] % ./test |
58 |
OpenSSL 0.9.8e 23 Feb 2007 |
59 |
|
60 |
Yes we can! |
61 |
This was Solaris, Linux works the same. Now let's check Darwin. |
62 |
|
63 |
Same test program. |
64 |
|
65 |
[tefnut:/var/tmp] % gcc -o test test.c -lssl -lcrypto |
66 |
[tefnut:/var/tmp] % ./test |
67 |
OpenSSL 0.9.8e 23 Feb 2007 |
68 |
[tefnut:/var/tmp] % otool -L test |
69 |
test: |
70 |
/Library/Gentoo/usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8) |
71 |
/Library/Gentoo/usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8) |
72 |
|
73 |
Ok, prefix paths. Darwin is MACH-O, which stores the full filename to |
74 |
the library in this case, so no rpath is there. chrpath doesn't work |
75 |
here for that reason, but on Darwin, there is the install_name_tool |
76 |
tool. |
77 |
|
78 |
[tefnut:/var/tmp] % install_name_tool -change /Library/Gentoo/usr/lib/libssl.0.9.8.dylib /usr/lib/libssl.0.9.8.dylib test |
79 |
[tefnut:/var/tmp] % otool -L testtest: |
80 |
/usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8) |
81 |
/Library/Gentoo/usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8) |
82 |
[tefnut:/var/tmp] % ./test |
83 |
dyld: Library not loaded: /usr/lib/libssl.0.9.8.dylib |
84 |
Referenced from: /private/var/tmp/./test |
85 |
Reason: image not found |
86 |
Trace/BPT trap |
87 |
|
88 |
Fix it? |
89 |
|
90 |
[tefnut:/var/tmp] % install_name_tool -change /usr/lib/libssl.0.9.8.dylib /Library/Gentoo/usr/lib/libssl.0.9.8.dylib test |
91 |
[tefnut:/var/tmp] % ./test |
92 |
OpenSSL 0.9.8e 23 Feb 2007 |
93 |
|
94 |
Yes! :) |
95 |
|
96 |
|
97 |
So, install_name_tool does it a bit different than chrpath, but with |
98 |
some scripting both can do the same: change the location libraries are |
99 |
looked for. What does this mean? Well, let's look at this: |
100 |
|
101 |
[tefnut:/var/tmp] % install_name_tool -change /Library/Gentoo/usr/lib/libssl.0.9.8.dylib /var/tmp/libssl.0.9.8.dylib test |
102 |
[tefnut:/var/tmp] % cp /Library/Gentoo/usr/lib/libssl.0.9.8.dylib . |
103 |
[tefnut:/var/tmp] % ./test |
104 |
OpenSSL 0.9.8e 23 Feb 2007 |
105 |
[tefnut:/var/tmp] % otool -L test |
106 |
test: |
107 |
/var/tmp/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8) |
108 |
/Library/Gentoo/usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8) |
109 |
|
110 |
Now suppose there is a server on the interweb that has this openssl |
111 |
installed, and I want to have it on my system. That system uses prefix |
112 |
/X/Y, while I use /A/B. What can we do? Simply scan all binaries and |
113 |
libraries and replace the paths from /X/Y/ to /A/B! |
114 |
|
115 |
Possible uses: |
116 |
- rescue your system after a major f****up |
117 |
- binhost kind of idea to avoid compiling all the time, even though |
118 |
prefixes aren't the same |
119 |
- bootstrap your system by injecting everything your need at once, |
120 |
including a compiler, then emerge world. |
121 |
- inject prefix/rpath _after_ a library has been merged without a |
122 |
ldwrapper-ed linker... |
123 |
|
124 |
So, does anyone know if a similar trick can be played on AIX? Marshall, you maybe? |
125 |
|
126 |
|
127 |
-- |
128 |
Fabian Groffen |
129 |
Gentoo on a different level |
130 |
|
131 |
-- |
132 |
gentoo-alt@g.o mailing list |