Snap for 15028875 from d41dba19d65193dcc81ad382eaa07a05717cdc9e to 26Q2-release Change-Id: I1b51a94daf251cc8e15d58f670bf5cf8c24e18ea
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2c7d3cd..232ef07 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml
@@ -31,3 +31,7 @@ run: | meson setup build-san -Db_sanitize=address,undefined -Dbuildtype=debugoptimized && ninja -C build-san test meson setup build-tsan -Db_sanitize=thread -Dbuildtype=debugoptimized && ninja -C build-tsan test + + - name: Build SYS_MINIMAL + run: | + meson setup build-min -Dsys_minimal=true && ninja -C build-min
diff --git a/Android.bp b/Android.bp index 061e586..35477b3 100644 --- a/Android.bp +++ b/Android.bp
@@ -64,6 +64,9 @@ "-fno-strict-overflow", "-fvisibility=hidden", ], + shared_libs: [ + "liblog", + ], } cc_library {
diff --git a/METADATA b/METADATA index 2d62a56..0ab5541 100644 --- a/METADATA +++ b/METADATA
@@ -8,14 +8,14 @@ license_type: NOTICE last_upgrade_date { year: 2026 - month: 2 - day: 17 + month: 3 + day: 12 } homepage: "https://github.com/lfi-project/lfi-runtime" identifier { type: "Git" value: "https://github.com/lfi-project/lfi-runtime" - version: "d0878d066b610ecf29b59b83939ae9dd9d3d9d19" + version: "dbe02592c0e860ffce90bbe76a7c1a2f37ef6750" primary_source: true } }
diff --git a/core/arch/arm64/callback.S b/core/arch/arm64/callback.S index 59b7dc8..fa322e2 100644 --- a/core/arch/arm64/callback.S +++ b/core/arch/arm64/callback.S
@@ -62,9 +62,11 @@ mov REG_ADDR, REG_BASE get_ctx x9 +#ifndef CTXREG // Save and replace tpidr_el0 with host value. ldr x12, [x9, REGS_HOST_TP] write_ctx x12, x11 +#endif .if \with_struct str x0, [x9, #REGS_X(0)]
diff --git a/core/arch/arm64/callback.c b/core/arch/arm64/callback.c index f36aebe..5fcdc09 100644 --- a/core/arch/arm64/callback.c +++ b/core/arch/arm64/callback.c
@@ -185,3 +185,11 @@ atomic_store_explicit(&box->cbinfo.dataentries_alias[slot].trampoline, 0, memory_order_seq_cst); } + +void +lfi_box_cb_free(struct LFIBox *box) +{ + if (box->cbinfo.dataentries_alias) + munmap(box->cbinfo.dataentries_alias, + MAXCALLBACKS * sizeof(struct CallbackDataEntry)); +}
diff --git a/core/arch/arm64/runtime.S b/core/arch/arm64/runtime.S index bf8819d..7d5f5d0 100644 --- a/core/arch/arm64/runtime.S +++ b/core/arch/arm64/runtime.S
@@ -143,6 +143,7 @@ stp x12, x13, [REG_BASE, REGS_X(12)] stp x14, x15, [REG_BASE, REGS_X(14)] stp x16, x17, [REG_BASE, REGS_X(16)] + str x18, [REG_BASE, REGS_X(18)] str REG_ADDR, [REG_BASE, REGS_ADDR] mov x1, sp stp x30, x1, [REG_BASE, REGS_X(30)] @@ -191,6 +192,7 @@ ldp x12, x13, [x0, REGS_X(12)] ldp x14, x15, [x0, REGS_X(14)] ldp x16, x17, [x0, REGS_X(16)] + ldr x18, [x0, REGS_X(18)] ldr REG_ADDR, [x0, REGS_ADDR] ldr REG_BASE, [x0, REGS_BASE] ldp x30, x1, [x0, REGS_X(30)]
diff --git a/core/arch/arm64/trampoline.S b/core/arch/arm64/trampoline.S index cbb15be..be29b2d 100644 --- a/core/arch/arm64/trampoline.S +++ b/core/arch/arm64/trampoline.S
@@ -208,12 +208,14 @@ // load target into x10 mov x10, x22 +#ifndef CTXREG // set the sandbox thread control block by saving the old value of // [tpidr_el0, TLS_SLOT_LFI] into the context and setting it to point to // the context itself. get_ctx x12 str x12, [x13, REGS_HOST_TP] write_ctx x13, x12 +#endif // save user sp to stack ldr x12, [x13, REGS_SP] @@ -232,6 +234,10 @@ // set address pointer to a valid value mov REG_ADDR, REG_BASE +#ifdef CTXREG + ldr x25, [x13, REGS_X(25)] +#endif + #ifndef STORES_ONLY // Zero non-argument registers for full LFI. // TODO: calling convention or LFI_INVOKE should enforce that all unused @@ -240,8 +246,8 @@ #endif // enter sandbox - add x10, REG_BASE, w10, uxtw - br x10 + add x16, REG_BASE, w10, uxtw + br x16 // the previous call should return through lfi_ret udf #0 @@ -257,9 +263,11 @@ lfi_ret: bti jc get_ctx REG_BASE +#ifndef CTXREG // restore host thread control block ldr x19, [REG_BASE, REGS_HOST_TP] write_ctx x19, x20 +#endif .lfi_ret_internal: // restore host stack ldr x19, [REG_BASE, REGS_HOST_SP]
diff --git a/core/arch/riscv64/callback.c b/core/arch/riscv64/callback.c index 5ea9c61..bbf1293 100644 --- a/core/arch/riscv64/callback.c +++ b/core/arch/riscv64/callback.c
@@ -29,3 +29,9 @@ { assert(!"unimplemented"); } + +void +lfi_box_cb_free(struct LFIBox *box) +{ + (void) box; +}
diff --git a/core/arch/x64/callback.S b/core/arch/x64/callback.S index 28c5dea..2fd3ef1 100644 --- a/core/arch/x64/callback.S +++ b/core/arch/x64/callback.S
@@ -73,6 +73,7 @@ // Save %r11 across the call (and stack alignment). pushq %r11 + cld callq *%r10 popq %r11
diff --git a/core/arch/x64/callback.c b/core/arch/x64/callback.c index 8bce9f4..dee06d8 100644 --- a/core/arch/x64/callback.c +++ b/core/arch/x64/callback.c
@@ -151,3 +151,11 @@ atomic_store_explicit(&box->cbinfo.cbentries_alias[slot].trampoline, 0, memory_order_seq_cst); } + +void +lfi_box_cb_free(struct LFIBox *box) +{ + if (box->cbinfo.cbentries_alias) + munmap(box->cbinfo.cbentries_alias, + MAXCALLBACKS * sizeof(struct CallbackEntry)); +}
diff --git a/core/arch/x64/runtime.S b/core/arch/x64/runtime.S index f0eb2a9..11237a5 100644 --- a/core/arch/x64/runtime.S +++ b/core/arch/x64/runtime.S
@@ -92,6 +92,7 @@ #endif // put val in the return register movq %rsi, %rax + cld // restore callee-saved registers saved in lfi_ctx_entry popq %rbp popq %rbx @@ -151,6 +152,7 @@ // restore host stack and call handler movq REGS_HOST_SP(%rcx), %rsp + cld pushq %rcx movq %rcx, %rdi callq lfi_syscall_handler @@ -236,7 +238,7 @@ .p2align 4 lfi_set_tp: #ifdef HAVE_PKU - pushq %rax + pushq %rdx pushq %rcx pushq %rax pku_all_access
diff --git a/core/arch/x64/trampoline.S b/core/arch/x64/trampoline.S index 043fcee..5dd5ebd 100644 --- a/core/arch/x64/trampoline.S +++ b/core/arch/x64/trampoline.S
@@ -285,6 +285,7 @@ movq %rbp, REGS_RSP(%rdi) popq %rbp // pop dummy value // return value should already be in %rax + cld popq %rbp popq %rbx popq %r12
diff --git a/core/box.c b/core/box.c index 1446e47..860f95d 100644 --- a/core/box.c +++ b/core/box.c
@@ -95,6 +95,10 @@ null_rtcall->rtcalls[2] = (uintptr_t) &lfi_set_tp; #endif null_rtcall->rtcalls[3] = (uintptr_t) &lfi_ret; + + int r2 = protectmem((void *) box->base, pagesize, PROT_READ, + box->pkey); + assert(r2 == 0); } // Map read-only. @@ -113,8 +117,7 @@ } size_t size = engine->opts.boxsize; - uintptr_t base = boxmap_addspace(engine->bm, - box_footprint(size, engine->opts)); + uintptr_t base = boxmap_addspace(engine->bm, box_footprint(size)); if (base == 0) { lfi_error = LFI_ERR_BOXMAP; goto err1; @@ -129,7 +132,7 @@ else LOG(engine, "could not allocate pkey: invalid argument"); lfi_error = LFI_ERR_PKU; - return NULL; + goto err1; } assert(pkey != 0); int r = pkey_mprotect((void *) base, size, PROT_NONE, pkey); @@ -141,9 +144,9 @@ .base = base, .size = size, .engine = engine, - .min = base + engine->guardsize + engine->opts.pagesize, - .max = base + size - engine->guardsize, - .max_exec = base + size - engine->guardsize, + .min = base + engine->opts.pagesize, + .max = base + size - BOX_INTERNAL_GUARD, + .max_exec = base + size - BOX_INTERNAL_GUARD, }; syssetup(box); @@ -157,7 +160,7 @@ return box; err2: - boxmap_rmspace(engine->bm, base, box_footprint(size, engine->opts)); + boxmap_rmspace(engine->bm, base, box_footprint(size)); err1: free(box); return NULL; @@ -331,6 +334,15 @@ return protectmem((void *) start, size, host_prot(prot), box->pkey); } +static void +cbunmap(uint64_t start, size_t len, struct MMInfo info, void *udata) +{ + (void) udata, (void) info; + void *p = mmap((void *) start, len, PROT_NONE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(p == (void *) start); +} + static lfiptr box_mapany(struct LFIBox *box, size_t size, int prot, int flags, int fd, off_t off, bool no_verify) @@ -340,7 +352,7 @@ return (lfiptr) -1; int r = mapverify(box, addr, size, prot, flags, fd, off, no_verify); if (r < 0) { - mm_unmap(&box->mm, addr, size); + mm_unmap_cb(&box->mm, addr, size, cbunmap, NULL); return (lfiptr) -1; } return p2l(box, addr); @@ -360,20 +372,12 @@ return box_mapany(box, size, prot, flags, fd, off, false); } -static void -cbunmap(uint64_t start, size_t len, struct MMInfo info, void *udata) -{ - (void) udata, (void) info; - void *p = mmap((void *) start, len, PROT_NONE, - MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); - assert(p == (void *) start); -} - EXPORT lfiptr lfi_box_mapat(struct LFIBox *box, lfiptr addr, size_t size, int prot, int flags, int fd, off_t off) { - assert(l2p(box, addr) >= box->min && l2p(box, addr) + size <= box->max); + if (!lfi_box_bufvalid(box, addr, size)) + return (lfiptr) -1; uintptr_t m_addr = mm_mapat_cb(&box->mm, l2p(box, addr), size, prot, flags, fd, off, cbunmap, NULL); @@ -381,7 +385,7 @@ return (lfiptr) -1; int r = mapverify(box, m_addr, size, prot, flags, fd, off, false); if (r < 0) { - mm_unmap(&box->mm, m_addr, size); + mm_unmap_cb(&box->mm, m_addr, size, cbunmap, NULL); return (lfiptr) -1; } return p2l(box, m_addr); @@ -391,14 +395,15 @@ lfi_box_mapat_register(struct LFIBox *box, lfiptr addr, size_t size, int prot, int flags, int fd, off_t off) { - assert(l2p(box, addr) >= box->min && l2p(box, addr) + size <= box->max); + if (!lfi_box_bufvalid(box, addr, size)) + return (lfiptr) -1; uintptr_t m_addr = mm_mapat_cb(&box->mm, l2p(box, addr), size, prot, flags, fd, off, cbunmap, NULL); if (m_addr == (uintptr_t) -1) return (lfiptr) -1; - int r = verify(box, m_addr, size, prot); - if (r < 0) { + bool r = verify(box, m_addr, size, prot); + if (!r) { mm_unmap(&box->mm, m_addr, size); return (lfiptr) -1; } @@ -408,22 +413,26 @@ EXPORT int lfi_box_mprotect(struct LFIBox *box, lfiptr addr, size_t size, int prot) { - assert(l2p(box, addr) >= box->min && l2p(box, addr) + size <= box->max); + if (!lfi_box_bufvalid(box, addr, size)) + return -1; - int r = mm_protect(&box->mm, l2p(box, addr), size, prot); + int r = protectverify(box, l2p(box, addr), size, prot, false); if (r < 0) return r; - return protectverify(box, l2p(box, addr), size, prot, false); + return mm_protect(&box->mm, l2p(box, addr), size, prot); } EXPORT int lfi_box_mprotect_noverify(struct LFIBox *box, lfiptr addr, size_t size, int prot) { - int r = mm_protect(&box->mm, l2p(box, addr), size, prot); + if (!lfi_box_bufvalid(box, addr, size)) + return -1; + + int r = protectverify(box, l2p(box, addr), size, prot, true); if (r < 0) return r; - return protectverify(box, l2p(box, addr), size, prot, true); + return mm_protect(&box->mm, l2p(box, addr), size, prot); } EXPORT bool @@ -444,7 +453,7 @@ EXPORT int lfi_box_munmap(struct LFIBox *box, lfiptr addr, size_t size) { - if (l2p(box, addr) >= box->min && l2p(box, addr) + size < box->max) + if (lfi_box_bufvalid(box, addr, size)) return mm_unmap_cb(&box->mm, l2p(box, addr), size, cbunmap, NULL); return -1; } @@ -452,11 +461,12 @@ EXPORT void lfi_box_free(struct LFIBox *box) { - void *p = mmap((void *) box->base, box->size, PROT_NONE, - MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); - assert(p == (void *) box->base); - boxmap_rmspace(box->engine->bm, box->base, - box_footprint(box->size, box->engine->opts)); + size_t pagesize = box->engine->opts.pagesize; + void *p = mmap((void *) (box->base - pagesize), box->size + pagesize, + PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(p == (void *) (box->base - pagesize)); + lfi_box_cb_free(box); + boxmap_rmspace(box->engine->bm, box->base, box_footprint(box->size)); #ifdef HAVE_PKU if (box->pkey != 0) pkey_free(box->pkey); @@ -476,7 +486,7 @@ lfi_box_bufvalid(struct LFIBox *box, lfiptr addr, size_t size) { lfiptr lp = l2p(box, addr); - return lp >= box->min && lp + size <= box->max; + return lp >= box->min && lp <= box->max && size <= box->max - lp; } EXPORT void *
diff --git a/core/boxmap.c b/core/boxmap.c index dbfb716..20289c4 100644 --- a/core/boxmap.c +++ b/core/boxmap.c
@@ -60,7 +60,7 @@ { size_t total = 0; for (size_t i = 0; i < map->nregions; i++) { - total += map->regions[i].size - 2 * map->opts.guardsize; + total += map->regions[i].size; } return total; } @@ -100,13 +100,14 @@ return false; } - // Since mmap gives us something page-aligned, we need to find a region - // within it that is properly chunk-aligned. - uintptr_t alignbase = ceilp((uintptr_t) base, map->opts.chunksize); - size_t alignsize = truncp(alignbase + - (size - (alignbase - (uintptr_t) base)), - map->opts.chunksize) - - alignbase; + // Find a chunk-aligned sub-region that has at least guardsize bytes of + // space on each side. The guard regions are the space between the mmap + // edges and the chunk-aligned allocatable region. + uintptr_t start = (uintptr_t) base + map->opts.guardsize; + uintptr_t end = (uintptr_t) base + size - map->opts.guardsize; + + uintptr_t alignbase = ceilp(start, map->opts.chunksize); + size_t alignsize = truncp(end, map->opts.chunksize) - alignbase; struct ExtAlloc *alloc = extalloc_new(alignbase, alignsize, map->opts.chunksize); @@ -120,11 +121,6 @@ return false; } - // Reserve the guard regions on either end of the new region. - extalloc_allocat(alloc, alignbase, map->opts.guardsize); - extalloc_allocat(alloc, alignbase + alignsize - map->opts.guardsize, - map->opts.guardsize); - map->regions[map->nregions++] = (struct AddrRegion) { .base = (void *) alignbase, .size = alignsize,
diff --git a/core/core.c b/core/core.c index 097fbd6..eacd621 100644 --- a/core/core.c +++ b/core/core.c
@@ -94,9 +94,7 @@ struct BoxMapOptions bm_opts = (struct BoxMapOptions) { .chunksize = gb(4), - // This is the guard size between the edge of the boxmap region and the - // outer world. - .guardsize = box_footprint(gb(4), opts), + .guardsize = REGION_GUARD, }; struct BoxMap *bm = boxmap_new(bm_opts); if (!bm) { @@ -104,11 +102,11 @@ goto err1; } - // Reserve space for n sandboxes with appropriate footprint, 2 guard pages, - // and 2 chunks worth of slack because boxmap has to do internal alignment - // when mmap returns non-chunk-aligned region. - size_t reserve = nsandboxes * box_footprint(opts.boxsize, opts) + - bm_opts.chunksize * 2 + bm_opts.guardsize * 2; + // Reserve space for n sandboxes with appropriate footprint, region guards + // on each side, and 1 chunk worth of slack because boxmap has to do + // internal alignment when mmap returns non-chunk-aligned region. + size_t reserve = nsandboxes * box_footprint(opts.boxsize) + + bm_opts.chunksize + bm_opts.guardsize * 2; if (nsandboxes > 0) { if (!boxmap_reserve(bm, reserve)) { @@ -126,7 +124,6 @@ *engine = (struct LFIEngine) { .bm = bm, .opts = opts, - .guardsize = kb(192), }; if (!engine->opts.no_init_sigaltstack)
diff --git a/core/core.h b/core/core.h index 5056e9a..e6a07b6 100644 --- a/core/core.h +++ b/core/core.h
@@ -21,7 +21,6 @@ void (*sys_handler)(struct LFIContext *ctx); struct LFIContext *(*clone_cb)(struct LFIBox *box); - size_t guardsize; stack_t altstack; }; @@ -89,6 +88,8 @@ extern thread_local int lfi_error; extern thread_local char *lfi_error_desc; +void lfi_box_cb_free(struct LFIBox *box); + static inline size_t kb(size_t x) { @@ -107,31 +108,52 @@ return x * 1024 * 1024 * 1024; } -// Return the total amount of virtual address space needed for a sandbox of a -// certain size. This depends on the architecture because it is effectively -// reserving a guard region beyond the sandbox. -static inline size_t -box_footprint(size_t boxsize, struct LFIOptions opts) -{ - if (boxsize != gb(4)) { - LOG_( - "warning: box_footprint does not properly support non-4GiB sandboxes"); - return boxsize; - } +// Guard sizes for sandbox isolation. These are configurable per-architecture. +// +// BOX_INTERNAL_GUARD: space at the end of each sandbox (within the box's +// allocated size) that is not usable by sandbox code. This reduces the +// sandbox's usable address range. +// +// BOX_EXTERNAL_GUARD: additional space allocated beyond each sandbox's size, +// increasing the per-sandbox footprint. This provides isolation between +// adjacent sandboxes when hardware masking alone is insufficient. +// +// REGION_GUARD: space reserved on each side of the entire sandbox pool region, +// protecting against accesses escaping the pool. + #if defined(LFI_ARCH_ARM64) - return gb(8); + +#define BOX_INTERNAL_GUARD kb(192) +#define BOX_EXTERNAL_GUARD 0 +#define REGION_GUARD mb(512) + #elif defined(LFI_ARCH_X64) +#define BOX_INTERNAL_GUARD 0 #ifdef HAVE_PKU - return gb(4); +#define BOX_EXTERNAL_GUARD 0 +#define REGION_GUARD 0 #else - // TODO: verify that we can safely reduce this to gb(4) if Segue is enabled. - return gb(44); +// TODO: verify that we can safely reduce BOX_EXTERNAL_GUARD if Segue is +// enabled. +#define BOX_EXTERNAL_GUARD gb(40) +#define REGION_GUARD gb(40) #endif #elif defined(LFI_ARCH_RISCV64) - return gb(4); + +#define BOX_INTERNAL_GUARD 0 +#define BOX_EXTERNAL_GUARD 0 +#define REGION_GUARD 0 + #else #error "invalid architecture" #endif + +// Return the total amount of virtual address space needed for a sandbox of a +// certain size. This is the sandbox size plus any external guard. +static inline size_t +box_footprint(size_t boxsize) +{ + return boxsize + BOX_EXTERNAL_GUARD; }
diff --git a/core/log.c b/core/log.c index d3bec14..93f0f40 100644 --- a/core/log.c +++ b/core/log.c
@@ -41,19 +41,3 @@ return strp; } - -#ifdef __ANDROID__ - -// This is a weak definition of __android_log_print in case it doesn't exist -// that just prints to stderr. This is used when building for Android but when -// liblog is not linked. -__attribute__((weak, visibility("default"))) int -__android_log_print(int prio, const char *tag, const char *fmt, ...) -{ - (void) prio; - (void) tag; - (void) fmt; - return 0; -} - -#endif
diff --git a/core/log.h b/core/log.h index 221809d..5b7b795 100644 --- a/core/log.h +++ b/core/log.h
@@ -19,15 +19,22 @@ #endif -#if 0 && defined(__ANDROID__) +#if defined(__ANDROID__) #include <android/log.h> +#include <stdio.h> -#define LOG_(...) \ - ((void) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) +#define LOG_(fmt, ...) \ + do { \ + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##__VA_ARGS__); \ + fprintf(stderr, "[" LOG_TAG "] " fmt "\n", ##__VA_ARGS__); \ + } while (0) -#define ERROR(...) \ - ((void) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) +#define ERROR(fmt, ...) \ + do { \ + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__); \ + fprintf(stderr, "[" LOG_TAG "] " fmt "\n", ##__VA_ARGS__); \ + } while (0) #else
diff --git a/core/mmap.c b/core/mmap.c index 705c2b6..d9518b1 100644 --- a/core/mmap.c +++ b/core/mmap.c
@@ -204,7 +204,7 @@ length = mmceil(mm, length); if (!mmvalid(mm, addr, length)) - return -LINUX_EINVAL; + return (uintptr_t) -1; struct MMNode *new = malloc(sizeof(struct MMNode)); if (!new) @@ -367,10 +367,11 @@ { struct MMNode *node = mm->nodes; while (node) { + struct MMNode *next = node->next; if (!node->info.original) mm_unmap_cb(mm, node->base << mm->p2pagesize, node->len << mm->p2pagesize, ufn, udata); - node = node->next; + node = next; } }
diff --git a/linux/fd.c b/linux/fd.c index cb137a4..df59e68 100644 --- a/linux/fd.c +++ b/linux/fd.c
@@ -79,10 +79,17 @@ t->fds[newfd] = knewfd; } else { knewfd = t->fds[newfd]; - if (knewfd == -1) - knewfd = newfd; - if (dup2(koldfd, knewfd) < 0) - goto err; + if (knewfd == -1) { + // Slot is unoccupied: allocate a new kernel fd rather than + // using the raw sandbox fd number, which could collide with + // monitor-internal file descriptors. + knewfd = dup(koldfd); + if (knewfd == -1) + goto err; + } else { + if (dup2(koldfd, knewfd) < 0) + goto err; + } t->fds[newfd] = knewfd; if (t->dirs[newfd]) { free(t->dirs[newfd]); @@ -133,9 +140,11 @@ t->fds[i] = -1; } +#ifndef SYS_MINIMAL t->fds[0] = dup(STDIN_FILENO); t->fds[1] = dup(STDOUT_FILENO); t->fds[2] = dup(STDERR_FILENO); +#endif t->passthrough = engine->opts.sys_passthrough; }
diff --git a/linux/include/lfi_linux.h b/linux/include/lfi_linux.h index 3105f85..4dc30e6 100644 --- a/linux/include/lfi_linux.h +++ b/linux/include/lfi_linux.h
@@ -69,6 +69,10 @@ struct LFILinuxEngine * lfi_linux_lib_engine(void); +// Frees the library engine and its underlying LFIEngine. +void +lfi_linux_lib_free(void); + // Frees the resources allocated for the linux engine (but not the underlying // LFIEngine). void
diff --git a/linux/linux.c b/linux/linux.c index 68bd60b..ff7aaee 100644 --- a/linux/linux.c +++ b/linux/linux.c
@@ -42,7 +42,7 @@ static struct LFILinuxEngine *lib_engine; // Total number of procs (libraries) that the lib_engine is initialized for. -#define MAX_LIBRARIES 16 +#define MAX_LIBRARIES 1 EXPORT bool lfi_linux_lib_init(struct LFIOptions opts, struct LFILinuxOptions linux_opts) @@ -70,6 +70,16 @@ } EXPORT void +lfi_linux_lib_free(void) +{ + if (lib_engine) { + lfi_free(lib_engine->engine); + free(lib_engine); + lib_engine = NULL; + } +} + +EXPORT void lfi_linux_free(struct LFILinuxEngine *engine) { free(engine);
diff --git a/linux/log.h b/linux/log.h index 1bd8201..acba48e 100644 --- a/linux/log.h +++ b/linux/log.h
@@ -16,7 +16,7 @@ #endif -#if 0 && defined(__ANDROID__) +#if defined(__ANDROID__) #include <android/log.h>
diff --git a/linux/proc.c b/linux/proc.c index e874db0..916088e 100644 --- a/linux/proc.c +++ b/linux/proc.c
@@ -97,8 +97,8 @@ // should do the same thing with the interpreter, even if we could // load it directly from the file. if (prog_fd == -1) { - interp.fd = -1; close(interp.fd); + interp.fd = -1; } LOG(proc->engine, "using sandbox dynamic linker: %s", interp_path); } else {
diff --git a/linux/sys/sys.h b/linux/sys/sys.h index f044478..59be41f 100644 --- a/linux/sys/sys.h +++ b/linux/sys/sys.h
@@ -88,11 +88,16 @@ { if (!ptrcheck(t, pathp)) return NULL; + // Clamp the copy length to the sandbox boundary so we never read past + // the end of the sandbox's valid address range. + size_t maxlen = t->proc->box_info.max - pathp; + if (maxlen > FILENAME_MAX - 1) + maxlen = FILENAME_MAX - 1; char *host = malloc(FILENAME_MAX); if (!host) return NULL; - strncpy(host, (char *) lfi_box_p2l(t->proc->box, pathp), FILENAME_MAX - 1); - host[FILENAME_MAX - 1] = 0; + strncpy(host, (char *) lfi_box_l2p(t->proc->box, pathp), maxlen); + host[maxlen] = 0; return host; }
diff --git a/linux/sys/sys_fchdir.c b/linux/sys/sys_fchdir.c index 38b156b..6da14e4 100644 --- a/linux/sys/sys_fchdir.c +++ b/linux/sys/sys_fchdir.c
@@ -3,6 +3,8 @@ int sys_fchdir(struct LFILinuxThread *t, int fd) { + if (fd < 0 || fd >= LINUX_NOFILE) + return -LINUX_EBADF; LOCK_WITH_DEFER(&t->proc->fdtable.lk, lk_fdtable); if (t->proc->fdtable.fds[fd] == -1) return -LINUX_EBADF;
diff --git a/linux/sys/sys_fchmod.c b/linux/sys/sys_fchmod.c index 45cdf18..aec5fbf 100644 --- a/linux/sys/sys_fchmod.c +++ b/linux/sys/sys_fchmod.c
@@ -8,5 +8,5 @@ int kfd = fdget(&t->proc->fdtable, fd); if (kfd == -1) return -LINUX_EBADF; - return HOST_ERR(int, fchmod(fd, mode)); + return HOST_ERR(int, fchmod(kfd, mode)); }
diff --git a/linux/sys_minimal.c b/linux/sys_minimal.c index 12a0421..418c6ee 100644 --- a/linux/sys_minimal.c +++ b/linux/sys_minimal.c
@@ -20,10 +20,6 @@ #endif SYS(brk, sys_brk(t, a0)) - SYS(mmap, - sys_mmap(t, a0, a1, a2, a3, a4, a5)) - SYS(munmap, - sys_munmap(t, a0, a1)) SYS(exit_group, sys_exit_group(t, a0)) SYS(exit,
diff --git a/linux/trampoline.c b/linux/trampoline.c index d1ed95e..d9e3095 100644 --- a/linux/trampoline.c +++ b/linux/trampoline.c
@@ -47,7 +47,11 @@ t->stack_size = stacksize; // Set stack pointer to top of stack (stack grows down). +# if defined(__aarch64__) || defined(_riscv) lfi_ctx_regs(t->ctx)->sp = t->stack + stacksize; +# elif defined(__x86_64__) + lfi_ctx_regs(t->ctx)->rsp = t->stack + stacksize; +# endif // Set tp to 0 (no TLS support in sys_minimal mode). lfi_ctx_set_tp(t->ctx, 0);
diff --git a/subprojects/packagefiles/lfi-verifier/meson.build b/subprojects/packagefiles/lfi-verifier/meson.build index 32b9c6d..99bf8df 100644 --- a/subprojects/packagefiles/lfi-verifier/meson.build +++ b/subprojects/packagefiles/lfi-verifier/meson.build
@@ -31,16 +31,14 @@ c_defines = [] if 'arm64' in arch - subdir('src/decode/disarm') - dependencies += disarm64.as_link_whole() + dependencies += subproject('disarm').get_variable('disarm64').as_link_whole() srcs += files( 'src/arm64/verify.c', ) c_defines += '-DARCH_ARM64' endif if 'x64' in arch - subdir('src/decode/fadec') - dependencies += fadec.as_link_whole() + dependencies += subproject('fadec').get_variable('fadec').as_link_whole() srcs += files( 'src/x64/verify.c', 'src/x64/bdd.c',