A Memory Safe Implementation of the Network Time Protocol
memorysafety.org
memorysafety.org
Unfortunately the server is relatively easy to build. The client, however, is where a LOT of the intelligence and difficulty lies.
You need something to get a list of servers, and maybe update the list overtime (if you're using a dns name).
For each server, you need to poll to accumulate a list of delays and offset. If you want to make the delay precise, you can try to get the NIC to timestamp the NTP packets. Once you've got sufficient samples from a server, you can use a regression to approximate the time offset and frequency offset for that server.
If you've got more than one server, you can choose one to follow (ala the ntp reference implementation) or merge the data from some selection. This is kind of tricky, but there are many examples to choose from. Some implementations use metrics from multiple servers to try to estimate how much of the delay is asymmetric and use that to enhance the clock precision; but the reference implementation didn't do that and most people didn't mind.
Once you've figured out which time and frequency offsets to do, send it to the OS via settimeofday and ntp_adjtime. This is a bit trickier if you don't want to step the clock, but you can calculate a frequency offset to slew the clock in the direction you want over the time you find acceptable. Reference ntp drops old measurements after an adjustment, but you can also scale them by your adjustments and keep using them.
You might want to have some feedback loop to adjust your polling rates, but either way.
None of this code needs to be particularly fast either. Ideally, very little in between timestamp and send, and receive and timestamp (NIC timestamping helps tremendously here, if that's possible); and you also want to have a minimum of delay during offset operations too. But the protocol parsing, and offset calculations can take as long as you like.
I've got a one-shot Erlang ntp client in 108 lines of Erlang, and 50 lines of nif (which is mostly unpacking the arguments) for an unpublished hobby os. It's not perfect, but it does pretty ok. If it ran continuously, it would probably meet or beat reference ntpd. Reference ntpd does a whole lot more cool stuff, of course.
It might be easier to validate the code in their repo, but I feel like they are ignoring the effort that would be needed to validate all of the very large number of dependencies.
Were you at all concerned when you discovered that the sources come from http-only servers and only have un-signed md5's for checksums?
Did you find the support for HP-UX distracting?
It is easier to report a security issue to ntpd or chrony instead of creating a new one.
How do you know they are unsafe? Have they been audited and memory un-safety been found? I don't understand why the Rust community automatically assumes there are always memory safety issues with C, for example. I get that it's possible to write unsafe programs in C, but not all programs are automatically unsafe just because they are written in C.
I need to do more research, because I don't actually trust that just writing a program in Rust will result in total memory safety, so these are actually questions I want answers to, not just me trying to attack Rust or anything. Thanks!
I would say I don't stand on the side of "rewrite nothing", but I'm more of a realist here, in that we absolutely cannot "rewrite everything" perfectly in a memory safe language, and we should first determine if a particular tool should be rewritten in a memory safe language by doing some analysis and testing on that tool.
Certainly, even though I know no Rust and am not an expert in memory safety, I would say that in the future we should try not to write totally new software in memory unsafe languages, but I'm not everyone so I can't make that rule and ensure it sticks.
Seriously, I would love to see a succinct explanation for the "rewrite everything" philosophy, but it seems religiously dogmatic to me so far and has done the opposite of convince me to use Rust (or another memory-safe language).
On the other hand, the "statically typed language" community has done a great job of convincing me that I should be using statically typed programming languages by showing many examples of where typing would help me in my day to day work, and now I like using Go a lot and I avoid tons of issues I had with Python in the past.
I'm definitely not debating that using better languages is better, but what I am saying is that some tools written in C have been effectively tested in the real-world by being on billions of machines and being used millions of times per day. I am not totally sure, but I think if there were major issues with the current NTP implementations we would probably have found them by now? Maybe not! But, in any case, rewrites need to be more carefully considered, planned, and executed than just some people I don't know writing a new NTP in Rust and stating it's fine to use for 80% of cases.
Thanks for having a nice discussion with me, I think I am a bit more convinced that we need to rewrite some stuff, but perhaps also more convinced that we need to do a better job of picking what to rewrite and why!
The point I am actually trying to make is that memory safety is not the only consideration for security and safety. If you make a memory safe NTP and there turns out to be bad logic inside that code that does something allowing a security hole, then that's just as bad, if not worse, than using the decades-old software that did not have that bad logic, because that software has been tested in the real world day in day out for DECADES.
I trust (somewhat) that Rust isn't going to allow unsafe memory access. I don't trust that Rust programmers can write code with no bugs that's better than a tool that has been refined over generations of programmers. Memory safe programming is a tech solution to a human problem (human imperfection).
Again, new projects should be written in a memory safe language, but that's a whole other topic, IMO.
I used to work in incoming quality inspection, I know human reviews are at best 85 percent accurate. I’m arguing that decades of hammering on those old as hell programs have done the reviews for you.
I'm not stamping my feet demanding you track down a Rust web browser. But the thread started with someone asking what the point of a Rust NTP daemon was. I think that's been amply answered now.
Are you just ignoring the NVME kernel driver dev who said literally the same thing about a quick naive implementation that is nearly as performant without optimization as the one that has been in tree and tuned for years?
This insistence on naysaying and defending a categorically indefensible language is baffling to me. How many major companies and products have to move to Rust and adopt it? Do y'all really convince yourselves that everyone is just in some hype train? Is this what it's like to not being able to inspect a technology and disambiguate hype from something real?
Importing drama from a random thread into a Show HN is pretty rude, and you shouldn't do it again.
Not to me! I'm happy with the discussion here, and will participate as long as you keep providing opportunities to point out (read: preen about) other problems with memory-unsafe software.
But it's super rude to the person who submitted their code to "Show HN". The rules on "Show HN" aren't the same as the rules for the rest of the site, because people are vulnerable when you're sharing new work. This particular person wasn't submitting their "rm with trash" program as part of an argument against memory-unsafe software. For all we know, they just like Rust, which is a legitimate reason to write in Rust. Further, approximately nobody in the industry is worried about whether "rm" is implemented in C or Rust. Your dig had nothing to do with "rmt" and everything to do with wanting to score points on this thread.
You might consider apologizing to the "rmt" person.
† slightly
Gonna blow your mind when I tell you every single coreutil on my system is built with Rust and moreover nearly every program on my system was BUILT with that Rust-built coreutils.
Amazingly emulating some existing program behavior in Rust is easier than writing safe C! Who would've guessed? (besides eeveyone else watching and betting on Rust for the past 8 years)
Security vulnerabilities caused by memory safety errors can be an indication.
The number of CVEs doesn't necessarily indicate the number of errors in the code, or whether or not something is secure, since there are a lot of factors at play. A project with many CVEs could be a good sign since it means people are actively looking for and reporting issues for example. Alternatively a project with few CVEs might have a ton of hidden bugs.
It's not a perfect measure for sure, but it can at least prove that there are real world memory safety bugs that can have disastrous effects if left unfixed.
- 8 were found within the project itself (mostly by me)
- none are memory-safety issues in the NTP-specific code
- the last memory-safety issue is from 2015 and it was in the custom management protocol (exploitable only by authenticated users), which was since then greatly simplified and made stateless
The project now has an excellent fuzzing coverage, it was audited, and I'm quite confident there are no remotely reachable memory-safety issues. I'll buy you a drink if you find one :).
NTP as a network protocol is extremely simple. There is no complex data, almost everything has a constant length. A minimal server+client implementation can be written in a few hundred lines of code. I wrote one in Rust, but the reason was server performance, not security.
Most of the complexity related to NTP is on the client side, in the processing of measurements provided by NTP. I don't think the language matters much here. However, if major operating systems will start switching to services written in Rust, I don't see a reason why chrony couldn't be rewritten in Rust, first the small parts related to networking and later everything.
What C project is safe, exactly? You imply that the default almost is churning out safe C, so what projects with "competent" coders is producing vulnerability-less C code bases? I'll not be holding my breath because everytime, there's never an answer. My favorite person who spouts this off has multiple projects that have segfaulted from C memory programming related bugs.
Maybe, like, validate the basics of Rust functionality instead of constantly just casting doubt and aspersions on something while offering really weak defenses of what you justhl happen to be conditioned to.
You folks are the reason no one likes Rust people and Rust adoption is lower than it should be; try being human for once.
That's vague. What do you mean specifically? Hostile nodes joining the pools? Any issues with the protocol? Something else?
Properly configured, with sufficient upstream time servers, etc... it's still pretty robust against DoS attacks and evil maid attacks, so you'll have to do some work to trick clients into following your fake NTP server. And it will be hard to hide what you're doing while you do it.
It took a while, but I think we've actually solved that security problem with NTS. Now we just have to get the vendors and the community to support and deploy NTS widely.
The more your clock is skewed, the more often you need to check to see how badly it's skewed and apply whatever corrections are necessary.
That said, I'm a big fan of running SNTP as a client, where you don't need the full power of the NTP protocol. There's no sense running a full blown NTP client on most systems.
I like the idea of memory safety, but that's just one category of potential security vulnerabilities. If Rust can solve for that and also give me other benefits like higher speed, then I'm all for it. But you have to give me a lot of good reasons, or a hell of a good single reason, if you want me to toss out everything and replace it with Rust. And IMO, memory safety alone is not a good enough reason for most use cases.
Additionally, the intersection of people who are interested in working on low level system daemons and people who prefer Haskell/OCaml must be pretty small compared to Rust.