Add: [system] max_vevent_rrule_entries option to catch DoS by problematic RRULE early enough

This commit is contained in:
Peter Bieringer
2026-08-01 18:54:31 +02:00
parent 4a4e571cce
commit b044addc53
11 changed files with 36 additions and 6 deletions

View File

@@ -79,6 +79,7 @@ class Application(ApplicationPartDelete, ApplicationPartHead,
_internal_server: bool
_max_content_length: int
_max_resource_size: int
_max_vevent_rrule_entries: int
_auth_realm: str
_auth_type: str
_web_type: str
@@ -120,6 +121,8 @@ class Application(ApplicationPartDelete, ApplicationPartHead,
self._max_resource_size = max_resource_size_limited
else:
logger.info("max_resource_size set to: %d bytes (%sbytes)", self._max_resource_size, utils.format_unit(self._max_resource_size, binary=True))
self._max_vevent_rrule_entries = configuration.get("server", "max_vevent_rrule_entries")
logger.info("max_vevent_rrule_entries set to: %d", self._max_vevent_rrule_entries)
self._bad_put_request_content = configuration.get("logging", "bad_put_request_content")
logger.info("log bad put request content: %s", self._bad_put_request_content)
self._request_header_on_debug = configuration.get("logging", "request_header_on_debug")

View File

@@ -122,6 +122,7 @@ class ApplicationBase:
_sharing: sharing.BaseSharing
_encoding: str
_max_resource_size: int
_max_vevent_rrule_entries: int
_permit_delete_collection: bool
_permit_overwrite_collection: bool
_strict_preconditions: bool

View File

@@ -47,6 +47,7 @@ PRODID = u"-//Radicale//NONSGML Version " + utils.package_version("radicale") +
def prepare(vobject_items: List[vobject.base.Component], path: str,
content_type: str, permission: bool, parent_permission: bool, max_resource_size: int,
max_vevent_rrule_entries: int,
tag: Optional[str] = None,
write_whole_collection: Optional[bool] = None) -> Tuple[
Iterator[radicale_item.Item], # items
@@ -73,7 +74,9 @@ def prepare(vobject_items: List[vobject.base.Component], path: str,
try:
if tag and write_whole_collection is not None:
radicale_item.check_and_sanitize_items(
vobject_items, is_collection=write_whole_collection, tag=tag)
vobject_items,
max_vevent_rrule_entries=max_vevent_rrule_entries,
is_collection=write_whole_collection, tag=tag)
if write_whole_collection and tag == "VCALENDAR":
vobject_components: List[vobject.base.Component] = []
vobject_item, = vobject_items
@@ -224,7 +227,9 @@ class ApplicationPartPut(ApplicationBase):
vobject_items, path, content_type,
bool(rights.intersect(access.permissions, "Ww")),
bool(rights.intersect(access.parent_permissions, "w")),
self._max_resource_size)
self._max_resource_size,
self._max_vevent_rrule_entries,
)
with self._storage.acquire_lock("w", user, path=path, request="PUT"):
item = next(iter(self._storage.discover(path)), None)
@@ -289,6 +294,7 @@ class ApplicationPartPut(ApplicationBase):
bool(rights.intersect(access.permissions, "Ww")),
bool(rights.intersect(access.parent_permissions, "w")),
self._max_resource_size,
self._max_vevent_rrule_entries,
tag, write_whole_collection)
props = prepared_props
if prepared_exc_info: