Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rust: declare cfi_encoding for lru_status

By default bindgen will convert 'enum lru_status' into a typedef for an
integer. For the most part, an integer of the same size as the enum
results in the correct ABI, but in the specific case of CFI, that is not
the case. The CFI encoding is supposed to be the same as a struct called
'lru_status' rather than the name of the underlying native integer type.

To fix this, tell bindgen to generate a newtype and set the CFI type
explicitly. Note that we need to set the CFI attribute explicitly as
bindgen is using repr(transparent), which is otherwise identical to the
inner type for ABI purposes.

This allows us to remove the page range helper C function in Binder
without risking a CFI failure when list_lru_walk calls the provided
function pointer.

The --with-attribute-custom-enum argument requires bindgen v0.71 or
greater.

[ In particular, the feature was added in 0.71.0 [1][2].

In addition, `feature(cfi_encoding)` has been available since
Rust 1.71.0 [3].

Link: https://github.com/rust-lang/rust-bindgen/issues/2520 [1]
Link: https://github.com/rust-lang/rust-bindgen/pull/2866 [2]
Link: https://github.com/rust-lang/rust/pull/105452 [3]

- Miguel ]

My testing procedure was to add this to the android17-6.18 branch and
verify that rust_shrink_free_page is successfully called without crash,
and verify that it does in fact crash when the cfi_encoding is set to
other values. Note that I couldn't test this on android16-6.12 as that
branch uses a bindgen version that is too old.

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Link: https://patch.msgid.link/20260223-cfi-lru-status-v2-1-89c6448a63a4@google.com
[ Rebased on top of the minimum Rust version bump series which provide
the required `bindgen` version. - Miguel ]
Reviewed-by: Gary Guo <gary@garyguo.net>
Link: https://patch.msgid.link/20260405235309.418950-32-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

authored by

Alice Ryhl and committed by
Miguel Ojeda
9e5946de 86c5d1c6

+10 -45
+1 -2
drivers/android/binder/Makefile
··· 5 5 rust_binder-y := \ 6 6 rust_binder_main.o \ 7 7 rust_binderfs.o \ 8 - rust_binder_events.o \ 9 - page_range_helper.o 8 + rust_binder_events.o
+3 -3
drivers/android/binder/page_range.rs
··· 642 642 unsafe { 643 643 bindings::list_lru_walk( 644 644 list_lru, 645 - Some(bindings::rust_shrink_free_page_wrap), 645 + Some(rust_shrink_free_page), 646 646 ptr::null_mut(), 647 647 nr_to_scan, 648 648 ) 649 649 } 650 650 } 651 651 652 - const LRU_SKIP: bindings::lru_status = bindings::lru_status_LRU_SKIP; 653 - const LRU_REMOVED_ENTRY: bindings::lru_status = bindings::lru_status_LRU_REMOVED_RETRY; 652 + const LRU_SKIP: bindings::lru_status = bindings::lru_status::LRU_SKIP; 653 + const LRU_REMOVED_ENTRY: bindings::lru_status = bindings::lru_status::LRU_REMOVED_RETRY; 654 654 655 655 /// # Safety 656 656 /// Called by the shrinker.
-24
drivers/android/binder/page_range_helper.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - 3 - /* C helper for page_range.rs to work around a CFI violation. 4 - * 5 - * Bindgen currently pretends that `enum lru_status` is the same as an integer. 6 - * This assumption is fine ABI-wise, but once you add CFI to the mix, it 7 - * triggers a CFI violation because `enum lru_status` gets a different CFI tag. 8 - * 9 - * This file contains a workaround until bindgen can be fixed. 10 - * 11 - * Copyright (C) 2025 Google LLC. 12 - */ 13 - #include "page_range_helper.h" 14 - 15 - unsigned int rust_shrink_free_page(struct list_head *item, 16 - struct list_lru_one *list, 17 - void *cb_arg); 18 - 19 - enum lru_status 20 - rust_shrink_free_page_wrap(struct list_head *item, struct list_lru_one *list, 21 - void *cb_arg) 22 - { 23 - return rust_shrink_free_page(item, list, cb_arg); 24 - }
-15
drivers/android/binder/page_range_helper.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - /* 3 - * Copyright (C) 2025 Google, Inc. 4 - */ 5 - 6 - #ifndef _LINUX_PAGE_RANGE_HELPER_H 7 - #define _LINUX_PAGE_RANGE_HELPER_H 8 - 9 - #include <linux/list_lru.h> 10 - 11 - enum lru_status 12 - rust_shrink_free_page_wrap(struct list_head *item, struct list_lru_one *list, 13 - void *cb_arg); 14 - 15 - #endif /* _LINUX_PAGE_RANGE_HELPER_H */
+4
rust/bindgen_parameters
··· 19 19 # warning. We don't need to peek into it anyway. 20 20 --opaque-type spinlock 21 21 22 + # enums that appear in indirect function calls should specify a cfi type 23 + --newtype-enum lru_status 24 + --with-attribute-custom-enum=lru_status='#[cfi_encoding="10lru_status"]' 25 + 22 26 # `seccomp`'s comment gets understood as a doctest 23 27 --no-doc-comments 24 28
-1
rust/bindings/bindings_helper.h
··· 149 149 #if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST) 150 150 #include "../../drivers/android/binder/rust_binder.h" 151 151 #include "../../drivers/android/binder/rust_binder_events.h" 152 - #include "../../drivers/android/binder/page_range_helper.h" 153 152 #endif
+1
rust/bindings/lib.rs
··· 19 19 unreachable_pub, 20 20 unsafe_op_in_unsafe_fn 21 21 )] 22 + #![feature(cfi_encoding)] 22 23 23 24 #[allow(dead_code)] 24 25 #[allow(clippy::cast_lossless)]
+1
rust/uapi/lib.rs
··· 24 24 unsafe_op_in_unsafe_fn 25 25 )] 26 26 #![cfg_attr(CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES, allow(unnecessary_transmutes))] 27 + #![feature(cfi_encoding)] 27 28 28 29 // Manual definition of blocklisted types. 29 30 type __kernel_size_t = usize;