Commit bb432b4e authored by tongkunkun's avatar tongkunkun Committed by Tomasz Zawadzki
Browse files

json: fix parsing json problems when json config is invalid.



Add parsing json as invalid cases:
1.json content that not enclosed in {}, it should be parsed as invalid, e.g.

"abc":"not encloesed in {}"

2.json content that 'subsystems' not associate with array, it will report error and return failure, e.g.

{"subsystems":"123"}

3.handle other invalid json formats, report and return failure, e.g. duplicate keys.

Added `spdk_json_find` API return errcode: EPROTOTYPE - json not enclosed in {}.

json config with content:
1."not enclosed in {}"
2."'subsystems' not be an array"
3."duplicate key in json"
and some other invaild cases will be regarded as invalid json config, and will fail to start app.

Fixes #2599

Signed-off-by: default avatartongkunkun <tongkunkun_yewu@cmss.chinamobile.com>
Change-Id: I02574c9acd7671e336d4c589ebbff8ed21eb3681
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13754


Community-CI: Mellanox Build Bot
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarGangCao <gang.cao@intel.com>
Reviewed-by: default avatarAleksey Marchuk <alexeymar@nvidia.com>
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent 19518dfb
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -2,6 +2,17 @@

## v22.09: (Upcoming Release)

### json

Added `spdk_json_find` API return errcode: EPROTOTYPE - json not enclosed in {}.
`spdk_json_find` now returns -EPROTOTYPE instead of -ENOENT if the object parameter
does not point to a JSON object (i.e. is not enclosed with {}).

### init

`spdk_subsystem_init_from_json_config` now fails if the JSON configuration file is not
an object with an array named "subsystems".

### bdev

New RPCs `bdev_xnvme_create` and `bdev_xnvme_delete` were added to support the xNVMe bdev.
+1 −0
Original line number Diff line number Diff line
@@ -266,6 +266,7 @@ int spdk_json_write_named_object_begin(struct spdk_json_write_ctx *w, const char
 * -EINVAL - json object is invalid
 * -ENOENT - key not found
 * -EDOM - key exists but value type mismatch.
 * -EPROTOTYPE - json not enclosed in {}.
 */
int spdk_json_find(struct spdk_json_val *object, const char *key_name, struct spdk_json_val **key,
		   struct spdk_json_val **val, enum spdk_json_val_type type);
+15 −3
Original line number Diff line number Diff line
@@ -566,14 +566,26 @@ spdk_subsystem_init_from_json_config(const char *json_config_file, const char *r

	/* Capture subsystems array */
	rc = spdk_json_find_array(ctx->values, "subsystems", NULL, &ctx->subsystems);
	if (rc) {
		SPDK_WARNLOG("No 'subsystems' key JSON configuration file.\n");
	} else {
	switch (rc) {
	case 0:
		/* Get first subsystem */
		ctx->subsystems_it = spdk_json_array_first(ctx->subsystems);
		if (ctx->subsystems_it == NULL) {
			SPDK_NOTICELOG("'subsystems' configuration is empty\n");
		}
		break;
	case -EPROTOTYPE:
		SPDK_ERRLOG("Invalid JSON configuration: not enclosed in {}.\n");
		goto fail;
	case -ENOENT:
		SPDK_WARNLOG("No 'subsystems' key JSON configuration file.\n");
		break;
	case -EDOM:
		SPDK_ERRLOG("Invalid JSON configuration: 'subsystems' should be an array.\n");
		goto fail;
	default:
		SPDK_ERRLOG("Failed to parse JSON configuration.\n");
		goto fail;
	}

	/* If rpc_addr is not an Unix socket use default address as prefix. */
+9 −3
Original line number Diff line number Diff line
@@ -530,11 +530,17 @@ spdk_json_find(struct spdk_json_val *object, const char *key_name, struct spdk_j
{
	struct spdk_json_val *_key = NULL;
	struct spdk_json_val *_val = NULL;
	struct spdk_json_val *it;
	struct spdk_json_val *it_first, *it;

	assert(object != NULL);

	for (it = json_first(object, SPDK_JSON_VAL_ARRAY_BEGIN | SPDK_JSON_VAL_OBJECT_BEGIN);
	it_first = json_first(object, SPDK_JSON_VAL_OBJECT_BEGIN);
	if (!it_first) {
		SPDK_JSON_DEBUG("Not enclosed in {}\n");
		return -EPROTOTYPE;
	}

	for (it = it_first;
	     it != NULL;
	     it = spdk_json_next(it)) {
		if (it->type != SPDK_JSON_VAL_NAME) {
@@ -553,7 +559,7 @@ spdk_json_find(struct spdk_json_val *object, const char *key_name, struct spdk_j
		_key = it;
		_val = json_value(_key);

		if (type != SPDK_JSON_VAL_INVALID && (_val->type & type) == 0) {
		if (type != SPDK_JSON_VAL_ANY && (_val->type & type) == 0) {
			SPDK_JSON_DEBUG("key '%s' type is %#x but expected one of %#x\n", key_name, _val->type, type);
			return -EDOM;
		}
+9 −0
Original line number Diff line number Diff line
@@ -7,6 +7,9 @@ source $testdir/nbd_common.sh

rpc_py=rpc_cmd
conf_file="$testdir/bdev.json"
nonenclosed_conf_file="$testdir/nonenclosed.json"
nonarray_conf_file="$testdir/nonarray.json"

# Make sure the configuration is clean
: > "$conf_file"

@@ -566,6 +569,12 @@ trap "cleanup" SIGINT SIGTERM EXIT
run_test "bdev_verify" $testdir/bdevperf/bdevperf --json "$conf_file" -q 128 -o 4096 -w verify -t 5 -C -m 0x3 "$env_ctx"
run_test "bdev_write_zeroes" $testdir/bdevperf/bdevperf --json "$conf_file" -q 128 -o 4096 -w write_zeroes -t 1 "$env_ctx"

# test json config not enclosed with {}
run_test "bdev_json_nonenclosed" $testdir/bdevperf/bdevperf --json "$nonenclosed_conf_file" -q 128 -o 4096 -w write_zeroes -t 1 "$env_ctx" || true

# test json config "subsystems" not with array
run_test "bdev_json_nonarray" $testdir/bdevperf/bdevperf --json "$nonarray_conf_file" -q 128 -o 4096 -w write_zeroes -t 1 "$env_ctx" || true

if [[ $test_type == bdev ]]; then
	run_test "bdev_qos" qos_test_suite "$env_ctx"
	run_test "bdev_qd_sampling" qd_sampling_test_suite "$env_ctx"
Loading