For the best experience on desktop, install the Chrome extension to track your reading on news.ycombinator.com
Hacker Newsnew | past | comments | ask | show | jobs | submit | history | jcalvinowens's commentsregister

It's unbelievable and it's only getting worse.

A 2x32GB DDR5 kit I paid $150 for 11 months ago costs $910 today from the same retailer. A 2x16GB DRR4 kit that was $105 last year is now $230.

The RAM alone in my newest machine would sell for over double what I paid for the entire machine one year ago.


I have been wondering about selling one of my 32gb DDR5 sticks and use the money to buy something else. I don't think a gaming pc really needs more than 32gb ram anyway.

There's a tradeoff here people often ignore: how much does the power consumption increase? In my experience, you end up using more total power because the SIMD instructions are so much more power hungry.

In the cloud, you don't pay the power bill and you have no reason to care. But it's not always like that.


The waymos are so consistently badly overpriced I've stopped even bothering to look. Nobody I know rides them! But they have riders more than half the time I walk by them, so clearly they're making money off somebody...

Yeah. It's becoming unbelievable how different the prevailing opinions on this site are from those of real people I know and work with. That's always been true to some extent... but good lord, it's like reading the news in a parallel universe right now.


As others have noted, this usually happens because both sides wrote data and one side didn't read it before calling close().

Here's a little reproducer: https://gist.github.com/jcalvinowens/da57edda9a01ca9f4c4088a...

    $ gcc -O2 test.c -o test
    
    $ strace -e socket,connect,write,accept,read,close ./test --rx        
    <...>                                                                           
    socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3                                                                           
    accept(3, NULL, NULL)                   = 4                                                                            
    close(3)                                = 0                                                                            
    read(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
    <...>
    read(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
    read(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 3035
    read(4, "", 4096)                       = 0
    close(4)                                = 0
    +++ exited with 0 +++

    $ strace -e socket,connect,write,accept,read,close ./test --tx
    <...>
    socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
    connect(3, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
    write(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 600000) = 600000
    close(3)                                = 0
    +++ exited with 0 +++
...versus:

    $ gcc -O2 -DWRITE_TO_SOCKET_BEFORE_READ test.c -o test
    
    $ strace -e socket,connect,write,accept,read,close ./test --rx
    <...>
    socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
    accept(3, NULL, NULL)                   = 4
    close(3)                                = 0
    write(4, "\250\3\0\0\0\0\0\0\250\3\0\0\0\0\0\0$\0\0\0\0\0\0\0$\0\0\0\0\0\0\0"..., 4096) = 4096
    read(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
    <...>
    read(4, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 997
    read(4, 0x7ffd45c2d3c0, 4096)           = -1 ECONNRESET (Connection reset by peer)
    <...>
    +++ exited with 1 +++
    
    $ strace -e socket,connect,write,accept,read,close ./test --tx
    <...>
    socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
    connect(3, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
    write(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 600000) = 600000
    close(3) 
    +++ exited with 0 +++


Does anybody else remember the Excel spreadsheet with a bunch of drop down menus that fed 1kloc of embedded visual basic to generate a C function to program the STM32 clock registers based on your selections? Top ten silliest things I've seen in my career for sure...

Related, I have a little end-to-end example of a piece of hardware with an STM32 running bare metal firmware like this: https://github.com/jcalvinowens/ledboard


Both major compilers yell at you for this nowadays... it's pretty unforgivable IMHO for somebody to be asking it as an exam or interview question if the right answer isn't "undefined":

    <source>:5:10: warning: multiple unsequenced modifications to 'a' [-Wunsequenced]
        5 |     a = a++ + ++a;
          |         


    <source>:5:7: warning: operation on 'a' may be undefined [-Wsequence-point]
        5 |     a = a++ + ++a;
          |     ~~^~~~~~~~~~~



Worker processes are forked from the master, which means they receive the same memory layout. You get unlimited crashes against the worker. There's probably a way to exploit that to get a read oracle. At the very least this is a reliable denial of service.

Depth First's full writeup: https://depthfirst.com/research/nginx-rift-achieving-nginx-r...


Sure, but I think the github README ought to make it more clear the POC as-is doesn't work against nginx on any current Linux distro.


So you're not vulnerable to script-kiddies running the published PoC. Still probably vulnerable to to a sufficiently-motivated attacker.


I doubt it: aslr is not as easy to break on modern Linux as everyone in this thread wants to pretend it is. And anybody who actually cares so much about security that a compromised web frontend is the end of the world should be doing other things which would additionally mitigate this...

I know they claimed they can bypass it: if that's true, they should publish it. The forking nature of nginx is uniquely bizarre and vulnerable, and I strongly suspect that's the only way they're pulling it off. I feel like that's the interesting thing here, not the buffer overrun.


Apache used forked processes; I don't think that's unique or a particular issue. NGINX uses async io to handle requests, which is a substantial upgrade from Apache; that's why it's performant.

Memory corruption vulnerabilities are possible whenever a language is used that performs copies of data across buffers without in-language guards.

This vulnerability does not require knowledge of the memory layout to generate worker crashes against a system with vulnerable configurations.

The vulnerability is not the end of the world. System administrators will upgrade nginx with the security patch when it's released across most distribution paths (right now it's available only on unstable Debian for example). In the meantime sysadmins will likely remove the vulnerable directives from nginx configs.


> Apache used forked processes; I don't think that's unique or a particular issue.

Of course it is... in a typical threaded daemon, the threads have randomized stack addresses. Exactly as you observed, you get unlimited tries because nginx dutifully restarts the worker process with the same literal stack address every time it segfaults. I'm willing to bet the ASLR break they claim to have relies on that, but I'd be happy to be proven wrong if they publish it :)


This a heap exploit. Threads share heap access with the main process.


I mean... you're missing the forest for the trees, but yes I meant "address space" generally not "stack" specifically. The nginx threads are forked, it would not be that terribly complex to set up a heap with a new random address base in each worker (the only real complexity is dealing with heap allocations which happened before fork()). But the stack matters too, generally moreso.


In your software, you set up a new heap for every pthread? I have never encountered this design pattern and would like to learn more.


If the workers weren't forked, the entire process would die to the SIGSEGV, and when it restarted the heap would be at a new address because of ASLR. This exploit couldn't work against a threaded daemon for that reason (only one guess).

In a world where they are forked, having a randomized heap base in each worker would also defeat the brute force approach. Instead of just fork(), it could execve() itself with some arguments that tell it to be a worker and where to find its brain, that effectively do an ASLR for each worker.


That's a reasonable solution.


Apache actually has had multiple modules for its concurrency for many years. The event and worker multi-processing modules use threading rather than forking.


My employers have generally been fine giving me blanket permission to contribute to specific open source projects.

The framing matters: don't say "can I please do some charity work because it makes me feel good".

Say, "can I have your permission to get free rigorous review from experts in my field, and zero out all future maintenance costs for your company by contributing my fixes to the upstream open source project?"

Because that's really how it is. No employer of mine has ever said no to that. It is entirely in their interest for you to do this, you just have to help them see it.


I'm a little sad that I got laid off from a previous job for a variety of reasons, but one big one was that there were discussions of letting me open source some very big changes I had made to the Kafka Streams library.

I rewrote a lot of stuff while keeping the API mostly compatible, focusing on emphasizing non-blocking IO with backpressure semantics available if necessary. It was really cool and enabled a lot of interesting stuff involving the state store and mixing+matching blocking and non-blocking IO in a way that was still relatively performant. I think it was really neat and it's one of the projects I am most proud of because I was able to squeeze out performance in a lot of places that were non-obvious.

I was pushing to allow us to release it to Github and/or make a PR to the upstream Kafka Streams project, but sadly they did layoffs before that was completed and afterwards there was really no "champion" to do that, so it's stuck in proprietary land.

I might still do it from scratch and FOSS it, it's been long enough to where I think I wouldn't get in trouble if I rewrote it and released it (there weren't any patents or anything attached to it), and there are a few things I'd like to change anyway (like getting rid of the dependency of Vert.x). Maybe if I ever get a week off I'll do that.


Fixing a bug in something open-source should be acceptable to most employers. However, if new functionality is being added, then it becomes an entirely different conversation.

I think it is good that you were taking the legal + compliance sign-offs before pursuing it.


When I worked at Apple, they were extremely strict about contributions to FOSS stuff, even on your own time, even for simple stuff like bugfixes or opening a Github issue.

I am sure they have their reasons even if I don't agree with them, but it's made me very cautious about making PRs and the like while working at BigCos and making outside contributions to FOSS stuff.

This even more so, though, because of course I was doing it on company time, so I wouldn't really blame them for wanting to audit stuff to ensure I'm not divulging company secrets and the like.


> even on your own time, even for simple stuff like bugfixes or opening a Github issue

During a recruitment process with a company a few years ago, they quite early asked for my GH profile and complained that I hadn't much content available.

Later, they asked me to do a small exercise and put it on my GH account.

When they sent me the contract, there was a clause telling that I would work for them exclusively and would not be allowed to contribute to anything else than company projects, even in my own time.

I didn't signed, and every person in the process seemed unable to understand what was wrong.


fortunately that's illegal in many jurisdictions, but i still would not sign unless they removed that passage.

i had one contract where i was able to replace the standard "we own all your work" passage into: "all your work will be released under the GPL"


This would be amazing to see upstreamed! I did some similar work for optimizing batch calls for the Quartz Scheduler. I left before it got merged, but was able to follow up and get it in as it was already PR'd.


Yeah, as I said I wouldn't mind reimplementing it anyway. I still more or less remember what I did so I don't think it would be too hard for me to reimplement if I get enough free time.

Kafka Streams is one of those things that I think is like 95% cool, but there are some design decisions I have mixed feelings on. One big thing is that while it does give an API for making new state stores out of the box and it's not too hard to write that, it is all dependent on blocking IO. This isn't that big of a deal with the built in RocksDB store because the latency isn't that high for it, so you can get away with everything being blocking, but if you want to substitute another store (e.g. Redis or even something like PostgreSQL), the naive version has you dealing with round trip latency for every item for a join, which can two or three orders of magnitude more expensive.

Less naively you can implement batching and the like in your driver, which is what my first version did, but you do eventually have to add blocking, and the Kafka Streams library doesn't really utilize virtual threads so you're paying the full cost of it at the end. Eventually I just found it more elegant to make Kafka Streams non-blocking-aware and adding built-in semantics for batching to automatically amortize the cost of these things.

Anyway, sorry, just kind of miss working on that project. I really should redo it.


I miss working at a place which allowed this.

Some employers get tangled up in just the legal review process.

Once I asked permission to submit a patch to a project and it had quite an interesting email trail. It came down to a single question: if the patch was written during hours billed to a customer for the purpose of fixing a bug in a deliverable product, and the library being patched had to be recompiled and delivered with the source code, and the contract states that all work and intellectual property associated to the product would be transferred to the customer, do we have authority to release the patch in the public domain?

Legal didn’t want to answer it.


The customer would probably prefer that you released it - that would mean next time they need a change the previous is up streamed.

Note that the resulting patch is almost assuredly not public domain and you should never use that term.


I think that's a generally good approach and a fantastic example of framing things professionally but also doesn't fix the core of the problem, which I see problematic if leadership of an engineering-focused company doesn't understand immediately.

Luck with your employer also plays a big part in how you approach this too.


“Sure, let me run this through the compliancy team. Just to make sure there’s no intellectual property infringement. Which repository and issue, exactly?”


it hurts how true this is


Yet again my plans for a productive morning have been derailed by an excellent new write up from Dmitry :)

That hand rolled DAC for the touchscreen with the eight gpio lines is hilarious.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search:

HN For You