• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 
3 // Copyright (C) 2024 Google LLC.
4 
5 //! Provides knobs for Rust ashmem.
6 
7 use crate::{ashmem_range, IGNORE_UNSET_PROT_EXEC, IGNORE_UNSET_PROT_READ};
8 use core::{marker::PhantomData, sync::atomic::Ordering};
9 use kernel::{
10     c_str,
11     error::to_result,
12     fs::File,
13     miscdevice::{IovIter, Kiocb, MiscDevice, MiscDeviceOptions, MiscDeviceRegistration},
14     prelude::*,
15 };
16 
kstrtobool(kstr: &CStr) -> Result<bool>17 fn kstrtobool(kstr: &CStr) -> Result<bool> {
18     let mut res = false;
19     to_result(unsafe { kernel::bindings::kstrtobool(kstr.as_char_ptr(), &mut res) })?;
20     Ok(res)
21 }
22 
23 pub(crate) trait AshmemToggle {
24     const NAME: &'static CStr;
set(enabled: bool) -> Result<()>25     fn set(enabled: bool) -> Result<()>;
get() -> bool26     fn get() -> bool;
27 }
28 
29 pub(crate) struct AshmemToggleMisc<T>(PhantomData<T>);
30 
31 impl<T: AshmemToggle> AshmemToggleMisc<T> {
new() -> Result<Pin<KBox<MiscDeviceRegistration<AshmemToggleMisc<T>>>>>32     pub(crate) fn new() -> Result<Pin<KBox<MiscDeviceRegistration<AshmemToggleMisc<T>>>>> {
33         KBox::pin_init(
34             MiscDeviceRegistration::register(MiscDeviceOptions { name: T::NAME }),
35             GFP_KERNEL,
36         )
37     }
38 }
39 
40 #[vtable]
41 impl<T: AshmemToggle> MiscDevice for AshmemToggleMisc<T> {
42     type Ptr = ();
open(_: &File, _: &MiscDeviceRegistration<Self>) -> Result<()>43     fn open(_: &File, _: &MiscDeviceRegistration<Self>) -> Result<()> {
44         Ok(())
45     }
read_iter(mut kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIter) -> Result<usize>46     fn read_iter(mut kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIter) -> Result<usize> {
47         if kiocb.ki_pos() != 0 {
48             return Ok(0);
49         }
50 
51         let data = match T::get() {
52             false => b"0\n",
53             true => b"1\n",
54         };
55 
56         // You better give me a buffer with space for at least two bytes.
57         iov.copy_to_iter(data)?;
58         *kiocb.ki_pos_mut() = 2;
59         Ok(2)
60     }
write_iter(_kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIter) -> Result<usize>61     fn write_iter(_kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIter) -> Result<usize> {
62         let mut data = [0; 16];
63         let len = iov.copy_from_iter(&mut data[..15]);
64         data[len] = 0;
65         let data = CStr::from_bytes_with_nul(&data[..len + 1])?;
66         T::set(kstrtobool(data)?)?;
67         Ok(len)
68     }
69 }
70 
71 pub(crate) struct AshmemToggleShrinker;
72 
73 impl AshmemToggle for AshmemToggleShrinker {
74     const NAME: &'static CStr = c_str!("ashmem_unpinning_enable");
set(enabled: bool) -> Result<()>75     fn set(enabled: bool) -> Result<()> {
76         ashmem_range::set_shrinker_enabled(enabled)
77     }
get() -> bool78     fn get() -> bool {
79         ashmem_range::get_shrinker_enabled()
80     }
81 }
82 
83 pub(crate) struct AshmemToggleRead;
84 
85 impl AshmemToggle for AshmemToggleRead {
86     const NAME: &'static CStr = c_str!("ashmem_ignore_unset_prot_read");
set(enabled: bool) -> Result<()>87     fn set(enabled: bool) -> Result<()> {
88         IGNORE_UNSET_PROT_READ.store(enabled, Ordering::Relaxed);
89         Ok(())
90     }
get() -> bool91     fn get() -> bool {
92         IGNORE_UNSET_PROT_READ.load(Ordering::Relaxed)
93     }
94 }
95 
96 pub(crate) struct AshmemToggleExec;
97 
98 impl AshmemToggle for AshmemToggleExec {
99     const NAME: &'static CStr = c_str!("ashmem_ignore_unset_prot_exec");
set(enabled: bool) -> Result<()>100     fn set(enabled: bool) -> Result<()> {
101         IGNORE_UNSET_PROT_EXEC.store(enabled, Ordering::Relaxed);
102         Ok(())
103     }
get() -> bool104     fn get() -> bool {
105         IGNORE_UNSET_PROT_EXEC.load(Ordering::Relaxed)
106     }
107 }
108