Compare commits

..

No commits in common. "criu-dev" and "v4.0" have entirely different histories.

404 changed files with 2161 additions and 18124 deletions

View file

@ -13,8 +13,9 @@ task:
nested_virtualization: true
setup_script: |
contrib/apt-install make gcc pkg-config git perl-modules iproute2 kmod wget cpu-checker
scripts/ci/apt-install make gcc pkg-config git perl-modules iproute2 kmod wget cpu-checker
sudo kvm-ok
ln -sf /usr/include/google/protobuf/descriptor.proto images/google/protobuf/descriptor.proto
build_script: |
make -C scripts/ci vagrant-fedora-no-vdso
@ -32,9 +33,10 @@ task:
memory: 8G
setup_script: |
ln -sf /usr/include/google/protobuf/descriptor.proto images/google/protobuf/descriptor.proto
dnf config-manager --set-enabled crb # Same as CentOS 8 powertools
dnf -y install epel-release epel-next-release
contrib/dependencies/dnf-packages.sh
dnf -y install --allowerasing asciidoc gcc git gnutls-devel libaio-devel libasan libcap-devel libnet-devel libnl3-devel libbsd-devel libselinux-devel make protobuf-c-devel protobuf-devel python-devel python-PyYAML python-protobuf python-junit_xml python3-importlib-metadata xmlto libdrm-devel
# The image has a too old version of nettle which does not work with gnutls.
# Just upgrade to the latest to make the error go away.
dnf -y upgrade nettle nettle-devel
@ -63,8 +65,9 @@ task:
nested_virtualization: true
setup_script: |
contrib/apt-install make gcc pkg-config git perl-modules iproute2 kmod wget cpu-checker
scripts/ci/apt-install make gcc pkg-config git perl-modules iproute2 kmod wget cpu-checker
sudo kvm-ok
ln -sf /usr/include/google/protobuf/descriptor.proto images/google/protobuf/descriptor.proto
build_script: |
make -C scripts/ci vagrant-fedora-rawhide
@ -83,11 +86,36 @@ task:
nested_virtualization: true
setup_script: |
contrib/apt-install make gcc pkg-config git perl-modules iproute2 kmod wget cpu-checker
scripts/ci/apt-install make gcc pkg-config git perl-modules iproute2 kmod wget cpu-checker
sudo kvm-ok
ln -sf /usr/include/google/protobuf/descriptor.proto images/google/protobuf/descriptor.proto
build_script: |
make -C scripts/ci vagrant-fedora-non-root
task:
name: aarch64 build GCC (native)
arm_container:
image: docker.io/library/ubuntu:jammy
cpu: 4
memory: 4G
script: uname -a
build_script: |
scripts/ci/apt-install make
ln -sf /usr/include/google/protobuf/descriptor.proto images/google/protobuf/descriptor.proto
make -C scripts/ci local
task:
name: aarch64 build CLANG (native)
arm_container:
image: docker.io/library/ubuntu:jammy
cpu: 4
memory: 4G
script: uname -a
build_script: |
scripts/ci/apt-install make
ln -sf /usr/include/google/protobuf/descriptor.proto images/google/protobuf/descriptor.proto
make -C scripts/ci local CLANG=1
task:
name: aarch64 Fedora Rawhide
arm_container:
@ -97,5 +125,6 @@ task:
script: uname -a
build_script: |
scripts/ci/prepare-for-fedora-rawhide.sh
ln -sf /usr/include/google/protobuf/descriptor.proto images/google/protobuf/descriptor.proto
make -C scripts/ci/ local CC=gcc SKIP_CI_PREP=1 SKIP_CI_TEST=1 CD_TO_TOP=1
make -C test/zdtm -j 4

View file

@ -1,3 +1,3 @@
[codespell]
skip = ./.git,./test/pki,./tags,./plugins/amdgpu/amdgpu_drm.h,./plugins/amdgpu/drm.h,./plugins/amdgpu/drm_mode.h
ignore-words-list = creat,fpr,fle,ue,bord,parms,nd,te,testng,inh,wronly,renderd,bui,clen,sems
skip = ./.git,./test/pki
ignore-words-list = creat,fpr,fle,ue,bord,parms,nd,te,testng,inh,wronly,renderd,bui,clen

View file

@ -1,25 +1,43 @@
name: aarch64 test
name: Actuated aarch64 test
on: [push, pull_request]
# Cancel any preceding run on the pull request.
concurrency:
group: aarch64-test-${{ github.event.pull_request.number || github.ref }}
group: actuated-test-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/criu-dev' }}
jobs:
build:
# Actuated runners are not available in all repositories.
if: ${{ github.repository == 'checkpoint-restore/criu' }}
# The memory size and the number of CPUs can be freely selected.
# 3GB and 4 CPUs seems to be enough according to the result from 'vmmeter'.
runs-on: actuated-arm64-4cpu-3gb
strategy:
matrix:
os: [ubuntu-24.04-arm, ubuntu-22.04-arm]
target: [GCC=1, CLANG=1]
runs-on: ${{ matrix.os }}
steps:
# https://gist.github.com/alexellis/1f33e581c75e11e161fe613c46180771#file-metering-gha-md
# vmmeter start
- name: Prepare arkade
uses: alexellis/arkade-get@master
with:
crane: latest
print-summary: false
- name: Install vmmeter
run: |
crane export --platform linux/arm64 ghcr.io/openfaasltd/vmmeter:latest | sudo tar -xvf - -C /usr/local/bin
- name: Run vmmeter
uses: self-actuated/vmmeter-action@master
# vmmeter end
- uses: actions/checkout@v4
- name: Run Tests ${{ matrix.target }} on ${{ matrix.os }}
# Following tests are failing on the VMs:
- name: Run Tests ${{ matrix.target }}
# Following tests are failing on the actuated VMs:
# ./change_mnt_context --pidfile=change_mnt_context.pid --outfile=change_mnt_context.out
# 45: ERR: change_mnt_context.c:23: mount (errno = 22 (Invalid argument))
#

View file

@ -9,11 +9,10 @@ concurrency:
jobs:
build:
runs-on: ubuntu-22.04
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-22.04-arm]
target: [GCC=1, CLANG=1]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4

View file

@ -12,14 +12,14 @@ jobs:
# Check if pull request does not have label "not-selfcontained-ok"
if: "!contains(github.event.pull_request.labels.*.name, 'not-selfcontained-ok')"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
# Needed to rebase against the base branch
fetch-depth: 0
# Checkout pull request HEAD commit instead of merge commit
ref: ${{ github.event.pull_request.head.sha }}
- name: Install dependencies
run: sudo contrib/apt-install libprotobuf-dev libprotobuf-c-dev protobuf-c-compiler protobuf-compiler python3-protobuf libnl-3-dev libnet-dev libcap-dev uuid-dev
run: sudo apt-get install -y libprotobuf-dev libprotobuf-c-dev protobuf-c-compiler protobuf-compiler python3-protobuf libnl-3-dev libnet-dev libcap-dev
- name: Configure git user details
run: |
git config --global user.email "checkpoint-restore@users.noreply.github.com"

View file

@ -29,22 +29,22 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Install Packages (cpp)
if: ${{ matrix.language == 'cpp' }}
run: |
sudo contrib/apt-install protobuf-c-compiler libprotobuf-c-dev libprotobuf-dev build-essential libprotobuf-dev libprotobuf-c-dev protobuf-c-compiler protobuf-compiler python3-protobuf libnet-dev pkg-config libnl-3-dev libbsd0 libbsd-dev iproute2 libcap-dev libaio-dev libbsd-dev python3-yaml libnl-route-3-dev gnutls-dev
sudo scripts/ci/apt-install protobuf-c-compiler libprotobuf-c-dev libprotobuf-dev build-essential libprotobuf-dev libprotobuf-c-dev protobuf-c-compiler protobuf-compiler python3-protobuf libnet-dev pkg-config libnl-3-dev libbsd0 libbsd-dev iproute2 libcap-dev libaio-dev libbsd-dev python3-yaml libnl-route-3-dev gnutls-dev
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{ matrix.language }}"

View file

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
target: [armv7-stable-cross, aarch64-stable-cross, ppc64-stable-cross, mips64el-stable-cross, riscv64-stable-cross]
target: [armv7-stable-cross, aarch64-stable-cross, ppc64-stable-cross, mips64el-stable-cross]
branches: [criu-dev, master]
steps:

View file

@ -21,7 +21,6 @@ jobs:
aarch64-stable-cross,
ppc64-stable-cross,
mips64el-stable-cross,
riscv64-stable-cross,
]
include:
- experimental: true

View file

@ -14,7 +14,7 @@ jobs:
image: registry.fedoraproject.org/fedora:latest
steps:
- name: Install tools
run: sudo dnf -y install git make ruff xz clang-tools-extra codespell git-clang-format ShellCheck
run: sudo dnf -y install git make ruff xz clang-tools-extra which codespell git-clang-format ShellCheck
- uses: actions/checkout@v4

View file

@ -1,24 +0,0 @@
name: Nftables bases testing
on: [push, pull_request]
# Cancel any preceding run on the pull request.
concurrency:
group: nftables-test-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/criu-dev' }}
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Remove iptables
run: sudo apt remove -y iptables
- name: Install libnftables-dev
run: sudo contrib/apt-install libnftables-dev
- name: chmod 755 /home/runner
# CRIU's tests are sometimes running as some random user and need
# to be able to access the test files.
run: sudo chmod 755 /home/runner
- name: Build with nftables network locking backend
run: sudo make -C scripts/ci local COMPILE_FLAGS="NETWORK_LOCK_DEFAULT=NETWORK_LOCK_NFTABLES"

2
.gitignore vendored
View file

@ -20,6 +20,8 @@ compel/compel
compel/compel-host-bin
images/*.c
images/*.h
images/google/protobuf/*.c
images/google/protobuf/*.h
.gitid
criu/criu
criu/unittest/unittest

View file

@ -23,3 +23,8 @@ extraction:
- "python3-yaml"
- "libnl-route-3-dev"
- "gnutls-dev"
configure:
command:
- "ls -laR images/google"
- "ln -s /usr/include/google/protobuf/descriptor.proto images/google/protobuf/descriptor.proto"
- "ls -laR images/google"

35
.travis.yml Normal file
View file

@ -0,0 +1,35 @@
language: c
os: linux
dist: bionic
services:
- docker
jobs:
include:
- os: linux
arch: ppc64le
env: TR_ARCH=local
dist: bionic
- os: linux
arch: ppc64le
env: TR_ARCH=local CLANG=1
dist: bionic
- os: linux
arch: s390x
env: TR_ARCH=local
dist: bionic
- os: linux
arch: arm64-graviton2
env: TR_ARCH=local RUN_TESTS=1
dist: focal
group: edge
virt: vm
- os: linux
arch: arm64-graviton2
env: TR_ARCH=local CLANG=1 RUN_TESTS=1
group: edge
virt: vm
dist: bionic
script:
- sudo make -C scripts/ci $TR_ARCH
after_success:
- make -C scripts/ci after_success

View file

@ -1 +0,0 @@
GEMINI.md

View file

@ -8,8 +8,8 @@ Here are some useful hints to get involved.
* We have both -- [very simple](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) and [more sophisticated](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3A%22new+feature%22) coding tasks;
* CRIU does need [extensive testing](https://github.com/checkpoint-restore/criu/issues?q=is%3Aissue+is%3Aopen+label%3Atesting);
* Documentation is always hard, we have [some information](https://criu.org/Category:Empty_articles) that is to be extracted from people's heads into wiki pages as well as [some texts](https://criu.org/Category:Editor_help_needed) that all need to be converted into useful articles;
* Feedback is expected on the GitHub issues page and on the [mailing list](https://lore.kernel.org/criu);
* We accept GitHub pull requests and this is the preferred way to contribute to CRIU. If you prefer to send patches by email, you are welcome to send them to [CRIU development mailing list](https://lore.kernel.org/criu).
* Feedback is expected on the GitHub issues page and on the [mailing list](https://lists.openvz.org/mailman/listinfo/criu);
* We accept GitHub pull requests and this is the preferred way to contribute to CRIU. If you prefer to send patches by email, you are welcome to send them to [CRIU development mailing list](https://lists.openvz.org/mailman/listinfo/criu).
Below we describe in more detail recommend practices for CRIU development.
* Spread the word about CRIU in [social networks](http://criu.org/Contacts);
* If you're giving a talk about CRIU -- let us know, we'll mention it on the [wiki main page](https://criu.org/News/events);
@ -27,43 +27,19 @@ The repository may contain multiple branches. Development happens in the **criu-
To clone CRIU repo and switch to the proper branch, run:
```
git clone https://github.com/checkpoint-restore/criu criu
cd criu
git checkout criu-dev
git clone https://github.com/checkpoint-restore/criu criu
cd criu
git checkout criu-dev
```
### Building from source
### Compile
Follow these steps to compile CRIU from source code.
First, you need to install compile-time dependencies. Check [Installation dependencies](https://criu.org/Installation#Dependencies) for more info.
#### Installing build dependencies
First, you need to install the required build dependencies. We provide scripts to simplify this process for several Linux distributions in [contrib/dependencies](contrib/dependencies). For a complete list of dependencies, please refer to the [installation guide](https://criu.org/Installation).
##### On Ubuntu/Debian-based systems:
To compile CRIU, run:
```
./contrib/dependencies/apt-packages.sh
```
##### On Fedora/CentOS-based systems:
```
./contrib/dependencies/dnf-packages.sh
```
##### Using Nix:
```
nix develop
```
#### Compiling CRIU
Once the dependencies are installed, you can compile CRIU by running the `make` command from the root of the source directory:
```
make
make
```
This should create the `./criu/criu` executable.
@ -87,7 +63,7 @@ The following command can be used to automatically run a code linter for Python
text spelling (codespell), and a number of CRIU-specific checks (usage of print macros and EOL whitespace for C files).
```
make lint
make lint
```
In addition, we have adopted a [clang-format configuration file](https://www.kernel.org/doc/Documentation/process/clang-format.rst)
@ -97,7 +73,7 @@ results in decreased readability, we may choose to ignore these errors.
Run the following command to check if your changes are compliant with the clang-format rules:
```
make indent
make indent
```
This command is built upon the `git-clang-format` tool and supports two options `BASE` and `OPTS`. The `BASE` option allows you to
@ -107,7 +83,7 @@ can use `BASE=origin/criu-dev`. The `OPTS` option can be used to pass additional
to check the last *N* commits for formatting errors, without applying the changes to the codebase you can use the following command.
```
make indent OPTS=--diff BASE=HEAD~N
make indent OPTS=--diff BASE=HEAD~N
```
Note that for pull requests, the "Run code linter" workflow runs these checks for all commits. If a clang-format error is detected
@ -120,7 +96,7 @@ Here are some bad examples of clang-format-ing:
```
@@ -58,8 +59,7 @@ static int register_membarriers(void)
}
if (!all_ok) {
- fail("can't register membarrier()s - tried %#x, kernel %#x",
- barriers_registered, barriers_supported);
@ -153,11 +129,16 @@ Here are some bad examples of clang-format-ing:
CRIU comes with an extensive test suite. To check whether your changes introduce any regressions, run
```
make test
make test
```
The command runs [ZDTM Test Suite](https://criu.org/ZDTM_Test_Suite). Check for any error messages produced by it.
In case you'd rather have someone else run the tests, you can use travis-ci for your
own GitHub fork of CRIU. It will check the compilation for various supported platforms,
as well as run most of the tests from the suite. See https://travis-ci.org/checkpoint-restore/criu
for more details.
## Describe your changes
Describe your problem. Whether your change is a one-line bug fix or
@ -185,21 +166,21 @@ If your change fixes a bug in a specific commit, e.g. you found an issue using
the SHA-1 ID, and the one line summary. For example:
```
Fixes: 9433b7b9db3e ("make: use cflags/ldflags for config.h detection mechanism")
Fixes: 9433b7b9db3e ("make: use cflags/ldflags for config.h detection mechanism")
```
The following `git config` settings can be used to add a pretty format for
outputting the above style in the `git log` or `git show` commands:
```
[pretty]
fixes = Fixes: %h (\"%s\")
[pretty]
fixes = Fixes: %h (\"%s\")
```
If your change address an issue listed in GitHub, please use `Fixes:` tag with the number of the issue. For instance:
```
Fixes: #339
Fixes: #339
```
The `Fixes:` tags should be put at the end of the detailed description.
@ -282,7 +263,7 @@ can certify the below:
then you just add a line saying
```
Signed-off-by: Random J Developer <random at developer.example.org>
Signed-off-by: Random J Developer <random at developer.example.org>
```
using your real name (please, no pseudonyms or anonymous contributions if
@ -294,14 +275,14 @@ commit message. To append such line to a commit you already made, use
```
From: Random J Developer <random at developer.example.org>
Subject: [PATCH] component: Short patch description
Subject: [PATCH] component: Short patch description
Long patch description (could be skipped if patch
is trivial enough)
Long patch description (could be skipped if patch
is trivial enough)
Signed-off-by: Random J Developer <random at developer.example.org>
---
Patch body here
Signed-off-by: Random J Developer <random at developer.example.org>
---
Patch body here
```
## Submit your work upstream
@ -335,8 +316,8 @@ contains the following:
revisions should be listed. For example:
```
v3: rebase on the current criu-dev
v2: add commit to foo() and update bar() coding style
v3: rebase on the current criu-dev
v2: add commit to foo() and update bar() coding style
```
If there are only minor updates to the commits in a pull request, it is
@ -354,7 +335,7 @@ Historically, CRIU worked with mailing lists and patches so if you still prefer
To create a patch, run
```
git format-patch --signoff origin/criu-dev
git format-patch --signoff origin/criu-dev
```
You might need to read GIT documentation on how to prepare patches
@ -365,8 +346,8 @@ at all.
We recommend to post patches using `git send-email`
```
git send-email --cover-letter --no-chain-reply-to --annotate \
--confirm=always --to=criu@lists.linux.dev criu-dev
git send-email --cover-letter --no-chain-reply-to --annotate \
--confirm=always --to=criu@openvz.org criu-dev
```
Note that the `git send-email` subcommand may not be in
@ -378,14 +359,14 @@ If this is your first time using git send-email, you might need to
configure it to point it to your SMTP server with something like:
```
git config --global sendemail.smtpServer stmp.example.net
git config --global sendemail.smtpServer stmp.example.net
```
If you get tired of typing `--to=criu@lists.linux.dev` all the time,
If you get tired of typing `--to=criu@openvz.org` all the time,
you can configure that to be automatically handled as well:
```
git config sendemail.to criu@lists.linux.dev
git config sendemail.to criu@openvz.org
```
If a developer is sending another version of the patch (e.g. to address
@ -398,7 +379,7 @@ version if needed though).
### Mail patches
The patches should be sent to CRIU development mailing list, `criu AT lists.linux.dev`. Note that you need to be subscribed first in order to post. The list web interface is available at https://lore.kernel.org/criu; you can also use standard mailman aliases to work with it.
The patches should be sent to CRIU development mailing list, `criu AT openvz.org`. Note that you need to be subscribed first in order to post. The list web interface is available at https://openvz.org/mailman/listinfo/criu; you can also use standard mailman aliases to work with it.
Please make sure the email client you're using doesn't screw your patch (line wrapping and so on).
@ -415,3 +396,5 @@ sometimes a patch may fly around a week before it gets reviewed.
Wiki article: [Continuous integration](https://criu.org/Continuous_integration)
CRIU tests are run for each series sent to the mailing list. If you get a message from our patchwork that patches failed to pass the tests, you have to investigate what is wrong.
We also recommend you to [enable Travis CI for your repo](https://criu.org/Continuous_integration#Enable_Travis_CI_for_your_repo) to check patches in your git branch, before sending them to the mailing list.

View file

@ -15,7 +15,6 @@ Checkpoint / Restore inside a docker container
Pytorch
Tensorflow
Using CRIU Image Streamer
Parallel Restore
DESCRIPTION
-----------

View file

@ -465,30 +465,6 @@ The 'mode' may be one of the following:
*skip*::: Don't lock the network. If *--tcp-close* is not used, the network
must be locked externally to allow CRIU to dump TCP connections.
*--allow-uprobes*::
Allow dumping when uprobes vma is present. When used on dump, this option is
required on restore as well.
A uprobes vma is automatically created by the kernel once a uprobe is
triggered. This mapping is not removed even once the uprobe is deleted. So,
even if a process once had uprobes attached to it, and they're removed by
the time the process is dumped, this option is still required because criu
has no way of knowing whether there are active uprobes or not.
When using this option on restore, make sure the uprobes (if any) active on
the dumped processes are still active. Otherwise, when execution reaches
a uprobe'd location in any of the restored processes, that process will be
sent a SIGTRAP.
As an example, say a uprobe is set at function foo in the executable of the
process p_bar. Whenever execution in p_bar reaches function foo, the uprobe
is triggered. If the uprobe has been triggered at least once, then the kernel
will have created the uprobes vma. To dump p_bar, this option is
necessary. After dumping, say the uprobe is deleted. Now, on restoring with
this option, once execution reaches function foo, SIGTRAP will be sent to
the restored p_bar. Unless it has a signal handler installed for SIGTRAP,
it will be terminated and core dumped.
*restore*
~~~~~~~~~
Restores previously checkpointed processes.
@ -502,8 +478,8 @@ Restores previously checkpointed processes.
The 'resource' argument can be one of the following:
+
- **tty[**__rdev__**:**__dev__**]**
- **pipe:[**__inode__**]**
- **socket:[**__inode__*]*
- **pipe[**__inode__**]**
- **socket[**__inode__*]*
- **file[**__mnt_id__**:**__inode__**]**
- 'path/to/file'
@ -716,10 +692,6 @@ The 'mode' may be one of the following:
*--skip-file-rwx-check*::
Skip checking file permissions (r/w/x for u/g/o) on restore.
*--allow-uprobes*::
Required when dumped with this option. Refer to this option in the section
on dumping for more details.
*check*
~~~~~~~
Checks whether the kernel supports the features needed by *criu* to

View file

@ -1,136 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="560px" height="560px" viewBox="0 0 560 560" enable-background="new 0 0 560 560" xml:space="preserve">
<path opacity="0.3" fill="#990000" d="M315.137,360.271c-18.771-7.159-41.548-8.85-68.479-8.85c-16.661,0-46.255,2.939-74.654,3.38
c11.209-4.884,20.734-10.265,24.842-16.87c14.531-23.346,17.645-65.893,17.645-65.893l-20.758,3.114c0,0-2.591,35.8-16.085,47.733
c-5.35,4.736-15.96,7.834-27.916,10.856c2.447-26.071,29.477-57.552,29.477-57.552l-14.874-3.966l-5.88-7.448
c0,0-3.011,1.761-7.588,5.315c-18.298,4.208-75.946,20.443-75.946,57.983c0,15.292,5.77,26.308,14.768,34.244
c-22.858,26.966-20.755,61.618-20.755,61.618s-8.945,16.61-8.021,31.254c2.083,32.973,34.931,25.097,44.313,26.374
c9.644,1.313,34.313-4.18,34.313-4.18s-16.276-2.639-15.329-18.562c0.5-8.369-0.947-27.628-21.404-37.307
c-1.13-10.066,2.111-18.309,6.379-28.015c18.452,45.263,92.601,53.97,92.601,53.97c0.393-0.097-10.269,20.047,0.221,35.632
c4.652,6.915,18.284,10.019,22.436,19.356c4.151,9.341,2.199,30.354,2.199,30.354s21.267-16.864,27.239-30.18
c3.334-7.432,25.989,0.926,25.989-34.047c0-14.077-12.26-26.841-13.675-29.815c-20.858-20.334-5.427-4.743,2.677-8.236
c12.758-5.499,35.412,11.657,35.412,11.657s-10.402-20.119-11.437-31.013c-0.795-8.335-4.537-16.816-16.624-30.042
c7.166-0.752,20.362,2.327,20.362,2.327s-5.202,11.251-0.879,25.515c3.588,11.84,7.193,7.193,14.736,14.737
c6.599,6.598,3.146,26.284,3.146,26.284s4.674-4.513,18.081-18.235c9.072-9.29,23.645-16.717,23.645-47.86
C355.312,365.969,334.97,360.979,315.137,360.271z M134.108,285.901c-11.5,13.048-23.667,32.329-28.23,58.293
c-4.821-3.519-7.613-8.1-7.613-14.043C98.265,309.699,117.078,295.016,134.108,285.901z"/>
<path fill="#990000" d="M382.184,115.435c3.654,1.208,7.327,2.37,10.968,3.444c14.16,4.183,26.745-9.798,26.745-9.798
s-8.785-2.243-17.857-3.497c12.173-2.653,21.085-18.66,21.085-18.66s-17.366,4.819-27.224,5.087
c-2.042,0.057-4.107,0.118-6.189,0.186c2.464-0.37,4.925-0.847,7.361-1.485c14.201-3.714,21.505-23.382,21.505-23.382
s-15.411,6.743-24.951,9.239c-2.694,0.703-5.438,1.437-8.197,2.185c3.038-1.071,6.008-2.306,8.815-3.82
c12.922-6.965,12.241-29.347,12.241-29.347s-10.162,11.926-18.844,16.605c-3.557,1.916-7.199,3.904-10.846,5.911
c3.798-2.277,7.45-4.743,10.596-7.569c10.918-9.814,7.722-29.605,7.722-29.605s-9.801,12.54-17.135,19.131
c-8.939,8.037-18.775,14.104-27.014,21.81c-6.427,6.011-25.14,35.236-36.812,46.283c-11.671,11.047-18.301,12.476-19.159,14.388
c-0.863,1.913,1.006,30.46-14.078,39.145c-16.476-21.583-50.565-44.007-53.101-72.033c-2.079-22.959,5.209-34.055,19.149-35.316
c14.994-1.359,15.998,24.507,15.998,24.507s-1.379,1.064-1.708,6.391c-0.097,0.629-0.145,1.272-0.083,1.934
c0.004,0.031,0.008,0.06,0.011,0.091c-0.014,1.674,0.065,3.664,0.278,6.039c1.131,12.474,4.53,14.574,4.53,14.574l2.075-0.722
c0,0-2.24-4.079-2.554-7.529c-0.172-1.917-0.187-3.556-0.079-4.977c0.45,0.067,0.949,0.081,1.506,0.031
c4.398-0.399,6.049-4.141,5.65-8.539c-0.042-0.45-0.069-0.885-0.094-1.316c2.485-26.032-1.756-29.637,4.788-41.391
c9.032-16.218,17.279-16.015,17.279-16.015l1.402-8.155c0,0-6.817,2.462-14.819,13.652c-8.833,12.354-8.983,26.229-9.066,47.958
c-0.188-0.761-0.502-1.37-1.017-1.784c-2.457-11.192-9.087-32.13-24.112-30.77c-16.72,1.514-29.419,14.974-26.773,44.171
c3.609,39.832,26.186,52.701,29.829,80.84c-13.47-2.349-23.883-10.656-30.866-20.282c-7.803-10.749-7.297-22.949-8.324-24.779
c-1.027-1.829-7.761-2.662-20.367-12.627c-12.605-9.965-33.845-37.41-40.78-42.824c-8.895-6.942-19.229-12.111-28.848-19.32
c-7.892-5.915-18.769-17.531-18.769-17.531s-1.419,19.995,10.323,28.8c3.386,2.536,7.246,4.665,11.229,6.597
c-3.808-1.674-7.616-3.33-11.327-4.925c-9.062-3.887-20.246-14.861-20.246-14.861s1.31,22.353,14.803,28.143
c2.931,1.257,6,2.223,9.12,3.019c-2.818-0.5-5.615-0.985-8.357-1.447c-9.728-1.636-25.677-6.981-25.677-6.981
s9.025,18.94,23.5,21.376c2.485,0.417,4.975,0.674,7.466,0.822c-2.08,0.118-4.148,0.242-6.183,0.368
c-9.843,0.61-27.566-2.645-27.566-2.645S85.667,120.333,110,120c-8.922,2.057-25.678,6.008-25.678,6.008s13.778,12.806,27.508,7.38
c3.533-1.394,7.087-2.876,10.62-4.404c-3.726,1.804-7.424,3.581-11.005,5.273c-8.963,4.243-19.428,10.176-19.428,10.176
s15.069,9.759,27.305,1.497c0.558-0.378,3.121-1.76,3.678-2.143c-7.904,5.808-19.754,14.937-19.754,14.937
s15.802,6.027,27.092-3.354c4.663-3.875,8.104-7.185,12.238-11.618c-3.773,4.55-6.699,8.018-10.634,12.106
c-6.839,7.104-13.06,19.791-13.06,19.791s15.597,0.39,24.359-11.388c4.488-6.035,7.482-11.633,10.974-18.191
c-3.113,6.479-5.468,11.95-8.911,17.788c-5.018,8.49-7.574,22.624-7.574,22.624s15.342-3.655,21.07-17.17
c2.231-5.266,2.107-9.783,3.694-15.291c-1.257,5.272-0.666,9.475-2.24,14.319c-3.045,9.379,0.011,25.554,0.011,25.554
s9.713-5.855,10.359-20.52c0.006-0.153,0.5-8.47,0.5-8.625L171,171.496c0,9.917,6.295,23.276,6.295,23.276
s11.459-10.649,9.369-25.266c-0.188-1.31-0.1-2.627-0.305-3.947c0.408,1.507,0.998,3.016,1.493,4.524
c3.075,9.429,3.5,15.957,3.5,15.957s6.483,1.251,8.73-1.594c0.764,5.625-0.843,10.2-0.843,10.2s5.471-1.1,8.893-3.756
c0.705,5.331,0.155,8.789,0.155,8.789s5.106-1.603,8.419-4.323c0.611,4.642,1.764,7.542,1.764,7.542s6.398-0.88,9.021-5.393
c0.199,0.038,0.395,0.079,0.59,0.117c2.269,4.875,1.438,8.517,1.438,8.517s7.492-2.14,9.492-6.14c0.003,0,0.007,0,0.01,0
c1.798,4,2.727,6.102,2.727,6.102s4.853-2.349,7.093-6.064c0.189,0.009,0.364-0.093,0.547-0.086
c-4.702,19.629-23.62,29.658-42.207,42.764c-1.392,0.981-2.712,1.925-3.97,2.884c-2.891,1.512-6.788,3.495-11.311,5.724
c-9.829,3.363-23.7,6.057-41.038,4.084c-9.798-1.115-21.037,10.02-21.037,10.02s6.87,4.843,16.565,5.028
c-8.819,3.621-17.438,12.632-17.438,12.632s0.045,0.019,0.069,0.029c-27.096,11.688-51.621,29.917-47.651,57.105
c2.375,16.27,14.692,25.475,31.704,30.254c-17.81,14.742-32.921,36.129-30.707,60.59c0.134,1.487,0.309,2.916,0.508,4.311
c-2.209,5.6-3.288,17.842-2.674,24.886c0.949,10.838,13.686,8.662,18.219,6.729c14.139,12.202,32.258,10.252,32.258,10.252
s-17.301,1.211-30.306-11.156c5.551-2.659,6.424-3.925,6.788-11.579c0.36-7.61-9.104-20.759-20.57-21.966
c-1.25-20.07,9.861-43.32,30.603-60.203c0.02,0.249,0.023,0.491,0.048,0.742c4.248,46.957,30.584,54.634,81.148,63.26
c12.603,2.15,22.04,5.821,29.042,10.457c-3.844,5.388-5.706,21.559-2.895,32.325c3.045,11.655,12.647,14.53,19.429,14.955
c-3.304,16.035-11.235,29.024-11.235,29.024s10.015-11.628,15.04-29.016c0.48-0.031,0.928-0.069,1.319-0.114
c10.922-1.262,16.17-11.338,14.743-23.071c-1.195-9.826-13.974-24.54-28.598-25.992c-33.117-21.52-109.104-9.05-113.877-61.769
c-0.341-3.746-0.517-7.367-0.571-10.888c5.709,1.111,11.782,1.844,18.104,2.244c14.111,28.517,62.158,22.269,95.818,20.694
c1.764,3.09,7.043,7.064,13.929,9.779c11.751,4.633,14.889,3.742,18.869,1.502c1.484-0.835,2.828-1.92,3.979-3.155
c10.822,10.456,25.37,30.251,25.37,30.251s-12.29-22.284-22.733-33.97c2.601-4.923,2.433-10.619-2.559-13.297
c-6.956-3.732-31.321,1.581-36.316,4.981c-30.811,1.668-71.853,6.551-89.576-16.474c41.005,1.192,88.786-9.133,102.385-10.365
c21.726-1.966,47.319,1.367,64.887,8.228c-0.783,5.681,1.867,18.47,4.641,25.318c3.316,8.197,11.561,5.887,16.562,3.028
c-0.588,13.3-4.495,22.638-4.495,22.638s7.86-14.125,9.117-26.183c4.354-4.041,4.774-5.562,2.904-12.887
c-1.849-7.24-14.317-16.821-25.47-15.096c-21.855-8.906-54.594-11.087-75.74-9.175c-18.253,1.653-61.404,10.802-97.611,10.237
c-1.895-3.338-3.402-7.122-4.412-11.479c5.113-2.364,10.551-4.388,16.307-5.975c30.999-8.551,40.97-29.258,42.943-48.579
c1.127,1.303,1.938,2.069,1.938,2.069s7.087-12.679,5.522-27.275c-0.264-2.469-0.429-4.737-0.553-6.911
c2.499,6.741,7.778,13.001,7.778,13.001s16.438-20.208,5.846-27.268c-11.583-7.714-6.836-13.283-4.31-15.299
c3.354-1.984,6.973-3.94,10.859-5.817c26.561-12.817,59.903-20.002,64.443-40.039c0.265-1.172,0.388-2.34,0.443-3.507
c3.701,2.396,9.165,2.053,9.165,2.053s-0.367-2.88-0.601-7.556c3.747,2.081,8.874,1.758,8.874,1.758s-0.986-2.319-1.255-7.689
c3.846,1.998,8.434,2.278,8.434,2.278s-0.725-2.246-1.24-5.573c3.788,0.719,8.84,0.419,8.84,0.419s-3.543-7.302-1.316-16.965
c0.357-1.547,0.666-3.09,0.938-4.626c-0.087,1.332-0.169,2.662-0.238,3.985c-0.783,14.742,10.85,24.47,10.85,24.47
S337,172.178,337,162.303c0-0.021,0-0.042,0-0.061c0,0.153-0.804,0.309-0.782,0.46c1.951,14.548,13.499,20.839,13.499,20.839
s2.388-16.471-1.478-25.542c-1.998-4.686-3.966-9.742-5.688-14.881c2.068,5.344,4.374,10.673,7.067,15.72
c6.909,12.952,20.498,15.406,20.498,15.406s-1.832-14.029-7.581-22.041c-3.952-5.505-7.874-11.654-11.551-17.83
c4.059,6.22,8.622,12.438,13.631,18.048c9.774,10.953,25.27,9.178,25.27,9.178s-7.323-12.085-14.767-18.552
c-4.283-3.722-8.589-7.824-12.754-12.019c4.513,4.047,9.319,7.944,14.31,11.39c12.077,8.341,27.281,0.931,27.281,0.931
s-10.533-7.219-18.926-12.302c0.595,0.332,1.186,0.662,1.777,0.988c12.922,7.14,28.146-3.013,28.146-3.013
s-12.036-5.887-21.343-9.313C389.896,118.341,386.055,116.903,382.184,115.435z M116.917,367.418
c-0.172,0.131-0.344,0.268-0.516,0.398c-17.301-3.899-29.646-12.415-31.124-28.752c-2.244-24.777,21.669-42.631,47.562-54.59
c3.553,1,9.203,1.919,15.541,0.503c-4.694,4.817-7.998,9.859-7.998,9.859s2.076,0.564,5.3,0.733
C133.582,308.673,115.917,333.715,116.917,367.418z M146.295,295.598c1.834,0.062,3.979-0.014,6.326-0.386
c-0.141,0.365-0.274,0.72-0.401,1.069c-10.511,14.57-18.745,34.363-17.404,59.912c-4.522,2.267-9.248,5.074-13.939,8.343
C122.237,330.3,136.218,307.613,146.295,295.598z M121.776,368.86c4.131-2.979,8.589-5.697,13.361-8.115
c0.358,3.527,1.032,6.741,2.025,9.634C131.805,370.131,126.629,369.657,121.776,368.86z M150.478,350.278
c-3.791,0.864-8.16,2.403-12.812,4.546c-0.062-0.425-0.168-0.803-0.224-1.236c-2.557-19.875,3.873-37.276,13.005-51.347
c0,0.005-0.007,0.032-0.007,0.032s13.533-3.395,23.088-14.017c-1.715,7.205,0.158,14.79,0.158,14.79s9.774-5.185,16.654-15.216
c-0.131,5.548,2.84,10.803,5.451,14.331C193.303,321.731,182.711,342.934,150.478,350.278z M259.516,275.357
c0.846-4.127,1.649-8.135,2.42-12.012c2.199-4.002,5.203-6.524,9.011-7.55c3.808-1.04,7.78-1.559,11.919-1.559l1.739-17.042
c-5.942,0.378-11.657,1.419-17.144,3.105c-5.492,1.672-10.946,3.611-16.369,5.8c-4.526,4.131-7.915,8.875-10.169,14.237
c-2.262,5.359-3.755,11.051-4.655,17.055c-0.906,6.007-1.268,12.17-1.268,18.489v18.209c0,3.23,0.201,6.368,0.779,9.393
c0.584,3.045,1.728,5.66,3.543,7.85c3.614,2.588,7.203,3.85,10.822,3.771c3.619-0.066,7.224-0.712,10.842-1.925
c3.611-1.23,7.162-2.757,10.647-4.558c3.484-1.811,6.904-3.293,10.266-4.457l7.159-14.521c-2.066,0.505-4.2,1.23-6.394,2.127
c-2.199,0.9-4.453,1.643-6.777,2.224c-2.322,0.585-4.649,0.773-6.977,0.585c-2.322-0.189-4.649-1.2-6.976-2.994
c-2.063-3.626-3.355-7.475-3.87-11.541c-0.519-4.065-0.612-8.165-0.289-12.296C258.1,283.619,258.674,279.488,259.516,275.357z
M367.6,320.582c-0.196-3.025-1.001-5.908-2.42-8.623c-1.031-3.608-2.649-6.588-4.846-8.905c-2.193-2.333-4.682-4.162-7.458-5.516
c-2.773-1.358-5.712-2.364-8.812-3.014c-3.098-0.643-6.004-1.056-8.717-1.259c-2.711-0.188-5.101-0.285-7.166-0.285
s-3.419-0.062-4.064-0.189c0.25-1.037,0.449-2.302,0.574-3.783c0.133-1.481,0.322-2.866,0.584-4.162
c0.258-1.419,0.512-2.977,0.773-4.65c6.326,0,12.073-0.581,17.242-1.749c5.165-1.148,9.688-3.059,13.558-5.705
c3.876-2.646,7.135-6.131,9.781-10.469c2.649-4.318,4.558-9.583,5.715-15.776c-5.684,0-11.596,0.029-17.727,0.093
s-12.328,0.158-18.593,0.284c-6.266,0.143-12.431,0.332-18.5,0.583c-6.066,0.27-11.812,0.584-17.236,0.979
c0.128,0,0.221,1.387,0.293,4.161c0.062,2.775,0.062,6.465,0,11.035c-0.072,4.588-0.2,9.788-0.386,15.589
c-0.199,5.819-0.49,11.73-0.875,17.734c-0.386,6.007-0.878,11.901-1.451,17.72c-0.584,5.815-1.262,10.908-2.035,15.304
c5.552-0.268,11.432-0.488,17.624-0.677c2.162-0.065,4.33-0.127,6.503-0.176l1.247-5.547c0.385-2.192,0.708-4.776,0.969-7.739
c0.259-2.979,0.513-5.754,0.773-8.338c0.259-3.093,0.386-6.196,0.386-9.286c0.646-0.127,1.677-0.206,3.103-0.206
c1.547,0,3.225,0.269,5.039,0.773c1.804,0.519,3.68,1.292,5.612,2.334c1.938,1.041,3.615,2.522,5.034,4.46
c1.42,1.925,2.45,4.352,3.104,7.252c0.638,2.914,0.638,6.495,0,10.75l0.631,5.39c1.609,0.033,3.207,0.079,4.796,0.144
c6.068,0.189,11.812,0.471,17.234,0.866C367.891,326.747,367.795,323.609,367.6,320.582z M327.506,263.345
c0.707-4.397,1.323-8.133,1.835-11.238c1.168-0.521,2.522-0.835,4.069-0.962c1.549-0.125,3.103-0.205,4.65-0.205
c1.677,0,3.291,0.031,4.845,0.112c1.547,0.062,2.901,0.093,4.069,0.093c0,1.151-0.041,2.586-0.103,4.256
c-0.066,1.688-0.189,3.42-0.389,5.232c-0.189,1.815-0.512,3.578-0.97,5.331c-0.446,1.732-1.127,3.182-2.034,4.347
c-0.896,0.918-2.128,1.657-3.681,2.224c-1.543,0.584-3.159,1.042-4.84,1.357c-1.677,0.33-3.291,0.55-4.838,0.677
c-1.555,0.141-2.78,0.207-3.682,0.207C326.439,271.542,326.798,267.727,327.506,263.345z M393.035,246.385
c-2.517,0.33-4.84,0.584-6.97,0.773c-2.135,0.205-3.781,0.172-4.939-0.096l3.678,2.711c0.899,5.423,1.356,11.051,1.356,16.851
c0,5.818-0.195,11.695-0.584,17.642c-0.385,5.941-0.872,11.805-1.45,17.624c-0.581,5.801-1,11.427-1.261,16.85
c-0.907,4.522-1.519,9.238-1.835,14.139c-0.331,4.901-0.843,9.713-1.554,14.425c-0.708,4.712-1.812,9.3-3.297,13.761
c-1.48,4.443-3.773,8.481-6.869,12.107l-2.908,1.543c0.513,0.52,1.323,0.993,2.42,1.45c1.093,0.457,1.842,0.678,2.23,0.678
c2.708-3.23,4.712-6.558,6.004-9.978c1.286-3.419,2.64-6.746,4.069-9.963c1.544-2.711,2.969-5.626,4.261-8.716
c1.286-3.107,2.774-6.008,4.455-8.719c1.671-2.708,3.681-5.045,6.008-6.984c2.322-1.938,5.285-3.15,8.903-3.67
c0.386-6.319,0.836-13.114,1.354-20.335c0.517-7.235,1.001-14.534,1.451-21.896c0.457-7.361,0.846-14.596,1.168-21.689
c0.323-7.111,0.482-13.684,0.482-19.769c-2.713,0-5.458,0.143-8.229,0.394C398.196,245.785,395.553,246.07,393.035,246.385z
M483.002,245c0,4-0.061,5.618-0.188,7.038c-0.135,1.419-0.323,3.525-0.581,5.259c-0.261,1.751-0.584,4.166-0.972,6.752
c-0.386,2.584-0.843,6.388-1.354,11.165c-0.519,4.791-1.135,11.551-1.839,19.167c-0.715,7.612-1.519,18.619-2.427,29.619h-32.15
c0-15,1.065-26.686,3.192-39.535c2.138-12.847,4.101-25.911,5.911-38.695c-5.034,0.52-9.85,1.042-14.427,1.812
c-4.589,0.773-9.136,0.898-13.662,0.52c-0.513,13.682-1.543,27.507-3.097,41.521c-1.553,13.998-3.23,27.586-5.038,40.749
c4.52,0,9.396-0.166,14.631-0.496c5.224-0.316,10.292-0.479,15.2-0.479c0.649,1.152,1.285,2.776,1.942,4.838
c0.638,2.065,1.22,4.318,1.738,6.779c0.517,2.457,0.997,5.027,1.454,7.753c0.447,2.715,0.873,5.424,1.258,8.135
c0.9,6.32,1.681,13.102,2.327,20.336c2.192-6.196,4.454-12.28,6.777-18.209c1.938-5.045,4.004-10.262,6.196-15.699
c2.199-5.423,4.327-10.073,6.393-13.936c2.323,0.254,4.649,0.316,6.974,0.188c2.326-0.124,4.681-0.25,7.071-0.392
c2.386-0.127,4.775-0.127,7.163,0c2.389,0.142,4.681,0.52,6.88,1.165c-0.257-6.716-0.164-13.619,0.293-20.728
c0.449-7.093,1.096-14.204,1.932-21.297c0.841-7.111,1.707-15.14,2.615-22.062c0.907-6.901,1.742-13.27,2.522-21.27H483.002z"/>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

136
GEMINI.md
View file

@ -1,136 +0,0 @@
# CRIU (Checkpoint/Restore In User-space)
CRIU is a tool for saving the state of a running application to a set of files
(checkpointing) and restoring it back to a live state. It is primarily used for
live migration of containers, in-place updates, and fast application startup.
It is implemented as a command-line tool called `criu`. The two primary commands
are `dump` and `restore`.
- `dump`: Saves a process tree and all its related resources (file
descriptors, IPC, sockets, namespaces, etc.) into a collection of image
files.
- `restore`: Restores processes from image files to the same state they were
in before the dump.
## Quick Start
To get a feel for `criu`, you can try checkpointing and restoring a simple
process.
1. **Run a simple process:**
Open a terminal and run a command that will run for a while. Find its PID.
```bash
sleep 1000 &
[1] 12345
```
2. **Dump the process:**
As root, use `criu dump` with the process ID (`-t`) and a directory for the
image files (`-D`).
```bash
sudo criu dump -t 12345 -D /tmp/sleep_images -v4 --shell-job
```
The `sleep` process will no longer be running.
3. **Restore the process:**
Use `criu restore` to bring the process back to life from the images.
```bash
sudo criu restore -D /tmp/sleep_images -v4 --shell-job
```
The `sleep` process will be running again as if nothing happened.
# For Developers and Contributors
This section contains more technical details about CRIU's internals and
development process.
## Dump Process
On dump, CRIU uses available kernel interfaces to collect information about
processes. For properties that can only be retrieved from within the process
itself, CRIU injects a binary blob (called a "parasite") into the process's
address space and executes it in the context of one of the process's threads.
This injection is handled by a subproject called **Compel**.
## Restore Process
On restore, CRIU reads the image files to reconstruct the processes. The goal is
to restore them to the exact state they were in before the dump. The restore
process is divided into several stages (defined as `CR_STATE_*` in
`./criu/include/restorer.h`).
The main `criu` process acts as a coordinator. It first restores resources with
inter-process dependencies (file descriptors, sockets, shared memory,
namespaces, etc.). It then forks the process tree and sets up namespaces.
Finally, it restores process-specific resources like file descriptors and memory
mappings.
A key step involves a small, self-contained binary called the "restorer". All
restored processes switch to executing this code, which unmaps the CRIU-specific
memory and restores the application's original memory mappings. On the final
step, the restorer calls `sigreturn` on a prepared signal frame to resume the
process with the state it had at the moment of the dump.
## Compel
Compel is a subproject responsible for generating the binary blobs used for the
parasite code (for dumping) and the restorer code (for restoring). It provides a
library for injecting and executing this code within the target process's
address space. It is a separate project because the logic for generating and
injecting Position-Independent Executable (PIE) code is complex and
self-contained.
## Coding Style
The C code in the CRIU project follows the
[Linux Kernel Coding Style](https://www.kernel.org/doc/html/latest/process/coding-style.html).
Here are some of the main points:
- **Indentation**: Use tabs, which are set to 8 characters.
- **Line Length**: The preferred line limit is 80 characters, but it can be
extended to 120 if it improves code readability.
- **Braces**:
- The opening brace for a function goes on a new line.
- The opening brace for a block (like `if`, `for`, `while`, `switch`) goes
on the same line.
- **Spaces**: Use spaces around operators (`+`, `-`, `*`, `/`, `%`, `<`, `>`,
`=`, etc.).
- **Naming**: Use descriptive names for functions and variables.
- **Comments**: Use C-style comments (`/* ... */`). For multi-line comments,
the preferred format is:
```c
/*
* This is a multi-line
* comment.
*/
```
## Code Layout
The code is organized into the following directories:
- `./compel`: The Compel sub-project.
- `./criu`: The main `criu` tool source code.
- `./images`: Protobuf descriptions for the image files.
- `./test`: All tests.
- `./test/zdtm`: The Zero-Downtime Migration (ZDTM) test suite.
- `./test/zdtm.py`: The executor script for ZDTM tests.
- `./scripts`: Helper scripts.
- `./scripts/build`: Docker image files used for CI and cross-compilation
checks.
- `./crit`: A tool to inspect and manipulate CRIU image files.
- `./soccr`: A library for TCP socket checkpoint/restore.
## Tests
The main test suite is ZDTM. Here is an example of how to run a single test:
```bash
sudo ./test/zdtm.py run -t zdtm/static/env00
```
Each ZDTM test has three stages: preparation, C/R, and results checks. During
the test, a process calls `test_daemon()` to signal it is ready for C/R, then
calls `test_waitsig()` to wait for the C/R stage to complete. After being
restored, the test checks that all its resources are still in a valid state.

View file

@ -1,31 +1,11 @@
## Building CRIU from source code
First, you need to install compile-time dependencies. Check [Installation dependencies](https://criu.org/Installation#Dependencies) for more info.
To compile CRIU, run:
```
make
```
This should create the `./criu/criu` executable.
To change the default behaviour of CRIU, the following variables can be passed
to the make command:
* **NETWORK_LOCK_DEFAULT**, can be set to one of the following
values: `NETWORK_LOCK_IPTABLES`, `NETWORK_LOCK_NFTABLES`,
`NETWORK_LOCK_SKIP`. CRIU defaults to `NETWORK_LOCK_IPTABLES`
if nothing is specified. If another network locking backend is
needed, `make` can be called like this:
`make NETWORK_LOCK_DEFAULT=NETWORK_LOCK_NFTABLES`
## Installing CRIU from source code
Once CRIU is built one can easily setup the complete CRIU package
(which includes executable itself, CRIT tool, libraries, manual
and etc) simply typing
```
make install
```
make install
this command accepts the following variables:
* **DESTDIR**, to specify global root where all components will be placed under (empty by default);
@ -36,17 +16,17 @@ this command accepts the following variables:
* **LIBDIR**, to specify directory where to put libraries (guess the correct path by default).
Thus one can type
```
make DESTDIR=/some/new/place install
```
make DESTDIR=/some/new/place install
and get everything installed under `/some/new/place`.
## Uninstalling CRIU
To clean up previously installed CRIU instance one can type
```
make uninstall
```
make uninstall
and everything should be removed. Note though that if some variable (**DESTDIR**, **BINDIR**
and such) has been used during installation procedure, the same *must* be passed with
uninstall action.

View file

@ -19,7 +19,7 @@ endif
#
# Supported Architectures
ifneq ($(filter-out x86 arm aarch64 ppc64 s390 mips loongarch64 riscv64,$(ARCH)),)
ifneq ($(filter-out x86 arm aarch64 ppc64 s390 mips loongarch64,$(ARCH)),)
$(error "The architecture $(ARCH) isn't supported")
endif
@ -43,7 +43,7 @@ ifeq ($(ARCH),arm)
endif
ifeq ($(ARMV),8)
# Running 'setarch linux32 uname -m' returns armv8l on aarch64.
# Running 'setarch linux32 uname -m' returns armv8l on travis aarch64.
# This tells CRIU to handle armv8l just as armv7hf. Right now this is
# only used for compile testing. No further verification of armv8l exists.
ARCHCFLAGS += -march=armv7-a
@ -64,8 +64,6 @@ endif
ifeq ($(ARCH),aarch64)
DEFINES := -DCONFIG_AARCH64
CC_MBRANCH_PROT := $(shell $(CC) -c -x c /dev/null -mbranch-protection=none -o /dev/null >/dev/null 2>&1 && echo "-mbranch-protection=none")
CFLAGS_PIE := $(CC_MBRANCH_PROT)
endif
ifeq ($(ARCH),ppc64)
@ -86,10 +84,6 @@ ifeq ($(ARCH),loongarch64)
DEFINES := -DCONFIG_LOONGARCH64
endif
ifeq ($(ARCH),riscv64)
DEFINES := -DCONFIG_RISCV64
endif
#
# CFLAGS_PIE:
#
@ -142,10 +136,6 @@ ifneq ($(GCOV),)
CFLAGS += $(CFLAGS-GCOV)
endif
ifneq ($(NETWORK_LOCK_DEFAULT),)
CFLAGS += -DNETWORK_LOCK_DEFAULT=$(NETWORK_LOCK_DEFAULT)
endif
ifeq ($(ASAN),1)
CFLAGS-ASAN := -fsanitize=address
export CFLAGS-ASAN
@ -447,14 +437,10 @@ help:
ruff:
@ruff --version
ruff check ${RUFF_FLAGS} --config=scripts/ruff.toml \
ruff ${RUFF_FLAGS} --config=scripts/ruff.toml \
test/zdtm.py \
test/inhfd/*.py \
test/others/rpc/config_file.py \
test/others/action-script/check_actions.py \
test/others/pycriu/*.py \
lib/pycriu/criu.py \
lib/pycriu/__init__.py \
lib/pycriu/images/pb2dict.py \
lib/pycriu/images/images.py \
scripts/criu-ns \
@ -468,8 +454,7 @@ ruff:
shellcheck:
shellcheck --version
shellcheck scripts/*.sh
shellcheck scripts/ci/*.sh
shellcheck contrib/apt-install contrib/dependencies/*.sh
shellcheck scripts/ci/*.sh scripts/ci/apt-install
shellcheck -x test/others/crit/*.sh
shellcheck -x test/others/libcriu/*.sh
shellcheck -x test/others/crit/*.sh test/others/criu-coredump/*.sh
@ -477,7 +462,7 @@ shellcheck:
shellcheck -x test/others/action-script/*.sh
codespell:
codespell
codespell -S tags
lint: ruff shellcheck codespell
# Do not append \n to pr_perror, pr_pwarn or fail
@ -492,7 +477,7 @@ lint: ruff shellcheck codespell
! git --no-pager grep -E '\s+$$' \*.c \*.h
.PHONY: lint ruff shellcheck codespell
codecov: SHELL := $(shell command -v bash)
codecov: SHELL := $(shell which bash)
codecov:
curl -Os https://uploader.codecov.io/latest/linux/codecov
chmod +x codecov

View file

@ -50,8 +50,8 @@ compel/plugins/%: $(compel-deps) .FORCE
#
# GNU make 4.x supports targets matching via wide
# match targeting, where GNU make 3.x series is not,
# so we have to write them here explicitly.
# match targeting, where GNU make 3.x series (used on
# Travis) is not, so we have to write them here explicitly.
compel/plugins/std.lib.a: $(compel-deps) .FORCE
$(Q) $(MAKE) $(build)=compel/plugins $@

View file

@ -9,7 +9,7 @@ ifeq ($(call try-cc,$(FEATURE_TEST_LIBBSD_DEV),-lbsd),true)
LIBS_FEATURES += -lbsd
FEATURE_DEFINES += -DCONFIG_HAS_LIBBSD
else
$(info Note: Building without setproctitle() support.)
$(info Note: Building without setproctitle() and strlcpy() support.)
$(info $S Install libbsd-devel (RPM) / libbsd-dev (DEB) to fix.)
endif
@ -59,10 +59,6 @@ endif
export LIBS += $(LIBS_FEATURES)
ifneq ($(PLUGINDIR),)
FEATURE_DEFINES += -DCR_PLUGIN_DEFAULT="\"$(PLUGINDIR)\""
endif
CONFIG_FILE = .config
$(CONFIG_FILE):
@ -84,7 +80,7 @@ endif
export DEFINES += $(FEATURE_DEFINES)
export CFLAGS += $(FEATURE_DEFINES)
FEATURES_LIST := TCP_REPAIR PTRACE_PEEKSIGINFO \
FEATURES_LIST := TCP_REPAIR STRLCPY STRLCAT PTRACE_PEEKSIGINFO \
SETPROCTITLE_INIT TCP_REPAIR_WINDOW MEMFD_CREATE \
OPENAT2 NO_LIBC_RSEQ_DEFS

View file

@ -46,13 +46,9 @@ endif
endif
# Default flags for pip install:
# --ignore-installed: Overwrite already installed pycriu/crit packages
# --no-build-isolation: Use current Python environment to build pycriu/crit packages
# --no-deps: Don't install any dependencies
# --no-index: Don't use PyPI index to find packages
# --progress-bar: Cleaner output
# --upgrade: Treat the install as an upgrade when replacing the installed version
PIPFLAGS ?= --ignore-installed --no-build-isolation --no-deps --no-index --progress-bar off --upgrade
# --upgrade: Upgrade crit/pycriu packages
# --ignore-installed: Ignore existing packages and reinstall them
PIPFLAGS ?= --upgrade --ignore-installed
export SKIP_PIP_INSTALL PIPFLAGS

View file

@ -1,10 +1,10 @@
#
# CRIU version.
CRIU_VERSION_MAJOR := 4
CRIU_VERSION_MINOR := 2
CRIU_VERSION_MINOR := 0
CRIU_VERSION_SUBLEVEL :=
CRIU_VERSION_EXTRA :=
CRIU_VERSION_NAME := CRIUTIBILITY
CRIU_VERSION_NAME := CRIUDA
CRIU_VERSION := $(CRIU_VERSION_MAJOR)$(if $(CRIU_VERSION_MINOR),.$(CRIU_VERSION_MINOR))$(if $(CRIU_VERSION_SUBLEVEL),.$(CRIU_VERSION_SUBLEVEL))$(if $(CRIU_VERSION_EXTRA),.$(CRIU_VERSION_EXTRA))
export CRIU_VERSION_MAJOR CRIU_VERSION_MINOR CRIU_VERSION_SUBLEVEL

View file

@ -7,7 +7,7 @@
[![CircleCI](https://circleci.com/gh/checkpoint-restore/criu.svg?style=svg)](
https://circleci.com/gh/checkpoint-restore/criu)
<p align="center"><img src="Documentation/logo.svg" width="256px"/></p>
<p align="center"><img src="https://criu.org/w/images/1/1c/CRIU.svg" width="256px"/></p>
## CRIU -- A project to implement checkpoint/restore functionality for Linux

3
compel/.gitignore vendored
View file

@ -4,9 +4,6 @@ arch/arm/plugins/std/syscalls/syscalls.S
arch/aarch64/plugins/std/syscalls/syscalls.S
arch/s390/plugins/std/syscalls/syscalls.S
arch/ppc64/plugins/std/syscalls/syscalls.S
arch/mips/plugins/std/syscalls/syscalls-64.S
arch/loongarch64/plugins/std/syscalls/syscalls-64.S
arch/riscv64/plugins/std/syscalls/syscalls.S
include/version.h
plugins/include/uapi/std/asm/syscall-types.h
plugins/include/uapi/std/syscall-64.h

View file

@ -32,8 +32,8 @@ ifeq ($(ARCH),x86)
lib-y += arch/$(ARCH)/src/lib/thread_area.o
endif
# handle_elf() has no support of ELF relocations on ARM and RISCV64 (yet?)
ifneq ($(filter arm aarch64 loongarch64 riscv64,$(ARCH)),)
# handle_elf() has no support of ELF relocations on ARM (yet?)
ifneq ($(filter arm aarch64 loongarch64,$(ARCH)),)
CFLAGS += -DNO_RELOCS
HOSTCFLAGS += -DNO_RELOCS
endif

View file

@ -1,47 +0,0 @@
#ifndef __UAPI_ASM_GCS_TYPES_H__
#define __UAPI_ASM_GCS_TYPES_H__
#ifndef NT_ARM_GCS
#define NT_ARM_GCS 0x410 /* ARM GCS state */
#endif
/* Shadow Stack/Guarded Control Stack interface */
#define PR_GET_SHADOW_STACK_STATUS 74
#define PR_SET_SHADOW_STACK_STATUS 75
#define PR_LOCK_SHADOW_STACK_STATUS 76
/* When set PR_SHADOW_STACK_ENABLE flag allocates a Guarded Control Stack */
#ifndef PR_SHADOW_STACK_ENABLE
#define PR_SHADOW_STACK_ENABLE (1UL << 0)
#endif
/* Allows explicit GCS stores (eg. using GCSSTR) */
#ifndef PR_SHADOW_STACK_WRITE
#define PR_SHADOW_STACK_WRITE (1UL << 1)
#endif
/* Allows explicit GCS pushes (eg. using GCSPUSHM) */
#ifndef PR_SHADOW_STACK_PUSH
#define PR_SHADOW_STACK_PUSH (1UL << 2)
#endif
#ifndef SHADOW_STACK_SET_TOKEN
#define SHADOW_STACK_SET_TOKEN 0x1 /* Set up a restore token in the shadow stack */
#endif
#define PR_SHADOW_STACK_ALL_MODES \
PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE | PR_SHADOW_STACK_PUSH
/* copied from: arch/arm64/include/asm/sysreg.h */
#define GCS_CAP_VALID_TOKEN 0x1
#define GCS_CAP_ADDR_MASK 0xFFFFFFFFFFFFF000ULL
#define GCS_CAP(x) ((((unsigned long)x) & GCS_CAP_ADDR_MASK) | GCS_CAP_VALID_TOKEN)
#define GCS_SIGNAL_CAP(addr) (((unsigned long)addr) & GCS_CAP_ADDR_MASK)
#include <asm/hwcap.h>
#ifndef HWCAP_GCS
#define HWCAP_GCS (1UL << 32)
#endif
#endif /* __UAPI_ASM_GCS_TYPES_H__ */

View file

@ -2,7 +2,6 @@
#define UAPI_COMPEL_ASM_TYPES_H__
#include <stdint.h>
#include <stdbool.h>
#include <signal.h>
#include <sys/mman.h>
#include <asm/ptrace.h>
@ -17,24 +16,7 @@
*/
typedef struct user_pt_regs user_regs_struct_t;
/*
* GCS (Guarded Control Stack)
*
* This mirrors the kernel definition but renamed to cr_user_gcs
* to avoid conflict with kernel headers (/usr/include/asm/ptrace.h).
*/
struct cr_user_gcs {
__u64 features_enabled;
__u64 features_locked;
__u64 gcspr_el0;
};
struct user_fpregs_struct {
struct user_fpsimd_state fpstate;
struct cr_user_gcs gcs;
};
typedef struct user_fpregs_struct user_fpregs_struct_t;
typedef struct user_fpsimd_state user_fpregs_struct_t;
#define __compel_arch_fetch_thread_area(tid, th) 0
#define compel_arch_fetch_thread_area(tctl) 0
@ -57,12 +39,4 @@ typedef struct user_fpregs_struct user_fpregs_struct_t;
__NR_##syscall; \
})
extern bool __compel_host_supports_gcs(void);
#define compel_host_supports_gcs __compel_host_supports_gcs
struct parasite_ctl;
extern int __parasite_setup_shstk(struct parasite_ctl *ctl,
user_fpregs_struct_t *ext_regs);
#define parasite_setup_shstk __parasite_setup_shstk
#endif /* UAPI_COMPEL_ASM_TYPES_H__ */

View file

@ -1,29 +1,19 @@
#ifndef UAPI_COMPEL_ASM_SIGFRAME_H__
#define UAPI_COMPEL_ASM_SIGFRAME_H__
#include <signal.h>
#include <asm/sigcontext.h>
#include <sys/ucontext.h>
#include <stdint.h>
#include <asm/types.h>
/* Copied from the kernel header arch/arm64/include/uapi/asm/sigcontext.h */
#define FPSIMD_MAGIC 0x46508001
#define GCS_MAGIC 0x47435300
typedef struct fpsimd_context fpu_state_t;
struct gcs_context {
struct _aarch64_ctx head;
__u64 gcspr;
__u64 features_enabled;
__u64 reserved;
};
struct aux_context {
struct fpsimd_context fpsimd;
struct gcs_context gcs;
/* additional context to be added before "end" */
struct _aarch64_ctx end;
};
@ -72,7 +62,6 @@ struct cr_sigcontext {
#define RT_SIGFRAME_AUX_CONTEXT(rt_sigframe) ((struct aux_context *)&(RT_SIGFRAME_SIGCONTEXT(rt_sigframe)->__reserved))
#define RT_SIGFRAME_FPU(rt_sigframe) (&RT_SIGFRAME_AUX_CONTEXT(rt_sigframe)->fpsimd)
#define RT_SIGFRAME_OFFSET(rt_sigframe) 0
#define RT_SIGFRAME_GCS(rt_sigframe) (&RT_SIGFRAME_AUX_CONTEXT(rt_sigframe)->gcs)
#define rt_sigframe_erase_sigset(sigframe) memset(&sigframe->uc.uc_sigmask, 0, sizeof(k_rtsigset_t))
#define rt_sigframe_copy_sigset(sigframe, from) memcpy(&sigframe->uc.uc_sigmask, from, sizeof(k_rtsigset_t))

View file

@ -2,8 +2,8 @@
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/auxv.h>
#include <asm/ptrace.h>
#include <linux/elf.h>
#include <compel/plugins/std/syscall-codes.h>
#include "common/page.h"
@ -13,8 +13,6 @@
#include "infect.h"
#include "infect-priv.h"
#include "asm/breakpoints.h"
#include "asm/gcs-types.h"
#include <linux/prctl.h>
unsigned __page_size = 0;
unsigned __page_shift = 0;
@ -35,54 +33,24 @@ static inline void __always_unused __check_code_syscall(void)
BUILD_BUG_ON(!is_log2(sizeof(code_syscall)));
}
bool __compel_host_supports_gcs(void)
{
unsigned long hwcap = getauxval(AT_HWCAP);
return (hwcap & HWCAP_GCS) != 0;
}
static bool __compel_gcs_enabled(struct cr_user_gcs *gcs)
{
if (!compel_host_supports_gcs())
return false;
return gcs && (gcs->features_enabled & PR_SHADOW_STACK_ENABLE) != 0;
}
int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
struct fpsimd_context *fpsimd = RT_SIGFRAME_FPU(sigframe);
struct gcs_context *gcs = RT_SIGFRAME_GCS(sigframe);
memcpy(sigframe->uc.uc_mcontext.regs, regs->regs, sizeof(regs->regs));
pr_debug("sigreturn_prep_regs_plain: sp %lx pc %lx\n", (long)regs->sp, (long)regs->pc);
sigframe->uc.uc_mcontext.sp = regs->sp;
sigframe->uc.uc_mcontext.pc = regs->pc;
sigframe->uc.uc_mcontext.pstate = regs->pstate;
memcpy(fpsimd->vregs, fpregs->fpstate.vregs, 32 * sizeof(__uint128_t));
memcpy(fpsimd->vregs, fpregs->vregs, 32 * sizeof(__uint128_t));
fpsimd->fpsr = fpregs->fpstate.fpsr;
fpsimd->fpcr = fpregs->fpstate.fpcr;
fpsimd->fpsr = fpregs->fpsr;
fpsimd->fpcr = fpregs->fpcr;
fpsimd->head.magic = FPSIMD_MAGIC;
fpsimd->head.size = sizeof(*fpsimd);
if (__compel_gcs_enabled(&fpregs->gcs)) {
gcs->head.magic = GCS_MAGIC;
gcs->head.size = sizeof(*gcs);
gcs->reserved = 0;
gcs->gcspr = fpregs->gcs.gcspr_el0 - 8;
gcs->features_enabled = fpregs->gcs.features_enabled;
pr_debug("sigframe gcspr=%llx features_enabled=%llx\n", fpregs->gcs.gcspr_el0 - 8, fpregs->gcs.features_enabled);
} else {
pr_debug("sigframe gcspr=[disabled]\n");
memset(gcs, 0, sizeof(*gcs));
}
return 0;
}
@ -91,7 +59,7 @@ int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, struct rt_sigfr
return 0;
}
int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct_t *ext_regs, save_regs_t save,
int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd, save_regs_t save,
void *arg, __maybe_unused unsigned long flags)
{
struct iovec iov;
@ -106,28 +74,14 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
goto err;
}
iov.iov_base = &ext_regs->fpstate;
iov.iov_len = sizeof(ext_regs->fpstate);
iov.iov_base = fpsimd;
iov.iov_len = sizeof(*fpsimd);
if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov))) {
pr_perror("Failed to obtain FPU registers for %d", pid);
goto err;
}
memset(&ext_regs->gcs, 0, sizeof(ext_regs->gcs));
iov.iov_base = &ext_regs->gcs;
iov.iov_len = sizeof(ext_regs->gcs);
if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_GCS, &iov) == 0) {
pr_info("gcs: GCSPR_EL0 for %d: 0x%llx, features: 0x%llx\n",
pid, ext_regs->gcs.gcspr_el0, ext_regs->gcs.features_enabled);
if (!__compel_gcs_enabled(&ext_regs->gcs))
pr_info("gcs: GCS is NOT enabled\n");
} else {
pr_info("gcs: GCS state not available for %d\n", pid);
}
ret = save(pid, arg, regs, ext_regs);
ret = save(arg, regs, fpsimd);
err:
return ret;
}
@ -136,44 +90,14 @@ int compel_set_task_ext_regs(pid_t pid, user_fpregs_struct_t *ext_regs)
{
struct iovec iov;
struct cr_user_gcs gcs;
struct iovec gcs_iov = { .iov_base = &gcs, .iov_len = sizeof(gcs) };
pr_info("Restoring GP/FPU registers for %d\n", pid);
iov.iov_base = &ext_regs->fpstate;
iov.iov_len = sizeof(ext_regs->fpstate);
iov.iov_base = ext_regs;
iov.iov_len = sizeof(*ext_regs);
if (ptrace(PTRACE_SETREGSET, pid, NT_PRFPREG, &iov)) {
pr_perror("Failed to set FPU registers for %d", pid);
return -1;
}
if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_GCS, &gcs_iov) < 0) {
pr_warn("gcs: Failed to get GCS for %d\n", pid);
} else {
ext_regs->gcs = gcs;
compel_set_task_gcs_regs(pid, ext_regs);
}
return 0;
}
int compel_set_task_gcs_regs(pid_t pid, user_fpregs_struct_t *ext_regs)
{
struct iovec iov;
pr_info("gcs: restoring GCS registers for %d\n", pid);
pr_info("gcs: restoring GCS: gcspr=%llx features=%llx\n",
ext_regs->gcs.gcspr_el0, ext_regs->gcs.features_enabled);
iov.iov_base = &ext_regs->gcs;
iov.iov_len = sizeof(ext_regs->gcs);
if (ptrace(PTRACE_SETREGSET, pid, NT_ARM_GCS, &iov)) {
pr_perror("gcs: Failed to set GCS registers for %d", pid);
return -1;
}
return 0;
}
@ -362,68 +286,3 @@ int ptrace_flush_breakpoints(pid_t pid)
return 0;
}
int inject_gcs_cap_token(struct parasite_ctl *ctl, pid_t pid, struct cr_user_gcs *gcs)
{
struct iovec gcs_iov = { .iov_base = gcs, .iov_len = sizeof(*gcs) };
uint64_t token_addr = gcs->gcspr_el0 - 8;
uint64_t sigtramp_addr = gcs->gcspr_el0 - 16;
uint64_t cap_token = ALIGN_DOWN(GCS_SIGNAL_CAP(token_addr), 8);
unsigned long restorer_addr;
pr_info("gcs: (setup) CAP token: 0x%lx at addr: 0x%lx\n", cap_token, token_addr);
/* Inject capability token at gcspr_el0 - 8 */
if (ptrace(PTRACE_POKEDATA, pid, (void *)token_addr, cap_token)) {
pr_perror("gcs: (setup) Inject GCS cap token failed");
return -1;
}
/* Inject restorer trampoline address (gcspr_el0 - 16) */
restorer_addr = ctl->parasite_ip;
if (ptrace(PTRACE_POKEDATA, pid, (void *)sigtramp_addr, restorer_addr)) {
pr_perror("gcs: (setup) Inject GCS restorer failed");
return -1;
}
/* Update GCSPR_EL0 */
gcs->gcspr_el0 = token_addr;
if (ptrace(PTRACE_SETREGSET, pid, NT_ARM_GCS, &gcs_iov)) {
pr_perror("gcs: PTRACE_SETREGS FAILED");
return -1;
}
pr_debug("gcs: parasite_ip=%#lx sp=%#llx gcspr_el0=%#llx\n",
ctl->parasite_ip, ctl->orig.regs.sp, gcs->gcspr_el0);
return 0;
}
int parasite_setup_shstk(struct parasite_ctl *ctl, user_fpregs_struct_t *ext_regs)
{
struct cr_user_gcs gcs;
struct iovec gcs_iov = { .iov_base = &gcs, .iov_len = sizeof(gcs) };
pid_t pid = ctl->rpid;
if(!__compel_host_supports_gcs())
return 0;
if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_GCS, &gcs_iov) != 0) {
pr_perror("GCS state not available for %d", pid);
return -1;
}
if (!__compel_gcs_enabled(&gcs))
return 0;
if (inject_gcs_cap_token(ctl, pid, &gcs)) {
pr_perror("Failed to inject GCS cap token for %d", pid);
return -1;
}
pr_info("gcs: GCS enabled for %d\n", pid);
return 0;
}

View file

@ -85,7 +85,7 @@ timer_settime 110 258 (kernel_timer_t timer_id, int flags, const struct itimer
timer_gettime 108 259 (int timer_id, const struct itimerspec *setting)
timer_getoverrun 109 260 (int timer_id)
timer_delete 111 261 (kernel_timer_t timer_id)
clock_gettime 113 263 (clockid_t which_clock, struct timespec *tp)
clock_gettime 113 263 (const clockid_t which_clock, const struct timespec *tp)
exit_group 94 248 (int error_code)
set_robust_list 99 338 (struct robust_list_head *head, size_t len)
get_robust_list 100 339 (int pid, struct robust_list_head **head_ptr, size_t *len_ptr)
@ -124,4 +124,3 @@ openat2 437 437 (int dirfd, char *pathname, struct open_how *how, size_t size
pidfd_getfd 438 438 (int pidfd, int targetfd, unsigned int flags)
rseq 293 398 (void *rseq, uint32_t rseq_len, int flags, uint32_t sig)
membarrier 283 389 (int cmd, unsigned int flags, int cpu_id)
map_shadow_stack 453 ! (unsigned long addr, unsigned long size, unsigned int flags)

View file

@ -94,7 +94,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
}
}
ret = save(pid, arg, regs, vfp);
ret = save(arg, regs, vfp);
err:
return ret;
}

View file

@ -46,7 +46,7 @@ __NR_sys_timer_gettime 108 sys_timer_gettime (int timer_id, const struct itimer
__NR_sys_timer_getoverrun 109 sys_timer_getoverrun (int timer_id)
__NR_sys_timer_settime 110 sys_timer_settime (kernel_timer_t timer_id, int flags, const struct itimerspec *new_setting, struct itimerspec *old_setting)
__NR_sys_timer_delete 111 sys_timer_delete (kernel_timer_t timer_id)
__NR_clock_gettime 113 sys_clock_gettime (clockid_t which_clock, struct timespec *tp)
__NR_clock_gettime 113 sys_clock_gettime (const clockid_t which_clock, const struct timespec *tp)
__NR_sched_setscheduler 119 sys_sched_setscheduler (int pid, int policy, struct sched_param *p)
__NR_restart_syscall 128 sys_restart_syscall (void)
__NR_kill 129 sys_kill (long pid, int sig)

View file

@ -91,7 +91,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
goto err;
}
ret = save(pid, arg, regs, fpregs);
ret = save(arg, regs, fpregs);
err:
return 0;
}

View file

@ -84,7 +84,7 @@ __NR_sys_timer_settime 5217 sys_timer_settime (kernel_timer_t timer_id, int fl
__NR_sys_timer_gettime 5218 sys_timer_gettime (int timer_id, const struct itimerspec *setting)
__NR_sys_timer_getoverrun 5219 sys_timer_getoverrun (int timer_id)
__NR_sys_timer_delete 5220 sys_timer_delete (kernel_timer_t timer_id)
__NR_clock_gettime 5222 sys_clock_gettime (clockid_t which_clock, struct timespec *tp)
__NR_clock_gettime 5222 sys_clock_gettime (const clockid_t which_clock, const struct timespec *tp)
__NR_exit_group 5205 sys_exit_group (int error_code)
__NR_set_thread_area 5242 sys_set_thread_area (unsigned long *addr)
__NR_openat 5247 sys_openat (int dfd, const char *filename, int flags, int mode)

View file

@ -5,31 +5,18 @@
#include "piegen.h"
#include "log.h"
static const unsigned char __maybe_unused elf_ident_64_le[EI_NIDENT] = {
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, /* clang-format */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
extern int __handle_elf(void *mem, size_t size);
int handle_binary(void *mem, size_t size)
{
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)mem;
if (memcmp(mem, elf_ident_64_le, sizeof(elf_ident_64_le)) == 0)
return __handle_elf(mem, size);
/* check ELF magic */
if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
ehdr->e_ident[EI_MAG3] != ELFMAG3) {
pr_err("Invalid ELF magic\n");
return -EINVAL;
}
/* check ELF class and data encoding */
if (ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
pr_err("Unsupported ELF class or data encoding\n");
return -EINVAL;
}
if (ehdr->e_ident[EI_ABIVERSION] != 0) {
pr_warn("Unusual ABI version: %d\n", ehdr->e_ident[EI_ABIVERSION]);
}
return __handle_elf(mem, size);
pr_err("Unsupported Elf format detected\n");
return -EINVAL;
}

View file

@ -149,7 +149,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
regs->regs[0] = 0;
}
ret = save(pid, arg, regs, xs);
ret = save(arg, regs, xs);
return ret;
}

View file

@ -82,7 +82,7 @@ __NR_sys_timer_settime 241 sys_timer_settime (kernel_timer_t timer_id, int flag
__NR_sys_timer_gettime 242 sys_timer_gettime (int timer_id, const struct itimerspec *setting)
__NR_sys_timer_getoverrun 243 sys_timer_getoverrun (int timer_id)
__NR_sys_timer_delete 244 sys_timer_delete (kernel_timer_t timer_id)
__NR_clock_gettime 246 sys_clock_gettime (clockid_t which_clock, struct timespec *tp)
__NR_clock_gettime 246 sys_clock_gettime (const clockid_t which_clock, const struct timespec *tp)
__NR_exit_group 234 sys_exit_group (int error_code)
__NR_waitid 272 sys_waitid (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru)
__NR_set_robust_list 300 sys_set_robust_list (struct robust_list_head *head, size_t len)

View file

@ -400,7 +400,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
if (ret)
return ret;
return save(pid, arg, regs, fpregs);
return save(arg, regs, fpregs);
}
int compel_set_task_ext_regs(pid_t pid, user_fpregs_struct_t *ext_regs)

View file

@ -1,35 +0,0 @@
#ifndef __ASM_PROLOGUE_H__
#define __ASM_PROLOGUE_H__
#ifndef __ASSEMBLY__
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#define sys_recv(sockfd, ubuf, size, flags) sys_recvfrom(sockfd, ubuf, size, flags, NULL, NULL)
typedef struct prologue_init_args {
struct sockaddr_un ctl_sock_addr;
unsigned int ctl_sock_addr_len;
unsigned int arg_s;
void *arg_p;
void *sigframe;
} prologue_init_args_t;
#endif /* __ASSEMBLY__ */
/*
* Reserve enough space for sigframe.
*
* FIXME It is rather should be taken from sigframe header.
*/
#define PROLOGUE_SGFRAME_SIZE 4096
#define PROLOGUE_INIT_ARGS_SIZE 1024
#endif /* __ASM_PROLOGUE_H__ */

View file

@ -1,28 +0,0 @@
#ifndef COMPEL_ARCH_SYSCALL_TYPES_H__
#define COMPEL_ARCH_SYSCALL_TYPES_H__
#define SA_RESTORER 0x04000000
typedef void rt_signalfn_t(int, siginfo_t *, void *);
typedef rt_signalfn_t *rt_sighandler_t;
typedef void rt_restorefn_t(void);
typedef rt_restorefn_t *rt_sigrestore_t;
#define _KNSIG 64 // number of signals
#define _NSIG_BPW 64 // number of signals per word
#define _KNSIG_WORDS (_KNSIG / _NSIG_BPW)
typedef struct {
unsigned long sig[_KNSIG_WORDS];
} k_rtsigset_t;
typedef struct {
rt_sighandler_t rt_sa_handler;
unsigned long rt_sa_flags;
rt_sigrestore_t rt_sa_restorer;
k_rtsigset_t rt_sa_mask;
} rt_sigaction_t;
#endif /* COMPEL_ARCH_SYSCALL_TYPES_H__ */

View file

@ -1,4 +0,0 @@
#ifndef __COMPEL_ARCH_FEATURES_H
#define __COMPEL_ARCH_FEATURES_H
#endif /* __COMPEL_ARCH_FEATURES_H */

View file

@ -1,7 +0,0 @@
#include "common/asm/linkage.h"
.section .head.text, "ax"
ENTRY(__export_parasite_head_start)
jal parasite_service
ebreak
END(__export_parasite_head_start)

View file

@ -1,59 +0,0 @@
ccflags-y += -iquote $(PLUGIN_ARCH_DIR)/std/syscalls/
asflags-y += -iquote $(PLUGIN_ARCH_DIR)/std/syscalls/
sys-types := $(obj)/include/uapi/std/syscall-types.h
sys-codes := $(obj)/include/uapi/std/syscall-codes.h
sys-proto := $(obj)/include/uapi/std/syscall.h
sys-def := $(PLUGIN_ARCH_DIR)/std/syscalls/syscall.def
sys-asm-common-name := std/syscalls/syscall-common.S
sys-asm-common := $(PLUGIN_ARCH_DIR)/$(sys-asm-common-name)
sys-asm-types := $(obj)/include/uapi/std/asm/syscall-types.h
sys-exec-tbl = $(PLUGIN_ARCH_DIR)/std/sys-exec-tbl.c
sys-gen := $(PLUGIN_ARCH_DIR)/std/syscalls/gen-syscalls.pl
sys-gen-tbl := $(PLUGIN_ARCH_DIR)/std/syscalls/gen-sys-exec-tbl.pl
sys-asm := ./$(PLUGIN_ARCH_DIR)/std/syscalls/syscalls.S
std-lib-y += $(sys-asm:.S=).o
ifeq ($(ARCH),arm)
arch_bits := 32
else
arch_bits := 64
endif
sys-exec-tbl := sys-exec-tbl.c
$(sys-asm) $(sys-types) $(sys-codes) $(sys-proto): $(sys-gen) $(sys-def) $(sys-asm-common) $(sys-asm-types)
$(E) " GEN " $@
$(Q) perl \
$(sys-gen) \
$(sys-def) \
$(sys-codes) \
$(sys-proto) \
$(sys-asm) \
$(sys-asm-common-name) \
$(sys-types) \
$(arch_bits)
$(sys-asm:.S=).o: $(sys-asm)
$(sys-exec-tbl): $(sys-gen-tbl) $(sys-def)
$(E) " GEN " $@
$(Q) perl \
$(sys-gen-tbl) \
$(sys-def) \
$(sys-exec-tbl) \
$(arch_bits)
$(sys-asm-types): $(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h
$(call msg-gen, $@)
$(Q) ln -s ../../../../../../$(PLUGIN_ARCH_DIR)/include/asm/syscall-types.h $(sys-asm-types)
$(Q) ln -s ../../../../../$(PLUGIN_ARCH_DIR)/std/syscalls/syscall-aux.S $(obj)/include/uapi/std/syscall-aux.S
$(Q) ln -s ../../../../../$(PLUGIN_ARCH_DIR)/std/syscalls/syscall-aux.h $(obj)/include/uapi/std/syscall-aux.h
std-headers-deps += $(sys-asm) $(sys-codes) $(sys-proto) $(sys-asm-types) $(sys-codes)
mrproper-y += $(std-headers-deps)
mrproper-y += $(obj)/include/uapi/std/syscall-aux.S
mrproper-y += $(obj)/include/uapi/std/syscall-aux.h

View file

@ -1,43 +0,0 @@
#!/usr/bin/perl
use strict;
use warnings;
my $in = $ARGV[0];
my $tblout = $ARGV[1];
my $bits = $ARGV[2];
my $code = "code$bits";
open TBLOUT, ">", $tblout or die $!;
open IN, "<", $in or die $!;
print TBLOUT "/* Autogenerated, don't edit */\n";
print TBLOUT "static struct syscall_exec_desc sc_exec_table[] = {\n";
for (<IN>) {
if ($_ =~ /\#/) {
next;
}
my $sys_name;
my $sys_num;
if (/(?<name>\S+)\s+(?<alias>\S+)\s+(?<code64>\d+|\!)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
$sys_name = $+{alias};
} elsif (/(?<name>\S+)\s+(?<code64>\d+|\!)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
$sys_name = $+{name};
} else {
unlink $tblout;
die "Invalid syscall definition file: invalid entry $_\n";
}
$sys_num = $+{$code};
if ($sys_num ne "!") {
print TBLOUT "SYSCALL($sys_name, $sys_num)\n";
}
}
print TBLOUT " { }, /* terminator */";
print TBLOUT "};"

View file

@ -1,99 +0,0 @@
#!/usr/bin/perl
use strict;
use warnings;
my $in = $ARGV[0];
my $codesout = $ARGV[1];
my $codes = $ARGV[1];
$codes =~ s/.*include\/uapi\//compel\/plugins\//g;
my $protosout = $ARGV[2];
my $protos = $ARGV[2];
$protos =~ s/.*include\/uapi\//compel\/plugins\//g;
my $asmout = $ARGV[3];
my $asmcommon = $ARGV[4];
my $prototypes = $ARGV[5];
$prototypes =~ s/.*include\/uapi\//compel\/plugins\//g;
my $bits = $ARGV[6];
my $codesdef = $codes;
$codesdef =~ tr/.\-\//_/;
my $protosdef = $protos;
$protosdef =~ tr/.\-\//_/;
my $code = "code$bits";
my $need_aux = 0;
unlink $codesout;
unlink $protosout;
unlink $asmout;
open CODESOUT, ">", $codesout or die $!;
open PROTOSOUT, ">", $protosout or die $!;
open ASMOUT, ">", $asmout or die $!;
open IN, "<", $in or die $!;
print CODESOUT <<"END";
/* Autogenerated, don't edit */
#ifndef $codesdef
#define $codesdef
END
print PROTOSOUT <<"END";
/* Autogenerated, don't edit */
#ifndef $protosdef
#define $protosdef
#include <$prototypes>
#include <$codes>
END
print ASMOUT <<"END";
/* Autogenerated, don't edit */
#include <$codes>
#include "$asmcommon"
END
for (<IN>) {
if ($_ =~ /\#/) {
next;
}
my $code_macro;
my $sys_macro;
my $sys_name;
if (/(?<name>\S+)\s+(?<alias>\S+)\s+(?<code64>\d+|\!)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
$code_macro = "__NR_$+{name}";
$sys_macro = "SYS_$+{name}";
$sys_name = "sys_$+{alias}";
} elsif (/(?<name>\S+)\s+(?<code64>\d+|\!)\s+(?<code32>(?:\d+|\!))\s+\((?<args>.+)\)/) {
$code_macro = "__NR_$+{name}";
$sys_macro = "SYS_$+{name}";
$sys_name = "sys_$+{name}";
} else {
unlink $codesout;
unlink $protosout;
unlink $asmout;
die "Invalid syscall definition file: invalid entry $_\n";
}
if ($+{$code} ne "!") {
print CODESOUT "#ifndef $code_macro\n#define $code_macro $+{$code}\n#endif\n";
print CODESOUT "#ifndef $sys_macro\n#define $sys_macro $code_macro\n#endif\n";
print ASMOUT "syscall $sys_name, $code_macro\n";
} else {
$need_aux = 1;
}
print PROTOSOUT "extern long $sys_name($+{args});\n";
}
if ($need_aux == 1) {
print ASMOUT "#include <compel/plugins/std/syscall-aux.S>\n";
print CODESOUT "#include <compel/plugins/std/syscall-aux.h>\n";
}
print CODESOUT "#endif /* $codesdef */";
print PROTOSOUT "#endif /* $protosdef */";

View file

@ -1,37 +0,0 @@
/**
* This source contains emulation of syscalls
* that are not implemented in the riscv64 Linux kernel
*/
ENTRY(sys_open)
add a3, x0, a2
add a2, x0, a1
add a1, x0, a0
addi a0, x0, -100
j sys_openat
END(sys_open)
ENTRY(sys_mkdir)
add a3,x0, a2
add a2, x0, a1
add a1, x0, a0
addi a0, x0, -100
j sys_mkdirat
END(sys_mkdir)
ENTRY(sys_rmdir)
addi a2, x0, 0x200 // flags = AT_REMOVEDIR
add a1, x0, a0
addi a0, x0, -100
j sys_unlinkat
END(sys_rmdir)
ENTRY(sys_unlink)
addi a2, x0, 0 // flags = 0
add a1, x0, a0
addi a0, x0, -100
j sys_unlinkat
END(sys_unlink)

View file

@ -1,3 +0,0 @@
#ifndef __NR_openat
#define __NR_openat 56
#endif

View file

@ -1,17 +0,0 @@
#include "common/asm/linkage.h"
syscall_common:
ecall
ret
.macro syscall name, nr
ENTRY(\name)
li a7, \nr
j syscall_common
END(\name)
.endm
ENTRY(__cr_restore_rt)
li a7, __NR_rt_sigreturn
ecall
END(__cr_restore_rt)

View file

@ -1,125 +0,0 @@
#
# System calls table, please make sure the table consists of only the syscalls
# really used somewhere in the project.
#
# The template is (name and arguments are optional if you need only __NR_x
# defined, but no real entry point in syscalls lib).
#
# name/alias code64 code32 arguments
# -----------------------------------------------------------------------
#
read 63 3 (int fd, void *buf, unsigned long count)
write 64 4 (int fd, const void *buf, unsigned long count)
open ! 5 (const char *filename, unsigned long flags, unsigned long mode)
close 57 6 (int fd)
lseek 62 19 (int fd, unsigned long offset, unsigned long origin)
mmap 222 ! (void *addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long offset)
mprotect 226 125 (const void *addr, unsigned long len, unsigned long prot)
munmap 215 91 (void *addr, unsigned long len)
brk 214 45 (void *addr)
rt_sigaction sigaction 134 174 (int signum, const rt_sigaction_t *act, rt_sigaction_t *oldact, size_t sigsetsize)
rt_sigprocmask sigprocmask 135 175 (int how, k_rtsigset_t *set, k_rtsigset_t *old, size_t sigsetsize)
rt_sigreturn 139 173 (void)
ioctl 29 54 (unsigned int fd, unsigned int cmd, unsigned long arg)
pread64 67 180 (unsigned int fd, char *buf, size_t count, loff_t pos)
ptrace 117 26 (long request, pid_t pid, void *addr, void *data)
mremap 216 163 (unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flag, unsigned long new_addr)
mincore 232 219 (void *addr, unsigned long size, unsigned char *vec)
madvise 233 220 (unsigned long start, size_t len, int behavior)
shmat 196 305 (int shmid, void *shmaddr, int shmflag)
pause 1061 29 (void)
nanosleep 101 162 (struct timespec *req, struct timespec *rem)
getitimer 102 105 (int which, const struct itimerval *val)
setitimer 103 104 (int which, const struct itimerval *val, struct itimerval *old)
getpid 172 20 (void)
socket 198 281 (int domain, int type, int protocol)
connect 203 283 (int sockfd, struct sockaddr *addr, int addrlen)
sendto 206 290 (int sockfd, void *buff, size_t len, unsigned int flags, struct sockaddr *addr, int addr_len)
recvfrom 207 292 (int sockfd, void *ubuf, size_t size, unsigned int flags, struct sockaddr *addr, int *addr_len)
sendmsg 211 296 (int sockfd, const struct msghdr *msg, int flags)
recvmsg 212 297 (int sockfd, struct msghdr *msg, int flags)
shutdown 210 293 (int sockfd, int how)
bind 235 282 (int sockfd, const struct sockaddr *addr, int addrlen)
setsockopt 208 294 (int sockfd, int level, int optname, const void *optval, socklen_t optlen)
getsockopt 209 295 (int sockfd, int level, int optname, const void *optval, socklen_t *optlen)
clone 220 120 (unsigned long flags, void *child_stack, void *parent_tid, unsigned long newtls, void *child_tid)
exit 93 1 (unsigned long error_code)
wait4 260 114 (int pid, int *status, int options, struct rusage *ru)
waitid 95 280 (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru)
kill 129 37 (long pid, int sig)
fcntl 25 55 (int fd, int type, long arg)
flock 32 143 (int fd, unsigned long cmd)
mkdir ! 39 (const char *name, int mode)
rmdir ! 40 (const char *name)
unlink ! 10 (char *pathname)
readlinkat 78 332 (int fd, const char *path, char *buf, int bufsize)
umask 166 60 (int mask)
getgroups 158 205 (int gsize, unsigned int *groups)
setgroups 159 206 (int gsize, unsigned int *groups)
setresuid 147 164 (int uid, int euid, int suid)
getresuid 148 165 (int *uid, int *euid, int *suid)
setresgid 149 170 (int gid, int egid, int sgid)
getresgid 150 171 (int *gid, int *egid, int *sgid)
getpgid 155 132 (pid_t pid)
setfsuid 151 138 (int fsuid)
setfsgid 152 139 (int fsgid)
getsid 156 147 (void)
capget 90 184 (struct cap_header *h, struct cap_data *d)
capset 91 185 (struct cap_header *h, struct cap_data *d)
rt_sigqueueinfo 138 178 (pid_t pid, int sig, siginfo_t *info)
setpriority 140 97 (int which, int who, int nice)
sched_setscheduler 119 156 (int pid, int policy, struct sched_param *p)
sigaltstack 132 186 (const void *uss, void *uoss)
personality 92 136 (unsigned int personality)
prctl 167 172 (int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
arch_prctl ! 17 (int option, unsigned long addr)
setrlimit 164 75 (int resource, struct krlimit *rlim)
mount 40 21 (char *dev_nmae, char *dir_name, char *type, unsigned long flags, void *data)
umount2 39 52 (char *name, int flags)
gettid 178 224 (void)
futex 98 240 (uint32_t *uaddr, int op, uint32_t val, struct timespec *utime, uint32_t *uaddr2, uint32_t val3)
set_tid_address 96 256 (int *tid_addr)
restart_syscall 128 0 (void)
timer_create 107 257 (clockid_t which_clock, struct sigevent *timer_event_spec, kernel_timer_t *created_timer_id)
timer_settime 110 258 (kernel_timer_t timer_id, int flags, const struct itimerspec *new_setting, struct itimerspec *old_setting)
timer_gettime 108 259 (int timer_id, const struct itimerspec *setting)
timer_getoverrun 109 260 (int timer_id)
timer_delete 111 261 (kernel_timer_t timer_id)
clock_gettime 113 263 (clockid_t which_clock, struct timespec *tp)
exit_group 94 248 (int error_code)
set_robust_list 99 338 (struct robust_list_head *head, size_t len)
get_robust_list 100 339 (int pid, struct robust_list_head **head_ptr, size_t *len_ptr)
signalfd4 74 355 (int fd, k_rtsigset_t *mask, size_t sizemask, int flags)
rt_tgsigqueueinfo 240 363 (pid_t tgid, pid_t pid, int sig, siginfo_t *info)
vmsplice 75 343 (int fd, const struct iovec *iov, unsigned long nr_segs, unsigned int flags)
timerfd_settime 86 353 (int ufd, int flags, const struct itimerspec *utmr, struct itimerspec *otmr)
fanotify_init 262 367 (unsigned int flags, unsigned int event_f_flags)
fanotify_mark 263 368 (int fanotify_fd, unsigned int flags, uint64_t mask, int dfd, const char *pathname)
open_by_handle_at 265 371 (int mountdirfd, struct file_handle *handle, int flags)
setns 268 375 (int fd, int nstype)
kcmp 272 378 (pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2)
openat 56 322 (int dirfd, const char *pathname, int flags, mode_t mode)
mkdirat 34 323 (int dirfd, const char *pathname, mode_t mode)
unlinkat 35 328 (int dirfd, const char *pathname, int flags)
memfd_create 279 385 (const char *name, unsigned int flags)
io_setup 0 243 (unsigned nr_events, aio_context_t *ctx)
io_submit 2 246 (aio_context_t ctx_id, long nr, struct iocb **iocbpp)
io_getevents 4 245 (aio_context_t ctx, long min_nr, long nr, struct io_event *evs, struct timespec *tmo)
seccomp 277 383 (unsigned int op, unsigned int flags, const char *uargs)
gettimeofday 169 78 (struct timeval *tv, struct timezone *tz)
preadv_raw 69 361 (int fd, struct iovec *iov, unsigned long nr, unsigned long pos_l, unsigned long pos_h)
userfaultfd 282 388 (int flags)
fallocate 47 352 (int fd, int mode, loff_t offset, loff_t len)
cacheflush ! 983042 (void *start, void *end, int flags)
ppoll 73 336 (struct pollfd *fds, unsigned int nfds, const struct timespec *tmo, const sigset_t *sigmask, size_t sigsetsize)
fsopen 430 430 (char *fsname, unsigned int flags)
fsconfig 431 431 (int fd, unsigned int cmd, const char *key, const char *value, int aux)
fsmount 432 432 (int fd, unsigned int flags, unsigned int attr_flags)
clone3 435 435 (struct clone_args *uargs, size_t size)
pidfd_open 434 434 (pid_t pid, unsigned int flags)
pidfd_getfd 438 438 (int pidfd, int targetfd, unsigned int flags)
rseq 293 293 (void *rseq, uint32_t rseq_len, int flags, uint32_t sig)
move_mount 429 429 (int from_dfd, const char *from_pathname, int to_dfd, const char *to_pathname, int flags)
open_tree 428 428 (int dirfd, const char *pathname, unsigned int flags)
openat2 437 437 (int dirfd, char *pathname, struct open_how *how, size_t size)
membarrier 283 283 (int cmd, unsigned int flags, int cpu_id)

View file

@ -1,32 +0,0 @@
OUTPUT_ARCH(riscv)
EXTERN(__export_parasite_head_start)
SECTIONS
{
.crblob 0x0 : {
*(.head.text)
ASSERT(DEFINED(__export_parasite_head_start),
"Symbol __export_parasite_head_start is missing");
*(.text*)
. = ALIGN(32);
*(.data*)
. = ALIGN(32);
*(.rodata*)
. = ALIGN(32);
*(.bss*)
. = ALIGN(32);
*(.got*)
. = ALIGN(32);
*(.toc*)
. = ALIGN(32);
} =0x00000000,
/DISCARD/ : {
*(.debug*)
*(.comment*)
*(.note*)
*(.group*)
*(.eh_frame*)
*(*)
}
}

View file

@ -1,78 +0,0 @@
#include <string.h>
#include <stdbool.h>
#include "compel-cpu.h"
#include "common/bitops.h"
#include "log.h"
#undef LOG_PREFIX
#define LOG_PREFIX "cpu: "
static compel_cpuinfo_t rt_info;
static void fetch_rt_cpuinfo(void)
{
static bool rt_info_done = false;
if (!rt_info_done) {
compel_cpuid(&rt_info);
rt_info_done = true;
}
}
void compel_set_cpu_cap(compel_cpuinfo_t *info, unsigned int feature)
{
}
void compel_clear_cpu_cap(compel_cpuinfo_t *info, unsigned int feature)
{
}
int compel_test_cpu_cap(compel_cpuinfo_t *info, unsigned int feature)
{
return 0;
}
int compel_test_fpu_cap(compel_cpuinfo_t *info, unsigned int feature)
{
return 0;
}
int compel_cpuid(compel_cpuinfo_t *info)
{
return 0;
}
bool compel_cpu_has_feature(unsigned int feature)
{
fetch_rt_cpuinfo();
return compel_test_cpu_cap(&rt_info, feature);
}
bool compel_fpu_has_feature(unsigned int feature)
{
fetch_rt_cpuinfo();
return compel_test_fpu_cap(&rt_info, feature);
}
uint32_t compel_fpu_feature_size(unsigned int feature)
{
fetch_rt_cpuinfo();
return 0;
}
uint32_t compel_fpu_feature_offset(unsigned int feature)
{
fetch_rt_cpuinfo();
return 0;
}
void compel_cpu_clear_feature(unsigned int feature)
{
fetch_rt_cpuinfo();
return compel_clear_cpu_cap(&rt_info, feature);
}
void compel_cpu_copy_cpuinfo(compel_cpuinfo_t *c)
{
fetch_rt_cpuinfo();
memcpy(c, &rt_info, sizeof(rt_info));
}

View file

@ -1 +0,0 @@
handle-elf.c

View file

@ -1,32 +0,0 @@
#include <string.h>
#include <errno.h>
#include "handle-elf.h"
#include "piegen.h"
#include "log.h"
static const unsigned char __maybe_unused elf_ident_64_le[EI_NIDENT] = {
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, /* clang-format */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char __maybe_unused elf_ident_64_be[EI_NIDENT] = {
0x7f, 0x45, 0x4c, 0x46, 0x02, 0x02, 0x01, 0x00, /* clang-format */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
int handle_binary(void *mem, size_t size)
{
const unsigned char *elf_ident =
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
elf_ident_64_le;
#else
elf_ident_64_be;
#endif
if (memcmp(mem, elf_ident, sizeof(elf_ident_64_le)) == 0)
return handle_elf_riscv64(mem, size);
pr_err("Unsupported Elf format detected\n");
return -EINVAL;
}

View file

@ -1,12 +0,0 @@
#ifndef COMPEL_HANDLE_ELF_H__
#define COMPEL_HANDLE_ELF_H__
#include "elf64-types.h"
#define __handle_elf handle_elf_riscv64
#define ELF_RISCV
#define arch_is_machine_supported(e_machine) (e_machine == EM_RISCV)
extern int handle_elf_riscv64(void *mem, size_t size);
#endif /* COMPEL_HANDLE_ELF_H__ */

View file

@ -1,8 +0,0 @@
#ifndef __COMPEL_SYSCALL_H__
#define __COMPEL_SYSCALL_H__
#define __NR(syscall, compat) \
({ \
(void)compat; \
__NR_##syscall; \
})
#endif

View file

@ -1,15 +0,0 @@
#ifndef __COMPEL_BREAKPOINTS_H__
#define __COMPEL_BREAKPOINTS_H__
#define ARCH_SI_TRAP TRAP_BRKPT
static inline int ptrace_set_breakpoint(pid_t pid, void *addr)
{
return 0;
}
static inline int ptrace_flush_breakpoints(pid_t pid)
{
return 0;
}
#endif

View file

@ -1,7 +0,0 @@
#ifndef UAPI_COMPEL_ASM_CPU_H__
#define UAPI_COMPEL_ASM_CPU_H__
typedef struct {
} compel_cpuinfo_t;
#endif /* UAPI_COMPEL_ASM_CPU_H__ */

View file

@ -1,4 +0,0 @@
#ifndef __CR_ASM_FPU_H__
#define __CR_ASM_FPU_H__
#endif /* __CR_ASM_FPU_H__ */

View file

@ -1,52 +0,0 @@
#ifndef UAPI_COMPEL_ASM_TYPES_H__
#define UAPI_COMPEL_ASM_TYPES_H__
#include <stdint.h>
#include <signal.h>
#include <sys/mman.h>
#include <asm/ptrace.h>
#define SIGMAX 64
#define SIGMAX_OLD 31
/*
* Copied from the Linux kernel header arch/riscv/include/uapi/asm/ptrace.h
*
* A thread RISC-V CPU context
*/
typedef struct user_regs_struct user_regs_struct_t;
typedef struct __riscv_d_ext_state user_fpregs_struct_t;
#define __compel_arch_fetch_thread_area(tid, th) 0
#define compel_arch_fetch_thread_area(tctl) 0
#define compel_arch_get_tls_task(ctl, tls)
#define compel_arch_get_tls_thread(tctl, tls)
#define REG_RES(registers) ((uint64_t)(registers).a0)
#define REG_IP(registers) ((uint64_t)(registers).pc)
#define SET_REG_IP(registers, val) ((registers).pc = (val))
/*
* REG_SP is also defined in riscv64-linux-gnu/include/sys/ucontext.h
* with a different meaning, and it's not used in CRIU. So we have to
* undefine it here.
*/
#ifdef REG_SP
#undef REG_SP
#endif
#define REG_SP(registers) ((uint64_t)((registers).sp))
#define REG_SYSCALL_NR(registers) ((uint64_t)(registers).a7)
#define user_regs_native(pregs) true
#define ARCH_SI_TRAP TRAP_BRKPT
#define __NR(syscall, compat) \
({ \
(void)compat; \
__NR_##syscall; \
})
#endif /* UAPI_COMPEL_ASM_TYPES_H__ */

View file

@ -1,26 +0,0 @@
#ifndef COMPEL_RELOCATIONS_H__
#define COMPEL_RELOCATIONS_H__
#include <stdint.h>
static inline uint32_t riscv_b_imm(uint32_t val)
{
return (val & 0x00001000) << 19 | (val & 0x000007e0) << 20 | (val & 0x0000001e) << 7 | (val & 0x00000800) >> 4;
}
static inline uint32_t riscv_i_imm(uint32_t val)
{
return val << 20;
}
static inline uint32_t riscv_u_imm(uint32_t val)
{
return val & 0xfffff000;
}
static inline uint32_t riscv_j_imm(uint32_t val)
{
return (val & 0x00100000) << 11 | (val & 0x000007fe) << 20 | (val & 0x00000800) << 9 | (val & 0x000ff000);
}
#endif /* COMPEL_RELOCATIONS_H__ */

View file

@ -1,4 +0,0 @@
#ifndef UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__
#define UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__
#endif /* UAPI_COMPEL_ASM_PROCESSOR_FLAGS_H__ */

View file

@ -1,68 +0,0 @@
#ifndef UAPI_COMPEL_ASM_SIGFRAME_H__
#define UAPI_COMPEL_ASM_SIGFRAME_H__
#include <sys/ucontext.h>
#include <stdint.h>
#include <signal.h>
/* Copied from the kernel header arch/riscv/include/uapi/asm/sigcontext.h */
/*
* Signal context structure
*
* This contains the context saved before a signal handler is invoked;
* it is restored by sys_sigreturn / sys_rt_sigreturn.
*/
// struct sigcontext {
// struct user_regs_struct sc_regs;
// union __riscv_fp_state sc_fpregs;
// /*
// * 4K + 128 reserved for vector state and future expansion.
// * This space is enough to store the vector context whose VLENB
// * is less or equal to 128.
// * (The size of the vector context is 4144 byte as VLENB is 128)
// */
// __u8 __reserved[4224] __attribute__((__aligned__(16)));
// };
#define rt_sigcontext sigcontext
#include <compel/sigframe-common.h>
/* Copied from the kernel source arch/riscv/kernel/signal.c */
struct rt_sigframe {
siginfo_t info;
ucontext_t uc; //ucontext_t structure holds the user context, e.g., the signal mask, GP regs
};
/*
generates inline assembly code for triggering the rt_sigreturn system call.
used to return from a signal handler back to the normal execution flow of the process.
*/
/* clang-format off */
#define ARCH_RT_SIGRETURN(new_sp, rt_sigframe) \
asm volatile( \
"mv sp, %0\n" \
"li a7, "__stringify(__NR_rt_sigreturn)" \n" \
"ecall\n" \
: \
: "r"(new_sp) \
: "a7", "memory")
/* clang-format on */
#define RT_SIGFRAME_UC(rt_sigframe) (&rt_sigframe->uc)
#define RT_SIGFRAME_REGIP(rt_sigframe) ((long unsigned int)(rt_sigframe)->uc.uc_mcontext.__gregs[REG_PC])
#define RT_SIGFRAME_HAS_FPU(rt_sigframe) 1
#define RT_SIGFRAME_OFFSET(rt_sigframe) 0
// #define RT_SIGFRAME_SIGCONTEXT(rt_sigframe) ((struct cr_sigcontext *)&(rt_sigframe)->uc.uc_mcontext)
// #define RT_SIGFRAME_AUX_CONTEXT(rt_sigframe) ((struct sigcontext *)&(RT_SIGFRAME_SIGCONTEXT(rt_sigframe)->__reserved))
// #define RT_SIGFRAME_FPU(rt_sigframe) (&RT_SIGFRAME_AUX_CONTEXT(rt_sigframe)->fpsimd)
#define rt_sigframe_erase_sigset(sigframe) \
memset(&sigframe->uc.uc_sigmask, 0, sizeof(k_rtsigset_t)) // erase the signal mask
#define rt_sigframe_copy_sigset(sigframe, from) \
memcpy(&sigframe->uc.uc_sigmask, from, sizeof(k_rtsigset_t)) // copy the signal mask
#endif /* UAPI_COMPEL_ASM_SIGFRAME_H__ */

View file

@ -1,224 +0,0 @@
#include <stdlib.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <linux/elf.h>
#include <compel/plugins/std/syscall-codes.h>
#include "common/page.h"
#include "uapi/compel/asm/infect-types.h"
#include "log.h"
#include "errno.h"
#include "infect.h"
#include "infect-priv.h"
unsigned __page_size = 0;
unsigned __page_shift = 0;
/*
* Injected syscall instruction
*/
const char code_syscall[] = {
0x73, 0x00, 0x00, 0x00, /* ecall */
0x73, 0x00, 0x10, 0x00 /* ebreak */
};
static const int code_syscall_aligned = round_up(sizeof(code_syscall), sizeof(long));
static inline void __always_unused __check_code_syscall(void)
{
BUILD_BUG_ON(code_syscall_aligned != BUILTIN_SYSCALL_SIZE);
BUILD_BUG_ON(!is_log2(sizeof(code_syscall)));
}
int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
sigframe->uc.uc_mcontext.__gregs[0] = regs->pc;
sigframe->uc.uc_mcontext.__gregs[1] = regs->ra;
sigframe->uc.uc_mcontext.__gregs[2] = regs->sp;
sigframe->uc.uc_mcontext.__gregs[3] = regs->gp;
sigframe->uc.uc_mcontext.__gregs[4] = regs->tp;
sigframe->uc.uc_mcontext.__gregs[5] = regs->t0;
sigframe->uc.uc_mcontext.__gregs[6] = regs->t1;
sigframe->uc.uc_mcontext.__gregs[7] = regs->t2;
sigframe->uc.uc_mcontext.__gregs[8] = regs->s0;
sigframe->uc.uc_mcontext.__gregs[9] = regs->s1;
sigframe->uc.uc_mcontext.__gregs[10] = regs->a0;
sigframe->uc.uc_mcontext.__gregs[11] = regs->a1;
sigframe->uc.uc_mcontext.__gregs[12] = regs->a2;
sigframe->uc.uc_mcontext.__gregs[13] = regs->a3;
sigframe->uc.uc_mcontext.__gregs[14] = regs->a4;
sigframe->uc.uc_mcontext.__gregs[15] = regs->a5;
sigframe->uc.uc_mcontext.__gregs[16] = regs->a6;
sigframe->uc.uc_mcontext.__gregs[17] = regs->a7;
sigframe->uc.uc_mcontext.__gregs[18] = regs->s2;
sigframe->uc.uc_mcontext.__gregs[19] = regs->s3;
sigframe->uc.uc_mcontext.__gregs[20] = regs->s4;
sigframe->uc.uc_mcontext.__gregs[21] = regs->s5;
sigframe->uc.uc_mcontext.__gregs[22] = regs->s6;
sigframe->uc.uc_mcontext.__gregs[23] = regs->s7;
sigframe->uc.uc_mcontext.__gregs[24] = regs->s8;
sigframe->uc.uc_mcontext.__gregs[25] = regs->s9;
sigframe->uc.uc_mcontext.__gregs[26] = regs->s10;
sigframe->uc.uc_mcontext.__gregs[27] = regs->s11;
sigframe->uc.uc_mcontext.__gregs[28] = regs->t3;
sigframe->uc.uc_mcontext.__gregs[29] = regs->t4;
sigframe->uc.uc_mcontext.__gregs[30] = regs->t5;
sigframe->uc.uc_mcontext.__gregs[31] = regs->t6;
memcpy(sigframe->uc.uc_mcontext.__fpregs.__d.__f, fpregs->f, sizeof(fpregs->f));
sigframe->uc.uc_mcontext.__fpregs.__d.__fcsr = fpregs->fcsr;
return 0;
}
int sigreturn_prep_fpu_frame_plain(struct rt_sigframe *sigframe, struct rt_sigframe *rsigframe)
{
return 0;
}
int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct_t *ext_regs, save_regs_t save,
void *arg, __maybe_unused unsigned long flags)
{
user_fpregs_struct_t tmp, *fpsimd = ext_regs ? ext_regs : &tmp;
struct iovec iov;
int ret = -1;
pr_info("Dumping FPU registers for %d\n", pid);
iov.iov_base = fpsimd;
iov.iov_len = sizeof(*fpsimd);
if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov))) {
pr_perror("Failed to obtain FPU registers for %d", pid);
return -1;
}
ret = save(pid, arg, regs, fpsimd);
return ret;
}
int compel_set_task_ext_regs(pid_t pid, user_fpregs_struct_t *ext_regs)
{
struct iovec iov;
pr_info("Restoring GP/FPU registers for %d\n", pid);
iov.iov_base = ext_regs;
iov.iov_len = sizeof(*ext_regs);
if (ptrace(PTRACE_SETREGSET, pid, NT_PRFPREG, &iov)) {
pr_perror("Failed to set FPU registers for %d", pid);
return -1;
}
return 0;
}
int compel_syscall(struct parasite_ctl *ctl, int nr, long *ret, unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6)
{
user_regs_struct_t regs = ctl->orig.regs;
int err;
regs.a7 = (unsigned long)nr;
regs.a0 = arg1;
regs.a1 = arg2;
regs.a2 = arg3;
regs.a3 = arg4;
regs.a4 = arg5;
regs.a5 = arg6;
regs.a6 = 0;
err = compel_execute_syscall(ctl, &regs, code_syscall);
*ret = regs.a0;
return err;
}
/*
* Calling the mmap system call in the context of the target (victim) process using the compel_syscall function.
* Used during the infection process to allocate memory for the parasite code.
*/
void *remote_mmap(struct parasite_ctl *ctl, void *addr, size_t length, int prot, int flags, int fd, off_t offset)
{
long map;
int err;
err = compel_syscall(ctl, __NR_mmap, &map, (unsigned long)addr, length, prot, flags, fd, offset);
if (err < 0 || (long)map < 0)
map = 0;
return (void *)map;
}
void parasite_setup_regs(unsigned long new_ip, void *stack, user_regs_struct_t *regs)
{
regs->pc = new_ip;
if (stack)
regs->sp = (unsigned long)stack;
}
bool arch_can_dump_task(struct parasite_ctl *ctl)
{
/*
* TODO: Add proper check here.
*/
return true;
}
/*
* Fetch the signal alternate stack (sigaltstack),
* sas is a separate memory area for the signal handler to run on,
* avoiding potential issues with the main process stack
*/
int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s)
{
long ret;
int err;
err = compel_syscall(ctl, __NR_sigaltstack, &ret, 0, (unsigned long)&s->uc.uc_stack, 0, 0, 0, 0);
return err ? err : ret;
}
/*
* Task size is the maximum virtual address space size that a process can occupy in the memory
* Refer to linux kernel arch/riscv/include/asm/pgtable.h,
* task size is:
* - 0x9fc00000 (~2.5GB) for RV32.
* - 0x4000000000 ( 256GB) for RV64 using SV39 mmu
* - 0x800000000000 ( 128TB) for RV64 using SV48 mmu
* - 0x100000000000000 ( 64PB) for RV64 using SV57 mmu
*/
#define TASK_SIZE_MIN (1UL << 38)
#define TASK_SIZE_MAX (1UL << 56)
unsigned long compel_task_size(void)
{
unsigned long task_size;
for (task_size = TASK_SIZE_MIN; task_size < TASK_SIZE_MAX; task_size <<= 1)
if (munmap((void *)task_size, page_size()))
break;
return task_size;
}
/*
* Get task registers (overwrites weak function)
*/
int ptrace_get_regs(int pid, user_regs_struct_t *regs)
{
struct iovec iov;
iov.iov_base = regs;
iov.iov_len = sizeof(user_regs_struct_t);
return ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov);
}
/*
* Set task registers (overwrites weak function)
*/
int ptrace_set_regs(int pid, user_regs_struct_t *regs)
{
struct iovec iov;
iov.iov_base = regs;
iov.iov_len = sizeof(user_regs_struct_t);
return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov);
}

View file

@ -82,7 +82,7 @@ __NR_sys_timer_settime 255 sys_timer_settime (kernel_timer_t timer_id, int flag
__NR_sys_timer_gettime 256 sys_timer_gettime (int timer_id, const struct itimerspec *setting)
__NR_sys_timer_getoverrun 257 sys_timer_getoverrun (int timer_id)
__NR_sys_timer_delete 258 sys_timer_delete (kernel_timer_t timer_id)
__NR_clock_gettime 260 sys_clock_gettime (clockid_t which_clock, struct timespec *tp)
__NR_clock_gettime 260 sys_clock_gettime (const clockid_t which_clock, const struct timespec *tp)
__NR_exit_group 248 sys_exit_group (int error_code)
__NR_waitid 281 sys_waitid (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru)
__NR_set_robust_list 304 sys_set_robust_list (struct robust_list_head *head, size_t len)

View file

@ -348,7 +348,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
}
}
/* Call save_task_regs() */
return save(pid, arg, regs, fpregs);
return save(arg, regs, fpregs);
}
int compel_set_task_ext_regs(pid_t pid, user_fpregs_struct_t *ext_regs)

View file

@ -85,7 +85,7 @@ __NR_sys_timer_settime 223 sys_timer_settime (kernel_timer_t timer_id, int fla
__NR_sys_timer_gettime 224 sys_timer_gettime (int timer_id, const struct itimerspec *setting)
__NR_sys_timer_getoverrun 225 sys_timer_getoverrun (int timer_id)
__NR_sys_timer_delete 226 sys_timer_delete (kernel_timer_t timer_id)
__NR_clock_gettime 228 sys_clock_gettime (clockid_t which_clock, struct timespec *tp)
__NR_clock_gettime 228 sys_clock_gettime (const clockid_t which_clock, const struct timespec *tp)
__NR_exit_group 231 sys_exit_group (int error_code)
__NR_openat 257 sys_openat (int dfd, const char *filename, int flags, int mode)
__NR_waitid 247 sys_waitid (int which, pid_t pid, struct siginfo *infop, int options, struct rusage *ru)

View file

@ -453,7 +453,7 @@ int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct
goto err;
out:
ret = save(pid, arg, regs, xs);
ret = save(arg, regs, xs);
err:
return ret;
}
@ -761,7 +761,7 @@ bool __compel_shstk_enabled(user_fpregs_struct_t *ext_regs)
return false;
}
int parasite_setup_shstk(struct parasite_ctl *ctl, __maybe_unused user_fpregs_struct_t *ext_regs)
int parasite_setup_shstk(struct parasite_ctl *ctl, user_fpregs_struct_t *ext_regs)
{
pid_t pid = ctl->rpid;
unsigned long sa_restorer = ctl->parasite_ip;

View file

@ -72,7 +72,6 @@ extern bool arch_can_dump_task(struct parasite_ctl *ctl);
extern int compel_get_task_regs(pid_t pid, user_regs_struct_t *regs, user_fpregs_struct_t *ext_regs, save_regs_t save,
void *arg, unsigned long flags);
extern int compel_set_task_ext_regs(pid_t pid, user_fpregs_struct_t *ext_regs);
extern int compel_set_task_gcs_regs(pid_t pid, user_fpregs_struct_t *ext_regs);
extern int arch_fetch_sas(struct parasite_ctl *ctl, struct rt_sigframe *s);
extern int sigreturn_prep_regs_plain(struct rt_sigframe *sigframe, user_regs_struct_t *regs,
user_fpregs_struct_t *fpregs);

View file

@ -3,20 +3,11 @@
#include "common/compiler.h"
/**
* The length of the hash is based on what libuuid provides.
* According to the manpage this is:
*
* The uuid_unparse() function converts the supplied UUID uu from the binary
* representation into a 36-byte string (plus trailing '\0')
*/
#define RUN_ID_HASH_LENGTH 37
/*
* compel_run_id is a unique value of the current run. It can be used to
* generate resource ID-s to avoid conflicts with other processes.
*/
extern char compel_run_id[RUN_ID_HASH_LENGTH];
extern uint64_t compel_run_id;
struct parasite_ctl;
extern int __must_check compel_util_send_fd(struct parasite_ctl *ctl, int fd);

View file

@ -13,15 +13,6 @@
#define PARASITE_START_AREA_MIN (4096)
#define PARASITE_STACK_SIZE (16 << 10)
/*
* A stack redzone is a small, protected region of memory located immediately
* after a parasite stack. It is intended to remain unchanged. While it can be
* implemented as a guard page, we want to avoid the overhead of additional
* remote system calls.
*/
#define PARASITE_STACK_REDZONE 128
extern int __must_check compel_interrupt_task(int pid);
struct seize_task_status {
@ -106,7 +97,7 @@ extern k_rtsigset_t *compel_thread_sigmask(struct parasite_thread_ctl *tctl);
struct rt_sigframe;
typedef int (*open_proc_fn)(int pid, int mode, const char *fmt, ...) __attribute__((__format__(__printf__, 3, 4)));
typedef int (*save_regs_t)(pid_t pid, void *, user_regs_struct_t *, user_fpregs_struct_t *);
typedef int (*save_regs_t)(void *, user_regs_struct_t *, user_fpregs_struct_t *);
typedef int (*make_sigframe_t)(void *, struct rt_sigframe *, struct rt_sigframe *, k_rtsigset_t *);
struct infect_ctx {
@ -192,14 +183,6 @@ void compel_set_thread_ip(struct parasite_thread_ctl *tctl, uint64_t v);
extern void compel_get_stack(struct parasite_ctl *ctl, void **rstack, void **r_thread_stack);
#ifndef compel_host_supports_gcs
static inline bool compel_host_supports_gcs(void)
{
return false;
}
#define compel_host_supports_gcs
#endif
#ifndef compel_shstk_enabled
static inline bool compel_shstk_enabled(user_fpregs_struct_t *ext_regs)
{

View file

@ -7,7 +7,7 @@
#include "infect-rpc.h"
#include "infect-util.h"
char compel_run_id[RUN_ID_HASH_LENGTH];
uint64_t compel_run_id;
int compel_util_send_fd(struct parasite_ctl *ctl, int fd)
{

View file

@ -38,6 +38,8 @@
#define UNIX_PATH_MAX (sizeof(struct sockaddr_un) - (size_t)((struct sockaddr_un *)0)->sun_path)
#endif
#define PARASITE_STACK_SIZE (16 << 10)
#ifndef SECCOMP_MODE_DISABLED
#define SECCOMP_MODE_DISABLED 0
#endif
@ -425,7 +427,7 @@ static int gen_parasite_saddr(struct sockaddr_un *saddr, int key)
int sun_len;
saddr->sun_family = AF_UNIX;
snprintf(saddr->sun_path, UNIX_PATH_MAX, "X/crtools-pr-%d-%s", key, compel_run_id);
snprintf(saddr->sun_path, UNIX_PATH_MAX, "X/crtools-pr-%d-%" PRIx64, key, compel_run_id);
sun_len = SUN_LEN(saddr);
*saddr->sun_path = '\0';
@ -1054,16 +1056,6 @@ int compel_infect_no_daemon(struct parasite_ctl *ctl, unsigned long nr_threads,
memcpy(ctl->local_map, ctl->pblob.hdr.mem, ctl->pblob.hdr.bsize);
compel_relocs_apply(ctl->local_map, ctl->remote_map, &ctl->pblob);
/*
* Ensure the infected thread sees the updated code.
*
* On architectures like ARM64, the Data Cache (D-cache) and
* Instruction Cache (I-cache) are not automatically coherent.
* Modifications land in the D-cache, so we must flush (clean) the
* D-cache to push changes to RAM to ensure the CPU fetches the updated
* instructions.
*/
__builtin___clear_cache(ctl->local_map, ctl->local_map + ctl->pblob.hdr.bsize);
p = parasite_size;
@ -1072,7 +1064,7 @@ int compel_infect_no_daemon(struct parasite_ctl *ctl, unsigned long nr_threads,
p += RESTORE_STACK_SIGFRAME;
p += PARASITE_STACK_SIZE;
ctl->rstack = ctl->remote_map + p - PARASITE_STACK_REDZONE;
ctl->rstack = ctl->remote_map + p;
/*
* x86-64 ABI requires a 16 bytes aligned stack.
@ -1086,7 +1078,7 @@ int compel_infect_no_daemon(struct parasite_ctl *ctl, unsigned long nr_threads,
if (nr_threads > 1) {
p += PARASITE_STACK_SIZE;
ctl->r_thread_stack = ctl->remote_map + p - PARASITE_STACK_REDZONE;
ctl->r_thread_stack = ctl->remote_map + p;
}
ret = arch_fetch_sas(ctl, ctl->rsigframe);
@ -1308,7 +1300,7 @@ struct plain_regs_struct {
user_fpregs_struct_t fpregs;
};
static int save_regs_plain(pid_t pid, void *to, user_regs_struct_t *r, user_fpregs_struct_t *f)
static int save_regs_plain(void *to, user_regs_struct_t *r, user_fpregs_struct_t *f)
{
struct plain_regs_struct *prs = to;

View file

@ -60,9 +60,6 @@ static const flags_t flags = {
#elif defined CONFIG_LOONGARCH64
.arch = "loongarch64",
.cflags = COMPEL_CFLAGS_PIE,
#elif defined CONFIG_RISCV64
.arch = "riscv64",
.cflags = COMPEL_CFLAGS_PIE,
#else
#error "CONFIG_<ARCH> not defined, or unsupported ARCH"
#endif

View file

@ -3,11 +3,6 @@ CFLAGS ?= -O2 -g -Wall -Werror
COMPEL := ../../../compel/compel-host
ifeq ($(GCS_ENABLE),1)
CFLAGS += -mbranch-protection=standard -DGCS_TEST_ENABLE=1
LDFLAGS += -z experimental-gcs=check
endif
all: victim spy
run:
@ -22,7 +17,7 @@ clean:
rm -f parasite.o
victim: victim.c
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
$(CC) $(CFLAGS) -o $@ $^
spy: spy.c parasite.h
$(CC) $(CFLAGS) $(shell $(COMPEL) includes) -o $@ $< $(shell $(COMPEL) --static libs)

View file

@ -112,9 +112,6 @@ int main(int argc, char **argv)
return -1;
}
#ifdef GCS_TEST_ENABLE
setenv("GLIBC_TUNABLES", "glibc.cpu.aarch64_gcs=1:glibc.cpu.aarch64_gcs_policy=2", 1);
#endif
pid = vfork();
if (pid == 0) {
close(p_in[1]);

View file

@ -50,6 +50,70 @@ static void *get_parasite_rstack_start(struct parasite_ctl *ctl)
return rstack_start;
}
static int page_writable(struct parasite_ctl *ctl, int pid, void *page)
{
FILE *maps;
size_t maps_line_len = 0;
char *maps_line = NULL;
char victim_maps_path[6 + 11 + 5 + 1];
int written;
int ret = 0;
if (((uintptr_t)page & (page_size() - 1)) != 0) {
fprintf(stderr, "Page address not aligned\n");
ret = -1;
goto done;
}
written = snprintf(victim_maps_path, sizeof(victim_maps_path), "/proc/%d/maps", pid);
if (written < 0 || written >= sizeof(victim_maps_path)) {
fprintf(stderr, "Failed to create path string to victim's /proc/%d/maps file\n", pid);
ret = -1;
goto done;
}
maps = fopen(victim_maps_path, "r");
if (maps == NULL) {
perror("Can't open victim's /proc/$pid/maps");
ret = -1;
goto done;
}
while (getline(&maps_line, &maps_line_len, maps) != -1) {
unsigned long vmstart, vmend;
char r, w;
if (sscanf(maps_line, "%lx-%lx %c%c", &vmstart, &vmend, &r, &w) < 4) {
fprintf(stderr, "Can't parse victim's /proc/%d/maps; line: %s\n", pid, maps_line);
ret = -1;
goto free_linebuf;
}
if (page >= (void *)vmstart && page < (void *)vmend) {
if (w == 'w') {
if (r != 'r') {
fprintf(stderr, "Expecting writable memory to also be readable");
ret = -1;
goto free_linebuf;
}
ret = 1;
}
break;
}
}
if (errno) {
perror("Can't read victim's /proc/$pid/maps");
ret = -1;
}
free_linebuf:
free(maps_line);
fclose(maps);
done:
return ret;
}
static void *read_proc_mem(int pid, void *offset, size_t len)
{
char victim_mem_path[6 + 11 + 4 + 1];
@ -89,6 +153,51 @@ freebuf:
return NULL;
}
static int save_data_near_stack(struct parasite_ctl *ctl, int pid, void *stack, void **saved_data,
size_t *saved_data_size)
{
size_t page_mask = page_size() - 1;
size_t saved_size = 0;
size_t stack_size_last_page = (uintptr_t)stack & page_mask;
void *next_page = stack;
if (stack_size_last_page != 0) {
size_t empty_space_last_page = page_size() - stack_size_last_page;
saved_size = min(empty_space_last_page, (size_t)SAVED_DATA_MAX);
next_page += page_size() - stack_size_last_page;
}
while (saved_size < SAVED_DATA_MAX && next_page != NULL) {
switch (page_writable(ctl, pid, next_page)) {
case 1:
saved_size = min((size_t)(saved_size + page_size()), (size_t)SAVED_DATA_MAX);
next_page += page_size();
break;
case 0:
next_page = NULL;
break;
default:
return -1;
}
}
if (saved_size > 0) {
void *sd;
sd = read_proc_mem(pid, stack, saved_size);
if (sd == NULL)
return -1;
*saved_data = sd;
} else {
*saved_data = NULL;
}
*saved_data_size = saved_size;
return 0;
}
static int check_saved_data(struct parasite_ctl *ctl, int pid, void *stack, void *saved_data, size_t saved_data_size)
{
if (saved_data != NULL) {
@ -112,7 +221,7 @@ static int do_infection(int pid)
struct infect_ctx *ictx;
int *arg;
void *stack;
size_t saved_data_size = PARASITE_STACK_REDZONE;
size_t saved_data_size;
int saved_data_check;
compel_log_init(print_vmsg, COMPEL_LOG_DEBUG);
@ -148,6 +257,8 @@ static int do_infection(int pid)
err_and_ret("Can't register cleanup function with atexit\n");
stack = get_parasite_rstack_start(ctl);
if (save_data_near_stack(ctl, pid, stack, &saved_data, &saved_data_size))
err_and_ret("Can't save data above stack\n");
if (compel_start_daemon(ctl))
err_and_ret("Can't start daemon in victim\n");

View file

@ -0,0 +1,19 @@
# Required packages for development in Debian
build-essential
libprotobuf-dev
libprotobuf-c-dev
protobuf-c-compiler
protobuf-compiler
python3-protobuf
libnet-dev
# Extra packages, required for testing and building other tools
pkg-config
libnl-3-dev
libbsd0
libbsd-dev
iproute2
libcap-dev
libaio-dev
python3-yaml
libnl-route-3-dev

View file

@ -1,42 +0,0 @@
#!/usr/bin/env sh
apk add --no-cache \
asciidoctor \
bash \
build-base \
coreutils \
e2fsprogs \
elfutils-dev \
git \
gnutls-dev \
go \
ip6tables \
iproute2 \
iptables \
iptables-legacy \
libaio-dev \
libbsd-dev \
libcap-dev \
libcap-utils \
libdrm-dev \
libnet-dev \
libnl3-dev \
libtraceevent-dev \
libtracefs-dev \
nftables \
nftables-dev \
perl \
pkgconfig \
procps \
protobuf-c-compiler \
protobuf-c-dev \
protobuf-dev \
py3-importlib-metadata \
py3-pip \
py3-protobuf \
py3-yaml \
python3 \
sudo \
tar \
util-linux \
util-linux-dev

View file

@ -1,37 +0,0 @@
#!/usr/bin/env sh
APT_INSTALL="$(cd "$(dirname "$0")/.." >/dev/null 2>&1 && pwd)/apt-install"
if [ ! -x "$APT_INSTALL" ]; then
echo "Error: apt-install not found or not executable"
exit 1
fi
"$APT_INSTALL" \
crossbuild-essential-"${DEBIAN_ARCH}" \
iproute2:"${DEBIAN_ARCH}" \
libaio-dev:"${DEBIAN_ARCH}" \
libbz2-dev:"${DEBIAN_ARCH}" \
libc6-"${DEBIAN_ARCH}"-cross \
libc6-dev-"${DEBIAN_ARCH}"-cross \
libcap-dev:"${DEBIAN_ARCH}" \
libdrm-dev:"${DEBIAN_ARCH}" \
libelf-dev:"${DEBIAN_ARCH}" \
libexpat1-dev:"${DEBIAN_ARCH}" \
libgnutls28-dev:"${DEBIAN_ARCH}" \
libnet-dev:"${DEBIAN_ARCH}" \
libnftables-dev:"${DEBIAN_ARCH}" \
libnl-3-dev:"${DEBIAN_ARCH}" \
libnl-route-3-dev:"${DEBIAN_ARCH}" \
libprotobuf-c-dev:"${DEBIAN_ARCH}" \
libprotobuf-dev:"${DEBIAN_ARCH}" \
libssl-dev:"${DEBIAN_ARCH}" \
libtraceevent-dev:"${DEBIAN_ARCH}" \
libtracefs-dev:"${DEBIAN_ARCH}" \
ncurses-dev:"${DEBIAN_ARCH}" \
uuid-dev:"${DEBIAN_ARCH}" \
build-essential \
pkg-config \
git \
protobuf-c-compiler \
protobuf-compiler \
python3-protobuf

View file

@ -1,44 +0,0 @@
#!/usr/bin/env sh
APT_INSTALL="$(cd "$(dirname "$0")/.." >/dev/null 2>&1 && pwd)/apt-install"
if [ ! -x "$APT_INSTALL" ]; then
echo "Error: apt-install not found or not executable"
exit 1
fi
"$APT_INSTALL" \
asciidoctor \
bash \
bsdmainutils \
build-essential \
gdb \
git-core \
iproute2 \
iptables \
kmod \
libaio-dev \
libbsd-dev \
libcap-dev \
libdrm-dev \
libelf-dev \
libgnutls28-dev \
libgnutls30 \
libnet-dev \
libnl-3-dev \
libnl-route-3-dev \
libperl-dev \
libprotobuf-c-dev \
libprotobuf-dev \
libselinux-dev \
libtraceevent-dev \
libtracefs-dev \
pkg-config \
protobuf-c-compiler \
protobuf-compiler \
python3-importlib-metadata \
python3-pip \
python3-protobuf \
python3-yaml \
time \
util-linux \
uuid-dev

View file

@ -1,40 +0,0 @@
#!/usr/bin/env sh
dnf install -y \
asciidoc \
binutils \
elfutils-libelf-devel \
gcc \
git \
glibc-devel \
gnutls-devel \
iproute \
iptables \
libaio-devel \
libasan \
libbpf-devel \
libbsd-devel \
libcap-devel \
libdrm-devel \
libnet-devel \
libnl3-devel \
libselinux-devel \
libtraceevent-devel \
libtracefs-devel \
libuuid-devel \
make \
nftables \
pkg-config \
protobuf \
protobuf-c \
protobuf-c-devel \
protobuf-compiler \
protobuf-devel \
python-devel \
python3-importlib-metadata \
python3-protobuf \
python3-pyyaml \
python3-setuptools \
python3-wheel \
rubygem-asciidoctor \
xmlto

View file

@ -1,34 +0,0 @@
#!/usr/bin/env sh
pacman -Syu --noconfirm \
asciidoctor \
base-devel \
bash \
coreutils \
diffutils \
git \
gnutls \
go \
iproute2 \
iptables \
libaio \
libbsd \
libcap \
libdrm \
libelf \
libnet \
libnl \
libtraceevent \
libtracefs \
nftables \
pkg-config \
protobuf \
protobuf-c \
python-importlib-metadata \
python-pip \
python-protobuf \
python-yaml \
sudo \
tar \
util-linux \
util-linux-libs

View file

@ -418,7 +418,7 @@ resolve_path() {
local p
p="${2}"
if command -v realpath > /dev/null; then
if which realpath > /dev/null; then
p=$(realpath "${p}")
fi
${ECHO} "${1}: ${p}"
@ -427,7 +427,7 @@ resolve_path() {
resolve_cmd() {
local cpath
cpath=$(command -v "${2}")
cpath=$(which "${2}")
resolve_path "${1}" "${cpath}"
}

View file

@ -6,8 +6,6 @@ import sys
import criu_coredump
PLATFORMS = ["aarch64", "armv7l", "x86_64"]
def coredump(opts):
generator = criu_coredump.coredump_generator()
@ -39,8 +37,8 @@ def main():
opts = vars(parser.parse_args())
if platform.machine() not in PLATFORMS:
print("ERROR: %s is only supported on: %s" % (sys.argv[0], ', '.join(PLATFORMS)))
if platform.machine() != 'x86_64':
print('ERROR: %s only supported on x86_64' % sys.argv[0])
sys.exit(1)
try:

View file

@ -31,7 +31,6 @@
import io
import sys
import ctypes
import platform
from pycriu import images
from . import elf
@ -55,7 +54,6 @@ status = {
"VMA_AREA_VVAR": 1 << 12,
"VMA_AREA_AIORING": 1 << 13,
"VMA_AREA_MEMFD": 1 << 14,
"VMA_AREA_UPROBES": 1 << 17,
"VMA_AREA_UNSUPP": 1 << 31
}
@ -96,13 +94,8 @@ class coredump:
buf.write(b"\0" * (8 - len(note.owner)))
buf.write(note.data)
bits = platform.architecture()[0] # 32 or 64 bits
ehdr = {"32bit": elf.Elf32_Ehdr, "64bit": elf.Elf64_Ehdr}
phdr = {"32bit": elf.Elf32_Phdr, "64bit": elf.Elf64_Phdr}
offset = ctypes.sizeof(ehdr[bits]())
offset += (len(self.vmas) + 1) * ctypes.sizeof(phdr[bits]())
offset = ctypes.sizeof(elf.Elf64_Ehdr())
offset += (len(self.vmas) + 1) * ctypes.sizeof(elf.Elf64_Phdr())
filesz = 0
for note in self.notes:
@ -137,20 +130,6 @@ class coredump_generator:
reg_files = None # reg-files;
pagemaps = {} # pagemap by pid;
# thread info key based on the current arch
thread_info_key = {
"aarch64": "ti_aarch64",
"armv7l": "ti_arm",
"x86_64": "thread_info",
}
machine = platform.machine() # current arch
bits = platform.architecture()[0] # 32 or 64 bits
ehdr = {"32bit": elf.Elf32_Ehdr, "64bit": elf.Elf64_Ehdr} # 32 or 64 bits Ehdr
nhdr = {"32bit": elf.Elf32_Nhdr, "64bit": elf.Elf64_Nhdr} # 32 or 64 bits Nhdr
phdr = {"32bit": elf.Elf32_Phdr, "64bit": elf.Elf64_Phdr} # 32 or 64 bits Phdr
def _img_open_and_strip(self, name, single=False, pid=None):
"""
Load criu image and strip it from magic and redundant list.
@ -222,62 +201,44 @@ class coredump_generator:
"""
Generate elf header for process pid with program headers phdrs.
"""
ei_class = {"32bit": elf.ELFCLASS32, "64bit": elf.ELFCLASS64}
ehdr = self.ehdr[self.bits]()
ehdr = elf.Elf64_Ehdr()
ctypes.memset(ctypes.addressof(ehdr), 0, ctypes.sizeof(ehdr))
ehdr.e_ident[elf.EI_MAG0] = elf.ELFMAG0
ehdr.e_ident[elf.EI_MAG1] = elf.ELFMAG1
ehdr.e_ident[elf.EI_MAG2] = elf.ELFMAG2
ehdr.e_ident[elf.EI_MAG3] = elf.ELFMAG3
ehdr.e_ident[elf.EI_CLASS] = ei_class[self.bits]
ehdr.e_ident[elf.EI_CLASS] = elf.ELFCLASS64
ehdr.e_ident[elf.EI_DATA] = elf.ELFDATA2LSB
ehdr.e_ident[elf.EI_VERSION] = elf.EV_CURRENT
if self.machine == "armv7l":
ehdr.e_ident[elf.EI_OSABI] = elf.ELFOSABI_ARM
else:
ehdr.e_ident[elf.EI_OSABI] = elf.ELFOSABI_NONE
ehdr.e_type = elf.ET_CORE
ehdr.e_machine = self._get_e_machine()
ehdr.e_machine = elf.EM_X86_64
ehdr.e_version = elf.EV_CURRENT
ehdr.e_phoff = ctypes.sizeof(self.ehdr[self.bits]())
ehdr.e_ehsize = ctypes.sizeof(self.ehdr[self.bits]())
ehdr.e_phentsize = ctypes.sizeof(self.phdr[self.bits]())
ehdr.e_phoff = ctypes.sizeof(elf.Elf64_Ehdr())
ehdr.e_ehsize = ctypes.sizeof(elf.Elf64_Ehdr())
ehdr.e_phentsize = ctypes.sizeof(elf.Elf64_Phdr())
# FIXME Case len(phdrs) > PN_XNUM should be handled properly.
# See fs/binfmt_elf.c from linux kernel.
ehdr.e_phnum = len(phdrs)
return ehdr
def _get_e_machine(self):
"""
Get the e_machine field based on the current architecture.
"""
e_machine_dict = {
"aarch64": elf.EM_AARCH64,
"armv7l": elf.EM_ARM,
"x86_64": elf.EM_X86_64,
}
return e_machine_dict[self.machine]
def _gen_phdrs(self, pid, notes, vmas):
"""
Generate program headers for process pid.
"""
phdrs = []
offset = ctypes.sizeof(self.ehdr[self.bits]())
offset += (len(vmas) + 1) * ctypes.sizeof(self.phdr[self.bits]())
offset = ctypes.sizeof(elf.Elf64_Ehdr())
offset += (len(vmas) + 1) * ctypes.sizeof(elf.Elf64_Phdr())
filesz = 0
for note in notes:
filesz += ctypes.sizeof(note.nhdr) + ctypes.sizeof(note.data) + 8
# PT_NOTE
phdr = self.phdr[self.bits]()
phdr = elf.Elf64_Phdr()
ctypes.memset(ctypes.addressof(phdr), 0, ctypes.sizeof(phdr))
phdr.p_type = elf.PT_NOTE
phdr.p_offset = offset
@ -297,7 +258,7 @@ class coredump_generator:
for vma in vmas:
offset += filesz
filesz = vma.filesz
phdr = self.phdr[self.bits]()
phdr = elf.Elf64_Phdr()
ctypes.memset(ctypes.addressof(phdr), 0, ctypes.sizeof(phdr))
phdr.p_type = elf.PT_LOAD
phdr.p_align = PAGESIZE
@ -354,7 +315,7 @@ class coredump_generator:
prpsinfo.pr_psargs = self._gen_cmdline(pid)[:80]
prpsinfo.pr_fname = core["tc"]["comm"].encode()
nhdr = self.nhdr[self.bits]()
nhdr = elf.Elf64_Nhdr()
nhdr.n_namesz = 5
nhdr.n_descsz = ctypes.sizeof(elf.elf_prpsinfo())
nhdr.n_type = elf.NT_PRPSINFO
@ -371,7 +332,7 @@ class coredump_generator:
Generate NT_PRSTATUS note for thread tid of process pid.
"""
core = self.cores[tid]
regs = self._get_gpregs(core)
regs = core["thread_info"]["gpregs"]
pstree = self.pstree[pid]
prstatus = elf.elf_prstatus()
@ -384,9 +345,35 @@ class coredump_generator:
prstatus.pr_pgrp = pstree["pgid"]
prstatus.pr_sid = pstree["sid"]
self._set_pr_regset(prstatus.pr_reg, regs)
prstatus.pr_reg.r15 = regs["r15"]
prstatus.pr_reg.r14 = regs["r14"]
prstatus.pr_reg.r13 = regs["r13"]
prstatus.pr_reg.r12 = regs["r12"]
prstatus.pr_reg.rbp = regs["bp"]
prstatus.pr_reg.rbx = regs["bx"]
prstatus.pr_reg.r11 = regs["r11"]
prstatus.pr_reg.r10 = regs["r10"]
prstatus.pr_reg.r9 = regs["r9"]
prstatus.pr_reg.r8 = regs["r8"]
prstatus.pr_reg.rax = regs["ax"]
prstatus.pr_reg.rcx = regs["cx"]
prstatus.pr_reg.rdx = regs["dx"]
prstatus.pr_reg.rsi = regs["si"]
prstatus.pr_reg.rdi = regs["di"]
prstatus.pr_reg.orig_rax = regs["orig_ax"]
prstatus.pr_reg.rip = regs["ip"]
prstatus.pr_reg.cs = regs["cs"]
prstatus.pr_reg.eflags = regs["flags"]
prstatus.pr_reg.rsp = regs["sp"]
prstatus.pr_reg.ss = regs["ss"]
prstatus.pr_reg.fs_base = regs["fs_base"]
prstatus.pr_reg.gs_base = regs["gs_base"]
prstatus.pr_reg.ds = regs["ds"]
prstatus.pr_reg.es = regs["es"]
prstatus.pr_reg.fs = regs["fs"]
prstatus.pr_reg.gs = regs["gs"]
nhdr = self.nhdr[self.bits]()
nhdr = elf.Elf64_Nhdr()
nhdr.n_namesz = 5
nhdr.n_descsz = ctypes.sizeof(elf.elf_prstatus())
nhdr.n_type = elf.NT_PRSTATUS
@ -398,83 +385,28 @@ class coredump_generator:
return note
def _get_gpregs(self, core):
"""
Get the general purpose registers based on the current architecture.
"""
thread_info_key = self.thread_info_key[self.machine]
thread_info = core[thread_info_key]
return thread_info["gpregs"]
def _set_pr_regset(self, pr_reg, regs):
"""
Set the pr_reg struct based on the current architecture.
"""
if self.machine == "aarch64":
pr_reg.regs = (ctypes.c_ulonglong * len(regs["regs"]))(*regs["regs"])
pr_reg.sp = regs["sp"]
pr_reg.pc = regs["pc"]
pr_reg.pstate = regs["pstate"]
elif self.machine == "armv7l":
pr_reg.r0 = regs["r0"]
pr_reg.r1 = regs["r1"]
pr_reg.r2 = regs["r2"]
pr_reg.r3 = regs["r3"]
pr_reg.r4 = regs["r4"]
pr_reg.r5 = regs["r5"]
pr_reg.r6 = regs["r6"]
pr_reg.r7 = regs["r7"]
pr_reg.r8 = regs["r8"]
pr_reg.r9 = regs["r9"]
pr_reg.r10 = regs["r10"]
pr_reg.fp = regs["fp"]
pr_reg.ip = regs["ip"]
pr_reg.sp = regs["sp"]
pr_reg.lr = regs["lr"]
pr_reg.pc = regs["pc"]
pr_reg.cpsr = regs["cpsr"]
pr_reg.orig_r0 = regs["orig_r0"]
elif self.machine == "x86_64":
pr_reg.r15 = regs["r15"]
pr_reg.r14 = regs["r14"]
pr_reg.r13 = regs["r13"]
pr_reg.r12 = regs["r12"]
pr_reg.rbp = regs["bp"]
pr_reg.rbx = regs["bx"]
pr_reg.r11 = regs["r11"]
pr_reg.r10 = regs["r10"]
pr_reg.r9 = regs["r9"]
pr_reg.r8 = regs["r8"]
pr_reg.rax = regs["ax"]
pr_reg.rcx = regs["cx"]
pr_reg.rdx = regs["dx"]
pr_reg.rsi = regs["si"]
pr_reg.rdi = regs["di"]
pr_reg.orig_rax = regs["orig_ax"]
pr_reg.rip = regs["ip"]
pr_reg.cs = regs["cs"]
pr_reg.eflags = regs["flags"]
pr_reg.rsp = regs["sp"]
pr_reg.ss = regs["ss"]
pr_reg.fs_base = regs["fs_base"]
pr_reg.gs_base = regs["gs_base"]
pr_reg.ds = regs["ds"]
pr_reg.es = regs["es"]
pr_reg.fs = regs["fs"]
pr_reg.gs = regs["gs"]
def _gen_fpregset(self, pid, tid):
"""
Generate NT_FPREGSET note for thread tid of process pid.
"""
core = self.cores[tid]
regs = self._get_fpregs(core)
regs = core["thread_info"]["fpregs"]
fpregset = elf.elf_fpregset_t()
ctypes.memset(ctypes.addressof(fpregset), 0, ctypes.sizeof(fpregset))
self._set_fpregset(fpregset, regs)
fpregset.cwd = regs["cwd"]
fpregset.swd = regs["swd"]
fpregset.ftw = regs["twd"]
fpregset.fop = regs["fop"]
fpregset.rip = regs["rip"]
fpregset.rdp = regs["rdp"]
fpregset.mxcsr = regs["mxcsr"]
fpregset.mxcr_mask = regs["mxcsr_mask"]
fpregset.st_space = (ctypes.c_uint * len(regs["st_space"]))(
*regs["st_space"])
fpregset.xmm_space = (ctypes.c_uint * len(regs["xmm_space"]))(
*regs["xmm_space"])
nhdr = elf.Elf64_Nhdr()
nhdr.n_namesz = 5
@ -488,86 +420,6 @@ class coredump_generator:
return note
def _get_fpregs(self, core):
"""
Get the floating point register dictionary based on the current architecture.
"""
fpregs_key_dict = {"aarch64": "fpsimd", "x86_64": "fpregs"}
fpregs_key = fpregs_key_dict[self.machine]
thread_info_key = self.thread_info_key[self.machine]
return core[thread_info_key][fpregs_key]
def _set_fpregset(self, fpregset, regs):
"""
Set the fpregset struct based on the current architecture.
"""
if self.machine == "aarch64":
fpregset.vregs = (ctypes.c_ulonglong * len(regs["vregs"]))(*regs["vregs"])
fpregset.fpsr = regs["fpsr"]
fpregset.fpcr = regs["fpcr"]
elif self.machine == "x86_64":
fpregset.cwd = regs["cwd"]
fpregset.swd = regs["swd"]
fpregset.ftw = regs["twd"]
fpregset.fop = regs["fop"]
fpregset.rip = regs["rip"]
fpregset.rdp = regs["rdp"]
fpregset.mxcsr = regs["mxcsr"]
fpregset.mxcr_mask = regs["mxcsr_mask"]
fpregset.st_space = (ctypes.c_uint * len(regs["st_space"]))(
*regs["st_space"])
fpregset.xmm_space = (ctypes.c_uint * len(regs["xmm_space"]))(
*regs["xmm_space"])
def _gen_arm_tls(self, tid):
"""
Generate NT_ARM_TLS note for thread tid of process pid.
"""
core = self.cores[tid]
tls = ctypes.c_ulonglong(core["ti_aarch64"]["tls"])
nhdr = elf.Elf64_Nhdr()
nhdr.n_namesz = 6
nhdr.n_descsz = ctypes.sizeof(ctypes.c_ulonglong)
nhdr.n_type = elf.NT_ARM_TLS
note = elf_note()
note.data = tls
note.owner = b"LINUX"
note.nhdr = nhdr
return note
def _gen_arm_vfp(self, tid):
"""
Generate NT_ARM_VFP note for thread tid of process pid.
"""
core = self.cores[tid]
fpstate = core["ti_arm"]["fpstate"]
data = elf.vfp_hard_struct()
ctypes.memset(ctypes.addressof(data), 0, ctypes.sizeof(data))
data.vfp_regs = (ctypes.c_uint64 * len(fpstate["vfp_regs"]))(*fpstate["vfp_regs"])
data.fpexc = fpstate["fpexc"]
data.fpscr = fpstate["fpscr"]
data.fpinst = fpstate["fpinst"]
data.fpinst2 = fpstate["fpinst2"]
nhdr = elf.Elf32_Nhdr()
nhdr.n_namesz = 6
nhdr.n_descsz = ctypes.sizeof(data)
nhdr.n_type = elf.NT_ARM_VFP
note = elf_note()
note.data = data
note.owner = b"LINUX"
note.nhdr = nhdr
return note
def _gen_x86_xstate(self, pid, tid):
"""
Generate NT_X86_XSTATE note for thread tid of process pid.
@ -617,7 +469,7 @@ class coredump_generator:
# FIXME zeroify everything for now
ctypes.memset(ctypes.addressof(siginfo), 0, ctypes.sizeof(siginfo))
nhdr = self.nhdr[self.bits]()
nhdr = elf.Elf64_Nhdr()
nhdr.n_namesz = 5
nhdr.n_descsz = ctypes.sizeof(elf.siginfo_t())
nhdr.n_type = elf.NT_SIGINFO
@ -636,22 +488,17 @@ class coredump_generator:
mm = self.mms[pid]
num_auxv = len(mm["mm_saved_auxv"]) // 2
class elf32_auxv(ctypes.Structure):
_fields_ = [("auxv", elf.Elf32_auxv_t * num_auxv)]
class elf64_auxv(ctypes.Structure):
class elf_auxv(ctypes.Structure):
_fields_ = [("auxv", elf.Elf64_auxv_t * num_auxv)]
elf_auxv = {"32bit": elf32_auxv(), "64bit": elf64_auxv()}
auxv = elf_auxv[self.bits]
auxv = elf_auxv()
for i in range(num_auxv):
auxv.auxv[i].a_type = mm["mm_saved_auxv"][i]
auxv.auxv[i].a_val = mm["mm_saved_auxv"][i + 1]
nhdr = self.nhdr[self.bits]()
nhdr = elf.Elf64_Nhdr()
nhdr.n_namesz = 5
nhdr.n_descsz = ctypes.sizeof(elf_auxv[self.bits])
nhdr.n_descsz = ctypes.sizeof(elf_auxv())
nhdr.n_type = elf.NT_AUXV
note = elf_note()
@ -728,7 +575,7 @@ class coredump_generator:
setattr(data, "file_ofs" + str(i), info.file_ofs)
setattr(data, "name" + str(i), info.name.encode())
nhdr = self.nhdr[self.bits]()
nhdr = elf.Elf64_Nhdr()
nhdr.n_namesz = 5 # strlen + 1
nhdr.n_descsz = ctypes.sizeof(elf_files())
@ -745,15 +592,9 @@ class coredump_generator:
notes = []
notes.append(self._gen_prstatus(pid, tid))
if self.machine != "armv7l":
notes.append(self._gen_fpregset(pid, tid))
notes.append(self._gen_fpregset(pid, tid))
notes.append(self._gen_x86_xstate(pid, tid))
notes.append(self._gen_siginfo(pid, tid))
if self.machine == "aarch64":
notes.append(self._gen_arm_tls(tid))
elif self.machine == "armv7l":
notes.append(self._gen_arm_vfp(tid))
elif self.machine == "x86_64":
notes.append(self._gen_x86_xstate(pid, tid))
return notes
@ -794,9 +635,7 @@ class coredump_generator:
off = 0 # in pages
for m in pagemap[1:]:
found = False
num_pages = m.get("nr_pages", m["compat_nr_pages"])
for i in range(num_pages):
for i in range(m["nr_pages"]):
if m["vaddr"] + i * PAGESIZE == page_no * PAGESIZE:
found = True
break

View file

@ -1,14 +1,5 @@
# Define structures and constants for generating elf file.
import ctypes
import platform
MACHINE = platform.machine()
Elf32_Half = ctypes.c_uint16 # typedef uint16_t Elf32_Half;
Elf32_Word = ctypes.c_uint32 # typedef uint32_t Elf32_Word;
Elf32_Addr = ctypes.c_uint32 # typedef uint32_t Elf32_Addr;
Elf32_Off = ctypes.c_uint32 # typedef uint32_t Elf32_Off;
Elf32_Xword = ctypes.c_uint64 # typedef uint64_t Elf32_Xword;
Elf64_Half = ctypes.c_uint16 # typedef uint16_t Elf64_Half;
Elf64_Word = ctypes.c_uint32 # typedef uint32_t Elf64_Word;
@ -16,7 +7,7 @@ Elf64_Addr = ctypes.c_uint64 # typedef uint64_t Elf64_Addr;
Elf64_Off = ctypes.c_uint64 # typedef uint64_t Elf64_Off;
Elf64_Xword = ctypes.c_uint64 # typedef uint64_t Elf64_Xword;
# Elf_Ehdr related constants.
# Elf64_Ehdr related constants.
# e_ident size.
EI_NIDENT = 16 # #define EI_NIDENT (16)
@ -37,50 +28,21 @@ EI_CLASS = 4 # #define EI_CLASS 4 /* File class byte index
EI_DATA = 5 # #define EI_DATA 5 /* Data encoding byte index */
EI_OSABI = 7 # #define EI_OSABI 7 /* OS ABI identification */
EI_VERSION = 6 # #define EI_VERSION 6 /* File version byte index */
ELFDATA2LSB = 1 # #define ELFDATA2LSB 1 /* 2's complement, little endian */
ELFCLASS32 = 1 # #define ELFCLASS32 1 /* 32-bit objects */
ELFCLASS64 = 2 # #define ELFCLASS64 2 /* 64-bit objects */
# Legal values for e_type (object file type).
ET_CORE = 4 # #define ET_CORE 4 /* Core file */
# Legal values for e_machine (architecture).
EM_ARM = 40 # #define EM_ARM 40 /* ARM */
EM_X86_64 = 62 # #define EM_X86_64 62 /* AMD x86-64 architecture */
EM_AARCH64 = 183 # #define EM_AARCH64 183 /* ARM AARCH64 */
# Legal values for e_version (version).
EV_CURRENT = 1 # #define EV_CURRENT 1 /* Current version */
# Legal values for e_osabi
ELFOSABI_NONE = 0 # #define ELFOSABI_NONE 0 /* UNIX System V ABI */
ELFOSABI_ARM = 97 # #define ELFOSABI_ARM 97 /* ARM */
class Elf32_Ehdr(ctypes.Structure): # typedef struct
_fields_ = [
("e_ident",
ctypes.c_ubyte * EI_NIDENT), # unsigned char e_ident[EI_NIDENT];
("e_type", Elf32_Half), # Elf32_Half e_type;
("e_machine", Elf32_Half), # Elf32_Half e_machine;
("e_version", Elf32_Word), # Elf32_Word e_version;
("e_entry", Elf32_Addr), # Elf32_Addr e_entry;
("e_phoff", Elf32_Off), # Elf32_Off e_phoff;
("e_shoff", Elf32_Off), # Elf32_Off e_shoff;
("e_flags", Elf32_Word), # Elf32_Word e_flags;
("e_ehsize", Elf32_Half), # Elf32_Half e_ehsize;
("e_phentsize", Elf32_Half), # Elf32_Half e_phentsize;
("e_phnum", Elf32_Half), # Elf32_Half e_phnum;
("e_shentsize", Elf32_Half), # Elf32_Half e_shentsize;
("e_shnum", Elf32_Half), # Elf32_Half e_shnum;
("e_shstrndx", Elf32_Half) # Elf32_Half e_shstrndx;
] # } Elf32_Ehdr;
class Elf64_Ehdr(ctypes.Structure): # typedef struct
_fields_ = [
@ -102,7 +64,7 @@ class Elf64_Ehdr(ctypes.Structure): # typedef struct
] # } Elf64_Ehdr;
# Elf_Phdr related constants.
# Elf64_Phdr related constants.
# Legal values for p_type (segment type).
PT_LOAD = 1 # #define PT_LOAD 1 /* Loadable program segment */
@ -114,19 +76,6 @@ PF_W = 1 << 1 # #define PF_W (1 << 1) /* Segment is writable
PF_R = 1 << 2 # #define PF_R (1 << 2) /* Segment is readable */
class Elf32_Phdr(ctypes.Structure): # typedef struct
_fields_ = [
("p_type", Elf32_Word), # Elf32_Word p_type;
("p_offset", Elf32_Off), # Elf32_Off p_offset;
("p_vaddr", Elf32_Addr), # Elf32_Addr p_vaddr;
("p_paddr", Elf32_Addr), # Elf32_Addr p_paddr;
("p_filesz", Elf32_Word), # Elf32_Word p_filesz;
("p_memsz", Elf32_Word), # Elf32_Word p_memsz;
("p_flags", Elf32_Word), # Elf32_Word p_flags;
("p_align", Elf32_Word), # Elf32_Word p_align;
] # } Elf32_Phdr;
class Elf64_Phdr(ctypes.Structure): # typedef struct
_fields_ = [
("p_type", Elf64_Word), # Elf64_Word p_type;
@ -140,25 +89,7 @@ class Elf64_Phdr(ctypes.Structure): # typedef struct
] # } Elf64_Phdr;
# Elf_auxv_t related constants.
class _Elf32_auxv_t_U(ctypes.Union):
_fields_ = [("a_val", ctypes.c_uint32)]
class Elf32_auxv_t(ctypes.Structure): # typedef struct
_fields_ = [
("a_type",
ctypes.c_uint32), # uint32_t a_type; /* Entry type */
("a_un", _Elf32_auxv_t_U) # union
# uint32_t a_val; /* Integer value */
# /* We use to have pointer elements added here. We cannot do that,
# though, since it does not work when using 32-bit definitions
# on 64-bit platforms and vice versa. */
# } a_un;
] # } Elf32_auxv_t;
# Elf64_auxv_t related constants.
class _Elf64_auxv_t_U(ctypes.Union):
@ -179,7 +110,7 @@ class Elf64_auxv_t(ctypes.Structure): # typedef struct
] # } Elf64_auxv_t;
# Elf_Nhdr related constants.
# Elf64_Nhdr related constants.
NT_PRSTATUS = 1 # #define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
NT_FPREGSET = 2 # #define NT_FPREGSET 2 /* Contains copy of fpregset struct */
@ -188,22 +119,6 @@ NT_AUXV = 6 # #define NT_AUXV 6 /* Contains copy of auxv array */
NT_SIGINFO = 0x53494749 # #define NT_SIGINFO 0x53494749 /* Contains copy of siginfo_t, size might increase */
NT_FILE = 0x46494c45 # #define NT_FILE 0x46494c45 /* Contains information about mapped files */
NT_X86_XSTATE = 0x202 # #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
NT_ARM_VFP = 0x400 # #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
NT_ARM_TLS = 0x401 # #define NT_ARM_TLS 0x401 /* ARM TLS register */
class Elf32_Nhdr(ctypes.Structure): # typedef struct
_fields_ = [
(
"n_namesz", Elf32_Word
), # Elf32_Word n_namesz; /* Length of the note's name. */
(
"n_descsz", Elf32_Word
), # Elf32_Word n_descsz; /* Length of the note's descriptor. */
(
"n_type", Elf32_Word
), # Elf32_Word n_type; /* Type of the note. */
] # } Elf32_Nhdr;
class Elf64_Nhdr(ctypes.Structure): # typedef struct
@ -219,52 +134,7 @@ class Elf64_Nhdr(ctypes.Structure): # typedef struct
] # } Elf64_Nhdr;
# Elf_Shdr related constants.
class Elf32_Shdr(ctypes.Structure):
_fields_ = [
(
# Section name (string tbl index)
"sh_name", Elf32_Word
),
(
# Section type
"sh_type", Elf32_Word
),
(
# Section flags
"sh_flags", Elf32_Word
),
(
# Section virtual addr at execution
"sh_addr", Elf32_Addr
),
(
# Section file offset
"sh_offset", Elf32_Off
),
(
# Section size in bytes
"sh_size", Elf32_Word
),
(
# Link to another section
"sh_link", Elf32_Word
),
(
# Additional section information
"sh_info", Elf32_Word
),
(
# Section alignment
"sh_addralign", Elf32_Word
),
(
# Entry size if section holds table
"sh_entsize", Elf32_Word
)
]
# Elf64_Shdr related constants.
class Elf64_Shdr(ctypes.Structure):
@ -348,7 +218,7 @@ class timeval(ctypes.Structure): # struct timeval
]
class x86_64_user_regs_struct(ctypes.Structure): # struct x86_64_user_regs_struct
class user_regs_struct(ctypes.Structure): # struct user_regs_struct
_fields_ = [
("r15",
ctypes.c_ulonglong), # __extension__ unsigned long long int r15;
@ -407,73 +277,10 @@ class x86_64_user_regs_struct(ctypes.Structure): # struct x86_64_user_regs_stru
]
class aarch64_user_regs_struct(ctypes.Structure): # struct aarch64_user_regs_struct
_fields_ = [
("regs",
ctypes.c_ulonglong * 31), # unsigned long long int regs[31];
("sp",
ctypes.c_ulonglong), # unsigned long long int sp;
("pc",
ctypes.c_ulonglong), # unsigned long long int pc;
("pstate",
ctypes.c_ulonglong), # unsigned long long int pstate;
]
class arm_user_regs_struct(ctypes.Structure): # struct arm_user_regs_struct
_fields_ = [
("r0",
ctypes.c_ulong), # unsigned ulong int r0;
("r1",
ctypes.c_ulong), # unsigned ulong int r1;
("r2",
ctypes.c_ulong), # unsigned ulong int r2;
("r3",
ctypes.c_ulong), # unsigned ulong int r3;
("r4",
ctypes.c_ulong), # unsigned ulong int r4;
("r5",
ctypes.c_ulong), # unsigned ulong int r5;
("r6",
ctypes.c_ulong), # unsigned ulong int r6;
("r7",
ctypes.c_ulong), # unsigned ulong int r7;
("r8",
ctypes.c_ulong), # unsigned ulong int r8;
("r9",
ctypes.c_ulong), # unsigned ulong int r9;
("r10",
ctypes.c_ulong), # unsigned ulong int r10;
("fp",
ctypes.c_ulong), # unsigned ulong int fp;
("ip",
ctypes.c_ulong), # unsigned ulong int ip;
("sp",
ctypes.c_ulong), # unsigned ulong int sp;
("lr",
ctypes.c_ulong), # unsigned ulong int lr;
("pc",
ctypes.c_ulong), # unsigned ulong int pc;
("cpsr",
ctypes.c_ulong), # unsigned ulong int cpsr;
("orig_r0",
ctypes.c_ulong), # unsigned ulong int orig_r0;
]
# elf_greg_t = ctypes.c_ulonglong
# ELF_NGREG = ctypes.sizeof(user_regs_struct)/ctypes.sizeof(elf_greg_t)
# elf_gregset_t = elf_greg_t*ELF_NGREG
user_regs_dict = {
"aarch64": aarch64_user_regs_struct,
"armv7l": arm_user_regs_struct,
"x86_64": x86_64_user_regs_struct,
}
try:
elf_gregset_t = user_regs_dict[MACHINE]
except KeyError:
raise ValueError("Current architecture %s is not supported." % MACHINE)
elf_gregset_t = user_regs_struct
class elf_prstatus(ctypes.Structure): # struct elf_prstatus
@ -613,7 +420,7 @@ class elf_prpsinfo(ctypes.Structure): # struct elf_prpsinfo
]
class x86_64_user_fpregs_struct(ctypes.Structure): # struct x86_64_user_fpregs_struct
class user_fpregs_struct(ctypes.Structure): # struct user_fpregs_struct
_fields_ = [
# unsigned short int cwd;
("cwd", ctypes.c_ushort),
@ -640,29 +447,7 @@ class x86_64_user_fpregs_struct(ctypes.Structure): # struct x86_64_user_fpregs_
]
class aarch64_user_fpregs_struct(ctypes.Structure): # struct aarch64_user_fpregs_struct
_fields_ = [
# unsigned long long int vregs[64];
("vregs", ctypes.c_ulonglong * 64),
# unsigned int fpsr;
("fpsr", ctypes.c_uint),
# unsigned int fpcr;
("fpcr", ctypes.c_uint),
# unsigned int padding[2];
("padding", ctypes.c_uint * 2),
]
user_fpregs_dict = {
"aarch64": aarch64_user_fpregs_struct,
"armv7l": None,
"x86_64": x86_64_user_fpregs_struct,
}
try:
elf_fpregset_t = user_fpregs_dict[MACHINE]
except KeyError:
raise ValueError("Current architecture %s is not supported." % MACHINE)
elf_fpregset_t = user_fpregs_struct
# siginfo_t related constants.
@ -1057,13 +842,3 @@ class elf_xsave_struct(ctypes.Structure): # struct xsave_struct {
# struct ymmh_struct ymmh;
("ymmh", ymmh_struct)
] # } __aligned(FP_MIN_ALIGN_BYTES) __packed;
class vfp_hard_struct(ctypes.Structure): # struct vfp_hard_struct {
_fields_ = [
("vfp_regs", ctypes.c_ulonglong * 32), # __u64 fpregs[32];
("fpexc", ctypes.c_ulong), # __u32 fpexc;
("fpscr", ctypes.c_ulong), # __u32 fpscr;
("fpinst", ctypes.c_ulong), # __u32 fpinst;
("fpinst2", ctypes.c_ulong), # __u32 fpinst2;
] # };

View file

@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
name = "crit"
description = "CRiu Image Tool"
authors = [
{name = "CRIU team", email = "criu@lists.linux.dev"},
{name = "CRIU team", email = "criu@openvz.org"},
]
license = {text = "GPLv2"}
dynamic = ["version"]

View file

@ -7,7 +7,7 @@
name = crit
description = CRiu Image Tool
author = CRIU team
author_email = criu@lists.linux.dev
author_email = criu@openvz.org
license = GPLv2
version = attr: crit.__version__

View file

@ -101,7 +101,6 @@ obj-$(CONFIG_COMPAT) += vdso-compat.o
CFLAGS_REMOVE_vdso-compat.o += $(CFLAGS-ASAN) $(CFLAGS-GCOV)
obj-y += pidfd-store.o
obj-y += hugetlb.o
obj-y += pidfd.o
PROTOBUF_GEN := scripts/protobuf-gen.sh

View file

@ -6,7 +6,6 @@ REQ-RPM-PKG-NAMES += protobuf-devel
REQ-RPM-PKG-NAMES += protobuf-python
REQ-RPM-PKG-NAMES += libnl3-devel
REQ-RPM-PKG-NAMES += libcap-devel
REQ-RPM-PKG-NAMES += libuuid-devel
REQ-RPM-PKG-TEST-NAMES += libaio-devel
@ -17,7 +16,6 @@ REQ-DEB-PKG-NAMES += protobuf-compiler
REQ-DEB-PKG-NAMES += $(PYTHON)-protobuf
REQ-DEB-PKG-NAMES += libnl-3-dev
REQ-DEB-PKG-NAMES += libcap-dev
REQ-DEB-PKG-NAMES += uuid-dev
REQ-DEB-PKG-TEST-NAMES += $(PYTHON)-yaml
REQ-DEB-PKG-TEST-NAMES += libaio-dev
@ -27,7 +25,7 @@ REQ-DEB-PKG-TEST-NAMES += libaio-dev
REQ-RPM-PKG-TEST-NAMES += $(PYTHON)-PyYAML
export LIBS += -lprotobuf-c -ldl -lnl-3 -lsoccr -Lsoccr/ -lnet -luuid
export LIBS += -lprotobuf-c -ldl -lnl-3 -lsoccr -Lsoccr/ -lnet
check-packages-failed:
$(warning Can not find some of the required libraries)

View file

@ -6,4 +6,3 @@ obj-y += cpu.o
obj-y += crtools.o
obj-y += sigframe.o
obj-y += bitops.o
obj-y += gcs.o

View file

@ -1,6 +1,5 @@
#include <string.h>
#include <unistd.h>
#include <linux/auxvec.h>
#include <linux/elf.h>
@ -12,7 +11,6 @@
#include "common/compiler.h"
#include <compel/ptrace.h>
#include "asm/dump.h"
#include "asm/gcs-types.h"
#include "protobuf.h"
#include "images/core.pb-c.h"
#include "images/creds.pb-c.h"
@ -22,137 +20,12 @@
#include "cpu.h"
#include "restorer.h"
#include "compel/infect.h"
#include "pstree.h"
#include <stdbool.h>
/*
* cr_user_pac_* are a copy of the corresponding uapi structs
* in arch/arm64/include/uapi/asm/ptrace.h
*/
struct cr_user_pac_address_keys {
__uint128_t apiakey;
__uint128_t apibkey;
__uint128_t apdakey;
__uint128_t apdbkey;
};
struct cr_user_pac_generic_keys {
__uint128_t apgakey;
};
/*
* The following HWCAP constants are copied from
* arch/arm64/include/uapi/asm/hwcap.h
*/
#ifndef HWCAP_PACA
#define HWCAP_PACA (1 << 30)
#endif
#ifndef HWCAP_PACG
#define HWCAP_PACG (1UL << 31)
#endif
/*
* The following NT_ARM_PAC constants are copied from
* include/uapi/linux/elf.h
*/
#ifndef NT_ARM_PACA_KEYS
#define NT_ARM_PACA_KEYS 0x407 /* ARM pointer authentication address keys */
#endif
#ifndef NT_ARM_PACG_KEYS
#define NT_ARM_PACG_KEYS 0x408
#endif
#ifndef NT_ARM_PAC_ENABLED_KEYS
#define NT_ARM_PAC_ENABLED_KEYS 0x40a /* AArch64 pointer authentication enabled keys. */
#endif
extern unsigned long getauxval(unsigned long type);
#define assign_reg(dst, src, e) dst->e = (__typeof__(dst->e))(src)->e
static int save_pac_keys(int pid, CoreEntry *core)
{
struct cr_user_pac_address_keys paca;
struct cr_user_pac_generic_keys pacg;
PacKeys *pac_entry;
long pac_enabled_key;
struct iovec iov;
int ret;
unsigned long hwcaps = getauxval(AT_HWCAP);
pac_entry = xmalloc(sizeof(PacKeys));
if (!pac_entry)
return -1;
core->ti_aarch64->pac_keys = pac_entry;
pac_keys__init(pac_entry);
if (hwcaps & HWCAP_PACA) {
PacAddressKeys *pac_address_keys;
pr_debug("%d: Dumping address authentication keys\n", pid);
iov.iov_base = &paca;
iov.iov_len = sizeof(paca);
if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_ARM_PACA_KEYS, &iov))) {
pr_perror("Failed to get address authentication key for %d", pid);
return -1;
}
pac_address_keys = xmalloc(sizeof(PacAddressKeys));
if (!pac_address_keys)
return -1;
pac_address_keys__init(pac_address_keys);
pac_entry->pac_address_keys = pac_address_keys;
pac_address_keys->apiakey_lo = paca.apiakey;
pac_address_keys->apiakey_hi = paca.apiakey >> 64;
pac_address_keys->apibkey_lo = paca.apibkey;
pac_address_keys->apibkey_hi = paca.apibkey >> 64;
pac_address_keys->apdakey_lo = paca.apdakey;
pac_address_keys->apdakey_hi = paca.apdakey >> 64;
pac_address_keys->apdbkey_lo = paca.apdbkey;
pac_address_keys->apdbkey_hi = paca.apdbkey >> 64;
iov.iov_base = &pac_enabled_key;
iov.iov_len = sizeof(pac_enabled_key);
ret = ptrace(PTRACE_GETREGSET, pid, NT_ARM_PAC_ENABLED_KEYS, &iov);
if (ret) {
pr_perror("Failed to get authentication key mask for %d", pid);
return -1;
}
pac_address_keys->pac_enabled_key = pac_enabled_key;
}
if (hwcaps & HWCAP_PACG) {
PacGenericKeys *pac_generic_keys;
pr_debug("%d: Dumping generic authentication keys\n", pid);
iov.iov_base = &pacg;
iov.iov_len = sizeof(pacg);
if ((ret = ptrace(PTRACE_GETREGSET, pid, NT_ARM_PACG_KEYS, &iov))) {
pr_perror("Failed to get a generic authantication key for %d", pid);
return -1;
}
pac_generic_keys = xmalloc(sizeof(PacGenericKeys));
if (!pac_generic_keys)
return -1;
pac_generic_keys__init(pac_generic_keys);
pac_entry->pac_generic_keys = pac_generic_keys;
pac_generic_keys->apgakey_lo = pacg.apgakey;
pac_generic_keys->apgakey_hi = pacg.apgakey >> 64;
}
return 0;
}
int save_task_regs(pid_t pid, void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd)
int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpsimd)
{
int i;
struct cr_user_gcs gcs_live;
struct iovec gcs_iov = {
.iov_base = &gcs_live,
.iov_len = sizeof(gcs_live),
};
CoreEntry *core = x;
// Save the Aarch64 CPU state
@ -164,24 +37,11 @@ int save_task_regs(pid_t pid, void *x, user_regs_struct_t *regs, user_fpregs_str
// Save the FP/SIMD state
for (i = 0; i < 32; ++i) {
core->ti_aarch64->fpsimd->vregs[2 * i] = fpsimd->fpstate.vregs[i];
core->ti_aarch64->fpsimd->vregs[2 * i + 1] = fpsimd->fpstate.vregs[i] >> 64;
}
assign_reg(core->ti_aarch64->fpsimd, &fpsimd->fpstate, fpsr);
assign_reg(core->ti_aarch64->fpsimd, &fpsimd->fpstate, fpcr);
if (save_pac_keys(pid, core))
return -1;
/* Save the GCS state */
if (compel_host_supports_gcs()) {
if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_GCS, &gcs_iov) < 0) {
pr_perror("Failed to get GCS for %d", pid);
return -1;
}
core->ti_aarch64->gcs->gcspr_el0 = gcs_live.gcspr_el0;
core->ti_aarch64->gcs->features_enabled = gcs_live.features_enabled;
core->ti_aarch64->fpsimd->vregs[2 * i] = fpsimd->vregs[i];
core->ti_aarch64->fpsimd->vregs[2 * i + 1] = fpsimd->vregs[i] >> 64;
}
assign_reg(core->ti_aarch64->fpsimd, fpsimd, fpsr);
assign_reg(core->ti_aarch64->fpsimd, fpsimd, fpcr);
return 0;
}
@ -191,7 +51,6 @@ int arch_alloc_thread_info(CoreEntry *core)
ThreadInfoAarch64 *ti_aarch64;
UserAarch64RegsEntry *gpregs;
UserAarch64FpsimdContextEntry *fpsimd;
UserAarch64GcsEntry *gcs;
ti_aarch64 = xmalloc(sizeof(*ti_aarch64));
if (!ti_aarch64)
@ -221,15 +80,6 @@ int arch_alloc_thread_info(CoreEntry *core)
if (!fpsimd->vregs)
goto err;
/* Allocate & init GCS */
if (compel_host_supports_gcs()) {
gcs = xmalloc(sizeof(*gcs));
if (!gcs)
goto err;
user_aarch64_gcs_entry__init(gcs);
ti_aarch64->gcs = gcs;
}
return 0;
err:
return -1;
@ -242,12 +92,6 @@ void arch_free_thread_info(CoreEntry *core)
xfree(CORE_THREAD_ARCH_INFO(core)->fpsimd->vregs);
xfree(CORE_THREAD_ARCH_INFO(core)->fpsimd);
}
if (CORE_THREAD_ARCH_INFO(core)->pac_keys) {
PacKeys *pac_entry = CORE_THREAD_ARCH_INFO(core)->pac_keys;
xfree(pac_entry->pac_address_keys);
xfree(pac_entry->pac_generic_keys);
xfree(pac_entry);
}
xfree(CORE_THREAD_ARCH_INFO(core)->gpregs->regs);
xfree(CORE_THREAD_ARCH_INFO(core)->gpregs);
xfree(CORE_THREAD_ARCH_INFO(core));
@ -259,7 +103,6 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core)
{
int i;
struct fpsimd_context *fpsimd = RT_SIGFRAME_FPU(sigframe);
struct gcs_context *gcs;
if (core->ti_aarch64->fpsimd->n_vregs != 64)
return 1;
@ -273,18 +116,6 @@ int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core)
fpsimd->head.magic = FPSIMD_MAGIC;
fpsimd->head.size = sizeof(*fpsimd);
if (compel_host_supports_gcs()) {
gcs = RT_SIGFRAME_GCS(sigframe);
pr_debug("sigframe gcspr %llx enabled %llx\n", gcs->gcspr, gcs->features_enabled);
gcs->head.magic = GCS_MAGIC;
gcs->head.size = sizeof(*gcs);
gcs->reserved = 0;
gcs->gcspr = core->ti_aarch64->gcs->gcspr_el0 - 8;
gcs->features_enabled = core->ti_aarch64->gcs->features_enabled;
}
return 0;
}
@ -304,83 +135,3 @@ int restore_gpregs(struct rt_sigframe *f, UserRegsEntry *r)
return 0;
}
int arch_ptrace_restore(int pid, struct pstree_item *item)
{
unsigned long hwcaps = getauxval(AT_HWCAP);
struct cr_user_pac_address_keys upaca;
struct cr_user_pac_generic_keys upacg;
PacAddressKeys *paca;
PacGenericKeys *pacg;
long pac_enabled_keys;
struct iovec iov;
int ret;
pr_debug("%d: Restoring PAC keys\n", pid);
paca = &rsti(item)->arch_info.pac_address_keys;
pacg = &rsti(item)->arch_info.pac_generic_keys;
if (rsti(item)->arch_info.has_paca) {
if (!(hwcaps & HWCAP_PACA)) {
pr_err("PACG support is required from the source system.\n");
return 1;
}
pac_enabled_keys = rsti(item)->arch_info.pac_address_keys.pac_enabled_key;
upaca.apiakey = paca->apiakey_lo + ((__uint128_t)paca->apiakey_hi << 64);
upaca.apibkey = paca->apibkey_lo + ((__uint128_t)paca->apibkey_hi << 64);
upaca.apdakey = paca->apdakey_lo + ((__uint128_t)paca->apdakey_hi << 64);
upaca.apdbkey = paca->apdbkey_lo + ((__uint128_t)paca->apdbkey_hi << 64);
iov.iov_base = &upaca;
iov.iov_len = sizeof(upaca);
if ((ret = ptrace(PTRACE_SETREGSET, pid, NT_ARM_PACA_KEYS, &iov))) {
pr_perror("Failed to set address authentication keys for %d", pid);
return 1;
}
iov.iov_base = &pac_enabled_keys;
iov.iov_len = sizeof(pac_enabled_keys);
if ((ret = ptrace(PTRACE_SETREGSET, pid, NT_ARM_PAC_ENABLED_KEYS, &iov))) {
pr_perror("Failed to set enabled key mask for %d", pid);
return 1;
}
}
if (rsti(item)->arch_info.has_pacg) {
if (!(hwcaps & HWCAP_PACG)) {
pr_err("PACG support is required from the source system.\n");
return 1;
}
upacg.apgakey = pacg->apgakey_lo + ((__uint128_t)pacg->apgakey_hi << 64);
iov.iov_base = &upacg;
iov.iov_len = sizeof(upacg);
if ((ret = ptrace(PTRACE_SETREGSET, pid, NT_ARM_PACG_KEYS, &iov))) {
pr_perror("Failed to set the generic authentication key for %d", pid);
return 1;
}
}
return 0;
}
void arch_rsti_init(struct pstree_item *p)
{
PacKeys *pac_keys = p->core[0]->ti_aarch64->pac_keys;
rsti(p)->arch_info.has_paca = false;
rsti(p)->arch_info.has_pacg = false;
if (!pac_keys)
return;
if (pac_keys->pac_address_keys) {
rsti(p)->arch_info.has_paca = true;
rsti(p)->arch_info.pac_address_keys = *pac_keys->pac_address_keys;
}
if (pac_keys->pac_generic_keys) {
rsti(p)->arch_info.has_pacg = true;
rsti(p)->arch_info.pac_generic_keys = *pac_keys->pac_generic_keys;
}
}

View file

@ -1,157 +0,0 @@
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <common/list.h>
#include <compel/cpu.h>
#include "asm/gcs-types.h"
#include "pstree.h"
#include "restorer.h"
#include "rst-malloc.h"
#include "vma.h"
#include <sys/auxv.h>
#include <stdbool.h>
static bool task_has_gcs_enabled(UserAarch64GcsEntry *gcs)
{
return gcs && (gcs->features_enabled & PR_SHADOW_STACK_ENABLE) != 0;
}
static bool host_supports_gcs(void)
{
unsigned long hwcap = getauxval(AT_HWCAP);
return (hwcap & HWCAP_GCS) != 0;
}
static bool task_needs_gcs(struct pstree_item *item, CoreEntry *core)
{
UserAarch64GcsEntry *gcs;
if (!task_alive(item))
return false;
gcs = core->ti_aarch64->gcs;
if (task_has_gcs_enabled(gcs)) {
if (!host_supports_gcs()) {
pr_warn_once("Restoring task with GCS on non-GCS host\n");
return false;
}
pr_info("Restoring task with GCS\n");
return true;
}
pr_info("Restoring a task without GCS\n");
return false;
}
static int gcs_prepare_task(struct vm_area_list *vmas,
struct rst_shstk_info *gcs)
{
struct vma_area *vma;
list_for_each_entry(vma, &vmas->h, list) {
if (vma_area_is(vma, VMA_AREA_SHSTK) &&
in_vma_area(vma, gcs->gcspr_el0)) {
unsigned long premapped_addr = vma->premmaped_addr;
unsigned long size = vma_area_len(vma);
gcs->vma_start = vma->e->start;
gcs->vma_size = size;
gcs->premapped_addr = premapped_addr;
return 0;
}
}
pr_err("Unable to find a shadow stack vma: %lx\n", gcs->gcspr_el0);
return -1;
}
int arch_gcs_prepare(struct pstree_item *item, CoreEntry *core,
struct task_restore_args *ta)
{
int i;
struct thread_restore_args *args_array = (struct thread_restore_args *)(&ta[1]);
struct vm_area_list *vmas = &rsti(item)->vmas;
struct rst_shstk_info *gcs = &ta->shstk;
if (!task_needs_gcs(item, core))
return 0;
gcs->gcspr_el0 = core->ti_aarch64->gcs->gcspr_el0;
gcs->features_enabled = core->ti_aarch64->gcs->features_enabled;
if (gcs_prepare_task(vmas, gcs)) {
pr_err("gcs: failed to prepare shadow stack memory\n");
return -1;
}
for (i = 0; i < item->nr_threads; i++) {
struct thread_restore_args *thread_args = &args_array[i];
core = item->core[i];
gcs = &thread_args->shstk;
gcs->gcspr_el0 = core->ti_aarch64->gcs->gcspr_el0;
gcs->features_enabled = core->ti_aarch64->gcs->features_enabled;
if (gcs_prepare_task(vmas, gcs)) {
pr_err("gcs: failed to prepare GCS memory\n");
return -1;
}
}
return 0;
}
int arch_shstk_trampoline(struct pstree_item *item, CoreEntry *core,
int (*func)(void *arg), void *arg)
{
int fret;
unsigned long flags = PR_SHADOW_STACK_ENABLE |
PR_SHADOW_STACK_PUSH |
PR_SHADOW_STACK_WRITE;
long ret, x1_after, x8_after;
/* If task doesn't need GCS, just call func */
if (!task_needs_gcs(item, core)) {
return func(arg);
}
pr_debug("gcs: GCS enable SVC about to fire: x8=%d x0=%d x1=0x%lx\n",
__NR_prctl, PR_SET_SHADOW_STACK_STATUS, flags);
asm volatile(
"mov x0, %3\n" // x0 = PR_SET_SHADOW_STACK_STATUS (75)
"mov x1, %4\n" // x1 = flags
"mov x2, xzr\n" // x2 = 0
"mov x3, xzr\n" // x3 = 0
"mov x4, xzr\n" // x4 = 0
"mov x8, %5\n" // x8 = __NR_prctl (167)
"svc #0\n" // Invoke syscall
"mov %0, x0\n" // Capture return value
"mov %1, x1\n" // Capture x1 after
"mov %2, x8\n" // Capture x8 after
: "=r"(ret), "=r"(x1_after), "=r"(x8_after)
: "i"(PR_SET_SHADOW_STACK_STATUS), // x0 - %3rd
"r"(flags), // x1 - %4th
"i"(__NR_prctl) // x8 - %5th
: "x0", "x1", "x2", "x3", "x4", "x8", "memory", "cc");
pr_info("gcs: after SVC: ret=%ld x1=%ld x8=%ld\n", ret, x1_after, x8_after);
if (ret != 0) {
int err = errno;
pr_err("gcs: failed to enable GCS: ret=%ld errno=%d (%s)\n", ret, err, strerror(err));
return -1;
}
fret = func(arg);
exit(fret);
return -1;
}

View file

@ -1,7 +1,7 @@
#ifndef __CR_ASM_DUMP_H__
#define __CR_ASM_DUMP_H__
extern int save_task_regs(pid_t pid, void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int save_task_regs(void *, user_regs_struct_t *, user_fpregs_struct_t *);
extern int arch_alloc_thread_info(CoreEntry *core);
extern void arch_free_thread_info(CoreEntry *core);

View file

@ -1,196 +0,0 @@
#ifndef __CR_ASM_GCS_H__
#define __CR_ASM_GCS_H__
#include <asm/gcs-types.h>
struct rst_shstk_info {
unsigned long vma_start; /* start of GCS VMA */
unsigned long vma_size; /* size of GCS VMA */
unsigned long premapped_addr; /* premapped buffer */
unsigned long tmp_gcs; /* temp area for GCS if needed */
u64 gcspr_el0; /* GCS pointer */
u64 features_enabled; /* GCS flags */
};
#define rst_shstk_info rst_shstk_info
struct task_restore_args;
struct pstree_item;
int arch_gcs_prepare(struct pstree_item *item, CoreEntry *core,
struct task_restore_args *ta);
#define arch_shstk_prepare arch_gcs_prepare
int arch_shstk_trampoline(struct pstree_item *item, CoreEntry *core,
int (*func)(void *arg), void *arg);
#define arch_shstk_trampoline arch_shstk_trampoline
static always_inline void shstk_set_restorer_stack(struct rst_shstk_info *gcs, void *ptr)
{
gcs->tmp_gcs = (long unsigned)ptr;
}
#define shstk_set_restorer_stack shstk_set_restorer_stack
static always_inline long shstk_restorer_stack_size(void)
{
return PAGE_SIZE;
}
#define shstk_restorer_stack_size shstk_restorer_stack_size
#ifdef CR_NOGLIBC
#include <compel/plugins/std/syscall.h>
#include <compel/cpu.h>
#include "vma.h"
static inline unsigned long gcs_map(unsigned long addr, unsigned long size, unsigned int flags)
{
long gcspr = sys_map_shadow_stack(addr, size, flags);
pr_info("gcs: syscall: map_shadow_stack at=%lx size=%ld\n", addr, size);
if (gcspr < 0) {
pr_err("gcs: failed to map GCS at %lx: %ld\n", addr, gcspr);
return -1;
}
if (addr && gcspr != addr) {
pr_err("gcs: address mismatch: need %lx, got %lx\n", addr, gcspr);
return -1;
}
pr_info("gcs: mmapped GCS at %lx\n", gcspr);
return gcspr;
}
/* clang-format off */
static always_inline void gcsss1(unsigned long *Xt)
{
asm volatile (
"sys #3, C7, C7, #2, %0\n"
:
: "rZ" (Xt)
: "memory");
}
static always_inline unsigned long *gcsss2(void)
{
unsigned long *Xt;
asm volatile (
"SYSL %0, #3, C7, C7, #3\n"
: "=r" (Xt)
:
: "memory");
return Xt;
}
static inline void gcsstr(unsigned long addr, unsigned long val)
{
asm volatile(
"mov x0, %0\n"
"mov x1, %1\n"
".inst 0xd91f1c01\n" // GCSSTR x1, [x0]
"mov x0, #0\n"
:
: "r"(addr), "r"(val)
: "x0", "x1", "memory");
}
/* clang-format on */
static always_inline int gcs_restore(struct rst_shstk_info *gcs)
{
unsigned long gcspr, val;
if (!(gcs && gcs->features_enabled & PR_SHADOW_STACK_ENABLE)) {
return 0;
}
gcspr = gcs->gcspr_el0 - 8;
val = ALIGN_DOWN(GCS_SIGNAL_CAP(gcspr), 8);
pr_debug("gcs: [0] GCSSTR VAL=%lx write at GCSPR=%lx\n", val, gcspr);
gcsstr(gcspr, val);
val = ALIGN_DOWN(GCS_SIGNAL_CAP(gcspr), 8) | GCS_CAP_VALID_TOKEN;
gcspr -= 8;
pr_debug("gcs: [1] GCSSTR VAL=%lx write at GCSPR=%lx\n", val, gcspr);
gcsstr(gcspr, val);
pr_debug("gcs: about to switch stacks via GCSSS1 to: %lx\n", gcspr);
gcsss1((unsigned long *)gcspr);
return 0;
}
#define arch_shstk_restore gcs_restore
static always_inline int gcs_vma_restore(VmaEntry *vma_entry)
{
unsigned long shstk, i, ret;
unsigned long *gcs_data = (void *)vma_premmaped_start(vma_entry);
unsigned long vma_size = vma_entry_len(vma_entry);
shstk = gcs_map(0, vma_size, SHADOW_STACK_SET_TOKEN);
if (shstk < 0) {
pr_err("Failed to map shadow stack at %lx: %ld\n", shstk, shstk);
}
/* restore shadow stack contents */
for (i = 0; i < vma_size / 8; i++)
gcsstr(shstk + i * 8, gcs_data[i]);
pr_debug("unmap %lx %ld\n", (unsigned long)gcs_data, vma_size);
ret = sys_munmap(gcs_data, vma_size);
if (ret < 0) {
pr_err("Failed to unmap premmaped shadow stack\n");
return ret;
}
vma_premmaped_start(vma_entry) = shstk;
return 0;
}
#define shstk_vma_restore gcs_vma_restore
static always_inline int gcs_switch_to_restorer(struct rst_shstk_info *gcs)
{
int ret;
unsigned long *ssp;
unsigned long addr;
unsigned long gcspr;
if (!(gcs && gcs->features_enabled & PR_SHADOW_STACK_ENABLE)) {
return 0;
}
pr_debug("gcs->premapped_addr + gcs->vma_size = %lx\n", gcs->premapped_addr + gcs->vma_size);
pr_debug("gcs->tmp_gcs = %lx\n", gcs->tmp_gcs);
addr = gcs->tmp_gcs;
if (addr % PAGE_SIZE != 0) {
pr_err("gcs: 0x%lx not page-aligned to size 0x%lx\n", addr, PAGE_SIZE);
return -1;
}
ret = sys_munmap((void *)addr, PAGE_SIZE);
if (ret < 0) {
pr_err("gcs: Failed to unmap aarea for dumpee GCS VMAs\n");
return -1;
}
gcspr = gcs_map(addr, PAGE_SIZE, SHADOW_STACK_SET_TOKEN);
if (gcspr == -1) {
pr_err("gcs: failed to gcs_map(%lx, %lx)\n", (unsigned long)addr, PAGE_SIZE);
return -1;
}
ssp = (unsigned long *)(addr + PAGE_SIZE - 8);
gcsss1(ssp);
return 0;
}
#define arch_shstk_switch_to_restorer gcs_switch_to_restorer
#endif /* CR_NOGLIBC */
#endif /* __CR_ASM_GCS_H__ */

View file

@ -26,14 +26,4 @@ static inline void core_get_tls(CoreEntry *pcore, tls_t *ptls)
int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core);
#define ARCH_RST_INFO y
struct rst_arch_info {
bool has_paca, has_pacg;
PacAddressKeys pac_address_keys;
PacGenericKeys pac_generic_keys;
};
int arch_ptrace_restore(int pid, struct pstree_item *item);
void arch_rsti_init(struct pstree_item *current);
#endif

Some files were not shown because too many files have changed in this diff Show more