As a beginner I would have expected you to actually explain the trick Mr. Rust wizard used to trick the compiler. I understand that it tricks the compiler but how does the code do it?I think thats the most interesting part here. Do I also need to be a wizard to understand that trick?
The helper function has an implicit constraint on the lifetimes from the signature, i.e. that 'b >= 'a. We then typecast the helper function to set the extra lifetime to static while keeping the implicit constraint. Finally we call helper with a double reference to a static value (&&()) which is valid. The compiler is not smart enough to follow the implicit constraint through these steps and misses the fact that 'a in make_static must be static.
this video I found did a pretty good job explaining it, it involves function parameter lifetime contravariance (a sentence dreamed up by the utterly deranged) th-cam.com/video/vfMpIsJwpjU/w-d-xo.html
@BartoszGrabias My comment is an objection to the notion that fixing soundness bugs has any significant impact on supply chain security, not the use of "safe" by the Rust ecosystem.
Who have thought, the Rust compiler is not perfect. Need to test if clippy or clippy in pedantic form will notice this. Yes, its a bug. A bug does not mean the promise is a lie. Rust 2024 is around the corner with a few big changes, including the internal changes. I wonder if that would resolve this bug and why they wasn't able to solve it yet. Maybe it requires some complete rewrites of the backend?
If you can guarantee that this vulnerability cannot be accidentally enabled, then I wouldn't count it as a vulnerability. I feel like the backend dev must deliberately write the bad code to introduce the issue. And no, being included in malicious dependency doesn't count, because a malicious dependency can screw you over without triggering a memory corruption exploit.
As long as it is memory-safe in actual application scenarios, it is fine, and there is no need to care about the special cases that deliberately make it unsafe.
Is there anyone with good knowledge of how this works that can explain why the compiler accepted the helper function. I mean, it should have complained that the output of the function needed to live for at least 'a .
@@rui-lianglyu7221 I believe the issue is with the trait solver, but even if it wasn't the formal proof works with a model which doesn't have to correspond to what's actually implemented.
Can you talk about some other topic, features or framework of Rust, move on from that memory safe thing, it's repetitive. Build an actual project, that would be more helpfull than always talking about memory. No offense !!
@@letsgetrusty I would really like a very deep dive into tokio, not just simple stuff that is done in 7 minutes like the other video, but really meat content like how to limit the threads count, how to write your own futures, how to make more than 1 runtimes on dedicated threads, etc. This kind of control is needed to for example make a game that doesnt hiccup
@@letsgetrustysome sugestions: Async with tokio is super important to learn for some. The clap crate has lots of awesome features for building cli tools. Front end libraries like egui and iced would really benefit from more tutorials.
Why would a library(even a malicious one), one written by any competent developers ever use this way more complex ways to cast &'a to &'static instead of a actually unsafe code? And supply chain attacks? For what would you even use it for exactly? There are way easier way to do a supply chain attack then to use this bypass, like just writing unsafe code and by that matter you could just open a backdoor in safe-rust.
The current rust solver took a whole PhD to write I think. They have been working on a new one for a while to fix some long standing issues, don't know when it will be released.
Wrong. Its the other way, its actually hard to make those kind of bugs in Rust. The complexity helps with that. In fact its much easier to make these kind of bugs in simple languages, because there are no safe guards in C in example. No, just because Rust is complex and a bit complicated does not mean people will make more stupid bugs in the code. People make less bugs in the code with Rust, thanks to the safe guards.
It is complicated, but not too complicated. It can be too complicated for a simple task. For me Rust is actually super elegant due to static typing and very explicit handling of all types and branches in code. The amount of weird bugs I've gotten in Python just because a function could return or receive many data types is insane.
I don't disagree but may I ask you what parts of Rust do you have in mind when you say that it is too complicated? I am personally waiting for Julia to compile. It is the closest to a simple and fast language. After that there's Crystal (already super fast, but has OOP which to me is a minus), Codon (with Python syntax), mind you I'm talking about high-level languages that target LLVM and become as fast as Rust (as it also targets LLVM) and Go (for a non-LLVM comparison), and of course C and C++ (both of which have both LLVM and non-LLVM targets). I like Rust but I would like it more if all the lifetime stuff would go away.
Rustaceans won't agree, but people with brains inside their skulls will, that this completely invalidates the promise of safety. Safety isn't just protection from accidents, it's also protection from intentions. Of course, that doesn't mean this can't still be triggered accidentally, and it likewise doesn't mean that it's not likely given that a complete newbie could bang something like this out trying to get around a weird warning or error that pops up in the compiler. The only possible caveat that a Rustacean has here is if it *always* causes a noticeable bug, and it doesn't.
I wouldn't say that it completely invalidates the promise of safety, as it's clearly not the case. The fact that the compiler is imperfect does, by the way, imply that developers should always be mindful of what they are doing, as it's always been and should always be. As for the promise of safety, I think we can still consider rust to be by far the best we have ever had despite it not being perfect.
This is an exploit of a bug. Likely being solved with the next big update, where they rewrote the entire trait solver for years. And no, the language safety features is one thing (what Rust promises) and the intentions are another thing. Rust lang designers are not developing the intentions of the end programmer. In fact, Rust allows for unsafe code and has the unsafe keyword to mark such intentions. But that does not invalidate the principles of Rust itself.
@ Talk about cope. It's a 10 year old bug that is likely never going to be fixed because the developers of the language are making it up as they go along instead of planning things out. By the way, principles can't be invalidated by bugs, and this isn't a principle being invalidated, it's a promise.
@ They could not fix the bug, because it was deeply rooted in the system they were using. And they were working on the a replacement system for the trait solver, which is finally after years of work finished and will be released in one month.
@ Even if you're right, that'll still only plug one hole. For starters, they don't think that leaks are unsafe, so they don't prevent any of them, even the obvious ones. And you still have many classes of logic errors that aren't prevented in the slightest. Not to mention FFI because the majority of the world's code is still not written in Rust.
I compiled your code but it didn't compiled successfully instead it gave me an error as follows: ``` * Executing task: cargo run --package refcell --bin reference_cycles Compiling refcell v0.1.0 (/mnt/d/Pankaj Batham/Coding PlayGround/Rust Coding Practice/refcell) error: lifetime may not live long enough --> src/bin/reference_cycles.rs:86:12 | 85 | fn make_static &'static T { | -- lifetime `'a` defined here 86 | let f: fn(_, &'a T) -> &'static T = helper; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` error: could not compile `refcell` (bin "reference_cycles") due to 1 previous error * The terminal process "cargo 'run', '--package', 'refcell', '--bin', 'reference_cycles'" terminated with exit code: 101. * Terminal will be reused by tasks, press any key to close it. ```
"Memory safe" languages make it harder for actual programmers to fully understand what the code is doing. There is a reason it has no place in kernel space.
@Madinko12 if your language panics on memory allocation failure, no it doesn't. Wannabe kernel programmers shouldn't be breaking shit just to use their favorite language. Write a stable kernel in Rust first then we can have that discussion.
@@sxlg_32 there are safe wrappers for kmalloc already being used in the current Linux kernel. The fact that some piece of software mandates "memory-unsafe" code in some specific places doesn't imply "memory-safe" languages "have no place" in said software. Your fallacy is called "false dilemma", you may want to look that up.
@@sxlg_32They already wrote a whole driver in Rust??? I agree, panicking is a no go, but actually useful people didn't cry about it and solved the issue. Rust without panicks, crazy what actual problem solving can accomplish
I think in terms of Rust, it's not too hard to fully understand what Rust code is doing, the thing that almost nobody understands however is how the compiler chooses to accept and not accept the code, which is what leads to this kind of mistake in the design of the language
📝Get your *FREE 4-day Rust training* :
letsgetrusty.com/bootcamp
>one line
>looks inside
>multiple lines
my program is only one line! { second_main(); }
And he didn't explain it. It's some combination of implied lifetimes and variance. I feel uneducated
This library allows you do this in 1 line of code: crates.io/crates/fake-static
@ I have seen a very similar video on this exact thing maybe a year ago. I can't find the video. Is this a repost, or was it a different channel?
@@letsgetrusty lol. Those are the same multiple lines, just packed into a library
0:30 "this defect is surprisingly easy to understand if we just unpack this code a bit"
2:53 "this code is using some very complicated rust features"
You got me
Also "someone just figured out... 10 years ago".
Rest of the rusty owl
@@letsgetrustymy man is indeed rusty 😂
As a beginner I would have expected you to actually explain the trick Mr. Rust wizard used to trick the compiler. I understand that it tricks the compiler but how does the code do it?I think thats the most interesting part here. Do I also need to be a wizard to understand that trick?
You need to be at least a level 38 wizard to understand the trick. Jokes aside I agree with your point. Thank you for the feedback!
The helper function has an implicit constraint on the lifetimes from the signature, i.e. that 'b >= 'a.
We then typecast the helper function to set the extra lifetime to static while keeping the implicit constraint. Finally we call helper with a double reference to a static value (&&()) which is valid.
The compiler is not smart enough to follow the implicit constraint through these steps and misses the fact that 'a in make_static must be static.
this video I found did a pretty good job explaining it, it involves function parameter lifetime contravariance (a sentence dreamed up by the utterly deranged) th-cam.com/video/vfMpIsJwpjU/w-d-xo.html
This should be resolved with the new trait solver system
Can you provide a link to some info about it?
@@letsgetrusty hes capping
@@letsgetrusty Links most likely get deleted. In the Rust Compiler Development Guide there is a section 50.6. Next-gen trait solving.
@@letsgetrusty also check out issues in rust repo with label fixed-by-next-solver
which we will get approximately never
Absence of `unsafe` does not mean that a malicious dependency is safe (in the colloquial sense) to use. Safe Rust isn't sandboxed.
True, but in rust safe and unsafe have very well defined meanings, which are far from the colloquial sense :)
@BartoszGrabias My comment is an objection to the notion that fixing soundness bugs has any significant impact on supply chain security, not the use of "safe" by the Rust ecosystem.
@@gamekiller0123 Oh, okay, sorry, I misunderstood then. Fully agree on that point.
Who have thought, the Rust compiler is not perfect. Need to test if clippy or clippy in pedantic form will notice this.
Yes, its a bug. A bug does not mean the promise is a lie. Rust 2024 is around the corner with a few big changes, including the internal changes. I wonder if that would resolve this bug and why they wasn't able to solve it yet. Maybe it requires some complete rewrites of the backend?
clippy doesn't but miri does
Yes, they are in the process of completely rewriting the trait solver. This will fix some long standing bugs
If you can guarantee that this vulnerability cannot be accidentally enabled, then I wouldn't count it as a vulnerability. I feel like the backend dev must deliberately write the bad code to introduce the issue. And no, being included in malicious dependency doesn't count, because a malicious dependency can screw you over without triggering a memory corruption exploit.
Ah yes, the doohickey footgun
i think CVE-RS also mentioned this
As long as it is memory-safe in actual application scenarios, it is fine, and there is no need to care about the special cases that deliberately make it unsafe.
Is there anyone with good knowledge of how this works that can explain why the compiler accepted the helper function. I mean, it should have complained that the output of the function needed to live for at least 'a .
yeah I see *&static* I see a disaster
I thought Rust borrow checker has been formally proven to be sound (free of bugs like this)?
@@rui-lianglyu7221 I believe the issue is with the trait solver, but even if it wasn't the formal proof works with a model which doesn't have to correspond to what's actually implemented.
i think the formal proof proved only a subset of the language was sound
Amazing, I'm now going to use it everytime rust complains about lifetimes
Look as like they're not back checking the lifetime in a generic when they make it concrete. Or if they are it's not recursive.
Can you talk about some other topic, features or framework of Rust, move on from that memory safe thing, it's repetitive.
Build an actual project, that would be more helpfull than always talking about memory.
No offense !!
Sure! What topics would you like me to cover specifically?
@@letsgetrusty I would really like a very deep dive into tokio, not just simple stuff that is done in 7 minutes like the other video, but really meat content like how to limit the threads count, how to write your own futures, how to make more than 1 runtimes on dedicated threads, etc. This kind of control is needed to for example make a game that doesnt hiccup
@@letsgetrusty And another - lifetimes in structs, and the hell it brings, structs with 8 references and 8 lifetimes type of hell and how to manage it
@@letsgetrustysome sugestions:
Async with tokio is super important to learn for some.
The clap crate has lots of awesome features for building cli tools.
Front end libraries like egui and iced would really benefit from more tutorials.
Why would a library(even a malicious one), one written by any competent developers ever use this way more complex ways to cast &'a to &'static instead of a actually unsafe code? And supply chain attacks? For what would you even use it for exactly? There are way easier way to do a supply chain attack then to use this bypass, like just writing unsafe code and by that matter you could just open a backdoor in safe-rust.
2:57 **sideeyes** What the...
What kind of scenarios that requires you to write code like this?
Where is your discord link? If not, just create one!!
it's not working on my end . I use v1.83.0
damn since 2015 ! what takes them too long to just fix the damn thing
The current rust solver took a whole PhD to write I think. They have been working on a new one for a while to fix some long standing issues, don't know when it will be released.
Cve-rs
and then theres Box::leak() :D
Дякую, Богдане!
Interesting
Great
The problem with Rust is that it is too complicated. If something is complicated there is higher probability of making stupid bugs in the code.
this same reason doesn't prevent a ton of people using c, c++ etc.
Wrong. Its the other way, its actually hard to make those kind of bugs in Rust. The complexity helps with that. In fact its much easier to make these kind of bugs in simple languages, because there are no safe guards in C in example. No, just because Rust is complex and a bit complicated does not mean people will make more stupid bugs in the code. People make less bugs in the code with Rust, thanks to the safe guards.
It is complicated, but not too complicated. It can be too complicated for a simple task. For me Rust is actually super elegant due to static typing and very explicit handling of all types and branches in code. The amount of weird bugs I've gotten in Python just because a function could return or receive many data types is insane.
I don't disagree but may I ask you what parts of Rust do you have in mind when you say that it is too complicated?
I am personally waiting for Julia to compile. It is the closest to a simple and fast language. After that there's Crystal (already super fast, but has OOP which to me is a minus), Codon (with Python syntax), mind you I'm talking about high-level languages that target LLVM and become as fast as Rust (as it also targets LLVM) and Go (for a non-LLVM comparison), and of course C and C++ (both of which have both LLVM and non-LLVM targets).
I like Rust but I would like it more if all the lifetime stuff would go away.
@@thingsiplay I think bartek was talking about language bugs, and that this language bug exists because of rust's extreme complexity
Rustaceans won't agree, but people with brains inside their skulls will, that this completely invalidates the promise of safety. Safety isn't just protection from accidents, it's also protection from intentions. Of course, that doesn't mean this can't still be triggered accidentally, and it likewise doesn't mean that it's not likely given that a complete newbie could bang something like this out trying to get around a weird warning or error that pops up in the compiler. The only possible caveat that a Rustacean has here is if it *always* causes a noticeable bug, and it doesn't.
I wouldn't say that it completely invalidates the promise of safety, as it's clearly not the case. The fact that the compiler is imperfect does, by the way, imply that developers should always be mindful of what they are doing, as it's always been and should always be. As for the promise of safety, I think we can still consider rust to be by far the best we have ever had despite it not being perfect.
This is an exploit of a bug. Likely being solved with the next big update, where they rewrote the entire trait solver for years. And no, the language safety features is one thing (what Rust promises) and the intentions are another thing. Rust lang designers are not developing the intentions of the end programmer.
In fact, Rust allows for unsafe code and has the unsafe keyword to mark such intentions. But that does not invalidate the principles of Rust itself.
@ Talk about cope. It's a 10 year old bug that is likely never going to be fixed because the developers of the language are making it up as they go along instead of planning things out. By the way, principles can't be invalidated by bugs, and this isn't a principle being invalidated, it's a promise.
@ They could not fix the bug, because it was deeply rooted in the system they were using. And they were working on the a replacement system for the trait solver, which is finally after years of work finished and will be released in one month.
@ Even if you're right, that'll still only plug one hole. For starters, they don't think that leaks are unsafe, so they don't prevent any of them, even the obvious ones. And you still have many classes of logic errors that aren't prevented in the slightest. Not to mention FFI because the majority of the world's code is still not written in Rust.
This is why o don’t like rust, it looks absolutely overly convoluted, worse than lisp even
This code is convoluted on purpose and not something you would write.
oi stop with the lisp disrespect
I compiled your code but it didn't compiled successfully instead it gave me an error as follows:
```
* Executing task: cargo run --package refcell --bin reference_cycles
Compiling refcell v0.1.0 (/mnt/d/Pankaj Batham/Coding PlayGround/Rust Coding Practice/refcell)
error: lifetime may not live long enough
--> src/bin/reference_cycles.rs:86:12
|
85 | fn make_static &'static T {
| -- lifetime `'a` defined here
86 | let f: fn(_, &'a T) -> &'static T = helper;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
error: could not compile `refcell` (bin "reference_cycles") due to 1 previous error
* The terminal process "cargo 'run', '--package', 'refcell', '--bin', 'reference_cycles'" terminated with exit code: 101.
* Terminal will be reused by tasks, press any key to close it.
```
"Memory safe" languages make it harder for actual programmers to fully understand what the code is doing. There is a reason it has no place in kernel space.
Except that it has a place in kernel space.
@Madinko12 if your language panics on memory allocation failure, no it doesn't. Wannabe kernel programmers shouldn't be breaking shit just to use their favorite language. Write a stable kernel in Rust first then we can have that discussion.
@@sxlg_32 there are safe wrappers for kmalloc already being used in the current Linux kernel. The fact that some piece of software mandates "memory-unsafe" code in some specific places doesn't imply "memory-safe" languages "have no place" in said software. Your fallacy is called "false dilemma", you may want to look that up.
@@sxlg_32They already wrote a whole driver in Rust??? I agree, panicking is a no go, but actually useful people didn't cry about it and solved the issue. Rust without panicks, crazy what actual problem solving can accomplish
I think in terms of Rust, it's not too hard to fully understand what Rust code is doing, the thing that almost nobody understands however is how the compiler chooses to accept and not accept the code, which is what leads to this kind of mistake in the design of the language