Saturday, April 21. 2012
LD_PRELOAD Trick Once Again
The past week two friends commented to me that, after patching some Solaris 10 boxes, the provider name for Sparc machines had changed from previous Sun_Microsystems to new Oracle Corporation. In most of the cases this little change is meaningless but an old licensed software stopped working in one of their boxes.
As the good sysadmins they are they found that a binary inside the software checked the license against hostid (a host identifier in Solaris OS) and hardware provider (the manufacturer of the hardware). This binary checked that both current values were the same to the ones saved when the license was installed. Obviously this procedure tries to avoid the re-installation of the license in other host, but, obviously again, this was not that case. As the software was quite old they understood that the final fix would last long time to come (they needed to renew the license for the changed provider and it was not going to be easy). After realizing that the binary used sysinfo() system call they phoned me asking if preloading a modified library would work. At first time I was not sure if libc routines can be preloaded but then I remembered that Linus Torvalds himself had used the same trick in the old flash-plugin problem commented before in this blog (he coded a library which preloaded a modified memcpy function). So it should work.
The sysinfo call just fills a char buffer with the value for some predefined commands (there are several defines like SI_HW_SERIAL -hostid- or SI_HW_PROVIDER -hardware provider- which this function interprets as commands). I developed a fake routine which just returns the Sun_Microsystems char array in case SI_HW_PROVIDER command is requested, if any other command is passed the routine relies in system _sysinfo (pre-processor added system call). Besides if a SI_HW_PROVIDER environment variable is set, the library returns that value instead of the hardcoded one. That was the second version of the fake library after some good advises from my colleagues. The routine is in the sysinfo.c file and it is compiled under Solaris like this (for 64 bits binaries a -m64 option should be added):
/usr/sfw/bin/gcc -fpic -c sysinfo.c /usr/sfw/bin/gcc -shared -o sysinfo.so sysinfo.o
Besides I created a little utility called sysinfo-test (sysinfo-test.c file) which was used to test the trick. Again it can be compiled using the following line.
/usr/sfw/bin/gcc -o sysinfo-test sysinfo-test.c
The utility command receives the number of the command to retrieve as an argument and just prints its value to the standard output. So it can be executed directly to display some commands.
-bash-3.00$ ./sysinfo-test USAGE: ./sysinfo-test num num: SI_SYSNAME = 1 SI_HOSTNAME = 2 SI_RELEASE = 3 SI_VERSION = 4 SI_MACHINE = 5 SI_ARCHITECTURE = 6 SI_ARCHITECTURE_64 = 517 SI_ARCHITECTURE_32 = 516 SI_ARCHITECTURE_K = 518 SI_ARCHITECTURE_NATIVE = 519 SI_ISALIST = 514 SI_PLATFORM = 513 SI_HW_PROVIDER = 8 SI_HW_SERIAL = 7 SI_SRPC_DOMAIN = 9 SI_DHCP_CACHE = 515 -bash-3.00$ ./sysinfo-test 8 Command '8'(ret=1): '' -bash-3.00$ ./sysinfo-test 1 Command '1'(ret=6): 'SunOS'
As you see SI_HW_PROVIDER and SI_SYSNAME are requested and printed (hardware provider is empty in my virtual KVM box). But if the execution uses my fake library preloaded the same commands return different values.
-bash-3.00$ LD_PRELOAD=./sysinfo.so ./sysinfo-test 8 Command '8'(ret=17): 'Sun_Microsystems' -bash-3.00$ LD_PRELOAD=./sysinfo.so ./sysinfo-test 1 Command '1'(ret=6): 'SunOS' -bash-3.00$ SI_HW_PROVIDER="CustomHW" LD_PRELOAD=./sysinfo.so ./sysinfo-test 8 Command '8'(ret=9): 'CustomHW'
The SI_HW_PROVIDER command returns my hardcoded char array and SI_SYSNAME returns the same value as before (system call is used). And, in the last execution, if I request the provider again but with an environment variable that var is returned.
So it is working. My friends can now use my little library in order to return what they need and fool the command. Meanwhile they will peacefully wait for a final solution. I am aware that we are cheating but sometimes in this crappy world it is your only choice. Do not forget either that their license was valid before the patching.
Sometimes... The end justifies the means!
Comments