lightning
[Top][All Lists]
Advanced

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

[PATCH 1/2] Add user-visible functions jit_protect and jit_unprotect.


From: marc . nieper+gnu
Subject: [PATCH 1/2] Add user-visible functions jit_protect and jit_unprotect.
Date: Mon, 31 Oct 2022 13:15:31 +0100

From: Marc Nieper-Wißkirchen <marc@nieper-wisskirchen.de>

* check/Makefile.am: Add test for jit_protect and jit_unprotect.
* check/protect.c: New test.
* doc/body.texi: Add documentation for jit_protect and
jit_unprotect.
* include/lightning.h.in: Add prototypes for jit_protect and
jit_unprotect.
* include/lightning/jit_private.h: Add a field to store the size
of the protected memory.
* lib/lightning.c: Remember the size of the protected memory and
implement the two new functions.
---
 ChangeLog                       | 14 ++++++++
 check/Makefile.am               |  8 +++--
 check/protect.c                 | 59 +++++++++++++++++++++++++++++++++
 doc/body.texi                   | 22 ++++++++++++
 include/lightning.h.in          |  4 +++
 include/lightning/jit_private.h |  2 ++
 lib/lightning.c                 | 32 ++++++++++++++++--
 7 files changed, 136 insertions(+), 5 deletions(-)
 create mode 100644 check/protect.c

diff --git a/ChangeLog b/ChangeLog
index 40ade7a..0848e6c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2022-10-30  Marc Nieper-Wißkirchen  <marc@nieper-wisskirchen.de>
+
+       Add user-visible functions jit_protect and jit_unprotect.
+       * check/Makefile.am: Add test for jit_protect and jit_unprotect.
+       * check/protect.c: New test.
+       * doc/body.texi: Add documentation for jit_protect and
+       jit_unprotect.
+       * include/lightning.h.in: Add prototypes for jit_protect and
+       jit_unprotect.
+       * include/lightning/jit_private.h: Add a field to store the size
+       of the protected memory.
+       * lib/lightning.c: Remember the size of the protected memory and
+       implement the two new functions.
+
 2022-10-12 Paulo Andrade <pcpa@gnu.org>
 
        * include/lightning/jit_loongarch.h, lib/jit_loongarch-cpu.c,
diff --git a/check/Makefile.am b/check/Makefile.am
index f58dc8b..f1839ef 100644
--- a/check/Makefile.am
+++ b/check/Makefile.am
@@ -17,7 +17,7 @@
 AM_CFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include -D_GNU_SOURCE
 
 check_PROGRAMS = lightning ccall self setcode nodata ctramp carg cva_list \
-       catomic
+       catomic protect
 
 lightning_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
 lightning_SOURCES = lightning.c
@@ -46,6 +46,9 @@ cva_list_SOURCES = cva_list.c
 catomic_LDADD = $(top_builddir)/lib/liblightning.la -lm -lpthread $(SHLIB)
 catomic_SOURCES = catomic.c
 
+protect_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+protect_SOURCES = protect.c
+
 $(top_builddir)/lib/liblightning.la:
        cd $(top_builddir)/lib; $(MAKE) $(AM_MAKEFLAGS) liblightning.la
 
@@ -324,7 +327,8 @@ $(nodata_TESTS):    check.nodata.sh
 TESTS += $(nodata_TESTS)
 endif
 
-TESTS += ccall self setcode nodata ctramp carg cva_list catomic
+TESTS += ccall self setcode nodata ctramp carg cva_list catomic \
+         protect
 CLEANFILES = $(TESTS)
 
 #TESTS_ENVIRONMENT=$(srcdir)/run-test;
diff --git a/check/protect.c b/check/protect.c
new file mode 100644
index 0000000..256242b
--- /dev/null
+++ b/check/protect.c
@@ -0,0 +1,59 @@
+/*
+ * Simple test of (un)protecting a code buffer.
+ */
+
+#include <lightning.h>
+#include <stdio.h>
+#include <assert.h>
+
+#define MARKER 10
+
+int
+main(int argc, char *argv[])
+{
+    jit_state_t                 *_jit;
+    jit_node_t           *load, *label, *ok;
+    unsigned char        *ptr;
+    void               (*function)(void);
+    int                          mmap_prot, mmap_flags;
+
+    init_jit(argv[0]);
+    _jit = jit_new_state();
+
+    jit_prolog();
+
+    load = jit_movi(JIT_R0, 0);
+    jit_ldr_c(JIT_R0, JIT_R0);
+    ok = jit_forward();
+    jit_patch_at(jit_beqi(JIT_R0, MARKER), ok);
+    jit_prepare();
+    jit_pushargi(1);
+    jit_finishi(exit);
+    jit_link(ok);
+    jit_prepare();
+    jit_pushargi((jit_word_t)"%s\n");
+    jit_ellipsis();
+    jit_pushargi((jit_word_t)"ok");
+    jit_finishi(printf);
+
+    jit_epilog();
+    label = jit_indirect();
+    jit_prolog();               /* Reserves enough space for a byte.  */
+    jit_patch_at(load, label);
+
+    function = jit_emit();
+    if (function == NULL)
+       abort();
+
+    jit_unprotect ();
+    ptr = jit_address (label);
+    *ptr = MARKER;
+    jit_protect ();
+
+    jit_clear_state();
+
+    (*function)();
+
+    jit_destroy_state();
+    finish_jit();
+}
diff --git a/doc/body.texi b/doc/body.texi
index 1d8d277..58f84ee 100644
--- a/doc/body.texi
+++ b/doc/body.texi
@@ -1680,6 +1680,28 @@ Get the current memory allocation function. Also, unlike 
the GNU GMP
 counterpart, it is an error to pass @code{NULL} pointers as arguments.
 @end deftypefun
 
+@section Protection
+Unless an alternate code buffer is used (see below), @code{jit_emit}
+set the access protections that the code buffer's memory can be read and
+executed, but not modified.  One can use the following functions after
+@code{jit_emit} but before @code{jit_clear} to temporarily lift the
+protection:
+
+@deftypefun void jit_unprotect ()
+Changes the access protection that the code buffer's memory can be read and
+modified.  Before the emitted code can be invoked, @code{jit_protect}
+has to be called to reset the change.
+
+This procedure has no effect when an alternate code buffer (see below) is used.
+@end deftypefun
+
+@deftypefun void jit_protect ()
+Changes the access protection that the code buffer's memory can be read and
+executed.
+
+This procedure has no effect when an alternate code buffer (see below) is used.
+@end deftypefun
+
 @section Alternate code buffer
 To instruct @lightning{} to use an alternate code buffer it is required
 to call @code{jit_realize} before @code{jit_emit}, and then query states
diff --git a/include/lightning.h.in b/include/lightning.h.in
index 67c6af1..2ed593b 100644
--- a/include/lightning.h.in
+++ b/include/lightning.h.in
@@ -1016,6 +1016,10 @@ extern void _jit_frame(jit_state_t*, jit_int32_t);
 extern void _jit_tramp(jit_state_t*, jit_int32_t);
 #define jit_emit()             _jit_emit(_jit)
 extern jit_pointer_t _jit_emit(jit_state_t*);
+#define jit_unprotect()         _jit_unprotect(_jit)
+extern void _jit_unprotect(jit_state_t*);
+#define jit_protect()           _jit_protect(_jit)
+extern void _jit_protect(jit_state_t*);
 
 #define jit_print()            _jit_print(_jit)
 extern void _jit_print(jit_state_t*);
diff --git a/include/lightning/jit_private.h b/include/lightning/jit_private.h
index 6d93ad8..a0c59af 100644
--- a/include/lightning/jit_private.h
+++ b/include/lightning/jit_private.h
@@ -658,6 +658,8 @@ struct jit_state {
     struct {
        jit_uint8_t     *ptr;
        jit_word_t       length;
+        /* PROTECTED bytes starting at PTR are mprotect'd. */
+        jit_word_t       protected;
     } code;
     struct {
        jit_uint8_t     *ptr;
diff --git a/lib/lightning.c b/lib/lightning.c
index 00f2a07..b308844 100644
--- a/lib/lightning.c
+++ b/lib/lightning.c
@@ -2398,12 +2398,12 @@ _jit_emit(jit_state_t *_jit)
        assert(result == 0);
     }
     if (!_jit->user_code) {
-       length = _jit->pc.uc - _jit->code.ptr;
+       _jit->code.protected = _jit->pc.uc - _jit->code.ptr;
 #  if __riscv && __WORDSIZE == 64
        /* FIXME should start adding consts at a page boundary */
-       length -= _jitc->consts.hash.count * sizeof(jit_word_t);
+       _jit->code.protected -= _jitc->consts.hash.count * sizeof(jit_word_t);
 #  endif
-       result = mprotect(_jit->code.ptr, length, PROT_READ | PROT_EXEC);
+       result = mprotect(_jit->code.ptr, _jit->code.protected, PROT_READ | 
PROT_EXEC);
        assert(result == 0);
     }
 #endif /* HAVE_MMAP */
@@ -2413,6 +2413,32 @@ fail:
     return (NULL);
 }
 
+void
+_jit_protect(jit_state_t *_jit)
+{
+#if !HAVE_MMAP
+  assert (_jit->user_code);
+#else
+  int result;
+  if (_jit->user_code) return;
+  result = mprotect (_jit->code.ptr, _jit->code.protected, PROT_READ | 
PROT_EXEC);
+  assert (result == 0);
+#endif
+}
+
+void
+_jit_unprotect(jit_state_t *_jit)
+{
+#if !HAVE_MMAP
+  assert (_jit->user_code);
+#else
+  int result;
+  if (_jit->user_code) return;
+  result = mprotect (_jit->code.ptr, _jit->code.protected, PROT_READ | 
PROT_WRITE);
+  assert (result == 0);
+#endif
+}
+
 void
 _jit_frame(jit_state_t *_jit, jit_int32_t frame)
 {
-- 
2.34.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]