NUL (`'\0'`) bytes within Rust strings cause issues
It's unlikely that someone actually wants to transmit strings that contain NUL in them. However in some applications it may be possible to get such strings into a D-Bus interface and cause it to hang.
Using this small example with zbus = 1.8.0
and zvariant = 2.4.0
:
use std::convert::TryInto;
use std::error::Error;
use zbus::Connection;
use zbus::ObjectServer;
use zbus::dbus_interface;
use zbus::fdo;
struct Smth {
whatever: String,
}
#[dbus_interface(name = "org.example.Smth1")]
impl Smth {
#[dbus_interface(property)]
fn whatever(&self) -> &str {
&self.whatever
}
}
fn main() -> Result<(), Box<dyn Error>> {
let conn = Connection::new_session()?;
fdo::DBusProxy::new(&conn)?.request_name(
"org.example.Smth1",
fdo::RequestNameFlags::ReplaceExisting.into(),
)?;
let mut objserv = ObjectServer::new(&conn);
let smth = Smth { whatever: String::from("hey, that's a string with 3 NULs\0\0\0") };
objserv.at(&"/org/example/Smth".try_into()?, smth)?;
loop {
if let Err(err) = objserv.try_handle_next() {
eprintln!("{}", err);
}
}
}
As a surface level way of debugging this, let's run it with strace
$ strace ./target/debug/smth
Then do something that tries to read the property:
$ busctl --user introspect org.example.Smth1 /org/example/Smth
This is the last usable part of the trace, recvmsg
is just endlessly
called until the program is killed.
getuid() = 1000
sendmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\0AUTH EXTERNAL 31303030\r\n", iov_len=25}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 25
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="OK c025737ba4fae3b1cfd49233c8110"..., iov_len=40}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 37
sendmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="NEGOTIATE_UNIX_FD\r\n", iov_len=19}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 19
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="AGREE_UNIX_FD\r\n", iov_len=40}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 15
sendmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="BEGIN\r\n", iov_len=7}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 7
getrandom("\x51\xe1\x0e\xb1\xf5\xa5\xa8\x5f\x7f\xbf\x05\x9e\xf9\xf2\x8a\x19", 16, GRND_NONBLOCK) = 16
sendmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\1\0\1\0\0\0\0\1\0\0\0m\0\0\0\1\1o\0\25\0\0\0/org/fre"..., iov_len=128}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 128
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="l\2\1\1\v\0\0\0\377\377\377\377?\0\0\0", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 16
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="\5\1u\0\1\0\0\0\7\1s\0\24\0\0\0org.freedesktop."..., iov_len=75}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 75
sendmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\1\0\1\34\0\0\0\2\0\0\0\215\0\0\0\10\1g\0\2su\0\7\1s\0\6\0\0\0"..., iov_len=188}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 188
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="l\4\1\1\v\0\0\0\377\377\377\377\217\0\0\0", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 16
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="\7\1s\0\24\0\0\0org.freedesktop.DBus\0\0\0\0"..., iov_len=155}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 155
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="l\4\1\1\26\0\0\0\377\377\377\377\217\0\0\0", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 16
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="\7\1s\0\24\0\0\0org.freedesktop.DBus\0\0\0\0"..., iov_len=166}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 166
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="l\2\1\1\4\0\0\0\377\377\377\377?\0\0\0", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 16
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="\5\1u\0\2\0\0\0\7\1s\0\24\0\0\0org.freedesktop."..., iov_len=68}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 68
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="l\1\0\1\0\0\0\0\2\0\0\0\227\0\0\0", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 16
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="\1\1o\0\21\0\0\0/org/example/Smth\0\0\0\0\0\0\0"..., iov_len=152}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 152
sendmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\2\0\1\220\5\0\0\3\0\0\0/\0\0\0\10\1g\0\1s\0\0\7\1s\0\6\0\0\0"..., iov_len=1488}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1488
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="l\1\0\1\26\0\0\0\3\0\0\0\217\0\0\0", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 16
recvmsg(3, {msg_name={sa_family=AF_UNIX, sun_path="/run/user/1000/bus"}, msg_namelen=128->21, msg_iov=[{iov_base="\1\1o\0\21\0\0\0/org/example/Smth\0\0\0\0\0\0\0"..., iov_len=166}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 166
sendmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="l\2\0\1?\0\0\0\4\0\0\0007\0\0\0\10\1g\0\5a{sv}\0\0\0\0\0\0"..., iov_len=135}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 135
recvmsg(3, {msg_name=0x7ffd87585cc8, msg_namelen=128->0, msg_iov=[{iov_base="", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 0
recvmsg(3, {msg_name=0x7ffd87585cc8, msg_namelen=128->0, msg_iov=[{iov_base="", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 0
recvmsg(3, {msg_name=0x7ffd87585cc8, msg_namelen=128->0, msg_iov=[{iov_base="", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 0
recvmsg(3, {msg_name=0x7ffd87585cc8, msg_namelen=128->0, msg_iov=[{iov_base="", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 0
recvmsg(3, {msg_name=0x7ffd87585cc8, msg_namelen=128->0, msg_iov=[{iov_base="", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 0
recvmsg(3, {msg_name=0x7ffd87585cc8, msg_namelen=128->0, msg_iov=[{iov_base="", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 0
recvmsg(3, {msg_name=0x7ffd87585cc8, msg_namelen=128->0, msg_iov=[{iov_base="", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 0
recvmsg(3, {msg_name=0x7ffd87585cc8, msg_namelen=128->0, msg_iov=[{iov_base="", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 0
recvmsg(3, {msg_name=0x7ffd87585cc8, msg_namelen=128->0, msg_iov=[{iov_base="", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 0
recvmsg(3, {msg_name=0x7ffd87585cc8, msg_namelen=128->0, msg_iov=[{iov_base="", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 0
recvmsg(3, {msg_name=0x7ffd87585cc8, msg_namelen=128->0, msg_iov=[{iov_base="", iov_len=16}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 0
...
I think that since Rust String
/str
with interior NULs in them are
completely valid, this should be handled in some way by zvariant
, I suppose?