Skip to content

Fix XPath mod SIGFPE on zero divisor, and xml_diff() with NULL first tree - #703

Open
khromenokroman wants to merge 3 commits into
clicon:masterfrom
khromenokroman:fix/xpath-mod-zero-xml-diff
Open

khromenokroman wants to merge 3 commits into
clicon:masterfrom
khromenokroman:fix/xpath-mod-zero-xml-diff

Conversation

@khromenokroman

Copy link
Copy Markdown
Contributor

@olofhagsand Hello

Description:
Two independent small fixes.

1. XPath mod crashed with SIGFPE

xp_numop() computed mod as ((int)n1)%((int)n2). If the divisor
truncates to 0, e.g. 1 mod 0 or 1 mod 0.5, the process is killed by
SIGFPE.

Such expressions can come from YANG must/when statements evaluated on
user data, or from an XPath filter in a NETCONF <get>, so a client can
crash the backend. Example:

  leaf r {
    type int32;
    must "(../a mod ../b) = 0";
  } 

  <c><a>6</a><b>0</b><r>1</r></c>   -> validate: backend killed by SIGFPE

XPath 1.0 section 3.5 defines mod on numbers (floating point) as the
remainder from a truncating division, i.e. fmod(). Using fmod():

  • returns NaN for a zero divisor (like div), so the must above simply
    fails validation;
  • gives correct results for non-integer operands: 5.5 mod 2 = 1.5
    (previously 1).
expression master this PR
5 mod 2, 5 mod -2, -5 mod 2 1, 1, -1 1, 1, -1
5.5 mod 2 1 1.5
1 mod 0 SIGFPE NaN
1 mod 0.5 SIGFPE 0
must "(../a mod ../b) = 0", b=0 SIGFPE Failed MUST xpath

2. xml_diff() with NULL first tree

If x0 == NULL, the whole second tree is new, but x0 (NULL) was appended
to the second vector instead of x1 (copy-paste from the x1 == NULL
case just above). Callers iterating second would get a NULL node.

Testing

xp_numop() computed mod as ((int)n1)%((int)n2). If the divisor truncates
to 0, eg "1 mod 0" or "1 mod 0.5", the process is killed by SIGFPE.
Such an expression may come from YANG must/when statements evaluated on
user data, or from an XPath filter in a NETCONF get request, so it can
crash the backend.

XPath 1.0 section 3.5 defines mod on numbers (floating point) as the
remainder from a truncating division, ie fmod(). Use fmod(), which also
returns correct results for non-integer operands (5.5 mod 2 = 1.5,
previously 1) and NaN for a zero divisor, as div does.
If the first tree is NULL, all of the second tree is new, but x0 (NULL)
was appended to the second vector instead of x1 (copy-paste error from
the x1 == NULL case above).

This branch has not been deployed

No deployments
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 this pull request may close these issues.

1 participant