-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Fix a bug that incorrectly reports GNU_STACK missing when its not. #2493
base: stable
Are you sure you want to change the base?
Conversation
Nvmd I believe I figured it out. |
We should start a new 4.13.2 changelog! The change sounds reasonable, but @Arusekk has a better overview of this. |
NX is a protection against data execution. Linux has had its quirks, but by default (GNU_STACK missing) NX is disabled on 'old' architectures (for compat: before NX was a thing, executables did not mark anything 'executable', not even text; they would crash if NX was on), but enabled on 'new' arches. If there is any GNU_STACK (even 'executable stack'), the kernel always enables NX. amd64 used to be an 'old' arch, but this changed to 'new' recently, hence the None value. By NX in the ELF class we mean enabling any NX at all (even for the heap). |
Ok I see the problem. It is still mis-reporting GNU_STACK as missing as a result of returning None but I understand the change now. I'll amend my PR. I think reporting Unknown for the nx state here is unhelpful. Since we know the exact conditions that would determine whether it's enabled or not why not report those conditions to the user so they can determine the state in their situation? I will update my PR to fix the misreporting of GNU_STACK presence and if I have time, and can find a clean way to do so, I will add the additional context if that is something you will approve. |
Why is That's the part that made me assume NX here was referring specifically to the stack. |
TBH I think you should ask Linux devs on the rationale behind READ_IMPLIES_EXEC handling. We just mimic the kernel logic here.
|
c19b135
to
ce79e3e
Compare
I added it. Not sure if you wanted me to move the I reverted all the logic changes, and just fixed the issue I initially set out to fix lol. Thanks for the insight @Arusekk I learned a lot and I also should have realized at least some of that myself before I went through all that. I am confident this final change is correct though because the only architecture that even returns |
When determining whether or not NX is set for amd64 binaries, checksec was
incorrectly reporting that GNU_STACK was missing.
During my investigation of that problem I became aware that the logic to
determine whether or not NX was enabled was also incorrect.
I believe the author of #2186 incorrectly understood the logic that determines
whether or not NX is enabled on the stack. I have compiled the evidence that led
me to that belief below. It is quite possible I am the one missing some context
but I hopefully included enough information to make it easy to validate my
claims.
In #2186 the author uses the code changed in this commit
as the basis for their reasoning, however they seem to imply that code directly
changes the possible states of NX, and makes it permanently enabled on amd64.
For amd64, although
read_implies_exec
is always false for kernel version >=5.8, that does not mean nx is always enabled for kernel version >= 5.8. The
kernel still honors GNU_STACK=+x as seen below:
In
fs/binfmt_elf.c
line 925, in the functionload_elf_binary
, the kernelchecks the GNU_STACK segment to determine if the executable bit is set for the
segment. If it is the kernel sets
executable_stack
toEXSTACK_ENABLE_X
.reference
Then on line 1000 of
fs/binfmt_elf.c
, still inload_elf_binary
, the kerneluses the
read_implies_exec
macro to determine whether or not to set theREAD_IMPLIES_EXEC
flag to the personality. It does not effect theexecutable_stack
variable. We see on line 1010 that theexecutable_stack
variable is passed to
setup_arg_pages
which is used to set the stackpermissions.
reference
Looking at the
setup_arg_pages
function infs/exec.c
, we see that theexecutable_stack
variable is used to set theVM_EXEC
flag ofvm_flags
, andthen, finally, the
vm_flags
get passed tomprotect_fixup
on line 790. Itwill cause a warning to fire but all that will happen is a warning written to
the system log.
reference
pr_warn_once
is just a kernel log statement. Nothing else.reference
As far as I can tell, nothing forces NX when it is explicitly disabled on amd64.
I read through the issue thread and the PR thread where these changes were
explained but I don't see an explanation for why we were returning
None
whenGNU_STACK
was present and it contained theX
bit.In addition, I am changing the return value when
GNU_STACK
is missing toreturn
True
. We can assume that NX is set ifGNU_STACK
is not present eventhough some older systems don't support NX, because those systems will just
ignore the NX bit anyways.
As this kernel commit message,
which was linked in the original PR thread, states:
I think it should be up to the user to determine whether or not NX will be
honored or not on the system they are attacking, and we should not let the rare
chance of a user targeting an old system, which doesn't support NX, make the
output of
checksec
less clear for the majority.