From d0c5fa9a6d90464fd1695681b3b354a229c9c0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B8=D1=80=D0=B8=D0=BB=D0=BB=20=D0=91=D0=B5=D0=B7?= =?UTF-8?q?=D1=83=D0=B3=D0=BB=D1=8B=D0=B9?= <k.bezuglyi@picodata.io> Date: Sat, 17 Aug 2024 00:02:31 +0300 Subject: [PATCH] feat: forbid unsupported IPROTO request types --- src/lib.rs | 46 ++++++++++++++++++++++++++++++++++++++++++ src/tarantool.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 452c0b64a6..db1c0ba0df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![allow(unknown_lints)] +#![allow(non_camel_case_types)] #![allow(clippy::too_many_arguments)] #![allow(clippy::let_and_return)] #![allow(clippy::needless_return)] @@ -324,6 +325,8 @@ fn init_handlers() { "#, ) .expect("pico.cas registration should never fail"); + + forbid_unsupported_iproto_requests(); } /// Sets interactive prompt to display `picodata>`. @@ -1097,3 +1100,46 @@ fn postjoin( Ok(()) } + +::tarantool::define_enum_with_introspection! { + /// IPROTO request types that are forbidden on picodata side + enum ForbiddenIprotoTypes { + // TODO(kbezuglyi): uncomment when vshard's + // bucket distribution and discovery stop + // using IPROTO_SELECT requests + // SELECT = 1, + INSERT = 2, + REPLACE = 3, + UPDATE = 4, + DELETE = 5, + // CALL_16 = 6, - needed + // AUTH = 7, - needed + // EVAL = 8, - needed + UPSERT = 9, + // CALL = 10, - needed + EXECUTE = 11, + NOP = 12, + PREPARE = 13, + BEGIN = 14, + COMMIT = 15, + ROLLBACK = 16, + } +} + +/// Automatically forbids all unsupported IPROTO request types. +#[inline] +fn forbid_unsupported_iproto_requests() { + for iproto_request in ForbiddenIprotoTypes::VARIANTS { + // SAFETY: function is exported properly and + // arguments with argument types are correct + let rc = unsafe { + tarantool::box_iproto_override( + *iproto_request as _, + Some(tarantool::iproto_override_cb), + None, + std::ptr::null_mut(), + ) + }; + assert_eq!(rc, 0); + } +} diff --git a/src/tarantool.rs b/src/tarantool.rs index 02a11ec3cf..c86bf8fd0a 100644 --- a/src/tarantool.rs +++ b/src/tarantool.rs @@ -432,3 +432,55 @@ extern "C" fn xlog_remove_cb( } }; } + +extern "C" { + /// Sets an IPROTO request handler with the provided + /// context for the given request type. + pub fn box_iproto_override( + req_type: u32, + handler: Option<iproto_handler_t>, + destroy: Option<iproto_handler_destroy_t>, + ctx: *mut (), + ) -> i32; +} + +/// Callback for overwritten handlers of IPROTO requests. +/// Sets diagnostic message and returns and error to register it. +pub extern "C" fn iproto_override_cb( + _header: *const u8, + _header_end: *const u8, + _body: *const u8, + _body_end: *const u8, + _ctx: *mut (), +) -> iproto_handler_status { + ::tarantool::set_error!( + ::tarantool::error::TarantoolErrorCode::Unsupported, + "picodata does not support this IPROTO request type, it was disabled" + ); + iproto_handler_status::IPROTO_HANDLER_ERROR +} + +/// Return codes for IPROTO request handlers. +#[allow(dead_code)] +#[repr(C)] +pub enum IprotoHandlerStatus { + IPROTO_HANDLER_OK = 0, + IPROTO_HANDLER_ERROR = 1, + IPROTO_HANDLER_FALLBACK = 2, +} + +/// Status of handlers of IPROTO requests when +/// request path of handling is overwritten. +type iproto_handler_status = IprotoHandlerStatus; + +/// Type of callback for a IPROTO request handler. +type iproto_handler_t = extern "C" fn( + header: *const u8, + header_end: *const u8, + body: *const u8, + body_end: *const u8, + ctx: *mut (), +) -> iproto_handler_status; + +/// Type of destroy callback for a IPROTO request handler. +type iproto_handler_destroy_t = extern "C" fn(ctx: *mut ()); -- GitLab