|
From: Ryan C. <et...@gm...> - 2019-12-21 01:00:57
|
`statx` is a relatively new system call, only appearing in Linux 4.11.
Rust uses a trick where it calls `statx` with two NULL pointers to see
if the kernel/glibc support it because it's faster than calling it with
a real filename. If it returns `EFAULT` the system call is supported,
otherwise it returns `ENOSYS`. The comments in the Rust source code
imply this is a known trick.
This allow either the filename or buffer to be NULL. This is a bit hacky
but it should be completely safe as Linux doesn't allow mapping on the
NULL page.
---
coregrind/m_syswrap/syswrap-linux.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c
index f1ecbbf14..87b345b4c 100644
--- a/coregrind/m_syswrap/syswrap-linux.c
+++ b/coregrind/m_syswrap/syswrap-linux.c
@@ -3694,8 +3694,12 @@ PRE(sys_statx)
PRE_REG_READ5(long, "statx",
int, dirfd, char *, file_name, int, flags,
unsigned int, mask, struct statx *, buf);
- PRE_MEM_RASCIIZ( "statx(file_name)", ARG2 );
- PRE_MEM_WRITE( "statx(buf)", ARG5, sizeof(struct vki_statx) );
+
+ if (ARG2 != 0)
+ PRE_MEM_RASCIIZ( "statx(file_name)", ARG2 );
+
+ if (ARG5 != 0)
+ PRE_MEM_WRITE( "statx(buf)", ARG5, sizeof(struct vki_statx) );
}
POST(sys_statx)
{
--
2.17.1
|
|
From: Ryan C. <et...@gm...> - 2019-12-21 01:03:12
|
This can be reproduced with the following code compiled on Rust 1.40:
fn main() {
println!("{:?}", std::path::PathBuf::from("/proc/cpuinfo").metadata());
}
Which raises:
==31878== Syscall param statx(file_name) points to unaddressable byte(s)
==31878== Syscall param statx(buf) points to unaddressable byte(s)
The relevant Rust source is here:
https://github.com/rust-lang/rust/blob/ccd238309f9dce92a05a23c2959e2819668c69a4/src/libstd/sys/unix/fs.rs#L128-L142
On Sat, Dec 21, 2019 at 12:00 PM Ryan Cumming <et...@gm...> wrote:
>
> `statx` is a relatively new system call, only appearing in Linux 4.11.
> Rust uses a trick where it calls `statx` with two NULL pointers to see
> if the kernel/glibc support it because it's faster than calling it with
> a real filename. If it returns `EFAULT` the system call is supported,
> otherwise it returns `ENOSYS`. The comments in the Rust source code
> imply this is a known trick.
>
> This allow either the filename or buffer to be NULL. This is a bit hacky
> but it should be completely safe as Linux doesn't allow mapping on the
> NULL page.
> ---
> coregrind/m_syswrap/syswrap-linux.c | 8 ++++++--
> 1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c
> index f1ecbbf14..87b345b4c 100644
> --- a/coregrind/m_syswrap/syswrap-linux.c
> +++ b/coregrind/m_syswrap/syswrap-linux.c
> @@ -3694,8 +3694,12 @@ PRE(sys_statx)
> PRE_REG_READ5(long, "statx",
> int, dirfd, char *, file_name, int, flags,
> unsigned int, mask, struct statx *, buf);
> - PRE_MEM_RASCIIZ( "statx(file_name)", ARG2 );
> - PRE_MEM_WRITE( "statx(buf)", ARG5, sizeof(struct vki_statx) );
> +
> + if (ARG2 != 0)
> + PRE_MEM_RASCIIZ( "statx(file_name)", ARG2 );
> +
> + if (ARG5 != 0)
> + PRE_MEM_WRITE( "statx(buf)", ARG5, sizeof(struct vki_statx) );
> }
> POST(sys_statx)
> {
> --
> 2.17.1
>
|
|
From: Julian S. <js...@ac...> - 2020-01-02 09:48:48
|
Ryan, I am seeing this problem also when running Gecko now, as compiled with rustc 1.40. > `statx` is a relatively new system call, only appearing in Linux 4.11. > Rust uses a trick where it calls `statx` with two NULL pointers to see > if the kernel/glibc support it because it's faster than calling it with > a real filename. If it returns `EFAULT` the system call is supported, > otherwise it returns `ENOSYS`. The comments in the Rust source code > imply this is a known trick. Can you point me at the comments in the Rust source code? I read the man page for statx pretty carefully, and saw nothing there implying that NULL is an acceptable value for the |filename| argument. I also didn't see anything like that in the kernel sources (but I could easily have missed it, it's a twisty maze in there). J |
|
From: Tom H. <to...@co...> - 2020-01-02 11:01:41
|
On 02/01/2020 09:48, Julian Seward wrote: > Ryan, I am seeing this problem also when running Gecko now, as compiled > with rustc 1.40. > >> `statx` is a relatively new system call, only appearing in Linux 4.11. >> Rust uses a trick where it calls `statx` with two NULL pointers to see >> if the kernel/glibc support it because it's faster than calling it with >> a real filename. If it returns `EFAULT` the system call is supported, >> otherwise it returns `ENOSYS`. The comments in the Rust source code >> imply this is a known trick. > > Can you point me at the comments in the Rust source code? I read the man > page for statx pretty carefully, and saw nothing there implying that NULL > is an acceptable value for the |filename| argument. I also didn't see > anything like that in the kernel sources (but I could easily have missed > it, it's a twisty maze in there). Well it sounds like it's relying on side effects of the implementation. No doubt the kernel will try to call copy_from_user or something similar on the filename argument and that will trigger EFAULT if the address is not a valid address in the processes address space, which NULL won't be. So EFAULT means the system call is implemented as the kernel has tried to access the filename, and ENOSYS means it isn't implemented. You could do much the same thing with any system call that takes a user space address as an argument. Tom -- Tom Hughes (to...@co...) http://compton.nu/ |