> Or is RW+NX use so much more likely that it makes sense to set only RO+X stuff explicitly when pages are taken into that kind of use?
Basically yes: the module loader allocates memory through the vmalloc() memory allocator, which is used also in a lots of places in the kernel. (Most) other users of this allocator use it for data, so it has to return RW memory, and it is safe to use +NX for it. The permissions could be set when memory is allocated again, but given that module loading/unloading is also likely to be infrequent you can (and should) make it more expensive, to slowing down all vmalloc() allocations.
> I mean, why it isn't RO+NX when not in use?
Interesting question, but:
1. Can you exploit more easily a system not doing that? My pretty long answer below is "under extreme circumstances, unlikely to happen in the real world, and (I think) never observed until now". However, maybe some world-class security expert knows of some obscure exception to this.
If each page is either writable or executable, you can't execute code of your choosing.
If you write to unused memory (which you could do through a buffer overflow overwriting a pointer), that can only affect the system if that memory is not initialized later before being used. That's a further bug needed, quite likely to cause you crashes without need of hostile attacks and therefore less likely to survive in a kernel release, and quite unlikely to allow you to execute arbitrary code (which is what you need). So you need 2 bugs, one of them is of a pretty unlikely kind, and you still can hardly do anything. If you're happy of remotely crashing the system, it's likely that you can do it via a plain buffer overflow.
2. If you wanted to do this change, either you protect all unused pages, or it isn't worth it, and that has surely a performance cost: you'd need to flush the TLB to apply the permissions change, at each memory allocation. You can't even protect all unused memory ranges, as with any memory allocator you end up with partially unused pages.
Moreover, I bet nobody could ever accept this slowdown for such tiny advantages; if you were ready to pay this price, then why not rather make all these problems impossible by running a kernel written in a memory-safe (i.e. garbage-collected) language, like Singularity? More pragmatically, move more drivers into userspace - there's already effort into this.