@@ -39,6 +39,25 @@ okl_uptr round_up(okl_uptr n, okl_uptr to) { return (n + to - 1) & ~(to - 1); }
3939
4040} // namespace
4141
42+ namespace {
43+ // Whether this kernel has `mseal': it answers a range of no length with zero,
44+ // and a kernel without it ENOSYS.
45+ bool sealing () {
46+ static int known = -1 ;
47+ if (known < 0 ) known = okl::failed (okl::sys (okl::nr_mseal, 0 , 0 , 0 )) ? 0 : 1 ;
48+ return known == 1 ;
49+ }
50+ // Whether instructions mapped PROT_BTI are held to branch targets: the
51+ // processor states it in AT_HWCAP2 (HWCAP2_BTI), and only on aarch64.
52+ bool branch_targets () {
53+ #if defined(__aarch64__)
54+ return (okl::auxval (26 /* AT_HWCAP2 */ ) & (okl_ulong{1 } << 17 )) != 0 ;
55+ #else
56+ return false ;
57+ #endif
58+ }
59+ } // namespace
60+
4261extern " C" {
4362
4463void * kal_exec_alloc (kal_uintptr size) {
@@ -51,6 +70,26 @@ void* kal_exec_alloc(kal_uintptr size) {
5170 return reinterpret_cast <void *>(r);
5271}
5372
73+ // AT AN ADDRESS (0.23): MAP_FIXED_NOREPLACE, which refuses rather than replaces
74+ // what is there. A kernel before 4.17 does not know the flag and reads the
75+ // address as a hint, so the answer is compared and a mapping placed elsewhere
76+ // released: the address is either given or refused, never approximated.
77+ void * kal_exec_alloc_at (void * at, kal_uintptr size) {
78+ const okl_uptr where = reinterpret_cast <okl_uptr>(at);
79+ if (size == 0 || where == 0 || (where & (page () - 1 )) != 0 ) return nullptr ;
80+ const okl_uptr bytes = round_up (static_cast <okl_uptr>(size), page ());
81+ const okl_long r = okl::sys (okl::nr_mmap, static_cast <okl_long>(where), static_cast <okl_long>(bytes),
82+ okl::prot_read | okl::prot_write,
83+ okl::map_private | okl::map_anonymous | 0x100000 /* MAP_FIXED_NOREPLACE */ ,
84+ -1 , 0 );
85+ if (okl::failed (r)) return nullptr ;
86+ if (static_cast <okl_uptr>(r) != where) {
87+ okl::sys (okl::nr_munmap, r, static_cast <okl_long>(bytes));
88+ return nullptr ;
89+ }
90+ return at;
91+ }
92+
5493int kal_exec_publish (void * p, kal_uintptr size) {
5594 if (p == nullptr || size == 0 ) return kal_err_invalid;
5695 const okl_uptr bytes = round_up (static_cast <okl_uptr>(size), page ());
@@ -114,6 +153,25 @@ int kal_exec_publish_part(void* region, kal_uintptr offset, kal_uintptr size) {
114153 return okl::failed (r) ? okl::translate (r) : kal_ok;
115154}
116155
156+ // SEALED READ-ONLY (0.23): the protection, and, for ever, `mseal' (Linux 6.10)
157+ // over it, after which the kernel refuses to change the part's protection or to
158+ // unmap it --- `mprotect' and `munmap' of it report EPERM, which this
159+ // implementation reports as kal_err_permission.
160+ int kal_exec_seal_part (void * region, kal_uintptr offset, kal_uintptr size, kal_uintptr flags) {
161+ const okl_uptr g = page ();
162+ if (region == nullptr || size == 0 || (offset & (g - 1 )) != 0 || (size & (g - 1 )) != 0
163+ || (reinterpret_cast <okl_uptr>(region) & (g - 1 )) != 0 || (flags & ~KAL_EXEC_SEAL_FOREVER ) != 0 )
164+ return kal_err_invalid;
165+ const okl_long at = reinterpret_cast <okl_long>(static_cast <char *>(region) + offset);
166+ const okl_long r = okl::sys (okl::nr_mprotect, at, static_cast <okl_long>(size), okl::prot_read);
167+ if (okl::failed (r)) return okl::translate (r);
168+ if ((flags & KAL_EXEC_SEAL_FOREVER ) && sealing ()) {
169+ const okl_long m = okl::sys (okl::nr_mseal, at, static_cast <okl_long>(size), 0 );
170+ if (okl::failed (m)) return okl::translate (m);
171+ }
172+ return kal_ok;
173+ }
174+
117175kal_uintptr kal_exec_granularity (void ) { return page (); }
118176
119177// A PART THAT IS A FILE'S (0.21): the file's pages mapped over the part,
@@ -127,18 +185,29 @@ int kal_exec_map_part(void* region, kal_uintptr offset, kal_uintptr size, kal_fi
127185 const int fd = okl::unpack (f.h );
128186 if (region == nullptr || size == 0 || fd < 0 || (offset & (g - 1 )) != 0 || (size & (g - 1 )) != 0
129187 || (reinterpret_cast <okl_uptr>(region) & (g - 1 )) != 0 || at % KAL_MAP_ALIGNMENT != 0
130- || (how & ~KAL_EXEC_MAP_EXECUTE ) != 0 )
188+ || (how & ~(KAL_EXEC_MAP_EXECUTE | KAL_EXEC_MAP_PREFETCH | KAL_EXEC_MAP_BTI | KAL_EXEC_MAP_WRITE )) != 0
189+ || ((how & KAL_EXEC_MAP_WRITE ) && (how & KAL_EXEC_MAP_EXECUTE )))
131190 return kal_err_invalid;
132191 okl::kstat st{};
133192 const okl_long s = okl::sys (okl::nr_fstat, fd, reinterpret_cast <okl_long>(&st));
134193 if (okl::failed (s)) return okl::translate (s);
135194 if ((st.mode & okl::s_ifmt) != okl::s_ifreg) return kal_err_not_supported;
136195 const kal_u64 length = st.size > 0 ? static_cast <kal_u64>(st.size ) : 0 ;
137196 if (at > length || static_cast <kal_u64>(size) > length - at) return kal_err_invalid;
138- const okl_long prot = okl::prot_read | ((how & KAL_EXEC_MAP_EXECUTE ) ? okl::prot_exec : 0 );
197+ // READ IN NOW (0.23): MAP_POPULATE reads the part and fills its page
198+ // tables in the one call, where each page would otherwise be a fault of its
199+ // own on its first touch. BRANCH TARGETS: PROT_BTI, where the processor
200+ // holds them.
201+ const bool bti = (how & KAL_EXEC_MAP_BTI ) && (how & KAL_EXEC_MAP_EXECUTE ) && branch_targets ();
202+ // WRITTEN PRIVATELY (0.23): the mapping is private already, so a page the
203+ // program writes is its own copy and the file is not changed.
204+ const okl_long prot = okl::prot_read | ((how & KAL_EXEC_MAP_EXECUTE ) ? okl::prot_exec : 0 )
205+ | ((how & KAL_EXEC_MAP_WRITE ) ? okl::prot_write : 0 )
206+ | (bti ? 0x10 /* PROT_BTI */ : 0 );
207+ const okl_long populate = (how & KAL_EXEC_MAP_PREFETCH ) ? 0x8000 /* MAP_POPULATE */ : 0 ;
139208 const okl_long r = okl::sys (okl::nr_mmap,
140209 reinterpret_cast <okl_long>(static_cast <char *>(region) + offset),
141- static_cast <okl_long>(size), prot, okl::map_private | okl::map_fixed, fd,
210+ static_cast <okl_long>(size), prot, okl::map_private | okl::map_fixed | populate , fd,
142211 static_cast <okl_long>(at));
143212 if (okl::failed (r)) {
144213 // ENODEV: the file system does not map. EPERM: its files are not
@@ -163,7 +232,8 @@ void kal_exec_free(void* p, kal_uintptr size) {
163232kal_uintptr kal_exec_props (void ) {
164233 // Executable memory is available to every artifact on this kernel: nothing
165234 // here is granted only to a program produced in a particular way.
166- return KAL_EXEC_PROP_REPUBLISH | KAL_EXEC_PROP_AVAILABLE | KAL_EXEC_PROP_FILE ;
235+ return KAL_EXEC_PROP_REPUBLISH | KAL_EXEC_PROP_AVAILABLE | KAL_EXEC_PROP_FILE | KAL_EXEC_PROP_PLACE
236+ | (sealing () ? KAL_EXEC_PROP_SEAL_FOREVER : 0u ) | (branch_targets () ? KAL_EXEC_PROP_BTI : 0u );
167237}
168238
169239} // extern "C"
0 commit comments