Proposal: Security Working Group


That’s fair. @Tom-Phinney, if you want to keep discussing, shoot me an email or open a new thread? This is definitely a worthwhile conversation to have, and you raise some good points.


Given so many people interested, y’all might want to ask for a working group channel on Discord and/or open a channel on IRC.


Yeah, I’m gonna need to figure out administrivia/logistics for this and a number of other questions. That’s definitely an option.


LLVM supports sign-extending an i1 into an iN, if you need help with this open a rust-lang/rust issue and cc me. I can try to expose the intrinsic that does this in core::intrinsics so that you can try it in nightly and see if it solves your problem.


I am interested in participating in this WG as well. I think that the main focus of the WG should be establishing crate signing and reviewing infrastructure. (e.g. see RFC 2474) On cryptography crates front it’s less clear for me that goals should WG have. Even for low-level we have several convergence points: RustCrypto, ring, dalek crates, OpenSSL/native/sodiumoxide bindings. Every project has it’s own approach and priorities, so I think it will be a bit hard to coordinate work in this space. Maybe starting point can be reviewing existing crates and formulating ways to improve them. Ideally crates should be interoperable via shared traits (see RustCrypto/traits), but I am not sure if other projects are willing to depend on such crates. (maybe dropping generic-array in favor of const generics will help here a bit)

As for communication platform I personally would prefer to use IRC or Zulip instead of Discord.


This is a great idea. I would love to join this WG :star_struck:


Yes, please no Discord.


I can contribute a few hours a week to the WG. I’d prefer an async communication platform as I’m in the UTC+1 timezone but otherwise I don’t have a strong opinion.


Is this opaque to the optimizer?


No, it is just an operation, like casting an i32 to an i64.

Whether such operations are opaque to the optimizer is kind of orthogonal to the operation itself. You can make any code un-optimizable by using, depending on what “level” of disabled optimizations you want: #[cold], #[inline(never)], the LLVM optnone attribute, inline asm!, etc.


Folks here may be interested in this proposal I just made for a process around the Unsafe Code Guidelines.


I’ve been doing security-related work on Rust lately on my own and I do not intend to stop, so I’d volunteer for the WG.

Oh my god, YES.

Performance seems to be a common reason, and a guide on getting safe code go fast (and diagnosing why it doesn’t) is badly needed. I’ve already argued this in more detail in my “Auditing popular crates” post.

Based on my experience with auditing Rust code so far, I can suggest the following actionable work items:

Plus a bunch of other, less critical things that I don’t want to list right now.

But the guide to replacing unsafe code with safe equivalents would be my #1 priority in this endeavor. Just to get the ball rolling and have something actionable, let’s think how the use of unsafe in Claxon could have been avoided so that this bug would have been prevented.


I would love to volunteer


Yeah, I’m a big fan of this approach. I’ve been working on something that I hope to eventually publish to the community once we get enough experience with it on Fuchsia that is in this vein. It’s worked really well for us, and I expect that the community will be able to get a lot of mileage out of that general approach.


The problem isn’t with converting i1 to iN (or u1 to uN), it is with realizing the Boolean result of a hardware comparison operation as an i1 or u1 in constant time. It is this process that usually causes LLVM codegen to output conditional branch instructions which have timing-observable side effects.

Many instruction-set architectures (e.g., RISC-V, ARM Cortex M, ARMv8 ) provide a way to materialize a Boolean result of a comparison directly in a register, enabling crypto algorithms to generate a bit mask of 0 or -1 and thus operate in constant time. (This approach is too inefficient for general use.) We need to have a way to annotate crypto-sensitive comparisons for MIR so that it has LLVM and other backends generate constant-time compare-to-Boolean code sequences via architecture-specific intrinsics, rather than generating conditional-branch instructions around loads of an immediate 0 or -1. That is the point I failed to make clear in my earlier post.


This is actually how most FFI crates work in practice today. (And I consider it good practice.)


Good to know. This was my first stab at FFI, so I was pretty unaware of the prior art, so I didn’t realize it wasn’t new lol. Do your research, kids.


To more forward with the WG I suggest starting a discussion on a structured debate platform such as Kialo regarding the scope. This thread is already getting unwieldy, and we’ve only just started.

Some like that would also be helpful to decide on a real-time communications platform to use, if any.


Ah! The only semi-reliable way that I know of to control whether conditional branch instructions are used in LLVM is to use the likely/unlikely intrinsics (that’s basically all they do).

We need to have a way to annotate crypto-sensitive comparisons for MIR so that it has LLVM and other backends

Does LLVM support this? I can’t find any attributes for this in the lang ref.


LLVM supports conditional compare of a pair of integer or float scalars or vectors, generating an i1 or N x i1 result

- <result> = icmp <cond> <ty> <op1>, <op2>
  yields i1 or <N x i1>:result 
  where cond = {eq, ne, ugt, uge, ult, ule, sgt, sge, slt, sle}
  and the prefix `u` means "unsigned" while the prefix `s` means "signed".

- <result> = fcmp [fast-math flags]* <cond> <ty> <op1>, <op2>
  yields i1 or <N x i1>:result
  where cond = {false, oeq, ogt, oge, olt, ole, one, ord, ueq, ugt, uge, ult, ule, une, uno, true}  
  and the prefix `o` means "ordered and …" while the prefix 'u' means "unordered or …".

Many Rust Tier 1 ISAs support the scalar integer compares and some variety of the float compares in single instructions. Some earlier ARM ISAs (e.g., Cortex M) require a cumbersome multi-instruction sequence. Other ISAs used in IoT devices might not have any support at all.