From 98dce5d9ea5017bfb0bebacd82f5144ea27a2fde Mon Sep 17 00:00:00 2001 From: mdecimus Date: Fri, 8 Aug 2025 17:07:35 +0200 Subject: [PATCH] Limit principal object size --- .../directory/src/backend/internal/manage.rs | 16 +++++++++++++ crates/directory/src/core/principal.rs | 24 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/crates/directory/src/backend/internal/manage.rs b/crates/directory/src/backend/internal/manage.rs index 0b3569a0..0182c1e4 100644 --- a/crates/directory/src/backend/internal/manage.rs +++ b/crates/directory/src/backend/internal/manage.rs @@ -553,6 +553,14 @@ impl ManageDirectory for Store { let pinfo_name = PrincipalInfo::new(principal_id, principal_create.typ, tenant_id); let pinfo_email = PrincipalInfo::new(principal_id, principal_create.typ, None); + // Validate object size + if principal_create.object_size() > 100_000 { + return Err(error( + "Invalid parameter", + "Principal object size exceeds 100kb safety limit.".into(), + )); + } + // Serialize let archiver = Archiver::new(principal_create); let principal_bytes = archiver.serialize().caused_by(trc::location!())?; @@ -1902,6 +1910,14 @@ impl ManageDirectory for Store { } } + // Validate object size + if principal.object_size() > 100_000 { + return Err(error( + "Invalid parameter", + "Principal object size exceeds 100kb safety limit.".into(), + )); + } + if update_principal { build_search_index( &mut batch, diff --git a/crates/directory/src/core/principal.rs b/crates/directory/src/core/principal.rs index 5ccbb7c7..657012f1 100644 --- a/crates/directory/src/core/principal.rs +++ b/crates/directory/src/core/principal.rs @@ -18,7 +18,7 @@ use serde::{ }; use std::{collections::hash_map::Entry, fmt, str::FromStr}; use store::{ - U64_LEN, + U32_LEN, U64_LEN, backend::MAX_TOKEN_LENGTH, write::{BatchBuilder, DirectoryClass}, }; @@ -310,6 +310,28 @@ impl Principal { updates } + pub fn object_size(&self) -> usize { + self.name.len() + + self.description.as_ref().map_or(0, |d| d.len()) + + self.secrets.iter().map(|s| s.len()).sum::() + + self.emails.iter().map(|e| e.len()).sum::() + + self + .data + .iter() + .map(|d| match d { + PrincipalData::MemberOf(items) + | PrincipalData::Roles(items) + | PrincipalData::Lists(items) => items.len() * U32_LEN, + PrincipalData::Permissions(items) => items.len() * U32_LEN, + PrincipalData::ExternalMembers(items) | PrincipalData::Urls(items) => { + items.iter().map(|s| s.len()).sum::() + } + PrincipalData::PrincipalQuota(items) => items.len() * U32_LEN, + PrincipalData::Picture(value) | PrincipalData::Locale(value) => value.len(), + }) + .sum::() + } + pub fn fallback_admin(fallback_pass: impl Into) -> Self { Principal { id: FALLBACK_ADMIN_ID,