-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Remove fdelt_chk back-compat code and sanity check #18862
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
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ACK if this passes the gitian build. This was a backward compatibility function for compatibility with old libc, it (including its sanity check) might no longer be needed. |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsNo conflicts as of last run. |
🐙 This pull request conflicts with the target branch and needs rebase. |
Now that we require glibc 2.17 or later, we no longer need to check for different return types in fdelt_chk. It was changed from unsigned long int to long int in glibc 2.16 . See this commit: https://sourceware.org/git/?p=glibc.git;a=commit;h=ceb9e56b3d1f8c1922e0526c2e841373843460e2 and related issue: https://sourceware.org/bugzilla/show_bug.cgi?id=14210.
As is, this sanity check doesn't seem to be testing fdelt_chk, because passing a value of "0" to FD_SET wont cause the compiler to insert any calls to fdelt_chk(). The documentation is a little misleading. If we actually triggered fdelt_chk at runtime, bitcoind would abort. I think this check would be better replaced (if possible) by additional checks in security-check.py. The compiler may insert a call to fdelt_warn() (aliased with fdelt_chk in glibc) at compile time if it can determine that an invalid value is being passed to FD_SET. These checks are essentially; value < 0 or value >= FD_SETSIZE along with a check for wether the value is a compile time constant. If the compiler can determine an invalid value is being passed, a call to fdelt_warn will be inserted. Passing 0 should never cause a call to be inserted. You can check this after compiling: ```bash objdump -dC bitcoind | grep sanity_fdelt ... 0000000000399d20 <sanity_test_fdelt()>: 399d20: 48 81 ec 98 00 00 00 sub $0x98,%rsp 399d27: b9 10 00 00 00 mov $0x10,%ecx 399d2c: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 399d33: 00 00 399d35: 48 89 84 24 88 00 00 mov %rax,0x88(%rsp) 399d3c: 00 399d3d: 31 c0 xor %eax,%eax 399d3f: 48 89 e7 mov %rsp,%rdi 399d42: fc cld 399d43: f3 48 ab rep stos %rax,%es:(%rdi) 399d46: 48 8b 84 24 88 00 00 mov 0x88(%rsp),%rax 399d4d: 00 399d4e: 64 48 33 04 25 28 00 xor %fs:0x28,%rax 399d55: 00 00 399d57: 75 0d jne 399d66 <sanity_test_fdelt()+0x46> 399d59: b8 01 00 00 00 mov $0x1,%eax 399d5e: 48 81 c4 98 00 00 00 add $0x98,%rsp 399d65: c3 retq 399d66: e8 85 df c8 ff callq 27cf0 <__stack_chk_fail@plt> 399d6b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) ``` To test, you could modify this test to pass -1 to FD_SET, and check that a call to fdelt_warn() is inserted, and that running bitcoind fails. i.e: ```bash 0000000000399d20 <sanity_test_fdelt()>: 399d20: 48 81 ec 98 00 00 00 sub $0x98,%rsp 399d27: b9 10 00 00 00 mov $0x10,%ecx 399d2c: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 399d33: 00 00 399d35: 48 89 84 24 88 00 00 mov %rax,0x88(%rsp) 399d3c: 00 399d3d: 31 c0 xor %eax,%eax 399d3f: 48 89 e7 mov %rsp,%rdi 399d42: fc cld 399d43: f3 48 ab rep stos %rax,%es:(%rdi) 399d46: 48 c7 c7 ff ff ff ff mov $0xffffffffffffffff,%rdi 399d4d: e8 3e ff ff ff callq 399c90 <__fdelt_warn> 399d52: 0f b6 04 24 movzbl (%rsp),%eax 399d56: 83 e0 01 and $0x1,%eax 399d59: 48 8b 94 24 88 00 00 mov 0x88(%rsp),%rdx 399d60: 00 399d61: 64 48 33 14 25 28 00 xor %fs:0x28,%rdx 399d68: 00 00 399d6a: 75 08 jne 399d74 <sanity_test_fdelt()+0x54> 399d6c: 48 81 c4 98 00 00 00 add $0x98,%rsp 399d73: c3 retq 399d74: e8 77 df c8 ff callq 27cf0 <__stack_chk_fail@plt> 399d79: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) ``` ```bash ./src/bitcoind *** buffer overflow detected ***: src/bitcoind terminated Aborted ```
ab7bce5
to
df6bde0
Compare
Guix builds
|
ACK df6bde0 |
sidhujag
pushed a commit
to syscoin/syscoin
that referenced
this pull request
May 14, 2020
df6bde0 test: remove glibc fdelt sanity check (fanquake) 8bf1540 build: remove fdelt_chk backwards compatibility code (fanquake) Pull request description: bitcoin@ae30d40 The return type of [`fdelt_chk`](https://sourceware.org/git/?p=glibc.git;a=blob;f=debug/fdelt_chk.c;h=f62ce7349707cb68f55831c1c591fd7387a90258;hb=HEAD) changed from `unsigned long int` to `long int` in glibc 2.16. See [this commit](https://sourceware.org/git/?p=glibc.git;a=commit;h=ceb9e56b3d1f8c1922e0526c2e841373843460e2). Now that we require [glibc >=2.17](bitcoin#17538) we can remove our back-compat code. bitcoin@ab7bce5 While looking at the above changes, I noticed that our glibc fdelt sanity check doesn't seem to be checking anything. `fdelt_warn()` also isn't something we'd want to actually "trigger" at runtime, as doing so would cause `bitcoind` to abort. The comments: > // trigger: Call FD_SET to trigger __fdelt_chk. FORTIFY_SOURCE must be defined > // as >0 and optimizations must be set to at least -O2. suggest calling FD_SET to check the invocation of `fdelt_chk` (this is [aliased with fdelt_warn in glibc](https://sourceware.org/git/?p=glibc.git;a=blob;f=debug/fdelt_chk.c;h=f62ce7349707cb68f55831c1c591fd7387a90258;hb=HEAD)). However just calling `FD_SET()` will not necessarily cause the compiler to insert a call to `fd_warn()`. Whether or not GCC (recent Clang should work, but may use different heuristics) inserts a call to `fdelt_warn()` depends on if the compiler can determine if the value passed in is a compile time constant (using [`__builtin_constant_p`](https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html)) and whether the value is < 0 or >= `FD_SETSIZE`. The glibc implementation is [here](https://sourceware.org/git/?p=glibc.git;a=blob;f=misc/bits/select2.h;h=7e17430ed94dd1679af10afa3d74795f9c97c0e8;hb=HEAD). This means our check should never cause a call to be inserted. Compiling master without `--glibc-back-compat` (if you do pass `--glibc-back-compat` the outcome is still the same; however the abort will only happen with >=`FD_SETSIZE` as that is what our [fdelt_warn()](https://github.com/bitcoin/bitcoin/blob/master/src/compat/glibc_compat.cpp#L24) checks for), there are no calls to `fdelt_warn()` inserted by the compiler: ```bash objdump -dC bitcoind | grep sanity_fdelt ... 0000000000399d20 <sanity_test_fdelt()>: 399d20: 48 81 ec 98 00 00 00 sub $0x98,%rsp 399d27: b9 10 00 00 00 mov $0x10,%ecx 399d2c: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 399d33: 00 00 399d35: 48 89 84 24 88 00 00 mov %rax,0x88(%rsp) 399d3c: 00 399d3d: 31 c0 xor %eax,%eax 399d3f: 48 89 e7 mov %rsp,%rdi 399d42: fc cld 399d43: f3 48 ab rep stos %rax,%es:(%rdi) 399d46: 48 8b 84 24 88 00 00 mov 0x88(%rsp),%rax 399d4d: 00 399d4e: 64 48 33 04 25 28 00 xor %fs:0x28,%rax 399d55: 00 00 399d57: 75 0d jne 399d66 <sanity_test_fdelt()+0x46> 399d59: b8 01 00 00 00 mov $0x1,%eax 399d5e: 48 81 c4 98 00 00 00 add $0x98,%rsp 399d65: c3 retq 399d66: e8 85 df c8 ff callq 27cf0 <__stack_chk_fail@plt> 399d6b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) ``` If you modify the sanity test to pass `-1` or `FD_SETSIZE` to `FD_SET`, you'll see calls to `fdelt_warn` inserted, and the runtime behaviour is an abort as expected. ```diff diff --git a/src/compat/glibc_sanity_fdelt.cpp b/src/compat/glibc_sanity_fdelt.cpp index 87140d0..16974bfa0 100644 --- a/src/compat/glibc_sanity_fdelt.cpp +++ b/src/compat/glibc_sanity_fdelt.cpp @@ -20,7 +20,7 @@ bool sanity_test_fdelt() { fd_set fds; FD_ZERO(&fds); - FD_SET(0, &fds); + FD_SET(FD_SETSIZE, &fds); return FD_ISSET(0, &fds); } #endif ``` ```bash 0000000000399d20 <sanity_test_fdelt()>: 399d20: 48 81 ec 98 00 00 00 sub $0x98,%rsp 399d27: b9 10 00 00 00 mov $0x10,%ecx 399d2c: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 399d33: 00 00 399d35: 48 89 84 24 88 00 00 mov %rax,0x88(%rsp) 399d3c: 00 399d3d: 31 c0 xor %eax,%eax 399d3f: 48 89 e7 mov %rsp,%rdi 399d42: fc cld 399d43: f3 48 ab rep stos %rax,%es:(%rdi) 399d46: 48 c7 c7 ff ff ff ff mov $0xffffffffffffffff,%rdi 399d4d: e8 3e ff ff ff callq 399c90 <__fdelt_warn> 399d52: 0f b6 04 24 movzbl (%rsp),%eax 399d56: 83 e0 01 and $0x1,%eax 399d59: 48 8b 94 24 88 00 00 mov 0x88(%rsp),%rdx 399d60: 00 399d61: 64 48 33 14 25 28 00 xor %fs:0x28,%rdx 399d68: 00 00 399d6a: 75 08 jne 399d74 <sanity_test_fdelt()+0x54> 399d6c: 48 81 c4 98 00 00 00 add $0x98,%rsp 399d73: c3 retq 399d74: e8 77 df c8 ff callq 27cf0 <__stack_chk_fail@plt> 399d79: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) ``` ```bash src/bitcoind *** buffer overflow detected ***: src/bitcoind terminated Aborted ``` I think the test should should be removed and replaced (if possible) with additional checks in security-check.py. I was thinking about adding a version of [this script](https://github.com/fanquake/core-review/blob/master/fortify.py) as part of the output, but that needs more thought. I'll address this in a follow up. ACKs for top commit: laanwj: ACK df6bde0 Tree-SHA512: d8b3af4f4eb2d6c767ca6e72ece51d0ab9042e1bbdfcbbdb7ad713414df21489ba3217662b531b8bfdac0265d2ce5431abfae6e861b6187d182ff26c6e59b32d
deadalnix
pushed a commit
to Bitcoin-ABC/bitcoin-abc
that referenced
this pull request
Jun 4, 2020
Summary: ```The return type of fdelt_chk changed from unsigned long int to long int in glibc 2.16. See this commit. Now that we require glibc >=2.17 we can remove our back-compat code. [...] ``` Note: we require glibc >= 2.19 so this also applies to us. Backport of core [[bitcoin/bitcoin#15146 | PR15146]] and [[bitcoin/bitcoin#18862 | PR18862]]. [[bitcoin/bitcoin#15146 | PR15146]] fix an edge case from the sanity check which is totally removed by the second commit of [[bitcoin/bitcoin#18862 | PR18862]]. The diff is then mostly a backport of the first commit from [[bitcoin/bitcoin#18862 | PR18862]]: bitcoin/bitcoin@8bf1540 Test Plan: Run the gitian builds. Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D6342
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
ae30d40
The return type of
fdelt_chk
changed fromunsigned long int
tolong int
in glibc 2.16. See this commit. Now that we require glibc >=2.17 we can remove our back-compat code.ab7bce5
While looking at the above changes, I noticed that our glibc fdelt sanity check doesn't seem to be checking anything.
fdelt_warn()
also isn't something we'd want to actually "trigger" at runtime, as doing so would causebitcoind
to abort.The comments:
suggest calling FD_SET to check the invocation of
fdelt_chk
(this is aliased with fdelt_warn in glibc). However just callingFD_SET()
will not necessarily cause the compiler to insert a call tofd_warn()
.Whether or not GCC (recent Clang should work, but may use different heuristics) inserts a call to
fdelt_warn()
depends on if the compiler can determine if the value passed in is a compile time constant (using__builtin_constant_p
) and whether the value is < 0 or >=FD_SETSIZE
. The glibc implementation is here. This means our check should never cause a call to be inserted.Compiling master without
--glibc-back-compat
(if you do pass--glibc-back-compat
the outcome is still the same; however the abort will only happen with >=FD_SETSIZE
as that is what our fdelt_warn() checks for), there are no calls tofdelt_warn()
inserted by the compiler:If you modify the sanity test to pass
-1
orFD_SETSIZE
toFD_SET
, you'll see calls tofdelt_warn
inserted, and the runtime behaviour is an abort as expected.I think the test should should be removed and replaced (if possible) with additional checks in security-check.py. I was thinking about adding a version of this script as part of the output, but that needs more thought. I'll address this in a follow up.