From: Stephen Roettger <sroettger@google.com>
To: libc-alpha@sourceware.org
Cc: Stephen Roettger <sroettger@google.com>, jeffxu@chromium.org
Subject: [RFC 1/1] elf: mseal non-writable segments
Date: Wed, 22 May 2024 13:29:31 +0200 [thread overview]
Message-ID: <20240522112933.2005066-2-sroettger@google.com> (raw)
In-Reply-To: <20240522112933.2005066-1-sroettger@google.com>
Mseal is a new Linux syscall that blocks any modifications to given
memory mappings like unmapping them or changing the permission bits.
This patch applies mseal to segments during loading if:
* the writable bit is not set
* mode is RTLD_NODELETE
In addition, it adds RTLD_NODELETE to the main binary/libraries and
propagates the RTLD_NODELETE to auxialliary library loads.
---
elf/dl-load.c | 6 ++++++
elf/dl-load.h | 1 +
elf/dl-map-segments.h | 6 ++++++
elf/dl-open.c | 3 ++-
elf/rtld.c | 12 +++++++++---
5 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/elf/dl-load.c b/elf/dl-load.c
index a34cb3559c..638028d6da 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1136,6 +1136,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize));
c->dataend = ph->p_vaddr + ph->p_filesz;
c->allocend = ph->p_vaddr + ph->p_memsz;
+ c->seal = false;
/* Remember the maximum p_align. */
if (powerof2 (ph->p_align) && ph->p_align > p_align_max)
p_align_max = ph->p_align;
@@ -1169,6 +1170,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
if (ph->p_flags & PF_X)
c->prot |= PROT_EXEC;
#endif
+
+ if (mode & RTLD_NODELETE && ((c->prot & PROT_WRITE) == 0)) {
+ c->seal = true;
+ }
+
break;
case PT_TLS:
diff --git a/elf/dl-load.h b/elf/dl-load.h
index 656ec229bf..040e744908 100644
--- a/elf/dl-load.h
+++ b/elf/dl-load.h
@@ -78,6 +78,7 @@ struct loadcmd
ElfW(Addr) mapstart, mapend, dataend, allocend, mapalign;
ElfW(Off) mapoff;
int prot; /* PROT_* bits. */
+ bool seal;
};
diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h
index 30977cf800..4cddb4b294 100644
--- a/elf/dl-map-segments.h
+++ b/elf/dl-map-segments.h
@@ -19,6 +19,8 @@
#include <dl-load.h>
+#define SYS_mseal 462
+
/* Map a segment and align it properly. */
static __always_inline ElfW(Addr)
@@ -143,6 +145,10 @@ _dl_map_segments (struct link_map *l, int fd,
== MAP_FAILED))
return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
+ if (c->seal) {
+ syscall(SYS_mseal, (void*) mm, map_size, 0);
+ }
+
postmap:
_dl_postprocess_loadcmd (l, header, c);
diff --git a/elf/dl-open.c b/elf/dl-open.c
index c378da16c0..a6c89134f8 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -636,7 +636,8 @@ dl_open_worker_begin (void *a)
/* Load that object's dependencies. */
_dl_map_object_deps (new, NULL, 0, 0,
- mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT));
+ mode & (__RTLD_DLOPEN | RTLD_DEEPBIND |
+ __RTLD_AUDIT | RTLD_NODELETE));
/* So far, so good. Now check the versions. */
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
diff --git a/elf/rtld.c b/elf/rtld.c
index e9525ea987..b471e4c0af 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -79,6 +79,8 @@
# define RTLD_TIMING_SET(var, value) (var) = (value)
# define RTLD_TIMING_REF(var) &(var)
+#define SYS_mseal 462
+
static inline void
rtld_timer_start (hp_timing_t *var)
{
@@ -809,7 +811,7 @@ do_preload (const char *fname, struct link_map *main_map, const char *where)
args.str = fname;
args.loader = main_map;
- args.mode = __RTLD_SECURE;
+ args.mode = __RTLD_SECURE | RTLD_NODELETE;
unsigned int old_nloaded = GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
@@ -1214,6 +1216,10 @@ rtld_setup_main_map (struct link_map *main_map)
segment. */
expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
& ~(GLRO(dl_pagesize) - 1));
+
+ if ((ph->p_flags & PF_W) == 0) {
+ syscall(SYS_mseal, mapstart, expected_load_address - mapstart, 0);
+ }
}
break;
@@ -1636,7 +1642,7 @@ dl_main (const ElfW(Phdr) *phdr,
/* Create a link_map for the executable itself.
This will be what dlopen on "" returns. */
main_map = _dl_new_object ((char *) "", "", lt_executable, NULL,
- __RTLD_OPENEXEC, LM_ID_BASE);
+ __RTLD_OPENEXEC | RTLD_NODELETE, LM_ID_BASE);
assert (main_map != NULL);
main_map->l_phdr = phdr;
main_map->l_phnum = phnum;
@@ -1964,7 +1970,7 @@ dl_main (const ElfW(Phdr) *phdr,
RTLD_TIMING_VAR (start);
rtld_timer_start (&start);
_dl_map_object_deps (main_map, preloads, npreloads,
- state.mode == rtld_mode_trace, 0);
+ state.mode == rtld_mode_trace, RTLD_NODELETE);
rtld_timer_accum (&load_time, start);
}
--
2.45.1.288.g0e0cd299f1-goog
next prev parent reply other threads:[~2024-05-22 11:29 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-22 11:29 [RFC 0/1] " Stephen Roettger
2024-05-22 11:29 ` Stephen Roettger [this message]
2024-05-22 16:24 ` [RFC 1/1] " Cristian Rodríguez
[not found] ` <CAEAAPHaEssoE79B0vWk1S42QaUk+WVwJ0sNxnUzF3hkXNG+b9w@mail.gmail.com>
2024-05-22 18:39 ` Carlos O'Donell
2024-05-22 18:57 ` [RFC 0/1] " Carlos O'Donell
2024-05-23 9:31 ` Stephen Röttger
2024-05-23 10:38 ` Florian Weimer
2024-05-22 19:42 ` Florian Weimer
2024-05-23 9:36 ` Stephen Röttger
2024-06-04 14:19 ` Adhemerval Zanella Netto
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240522112933.2005066-2-sroettger@google.com \
--to=sroettger@google.com \
--cc=jeffxu@chromium.org \
--cc=libc-alpha@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).