Skip to content

Commit 5f701d0

Browse files
authored
MOD-4822: Disable recursion limit on RDB load (RedisJSON#919)
* disable recursion limit on RDB load
1 parent 54125ef commit 5f701d0

File tree

7 files changed

+47
-19
lines changed

7 files changed

+47
-19
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ bitflags = "1.3"
2727
log = "0.4"
2828
bson = "0.14"
2929
ijson = "0.1.3"
30-
serde_json = "1.0"
30+
serde_json = { version="1.0", features = ["unbounded_depth"]}
3131
serde = "1.0"
3232
libc = "0.2"
3333
redis-module = { version="1.0", features = ["experimental-api"]}

src/commands.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ pub fn json_set<M: Manager>(manager: M, ctx: &Context, args: Vec<RedisString>) -
606606
let mut redis_key = manager.open_key_write(ctx, key)?;
607607
let current = redis_key.get_value()?;
608608

609-
let val = manager.from_str(value, format)?;
609+
let val = manager.from_str(value, format, true)?;
610610

611611
match (current, set_option) {
612612
(Some(ref mut doc), ref op) => {
@@ -1334,7 +1334,7 @@ pub fn json_arr_append<M: Manager>(
13341334
Vec::with_capacity(args.len()),
13351335
|mut acc, arg| {
13361336
let json = arg.try_as_str()?;
1337-
acc.push(manager.from_str(json, Format::JSON)?);
1337+
acc.push(manager.from_str(json, Format::JSON, true)?);
13381338
Ok(acc)
13391339
},
13401340
)?;
@@ -1494,7 +1494,7 @@ pub fn json_arr_insert<M: Manager>(
14941494
Vec::with_capacity(args.len()),
14951495
|mut acc, arg| {
14961496
let json = arg.try_as_str()?;
1497-
acc.push(manager.from_str(json, Format::JSON)?);
1497+
acc.push(manager.from_str(json, Format::JSON, true)?);
14981498
Ok(acc)
14991499
},
15001500
)?;

src/ivalue_manager.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
/*
2-
* Copyright Redis Ltd. 2016 - present
3-
* Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or
4-
* the Server Side Public License v1 (SSPLv1).
5-
*/
6-
1+
/*
2+
* Copyright Redis Ltd. 2016 - present
3+
* Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or
4+
* the Server Side Public License v1 (SSPLv1).
5+
*/
6+
77
use crate::error::Error;
88
use crate::manager::{err_json, err_msg_json_expected, err_msg_json_path_doesnt_exist};
99
use crate::manager::{Manager, ReadHolder, WriteHolder};
@@ -16,7 +16,7 @@ use redis_module::key::{verify_type, RedisKey, RedisKeyWritable};
1616
use redis_module::raw::{RedisModuleKey, Status};
1717
use redis_module::rediserror::RedisError;
1818
use redis_module::{Context, NotifyEvent, RedisString};
19-
use serde::Serialize;
19+
use serde::{Deserialize, Serialize};
2020
use serde_json::Number;
2121
use std::marker::PhantomData;
2222
use std::mem::size_of;
@@ -601,9 +601,15 @@ impl<'a> Manager for RedisIValueJsonKeyManager<'a> {
601601
})
602602
}
603603

604-
fn from_str(&self, val: &str, format: Format) -> Result<Self::O, Error> {
604+
fn from_str(&self, val: &str, format: Format, limit_depth: bool) -> Result<Self::O, Error> {
605605
match format {
606-
Format::JSON => Ok(serde_json::from_str(val)?),
606+
Format::JSON => {
607+
let mut deserializer = serde_json::Deserializer::from_str(val);
608+
if !limit_depth {
609+
deserializer.disable_recursion_limit();
610+
}
611+
IValue::deserialize(&mut deserializer).map_err(|e| e.into())
612+
}
607613
Format::BSON => decode_document(&mut Cursor::new(val.as_bytes())).map_or_else(
608614
|e| Err(e.to_string().into()),
609615
|docs| {
@@ -619,6 +625,7 @@ impl<'a> Manager for RedisIValueJsonKeyManager<'a> {
619625
self.from_str(
620626
&String::from_utf8(out.into_inner()).unwrap(),
621627
Format::JSON,
628+
limit_depth,
622629
)
623630
.unwrap()
624631
},

src/manager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ pub trait Manager {
8080
key: RedisString,
8181
) -> Result<Self::WriteHolder, RedisError>;
8282
#[allow(clippy::wrong_self_convention)]
83-
fn from_str(&self, val: &str, format: Format) -> Result<Self::O, Error>;
83+
fn from_str(&self, val: &str, format: Format, limit_depth: bool) -> Result<Self::O, Error>;
8484
fn get_memory(&self, v: &Self::V) -> Result<usize, RedisError>;
8585
fn is_json(&self, key: *mut RedisModuleKey) -> Result<bool, RedisError>;
8686
}

src/redisjson.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ pub mod type_methods {
148148
let m = RedisJsonKeyManager {
149149
phantom: PhantomData,
150150
};
151-
let v = m.from_str(&json_string, Format::JSON);
151+
let v = m.from_str(&json_string, Format::JSON, false);
152152
v.map_or(null_mut(), |res| {
153153
Box::into_raw(Box::new(res)).cast::<libc::c_void>()
154154
})
@@ -157,7 +157,7 @@ pub mod type_methods {
157157
let m = RedisIValueJsonKeyManager {
158158
phantom: PhantomData,
159159
};
160-
let v = m.from_str(&json_string, Format::JSON);
160+
let v = m.from_str(&json_string, Format::JSON, false);
161161
v.map_or(null_mut(), |res| {
162162
Box::into_raw(Box::new(res)).cast::<libc::c_void>()
163163
})

src/serde_value_manager.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
use crate::jsonpath::select_value::SelectValue;
8+
use serde::Deserialize;
89
use serde_json::map::Entry;
910
use serde_json::{Number, Value};
1011

@@ -478,9 +479,15 @@ impl<'a> Manager for RedisJsonKeyManager<'a> {
478479
})
479480
}
480481

481-
fn from_str(&self, val: &str, format: Format) -> Result<Value, Error> {
482+
fn from_str(&self, val: &str, format: Format, limit_depth: bool) -> Result<Value, Error> {
482483
match format {
483-
Format::JSON => Ok(serde_json::from_str(val)?),
484+
Format::JSON => {
485+
let mut deserializer = serde_json::Deserializer::from_str(val);
486+
if !limit_depth {
487+
deserializer.disable_recursion_limit();
488+
}
489+
Value::deserialize(&mut deserializer).map_err(|e| e.into())
490+
}
484491
Format::BSON => decode_document(&mut Cursor::new(val.as_bytes()))
485492
.map(|docs| {
486493
let v = if docs.is_empty() {

tests/pytest/test.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import json
99
from RLTest import Env
1010
from includes import *
11-
11+
from redis.client import NEVER_DECODE
1212
from RLTest import Defaults
1313

1414
Defaults.decode_responses = True
@@ -1279,6 +1279,20 @@ def testFilterPrecedence(env):
12791279
r.assertEqual(json.loads(res), [doc[0]])
12801280
r.expect('JSON.GET', 'doc', '$[?(@.f==true || @.one==1 && @.t==false)]').equal('[]')
12811281

1282+
def testRDBUnboundedDepth(env):
1283+
# Test RDB Unbounded Depth load
1284+
r = env
1285+
json_value = nest_object(128, 5, "__leaf", 42)
1286+
r.expect('JSON.SET', 'doc', '$', json_value).ok()
1287+
1288+
# concat the string_126 at the end of itself
1289+
json_value = nest_object(3, 5, "__deep_leaf", 420)
1290+
r.expect('JSON.SET', 'doc', '$..__leaf', json_value).ok()
1291+
1292+
# RDB dump and restore the key 'doc' and check that the key is still valid
1293+
dump = env.execute_command('dump', 'doc', **{NEVER_DECODE: []})
1294+
r.expect('RESTORE', 'doc1', 0, dump).ok()
1295+
r.expect('JSON.GET', 'doc1', '$..__leaf..__deep_leaf').equal('[420]')
12821296

12831297
# class CacheTestCase(BaseReJSONTest):
12841298
# @property

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy