The Wayback Machine - https://web.archive.org/web/20220303100819/https://github.com/github/codeql/pull/6949
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

CPP: Add query for CWE-266 Incorrect Privilege Assignment #6949

Merged
merged 14 commits into from Jan 4, 2022

Conversation

ihsinme
Copy link
Contributor

@ihsinme ihsinme commented Oct 25, 2021

The request looks for situations of incorrect work with setting access rights. Firstly, this is the use of arithmetic to calculate the access mask, and secondly, the use of the same mask in opposite functions, and thirdly, the use of a sufficiently wide mask.

CVE-2013-6412
CVE-2018-14348
CVE-2013-2007
CVE-2001-0859

mydumper/mydumper#451

Copy link
Contributor

@geoffw0 geoffw0 left a comment

My initial thoughts. I'm also interested to see what kind of results we find in real world projects / on LGTM.

globalValueNumber(fc.getArgument(0)) = globalValueNumber(fctmp.getArgument(1)) and
fc.getArgument(0).getValue() != "0"
) and
msg = "not use equal argument in umask and " + fctmp.getTarget().getName() + " functions"
Copy link
Contributor

@geoffw0 geoffw0 Nov 9, 2021

Choose a reason for hiding this comment

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

I'm not convinced this case is right:

  • if the umask and the chmod values are equal, the resulting file permissions are 0. This may or may not be what the programmer intended, but 0 is a very safe permission setting.
    • I think what we really want is that the argument to chmod minus the bits from umask contains at least one bit we consider dangerous, e.g. global write permission, suggesting a dangerous setup.
  • if there's more than one call to umask in the program, we don't know which chmod calls correspond with which umask call. I'm not sure how common it is in practice to set umask anywhere other than once at the beginning of the program.

Copy link
Contributor Author

@ihsinme ihsinme Nov 14, 2021

Choose a reason for hiding this comment

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

I agree with what you say. (except for using 0 in chmod, I can't figure out why disallow everything for my file)

in the request, I wanted to take a broader look at the cwe-560. and for me the error indicator is the use of the same value in opposite functions. in my opinion, this is a good criterion, devoid of false detection.

but if you insist, I will remove this section from the request

Copy link
Contributor

@geoffw0 geoffw0 Nov 15, 2021

Choose a reason for hiding this comment

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

I see what you mean, even if a resulting permission of 0 is safe, it may indicate a mistake by the programmer. Perhaps we should wait until we run the query on LGTM (after resolving the other questions) and see whether your approach produces good results in practice?

globalValueNumber(fc.getArgument(0)) = globalValueNumber(fctmp.getArgument(1)) and
fc.getArgument(0).getValue() != "0"
) and
msg = "not use equal argument in umask and " + fctmp.getTarget().getName() + " functions"
Copy link
Contributor

@geoffw0 geoffw0 Nov 15, 2021

Choose a reason for hiding this comment

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

I see what you mean, even if a resulting permission of 0 is safe, it may indicate a mistake by the programmer. Perhaps we should wait until we run the query on LGTM (after resolving the other questions) and see whether your approach produces good results in practice?

ihsinme and others added 3 commits Nov 15, 2021
…eAssignment.cpp

Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
…eAssignment.cpp

Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
geoffw0
geoffw0 previously approved these changes Nov 17, 2021
Copy link
Contributor

@geoffw0 geoffw0 left a comment

All looks good to me.

I've started an LGTM run so we can hopefully see some real world results: https://lgtm.com/query/4020291079589842106/

@JarLob
Copy link
Contributor

@JarLob JarLob commented Nov 18, 2021

  1. @ihsinme @geoffw0 Could the message be improved, like in the query above, to point where chmod or fopen is used?
  2. In the query above:
    image
    Isn't the ql designed to skip the result?
  fc.getTarget().hasGlobalOrStdName("umask") and
  fc.getArgument(0).getValue() = "0" and
  not exists(FunctionCall fctmp |
    fctmp.getTarget().hasGlobalOrStdName("umask") and
    fctmp.getArgument(0).getValue() != "0"
  ) and

…eAssignment.ql

Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
@ihsinme
Copy link
Contributor Author

@ihsinme ihsinme commented Nov 19, 2021

Good day @geoffw0
On the issue of including information about fopen or chmod in the message.
for fopen this is not very good, because we are looking for a wide mask, and there can be many places for calling function fopen.
for chmod this is reasonable enough, but it will require the introduction of additional variables. as an option, I propose to consider replacing the detector, in this block from umask to chmod

@geoffw0
Copy link
Contributor

@geoffw0 geoffw0 commented Nov 19, 2021

I propose to consider replacing the detector, in this block from umask to chmod

For the second case in your query I think this might be sensible.


Its possible to report both locations with something along the lines of:

select firstElement, "This relates to $@.", secondElement, secondElement.toString()

This is tricky to do when you sometimes do and sometimes don't have that secondElement (you end up having a secondElement regardless but assigning it to a harmless value when you don't have $@ in the string).

@ihsinme
Copy link
Contributor Author

@ihsinme ihsinme commented Nov 19, 2021

if you agree, then I will change the request like this.

https://lgtm.com/query/9071199583040934385/

@geoffw0
Copy link
Contributor

@geoffw0 geoffw0 commented Nov 22, 2021

@ihsinme
Copy link
Contributor Author

@ihsinme ihsinme commented Nov 23, 2021

@geoffw0
I made changes.
can you run a check?

@JarLob
Copy link
Contributor

@JarLob JarLob commented Nov 23, 2021

I made changes. can you run a check?

Running...

geoffw0
geoffw0 previously approved these changes Nov 23, 2021
Copy link
Contributor

@geoffw0 geoffw0 left a comment

LGTM.

@JarLob
Copy link
Contributor

@JarLob JarLob commented Nov 23, 2021

Please don't merge yet, WIP :)

@JarLob
Copy link
Contributor

@JarLob JarLob commented Nov 23, 2021

@ihsinme Correct me if I'm wrong, but the vulnerability pattern is valid when functions like fopen create the file with incorrect permissions. This requires "a", "a+" or O_CREAT to be specified. Do I miss any other scenario?
Looking at results for https://github.com/cottsay/openelp for example, shouldn't it exclude the fopen(file, "r") reference as safe?
In some cases all fopen usages might be safe.

@ihsinme
Copy link
Contributor Author

@ihsinme ihsinme commented Nov 23, 2021

@JarLob
in the first block of this query, we find work with a wide mask, without narrowing it after. if there are functions for opening the file.
not important for writing or reading.
In fact, we are looking for files that open with the ability to access them from users in other groups.
this creates the possibility of influencing accessibility (using links and overwriting third-party files on behalf of the program), integrity (the ability to change files) and confidentiality (access to files)

@JarLob
Copy link
Contributor

@JarLob JarLob commented Dec 6, 2021

As I understand from umask documentation this is about a process file mode creation default mask. The file creation (with incorrectly wide file permissions) may happen implicitly during such file operations as fopen when file mode is set to "a" that automatically creates the file if it doesn't exist. However in case of the file mode "r" the fopen is documented to fail if the file doesn't exist, so there is no room for implicit file creation with the default permission mask. If fopen operates on an existing file AFAIK it doesn't change it permissions.

Could you please explain me once more why the combination of fopen(..., "r") and umask(0) is dangerous? You may write in your native language to eliminate any language barrier...

@ihsinme
Copy link
Contributor Author

@ihsinme ihsinme commented Dec 7, 2021

As I understand from umask documentation this is about a process file mode creation default mask. The file creation (with incorrectly wide file permissions) may happen implicitly during such file operations as fopen when file mode is set to "a" that automatically creates the file if it doesn't exist. However in case of the file mode "r" the fopen is documented to fail if the file doesn't exist, so there is no room for implicit file creation with the default permission mask. If fopen operates on an existing file AFAIK it doesn't change it permissions.

Could you please explain me once more why the combination of fopen(..., "r") and umask(0) is dangerous? You may write in your native language to eliminate any language barrier...

good afternoon @JarLob
You're right, there are no security concerns with this combination.
Dear @geoffw0 , tell me how to remove the file reading situation from the detection. I do not find standard approaches in codeql.
Thanks.

@geoffw0
Copy link
Contributor

@geoffw0 geoffw0 commented Dec 8, 2021

tell me how to remove the file reading situation from the detection.

We don't currently have a good model for fopen with details such as this, so I think your best bet is to check the value of the second parameter yourself. Something like:

exists(FunctionCall fc |
  fc.getTarget().hasGlobalOrStdName("fopen") and
  not fc.getArgument(1).getValue().matches("r%") // r or r+
)

@ihsinme
Copy link
Contributor Author

@ihsinme ihsinme commented Dec 9, 2021

not fc.getArgument(1).getValue().matches("r%") // r or r+

Thanks for the answer.
if I do so, do you agree?

  exists(FunctionCall fctmp |
    (
      (
        fctmp.getTarget().hasGlobalOrStdName("fopen") or
        fctmp.getTarget().hasGlobalOrStdName("open")
      ) and
      (
        not fctmp.getArgument(1).getValue().matches("r%") and
        not fctmp.getArgument(1).getValue().matches("O_RDONLY")
      )
    ) and

@geoffw0
Copy link
Contributor

@geoffw0 geoffw0 commented Dec 13, 2021

O_RDONLY is probably a macro or enum constant access, .getValue() will return a string representation of its value (like "0" or "1" or something) not of the access. Other than that your code looks fine.

@ihsinme
Copy link
Contributor Author

@ihsinme ihsinme commented Dec 13, 2021

good afternoon @geoffw0 and @JarLob.
please see the changes made.

geoffw0
geoffw0 approved these changes Jan 4, 2022
Copy link
Contributor

@geoffw0 geoffw0 left a comment

LGTM.

@geoffw0 geoffw0 merged commit 344e380 into github:main Jan 4, 2022
9 checks passed
JarLob added a commit to JarLob/codeql that referenced this issue Jan 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

5 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.