Skip to content

JSON.DEL with wildcard path crashes server (SIGSEGV) when object keys contain '~' #104

@madolson

Description

@madolson

Description

A JSON.DEL using a multi-match path ($.*, $..*) against an object whose keys contain a tilde (~) crashes the server with a SIGSEGV (out-of-bounds read). Any authenticated client can trigger it with two commands and no special configuration.

Steps to reproduce

JSON.SET k '$' '{"~":1,"~~":2}'
JSON.DEL k '$.*'

The server dies; the client sees Error: Server closed the connection.

Also reproduces via recursive descent:

JSON.SET t '$' '{"o":{"~":1,"~a":2}}'
JSON.DEL t '$..*'

Minimal condition: an object with >=2 keys each containing ~, deleted via a path that selects more than one such member. With a single match the comparator is never invoked, so it does not crash.

Crash output

=== VALKEY BUG REPORT START ===
crashed by signal: 11, si_code: 1
Accessing address: 0xfffffffffffffffc
...
libjson.so pathCompare::operator()(...)
  -> std::set<...,pathCompare>::insert
  -> _Rb_tree::_M_get_insert_unique_pos

Root cause

escape_member_name_for_json_pointer() (src/json/selector.cc:2426) escapes / -> ~1 but not ~ -> ~0, violating RFC 6901. Keys containing ~ therefore produce malformed JSON pointers.

In Selector::deleteValues() (src/json/selector.cc:678-689) these paths are inserted into a jsn::set<jsn::string, pathCompare>. The comparator pathCompare::operator() (src/json/selector.cc:611) does:

JPointer ptr1 = JPointer(path1);
auto depth1 = ptr1.GetTokenCount();   // 0 for the invalid pointer
... tokenArray1[depth1 - 1] ...       // tokenArray[(size_t)-1] -> OOB read

GetTokenCount() returns 0 for the invalid pointer, so tokenArray[depth - 1] reads at offset (size_t)-1, faulting at 0xfffffffffffffffc.

Suggested fix

Escape ~ -> ~0 (before / -> ~1) in escape_member_name_for_json_pointer(), and/or guard pathCompare against GetTokenCount() == 0 / ptr.HasError().

Environment

  • valkey-json commit a932a1c, valkey/valkey-bundle:unstable
  • Reproduced on Linux x86_64

This issue was generated by AI but verified, with love, by a human.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions