-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Swift: Add libxml2 sinks to the XXE query #11165
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
Swift: Add libxml2 sinks to the XXE query #11165
Conversation
QHelp previews: swift/ql/src/queries/Security/CWE-611/XXE.qhelpResolving XML external entity in user-controlled dataParsing untrusted XML files with a weakly configured XML parser may lead to an XML External Entity (XXE) attack. This type of attack uses external entity references to access arbitrary files on a system, carry out denial of service, or server side request forgery. Even when the result of parsing is not returned to the user, out-of-band data retrieval techniques may allow attackers to steal sensitive data. Denial of services can also be carried out in this situation. RecommendationThe easiest way to prevent XXE attacks is to disable external entity handling when parsing untrusted data. How this is done depends on the library being used. Note that some libraries, such as recent versions of ExampleThe following example uses the
To guard against XXE attacks, the
References
|
* Holds if taint can flow from `source` to `sink` in one local step, | ||
* including bitwise operations, accesses to `.rawValue`, and casts to `Int32`. | ||
*/ | ||
private predicate lib2xmlOptionLocalTaintStep(DataFlow::Node source, DataFlow::Node sink) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a little ad-hoc, but the expected use should actually adhere to this pattern (Int32(XML_PARSE_NOENT.rawValue)
, potentially bitwise-OR'ed with other options, and reaching the options
argument of a libxml2
XML-parsing call).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which of the steps in this predicate do you think should ultimately be ported to the data flow or taint flow libraries? Most of them look like they could be taint steps to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bitwise operation and .rawValue
ones are probably of general interest as taint steps. The Int32
constructor technically applies globally too, although it may seem a little more niche.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in #14502 . Actually, we've chipped away at this in a few steps, but that PR gets rid of the last special case here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great. I have a few questions, quite possibly none of them need any actual changes.
// --- tests --- | ||
|
||
func sourcePtr() -> UnsafeMutablePointer<UInt8> { return UnsafeMutablePointer<UInt8>.allocate(capacity: 0) } | ||
func sourceCharPtr() -> UnsafeMutablePointer<CChar> { return UnsafeMutablePointer<CChar>.allocate(capacity: 0) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think these sources would look like in actual Swift code? I'm very happy with this solution for the query test, but we might want to plan work to ensure proper taint flow through the UnsafeMutablePointer
operations in real code leading up to an XML
parse call.
We do have https://github.com/github/codeql-c-team/issues/1333 planned if that's relevant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to model them properly at first, but it started getting too complicated and I used this "dummy" sources as a fallback.
I think we'd need to model, at the very least, the various flavors of initialize
and with*
, which seem the ones that could translate our current sources to an UnsafeMutablePointer
. Probably there are more, this would need its own PR to do it right I guess.
I don't think we should worry about direct UnsafeMutablePointer
sources for now, but that would be easy to model anyway.
* Holds if taint can flow from `source` to `sink` in one local step, | ||
* including bitwise operations, accesses to `.rawValue`, and casts to `Int32`. | ||
*/ | ||
private predicate lib2xmlOptionLocalTaintStep(DataFlow::Node source, DataFlow::Node sink) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which of the steps in this predicate do you think should ultimately be ported to the data flow or taint flow libraries? Most of them look like they could be taint steps to me.
a927ac2
to
16a7685
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adds sinks for
libxml2
.