Kernel Newbies archive on lore.kernel.org
 help / Atom feed
* How to forbid user space and kernel executable pages from becoming writable?
@ 2019-01-05 15:30 Lev Olshvang
  2019-01-05 20:22 ` Shachar Shemesh
  2019-01-05 20:35 ` valdis.kletnieks
  0 siblings, 2 replies; 3+ messages in thread
From: Lev Olshvang @ 2019-01-05 15:30 UTC (permalink / raw)
  To: linux-il, kernelnewbies

I am researching this issue and I am confused with the finding

Some articles, ex https://shanetully.com/2013/12/writing-a-self-mutating-x86_64-c-program/
state that mprotect() can change protection of executable section.

As I understanf pte entry has page protection bits set to RO so  mprotect should change pte which is loaded to MMU/TLB. Why kernel can not refuse do perform this mprotect call(). Whu we do norhave kernel config options to forbid user-space mutable code as security feature?



From the other side,  when  run-time linker or elf_loader loads the executable it uses MAP_DENYWRITE which protect executable file from being overwritten. 

But writing to  executable text  will make  page dirty and require the write-back which is disabled by MAP_DENYWRITE. (or it might be disable for other processes except current, I am not sure?)


To add to the confusion, the following quote from the LWN articlle 
https://lwn.net/Articles/422487/ about CONFIG_DEBUG_SET_MODULE_RONX 
"Marking the kernel module pages as RO and/or NX is important not only because it is consistent with how the rest of the kernel pages are handled"
  
Digging dipper I see that ARM since kernel version 4.11 has CONFIG_STRICT_KERNEL_RWX ,  and as I understand it is enforced in hardware.

But I am not sure that some variant of pte_clear(), pte_mkexec(0 can not disable it.

So let me cut to final qiestion:

Suppose I want to cut off dynamic code instrumentation, like ftrace and friends.
Is it achievable at least at ARM architecture to enforce RO+X at hardware or kernel? 

Thanks to all folks for reading till this point.

Regards
Lev



_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: How to forbid user space and kernel executable pages from becoming writable?
  2019-01-05 15:30 How to forbid user space and kernel executable pages from becoming writable? Lev Olshvang
@ 2019-01-05 20:22 ` Shachar Shemesh
  2019-01-05 20:35 ` valdis.kletnieks
  1 sibling, 0 replies; 3+ messages in thread
From: Shachar Shemesh @ 2019-01-05 20:22 UTC (permalink / raw)
  To: Lev Olshvang, linux-il, kernelnewbies

[-- Attachment #1: Type: text/html, Size: 5157 bytes --]

<html style="direction: ltr;">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <style type="text/css">body p { margin-bottom: 0cm; margin-top: 0pt; } </style>
  </head>
  <body bidimailui-charset-is-forced="true" style="direction: ltr;"
    bgcolor="#FFFFFF" text="#000000">
    <p>All of the below seemed really strange to me, because I
      researched it when I wrote fakeroot-ng. To make sure, I wrote the
      following program:</p>
    <p><br>
    </p>
    <p>#include &lt;sys/types.h&gt;<br>
      #include &lt;sys/stat.h&gt;<br>
      #include &lt;fcntl.h&gt;<br>
      #include &lt;sys/mman.h&gt;<br>
      #include &lt;unistd.h&gt;<br>
      #include &lt;stdio.h&gt;<br>
      <br>
      int main() {<br>
          int fd = open("testfile", O_CREAT|O_TRUNC|O_WRONLY, 0666);<br>
          ftruncate(fd, 4096);<br>
          close(fd);<br>
      <br>
          fd = open("testfile", O_RDONLY);<br>
          char *map = (char *)mmap( nullptr, 4096, PROT_READ,
      MAP_SHARED|MAP_FILE, fd, 0 );<br>
          if( map==MAP_FAILED ) {<br>
              perror("mmap failed");<br>
              return 1;<br>
          }<br>
      <br>
          if( mprotect(map, 4096, PROT_READ|PROT_WRITE)&lt;0 ) {<br>
              perror("mprotect failed");<br>
              return 1;<br>
          }<br>
      }</p>
    <p><br>
    </p>
    <p>As I expected, the mprotect fails with "Permission denied". It is
      not possible to change the mapping to allow writing to the memory
      when it is a shared mapping of a file opened in read-only. I have
      no idea what the other resources are saying, but this is what I
      see.</p>
    <p><br>
    </p>
    <p>Since the above completely describes what the loader does to an
      executable file, I don't see how mprotect can be used there
      either.</p>
    <p><br>
    </p>
    <p>With that said, I know that debuggers often change the text
      segment of debugees in order to insert breakpoints. I have to
      admit that testing the mechanism by which that happens is on my
      todo list, but I have not got around to actually doing it. I am
      guessing that writing from the debugger switches the map mode to
      MAP_PRIVATE (i.e. - copy on write), which means there is no need
      to flush the changes to the file.</p>
    <p><br>
    </p>
    <p>With that said, I have been unable to find a way to trigger that
      change by any other means, so a mapping made from a file opened in
      read only mode is, as far as I can tell, safe from manipulation
      barring the ptrace route.</p>
    <p><br>
    </p>
    <p>Shachar<br>
    </p>
    <p><br>
    </p>
    <div class="moz-cite-prefix">On 05/01/2019 17:30, Lev Olshvang
      wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:33504091546702201@myt2-cd7fa496c4f7.qloud-c.yandex.net">
      <pre class="moz-quote-pre" wrap="">I am researching this issue and I am confused with the finding

Some articles, ex <a class="moz-txt-link-freetext" href="https://shanetully.com/2013/12/writing-a-self-mutating-x86_64-c-program/">https://shanetully.com/2013/12/writing-a-self-mutating-x86_64-c-program/</a>
state that mprotect() can change protection of executable section.

As I understanf pte entry has page protection bits set to RO so  mprotect should change pte which is loaded to MMU/TLB. Why kernel can not refuse do perform this mprotect call(). Whu we do norhave kernel config options to forbid user-space mutable code as security feature?



From the other side,  when  run-time linker or elf_loader loads the executable it uses MAP_DENYWRITE which protect executable file from being overwritten. 

But writing to  executable text  will make  page dirty and require the write-back which is disabled by MAP_DENYWRITE. (or it might be disable for other processes except current, I am not sure?)


To add to the confusion, the following quote from the LWN articlle 
<a class="moz-txt-link-freetext" href="https://lwn.net/Articles/422487/">https://lwn.net/Articles/422487/</a> about CONFIG_DEBUG_SET_MODULE_RONX 
"Marking the kernel module pages as RO and/or NX is important not only because it is consistent with how the rest of the kernel pages are handled"
  
Digging dipper I see that ARM since kernel version 4.11 has CONFIG_STRICT_KERNEL_RWX ,  and as I understand it is enforced in hardware.

But I am not sure that some variant of pte_clear(), pte_mkexec(0 can not disable it.

So let me cut to final qiestion:

Suppose I want to cut off dynamic code instrumentation, like ftrace and friends.
Is it achievable at least at ARM architecture to enforce RO+X at hardware or kernel? 

Thanks to all folks for reading till this point.

Regards
Lev



_______________________________________________
Linux-il mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Linux-il@cs.huji.ac.il">Linux-il@cs.huji.ac.il</a>
<a class="moz-txt-link-freetext" href="http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il">http://mailman.cs.huji.ac.il/mailman/listinfo/linux-il</a>
</pre>
    </blockquote>
  </body>
</html>


[-- Attachment #2: Type: text/plain, Size: 170 bytes --]

_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: How to forbid user space and kernel executable pages from becoming writable?
  2019-01-05 15:30 How to forbid user space and kernel executable pages from becoming writable? Lev Olshvang
  2019-01-05 20:22 ` Shachar Shemesh
@ 2019-01-05 20:35 ` valdis.kletnieks
  1 sibling, 0 replies; 3+ messages in thread
From: valdis.kletnieks @ 2019-01-05 20:35 UTC (permalink / raw)
  To: Lev Olshvang; +Cc: linux-il, kernelnewbies

On Sat, 05 Jan 2019 18:30:01 +0300, Lev Olshvang said:

> Some articles, ex https://shanetully.com/2013/12/writing-a-self-mutating-x86_64-c-program/
> state that mprotect() can change protection of executable section.

Note that appears to be a 5 year old article, and one that tries to be operating system
agnostic.

> As I understanf pte entry has page protection bits set to RO so  mprotect
> should change pte which is loaded to MMU/TLB. Why kernel can not refuse do
> perform this mprotect call(). Whu we do norhave kernel config options to forbid
> user-space mutable code as security feature?

Hint: Read up on how shared libraries get loaded when a process starts up, and
also read up on dlopen() 

Think about how you get those to work if you can't have user-space mutable code
at all.

Are you ready to accept the performance hit of statically linked binaries?  Or the
maintenance nightmare of replacing every relevant binary whenever a bug is
found in a library (use glibc as an example)?

> From the other side,  when  run-time linker or elf_loader loads the
> executable it uses MAP_DENYWRITE which protect executable file from being
> overwritten. 

Now, That's a reasonably cheap protection that closes a fairly large attack surface.
It's a lot harder to exploit a buffer overrun or similar if it's difficult to find or create
a page that's both writable and executable.  Of course, there's always ways to change
a page mapping to allow it - the other half of the protection is that the vast majority
of exploits are severely limited in how many bytes can be injected.

> To add to the confusion, the following quote from the LWN articlle 
> https://lwn.net/Articles/422487/ about CONFIG_DEBUG_SET_MODULE_RONX 
> "Marking the kernel module pages as RO and/or NX is important not only because

> But I am not sure that some variant of pte_clear(), pte_mkexec() can not disable it.

So how would modprobe and (possibly more importantly) rmmod work if it couldn't
be disabled?

> So let me cut to final qiestion:
>
> Suppose I want to cut off dynamic code instrumentation, like ftrace and friends.
> Is it achievable at least at ARM architecture to enforce RO+X at hardware or kernel? 

And here is where we get into a discussion of computer security, and this thing
called a "treat model".  Basically, it boils down to several questions:

1) What sensitive data are you trying to protect?
2) Who/what are you trying to protect it from?
3) Why do you think "I should prevent XYZ" is a reasonable protection?

If you're trying to harden a given feature, it's important to ask whether it's worth the
effort (and include "amount of inconvenience caused" in there).  

And an often overlooked part is "how easy is it to bypass?".  Say you manage to fix
dlopen() and the dynamic loader to totally prevent code outside dlopen() from finding
a writable executable page.  What stops an attacker from simply handing an existing
program a booby-trapped shared library via LD_LIBRARY_PATH?

Similarly, disabling ftrace in the kernel doesn't buy you much if an attacker can
modprobe code that re-enables it, or write a new kernel down into /boot and
waiting for (or causing) a reboot.

So now your security measure needs to include modifying the shared library loader
to ignore environment variables when loading into a setuid binary, and add support
for secure boot and crypto signing of kernel modules and other similar things....

_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, back to index

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-05 15:30 How to forbid user space and kernel executable pages from becoming writable? Lev Olshvang
2019-01-05 20:22 ` Shachar Shemesh
2019-01-05 20:35 ` valdis.kletnieks

Kernel Newbies archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/kernelnewbies/0 kernelnewbies/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 kernelnewbies kernelnewbies/ https://lore.kernel.org/kernelnewbies \
		kernelnewbies@kernelnewbies.org kernelnewbies@archiver.kernel.org
	public-inbox-index kernelnewbies


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernelnewbies.kernelnewbies


AGPL code for this site: git clone https://public-inbox.org/ public-inbox