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

printsiginfo: decode si_pkey field #210

Merged
merged 3 commits into from Feb 6, 2022
Merged

Conversation

bacher09
Copy link
Contributor

@bacher09 bacher09 commented Feb 2, 2022

This adds decoding of si_pkey field which is set on SIGSEGV in case
of memory access violation on some modern CPUs (these have pku flag in /proc/cpuinfo).

Here's few sample outputs:

pkey_alloc(0, 0)                        = 3
pkey_mprotect(0x7f3f20662000, 4096, PROT_READ|PROT_WRITE, 3) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_PKUERR, si_addr=0x7f3f20662000, si_pkey=3} ---

or another case:

mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f137374b000
mprotect(0x7f137374b000, 4096, PROT_EXEC) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_PKUERR, si_addr=0x7f137374b000, si_pkey=1} ---

This adds decoding of si_pkey field which is set on SIGSEGV in case
of memory access violation on some modern CPUs (these have pku flag
in /proc/cpuinfo).

* NEWS: Mention this change.
* configure.ac (AC_CHECK_MEMBERS): Check for siginfo_t.si_pkey.
* src/printsiginfo.c (print_si_info) <case SIGSEGV>
[HAVE_SIGINFO_T_SI_PKEY]: Decode si_pkey field.
@codecov
Copy link

codecov bot commented Feb 2, 2022

Codecov Report

Merging #210 (1ffe04f) into master (dadd6b4) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #210   +/-   ##
=======================================
  Coverage   89.95%   89.95%           
=======================================
  Files         287      287           
  Lines       24043    24049    +6     
=======================================
+ Hits        21628    21634    +6     
  Misses       2415     2415           
Impacted Files Coverage Δ
src/printsiginfo.c 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update dadd6b4...1ffe04f. Read the comment docs.

* tests/segv_pkuerr.c: New file.
* tests/gen_tests.in (segv_pkuerr): New test.
* tests/Makefile.am (check_PROGRAMS): Add segv_pkuerr.
* tests/.gitignore: Likewise.
* tests/ptrace.c (main) [HAVE_SIGINFO_T_SI_PKEY]: Check decoding
of SEGV_PKUERR.
@ldv-alt
Copy link
Member

ldv-alt commented Feb 3, 2022 via email

Copy link
Member

@ldv-alt ldv-alt left a comment

Choose a reason for hiding this comment

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

commit message: please change

* src/printsiginfo.c: decode si_pkey field.

to

* src/printsiginfo.c (print_si_info) [HAVE_SIGINFO_T_SI_PKEY]: Decode
si_pkey field.

NEWS Outdated
@@ -12,6 +12,7 @@ Noteworthy changes in release ?.?? (????-??-??)
* Implemented decoding of PR_SET_VMA operation of prctl syscall.
* Updated lists of FAN_*, IORING_*, IOSQE_*, KVM_*, MODULE_INIT_*, TCA_ACT_*,
and *_MAGIC constants.
* Add decoding of si_pkey field in siginfo struct
Copy link
Member

Choose a reason for hiding this comment

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

Please make sure each sentence ends with a dot.

If you have a look at the NEWS file, you'll see that almost every
"Improvements" section ends with "Updated lists of constants" line followed by
"Updated lists of ioctl commands" line.
Let's keep this tradition, please add your line before rather than after
these lines.

Comment on lines 165 to 171
case SIGSEGV: case SIGBUS:
tprint_struct_next();
PRINT_FIELD_PTR(*sip, si_addr);
#ifdef HAVE_SIGINFO_T_SI_PKEY
if (sip->si_signo == SIGSEGV && sip->si_code == SEGV_PKUERR) {
tprint_struct_next();
PRINT_FIELD_D(*sip, si_pkey);
Copy link
Member

Choose a reason for hiding this comment

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

Apparently, siginfo_t.si_pkey is not the only field that could be printed in case of SIGSEGV or SIGBUS,
so I'd suggest to separate case SIGSEG and case SIGBUS, and use a switch on sip->si_code instead of an if statement.

@bacher09
Copy link
Contributor Author

bacher09 commented Feb 3, 2022

I wonder whether the new code could be tested?

Behavior is different on different platforms. On platforms that have pku and ospke in /proc/cpuinfo this code would crash with SIGSEGV (and si_pkey=1) :

#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/prctl.h>

int main(void) {
   prctl(PR_SET_DUMPABLE, 0);
   int *buf = mmap(NULL, getpagesize(), PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);

   if (buf == MAP_FAILED) {
       perror("mmap");
       exit(EXIT_FAILURE);
   }
   if (*buf) {
       asm volatile("":::"memory");
   }
   puts("PKU disabled, so it isn't crashed");
}

while on other platforms it will succeed (since these allow read access to PROT_EXEC regions).

I can try to make conditional test, that would be executed only of pku is present in /proc/cpuinfo.

@ldv-alt
Copy link
Member

ldv-alt commented Feb 3, 2022 via email

* tests/segv_accerr.c: New file.
* tests/gen_tests.in (segv_accerr): New test.
* tests/Makefile.am (check_PROGRAMS): Add segv_accerr.
* tests/.gitignore: Likewise.
@bacher09
Copy link
Contributor Author

bacher09 commented Feb 5, 2022

Hey, wanted to ask what do you think about tests like this:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/prctl.h>

int main(void)
{
        prctl(PR_SET_DUMPABLE, 0);
        int *buf = mmap(NULL, getpagesize(), PROT_EXEC,
                                        MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);

        if (buf == MAP_FAILED) {
           perror("mmap");
           exit(EXIT_FAILURE);
        }
        asm volatile("":: "r" (*buf));
        puts("SIGSEGV did not happen");
        return 0;
}

and script like this:

#
# Check -i option.
#
# Copyright (c) 2015-2022 The strace developers.
# All rights reserved.
#
# SPDX-License-Identifier: GPL-2.0-or-later

. "${srcdir=.}/init.sh"

check_prog grep
check_prog sed


if [ ! "/proc/cpuinfo" ]; then
        exit 0
fi

if ! grep -E -e '^flags.*pku' /proc/cpuinfo | grep ospke > /dev/null 2>&1; then
        exit 0
fi

# this test works only if pku is present
set -- "../$NAME"
$STRACE -e trace=none "$@" > "$LOG"  2>&1 |:
addr="$(sed -r -n 's/^--- SIGSEGV \{si_signo=SIGSEGV, si_code=SEGV_PKUERR, si_addr=(0x[[:xdigit:]]+),.*/\1/p' $LOG)" &&
[ -n "$addr" ] || dump_log_and_fail_with
cat > "$EXP" << __EOF__
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_PKUERR, si_addr=${addr}, si_pkey=1} ---
+++ killed by SIGSEGV +++
__EOF__

match_diff "$LOG" "$EXP"

I was going to improve it a bit, so it would check cases with different si_pkey.

@bacher09
Copy link
Contributor Author

bacher09 commented Feb 5, 2022

I've pushed my changes into another branch (to avoid overwriting your changes), you can check it here. If it's fine I can force push into this branch.

@bacher09
Copy link
Contributor Author

bacher09 commented Feb 6, 2022

Hey, I've replaced:

if (*p)
    __asm__ volatile("":::"memory");

with

__asm__ volatile("":: "r" (*p));

which is IMHO a bit simpler and generates a single mov instruction (in x86 assembly), unlike trick with if (which produces 2 instructions).

@ldv-alt
Copy link
Member

ldv-alt commented Feb 6, 2022 via email

@ldv-alt
Copy link
Member

ldv-alt commented Feb 6, 2022 via email

@ldv-alt
Copy link
Member

ldv-alt commented Feb 6, 2022 via email

@ldv-alt ldv-alt merged commit 1ffe04f into strace:master Feb 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants