Solaris Non-Executable Stack Concluded

Since publishing my two part series on non-executable stacks in the Solaris operating system, I received some very useful feedback and clarifications that I wanted to share with everyone. First, Vladimir Kotal commented on my first article that:

Having to grep(1) for the CPU features is really clumsy. Maybe psrinfo(1M) could be extended to print them out? (for every (virtual) CPU present in the system)

Frankly, I agree. After asking around however, today there does not appear to be a cleaner interface (although there is a bunch of discussion around adding one). Sherry Moore and Joe Bonasera were kind enough to point out that there is a programmatic way to access this information in the form of cpuid(7d). Joe also shared the following with me that you may find interesting:

The NX information doesn't belong in isainfo. isainfo, I'm told, is only meant to reflect processor capability information that is directly usable from user mode.

The NX bit feature has to do with page table construction which is not something you do from userland. What's a more interesting thing to know is "Does not specifying PROT_EXEC have any effect on this system, or is PROT_EXEC implicit for all PROT_READ segments?" Even cpuid doesn't help with that information as various bits of the OS memory subsystems might do different things along the way. For example if for some reason you're running a non-PAE 32 bit kernel, even though cpuid says that NX is supported, NX bits wont be used.

A similar issue has come up in the Open Solaris Xen project, in that many people want to know if their processor supports AMD-V or Intel VT-x. That information comes from CPUID, but is only usable from supervisor (either kernel or hypervisor) code, hence we haven't added it to isainfo. But it is a valid question to ask if the cpu/bios you have would support running such software w/o actually having it.

That said, Sherry did clue me in on a program called cpuid which can allow us to get this information and a lot more (subject to the issues noted by Joe above). Unfortunately, the cpuid program was developed for Linux and will not compile by default on Solaris:

blackhole$ gmake
cc -g -Wall -Wshadow -Wcast-align -Wredundant-decls -Wbad-function-cast -Wcast-qual -Wwrite-strings -Waggregate-return 
-Wstrict-prototypes -Wmissing-prototypes -D_FILE_OFFSET_BITS=64 -DVERSION=20070801 -o cpuid cpuid.c
cpuid.c:26:25: linux/major.h: No such file or directory
cpuid.c: In function `explain_errno':
cpuid.c:3191: error: `CPUID_MAJOR' undeclared (first use in this function)
cpuid.c:3191: error: (Each undeclared identifier is reported only once
cpuid.c:3191: error: for each function it appears in.)
cpuid.c: In function `real_setup':
cpuid.c:3472: warning: implicit declaration of function `makedev'
cpuid.c:3472: error: `CPUID_MAJOR' undeclared (first use in this function)
cpuid.c: In function `main':
cpuid.c:3751: warning: initialization discards qualifiers from pointer target type
cpuid.c:3752: warning: initialization discards qualifiers from pointer target type
cpuid.c:3753: warning: initialization discards qualifiers from pointer target type
cpuid.c:3754: warning: initialization discards qualifiers from pointer target type
cpuid.c:3755: warning: initialization discards qualifiers from pointer target type
cpuid.c:3756: warning: initialization discards qualifiers from pointer target type
cpuid.c:3757: warning: initialization discards qualifiers from pointer target type
gmake: \*\*\* [cpuid] Error 1

Luckily, the changes to get this program to work on Solaris were simple (Thanks Sherry!). All that we needed to do was remove the references to /dev/cpu/\* as that is a Linux-ism that does not exist on Solaris. Here is the complete diff for those wanting to try this at home:

blackhole$ diff linux-cpuid.c cpuid.c
25a26
> #if 0
26a28
> #endif
3188a3191
> #if 0
3194a3198
> #endif
3450a3455
> #if 0
3489a3495
> #endif

Clearly, if you wanted the program to work on either OS, you could just substitute the #if 0 strings for something like #if !defined(SOLARIS) and then just define SOLARIS in the CFLAGS parameter when compiling on Solaris. But I digress... With this simple change implemented, you can now compile the cpuid program on Solaris:

blackhole$ gmake
cc -g -Wall -Wshadow -Wcast-align -Wredundant-decls -Wbad-function-cast -Wcast-qual -Wwrite-strings -Waggregate-return 
-Wstrict-prototypes -Wmissing-prototypes -D_FILE_OFFSET_BITS=64 -DVERSION=20070801 -o cpuid cpuid.c
cpuid.c: In function `main':
cpuid.c:3757: warning: initialization discards qualifiers from pointer target type
cpuid.c:3758: warning: initialization discards qualifiers from pointer target type
cpuid.c:3759: warning: initialization discards qualifiers from pointer target type
cpuid.c:3760: warning: initialization discards qualifiers from pointer target type
cpuid.c:3761: warning: initialization discards qualifiers from pointer target type
cpuid.c:3762: warning: initialization discards qualifiers from pointer target type
cpuid.c:3763: warning: initialization discards qualifiers from pointer target type
gzip < cpuid.man > cpuid.man.gz

These warnings can be safely ignored. With the program now compiled, let's give it a try and see what it can tell us about the NX bit:

blackhole$ ./cpuid | grep exec
      execution disable                      = false

Interesting. This system does not have the NX capability likely because I am running (Nevada in this case) in a Parallels VM which is 32-bit (reference Joe's note above). Let's give this a better test subject by trying it on a Sun X2100. This command is run from the global zone of a system running Solaris 10 11/06:

$ ./cpuid | grep exec
      no-execute page protection            = true

Careful observation will also show the AMD and Intel naming differences that I had talked about previously with respect to XD and NX.

Well, I think that I have talked about this subject to death. I hope that you found it interesting and perhaps a little educational. As always, I love to get your feedback! Before signing off, once again I would like to thank Sherry Moore and Joe Bonasera for sharing their knowledge and experience with me (and thereby with you)!

Take care,

Glenn

Technorati Tag:

Comments:

Actually, Solaris does have a /dev/cpu, which explicitly mimics Linux's, but only /dev/cpu/self/cpuid, instead of /dev/cpu/[0...]/cpuid like Linux has. Another (IMO more developed) program, x86info, already supports Solaris out of the box in its most recent development version.

Posted by John Levon on August 01, 2007 at 11:57 AM EDT #

John,

Thank you very much for this clarification and for your suggestion of the x86info program. I will definitely have to give it a try!

Thanks again!

Glenn

Posted by Glenn Brunette on August 01, 2007 at 02:23 PM EDT #

For the SFE repository on sourceforge there is a SFEx86info.spec file to fetch, compile and install x86info with the tools "pkgbuild/pkgtool".

Example from my Acer Ferrari 4005 Notebook:

book ~/spec-files-extra $ x86info 
x86info v1.21.  Dave Jones 2001-2007
Feedback to <davej@redhat.com>.

Found 1 CPU
--------------------------------------------------------------------------
Family: 15 Model: 4 Stepping: 2
CPU Model : Athlon 64 
Processor name string: AMD Turion(tm) 64 Mobile Technology ML-37

Feature flags:
 fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflsh mmx fxsr sse sse2 sse3
Extended feature flags:
 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] syscall [12] [13] [14] [15] [16] [17] nx mmxext [23] [24] Fast fxsave/fxrstor lm 3dnowext 3dnow lahf/sahf


The above is called as normal user. Called as root, x86info fails with "readEntry: Bad address". I haven't looked at the code yet, any ideas?

Posted by Thomas Wagner on August 03, 2007 at 10:37 PM EDT #

Uh, no idea, I was working with x86info CVS sources. If you check that out and compile it, it should work fine.

Posted by John Levon on August 03, 2007 at 11:13 PM EDT #

Post a Comment:
Comments are closed for this entry.
About

gbrunett

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today