Bug 37554

Summary: [vm] [patch] make ELF shared libraries immutable once loaded (like executables)
Product: Base System Reporter: Peter Edwards <pmedwards>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Open ---    
Severity: Affects Only Me Keywords: patch
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
shlib-textbusy.tar.Z none

Description Peter Edwards 2002-04-29 09:20:01 UTC
Before executing a program, the kernel marks the executable file as
immutable by setting the VTEXT flag in its vnode. This makes write
operations return with ETXTBSY when attempted.

However, no such flag is set for shared libraries mapped by rtld.

This patch adds a new fcntl command, F_TXTBSY, which sets the VTEXT flag
in the vnode associated with the file, and gets rtld-elf to make use
of it.

There may be security issues here, allowing user code to set this flag
in contexts it wasn't designed for, but I don't think it allows you do
anything that you couldn't already. You can't stop someone creating a
custom executable in order to get VTEXT set on it anyway, and root can
always kill any processes holding the object in memory to clear the
flag if neccessary.

Fix: Apply the following patch.
How-To-Repeat: Write a program that depends on a shared library, and overwrite that
library while the program is running. Bad Things happen.

Trying the same on an executable results in the write operation
returning ETXTBSY
Comment 1 Peter Edwards 2002-06-13 20:19:11 UTC
Hm. This is possibly a nicer way to do it, and certainly a smaller, if more 
intrusive, patch. It changes the semantics of mmap() somewhat, but I think 
in a reasonable way, and it avoids all that ugliness in the run-time linker.

Basically, a request for PROT_EXEC on a regular file will cause it to become 
immutable:


--- vm_mmap.c   3 Nov 2001 01:41:10 -0000       1.108.2.5
+++ vm_mmap.c   13 Jun 2002 19:15:28 -0000
@@ -406,8 +406,17 @@

         error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot,
             flags, handle, pos);
-       if (error == 0)
+       if (error == 0) {
                 p->p_retval[0] = (register_t) (addr + pageoff);
+               /*
+                * A successful map for a regular file, with execute access:
+                * mark the vnode immutable.
+                * XXX: GCC warns, but (handle == 0 || handle == vp)
+                * I'm not sure of the "correct" way to avoid this.
+                */
+               if (handle && vp->v_type == VREG && (prot & PROT_EXEC))
+                       vp->v_flag |= VTEXT;
+       }
  done:
         if (fp)
                 fdrop(fp, p);



Of course, the utility of all this is questionable: I just wanted the 
functionality for something locally.
Cheers,
Peter
Comment 2 John-Mark Gurney freebsd_committer freebsd_triage 2003-09-16 02:05:46 UTC
Responsible Changed
From-To: freebsd-bugs->jmg

I'm going to take this, since I'm interested in it.
Comment 3 Eitan Adler freebsd_committer freebsd_triage 2012-11-04 04:53:18 UTC
Responsible Changed
From-To: jmg->freebsd-bugs

no progress from jmg since 2003
Comment 4 Eitan Adler freebsd_committer freebsd_triage 2017-12-31 07:59:13 UTC
For bugs matching the following criteria:

Status: In Progress Changed: (is less than) 2014-06-01

Reset to default assignee and clear in-progress tags.

Mail being skipped
Comment 5 Graham Perrin freebsd_committer freebsd_triage 2022-10-17 12:38:55 UTC
Keyword: 

    patch
or  patch-ready

– in lieu of summary line prefix: 

    [patch]

* bulk change for the keyword
* summary lines may be edited manually (not in bulk). 

Keyword descriptions and search interface: 

    <https://bugs.freebsd.org/bugzilla/describekeywords.cgi>