Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Give example of overlapping version_data #12

Closed
iamamoose opened this issue Mar 3, 2021 · 2 comments · Fixed by #100
Closed

Give example of overlapping version_data #12

iamamoose opened this issue Mar 3, 2021 · 2 comments · Fixed by #100
Assignees

Comments

@iamamoose
Copy link
Contributor

Applicable to 4.0 and 5.0, version_data description includes "...This also allows more complex statements such as "Product X between versions 10.2 and 10.8" to be put in a machine-readable format." but it's not entirely clear how you'd represent it, i.e. let's say 2.4.x is affected between versions 2.4.33 and 2.4.43 are (the fix is in 2.4.44), would you do

{ version_value:"2.4", version_affected:"<",version_value:"2.4.44" },
{ version_value:"2.4", version_affected:">=",version_value:"2.4.33" }

or is it expected to use the !<

{ version_value:"2.4", version_affected:"<",version_value:"2.4.44" },
{ version_value:"2.4", version_affected:"!<",version_value:"2.4.33" }

Do we know if anything is actually machine parsing the affected versions? Given the Mitre entries are mostly plaintext (i.e. simply { "version_value": "2.4.33 to 2.4.43" }

@chandanbn
Copy link
Collaborator

These two should be minimally sufficient to state this range, all conditions evaluated with a logical AND operator.

{ versionGroup:"2.4", versionAffected:"<", versionValue:"2.4.44" },
{ versionGroup:"2.4", versionAffected:">=", versionValue:"2.4.33" }

Then it is easier to automatically determine if any given version if affected. For example:
Take 2.4.40:

2.4.40 < 2.4.44 → True
2.4.40 >= 2.4.33 → True
True AND True → True.

Take 2.4.20:

2.4.20 < 2.4.44 → True
2.4.20 >= 2.4.33 → False
True AND False → False

So 2.4.20 is not affected.

One can reinforce it with these additional statements that explicitly state what is not affected.

{ versionGroup:"2.4", versionAffected:"!>=", versionValue:"2.4.44" },
{ versionGroup:"2.4", versionAffected:"!<", versionValue:"2.4.33" }

Extending the logic, lets say if 2.3 is no longer supported and the CNA has not evaluated if 2.3 is affected or not:

{ versionGroup:"2.3", versionAffected:"?>", versionValue:"2.3.0" }

For eg., take 2.3.4, Since 2.3.4 > 2.3.0, it is not known if it is affected or not.

Alternatively, one can also say:

{ versionGroup:"all", versionAffected:"?<", versionValue:"2.4.0" }

i.e., any version before 2.4.0 has not been evaluated if the vulnerability exists or not.

This way it is more automation friendly than plaintext ranges.
These fields help us to determine CVE applicability for any given product version and enable better searching/listing of CVEs. For eg.,
https://security.paloaltonetworks.com/?version=PAN-OS+9.1.2
We are able to support filtering applicable CVEs per product version. In the backend we have enumerated all existing versions that are affected, based on values of these fields.

@iamamoose
Copy link
Contributor Author

Thank you! So adding "conditions evaluated with a logical AND operator" is important, non-obvious, and should be stated in the docs and/or examples.

@chandanbn chandanbn self-assigned this Apr 8, 2021
rsc added a commit to rsc/cve-schema that referenced this issue Aug 23, 2021
The shorthand version of this schema is:

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

	    range: string (‘semver’, ‘git’, ..., to define meaning of <)
	    repo: string (optional for range ‘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, range: R, 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 versions {
	    if entry.limit is not present and v == entry.version {
	        return entry.status
	    }
	    if entry.limit is present and v <= entry.version and v < entry.limit {
	        status = entry.status
	        for change in entry.changes {
	            if v >= change.at {
	                status = change.status
	            }
	        }
	        return status
	    }
	}
	return "unknown"

Fixes CVEProject#87.
Fixes CVEProject#12.
Fixes CVEProject#77.
rsc added a commit to rsc/cve-schema that referenced this issue Aug 23, 2021
The shorthand version of this schema is:

	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 versions {
	    if entry.limit is not present and v == entry.version {
	        return entry.status
	    }
	    if entry.limit is present and v <= entry.version and v < entry.limit {
	        status = entry.status
	        for change in entry.changes {
	            if v >= change.at {
	                status = change.status
	            }
	        }
	        return status
	    }
	}
	return "unknown"

Fixes CVEProject#87.
Fixes CVEProject#12.
Fixes CVEProject#77.
rsc added a commit to rsc/cve-schema that referenced this issue Aug 24, 2021
The shorthand version of this schema is:

	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 versions {
	    if entry.limit is not present and v == entry.version {
	        return entry.status
	    }
	    if entry.limit is present and entry.version <= v and v < entry.limit {
	        status = entry.status
	        for change in entry.changes {
	            if change.at <= v {
	                status = change.status
	            }
	        }
	        return status
	    }
	}
	return "unknown"

Fixes CVEProject#87.
Fixes CVEProject#12.
Fixes CVEProject#77.
rsc added a commit to rsc/cve-schema that referenced this issue Aug 24, 2021
The shorthand version of this schema is:

	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 versions {
	    if entry.limit is not present and v == entry.version {
	        return entry.status
	    }
	    if entry.limit is present and entry.version <= v and v < entry.limit {
	        status = entry.status
	        for change in entry.changes {
	            if change.at <= v {
	                status = change.status
	            }
	        }
	        return status
	    }
	}
	return "unknown"

Fixes CVEProject#87.
Fixes CVEProject#12.
Fixes CVEProject#77.
rsc added a commit to rsc/cve-schema that referenced this issue Aug 24, 2021
The shorthand version of this schema is:

	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 versions {
	    if entry.limit is not present and v == entry.version {
	        return entry.status
	    }
	    if entry.limit is present and entry.version <= v and v < entry.limit {
	        status = entry.status
	        for change in entry.changes {
	            if change.at <= v {
	                status = change.status
	            }
	        }
	        return status
	    }
	}
	return "unknown"

Fixes CVEProject#87.
Fixes CVEProject#12.
Fixes CVEProject#77.
rsc added a commit to rsc/cve-schema that referenced this issue Aug 24, 2021
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 CVEProject#87.
Fixes CVEProject#12.
Fixes CVEProject#77.
rsc added a commit to rsc/cve-schema that referenced this issue Aug 24, 2021
The shorthand version of this schema is:

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

	    versionType: string (‘semver’, ‘git’, ..., to define meaning of <)
	    repo: string (optional, intended for versionType ‘git’)
	    lessThan/lessThanOrEqual: $version (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, lessThan: L OR lessThanOrEqual: LE, status: S, changes: C},
   which indicates the status of the half-open interval [V, L) or closed interval [V, LE].
   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 CVEProject#87.
Fixes CVEProject#12.
Fixes CVEProject#77.
rsc added a commit to rsc/cve-schema that referenced this issue Aug 26, 2021
The shorthand version of this schema is:

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

	    versionType: string (‘semver’, ‘git’, ..., to define meaning of <)
	    repo: string (optional, intended for versionType ‘git’)
	    lessThan/lessThanOrEqual: $version (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, lessThan: L OR lessThanOrEqual: LE, status: S, changes: C},
   which indicates the status of the half-open interval [V, L) or closed interval [V, LE].
   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 CVEProject#87.
Fixes CVEProject#12.
Fixes CVEProject#77.
rsc added a commit to rsc/cve-schema that referenced this issue Aug 26, 2021
The shorthand version of this schema is:

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

	    versionType: string (‘semver’, ‘git’, ..., to define meaning of <)
	    repo: string (optional, intended for versionType ‘git’)
	    lessThan/lessThanOrEqual: $version (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, lessThan: L OR lessThanOrEqual: LE, status: S, changes: C},
   which indicates the status of the half-open interval [V, L) or closed interval [V, LE].
   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 CVEProject#87.
Fixes CVEProject#12.
Fixes CVEProject#77.
rsc added a commit to rsc/cve-schema that referenced this issue Aug 26, 2021
The shorthand version of this schema is:

	defaultStatus: $status  (default 'unknown')
	versions: [{
	    version: $version
	    status: $status  // unknown, affected, unaffected

	    versionType: string (‘semver’, ‘git’, ..., to define meaning of <)
	    repo: string (optional, intended for versionType ‘git’)
	    lessThan/lessThanOrEqual: $version (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, lessThan: L OR lessThanOrEqual: LE, status: S, changes: C},
   which indicates the status of the half-open interval [V, L) or closed interval [V, LE].
   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

Versions or defaultStatus may be omitted, but not both,

Fixes CVEProject#87.
Fixes CVEProject#12.
Fixes CVEProject#77.
rsc added a commit to rsc/cve-schema that referenced this issue Aug 26, 2021
The shorthand version of this schema is:

	defaultStatus: $status  (default 'unknown')
	versions: [{
	    version: $version
	    status: $status  // unknown, affected, unaffected

	    versionType: string (‘semver’, ‘git’, ..., to define meaning of <)
	    repo: string (optional, intended for versionType ‘git’)
	    lessThan/lessThanOrEqual: $version (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, lessThan: L OR lessThanOrEqual: LE, status: S, changes: C},
   which indicates the status of the half-open interval [V, L) or closed interval [V, LE].
   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

Versions or defaultStatus may be omitted, but not both,

Fixes CVEProject#87.
Fixes CVEProject#12.
Fixes CVEProject#77.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants