HNHacker News
TopNewBestAskShowJobs

jcalvinowens

2,705 karma · joined October 25, 2013

calvin@wbinvd.org github.com/jcalvinowens

I do not use LLMs for writing comments at all.

submissionscomments
jcalvinowens··on Ask HN: Who wants to be hired? (September 2026)

  Location: Bay Area, CA, USA
  Remote: Yes
  Willing to relocate: No
  Technologies: C, C++, Linux, drivers, embedded, HPC, networking, video, radio, yocto
  Résumé/CV: https://github.com/jcalvinowens/misc/blob/main/resume/resume.pdf
  Email: calvin@wbinvd.org
I solve technical problems in exchange for monetary compensation. I do a little bit of everything: https://github.com/jcalvinowens

I'm not considering full time roles at this time, only contract work. Thanks.

jcalvinowens··on Hardware backdoors in some x86 CPUs
A much better title would be "A hardware backdoor in a historical VIA x86 CPU".
jcalvinowens··on Why some people mow a lawn better than others
You stand to the side and pull it with one arm
jcalvinowens··on Civilian plane crash in New Mexico tied to military GPS blocking
The preliminary NTSB report: https://data.ntsb.gov/carol-repgen/api/Aviation/ReportMain/G...
jcalvinowens··on Why some people mow a lawn better than others
A lawn mower cuts grass whether you push it forward or pull it backwards: my trick when I was a kid was just to push and pull it back and forth across the lawn without changing the direction it faced at all.
jcalvinowens··on Ask HN: Who wants to be hired? (August 2026)

  Location: Bay Area, CA, USA
  Remote: Yes
  Willing to relocate: No
  Technologies: C, C++, Linux, drivers, embedded, HPC, networking, video, radio, yocto
  Résumé/CV: https://github.com/jcalvinowens/misc/blob/main/resume/resume.pdf
  Email: calvin@wbinvd.org
I solve technical problems in exchange for monetary compensation. I do a little bit of everything: https://github.com/jcalvinowens

I currently have 20 hours/week available. I'm not considering full time roles at this time, only contract work. Thanks.

jcalvinowens··on ESP32-C6 Power Consumption: Arduino vs. Zephyr vs. ESP-IDF Comparison
Remember that -Os is much much more aggressive in GCC than it is in LLVM, with LLVM you need to use -Oz to get the same result.

GCC has historically been a bit of a pig about -Os, my favorite example is on x86 where it will emit a runtime divide for a division by a compile time constant power of two because it saves a byte of text!

  int fn(int n)
  {
    return n / 8;
  }
..becomes:

  0000000000000000 <fn>:
   0:   89 f8                   mov    %edi,%eax
   2:   b9 08 00 00 00          mov    $0x8,%ecx
   7:   99                      cltd
   8:   f7 f9                   idiv   %ecx
   a:   c3                      ret
..versus:

  0000000000000000 <fn>:
   0:   8d 47 07                lea    0x7(%rdi),%eax
   3:   85 ff                   test   %edi,%edi
   5:   0f 49 c7                cmovns %edi,%eax
   8:   c1 f8 03                sar    $0x3,%eax
   b:   c3                      ret
jcalvinowens··on ECC and DDR5
> One thing that concerns me is the possibility of on-die ECC interacting with ECC on the motherboard and reducing it’s effectiveness

DDR5 on-die ECC detects and corrects one-bit errors. It cannot detect two-bit errors, so it will miscorrect some of them into three-bit errors. My understanding is that the on-die error correction scheme is specifically specially designed such that the resulting three-bit errors are mathematically guaranteed to be detected as uncorrectable two-bit errors by a standard full system-level ECC running on top of the on-die ECC. But I've never found a real authoritative reference that directly says that.

jcalvinowens··on AMD Readies Full Open-Source HDMI 2.1 Support for Linux
HDCP1 is completely broken, you can buy HDCP2.x strippers on amazon (they're often marketed as "converters").
jcalvinowens··on Benchmarking OpenZFS vs. EXT4 for My NAS
+1 for btrfs

If a NAS has a 1G or even 2.5G NIC, improving the filesystem performance is a waste of time... the network is the bottleneck. My N100 two-disk btrfs-raid1 NAS hits line rate on a 2.5G NIC, that's all that matters to me.

jcalvinowens··on Linux 7.1
It's actually faster than I remembered:

  {0}[calvinow@sousa ~/git/linux] git describe
  v7.1
  {0}[calvinow@sousa ~/git/linux] git clean -dffxq
  {0}[calvinow@sousa ~/git/linux] zcat /proc/config.gz > .config
  {0}[calvinow@sousa ~/git/linux] time make -skj32 tar-pkg
  './System.map' -> 'tar-install/boot/System.map-7.1.0'
  '.config' -> 'tar-install/boot/config-7.1.0'
  './vmlinux' -> 'tar-install/boot/vmlinux-7.1.0'
  'arch/x86/boot/bzImage' -> 'tar-install/boot/vmlinuz-7.1.0'
  
  real    0m56.539s
  user    18m41.863s
  sys     2m8.754s
jcalvinowens··on Linux 7.1
No, 90 seconds is the clean build time without ccache.
jcalvinowens··on Linux 7.1
> The build takes about 30-45 minutes

If you don't actually need all the drivers, you can use "make localmodconfig" to substantially reduce that. My local kernels build in 90 seconds on a 32-thread desktop machine :)

The kernel is a lot more stable than people think: I run the daily linux-next on my Debian stable gaming PC to look for bugs, and I don't find very many.

jcalvinowens··on A key remapping daemon for Linux
I love keyd, it uses uinput so it works on the vtty too.
jcalvinowens··on Magnetoelectric antennas could transform how underwater robots talk
https://arxiv.org/pdf/2411.09241
jcalvinowens··on What is the purpose of the lost+found folder in Linux and Unix? (2014)
XFS does use /lost+found, it calls it the "orphanage directory" and xfs_repair reparents children of corrupt directories there.

Based on comments in the kernel source, it seems like the userspace fsck for JFS and F2FS will also sometimes create /lost+found. There might be more that do.

jcalvinowens··on Moving beyond fork() + exec()
It is a weirdly common misconception that that fork() is cheap... it is O(N) on the size of the process, and it always has been.

Yes, it's copy on write... but there is a linear relationship between the size of the process and the number of page table entries required to represent it.

jcalvinowens··on 32GB of DDR5 now costs $375 – AI shortage continues to squeeze PC building
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.

jcalvinowens··on Building a Host-Tuned GCC to Make GCC Compile Faster
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.

jcalvinowens··on Waymo expands pause to four cities as robotaxis keep driving into floods
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...
jcalvinowens··on AI is just unauthorised plagiarism at a bigger scale
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.
jcalvinowens··on The occasional ECONNRESET
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 +++
jcalvinowens··on New Nginx Exploit
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.

jcalvinowens··on Bare-metal STM32: vector table, linker script, and startup code from scratch
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

jcalvinowens··on New Nginx Exploit
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.
jcalvinowens··on New Nginx Exploit
> 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 :)

jcalvinowens··on Int a = 5; a = a++ + ++a; a =? (2011)
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;
          |     ~~^~~~~~~~~~~
jcalvinowens··on New Nginx Exploit
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.

jcalvinowens··on New Nginx Exploit
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.
jcalvinowens··on New Nginx Exploit
The POC disables aslr: https://github.com/DepthFirstDisclosures/Nginx-Rift/blob/mai...
Page 1 of 30Next →