* [PATCH 1/2] rust: add synchronous message digest support
[not found] <20230515043353.2324288-1-tomo@exabit.dev>
@ 2023-05-15 4:34 ` FUJITA Tomonori
2023-05-15 6:11 ` Kent Overstreet
2023-05-16 5:52 ` Eric Biggers
2023-05-15 4:34 ` [PATCH 2/2] rust: add socket support FUJITA Tomonori
1 sibling, 2 replies; 10+ messages in thread
From: FUJITA Tomonori @ 2023-05-15 4:34 UTC (permalink / raw)
To: rust-for-linux, netdev, linux-crypto; +Cc: FUJITA Tomonori
From: FUJITA Tomonori <fujita.tomonori@gmail.com>
Adds abstractions for crypto shash.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
rust/bindings/bindings_helper.h | 1 +
rust/helpers.c | 24 +++++++
rust/kernel/crypto.rs | 108 ++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 2 +
4 files changed, 135 insertions(+)
create mode 100644 rust/kernel/crypto.rs
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 50e7a76d5455..65683b9aa45d 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -6,6 +6,7 @@
* Sorted alphabetically.
*/
+#include <crypto/hash.h>
#include <linux/slab.h>
#include <linux/refcount.h>
#include <linux/wait.h>
diff --git a/rust/helpers.c b/rust/helpers.c
index 81e80261d597..03c131b1ca38 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -18,6 +18,7 @@
* accidentally exposed.
*/
+#include <crypto/hash.h>
#include <linux/bug.h>
#include <linux/build_bug.h>
#include <linux/err.h>
@@ -27,6 +28,29 @@
#include <linux/sched/signal.h>
#include <linux/wait.h>
+void rust_helper_crypto_free_shash(struct crypto_shash *tfm)
+{
+ crypto_free_shash(tfm);
+}
+EXPORT_SYMBOL_GPL(rust_helper_crypto_free_shash);
+
+unsigned int rust_helper_crypto_shash_digestsize(struct crypto_shash *tfm)
+{
+ return crypto_shash_digestsize(tfm);
+}
+EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_digestsize);
+
+unsigned int rust_helper_crypto_shash_descsize(struct crypto_shash *tfm)
+{
+ return crypto_shash_descsize(tfm);
+}
+EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_descsize);
+
+int rust_helper_crypto_shash_init(struct shash_desc *desc) {
+ return crypto_shash_init(desc);
+}
+EXPORT_SYMBOL_GPL(rust_helper_crypto_shash_init);
+
__noreturn void rust_helper_BUG(void)
{
BUG();
diff --git a/rust/kernel/crypto.rs b/rust/kernel/crypto.rs
new file mode 100644
index 000000000000..963487428525
--- /dev/null
+++ b/rust/kernel/crypto.rs
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Cryptography.
+//!
+//! C headers: [`include/crypto/hash.h`](../../../../include/crypto/hash.h)
+
+use crate::{
+ error::{from_err_ptr, to_result, Result},
+ str::CStr,
+};
+use alloc::alloc::{alloc, dealloc};
+use core::alloc::Layout;
+
+/// Represents `struct crypto_shash *`.
+///
+/// # Invariants
+///
+/// The pointer is valid.
+pub struct Shash(*mut bindings::crypto_shash);
+
+impl Drop for Shash {
+ fn drop(&mut self) {
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ unsafe { bindings::crypto_free_shash(self.0) }
+ }
+}
+
+impl Shash {
+ /// Creates a [`Shash`] object for a message digest handle.
+ pub fn new(name: &'static CStr, t: u32, mask: u32) -> Result<Shash> {
+ // SAFETY: FFI call.
+ let ptr =
+ unsafe { from_err_ptr(bindings::crypto_alloc_shash(name.as_char_ptr(), t, mask)) }?;
+ Ok(Self(ptr))
+ }
+
+ /// Sets optional key used by the hashing algorithm.
+ pub fn setkey(&mut self, data: &[u8]) -> Result {
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ to_result(unsafe {
+ bindings::crypto_shash_setkey(self.0, data.as_ptr(), data.len() as u32)
+ })
+ }
+
+ /// Returns the size of the result of the transformation.
+ pub fn digestsize(&self) -> u32 {
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ unsafe { bindings::crypto_shash_digestsize(self.0) }
+ }
+}
+
+/// Represents `struct shash_desc *`.
+///
+/// # Invariants
+///
+/// The field `ptr` is non-null and valid for the lifetime of the object.
+pub struct ShashDesc<'a> {
+ ptr: *mut bindings::shash_desc,
+ tfm: &'a Shash,
+ size: usize,
+}
+
+impl Drop for ShashDesc<'_> {
+ fn drop(&mut self) {
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ unsafe {
+ dealloc(
+ self.ptr.cast(),
+ Layout::from_size_align(self.size, 2).unwrap(),
+ );
+ }
+ }
+}
+
+impl<'a> ShashDesc<'a> {
+ /// Creates a [`ShashDesc`] object for a request data structure for message digest.
+ pub fn new(tfm: &'a Shash) -> Result<Self> {
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ let size = core::mem::size_of::<bindings::shash_desc>()
+ + unsafe { bindings::crypto_shash_descsize(tfm.0) } as usize;
+ let layout = Layout::from_size_align(size, 2)?;
+ let ptr = unsafe { alloc(layout) } as *mut bindings::shash_desc;
+ let mut desc = ShashDesc { ptr, tfm, size };
+ // SAFETY: The `desc.tfm` is non-null and valid for the lifetime of this object.
+ unsafe { (*desc.ptr).tfm = desc.tfm.0 };
+ Ok(desc)
+ }
+
+ /// (Re)initializes message digest.
+ pub fn init(&mut self) -> Result {
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ to_result(unsafe { bindings::crypto_shash_init(self.ptr) })
+ }
+
+ /// Adds data to message digest for processing.
+ pub fn update(&mut self, data: &[u8]) -> Result {
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ to_result(unsafe {
+ bindings::crypto_shash_update(self.ptr, data.as_ptr(), data.len() as u32)
+ })
+ }
+
+ /// Calculates message digest.
+ pub fn finalize(&mut self, output: &mut [u8]) -> Result {
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ to_result(unsafe { bindings::crypto_shash_final(self.ptr, output.as_mut_ptr()) })
+ }
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 676995d4e460..753fd62b84f1 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -35,6 +35,8 @@ extern crate self as kernel;
#[cfg(not(testlib))]
mod allocator;
mod build_assert;
+#[cfg(CONFIG_CRYPTO)]
+pub mod crypto;
pub mod error;
pub mod init;
pub mod ioctl;
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/2] rust: add socket support
[not found] <20230515043353.2324288-1-tomo@exabit.dev>
2023-05-15 4:34 ` [PATCH 1/2] rust: add synchronous message digest support FUJITA Tomonori
@ 2023-05-15 4:34 ` FUJITA Tomonori
2023-05-15 14:14 ` Andrew Lunn
2023-05-16 17:08 ` Wedson Almeida Filho
1 sibling, 2 replies; 10+ messages in thread
From: FUJITA Tomonori @ 2023-05-15 4:34 UTC (permalink / raw)
To: rust-for-linux, netdev, linux-crypto; +Cc: FUJITA Tomonori
From: FUJITA Tomonori <fujita.tomonori@gmail.com>
minimum abstraction for networking.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
rust/bindings/bindings_helper.h | 3 +
rust/kernel/lib.rs | 2 +
rust/kernel/net.rs | 174 ++++++++++++++++++++++++++++++++
3 files changed, 179 insertions(+)
create mode 100644 rust/kernel/net.rs
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 65683b9aa45d..7cbb5dd96bf6 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -7,8 +7,11 @@
*/
#include <crypto/hash.h>
+#include <linux/net.h>
#include <linux/slab.h>
#include <linux/refcount.h>
+#include <linux/socket.h>
+#include <linux/tcp.h>
#include <linux/wait.h>
#include <linux/sched.h>
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 753fd62b84f1..42dbef3d9e88 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -40,6 +40,8 @@ pub mod crypto;
pub mod error;
pub mod init;
pub mod ioctl;
+#[cfg(CONFIG_NET)]
+pub mod net;
pub mod prelude;
pub mod print;
mod static_assert;
diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
new file mode 100644
index 000000000000..204b5222abdc
--- /dev/null
+++ b/rust/kernel/net.rs
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Networking.
+//!
+//! C headers: [`include/linux/net.h`](../../../../include/linux/net.h),
+//! [`include/linux/socket.h`](../../../../include/linux/socket.h),
+
+use crate::{
+ bindings,
+ error::{to_result, Result},
+};
+use alloc::vec::Vec;
+
+/// Represents `struct socket *`.
+///
+/// # Invariants
+///
+/// The pointer is valid.
+pub struct Socket {
+ pub(crate) sock: *mut bindings::socket,
+}
+
+impl Drop for Socket {
+ fn drop(&mut self) {
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ unsafe { bindings::sock_release(self.sock) }
+ }
+}
+
+/// Address families. Defines AF_* here.
+pub enum Family {
+ /// Internet IP Protocol.
+ Ip = bindings::AF_INET as isize,
+}
+
+/// Communication type.
+pub enum SocketType {
+ /// Stream (connection).
+ Stream = bindings::sock_type_SOCK_STREAM as isize,
+}
+
+/// Protocols.
+pub enum Protocol {
+ /// Transmission Control Protocol.
+ Tcp = bindings::IPPROTO_TCP as isize,
+}
+
+impl Socket {
+ /// Creates a [`Socket`] object.
+ pub fn new(family: Family, sf: SocketType, proto: Protocol) -> Result<Self> {
+ let mut sock = core::ptr::null_mut();
+
+ // SAFETY: FFI call.
+ to_result(unsafe {
+ bindings::sock_create_kern(
+ &mut bindings::init_net,
+ family as _,
+ sf as _,
+ proto as _,
+ &mut sock,
+ )
+ })
+ .map(|_| Socket { sock })
+ }
+
+ /// Moves a socket to listening state.
+ pub fn listen(&mut self, backlog: i32) -> Result {
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ to_result(unsafe { bindings::kernel_listen(self.sock, backlog) })
+ }
+
+ /// Binds an address to a socket.
+ pub fn bind(&mut self, addr: &SocketAddr) -> Result {
+ let (addr, addrlen) = match addr {
+ SocketAddr::V4(addr) => (
+ addr as *const _ as _,
+ core::mem::size_of::<bindings::sockaddr>() as i32,
+ ),
+ };
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ to_result(unsafe { bindings::kernel_bind(self.sock, addr, addrlen) })
+ }
+
+ /// Accepts a connection
+ pub fn accept(&mut self) -> Result<Self> {
+ let mut client = core::ptr::null_mut();
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ to_result(unsafe { bindings::kernel_accept(self.sock, &mut client, 0) })
+ .map(|_| Socket { sock: client })
+ }
+
+ /// Receives a message from a socket.
+ pub fn recvmsg(&mut self, bufs: &mut [&mut [u8]], flags: i32) -> Result<usize> {
+ let mut msg = bindings::msghdr::default();
+ let mut kvec = Vec::try_with_capacity(bufs.len())?;
+ let mut len = 0;
+ for i in 0..bufs.len() {
+ len += bufs[i].len();
+ kvec.try_push(bindings::kvec {
+ iov_base: bufs[i].as_mut_ptr().cast(),
+ iov_len: bufs[i].len(),
+ })?;
+ }
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ let r = unsafe {
+ bindings::kernel_recvmsg(
+ self.sock,
+ &mut msg,
+ kvec.as_mut_ptr(),
+ bufs.len(),
+ len,
+ flags,
+ )
+ };
+ to_result(r).map(|_| r as usize)
+ }
+
+ /// Sends a message through a socket.
+ pub fn sendmsg(&mut self, bufs: &[&[u8]]) -> Result<usize> {
+ let mut msg = bindings::msghdr::default();
+ let mut kvec = Vec::try_with_capacity(bufs.len())?;
+ let mut len = 0;
+ for i in 0..bufs.len() {
+ len += bufs[i].len();
+ kvec.try_push(bindings::kvec {
+ iov_base: bufs[i].as_ptr() as *mut u8 as _,
+ iov_len: bufs[i].len(),
+ })?;
+ }
+ // SAFETY: The type invariant guarantees that the pointer is valid.
+ let r = unsafe {
+ bindings::kernel_sendmsg(self.sock, &mut msg, kvec.as_mut_ptr(), bufs.len(), len)
+ };
+ to_result(r).map(|_| r as usize)
+ }
+}
+
+/// A socket address.
+pub enum SocketAddr {
+ /// An IPv4 socket address.
+ V4(SocketAddrV4),
+}
+
+/// Represents `struct in_addr`.
+#[repr(transparent)]
+pub struct Ipv4Addr(bindings::in_addr);
+
+impl Ipv4Addr {
+ /// Creates a new IPv4 address from four eight-bit octets.
+ pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
+ Self(bindings::in_addr {
+ s_addr: u32::from_be_bytes([a, b, c, d]).to_be(),
+ })
+ }
+}
+
+/// Prepresents `struct sockaddr_in`.
+#[repr(transparent)]
+pub struct SocketAddrV4(bindings::sockaddr_in);
+
+impl SocketAddrV4 {
+ /// Creates a new IPv4 socket address.
+ pub const fn new(addr: Ipv4Addr, port: u16) -> Self {
+ Self(bindings::sockaddr_in {
+ sin_family: Family::Ip as _,
+ sin_port: port.to_be(),
+ sin_addr: addr.0,
+ __pad: [0; 8],
+ })
+ }
+}
+
+/// Waits for a full request
+pub const MSG_WAITALL: i32 = bindings::MSG_WAITALL as i32;
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] rust: add synchronous message digest support
2023-05-15 4:34 ` [PATCH 1/2] rust: add synchronous message digest support FUJITA Tomonori
@ 2023-05-15 6:11 ` Kent Overstreet
2023-05-16 5:52 ` Eric Biggers
1 sibling, 0 replies; 10+ messages in thread
From: Kent Overstreet @ 2023-05-15 6:11 UTC (permalink / raw)
To: FUJITA Tomonori; +Cc: rust-for-linux, netdev, linux-crypto, FUJITA Tomonori
On Mon, May 15, 2023 at 04:34:27AM +0000, FUJITA Tomonori wrote:
> From: FUJITA Tomonori <fujita.tomonori@gmail.com>
>
> Adds abstractions for crypto shash.
>
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> ---
> rust/bindings/bindings_helper.h | 1 +
> rust/helpers.c | 24 +++++++
> rust/kernel/crypto.rs | 108 ++++++++++++++++++++++++++++++++
> rust/kernel/lib.rs | 2 +
I think in the long run we're going to need Rust bindings located right
next to the .c files they're wrapping. Certainly modules will.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] rust: add socket support
2023-05-15 4:34 ` [PATCH 2/2] rust: add socket support FUJITA Tomonori
@ 2023-05-15 14:14 ` Andrew Lunn
2023-05-16 5:43 ` FUJITA Tomonori
2023-05-16 17:08 ` Wedson Almeida Filho
1 sibling, 1 reply; 10+ messages in thread
From: Andrew Lunn @ 2023-05-15 14:14 UTC (permalink / raw)
To: FUJITA Tomonori; +Cc: rust-for-linux, netdev, linux-crypto, FUJITA Tomonori
On Mon, May 15, 2023 at 04:34:28AM +0000, FUJITA Tomonori wrote:
> From: FUJITA Tomonori <fujita.tomonori@gmail.com>
>
> minimum abstraction for networking.
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> ---
> rust/bindings/bindings_helper.h | 3 +
> rust/kernel/lib.rs | 2 +
> rust/kernel/net.rs | 174 ++++++++++++++++++++++++++++++++
The full networking API is huge. So trying to put it all into net.rs
is unlikely to work in the long run. Maybe it would be better to name
this file based on the tiny little bit of the network API you are
writing an abstraction for?
If i'm reading the code correctly, you are abstracting the in kernel
socket API for only TCP over IPv4. Probably with time that will get
extended to IPv6, and then UDP. So maybe call this net-kern-socket.rs?
Andrew
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] rust: add socket support
2023-05-15 14:14 ` Andrew Lunn
@ 2023-05-16 5:43 ` FUJITA Tomonori
2023-05-16 12:07 ` Andrew Lunn
0 siblings, 1 reply; 10+ messages in thread
From: FUJITA Tomonori @ 2023-05-16 5:43 UTC (permalink / raw)
To: andrew; +Cc: tomo, rust-for-linux, netdev, linux-crypto, fujita.tomonori
On Mon, 15 May 2023 16:14:56 +0200
Andrew Lunn <andrew@lunn.ch> wrote:
> On Mon, May 15, 2023 at 04:34:28AM +0000, FUJITA Tomonori wrote:
>> From: FUJITA Tomonori <fujita.tomonori@gmail.com>
>>
>> minimum abstraction for networking.
>
>> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
>> ---
>> rust/bindings/bindings_helper.h | 3 +
>> rust/kernel/lib.rs | 2 +
>> rust/kernel/net.rs | 174 ++++++++++++++++++++++++++++++++
>
> The full networking API is huge. So trying to put it all into net.rs
> is unlikely to work in the long run. Maybe it would be better to name
> this file based on the tiny little bit of the network API you are
> writing an abstraction for?
Yeah, in the long run. I tried the simplest but if the maintainers
prefer that approach as the first step, I'll update the patch. how
about rust/net/socket.rs ?
> If i'm reading the code correctly, you are abstracting the in kernel
> socket API for only TCP over IPv4. Probably with time that will get
> extended to IPv6, and then UDP. So maybe call this net-kern-socket.rs?
Yes. It's thin abstraction, just wrapping socket APIs. So it's easy to
extend it for IPv6, non IP protocols, etc.
Thanks,
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] rust: add synchronous message digest support
2023-05-15 4:34 ` [PATCH 1/2] rust: add synchronous message digest support FUJITA Tomonori
2023-05-15 6:11 ` Kent Overstreet
@ 2023-05-16 5:52 ` Eric Biggers
2023-05-16 8:25 ` FUJITA Tomonori
1 sibling, 1 reply; 10+ messages in thread
From: Eric Biggers @ 2023-05-16 5:52 UTC (permalink / raw)
To: FUJITA Tomonori; +Cc: rust-for-linux, netdev, linux-crypto, FUJITA Tomonori
Hi Fujita,
On Mon, May 15, 2023 at 04:34:27AM +0000, FUJITA Tomonori wrote:
> diff --git a/rust/helpers.c b/rust/helpers.c
> index 81e80261d597..03c131b1ca38 100644
> --- a/rust/helpers.c
> +++ b/rust/helpers.c
> @@ -18,6 +18,7 @@
> * accidentally exposed.
> */
>
> +#include <crypto/hash.h>
> #include <linux/bug.h>
> #include <linux/build_bug.h>
> #include <linux/err.h>
> @@ -27,6 +28,29 @@
> #include <linux/sched/signal.h>
> #include <linux/wait.h>
>
> +void rust_helper_crypto_free_shash(struct crypto_shash *tfm)
> +{
> + crypto_free_shash(tfm);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper_crypto_free_shash);
Shouldn't this code be compiled only when the crypto API is available?
> +impl<'a> ShashDesc<'a> {
> + /// Creates a [`ShashDesc`] object for a request data structure for message digest.
> + pub fn new(tfm: &'a Shash) -> Result<Self> {
> + // SAFETY: The type invariant guarantees that the pointer is valid.
> + let size = core::mem::size_of::<bindings::shash_desc>()
> + + unsafe { bindings::crypto_shash_descsize(tfm.0) } as usize;
> + let layout = Layout::from_size_align(size, 2)?;
> + let ptr = unsafe { alloc(layout) } as *mut bindings::shash_desc;
> + let mut desc = ShashDesc { ptr, tfm, size };
> + // SAFETY: The `desc.tfm` is non-null and valid for the lifetime of this object.
> + unsafe { (*desc.ptr).tfm = desc.tfm.0 };
> + Ok(desc)
> + }
> +
> + /// (Re)initializes message digest.
> + pub fn init(&mut self) -> Result {
> + // SAFETY: The type invariant guarantees that the pointer is valid.
> + to_result(unsafe { bindings::crypto_shash_init(self.ptr) })
> + }
> +
> + /// Adds data to message digest for processing.
> + pub fn update(&mut self, data: &[u8]) -> Result {
> + // SAFETY: The type invariant guarantees that the pointer is valid.
> + to_result(unsafe {
> + bindings::crypto_shash_update(self.ptr, data.as_ptr(), data.len() as u32)
> + })
> + }
> +
> + /// Calculates message digest.
> + pub fn finalize(&mut self, output: &mut [u8]) -> Result {
> + // SAFETY: The type invariant guarantees that the pointer is valid.
> + to_result(unsafe { bindings::crypto_shash_final(self.ptr, output.as_mut_ptr()) })
> + }
This doesn't enforce that init() is called before update() or finalize(). I
think that needs to be checked in the Rust code, since the C code doesn't have
defined behavior in that case.
- Eric
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] rust: add synchronous message digest support
2023-05-16 5:52 ` Eric Biggers
@ 2023-05-16 8:25 ` FUJITA Tomonori
0 siblings, 0 replies; 10+ messages in thread
From: FUJITA Tomonori @ 2023-05-16 8:25 UTC (permalink / raw)
To: ebiggers; +Cc: tomo, rust-for-linux, netdev, linux-crypto, fujita.tomonori
Hi,
On Mon, 15 May 2023 22:52:19 -0700
Eric Biggers <ebiggers@kernel.org> wrote:
>> +#include <crypto/hash.h>
>> #include <linux/bug.h>
>> #include <linux/build_bug.h>
>> #include <linux/err.h>
>> @@ -27,6 +28,29 @@
>> #include <linux/sched/signal.h>
>> #include <linux/wait.h>
>>
>> +void rust_helper_crypto_free_shash(struct crypto_shash *tfm)
>> +{
>> + crypto_free_shash(tfm);
>> +}
>> +EXPORT_SYMBOL_GPL(rust_helper_crypto_free_shash);
>
> Shouldn't this code be compiled only when the crypto API is available?
Oops, I'll add #ifdef CONFIG_CRYPTO
>> +impl<'a> ShashDesc<'a> {
>> + /// Creates a [`ShashDesc`] object for a request data structure for message digest.
>> + pub fn new(tfm: &'a Shash) -> Result<Self> {
>> + // SAFETY: The type invariant guarantees that the pointer is valid.
>> + let size = core::mem::size_of::<bindings::shash_desc>()
>> + + unsafe { bindings::crypto_shash_descsize(tfm.0) } as usize;
>> + let layout = Layout::from_size_align(size, 2)?;
>> + let ptr = unsafe { alloc(layout) } as *mut bindings::shash_desc;
>> + let mut desc = ShashDesc { ptr, tfm, size };
>> + // SAFETY: The `desc.tfm` is non-null and valid for the lifetime of this object.
>> + unsafe { (*desc.ptr).tfm = desc.tfm.0 };
>> + Ok(desc)
>> + }
>> +
>> + /// (Re)initializes message digest.
>> + pub fn init(&mut self) -> Result {
>> + // SAFETY: The type invariant guarantees that the pointer is valid.
>> + to_result(unsafe { bindings::crypto_shash_init(self.ptr) })
>> + }
>> +
>> + /// Adds data to message digest for processing.
>> + pub fn update(&mut self, data: &[u8]) -> Result {
>> + // SAFETY: The type invariant guarantees that the pointer is valid.
>> + to_result(unsafe {
>> + bindings::crypto_shash_update(self.ptr, data.as_ptr(), data.len() as u32)
>> + })
>> + }
>> +
>> + /// Calculates message digest.
>> + pub fn finalize(&mut self, output: &mut [u8]) -> Result {
>> + // SAFETY: The type invariant guarantees that the pointer is valid.
>> + to_result(unsafe { bindings::crypto_shash_final(self.ptr, output.as_mut_ptr()) })
>> + }
>
> This doesn't enforce that init() is called before update() or finalize(). I
> think that needs to be checked in the Rust code, since the C code doesn't have
> defined behavior in that case.
Surely, Rust side should handle the case.
If the new() function internally calls init() before returning, it
works? The new() returns an initialized ShaDesc object.
Thanks for reviewing!
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] rust: add socket support
2023-05-16 5:43 ` FUJITA Tomonori
@ 2023-05-16 12:07 ` Andrew Lunn
0 siblings, 0 replies; 10+ messages in thread
From: Andrew Lunn @ 2023-05-16 12:07 UTC (permalink / raw)
To: FUJITA Tomonori; +Cc: rust-for-linux, netdev, linux-crypto, fujita.tomonori
On Tue, May 16, 2023 at 05:43:21AM +0000, FUJITA Tomonori wrote:
> On Mon, 15 May 2023 16:14:56 +0200
> Andrew Lunn <andrew@lunn.ch> wrote:
>
> > On Mon, May 15, 2023 at 04:34:28AM +0000, FUJITA Tomonori wrote:
> >> From: FUJITA Tomonori <fujita.tomonori@gmail.com>
> >>
> >> minimum abstraction for networking.
> >
> >> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> >> ---
> >> rust/bindings/bindings_helper.h | 3 +
> >> rust/kernel/lib.rs | 2 +
> >> rust/kernel/net.rs | 174 ++++++++++++++++++++++++++++++++
> >
> > The full networking API is huge. So trying to put it all into net.rs
> > is unlikely to work in the long run. Maybe it would be better to name
> > this file based on the tiny little bit of the network API you are
> > writing an abstraction for?
>
> Yeah, in the long run. I tried the simplest but if the maintainers
> prefer that approach as the first step, I'll update the patch. how
> about rust/net/socket.rs ?
That is better. But probably Eric or one of the other core maintainers
should comment. I also put kern into the name to try to make it clear
that this is not the BSD Socket kAPI, but the kernel internal API for
sockets. I don't know how important this distinction is.
Andrew
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] rust: add socket support
2023-05-15 4:34 ` [PATCH 2/2] rust: add socket support FUJITA Tomonori
2023-05-15 14:14 ` Andrew Lunn
@ 2023-05-16 17:08 ` Wedson Almeida Filho
2023-05-17 2:46 ` FUJITA Tomonori
1 sibling, 1 reply; 10+ messages in thread
From: Wedson Almeida Filho @ 2023-05-16 17:08 UTC (permalink / raw)
To: FUJITA Tomonori; +Cc: rust-for-linux, netdev, linux-crypto, FUJITA Tomonori
On Mon, 15 May 2023 at 02:45, FUJITA Tomonori <tomo@exabit.dev> wrote:
>
> From: FUJITA Tomonori <fujita.tomonori@gmail.com>
>
> minimum abstraction for networking.
>
> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
> ---
> rust/bindings/bindings_helper.h | 3 +
> rust/kernel/lib.rs | 2 +
> rust/kernel/net.rs | 174 ++++++++++++++++++++++++++++++++
> 3 files changed, 179 insertions(+)
> create mode 100644 rust/kernel/net.rs
Fujita, thanks for this.
We have basic networking support in the `rust` branch. In fact, we
also have support for async networking in there as well. For example,
the 9p server uses it.
At the moment we're prioritizing upstreaming the pieces for which we
have projects waiting. Do you have an _actual_ user in mind for this?
In any case, let's please start with that instead of a brand-new
reimplementation.
Cheers,
-Wedson
> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
> index 65683b9aa45d..7cbb5dd96bf6 100644
> --- a/rust/bindings/bindings_helper.h
> +++ b/rust/bindings/bindings_helper.h
> @@ -7,8 +7,11 @@
> */
>
> #include <crypto/hash.h>
> +#include <linux/net.h>
> #include <linux/slab.h>
> #include <linux/refcount.h>
> +#include <linux/socket.h>
> +#include <linux/tcp.h>
> #include <linux/wait.h>
> #include <linux/sched.h>
>
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 753fd62b84f1..42dbef3d9e88 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -40,6 +40,8 @@ pub mod crypto;
> pub mod error;
> pub mod init;
> pub mod ioctl;
> +#[cfg(CONFIG_NET)]
> +pub mod net;
> pub mod prelude;
> pub mod print;
> mod static_assert;
> diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs
> new file mode 100644
> index 000000000000..204b5222abdc
> --- /dev/null
> +++ b/rust/kernel/net.rs
> @@ -0,0 +1,174 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Networking.
> +//!
> +//! C headers: [`include/linux/net.h`](../../../../include/linux/net.h),
> +//! [`include/linux/socket.h`](../../../../include/linux/socket.h),
> +
> +use crate::{
> + bindings,
> + error::{to_result, Result},
> +};
> +use alloc::vec::Vec;
> +
> +/// Represents `struct socket *`.
> +///
> +/// # Invariants
> +///
> +/// The pointer is valid.
> +pub struct Socket {
> + pub(crate) sock: *mut bindings::socket,
> +}
> +
> +impl Drop for Socket {
> + fn drop(&mut self) {
> + // SAFETY: The type invariant guarantees that the pointer is valid.
> + unsafe { bindings::sock_release(self.sock) }
> + }
> +}
> +
> +/// Address families. Defines AF_* here.
> +pub enum Family {
> + /// Internet IP Protocol.
> + Ip = bindings::AF_INET as isize,
> +}
> +
> +/// Communication type.
> +pub enum SocketType {
> + /// Stream (connection).
> + Stream = bindings::sock_type_SOCK_STREAM as isize,
> +}
> +
> +/// Protocols.
> +pub enum Protocol {
> + /// Transmission Control Protocol.
> + Tcp = bindings::IPPROTO_TCP as isize,
> +}
> +
> +impl Socket {
> + /// Creates a [`Socket`] object.
> + pub fn new(family: Family, sf: SocketType, proto: Protocol) -> Result<Self> {
> + let mut sock = core::ptr::null_mut();
> +
> + // SAFETY: FFI call.
> + to_result(unsafe {
> + bindings::sock_create_kern(
> + &mut bindings::init_net,
> + family as _,
> + sf as _,
> + proto as _,
> + &mut sock,
> + )
> + })
> + .map(|_| Socket { sock })
> + }
> +
> + /// Moves a socket to listening state.
> + pub fn listen(&mut self, backlog: i32) -> Result {
> + // SAFETY: The type invariant guarantees that the pointer is valid.
> + to_result(unsafe { bindings::kernel_listen(self.sock, backlog) })
> + }
> +
> + /// Binds an address to a socket.
> + pub fn bind(&mut self, addr: &SocketAddr) -> Result {
> + let (addr, addrlen) = match addr {
> + SocketAddr::V4(addr) => (
> + addr as *const _ as _,
> + core::mem::size_of::<bindings::sockaddr>() as i32,
> + ),
> + };
> + // SAFETY: The type invariant guarantees that the pointer is valid.
> + to_result(unsafe { bindings::kernel_bind(self.sock, addr, addrlen) })
> + }
> +
> + /// Accepts a connection
> + pub fn accept(&mut self) -> Result<Self> {
> + let mut client = core::ptr::null_mut();
> + // SAFETY: The type invariant guarantees that the pointer is valid.
> + to_result(unsafe { bindings::kernel_accept(self.sock, &mut client, 0) })
> + .map(|_| Socket { sock: client })
> + }
> +
> + /// Receives a message from a socket.
> + pub fn recvmsg(&mut self, bufs: &mut [&mut [u8]], flags: i32) -> Result<usize> {
> + let mut msg = bindings::msghdr::default();
> + let mut kvec = Vec::try_with_capacity(bufs.len())?;
> + let mut len = 0;
> + for i in 0..bufs.len() {
> + len += bufs[i].len();
> + kvec.try_push(bindings::kvec {
> + iov_base: bufs[i].as_mut_ptr().cast(),
> + iov_len: bufs[i].len(),
> + })?;
> + }
> + // SAFETY: The type invariant guarantees that the pointer is valid.
> + let r = unsafe {
> + bindings::kernel_recvmsg(
> + self.sock,
> + &mut msg,
> + kvec.as_mut_ptr(),
> + bufs.len(),
> + len,
> + flags,
> + )
> + };
> + to_result(r).map(|_| r as usize)
> + }
> +
> + /// Sends a message through a socket.
> + pub fn sendmsg(&mut self, bufs: &[&[u8]]) -> Result<usize> {
> + let mut msg = bindings::msghdr::default();
> + let mut kvec = Vec::try_with_capacity(bufs.len())?;
> + let mut len = 0;
> + for i in 0..bufs.len() {
> + len += bufs[i].len();
> + kvec.try_push(bindings::kvec {
> + iov_base: bufs[i].as_ptr() as *mut u8 as _,
> + iov_len: bufs[i].len(),
> + })?;
> + }
> + // SAFETY: The type invariant guarantees that the pointer is valid.
> + let r = unsafe {
> + bindings::kernel_sendmsg(self.sock, &mut msg, kvec.as_mut_ptr(), bufs.len(), len)
> + };
> + to_result(r).map(|_| r as usize)
> + }
> +}
> +
> +/// A socket address.
> +pub enum SocketAddr {
> + /// An IPv4 socket address.
> + V4(SocketAddrV4),
> +}
> +
> +/// Represents `struct in_addr`.
> +#[repr(transparent)]
> +pub struct Ipv4Addr(bindings::in_addr);
> +
> +impl Ipv4Addr {
> + /// Creates a new IPv4 address from four eight-bit octets.
> + pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
> + Self(bindings::in_addr {
> + s_addr: u32::from_be_bytes([a, b, c, d]).to_be(),
> + })
> + }
> +}
> +
> +/// Prepresents `struct sockaddr_in`.
> +#[repr(transparent)]
> +pub struct SocketAddrV4(bindings::sockaddr_in);
> +
> +impl SocketAddrV4 {
> + /// Creates a new IPv4 socket address.
> + pub const fn new(addr: Ipv4Addr, port: u16) -> Self {
> + Self(bindings::sockaddr_in {
> + sin_family: Family::Ip as _,
> + sin_port: port.to_be(),
> + sin_addr: addr.0,
> + __pad: [0; 8],
> + })
> + }
> +}
> +
> +/// Waits for a full request
> +pub const MSG_WAITALL: i32 = bindings::MSG_WAITALL as i32;
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] rust: add socket support
2023-05-16 17:08 ` Wedson Almeida Filho
@ 2023-05-17 2:46 ` FUJITA Tomonori
0 siblings, 0 replies; 10+ messages in thread
From: FUJITA Tomonori @ 2023-05-17 2:46 UTC (permalink / raw)
To: wedsonaf; +Cc: tomo, rust-for-linux, netdev, linux-crypto, fujita.tomonori
Hi,
On Tue, 16 May 2023 14:08:47 -0300
Wedson Almeida Filho <wedsonaf@gmail.com> wrote:
> We have basic networking support in the `rust` branch. In fact, we
> also have support for async networking in there as well. For example,
> the 9p server uses it.
>
> At the moment we're prioritizing upstreaming the pieces for which we
> have projects waiting. Do you have an _actual_ user in mind for this?
I've implemented in-kernel TLS 1.3 handshake on the top of this.
https://github.com/fujita/rust-tls
The in-kernel TLS handshake feature is controversial. Proposals were
rejected in the past. So I like to know the opinions of subsystem
maintainers early, implementing in-kernel security-relevant code in
Rust could change the situation.
The requirement for networking is simple, read/write with a vector and
setsockopt. So I submitted minimum abstractions.
> In any case, let's please start with that instead of a brand-new
> reimplementation.
Sure, if netdev maintainers could merge Rust abstractions for
networking soon, I'll rework on this. But I don't think there is much
overlap between this and rust branch. Even if we could have
abstractions specific for TCP like TcpListener and TcpStream, we still
need thin abstractions for socket because there are several use-cases
of non IP sockets, I think.
Thanks,
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2023-05-17 3:05 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20230515043353.2324288-1-tomo@exabit.dev>
2023-05-15 4:34 ` [PATCH 1/2] rust: add synchronous message digest support FUJITA Tomonori
2023-05-15 6:11 ` Kent Overstreet
2023-05-16 5:52 ` Eric Biggers
2023-05-16 8:25 ` FUJITA Tomonori
2023-05-15 4:34 ` [PATCH 2/2] rust: add socket support FUJITA Tomonori
2023-05-15 14:14 ` Andrew Lunn
2023-05-16 5:43 ` FUJITA Tomonori
2023-05-16 12:07 ` Andrew Lunn
2023-05-16 17:08 ` Wedson Almeida Filho
2023-05-17 2:46 ` FUJITA Tomonori
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).