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