From da5c1e983384777b9f62b8cc5504a22e8f58dae0 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 30 Jan 2022 14:21:08 -0800 Subject: [PATCH] [kernel] Add new zero_ok flag to syscall params The new zero_ok flag is similar to optional for reference parameters, but only in cases where there is a length parameter. If that parameter is a reference parameter itself and is null, or it is non-null and contains a non-zero length, or there is no length parameter, then the main parameter may not be null. --- definitions/objects/endpoint.def | 4 +-- scripts/definitions/types/function.py | 4 ++- src/kernel/syscall_verify.cpp.cog | 42 ++++++++++++++++++++------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/definitions/objects/endpoint.def b/definitions/objects/endpoint.def index da33cde..21ddb09 100644 --- a/definitions/objects/endpoint.def +++ b/definitions/objects/endpoint.def @@ -22,7 +22,7 @@ object endpoint : object { # is available. method receive [cap:receive] { param tag uint64 [out] - param data buffer [out optional] + param data buffer [out zero_ok] param timeout uint64 # Receive timeout in nanoseconds } @@ -31,7 +31,7 @@ object endpoint : object { # operation. method sendrecv [cap:send cap:receive] { param tag uint64 [inout] - param data buffer [inout] + param data buffer [inout zero_ok] param timeout uint64 # Receive timeout in nanoseconds } } diff --git a/scripts/definitions/types/function.py b/scripts/definitions/types/function.py index 501cade..eb3b0e7 100644 --- a/scripts/definitions/types/function.py +++ b/scripts/definitions/types/function.py @@ -62,5 +62,7 @@ class Param: @property def optional(self): - return "optional" in self.options + if "zero_ok" in self.options: return "zero_ok" + elif "optional" in self.options: return "optional" + else: return "required" diff --git a/src/kernel/syscall_verify.cpp.cog b/src/kernel/syscall_verify.cpp.cog index 97390b0..529f43e 100644 --- a/src/kernel/syscall_verify.cpp.cog +++ b/src/kernel/syscall_verify.cpp.cog @@ -22,11 +22,34 @@ for obj in syscalls.exposes: //[[[end]]] namespace { + enum class req { required, optional, zero_ok }; + template __attribute__((always_inline)) - inline bool check_refparam(const T* param, bool optional) { - return reinterpret_cast(param) < arch::kernel_offset && - (optional || param); + inline bool range_check(const T* param) { + return reinterpret_cast(param) < arch::kernel_offset; + } + + template + __attribute__((always_inline)) + inline bool check_refparam(const T* param, req required) { + return range_check(param) && ((required == req::optional) || param); + } + + template + __attribute__((always_inline)) + inline bool check_refparam(const T* param, size_t len, req required) { + bool nullok = (required == req::optional) || (required == req::zero_ok && !len); + return range_check(param) && (param || nullok); + } + + template + __attribute__((always_inline)) + inline bool check_refparam(const T* param, size_t *len, req required) { + if (!range_check(len)) return false; + if (len) return check_refparam(param, *len, required); + // if len is null but param is not, call that invalid. + else return !param && required == req::optional; } // When called with more than 6 arguments, the 7th argument to the @@ -67,7 +90,7 @@ for id, scope, method in syscalls.methods: argdefs.append(("j6_handle_t *", "self")) cxxargdefs.append("j6_handle_t *self") args.append("self") - refparams.append(("self", False)) + refparams.append(("self", "required")) elif not method.static: argdefs.append(("j6_handle_t", "self")) @@ -104,10 +127,9 @@ for id, scope, method in syscalls.methods: if param.refparam: subs = param.type.c_names(param.options) - refparams.append((param.name + subs[0][1], param.optional)) - if param.outparam: - for sub in subs[1:]: - refparams.append((param.name + sub[1], param.optional)) + checkargs = map(lambda x: f"{param.name}{x[1]}", subs) + + refparams.append((", ".join(checkargs), param.optional)) first_args = ", ".join(map(lambda x: f"{x[0]} {x[1]}", argdefs[:6])) extra_argdefs = argdefs[6:] @@ -124,8 +146,8 @@ for id, scope, method in syscalls.methods: if extra_argdefs: cog.outl() - for pname, optional in refparams: - cog.outl(f" if (!check_refparam({pname}, {cbool[optional]}))") + for checkargs, optional in refparams: + cog.outl(f" if (!check_refparam({checkargs}, req::{optional}))") cog.outl( " return j6_err_invalid_arg;") cog.outl()