Re: Kernel Executable Pages

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a feature of the Intel CPU - called the NX bit.   Once turned
on, it is a hardware feature whereby u can specify whether the code is
made executeable or not.   As of 2nd edition of Understanding Linux
Kernel, it is still mentioned that x86 cannot distinguished between
executeable and non-executable memory.   But later Intel introduced
this bit.

Lookup all the codes for implementing this in arch/x86/mm.

For eg, init_32.c - u can specify to disable this feature via
"noexec=off" at the kernel bootup prompt.

 * Control non executable mappings.
 *
 * on      Enable
 * off     Disable
 */
static int __init noexec_setup(char *str)
{
        if (!str || !strcmp(str, "on")) {
                if (cpu_has_nx) {
                        __supported_pte_mask |= _PAGE_NX;
                        disable_nx = 0;
                }
        } else {
                if (!strcmp(str, "off")) {
                        disable_nx = 1;
                        __supported_pte_mask &= ~_PAGE_NX;
                } else {
                        return -EINVAL;


Or in pageattr.c:

/*
 * Certain areas of memory on x86 require very specific protection flags,
 * for example the BIOS area or kernel text. Callers don't always get this
 * right (again, ioremap() on BIOS memory is not uncommon) so this function
 * checks and fixes these known static required protection bits.
 */
static inline pgprot_t static_protections(pgprot_t prot, unsigned long address,
                                   unsigned long pfn)
{
        pgprot_t forbidden = __pgprot(0);

        /*
         * The BIOS area between 640k and 1Mb needs to be executable for
         * PCI BIOS based config access (CONFIG_PCI_GOBIOS) support.
         */
        if (within(pfn, BIOS_BEGIN >> PAGE_SHIFT, BIOS_END >> PAGE_SHIFT))
                pgprot_val(forbidden) |= _PAGE_NX;

        /*
         * The kernel text needs to be executable for obvious reasons
         * Does not cover __inittext since that is gone later on. On
         * 64bit we do not enforce !NX on the low mapping
         */
        if (within(address, (unsigned long)_text, (unsigned long)_etext))
                pgprot_val(forbidden) |= _PAGE_NX;

        /*
         * The .rodata section needs to be read-only. Using the pfn
         * catches all aliases.
         */
        if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT,
                   __pa((unsigned long)__end_rodata) >> PAGE_SHIFT))
                pgprot_val(forbidden) |= _PAGE_RW;

        prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));

        return prot;
}

Read the comment of this function - basically, it is saying that
certain ranges of the page frame, if it fall within a certain range of
the physical address, will have certain page protection properties
(set into the memory descriptor) - like read/write/executeable.

And according to its definition in pgtable.h:

#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
#define _PAGE_NX        (_AT(pteval_t, 1) << _PAGE_BIT_NX)
#else
#define _PAGE_NX        (_AT(pteval_t, 0))
#endif

Only 64-bit x86 have this feature enabled.

What can u do about it?

One way is to disable it via command line as mentioned above, another
way is understand enough of change_page_attr_set() (in
pageattr.c) to do what u want to do - but it is also a static
function, so inside your module this function is not visible to you.

It is just a memory descriptor thing, so u can manipulate it any other
way u want to as well, but the TLB have to be flush, per-cpu.

CMIW.

Thanks.


On Wed, Jul 16, 2008 at 1:51 AM, Asim <linkasim@xxxxxxxxx> wrote:
> The itf is actually addr variable . That was a typo while formatting
> code in the mail.
>
> Regards,
> Asim
>
> On 7/15/08, Asim <linkasim@xxxxxxxxx> wrote:
>> I'm allocation some function pointers and they were not executable. I
>> wanted to make them executable. I was able to fix my problem. Let me
>> know if there is any bug in what I did.
>>
>> my_array_of _fn_pointers = kmalloc(sizeof
>> your_favourite_fn_ptr_struct_here, GFP_KERNEL);
>>
>>  addr = my_array_of _fn_pointers ;
>>  addr_end = (unsigned long) my_array_of _fn_pointers + (unsigned long)
>> sizeof(your_favourite_fn_ptr_struct_here);
>>
>>   /* Make the memory allocated executable. */
>>   for (; addr < addr_end; addr += PAGE_SIZE)
>>     change_page_attr(virt_to_page(itf), 1, PAGE_KERNEL_EXEC);
>>
>>   printk ("Making the pages executable.\n");
>>   global_flush_tlb();
>>
>> It seems to work fine so far.
>>
>> Regards,
>> Asim Kadav
>>
>> On 7/15/08, Sandeep K Sinha <sandeepksinha@xxxxxxxxx> wrote:
>>> Can you be a bit more specific ?
>>>
>>> On Tue, Jul 15, 2008 at 9:55 PM, Asim <linkasim@xxxxxxxxx> wrote:
>>>> Hi,
>>>>
>>>> I try to allocate memory to generate some executable code in memory.
>>>> But when i try to execute - I get the following error "kernel tried to
>>>> execute NX-protected page - exploit attempt? (uid: 0)". Is there some
>>>> different way to allocate executable memory (and not data). Kindly
>>>> help.
>>>>
>>>> Regards,
>>>> Asim
>>>>
>>>> --
>>>> To unsubscribe from this list: send an email with
>>>> "unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx
>>>> Please read the FAQ at http://kernelnewbies.org/FAQ
>>>>
>>>>
>>>
>>>
>>>
>>> --
>>> Regards,
>>> Sandeep.
>>>
>>>
>>>
>>>
>>>
>>>
>>> "To learn is to change. Education is a process that changes the learner."
>>>
>>
>
> --
> To unsubscribe from this list: send an email with
> "unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx
> Please read the FAQ at http://kernelnewbies.org/FAQ
>
>



-- 
Regards,
Peter Teoh

--
To unsubscribe from this list: send an email with
"unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx
Please read the FAQ at http://kernelnewbies.org/FAQ


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux