Skip to content

RB: add a query flagging uses of Kernel.open() that are not with a constant string #10708

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

Merged
merged 4 commits into from
Oct 14, 2022

Conversation

erik-krogh
Copy link
Contributor

@erik-krogh erik-krogh commented Oct 6, 2022

CVE-2019-10780: TP/TN
CVE-2019-13574: TP/TN
CVE-2019-5477: TP/TN
CVE-2020-8130: TP/TN
CVE-2021-21289: TP/TN
CVE-2021-31799: TP/TN

The alert-message and severity are different from rb/kernel-open.
But I think the existing qhelp for rb/kernel-open fit nicely, so I reused it completely.

Evaluation looks fine. Performance is good.
There are plenty of results, but the results look OK to me.
Although I don't think many of them are exploitable.

The QHelp preview CI fails hard, and I'm not sure why.
It works fine locally, and the qhelp check passes.
So it's a problem with the preview workflow, and not with the qhelp itself.

@erik-krogh erik-krogh changed the title RB: add a query flagging uses of Kernel.open that are not with a constant string RB: add a query flagging uses of Kernel.open() that are not with a constant string Oct 6, 2022
@erik-krogh erik-krogh assigned erik-krogh and unassigned erik-krogh Oct 6, 2022
@erik-krogh erik-krogh marked this pull request as ready for review October 6, 2022 19:58
@erik-krogh erik-krogh requested a review from a team as a code owner October 6, 2022 19:58
@calumgrant calumgrant requested a review from hmac October 10, 2022 08:49
@hmac
Copy link
Contributor

hmac commented Oct 10, 2022

There's a compile warning which should be fixed if you rebase against main. And I think the QHelp preview job may be fixed by a rebase too.

@@ -0,0 +1,44 @@
/**
* Provides a utility classes and predicates for queries reasoning about Kernel.open and related methods.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Provides a utility classes and predicates for queries reasoning about Kernel.open and related methods.
* Provides utility classes and predicates for reasoning about `Kernel.open` and related methods.

private import codeql.ruby.frameworks.core.Kernel::Kernel

/** A call to a method that might access a file or start a process. */
abstract class AmbiguousPathCall extends DataFlow::CallNode {
Copy link
Contributor

@hmac hmac Oct 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that we don't want to be adding any new abstract classes which are exposed to end users (unless we expect them to be extending it, and then we should use the range pattern). E.g. we moved a load of these into an internal directory in this PR. We may want to do the same thing or something similar here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed it to a simple non-abstract class, and moved the implementations into that class.
We can always change that to the Range:: pattern later without breaking changes.

Copy link
Contributor

@hmac hmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, but I wonder if there's a problem if we have two queries that can generate alerts for the same vulnerability? Will that lead to duplicate alerts in code scanning and/or some weird UX?

@github-actions
Copy link
Contributor

QHelp previews:

ruby/ql/src/queries/security/cwe-078/KernelOpen.qhelp

Use of Kernel.open or IO.read with user-controlled input

If Kernel.open is given a file name that starts with a | character, it will execute the remaining string as a shell command. If a malicious user can control the file name, they can execute arbitrary code. The same vulnerability applies to IO.read.

Recommendation

Use File.open instead of Kernel.open, as the former does not have this vulnerability. Similarly, use File.read instead of IO.read.

Example

The following example shows code that calls Kernel.open on a user-supplied file path.

class UsersController < ActionController::Base
  def create
    filename = params[:filename]
    open(filename) # BAD
  end
end  

Instead, File.open should be used, as in the following example.

class UsersController < ActionController::Base
    def create
      filename = params[:filename]
      File.open(filename)
    end
  end  

References

ruby/ql/src/queries/security/cwe-078/NonConstantKernelOpen.qhelp

Use of Kernel.open or IO.read with a non-constant value

If Kernel.open is given a file name that starts with a | character, it will execute the remaining string as a shell command. If a malicious user can control the file name, they can execute arbitrary code. The same vulnerability applies to IO.read.

Recommendation

Use File.open instead of Kernel.open, as the former does not have this vulnerability. Similarly, use File.read instead of IO.read.

Example

The following example shows code that calls Kernel.open on a user-supplied file path.

class UsersController < ActionController::Base
  def create
    filename = params[:filename]
    open(filename) # BAD
  end
end  

Instead, File.open should be used, as in the following example.

class UsersController < ActionController::Base
    def create
      filename = params[:filename]
      File.open(filename)
    end
  end  

References

@erik-krogh
Copy link
Contributor Author

This looks good, but I wonder if there's a problem if we have two queries that can generate alerts for the same vulnerability? Will that lead to duplicate alerts in code scanning and/or some weird UX?

I just tried that in a draft PR by adding a few QL-for-QL alerts on the same line.
You just get two code-scanning boxes next to each other, it l looks fine.
Screenshot 2022-10-11 at 09 45 25

@erik-krogh erik-krogh requested a review from hmac October 11, 2022 09:24
@aibaars
Copy link
Contributor

aibaars commented Oct 13, 2022

This query has quite a lot of results, but they all seem to make sense. There are quite a lot of cases like if File.exists(path) then open(path) which are sort of safe (unless you have an existing file named |launch_the_rockets) . In those cases it would still be to use File.open instead of Kernel.open.

@erik-krogh
Copy link
Contributor Author

@hmac do you have anymore comments?
I noticed you started an evaluation.

Copy link
Contributor

@hmac hmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the duplicate alert is a bit unfortunate, but not a huge deal. The large number of results is also a little scary but hopefully since this is a "warning" with lowish severity, users won't mind too much...

@erik-krogh erik-krogh merged commit 332bc35 into github:main Oct 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants