... h2. OS version checks (uname) {section} {column:width=70%} h3. Introduction / Motivation DTrace is not just able to monitor / view things. Adding a special pragma statement, it is even possible to overwrite / modify values. Within this chapter you will find an unsupported use-case: run software doing hard coded OS version checks on newer OS versions (like OpenSolaris).
h3. Background In case you are interested in playing around with SAP on OpenSolaris, you will encounter SAP error messages which are due to the fact, that your SAP kernel has not been released for SunOS 5.11. If you query disp+work, you will see something like:
{noformat} solman:demadm 6% disp+work
-------------------- disp+work information --------------------
kernel release 700 kernel make variant 700_REL compiled on SunOS 5.9 Generic_117171-13 sun4u compiled for 64 BIT compilation mode UNICODE compile time Feb 3 2008 21:08:24 update level 0 patch number 146 source id 0.146
--------------------- supported environment ---------------------
database (SAP, table SVERS) 700 operating system SunOS 5.9 SunOS 5.10 solman:demadm 6% {noformat}
{column}
{column:width=30%} {info: icon=false} {recently-updated: spaces=SAPonSun | labels=rss | maxResults=4} {info} {column} {section}
{section} If you try to logon to SAP, you will see error messages indicating a problem in your setup. Running the SAP Initial Consistency Check transaction (SICK), you will see: \\ \\ !sick_bad2.png! \\ In order to get rid of this message *on a sandbox system* (!!), it seems to be appealing to fake the Solaris version. There are also software packages that check the OS version during installation and exit without installing the software in case the OS version differs from expected values. This is partially true also for Oracle's runInstaller. However, this tool provides options to bypass tests for prerequisites by using the parameter '-ignoreSysPrereqs'. But back to SAP SICK problems. How can DTrace help ?
h3. Solution The system call that is used to determine the OS version is 'uname' (not the Solaris 'uname'-command). So let's start with a very basic and easy script which uses the entry probe of this system call. The provider we are going to use is called 'syscall': \\ !unamed_screen2.png! \\ |
The predicate /uid == $1/ will make sure, that only uname calls executed by the specified userid will be caught. But that's just the start. The script to overwrite the OS version is listed below: |
| {noformat}
{code} |
#!/usr/sbin/dtrace -s #pragma D option destructive |
... /* * Disclaimer: * Use at own risk ! * Don't try this at work ! * this script may be used in sandbox environments to * pretend a different Solaris version to a specific * OS user. By changing the predicate it is possible * to filter other processes like the ones within a * specific zone, a specific project etc. * The builtin curpsinfo struct might be your friend */
struct utsname myuts;
syscall::uname:entry /uid == $1/ { self->uts_name_addr = arg0; }
syscall::uname:return /uid == $1/ { rel_size = sizeof(myuts.release); rel_offset = offsetof(struct utsname, release);
|
copyoutstr("5.10", self->uts_name_addr+rel_offset, rel_size); } |
| {noformat}
{code} |
The statement '#pragma D option destructive' explicitely allows data modification. We still have an entry probe on uname, just because we need to save the pointer to a struct containing the OS version, which is the first argument to uname. This struct is called utsname. You can find details about this struct in sys/utsname.h: |
| {noformat}
{code} |
struct utsname { char sysname[_SYS_NMLN]; |
... char nodename[_SYS_NMLN]; char release[_SYS_NMLN]; char version[_SYS_NMLN]; |
char machine[_SYS_NMLN]; }; |
| {noformat}
{code} |
We are particularly interested in the third field with name 'release'. In order to acces that field within the return probe, we have to use the pointer to the utsname struct (saved in the thread local variable uts_name_addr) and apply the corresponding offset. For the same reason we have been using the copyinstr command before, we have to use the copyoutstr command now: DTrace runs within kernel context and cannot access the application context directly. In case you want to change the OS version for all processes within a given zone (passed as argument), just replace the two predicate lines by: |
| {noformat}
{code} |
| /curpsinfo->pr_zoneid == $1/ |
| {noformat}
{code} |
After running the DTrace script and starting SAP, we want to check transaction SICK again: \\ |
... !sick_good2.png! \\ SAP is no longer reporting an unsupported OS. Well, DTrace is certainly a good argument not to complain. |