Skip to content

Commit

Permalink
schema/v5.0: introduce computable version ranges
Browse files Browse the repository at this point in the history
The shorthand version of this schema is:

	defaultStatus: $status
	versions: [{
	    version: $version
	    status: $status  // unknown, affected, unaffected; unsupported?

	    versionType: string (‘semver’, ‘git’, ..., to define meaning of <)
	    repo: string (optional, intended for versionType ‘git’)
	    limit: $versionLimit (this range stops just before limit; can use * for “infinity” aka "maxuint")
	    changes: [{
	        at: version where status changes
	        status: ...
	    }]
	}]

An object in the versions list can be either:

 - a simple {version: V, status: S},
   which indicates the status of the single version V.
 - a range {version: V, versionType: T, limit: L, status: S, changes: C},
   which indicates the status of the half-open interval [V, L) (that is, V is included but L is not).
   The range starts with V having status S and then changes over time according to the events listed in C.

The algorithm for deciding the status of a particular version V is then:

	for entry in product.versions {
	    if entry.lessThan is not present and entry.lessThanOrEqual is not present and v == entry.version {
	        return entry.status
	    }
	    if (entry.lessThan is present and entry.version <= v and v < entry.lessThan) or
	       (entry.lessThanOrEqual is present and entry.version <= v and v <= entry.lessThanOrEqual) {
	        status = entry.status
	        for change in entry.changes {
	            if change.at <= v {
	                status = change.status
	            }
	        }
	        return status
	    }
	}
	return product.defaultStatus

Fixes #87.
Fixes #12.
Fixes #77.
  • Loading branch information
rsc committed Aug 24, 2021
1 parent c8638e2 commit 41f8442
Showing 1 changed file with 75 additions and 33 deletions.
108 changes: 75 additions & 33 deletions schema/v5.0/CVE_JSON_5.0.schema
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@
"description": "Date/time format based on RFC3339 and ISO ISO8601, with an optional timezone in the format 'yyyy-MM-ddTHH:mm:ssZZZZ'. If timezone offset is not given, GMT (0000) is assumed.",
"pattern": "^((2000|2400|2800|(19|2[0-9](0[48]|[2468][048]|[13579][26])))-02-29)|(((19|2[0-9])[0-9]{2})-02-(0[1-9]|1[0-9]|2[0-8]))|(((19|2[0-9])[0-9]{2})-(0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01]))|(((19|2[0-9])[0-9]{2})-(0[469]|11)-(0[1-9]|[12][0-9]|30))T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})?$"
},
"version": {
"description": "A single version of a product, as expressed in its own version numbering scheme.",
"type": "string",
"minLength": 1,
"maxLength": 1024
},
"status": {
"description": "The vulnerability status of a given version or range of versions of a product. The statuses 'affected' and 'unaffected' indicate that the version is affected or unaffected by the vulnerability. The status 'unknown' indicates that it is unknown or unspecified whether the given version is affected. There can be many reasons for an 'unknown' status, including that an investigation has not been undertaken or that a vendor has not disclosed the status.",
"type": "string",
"enum": ["affected", "unaffected", "unknown"]
},
"product": {
"type": "object",
"description": "Provides information about the set of products and services affected by this vulnerability.",
Expand Down Expand Up @@ -245,51 +256,82 @@
"maxLength": 1024
}
},
"defaultStatus": {
"description": "The default status for versions that are not otherwise listed in the versions list.",
"$ref": "#/definitions/status"
},
"versions": {
"type": "array",
"description": "Set of product versions related to the vulnerability. The versions satisfy the CNA Rules [8.1.2 requirement](https://cve.mitre.org/cve/cna/rules.html#section_8-1_cve_entry_information_requirements).",
"description": "Set of product versions or version ranges related to the vulnerability. The versions satisfy the CNA Rules [8.1.2 requirement](https://cve.mitre.org/cve/cna/rules.html#section_8-1_cve_entry_information_requirements).",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "object",
"description": "Affected/non-affected/fixed versions of a given technology, product, hardware, etc.",
"required": ["versionValue"],
"description": "A single version or a range of versions, with vulnerability status.\n\nAn entry with only 'version' and 'status' indicates the status of a single version.\n\nOtherwise, an entry describes a range; it must include the 'versionType' property, to define the version numbering semantics in use, and 'limit', to indicate the non-inclusive upper limit of the range. The object describes the status for versions V such that 'version' <= V and V < 'limit', using the <= and < semantics defined for the specific kind of 'versionType'. Status changes within the range can be specified by an optional 'changes' list.\n\nThe algorithm to decide the status specified for a version V is:\n\n\tfor entry in product.versions {\n\t\tif entry.lessThan is not present and entry.lessThanOrEqual is not present and v == entry.version {\n\t\t\treturn entry.status\n\t\t}\n\t\tif (entry.lessThan is present and entry.version <= v and v < entry.lessThan) or\n\t\t (entry.lessThanOrEqual is present and entry.version <= v and v <= entry.lessThanOrEqual) { // <= and < defined by entry.versionType\n\t\t\tstatus = entry.status\n\t\t\tfor change in entry.changes {\n\t\t\t\tif change.at <= v {\n\t\t\t\t\tstatus = change.status\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn status\n\t\t}\n\t}\n\treturn product.defaultStatus\n\n",
"oneOf": [
{
"required": ["version", "status"],
"maxProperties": 2
},
{
"required": ["version", "status", "versionType"],
"oneOf": [
{"required": ["lessThan"]},
{"required": ["lessThanOrEqual"]}
]
}
],
"properties": {
"versionGroup": {
"type": "string",
"description": "A string that represents a version branch, group, or a major version (e.g. 10.0, 3.1.*) where all version values are typically sequential or versionAffected comparisons are meaningful (optional).",
"minLength": 1,
"maxLength": 1024
"version": {
"description": "The single version being described, or the version at the start of the range.",
"$ref": "#/definitions/version"
},
"versionValue": {
"type": "string",
"description": "The version name/value (e.g. 10.0.1, 3.1.2, \"IceHouse\")",
"minLength": 1,
"maxLength": 1024
"status": {
"description": "The vulnerability status for the version or range of versions. For a range, the status may be refined by the 'changes' list.",
"$ref": "#/definitions/status"
},
"versionAffected": {
"versionType": {
"type": "string",
"description": "A string value:\n \"=\" (affects versionValue),\n \"<\" (affects versions prior to versionValue),\n \">\" (affects versions later than versionValue),\n \"<=\" (affects versionValue and prior versions),\n \">=\" (affects versionValue and later versions),\n \"!\" (doesn't affect versionValue),\n \"!<\" (doesn't affect versions prior to versionValue),\n \"!>\" (doesn't affect versions later than versionValue),\n \"!<=\" (doesn't affect versionValue and prior versions),\n \"!>=\" (doesn't affect versionValue and later versions),\n \"?\" (status of versionValue is unknown),\n \"?<\" (status of versions prior to versionValue is unknown),\n \"?>\" (status of versions later than versionValue is unknown),\n \"?<=\" (status of versionValue and prior versions is unknown),\n \"?>=\" (status of versionValue and later versions is unknown)",
"enum": [
"=",
"<",
">",
"<=",
">=",
"!",
"!<",
"!>",
"!<=",
"!>=",
"?",
"?<",
"?>",
"?<=",
"?>="
"description": "The version numbering system used for specifying the range. This defines the exact semantics of the comparison (less-than) operation on versions, which is required to understand the range itself.",
"minLength": 1,
"maxLength": 128,
"examples": [
"custom",
"git",
"maven",
"python",
"rpm",
"semver"
]
},
"references": {
"$ref": "#/definitions/references"
"limit": {
"description": "The upper limit of the range. This is the least version not in the range (that is, a non-inclusive upper limit). The usual version syntax is expanded to allow a pattern to end in an asterisk (*), indicating an arbitrarily large number in the version ordering. For example, {version: 1.0 limit: 1.*} would describe the entire 1.X branch for most range kinds, and {version: 2.0, limit: *} describes all versions starting at 2.0, including 3.0, 5.1, and so on.",
"$ref": "#/definitions/version"
},
"repo": {
"description": "The URL of the source code repository, for use with 'versionType' set to 'git'.",
"$ref": "#/definitions/uriType"
},
"changes": {
"type": "array",
"description": "A list of status changes that take place during the range. The array should be sorted in increasing order by the 'at' field, according to the versionType, but clients must re-sort the list themselves rather than assume it is sorted.",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "object",
"description": "The start of a single status change during the range.",
"required": ["at", "status"],
"properties": {
"at": {
"description": "The version at which a status change occurs.",
"$ref": "#/definitions/version"
},
"status": {
"description": "The new status in the range starting at the given version.",
"$ref": "#/definitions/status"
}
}
}
}
}
}
Expand Down

0 comments on commit 41f8442

Please sign in to comment.