Changes in v6:
- Updated the interface and made cosmetic changes
Original Cover Letter in v5:
Hello,
This patch series implements IOCTL on the pagemap procfs file to get the
information about the page table entries (PTEs). The following operations
are supported in this ioctl:
- Get the information if the pages are soft-dirty, file mapped, present
or swapped.
- Clear the soft-dirty PTE bit of the pages.
- Get and clear the soft-dirty PTE bit of the pages atomically.
Soft-dirty PTE bit of the memory pages can be read by using the pagemap
procfs file. The soft-dirty PTE bit for the whole memory range of the
process can be cleared by writing to the clear_refs file. There are other
methods to mimic this information entirely in userspace with poor
performance:
- The mprotect syscall and SIGSEGV handler for bookkeeping
- The userfaultfd syscall with the handler for bookkeeping
Some benchmarks can be seen here[1]. This series adds features that weren't
present earlier:
- There is no atomic get soft-dirty PTE bit status and clear operation
possible.
- The soft-dirty PTE bit of only a part of memory cannot be cleared.
Historically, soft-dirty PTE bit tracking has been used in the CRIU
project. The procfs interface is enough for finding the soft-dirty bit
status and clearing the soft-dirty bit of all the pages of a process.
We have the use case where we need to track the soft-dirty PTE bit for
only specific pages on demand. We need this tracking and clear mechanism
of a region of memory while the process is running to emulate the
getWriteWatch() syscall of Windows. This syscall is used by games to
keep track of dirty pages to process only the dirty pages.
The information related to pages if the page is file mapped, present and
swapped is required for the CRIU project[2][3]. The addition of the
required mask, any mask, excluded mask and return masks are also required
for the CRIU project[2].
The IOCTL returns the addresses of the pages which match the specific masks.
The page addresses are returned in struct page_region in a compact form.
The max_pages is needed to support a use case where user only wants to get
a specific number of pages. So there is no need to find all the pages of
interest in the range when max_pages is specified. The IOCTL returns when
the maximum number of the pages are found. The max_pages is optional. If
max_pages is specified, it must be equal or greater than the vec_size.
This restriction is needed to handle worse case when one page_region only
contains info of one page and it cannot be compacted. This is needed to
emulate the Windows getWriteWatch() syscall.
Some non-dirty pages get marked as dirty because of the kernel's
internal activity (such as VMA merging as soft-dirty bit difference isn't
considered while deciding to merge VMAs). The dirty bit of the pages is
stored in the VMA flags and in the per page flags. If any of these two bits
are set, the page is considered to be soft dirty. Suppose you have cleared
the soft dirty bit of half of VMA which will be done by splitting the VMA
and clearing soft dirty bit flag in the half VMA and the pages in it. Now
kernel may decide to merge the VMAs again. So the half VMA becomes dirty
again. This splitting/merging costs performance. The application receives
a lot of pages which aren't dirty in reality but marked as dirty.
Performance is lost again here. Also sometimes user doesn't want the newly
allocated memory to be marked as dirty. PAGEMAP_NO_REUSED_REGIONS flag
solves both the problems. It is used to not depend on the soft dirty flag
in the VMA flags. So VMA splitting and merging doesn't happen. It only
depends on the soft dirty bit of the individual pages. Thus by using this
flag, there may be a scenerio such that the new memory regions which are
just created, doesn't look dirty when seen with the IOCTL, but look dirty
when seen from procfs. This seems okay as the user of this flag know the
implication of using it.
[1] https://lore.kernel.org/lkml/54d4c322-cd6e-eefd-b161-2af2b56aae24@collabora…
[2] https://lore.kernel.org/all/YyiDg79flhWoMDZB@gmail.com/
[3] https://lore.kernel.org/all/20221014134802.1361436-1-mdanylo@google.com/
Regards,
Muhammad Usama Anjum
Muhammad Usama Anjum (3):
fs/proc/task_mmu: update functions to clear the soft-dirty PTE bit
fs/proc/task_mmu: Implement IOCTL to get and/or the clear info about PTEs
selftests: vm: add pagemap ioctl tests
fs/proc/task_mmu.c | 410 +++++++++++-
include/uapi/linux/fs.h | 56 ++
tools/include/uapi/linux/fs.h | 56 ++
tools/testing/selftests/vm/.gitignore | 1 +
tools/testing/selftests/vm/Makefile | 5 +-
tools/testing/selftests/vm/pagemap_ioctl.c | 698 +++++++++++++++++++++
6 files changed, 1193 insertions(+), 33 deletions(-)
create mode 100644 tools/testing/selftests/vm/pagemap_ioctl.c
--
2.30.2
From: Roberto Sassu <roberto.sassu(a)huawei.com>
Notes:
- This patch set addresses the kernel panic described below, and not the
more broad issue of accessing kernel objects whose pointer is passed
as parameter by LSM hooks
- Alternative approaches trying to limit return values at run-time either
in the security subsystem or in the eBPF JIT are not preferred by the
respective maintainers
- Although all eBPF selftests have been verified to pass, it still might
be cumbersome to have an eBPF program being accepted by the eBPF
verifier (e.g. ANDing negative numbers causes existing bounds to be lost)
- The patch to store whether a register state changed due to an ALU64 or an
ALU32 operation might not be correct/complete, a review by eBPF
maintainers would be needed
- This patch set requires "lsm: make security_socket_getpeersec_stream()
sockptr_t safe", in lsm/next
- The modification of the LSM infrastructure to define allowed return
values for the LSM hooks could be replaced with an eBPF-only fix, with
the drawback of having to update the information manually each time a
new hook is added; allowing zero or negative values by default could be
reasonable, but there are already exceptions of LSM hooks accepting 0 or
1 (ismaclabel)
- The patches to fix the LSM infrastructure documentation are separated
from this patch set and available here:
https://lore.kernel.org/linux-security-module/20221128144240.210110-1-rober…
BPF LSM defines attachment points to allows security modules (eBPF programs
with type LSM) to provide their implementation of the desired LSM hooks.
Unfortunately, BPF LSM does not restrict which values security modules can
return (for non-void LSM hooks). If they put arbitrary values instead of
those stated in include/linux/lsm_hooks.h, they could cause big troubles.
For example, this simple eBPF program:
SEC("lsm/inode_permission")
int BPF_PROG(test_int_hook, struct inode *inode, int mask)
{
return 1;
}
causes the following kernel panic:
[ 181.130807] BUG: kernel NULL pointer dereference, address: 0000000000000079
[ 181.131478] #PF: supervisor read access in kernel mode
[ 181.131942] #PF: error_code(0x0000) - not-present page
[ 181.132407] PGD 0 P4D 0
[ 181.132650] Oops: 0000 [#1] PREEMPT SMP NOPTI
[ 181.133054] CPU: 5 PID: 857 Comm: systemd-oomd Tainted: G OE 6.1.0-rc7+ #530
[ 181.133806] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.13.0-1ubuntu1.1 04/01/2014
[ 181.134601] RIP: 0010:do_sys_openat2+0x235/0x300
[...]
[ 181.136682] RSP: 0018:ffffc90001557ee0 EFLAGS: 00010203
[ 181.137154] RAX: 0000000000000001 RBX: ffffc90001557f20 RCX: ffff888112003380
[ 181.137790] RDX: 0000000000000000 RSI: ffffffff8280b026 RDI: ffffc90001557e28
[ 181.138432] RBP: 0000000000000001 R08: 0000000000000001 R09: 0000000000000000
[ 181.139081] R10: ffffffff835097dc R11: 0000000000000000 R12: ffff888106118000
[ 181.139717] R13: 000000000000000c R14: 0000000000000000 R15: 0000000000000000
[ 181.140149] FS: 00007fa6ceb0bb40(0000) GS:ffff88846fb40000(0000) knlGS:0000000000000000
[ 181.140556] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 181.140865] CR2: 0000000000000079 CR3: 0000000135c50000 CR4: 0000000000350ee0
[ 181.141239] Call Trace:
[ 181.141373] <TASK>
[ 181.141495] do_sys_open+0x34/0x60
[ 181.141678] do_syscall_64+0x3b/0x90
[ 181.141875] entry_SYSCALL_64_after_hwframe+0x63/0xcd
Avoid this situation by statically analyzing the eBPF programs attaching to
LSM hooks, and ensure that their return values are compatible with the LSM
infrastructure conventions.
First, add a preliminary patch (patch 1) to fix a small code duplication
issue.
Extend the eBPF verifier to let BPF LSM determine whether it should check
estimated 64 bit values or the 32 bit ones (patch 2). Also, extend the LSM
infrastructure to record more precisely the allowed return values depending
on the documentation found in include/linux/lsm_hooks.h (patch 3). Add the
LSM_RET_NEG, LSM_RET_ZERO, LSM_RET_ONE, LSM_RET_GT_ONE flags to an LSM hook
if that hook allows respectively > 0, 0, 1, > 1 return values.
Then, extend BPF LSM to verify that return values, estimated by the
verifier by analyzing the eBPF program, fall in the allowed intervals found
from the return value flags of the LSM hook being attached to (patch 4).
Finally, add new tests to ensure that the verifier enforces return values
correctly (patch 5), and slightly modify existing tests to make them follow
the LSM infrastructure conventions (patches 6-7) and are accepted by the
verifier.
Changelog:
v1:
- Complete the documentation of return values in lsm_hooks.h
- Introduce return value flags in the LSM infrastructure
- Use those flags instead of the scattered logic (suggested by KP)
- Expose a single verification function to the verifier (suggested by KP)
- Add new patch to remove duplicated function definition
- Add new patch to let BPF LSM determine the appropriate register values
to use
Roberto Sassu (7):
bpf: Remove superfluous btf_id_set_contains() declaration
bpf: Mark ALU32 operations in bpf_reg_state structure
lsm: Redefine LSM_HOOK() macro to add return value flags as argument
bpf-lsm: Enforce return value limitations on security modules
selftests/bpf: Check if return values of LSM programs are allowed
selftests/bpf: Prevent positive ret values in test_lsm and
verify_pkcs7_sig
selftests/bpf: Change return value in test_libbpf_get_fd_by_id_opts.c
include/linux/bpf.h | 1 -
include/linux/bpf_lsm.h | 11 +-
include/linux/bpf_verifier.h | 1 +
include/linux/lsm_hook_defs.h | 780 ++++++++++--------
include/linux/lsm_hooks.h | 9 +-
kernel/bpf/bpf_lsm.c | 81 +-
kernel/bpf/verifier.c | 17 +-
security/bpf/hooks.c | 2 +-
security/security.c | 4 +-
tools/testing/selftests/bpf/progs/lsm.c | 4 +
.../bpf/progs/test_libbpf_get_fd_by_id_opts.c | 7 +-
.../bpf/progs/test_verify_pkcs7_sig.c | 11 +-
.../testing/selftests/bpf/verifier/lsm_ret.c | 148 ++++
13 files changed, 729 insertions(+), 347 deletions(-)
create mode 100644 tools/testing/selftests/bpf/verifier/lsm_ret.c
--
2.25.1
Guest assertions depend on successfully allocating a ucall structure. As
such, the use of guest assertions when ucall_alloc() fails simply leads
to an infinite loop in guest code.
Use GUEST_UCALL_NONE() to indicate failure instead. Though not
technically necessary, use a goto to have a single callsite and an
associated comment about why assertions don't work here. It isn't
perfect, at least the poor developer gets some signal out of the
guest...
Fixes: 426729b2cf2e ("KVM: selftests: Add ucall pool based implementation")
Signed-off-by: Oliver Upton <oliver.upton(a)linux.dev>
---
tools/testing/selftests/kvm/lib/ucall_common.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/kvm/lib/ucall_common.c b/tools/testing/selftests/kvm/lib/ucall_common.c
index 0cc0971ce60e..e8370da3de24 100644
--- a/tools/testing/selftests/kvm/lib/ucall_common.c
+++ b/tools/testing/selftests/kvm/lib/ucall_common.c
@@ -41,7 +41,8 @@ static struct ucall *ucall_alloc(void)
struct ucall *uc;
int i;
- GUEST_ASSERT(ucall_pool);
+ if (!ucall_pool)
+ goto out;
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
if (!test_and_set_bit(i, ucall_pool->in_use)) {
@@ -51,7 +52,14 @@ static struct ucall *ucall_alloc(void)
}
}
- GUEST_ASSERT(0);
+out:
+ /*
+ * If the guest cannot grab a ucall structure from the pool then the
+ * only option to get out to userspace is a bare ucall. This is probably
+ * a good time to mention that guest assertions depend on ucalls with
+ * arguments too.
+ */
+ GUEST_UCALL_NONE();
return NULL;
}
--
2.39.0.rc1.256.g54fd8350bd-goog
From: Tiezhu Yang <yangtiezhu(a)loongson.cn>
[ Upstream commit 6a30d3e3491dc562384e9f15b201a8a25b57439f ]
The latest version of grep claims the egrep is now obsolete so the build
now contains warnings that look like:
egrep: warning: egrep is obsolescent; using grep -E
fix this using "grep -E" instead.
sed -i "s/egrep/grep -E/g" `grep egrep -rwl tools/testing/selftests/net`
Here are the steps to install the latest grep:
wget http://ftp.gnu.org/gnu/grep/grep-3.8.tar.gz
tar xf grep-3.8.tar.gz
cd grep-3.8 && ./configure && make
sudo make install
export PATH=/usr/local/bin:$PATH
Signed-off-by: Tiezhu Yang <yangtiezhu(a)loongson.cn>
Link: https://lore.kernel.org/r/1669864248-829-1-git-send-email-yangtiezhu@loongs…
Signed-off-by: Jakub Kicinski <kuba(a)kernel.org>
Signed-off-by: Sasha Levin <sashal(a)kernel.org>
---
tools/testing/selftests/net/toeplitz.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/net/toeplitz.sh b/tools/testing/selftests/net/toeplitz.sh
index 0a49907cd4fe..da5bfd834eff 100755
--- a/tools/testing/selftests/net/toeplitz.sh
+++ b/tools/testing/selftests/net/toeplitz.sh
@@ -32,7 +32,7 @@ DEV="eth0"
# This is determined by reading the RSS indirection table using ethtool.
get_rss_cfg_num_rxqs() {
echo $(ethtool -x "${DEV}" |
- egrep [[:space:]]+[0-9]+:[[:space:]]+ |
+ grep -E [[:space:]]+[0-9]+:[[:space:]]+ |
cut -d: -f2- |
awk '{$1=$1};1' |
tr ' ' '\n' |
--
2.35.1