❌

Lees weergave

Steinar H. Gunderson: Decompilation patterns, part 17: Loop rotation

Occasionally, you'll see code like this (after initial cleanup):

    var_v0_2 = crc & 0x80000000;
    do {
       if (var_v0_2 != 0) {
           crc = (crc << 1) ^ 0x1EDC6F41;
       } else {
           crc <<= 1;
       }
       var_a0 += 1;
       var_v0_2 = crc & 0x80000000;
    } while (var_a0 < 8U);

The thing with var_v0_2 is unnatural. GCC sometimes does these loop rotation tricks, seemingly to save registers (don't ask me how exactly it does). You want to un-rotate back into:

    do {
       var_v0_2 = crc & 0x80000000;
       if (var_v0_2 != 0) {
           crc = (crc << 1) ^ 0x1EDC6F41;
       } else {
           crc <<= 1;
       }
       var_a0 += 1;
    } while (var_a0 < 8U);

and then of course, you can clean up the rest:

for (i = 0; i < 8; ++i) {
    if (crc & 0x80000000) {
        crc = (crc << 1) ^ 0x1EDC6F41;
    } else {
        crc <<= 1;
    }
}

Last one tomorrow, I think.

  •  

Thadeu Lima de Souza Cascardo: Restricting device memory usage on Linux 7.3

Linux cgroups has been used for a while to group processes and control their access to certain system resources. One of those resources is memory, through the use of memcg. That control is dynamic, allowing for cgroups to setup a minimal and a maximal amount of memory, as well as low and high thresholds, which will control the reclaim process.

But what about device memory that is not available as system RAM? Memory that is not available to the Linux page allocator? One of those device memories is GPU VRAM.

That's where the dmem cgroup controller comes in. Introduced in Linux 6.14, it was first adopted by the Intel Xe driver. In Linux 6.15, AMD amdgpu driver also adopted it. In 7.3, it was adopted by nouveau.

Such a cgroup controller allows the system to be configured such that a workload, be it a browser, a game, or another GPU rendering process can have some minimal VRAM available. Or it can prevent one of these processes from using all VRAM, preventing your compositor from using it, for example.

Let's go through the system knobs that are available to control this and what's new in Linux 7.3.

dmem regions and dmem.capacity

Since a given system might have multiple GPUs, there might be multiple device memory regions. So, on dmem, each such region is described by a name. Every dmem cgroup setting file will contain one line per region. One of those files shows the capacity of each region in bytes and is present only in the root cgroup.

After enabling the dmem cgroup with the following command:

# echo +dmem > /sys/fs/cgroup/cgroup.subtree_control

One can inspect the capacity of any available regions by looking at dmem.capacity at the root cgroup:

# cat /sys/fs/cgroup/dmem.capacity
drm/0000:03:00.0/vram 8573157376

That shows that the GPU at PCI address 0000:03:00.0 has a 8176MiB VRAM dmem region.

dmem settings

When introduced at 6.14, the following settings were available.

dmem.current

In every dmem cgroup, including the root cgroup, the dmem.current is a read-only file that shows the current usage of each region by the given cgroup.

# cat /sys/fs/cgroup/user.slice/dmem.current
drm/0000:03:00.0/vram 292757504

Here, it shows that user.slice cgroup is currently using above 292 MB of VRAM.

# cat /sys/fs/cgroup/dmem.current
drm/0000:03:00.0/vram 311377920

Here, we can check that total system usage is above 311 MB.

dmem.max

Excluding the root cgroup, dmem cgroups can control the maximal number of bytes that can be allocated from a region by processes in that cgroup. If an allocation moves the usage above the max setting, it will be refused. In that case, the allocation might be attempted at system memory or it might trigger eviction, depending on the allocation parameters and the driver.

Here, the max value has special meaning, which is unrestricted usage.

# echo drm/0000:03:00.0/vram 536870912 > /sys/fs/cgroup/user.slice/dmem.max
# cat /sys/fs/cgroup/user.slice/dmem.max
drm/0000:03:00.0/vram 536870912
# echo drm/0000:03:00.0/vram max > /sys/fs/cgroup/user.slice/dmem.max
# cat /sys/fs/cgroup/user.slice/dmem.max
drm/0000:03:00.0/vram max

dmem.min

dmem.min, also not available on the root cgroup, will control the eviction process - when memory needs to be moved out of VRAM to make room for other VRAM allocations. If an object belongs to a cgroup which is using less than its min setting, it will not be considered for eviction. It effectively works as a hard protection such that the cgroup can use at least the minimal setting.

Given multiple cgroups may set a minimal value that exceeds the device memory capacity, it computes an effective minimal depending on the hierarchy.

dmem.low

While dmem.min works as a hard limit, dmem.low is a soft limit that will prevent eviction in case other objects from different cgroups are available for eviction. That is, the system will try to evict from different, possibly unprotected cgroups, before it tries to evict from a cgroup if evicting would leave its usage below the value set as dmem.low.

Recent developments in Linux 7.3

Some new changes have been recently introduced in the dmem cgroup controller and its integration with GPUs.

One of those is a new read-only file, dmem.peak, which was introduced to allow the peak usage of a region in a cgroup to be inspected.

Also, Linux 7.3 fixed certain scenarios where a given cgroup would not be able to allocate VRAM up to its minimal or low limits if other processes had already allocated most of VRAM, even though they had no such limits set.

Changing multiple regions' settings in a single write was possible before 7.3, but it was prone to failures which would not be reported to userspace and might have left the values partially updated. Starting with 7.3, only one region may be updated per write.

And, finally, prior to 7.3, setting dmem.max in a cgroup that was using more than the new setting would silently fail. Now, there is a mechanism that allows a reclaim mechanism to be triggered. That way, when a process writes to dmem.max and sets a maximal value below the current usage, it will wait (unless O_NONBLOCK is used) for the reclaim process to move objects out of VRAM until the usage gets below the maximal value. If that is not possible for some reason, the setting will still be in place, restricting further alloctions by that cgroup.

  •  

Russell Coker: Cixin Liu is a Bad Person

The Chinese author Cixin Liu [1] is most known for his book The Three Body Problem and it’s sequels. One of the main plot elements in the book is that every species in the universe is cool with genocide and willing to commit genocide as a preemptive strike against any star system found to contain intelligent life.

It’s not unreasonable to think that some planets may be by run societies like that, if one star system in 10,000 had a technological society and one society in 10,000 is run by depraved autocratic governments that would make 1,000+ planets in our galaxy that are run by genocidal groups!

To think that every single society wants to commit genocide at every opportunity says a lot about every person who makes such claims. If you believe that everyone wants to do something then it must be something you really want to do. If there’s something you really don’t want to do then you will be able to imagine a system of government where the majority of citizens vote against doing it.

Even in the more horrible parts of human history there hasn’t been a genocide comparable to destroying and entire star system, genocide is usually based on slavery and large scale armed robbery. To just commit large scale genocide with a side effect of destroying valuable resources without any investigation or attempts at negotiation just based on fear of others is an extreme that I don’t think humans have reached in history.

The Daleks are portrayed as a perverse extreme of xenophobia but even with the low budget SciFi trend of depicting aliens as mostly having a common belief system they managed to show some Daleks going against their system from time to time. Cixin Liu is a very talented writer but his attitude towards genocide has caused him to write SciFi with a major plot point that’s not great by Dr Who standards.

Overall his short stories are much better than the three novels he is most known for. But he shows his ass in some of them too. One notable example is a short story where a significant plot point is declaring a “right to sex” (for men) which involves government sponsored sex workers. A “right to sex” conflicts with a sex workers right to refuse sex for a potential client who is undesirable in some way. Regardless of opinions on whether sex work should be permitted I hope that the vast majority of voters in every jurisdiction can agree that sex workers shouldn’t be forced to do things that they don’t want to do.

Some writers like George Orwell create deliberately fictional scenarios that they hope to inspire opposition to bad ideas, I’m sure that many proposed laws have failed to get enacted after being described as “Orwellian”. But describing a fictional horror situation as inevitable is a way of driving support for such things. It’s particularly noteworthy when written by a citizen of a country that’s involved in genocide.

A possible counter argument would be “but he is living in a repressive country and can’t oppose his government”. But when Hergé (the author of the Tintin graphic novels) was threatened about the consequences of writing another book like King Ottokar’s Sceptre [2] he didn’t write books in favour of authoritarianism, he just avoided the topic by writing about visiting the moon instead. I don’t think that people living in China now should be expected to publicly oppose evil things done by their government, but when they go out of their way to support such things it’s their choice and we should note that they made that choice.

I’m not saying that people shouldn’t read his work as his short stories are definitely worth reading. But the Three Body Problem series really isn’t that good, he prevented many potentially interesting situations from happening by having every interaction between different species be based around genocide or the potential for it. Being a horrible person also made him a less capable SciFi author.

Related posts:

  1. Server Use Per Person I’ve just read Diego’s response to an ill-informed NYT article...
  2. Terrorists Inspired by Fiction The Tom Clancy book Debt of Honor published in August...
  3. Links August 2012 Google are providing some really good employee benefits including benefits...
  •  

Steinar H. Gunderson: Decompilation patterns, part 16: Tail reduplication

We're nearing the end soon, I promise. Here's one that I see all the time:

     ...
         } else {
             var_t0_5 = temp_a0_3 - 0x140;
             var_a2_5 = 0xA0 - temp_a3_5;
             goto block_45;
         }
     } else {
         var_t0_5 = 0xA0 - temp_a0_3;
         var_a2_5 = temp_a3_5 - 0x118;
block_45:               
         var_v0_3 = var_t0_5 + 0xA0;
         var_v1_4 = var_a2_5 + 0x78;
     }

So, eh, what's that goto doing there? What happened was that the compiler helpfully figured it could help with some tail deduplication; someone wrote the same code twice, and the compiler figured taking the cost of a branch was better than keeping it duplicated. (In a sense, it's the opposite of inlining. Ish.) In most cases, it's as simple as copying the block and then you can remove the label:

     ...
         } else {
             var_t0_5 = temp_a0_3 - 0x140;
             var_a2_5 = 0xA0 - temp_a3_5;
             var_v0_3 = var_t0_5 + 0xA0;
             var_v1_4 = var_a2_5 + 0x78;
         }
     } else {
         var_t0_5 = 0xA0 - temp_a0_3;
         var_a2_5 = temp_a3_5 - 0x118;
         var_v0_3 = var_t0_5 + 0xA0;
         var_v1_4 = var_a2_5 + 0x78;
     }

Sometimes, these are nested, with multiple tails goto-ing into each other, so in that case, you'll need to reduplicate multiple times. Make sure you actually come out on the correct side afterwards, though.

As an extra complication, the code is deduplicated not on the C statement level, but on RTL instructions, so if you're calling functions with five parameters of more (which requires pushing parameters onto the stack), m2c can get really confused and start throwing M2C_ERROR() at you on the receiving side because it's not clear at all where the parameters would be coming from.

  •  

Dirk Eddelbuettel: myman 0.12.0 on CRAN: Two new waves!

Another new and exciting version of our still-new package myman reached CRAN this morning, and has been built for r2u and on r-universe. The matching Python package has also been updated. The package offers twenty one hundred eighty four “My man …” posts by Kevin Kruse made on bsky during the summer of 2026. Each wave picked at one particular public persona. This package wrapse these up in the style of packages like fortunes or gaussfacts.

This release regroups two new waves of posts mocking, respectively, Peter Thiel and Michael Tracy, and make a small update to continuous integration. The short NEWS entry for this release follows.

Changes in version 0.12.0 (2026-10-18)

  • New waves eleven (100 posts) and twelve (100 posts) made last week; total is now 2184 posts

  • Small update to continuous integration

Courtesy of my CRANberries, there is also a diffstat report for the most recent release. More information is available at the repository or the package page.

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can sponsor me at GitHub.

  •  

Ludovic Rousseau: New version of pcsc-lite: 2.5.3

I have just released a new version of pcsc-lite 2.5.3.

pcsc-lite is a Free Software implementation of the PC/SC (also known as WinSCard) API for Unix systems. It provides an API for using smart cards and smart card readers.

Changes:

2.5.3: Ludovic Rousseau

18 October 2026

  • pcscd.service: preserve card sessions across polkit restarts

  • correctly decode all ATRs (fix the fix suggested by AI)

  • Fix authorization for uid > 65536

  •  

Steinar H. Gunderson: Decompilation patterns, part 15: Redundant if-for

Yet another way of writing for loops:

    var_a2_4 = ...
    if (var_a2_4 < 0x78) {
        ...
        do {
            ...
            var_a2_4 += 1;
        } while (var_a2_4 < 0x78);
    }

This extra if is merely there because the compiler wasn't able to prove that the variable didn't start below the bound, so it can't rewrite the while-do to a do-while without that extra check. So the rewrite still reads:

for (var_a2_4 = ...; var_a2_4 < 0x78; ++var_a2_4) {
    ...
}

possibly with the initializer skipped, if it comes from something complex earlier.

  •  

Dirk Eddelbuettel: RcppArmadillo 15.6.2-1 on CRAN: New Upstream

armadillo image

Armadillo is a powerful and expressive C++ template library for linear algebra and scientific computing. It aims towards a good balance between speed and ease of use, has a syntax deliberately close to Matlab, and is useful for algorithm development directly in C++, or quick conversion of research code into production environments. RcppArmadillo integrates this library with the R environment and language–and is widely used by (currently) 1370 other packages on CRAN, downloaded 49.4 million times (per the partial logs from the cloud mirrors of CRAN), and the CSDA paper (preprint / vignette) by Conrad and myself has been cited 735 times according to Google Scholar.

This versions updates to the 15.6.2 upstream Armadillo release made yesterday. It, along with 15.6.1 release we incorporated earlier, addresses only minor issues and should not present any user-facing changes. As usual, we did run full reverse-depdency checks against the over 1300 ackages, and did not find anything. As usual, we aim to accommodate the desired CRAN cadences for uploads and try not to exceed six in six months—so we did not ship 15.6.1-1 there. The package has also already been updated for Debian, built for r2u and r-universe, and will build shortly at CRAN for the different binary releases.

All changes since the last CRAN release follow.

Changes in RcppArmadillo version 15.6.2-1 (2026-10-16)

  • Upgraded to Armadillo release 15.6.2 (Medium Roast Cortado)

    • Faster inplace addition of eye() expressions

Changes in RcppArmadillo version 15.6.1-1 [github-only] (2026-10-02)

  • Upgraded to Armadillo release 15.6.1 (Medium Roast Cortado)

    • Fix for failures in pinv() when using the (non-default) "std" method

Courtesy of my CRANberries, there is a diffstat report relative to previous release. More detailed information is on the RcppArmadillo page. Questions, comments etc should go to the rcpp-devel mailing list off the Rcpp R-Forge page.

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can sponsor me at GitHub.

  •  

Steinar H. Gunderson: Decompilation patterns, part 14: Strength increase

Let's look at the entire loop from yesterday:

    u16 spE10;
    u16 *var_v0_2;

    ...

    var_t1_2 = 0x7F;
    var_v0_2 = &spE10 + 0xFE;
    do {
        *var_v0_2 = 0;
        var_t1_2 -= 1;
        var_v0_2 -= 2;
    } while (var_t1_2 >= 0);

What's going with the pointer arithmetic here? Why is it indexing out-of-bounds?

The first thing to notice is that m2c doesn't really take into account that arithmetic on pointers in C is multiplied by the size of the element. And obviously, spE10 is the root of some array. So corrected, this reads:

    u16 spE10[0x80];  // Modified.
    u16 *var_v0_2;

    ...

    var_t1_2 = 0x7F;
    var_v0_2 = spE10 + 0x7F;  // Modified.
    do {
        *var_v0_2 = 0;
        var_t1_2 -= 1;
        var_v0_2 -= 1;  // Modified.
    } while (var_t1_2 >= 0);

We saw yesterday how we should rewrite the iteration back to a for loop, but also, most likely, the pointer arithmetic here came from strength reduction; the compiler took a multiplication operation and rewrote it to a “weaker” operation (subtraction) since that's typically cheaper, at the cost of making the values dependent, an easy trade. So we can rewrite it back into multiplication:

    var_t1_2 = 0x7F;
    do {
        var_v0_2 = spE10 + var_t1_2;
        *var_v0_2 = 0;
        var_t1_2 -= 1;
    } while (var_t1_2 >= 0);

and now it's easy to see that the loop should read:

    for (i = 0; i < 0x80; ++i) {
        spE10[i] = 0;
    }

and then, of course, the array should get a better name.

Sometimes the loop counter will go backwards while the pointer will go forwards, which is also completely normal, especially if there's side effects. The compiler will reverse one but not the other.

  •  

Steinar H. Gunderson: Decompilation patterns, part 13: Reverse loop

Anyone who's read “bro-coder” C from before that was a name will recognize this idiom:

    var_t1_2 = 0x7F;
    ...
    do {
        ...
        var_t1_2 -= 1;
    } while (var_t1_2 >= 0);

Why does the loop count backwards? It's because comparison with zero is cheaper on some (many) platforms. Some people would reverse the loop manually, but compilers quickly managed to do that themselves. So you want:

   for (i = 0; i < 0x80; ++i) {
      ...
   }

and tomorrow, we'll have a look at what's inside the loop as well.

  •  

Dirk Eddelbuettel: RcppSimdJson 0.1.17 on CRAN: Updates

A brand new release 0.1.17 of the RcppSimdJson package is now on CRAN, and has been built for r2u and on r-universe.

RcppSimdJson wraps the fantastic and genuinely impressive simdjson library by Daniel Lemire and collaborators. Via very clever algorithmic engineering to obtain largely branch-free code, coupled with modern C++ and newer compiler instructions, it results in parsing gigabytes of JSON parsed per second which is quite mindboggling. The best-case performance is ‘faster than CPU speed’ as use of parallel SIMD instructions and careful branch avoidance can lead to less than one cpu cycle per byte parsed; see the video of the talk by Daniel Lemire at QCon.

This release is a small increment relative to the 0.1.6 release last week that got us (upstream) version 5.0.2 with many notable changes and sizeable speed gains on all fronts, including the interface from R. However, this failed to compile at CRAN on macOS x86_64 as the machine is setup for only partial support of C++20: no ranges, no concepts. So we now test, and fall back to C++17 if the test compilation fails. Upstream, meanwhile, already got to 5.0.5 which is included. It also gets us improved handling of disabling pragmas which we hope will survive CRAN checks.

The brief NEWS entry for this release follows.

Changes in version 0.1.17 [unreleased] (2026-10-xx)

  • Compilation starts with a C++20 feature test; if this fails C++17 is used (Dirk in #111 fixing #110)

  • simdjson was upgraded to version 5.0.5 (Daniel in #112)

Courtesy of my CRANberries, there is also a diffstat report for this release. For questions, suggestions, or issues please use the issue tracker at the GitHub repo.

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can now sponsor me at GitHub.

  •  

Matthew Garrett: Epic's EAC2 v2 seems fairly easily bypassable

Epic just announced the upcoming version 2 of their Linux implementation of Easy Anti-Cheat. It’s based on using the Linux eBPF security module to monitor what’s happening, and then a bunch of extra infrastructure to make sure this can’t be bypassed. The core part of this is requiring secure boot be enabled (ensuring that modified kernels can’t be used), using measured boot to verify that secure boot is enabled and which keys are used (to prevent you from just signing your own modified kernel), and then doing remote attestation, a mechanism where the TPM generates a signed copy of the boot measurements and passes that off to a server which verifies it came from a real TPM, verifies that you have secure boot enabled and are using the right keys, and presumably then allows you into the game.

This is all fine as long as you can prove that the measurements provided are real, and that’s actually a lot harder than you might think. First, we can simply make up our own quote signed with our own key and say that it came from a TPM. This is avoided by every TPM having an Endorsement Key (or EK) and an associated certificate, with that certificate being signed by the TPM vendor. If you have a list of all the legitimate TPM vendors and their CA keys, you can verify that the measurements came from a real TPM. Easy enough. So we need to get the measurements from a real TPM, and the one on our motherboard contains the measurements that were generated by the firmware and bootloader, and we can’t reset those at runtime without resetting the TPM, which… oh huh there’s actually nothing stopping us from doing that at runtime, as long as we have access to the hardware. Many desktop boards have the TPM on a small plugin module with a standard pinout that includes a reset pin. Simply short that to ground briefly and the TPM is back in its initial state, and userland can write whatever measurements it wants to it. Boot a modified kernel which lies to the eBPF code? As long as you replay the expected log values from a boot with secure boot on and a trusted kernel, the TPM will still happily provide a legitimate set of measurements that’ll satisfy the checker.

What if the TPM is less accessible, either because it’s mounted directly to the motherboard or it’s inside the CPU or chipset? That’s going to be trickier. But here’s the thing. The quote needs to come from a TPM, but not necessarily the TPM on your motherboard. TPMs these days are usually connected via the Serial Peripheral Interface, usually referred to as SPI. Microchip make a USB to SPI bridge, and there’s a Linux driver. Wire one of those up with an appropriate header and you can plug in an easily available TPM module intended for plugging into a motherboard, and now we tell the kernel to ignore the motherboard TPM and make /dev/tpmrm0 point at the USB one and program it with a set of trusted measurements and once again everything is going to look just fine (yes obviously the eBPF code can look for this, but we’re running a modified kernel so we can just lie to the eBPF code).

Remote attestation on PCs just doesn’t work that well in environments where you can’t associate a specific TPM with a specific system, which is basically everywhere except enterprises. But maybe that doesn’t matter and cheaters wouldn’t be willing to spend the $20 or so it’d take to produce one of these things? That would seem somewhat surprising, but it’s not impossible. And obviously any server-side cheat detection that triggers could then block that specific TPM, meaning they’d need to go and get another TPM, and maybe that ends up being enough to discourage people from bothering. From a practical level, this may be sufficient. But at a technical level? It’s not great.

  •  

Steinar H. Gunderson: Decompilation patterns, part 12: __builtin_memcpy

Say you see this lovely chunk of decompiled code:

    var_v1 = &sp10
    var_v0 = D_80010040;
    temp_s4 = var_v1;
    sp110 = &sp2C
    sp114 = &sp30
    do {
        var_v1->unk0 = (s32) var_v0->unk0;
        var_v1->unk4 = (s32) var_v0[1];
        var_v1->unk8 = (s32) var_v0[2];
        var_v1->unkC = (s32) var_v0[3];
        var_v0 += 0x10;
        var_v1 += 0x10;
    } while (var_v0 != &D_8001040[0x3C]);
    var_v1->unk0 = (s32) var_v0->unk0;
    var_v1->unk4 = (s32) var_v0[1];
    var_v1->unk8 = (s32) var_v0[2];

If you ignore the fact that m2c wrote ->unk0 for [0] (it has a bit of an annoying habit to do that), this is obviously something copying 16 bytes at a time and then 12 more bytes at the end. But would a programmer ever do this? Nope, this is an inlined, unrolled memcpy.

This is known in GCC as __builtin_memcpy, and it can happen either implicitly, or by some sort of lowering from a struct or array copy (e.g., through initialization of a stack array). Depending a bit on whether the variable is known to be aligned or not, you'll either get just lw or some evil lwr/lwl sequence; I'm always struggling a bit to change one to the other. In any case, what you want here is:

    __builtin_memcpy(&sp10, D_80010040, 0x4C);

and then make sp10 the right type instead of a scalar, ideally so that you can use sizeof() on it. Or, in some cases, a direct initialization:

    s32 foo[] = { 1, 2, 3, ...more data from D_80010040... };
  •  

Dirk Eddelbuettel: qlcal 0.1.4 on CRAN: Fresh Upstream Updates

The twenty-second release of the qlcal package arrivied at CRAN yesterday, and has been built for r2u as well as on r-universe.

qlcal delivers the calendaring parts of QuantLib. It is provided (for the R package) as a set of included files, so the package is self-contained and does not depend on an external QuantLib library (which can be demanding to build). qlcal covers over seventy country / market calendars and can compute holiday lists, its complement (i.e. business day lists) and much more. Examples are in the README at the repository, the package page, and course at the CRAN package page.

This release is based on the changes in the QuantLib 1.44 release also made yesterday. It includes two new calendars for Malaysia and the Philippines, updates to around a dozen calendars, and a few other updates to internal files. Maxmilian Muecke spotted and fixed a few small bugs just as he did for the RQuantLib release we made yesterday; this is equally appreciated! The full details from NEWS.Rd follow.

Changes in version 0.1.4 (2026-10-13)

  • Add missing market calendars for Poland, Russia, Romania, Indonesia (Maximilian Muecke in #21)

  • Add (semi-deprecated) alternate separators '::' for Israel and New Zealand markets (Maximilian Muecke in #22)

  • Fix several typos across source, configuration and documentation files (Maximilian Muecke in #23)

  • Synchronize with QuantLib 1.44, add two new calendars, update several others, and update general utility files (Dirk in #24)

Courtesy of my CRANberries, there is a diffstat report for this release. See the project page and package documentation for more details, and more examples.

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can sponsor me at GitHub.

  •  

Steinar H. Gunderson: Decompilation patterns, part 11: Irregular switch

Here's one that m2c usually gets right itself, but sometimes cannot:

    if (var_v1_7 != 1) {
        if (var_v1_7 < 2) { 
            if (var_v1_7 != 0) {
                spF0 = 40; 
            } else {
                vram_x = cmt46->vram_x;
                vram_y = cmt46->vram_y;
                spF0 = 40;
            }
        } else if (var_v1_7 != 2) {
            if (var_v1_7 != 3) {

Repeated comparisons against the same variable, especially in a nested form that could be binary search, should remind you of one thing: A switch. Usually, the compiler implements a switch with a jump table, but not always; if there are few conditions, or the range is too large for a reasonably-sized table, it will do some ifs instead (or, enough ifs to get within the range of a table). So what you want here is more like:

    switch (var_v1_7) {
    case 0:
       vram_x = cmt46->vram_x;
       vram_y = cmt46->vram_y;
       spF0 = 40;
       break;
    case 1:
       spF0 = 40;
       break;
    case 2:
       ...
    }

Remember that sometimes, you may need to insert cases that are not explicitly mentioned in the ifs (and/or a default case) to get everything to match back properly.

  •  

Reproducible Builds: Reproducible Builds in September 2026

Welcome to the September 2026 report from the Reproducible Builds project!

In our reports, we try to outline the most important things that we have been up to over the past month. As a quick recap about what problem our project intends to solve, whilst anyone may inspect the source code of free software for malicious flaws, almost all software is distributed to end users as pre-compiled binaries. The motivation behind the reproducible builds effort is to ensure no flaws have been introduced during this compilation process by promising identical results are always generated from a given source, thus allowing multiple third-parties to come to a consensus on whether a build was compromised or not.

As ever, if you are interested in contributing to the project, please visit our Contribute page on our website.

In this month’s report, we cover:

  1. Reproducible Builds Summit 2026 held in Gothenburg, Sweden
  2. dettrace expanding architecture support for PGO & Lisp dumps
  3. “They don’t care about this!”
  4. SOURCE_DATE_EPOCH specification updates
  5. Reproducible Builds at SeaGL 2026
  6. New Code of Conduct (CoC)
  7. Supporter Spotlight: Jochen Sprickerhof
  8. Mailing list news
  9. Tool and documentation development
  10. Patches

Reproducible Builds Summit 2026 held in Gothenburg, Sweden

The annual Reproducible Builds summit took place from 22 to 24 September 2026 in Gothenburg, Sweden. The event brought together developers, distribution maintainers, security researchers and free software advocates from across the ecosystem to share updates on current initiatives, address outstanding toolchain bottlenecks and strengthen cross-project collaboration.

Participants engaged in a series of working sessions and technical roundtables focused on expanding the practical scope of reproducibility. Discussions covered ongoing work within major Linux distributions, language-specific package ecosystems and the various parts of the binary verification infrastructure.

Strategic planning formed a pillar of the gathering, with participants discussing long-term roadmap goals for supply-chain security, software integrity and related topics. Attendees explored new methods for automated verification, discussing how to lower the adoption barriers for maintainers and streamline the integration of deterministic build pipelines into established continuous integration (CI) systems. The event was then followed by two days of unmoderated hacking sessions. These hacking sessions provided space for technical progress, allowing attendees to draft specification updates, prototype new tool features and resolve standing reproducibility bugs in-person.


Dettrace expanding architecture support for PGO & Lisp dumps

Bernhard M. Wiedemann announced major updates to dettrace, porting the tool across most architectures supported by Debian and openSUSE. The release addresses key stability issues, passing test suites across these targets and making it ready for production build pipelines.

These improvements enable deterministic builds when utilising Profile-Guided Optimisations (PGO), removing the need to sacrifice runtime performance for reproducibility. Additionally, dettrace can now be applied to (notoriously difficult-to-reproduce) Lisp and Scheme memory dumps, including environments such as CLISP, SBCL, Scheme 48, Racket and GNU Emacs.


“They don’t care about this”

Annika Wilde, Marco Gutfleisch, Felix Reichmann, Anirban Chakraborty, Yuval Yarom, M. Angela Sasse and Ghassan Karame published a paper this month entitled “They don’t care about this”: A Systematic Study of Trusted Execution Environments Build Reproducibility in the Wild:

Trusted Execution Environments (TEEs) have become a cornerstone of modern cloud computing, providing strong confidentiality and integrity guarantees for both code and data. A critical component of this trust model is remote attestation, which enables external entities to verify the authenticity and integrity of code executing within a TEE through cryptographic measurements. However, the effectiveness of remote attestation fundamentally depends on the verifier’s ability to trace the reported measurement back to the original source code - a property that can only be guaranteed through reproducible builds. […]

The full PDF can be read online.


SOURCE_DATE_EPOCH specification updates

Bernhard M. Wiedemann shared a number of proposals regarding updating the SOURCE_DATE_EPOCH specification following discussions at a project summit. Seven distinct proposed changes have been submitted as merge requests on Salsa.

Bernhard’s proposed modifications are independent of one another, allowing for any combination to be merged depending on community feedback. Bernhard noted that one proposal may see the most debate, and could still benefit from further refinement before reaching consensus. Community members are invited to review and provide feedback on the individual merge requests by 1 December 2026. Input can be submitted via reactions or comments on Salsa, directly by email to Bernhard or the mailing list.

The specification was first published in 2015 and updated in 2017.


Reproducible Builds at SeaGL 2026

Reproducible Builds will be present at SeaGL in Seattle, WA, on October 23rd & 24th. Come chat with us in person!

Founded in 2013, SeaGL is a free, grassroots technical summit dedicated to spreading awareness and knowledge about free source software, hardware and culture.


New Code of Conduct (CoC) for the Reproducible Builds project

Mattia Rizzolo announced the official launch of a Code of Conduct for the Reproducible Builds project. This follows work and community discussions originally initiated in 2024, incorporating feedback gathered over email and during project summits, as well as with input from the Software Freedom Conservancy.

The new Code of Conduct establishes guidelines emphasising mutual respect among project contributors. It also defines a formalised process for submitting and handling complaints regarding community misconduct, ensuring transparent governance across project spaces. Along with the core policy document, an accompanying Code of Conduct FAQ has been published to outline the rationale behind adopting the guidelines.


Supporter Spotlight: Jochen Sprickerhof

As a reminder, another supporter spotlight interview was published featuring long-time Debian and Reproducible Builds contributor Jochen Sprickerhof, highlighting his work on package verification and project infrastructure.


Mailing list news

On our mailing list this month:

  • Jonathan Starr from the Institute of Open Science Practices (IOSP) posted with an announcement of its upcoming 2026 workshop series in Leiden in the Netherlands. This free-to-attend event aims to build a participant-owned data storage consortium, allowing community members to publish datasets, code and knowledge objects alongside algorithms designed to evaluate trust and value. The event features a dedicated Community Track for talks and discussions, a tool showcase and an opening session on resilient data storage.

  • Following up on IRC discussions regarding profile-guided optimization (PGO) on build servers, kpcyrd created a demonstration repository showing how PGO profiling can introduce non-determinism into output binaries. The demo highlights how runtime randomness (specifically, the randomised keys used in HashMaps to prevent denial-of-service attacks) causes varying bucket collision rates during test runs. These structural variances alter execution weights on underlying code branches, prompting the compiler to generate differing final assembly output for builds that would otherwise be perfectly reproducible if PGO was disabled. Rather than abandoning PGO performance gains, kpcyrd suggested treating generated profiling data as a documented build input or recorded environment artifact (similar to .buildinfo files), rather than regenerating profiles dynamically on the fly during build execution.

  • An autonomous AI agent (!), posted a controlled build result and reproducer demonstrating that pre-creating an obj directory in libmilter source trees prevents kernel-release path leaks (obj.Linux.<release>.x86_64) into debugging symbols. kpcyrd followed up with a helpful reply.

  • Alexander Sosedkin inquired on the mailing list about the preferred approach for sourcing pinned translation files to create reproducible GnuTLS release tarballs, asking whether external hosting should provide versioned downloads, or if projects ought to use Git submodules, dedicated side-repositories or some other mechanism.


Tool and documentation development

diffoscope is our in-depth and content-aware diff utility that can locate and diagnose reproducibility issues. This month, Chris Lamb made a number of changes, including preparing and uploading versions 330, 331 and 332 to Debian. In particular, Chris committed support for radare2 versions greater than 5.9.0 […] based on input from Guillaume Girol […], and committed support for .nar files via Guix. […][…].

Chris later modified diffoscope to not Build-Depend on the Debian package of GNU Guix, as its status in the Debian bug tracking system would transitively render diffoscope as being overly buggy for the next stable release […]. Similarly, he adjusted the Build-Depends on the apksigcopier package as it has been removed from Debian testing […] and, finally, he updated a number of copyright years […][…].

Vagrant Cascadian updated diffoscope in GNU Guix to version 332.


reprotest is our tool for building the same source code twice in different environments and then checking the binaries produced by each build for any differences. This month, reprotest version 0.7.33 was uploaded to Debian by Holger Levsen with the following changes:

  • Sergei Tachenov fixed the fileordering test on all filesystems, including the likes of ZFS, which could return a different order across two builds due to build being done in a different directory […].

  • Holger Levsen bumped the Standards-Version to 4.7.4, reflected that Priority: optional is the default now […], fixed the old Free Software Foundation address […] and bumped the debhelper ‘compat’ level to 14 after confirming there are only desired changes […].

  • Vagrant Cascadian updated *reprotest* to version 0.7.33 in GNU Guix.


rebuilderd, our server designed monitor the official package repositories of Linux distributions and attempt to reproduce the observed results there; it powers, amongst other things, reproduce.debian.net. This month, Bernhard M. Wiedemann submitted a pull request to rebuilderd that refactors RPM repository metadata handling. The change extracts rpm-md parsing out of the Fedora-specific scheduler module and into a shared one.


Lastly, there were a number of improvements made to our website this month as well. For example:


Patches

The Reproducible Builds project detects, dissects and attempts to fix as many currently-unreproducible packages as possible. We endeavour to send all of our patches upstream where applicable or possible. This month, we wrote a large number of such patches, including:

Vagrant Cascadian also performed a number of Non-Maintainer Uploads (NMUs) and Quality Assurance (QA) uploads in Debian for several packages with outstanding reproducibility issues. These included molttemplate, buddy, xfonts-nexus, fte and lifelines.

At the time of this writing, that leaves 130 submitted patches, with only 61 outstanding submitted patches that older than a year in the Debian bug tracking system. This number is only 26 if we exclude any low-priority build path issues.



If you are interested in contributing to the Reproducible Builds project, please visit our Contribute page on our website. However, you can get in touch with us via:

  •  

Matthew Garrett: Linux Lockdown and Hibernation (again)

(This is an updated version of an older post - the introduction remains the same, the technical details are different)

Linux draws a distinction between code running in kernel (kernel space) and applications running in userland (user space). This is enforced at the hardware level - in x86-speak1, kernel space code runs in ring 0 and user space code runs in ring 32. If you’re running in ring 3 and you attempt to touch memory that’s only accessible in ring 0, the hardware will raise a fault. No matter how privileged your ring 3 code, you don’t get to touch ring 0.

Kind of. In theory. Traditionally this wasn’t well enforced. At the most basic level, since root can load kernel modules, you could just build a kernel module that performed any kernel modifications you wanted and then have root load it. Technically user space code wasn’t modifying kernel space code, but the difference was pretty semantic rather than useful. But it got worse - root could also map memory ranges belonging to PCI devices3, and if the device could perform DMA you could just ask the device to overwrite bits of the kernel4. Or root could modify special CPU registers (“Model Specific Registers”, or MSRs) that alter CPU behaviour via the /dev/msr interface, and compromise the kernel boundary that way.

It turns out that there were a number of ways root was effectively equivalent to ring 0, and the boundary was more about reliability (ie, a process running as root that ends up misbehaving should still only be able to crash itself rather than taking down the kernel with it) than security. After all, if you were root you could just replace the on-disk kernel with a backdoored one and reboot. Going deeper, you could replace the bootloader with one that automatically injected backdoors into a legitimate kernel image. We didn’t have any way to prevent this sort of thing, so attempting to harden the root/kernel boundary wasn’t especially interesting.

In 2012 Microsoft started requiring vendors ship systems with UEFI Secure Boot, a firmware feature that allowed5 systems to refuse to boot anything without an appropriate signature. This not only enabled the creation of a system that drew a strong boundary between root and kernel, it arguably required one - what’s the point of restricting what the firmware will stick in ring 0 if root can just throw more code in there afterwards? What ended up as the Lockdown Linux Security Module provides the tooling for this, blocking userspace interfaces that can be used to modify the kernel and enforcing that any modules have a trusted signature.

But that comes at something of a cost. Most of the features that Lockdown blocks are fairly niche, so the direct impact of having it enabled is small. Except that it also blocks hibernation6, and it turns out some people were using that. The obvious question is “what does hibernation have to do with keeping root out of kernel space”, and the answer is a little convoluted and is tied into how Linux implements hibernation. Basically, Linux saves system state into the swap partition and modifies the header to indicate that there’s a hibernation image there instead of swap. On the next boot, the kernel sees the header indicating that it’s a hibernation image, copies the contents of the swap partition back into RAM, and then jumps back into the old kernel code. What ensures that the hibernation image was actually written out by the kernel? Absolutely nothing, which means a motivated attacker with root access could turn off swap, write a hibernation image to the swap partition themselves, and then reboot. The kernel would happily resume into the attacker’s image, giving the attacker control over what gets copied back into kernel space.

This is annoying, because normally when we think about attacks on swap we mitigate it by requiring an encrypted swap partition. But in this case, our attacker is root, and so already has access to the plaintext version of the swap partition. Disk encryption doesn’t save us here. We need some way to verify that the hibernation image was written out by the kernel, not by root. And thankfully we have some tools for that.

Trusted Platform Modules (TPMs) are cryptographic coprocessors7 capable of doing things like generating encryption keys and then encrypting things with them. You can ask a TPM to encrypt something with a key that’s tied to that specific TPM - the OS has no access to the decryption key, and nor does any other TPM. So we can have the kernel generate an encryption key, encrypt part of the hibernation image with it, and then have the TPM encrypt it. We store the encrypted copy of the key in the hibernation image as well. On resume, the kernel reads the encrypted copy of the key, passes it to the TPM, gets the decrypted copy back and is able to verify the hibernation image.

That’s great! Except root can do exactly the same thing. This tells us the hibernation image was generated on this machine, but doesn’t tell us that it was done by the kernel. We need some way to be able to differentiate between keys that were generated in kernel and ones that were generated in userland. TPMs have the concept of “localities” (effectively privilege levels) that would be perfect for this. Userland is only able to access locality 0, so the kernel could simply use locality 1 to encrypt the key. Unfortunately, localities are typically only available on systems that implement a Dynamic Root of Trust Measurement like Intel’s TXT, and most consumer systems have no support for this. So, we need another approach.

TPMs have a set of Platform Configuration Registers (PCRs), intended for keeping a record of system state. The OS isn’t able to modify the PCRs directly. Instead, the OS provides a cryptographic hash of some material to the TPM. The TPM takes the existing PCR value, appends the new hash to that, and then stores the hash of the combination in the PCR - a process called “extension”. This means that the new value of the TPM depends not only on the value of the new data, it depends on the previous value of the PCR - and, in turn, that previous value depended on its previous value, and so on. The only way to get to a specific PCR value is to either (a) break the hash algorithm, or (b) perform exactly the same sequence of writes. On system reset the PCRs go back to a known value, and the entire process starts again.

Some PCRs are different. PCR 23, for example, can be reset back to its original value without resetting the system. We can make use of that. The first thing we need to do is to prevent userland from being able to reset or extend PCR 23 itself. All TPM accesses go through the kernel, so this is a simple matter of parsing the write before it’s sent to the TPM and returning an error if it’s a sensitive command that would touch PCR 23. We now know that any change in PCR 23’s state will be restricted to the kernel.

When we encrypt material with the TPM, we can ask it to record the PCR state. This is given back to us as metadata accompanying the encrypted secret. Along with the metadata is an additional signature created by the TPM, which can be used to prove that the metadata is both legitimate and associated with this specific encrypted data. In our case, that means we know what the value of PCR 23 was when we encrypted the key. That means that if we simply extend PCR 23 with a known value in-kernel before encrypting our key, we can look at the value of PCR 23 in the metadata. If it matches, the key was encrypted by the kernel - userland can create its own key, but it has no way to extend PCR 23 to the appropriate value first. We now know that the key was generated by the kernel.

Unfortunately it turns out that some people actually make use of PCR 23, and restricting it to the kernel makes them sad. There are other resettable PCRs, but only in non-0 localities, so (a) we can’t reset them on most systems and (b) we’ll just find someone who uses them anyway and run into the same problem. We need a different approach.

Thankfully TPMs have a small chunk of non-volatile RAM that can be used for storing things, and by “storing” I mean they can be used in a range of different ways. One of these is effectively as additional PCRs. These values can be configured such that they work the same way as PCRs, with the only way to modify them being to append a new hash to their existing value and update the new value to the hash of that merged value. We can allocate one of these for in-kernel use and reject any access from userspace, and also there are officially allocated ranges (so people shouldn’t be using random values) and the namespace is large enough anyway that w eshouldn’t collide with anyone, so we can carve one of those out and use it for this purpose.

Unfortunately, though, these NV indexes aren’t included in the creation data we get when we create a key, so we need another approach. TPMs have the concept of sessions, a series of commands executed in sequence. A flag allows these sessions to be “audited”, with the TPM keeping a running track of the hash of the commands executed and the results returned. At the end of the session you can ask for a signed copy of this hash, and if you’ve kept a log of all the commands then you can verify that they match that signed hash and know that this log represents a real communication with the TPM. If we read the NV index and generate the key inside the same session, we can verify that the key we’re looking at was created while the NV index had a specific value, and if only the kernel can set that value then we know that the key was generated by the kernel.

Or, well, can we? Only new kernels would impose the restriction on modifying that NV index. An attacker could boot an old kernel, generate a key there in userland, sign a hibernation image with it, and then reboot into a new kernel. The new kernel would see a valid signature with a valid NV index associated with it and have no way to know it was generated from userland rather than the kernel. We need to be able to tell the difference between kernels that implement this feature and ones that don’t, and we need to do that without being able to go back in time to change old kernel behaviour. We can extend a PCR to indicate we implement the new functionality, but so can an attacker running an old kernel.

The normal approach to determining whether an event occurred in a specific phase of the boot process is to “cap” the PCRs - extend them with a known value that indicates a transition between stages of the boot process. Any events that occur before the cap event must have occurred in the previous stage of boot, and since the final PCR value depends on the order of measurements and not just the contents of those measurements, if a PCR is capped before userland runs, userland can’t fake the same PCR value afterwards. If Linux capped the PCRs before userland started running, we’d be able to place a measurement there before the cap occurred and then prove that that extension occurred before userland had the opportunity to interfere. We could simply place a statement that the kernel supported the NV index restrictions there, and we’d be fine.

Unfortunately Linux doesn’t currently do this, and adding support for doing so doesn’t fix the problem - if an attacker boots a kernel that doesn’t cap a PCR, they can just cap it themselves from userland. So, we’re faced with the same problem: booting an older kernel allows the system to be placed in an identical state to the current kernel, and a fake hibernation image can be written out. Solving this requires a PCR that was being modified after kernel code was running, but before userland was started, even with existing kernels.

Thankfully, there is one! PCR 5 is defined as containing measurements related to boot management configuration and data. One of the measurements it contains is the result of the UEFI ExitBootServices() call. ExitBootServices() is called at the transition from the UEFI boot environment to the running OS, and the kernel contains code that executes before it. So, if we measure an assertion regarding whether or not we support restricted access to NV indexes into PCR 5 before we call ExitBootServices(), this will prevent userspace from spoofing us (because userspace will only be able to extend PCR 5 after the firmware extended PCR 5 in response to ExitBootServices() being called). Obviously this depends on the firmware actually performing the PCR 5 extension when ExitBootServices() is called, but if firmware’s out of spec then I don’t think there’s any real expectation of it being secure enough for any of this to buy you anything anyway.

That’s what this patchset does. Review feedback so far seems positive, although James Bottomley suggested a design improvement. My approach of using an NV index as a PCR and generating a signing key made sense as a consequence of my original approach involving PCR 23, which had been to use the key creation data and not use audit sessions at all. But the goal isn’t to use a key - it’s to prove that hibernation occurred in-kernel, and while signing is one way of doing that, there are others. His suggestion is to simply record the hash of the hibernation image into the NV index and then read that back as part of the audit session. On resume we verify the audit session log is legitimate, read the hibernation image, and compare the hash of the hibernation image against the hash in the log. If it matches, and if the PCR 5 value matches, we know the audit session happened in kernel and that the hibernation image hasn’t been modified.

It still seems like we’re missing something, though. If we’re not storing a key anywhere, how do we verify the audit session? To explain this we’re going to need to go into some details about how TPM keys work in the first place. TPMs can produce a special kind of key called an Attestation Key, or AK. Attestation keys are used to sign attestation statements from the TPM, such as PCR quotes or audit logs. We need a separate key type for this in order to prove that the signature was generated as part of an attestation - normal TPM signing keys are fundamentally designed to sign arbitrary material, and so can be used by userland to sign something that looks identical to an attestation record. By being able to distinguish the types of key the TPM uses, we can prove that a signature was generated using an AK, and so know that it’s a real TPM attestation (because nothing other than the TPM can sign stuff with an AK).

But even beyond this distinction, TPMs have different key types. Ordinary keys are generated using an RNG and will be unique. Primary keys are generated using a seed that is used as an input into a key derivation function. For a given TPM, using the same seed to generate the same type of primary key will always generate the same primary key8. We can have the kernel deterministically generate an AK during suspend in order to sign the audit log, and then generate the same key again on resume to validate it. This means we don’t need any other form of trusted storage for the AK - the TPM already provides that functionality.

This is all rather complicated but I’ve been thinking about this for some time now and I haven’t come up with a cleaner solution. The only real open issue is the degree to which machines actually perform the PCR 5 extension. If it turns out there’s a bunch that don’t we’ll need to come up with some alternative approach to identifying whether the kernel supports this functionality, but the design is such that that should be invisible to userspace so adding alternatives later shouldn’t be an issue. Filtering accesses to the NV index is also not super clean, and depends on there not being alternative mechanisms to get at the TPM by sending raw commands. Again, this is intended to be opaque to userland and can be improved if we come up with something better later on (such as a secure way to pass a secret to the kernel on boot that can be used as an auth value for acess to the NV index).

Anyway. Time to go and fix the next thing.


  1. Other architectures use different terminology here, such as “supervisor” and “user” mode, but it’s broadly equivalent ↩︎

  2. In theory rings 1 and 2 would allow you to run drivers with privileges somewhere between full kernel access and userland applications, but in reality we just don’t talk about them in polite company ↩︎

  3. This is how graphics worked in Linux before kernel modesetting turned up. XFree86 would just map your GPU’s registers into userland and poke them directly. This was not a huge win for stability ↩︎

  4. IOMMUs can help you here, by restricting the memory PCI devices can DMA to or from. The kernel then gets to allocate ranges for device buffers and configure the IOMMU such that the device can’t DMA to anything else. Except that region of memory may still contain sensitive material such as function pointers, and attacks like this can still cause you problems as a result. ↩︎

  5. This describes why I’m using “allowed” rather than “required” here ↩︎

  6. Saving the system state to disk and powering down the platform entirely - significantly slower than suspending the system while keeping state in RAM, but also resilient against the system losing power. ↩︎

  7. With some handwaving around “coprocessor”. TPMs can’t be part of the OS or the system firmware, but they don’t technically need to be an independent component. Intel have a TPM implementation that runs on the Management Engine, a separate processor built into the motherboard chipset. AMD have one that runs on the Platform Security Processor, a small ARM core built into their CPU. Various ARM implementations run a TPM in Trustzone, a special CPU mode that (in theory) is able to access resources that are entirely blocked off from anything running in the OS, kernel or otherwise. ↩︎

  8. Unless the TPM is cleared, in which case it’ll generate a new internal seed and now the keys will be different to before the clear ↩︎

  •  

Freexian Collaborators: Debian Contributions: New experimental backend for autopkgtest using pconr, DebConf site visit and more! (by Anupa Ann Joseph)

Debian Contributions: 2026-09

Contributing to Debian is part of Freexian’s mission. This article covers the latest achievements of Freexian and their collaborators. All of this is made possible by organizations subscribing to our Long Term Support contracts and consulting services.

DebConf site visit, by Stefano Rivera

In preparation for DebConf 27, Stefano Rivera, Nattie Mayer-Hutchings, and Jongmin Kim from the DebConf Committee visited Asahikawa Japan. A contingent of the local team gathered to tour the venues with us, discuss plans, and meet the local organizations assisting the event. We held a press conference at the city hall that got some coverage. A few potential day-trip options were explored. Photos from the site visit.

autopkgtest-virt-pconr, by Helmut Grohne

Following the creation of the pconr module that provides a basis for unschroot and a more secure containment for mmdebstrap, an experimental autopkgtest backend autopkgtest-virt-pconr is now available. It fits a spot between autopkgtest-virt-unshare and more fully fledged containers as it does not require much infrastructure like setting up incus or lxc but still provides a containment running an initsystem. Due to the use of erofs as base image format, it boots and reverts quickly. This development also required fixing concurrency issues in asyncvarlink and even shed light on a matching bug in systemd that was promptly fixed upstream.

Miscellaneous contributions

  • Carles reviewed and submitted six Catalan po-debconf translations using po-debconf-manager. Improved po-debconf-manager’s workflow for updating translations.
  • Carles reviewed, translated or updated webwml Catalan translations for security and CD pages. He also fixed issues that prevented building webwml, deleted orphaned translation pages, etc. and experimented with a more global HTML tidying up experiment.
  • Carles refactored check-relations adding capacity to ignore concrete from_package -> to_package specific relations and more flexibility around ignores. Detects unused ignore rules as well.
  • Carles improved some Wiki pages (LibreOffice, Framework amongst some other ones)
  • Thorsten did an hplip upload to replace an expired certificate of HP. This certificate is used to sign new upstream releases and modules that can be downloaded later. Afterwards work on a new upstream version started.
  • Thorsten also struggles with autopkgtest problems of the new upstream version of cups. Work is still ongoing.
  • Antonio loaded the video recording URLs into the MiniDebConf Winterthur 2026 website, and deployed the website for MiniDebConf Curitiba 2027 (still very early work in progress at this point).
  • Antonio uploaded debci 4.3, autodep8 0.31, gem2deb 2.2.10, ruby-sass 3.7.4-7, init-system-helpers 1.69+nmu2 and 1.69+nmu3.
  • Antonio worked on several topics around Debian CI maintenance, reliability and performance.
  • Stefano updated the autopkgtests for cPython packages in Debian to support setuptools 80.
  • Stefano uploaded pypy 8.
  • Stefano helped to get DebConf 26 reimbursement claims processed, and worked on some of the resulting issues in debian-reimbursements.
  • Emilio managed various transitions.
  • Emilio worked on the rustc-web/trixie bootstrap for armel, using the rustc 1.95 version from trixie-backports. This will be needed by the upcoming clamav security updates.
  • Helmut sent patches for 11 cross build failures.
  • Helmut introduced a new build profile to libcap-ng to keep architecture cross bootstrap working.
  • Helmut uploaded debvm_0.5.5 introducing support for Hurd thanks to a lot of work by Johannes Schauer Marin Rodrigues.
  • Colin worked with OpenSSH upstream to reduce the linkage of /usr/sbin/sshd, hardening it a little further.
  • Colin upgraded to new security releases of groff and parted.
  • Colin upgraded 50 Python packages to new upstream versions, and fixed over 40 RC bugs in the Python team.
  • Santiago continued mentoring Aryan Karamtoth with the GSoC project about introducing livepatching support for linux. This mentoring is done in collaboration with Emmanuel Arias. In particular, Santiago explored different requirements for providing binary modules for the same kernel packages used by Debian, that require a matching version number.
  • Anupa joined Jean-Pierre Giraud to prepare the files for point release announcement for Debian 13.7.
  •  

Russ Allbery: Review: Ties That Bond in Gretna Green

Review: Ties That Bond in Gretna Green, by Linzi Day

Series: Midlife Recorder #3
Publisher: Linzi Day
Copyright: February 2023
ISBN: 9798376517017
Format: Kindle
Pages: 616

Ties That Bond in Gretna Green is a self-published fantasy novel and the third book in the Midlife Recorder series. As with the previous book, it picks up almost immediately after Painting the Blues in Gretna Green. Day calls the genre paranormal women's fantasy, and that sounds about right to me.

There is an intervening short story that you can get by joining Day's mailing list (along with an epilogue to the first book and to this book). I don't think it's that important, but there are frequent references to it at the start of this novel that become somewhat annoying if you haven't read it.

Valentine's Day is fast approaching. This the busiest day of the year for the part of the Recorder's job that Niki already knew how to do: marrying people. She performed marriage ceremonies in her previous job before her inheritance, and she loved that work despite her awful boss. Performing marriages in the Gateway sounds even more rewarding, but the sheer number of couples and the political complications from the first two books create logistical problems she has to solve first.

Also, the remaining member of her staff held over from her grandmother's time has returned from vacation to discover that Niki has upended most of what she thought she knew about the job. Time for Niki to apply what she learned from the change management training her old boss forced her to attend and then ignored! (If you just groaned, rest assured that Day somehow makes this work, although she clearly has a higher opinion of corporate training than I do.)

This plot was more to my taste than Painting the Blues, mostly because Niki seemed on top of the problems and didn't postpone looking at them for half the book. There is more of the management competence porn that readers have come to expect of the series, a few more revelations about Niki's magic, more mysterious manifestations and the first mention of a prophecy, and a few political developments. As always, the pacing is exceptional. These books grab me and pull me along, page after page, often robbing me of sleep because I find them nearly impossible to put down.

Ties that Bond (and to some extent the last book) looked like it was going to introduce a romantic subplot, and I was preparing to be annoyed by it because I did not like the man in the subplot at all. I won't spoil how it works out in this book, but I will say that Niki surprised me and showed more sense than I thought the author was telegraphing. This is not the first time that Day has surprised me with what I thought was foreshadowing that did not turn out how I expected, usually for the better. If she can keep that up, it's a nice effect (if a bit unbalancing) and adds to my desire to read just one more chapter.

The way the world-building of these books is structured continues to intrigue me. Day gets away with some problems that I think would be more noticeable in other books thanks to the excellent pacing (no time to ponder the world-building, we're on to the next crisis!) and the tight third-person perspective. Niki is not a detail person, to say the least, but she does keep returning to bits of world-building and poking at them a bit harder, which gives Day repeated opportunities to shore up ideas that felt shaky and dubious at first glance. Still, this is not a book that prizes deep logical consistency or full exploration of the ramifications of a bit of magic. You have to be willing to go along with the ride and not think too hard.

For example, Niki can see bonds between couples and judge their strength. This is apparently a long-standing power of the Recorder's line (she was able to do that before she became the Recorder), and part of her responsibility in these weddings is to check the bonds of the couples. This leads to some well-handled scenes where she diagnoses a problem or resolves a conflict because she can magically see the true relationship structure.

Everyone in the book just takes this power in stride. This is wild to me! This ability would completely upend half of society if you fully worked out its ramifications and could find people other than Niki with the same ability. Even if one assumes that a bond only forms over time and can't be sensed in the early stages of a relationship (something the book never establishes), can you imagine the implications of having an infallible oracle that says at a glance whether a marriage will work (permanently, the book strongly implies)? The implications for how to structure marriage, for family planning, for psychology and psychiatry, for how to structure dating, even for living arrangements and housing markets? This is not a small world-building detail, and yet it's treated more like part of Niki's characterization than like a foundation of society.

I think some of this all-vibes world-building may come from the general new-age feel to how magic works. Day makes a grab-bag of random magic canonical in this world: psychic lie detecting abilities, auras, chakras, premonitions, and other bits of the sort of spiritualism that tends to be heavily marketed to middle-class women. I have that niggling feeling that one sometimes gets in SF that a lot of this is in the world-building because the author believes it's partly real (see, for instance, psychic powers and the Dean drive in 1960s science fiction). If one believes that psychic powers and various bits of mysticism are true in our world, one has already developed the rationalization mechanisms to explain away their almost total lack of influence or impact on how the world is structured. If one then introduces them into a true fantasy world, one may not notice how many implications that should have for how society is structured, since one is used to believing magic exists but has no significant implications.

I could be entirely wrong about this analysis, and maybe it's a bit unfair to Day. I should also be clear that this is not a complaint, just a point of fascination to me when I think back over one of these books after I finished it. There is a glut of fantasy out there that's constructed like an engineering problem or that goes deep into politics or social theory, usually written by people with strong opinions but not a lot of training in real sociology. One of the joys of self-published books is that you occasionally get something that assembles genre conventions in a way that feels odd and delightfully strange. What if, in addition to dimensional gates and overwhelming protean power invested in a true heir, all the magic sold by the local Tarot and crystal store was also true? Sure, why not! If the pacing is good and the story is grabby, it works for me.

It does seem worth attaching a warning for the folks who need scientific reproducibility and explored implications in their world-building, though. If you're the sort of reader who is bothered by political boundaries and economic systems that match our world despite the existence of magic, this series may cause you problems.

This continues to be a grabby, highly entertaining story of a woman who finally gets to run her own small business the way that she always thought the business should be run after years of working for an awful manager, except that her business is total magical power over an interchange point between dimensions, she's the chosen one, and the setting is a high fantasy world with prophecies and gods. If that sounds appealing, don't start here, but I highly recommend giving Midlife in Gretna Green a try. The series seems to be holding up.

Followed by a short story epilogue available by joining Day's mailing list, an optional novella (maybe novelette) published in Spilling the Tea in Gretna Green, and then Seeing Red in Gretna Green.

Rating: 7 out of 10

  •  

Dirk Eddelbuettel: RQuantLib 0.4.29 on CRAN: New QuantLib, Plus Small Fixes

A new release 0.4.29 of RQuantLib arrived on CRAN this evening, had already been built for r2u as well as on r-universe and has just been uploaded to Debian.

QuantLib is a rather comprehensice free/open-source library for quantitative finance. RQuantLib connects (some parts of) it to the R environment and language, and has been part of CRAN for twenty-three years (!!) as it was one of the first packages I uploaded to CRAN.

This release of RQuantLib brings two new calendars (Malaysia, Philippines), updates to a number of other calendars as well to other files, and two deprecations we are reflecting in this release. It also benefits from a number of careful and attentive pull requests by Maximilian Muecke cleaning up an (astonishing !!) number of likely rather old little bugs. Full details from the NEWS file follow as usual.

Changes in RQuantLib version 0.4.29 (2026-10-13)

  • Configure check for outdated QuantLib version updated,

  • Adjust two instantiations on macOS x86_64 with old compilers

  • Correct Euribor2W and Euribor3W tenors setters (Maximilian Muecke in #196)

  • Accect Euribor1W as alias for EuriborSW tenor (Maximilian Muecke in #197)

  • Correct default handling of the payFixed parameter (Maximilian Muecke in #198)

  • Assign missing S3 class to American option implied volatitly return (Maximilian Muecke in #199)

  • Correct spelling in manual pages and R code (Maximilian Muecke in #202, #203)

  • Support additional Polish settlements (Maximilian Muecke in #204)

  • Check for curve parameters in FittedBondCurve (Dirk in #205 fixing #201)

  • Reflect two deprecations in QuantLib 1.44 and adjust code in two spot (Dirk in #206)

Courtesy of my CRANberries, there is also a diffstat report for the this release. As always, more detailed information is on the RQuantLib page. Questions, comments etc should go to the rquantlib-devel mailing list. Issue tickets can be filed at the GitHub repo.

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. If you like this or other open-source work I do, you can now sponsor me at GitHub.

  •  

Steinar H. Gunderson: Decompilation patterns, part 10: return var_v0

The v0 register on MIPS is special in that it is the return register (like rax is on x86-64), so when you see code like this:

if (x == 3) {
    var_v0 = 1;
} else if (y == 4) {
    ...
    var_v0 = 3;
}
var_v0 = 5;
return var_v0;

then you have to consider the possibility that the intended match is:

if (x == 3) {
    return 1;
} else if (y == 4) {
    ...
    return 3;
} else {
    return 5;
}

Whether you put the last return in an else block or not is irrelevant for the match, of course, it's purely a matter of taste.

  •  

Maytham Alsudany: Menus without JavaScript

This is more of a note to myself since I keep forgetting and "rediscovering" this technique every time I need it, but if it helps you, great!

The JavaScript way is to toggle displaying the menu based on a button click. For instance, here's an example in Svelte:

[This interactive/preview is only available on the website.]
<script lang="ts">
	let showMenu = $state(false);
</script>

<button onclick={() => (showMenu = !showMenu)}>
	{#if showMenu}
		Hide menu
	{:else}
		Show menu
	{/if}
</button>
<nav class:hidden={!showMenu}>
	<ul>
		<li>Home</li>
		<li>Blog</li>
		<li>Foo</li>
		<li>Bar</li>
	</ul>
</nav>

<style>
	.hidden {
		display: none;
	}
</style>

But there is a hack to use a hidden checkbox and some CSS to achieve the same thing without any JavaScript. The example here turns the menu button into a label that toggles the checkbox, and uses the checkbox state to determine when to show the menu via the next-sibling combinator.

[This interactive/preview is only available on the website.]
<input type="checkbox" id="menu-state" />
<div class="menu-ctn">
	<label class="menu-toggle" for="menu-state">
		<span class="menu-closed">Show menu</span>
		<span class="menu-open">Hide menu</span>
	</label>
	<nav class="menu-open">
		<ul>
			<li>Home</li>
			<li>Blog</li>
			<li>Foo</li>
			<li>Bar</li>
		</ul>
	</nav>
</div>

<style>
	#menu-state {
		display: none;
	}
	.menu-open {
		display: none;
	}
	.menu-closed {
		display: block;
	}
	#menu-state:checked + .menu-ctn .menu-open {
		display: block;
	}
	#menu-state:checked + .menu-ctn .menu-closed {
		display: none;
	}
</style>
  •  

Steinar H. Gunderson: Decompilation patterns part 9, sign extension

Today, for something completely different:

s.x = (s16) ((s32) (temp_v0 << 0x10) >> 0x11);

MIPS has 16-bit loads and stores, but not 16-bit (signed) arithmetic, so if it wants to do that, it needs to sign-extend to 32-bit first. And it does that by first shifting up by 16 so that the 16-bit sign bit is at the 32-bit sign bit, and then it can do an arithmetic shift afterwards. So what you want is:

s16 temp_v0;

s.x = temp_v0 >> 1;

Sometimes, it can be pretty stubborn, and you'll need to go through memory or similar before GCC really inserts the shift patterns you want.

  •  

Maytham Alsudany: There's more to CSS for underlining

I read Ruben Schade's notes on underlining and wanted to add more, as adding a border-bottom and leaving at that seemed incomplete to me.

Modern

Of course, you could just use the modern choice. Here, I've shortened what Schade uses into one line of CSS (because I can). As noted, this is a fairly new feature so not every browser supports this.

[This interactive/preview is only available on the website.]
.underline-me {
	text-decoration: underline red solid 3px;
}

Workarounds

Since some browsers don't support text-decoration, here are the alternatives I could think of.

border-bottom

The workaround Schade describes is using border-bottom, though it has a gap between the text in the line.

[This interactive/preview is only available on the website.]
I am <span class="underline-me">underlining this yap</span> within the sentence.
.underline-me {
	border-bottom: red solid 3px;
}

::after

Probably the better way is to create an ::after element, which gets very close, but displays above the text (covering the letters 'g' and 'y').

[This interactive/preview is only available on the website.]
I am <span class="underline-me">underlining this yap</span> within the sentence.
.underline-me {
	position: relative;
}
.underline-me::after {
	content: '';
	position: absolute;
	width: 100%;
	height: 3px;
	background-color: red;
	left: 0;
	bottom: 2px;
}

::after in a container

If you use a container (in this case, two nested <span>s instead of just one), then you can get very close with the underline displaying below the text.

[This interactive/preview is only available on the website.]
I am
<span class="underline-me-ctn">
	<span class="underline-me">underlining this yap</span>
</span>
within the sentence.
.underline-me-ctn {
	position: relative;
}
.underline-me {
	z-index: 10;
	position: relative;
}
.underline-me-ctn::after {
	content: '';
	position: absolute;
	width: 100%;
	height: 3px;
	background-color: red;
	left: 0;
	bottom: 2px;
}

::after in a container with text stroke

And now if you add a stroke to the text via -webkit-text-stroke, you're pretty much there, though this may not be feasible in some situations (e.g. gradient or image background behind the text). Support for -webkit-text-stroke is not that much better than text-decoration though, so make of that what you will.

[This interactive/preview is only available on the website.]
I am
<span class="underline-me-ctn">
	<span class="underline-me-outline">underlining this yap</span>
	<span class="underline-me">underlining this yap</span>
</span>
within the sentence.
.underline-me-ctn {
	position: relative;
}
.underline-me-outline {
	z-index: 5;
	position: absolute;
	left: 0;
	color: var(--background);
	-webkit-text-stroke: 0.3em var(--background);
}
.underline-me {
	z-index: 10;
	position: relative;
}
.underline-me-ctn::after {
	content: '';
	position: absolute;
	width: 100%;
	height: 3px;
	background-color: red;
	left: 0;
	bottom: 2px;
}
  •  

Steinar H. Gunderson: Decompiler patterns, part 8: Un-repetition of conditions

Today, for a slightly more complicated snippet, but still in the same general area; say you have code like this:

x = (0x1000 - y) / 24;
z = var_s5 < 5;
if (x >= 0x81) {
    x = 0x80;
    z = var_s5 < 5;
}
var_s4 = 0;
if (z == 0) {

In particular, note the z = var_s5 < 5; repeated. Most likely, this is the compiler sticking stuff into branch delay slots, or else re-checking the condition if var_s5 changed in the branches (it does not here). You almost certainly want to undo this into:

x = (0x1000 - y) / 24;
if (x >= 0x81) {
    x = 0x80;
}
var_s4 = 0;
if ((var_s5 < 5) == 0) {

and the if, as we already know, should probably rather then be:

if (var_s5 >= 5) {

For a small bonus (since I'm not going to have a separate post about it), you can choose to change the upper if to:

if (x > 0x80) {
    x = 0x80;
}

which generates exactly the same code (on MIPS), but may in many cases be easier to understand.

  •  

Russ Allbery: Review: Daggerbound

Review: Daggerbound, by T. Kingfisher

Series: Swordheart #2
Publisher: Bramble
Copyright: 2026
ISBN: 1-250-40009-0
Format: Kindle
Pages: 436

Daggerbound is a secondary-world fantasy and a sequel to Swordheart, although it follows different protagonists for most of the book. It's also a sort of sequel to the Clocktaur War duology in that one of the protagonists was a protagonist of those books. T. Kingfisher is the pen name Ursula Vernon uses for her adult fiction.

Learned Edmond was once a devout acolyte of the Order of the Many-Armed God and a true believer in its teachings, including the ones about the evils of women. Then he went on an adventure with, among other people, a forger named Mistress Slate, during which he learned a great deal of things about the world that his order did not teach him. He has spent the subsequent years trying to bring this important new information to his order and encourage them to adjust their view of the world accordingly.

The order has not changed, and Edmond is very tired.

Someone needs to carry a number of books and a magical sword to the city of Archon's Glory. Edmond has volunteered and intends to perform the task exactly as expected, and then never return. He is unsure what he will do then, but at least it will be different.

Edmond did not expect to be waylaid by bandits or to accidentally draw the magical sword. He certainly did not expect the man who appeared in a flash of light and violently saved him from the bandits.

It would have been very convenient for the Dervish if Edmond died of his injuries after drawing the sword. That would leave the sword without a wielder and therefore the Dervish without someone he had to protect. All he would have to do was sit and watch while the fever and cold and lack of water did the work, and then he would be free. Given his past experience with wielders, no one could even blame him. Except maybe his own conscience.

I did not realize I wanted to read a novel about a traumatized Mercedes Lackey sword waking up in a T. Kingfisher universe, but apparently I did.

The Dervish is not a sword, precisely, at least not in the way that Need has become by the time we meet her in Lackey's novels. He's a man trapped in a sword, he doesn't like it, and he would very much like it to stop. But at the start of the book, he has the rest of the vibe of a Mercedes Lackey protagonist: vast past trauma, poor emotional regulation skills, and a prickly cynicism that only runs skin deep. Pairing him with an Edmund who is far more mature than in the earlier duology but still rather innocent and delightfully neurodivergent is a great touch.

The rest of the plot was fine but not that memorable. Like the Clocktaur series, there is a strong feeling of episodic D&D adventure as the characters stumble across disconnected problems and hostilities while collecting party members. Like Ursula Vernon's occasional D&D recaps, this party has a tendency to adopt everyone they come in contact with, which includes a gnole (as always one of the best parts of the book) and a sentient giant pill bug. The pill bug, who has a complex appendage-operated mechanical talk box and a banner that says "I DO NOT EAT HUMAN MEAT," is the most Ursula Vernon character that has ever existed in fiction.

There is a romance because there is always a romance in the novels set in this universe. I didn't mind this one. Like every Kingfisher romance, it involves a lot of irritating refusal to communicate and endless angst about how the other person couldn't possibly be in love with them, but the characters have rather more justification than usual and at least I didn't spend most of the book thinking one half of the romantic pairing was an idiot. Apparently it helps if no paladins are involved.

The strongest parts of this book are the beginning, before the Lackey vibes unfortunately drain out of the story, and the end, when all of the best characters from Swordheart show up again. The Temple of the White Rat continues to be the best feature of this fictional universe, and I could read endless books about how they solve problems.

The Dervish gazed at her with admiration. "And here I thought you'd be on the side of law and order..."

"No, young man," said Beartongue, despite being several centuries his junior. "I am on the side of justice. If we're lucky, the two run in parallel. If they don't, we bend the law to attain justice, not the other way around."

The ending also featured some exploration of the edge cases of the rules for the sentient swords that reminded me a bit of Fred Saberhagen with better characterization.

Daggerbound was not as charming as Swordheart, mostly because Halla appeared only at the end. I wish Kingfisher had leaned more into the Mercedes Lackey vibes rather than taking her normal D&D-flavored romance approach. But this was enjoyable, charming at times, had great supporting characters like all Kingfisher novels, and was a satisfying continuation of the series. I am looking forward to the third (and I believe final) book, which is supposed to be out next year.

Recommended if you liked Swordheart.

Followed by the not-yet-published Shieldborn.

Rating: 7 out of 10

  •  

Utkarsh Gupta: FOSS Activities in September 2026

Here’s my monthly but brief update about the activities I’ve done in the FOSS world.

Debian

Whilst I didn’t have much time, here are still a few things that I worked on:

  • Sponsored ubuntu-dev-tools/0.214 for Florent ‘Skia’ Jacquet, which updates seeded-in-ubuntu to use the new per-series indexer (LP: #2160240).
  • Assisted a few folks in getting their patches submitted via Salsa.
  • Mentoring for newcomers.
  • Moderation of -project mailing list.

Ubuntu

I joined Canonical to work on Ubuntu full-time back in February 2021.

  • With 26.10 in Feature Freeze, wore my Release team hat to:
    • Review and approve a bunch of Feature Freeze Exceptions, including the Go 1.27 transition, Qt 6.11.2, rust-coreutils 0.12.0, devscripts 2.6.12, kdump-tools moving to dracut, and a few GCE packages.
    • Point linux-entra-sso to the SRU team, as it didn’t need an FFe at all, and milestone a couple of bugs for 26.10.
  • Continued to push for infrastructure improvements:
    • Made ubuntu-cdimage more resilient to Launchpad hiccups (MP).
    • Taught generate-freeze-block in ubuntu-archive-tools a couple of new options (--skip-update and --series) and better error handling (MP).
    • Bumped the arm64 generic non-cloud image to 4.5G in livecd-rootfs and uploaded it as 26.10.16; also sponsored the follow-up 26.10.17 for Chloé.
  • Sponsored aevol/9.4.0-2ubuntu1 for Matthieu, fixing an FTBFS with GCC 15’s LTO (LP: #2167811).
  • Reviewed quite a lot of MPs - britney hints, meta-release, ubuntu-release-tools, ubuntu-archive-tools, ubuntu-cdimage, livecd-rootfs, ubuntu-seeds, and so on.
  • Enabled upgrades to 26.04 LTS.
  • Released 26.10 Beta and announced it on Discourse.
  • Did Archive Admin, DMB, and Release team duties as usual.

Debian (E)LTS

This month I have worked 33.5 hours on Debian Long Term Support (LTS) and on its sister Extended LTS project and did the following things:

(A quick note that I did quite a lot of the work during my work as Frontdesk that went on till 4th Oct, so 33.50 hours include the work I did till 4th October 2026.)

Released Security Updates

  • node-lodash: Prototype pollution in _.unset and _.omit (plus a bypass of the initial fix for it), and code injection via the imports option of _.template.

    • [LTS]: Fixed CVE-2025-13465, CVE-2026-2950, and CVE-2026-4800 via 4.17.21+dfsg+~cs8.31.198.20210220-9+deb12u1 for bookworm. This has been released as DLA 4820-1.
    • This is the bookworm follow-up to DLA 4663-1 that I carried over from July. The update had been sitting prepared and tested on debusine, so once the upstream discussion wrapped up, it went straight out. It also carries an extra patch to the lodash-cli dependency map - without it, the regenerated lodash.template module throws “assignWith is not defined” at runtime, which node-gulp-util’s autopkgtest caught.
  • libpng1.6: Use-after-free of zlib input in png_read_end() after incomplete zTXt, iTXt, or iCCP decompression, which could result in denial of service.

Work in Progress

  • libpng1.6: The same CVE-2026-46675.
    • [ELTS]: Claimed in ela-needed; the same upstream fix applies to all three ELTS suites, so this should go out shortly.

Other Activities

  • [E/LTS] Did my front-desk week from 28-09 to 04-10.

    • Over the week I did roughly:
      • Triage of 524 unique CVEs across 192 source packages and all four suites. And 1 automated ELTS end-of-life sweep.
      • Additional data is now part of the front-desk job too, so 75 commits record it for 179 CVEs across 71 packages.
    • Newly queued 22 source packages - 13 in dla-needed (apache2, chromium, firefox-esr, libnet-idn-encode-perl, libpng1.6, node-shell-quote, nvidia-graphics-drivers, openssl, pcre2, php-mongodb, php8.2, social-auth-core, and wpa) and 16 in ela-needed (apache2, firefox-esr, gegl, lemonldap-ng, libnet-idn-encode-perl, libpng1.6, libwebsockets, nsd, nvidia-graphics-drivers, pcre2, php7.0, php7.3, php7.4, rar, unrar-nonfree, and wpa), 7 of them in both. Also widened 3 ELTS entries to bullseye - antiword, ocaml, and openvswitch.
    • Most of the interesting work was again in the <not-affected> verdicts: 217 of 263 (83%, across 57 packages) rest on showing that the vulnerable code or feature isn’t in the source we ship. Another 17 cover incomplete upstream fixes that we either never shipped or shipped with the follow-up already in (expat, libxml2, node-tar, and pyjwt). 15 come from bundled components we don’t ship - node-ajv again, which uses uri-js and not fast-uri, and nvidia-open, which doesn’t ship the NGX updater. And 13 are vendor- or platform-specific - openssh’s CVE-2026-55654 lives only in a Red Hat GSSAPI patch, and the netdata and PHP ones only affect Windows.
    • Did 4 rounds of newly supported bullseye packages (33 packages overall), plus libmail-mboxparser-perl for buster - 34 in all. The existing CVE data mostly held up; the real finds were discovery gaps. One interesting gotcha: sid renamed stunnel4 to stunnel, and two new CVEs were associated only with the new name, so they never showed up for trixie, bookworm, or any ELTS suite. I also sorted the 180 “Triage needed” entries (57 packages) from elts-eol by where each was already handled, and triaged for ELTS the 100 that trixie or bookworm had already decided; the rest come next. And I imported 79 package-level lines for the older source names ELTS still ships (tomcat8, php7.0/7.3/7.4, netty-3.9, openssl1.0, python2.7/3.5/3.7, and pypy).
    • Caught some inconsistencies in released advisories: DLA 4801-1 (swift) was missing a CVE, ELA 1831-1 (redis) listed the wrong one, and DLA 4808-1 (network-manager-l2tp) listed CVE-2026-75883 - an ID that was renamed and then reassigned to an unrelated ppp issue. I fixed all three in the tracker’s advisory lists.
    • Made the Security team and the uploaders aware of regressions from our own updates:
      • libde265: the CVE-2026-49337 fix in DLA 4789-1/ELA 1828-1 (and DSA 6413-1) misses upstream’s follow-up commit.
      • libxml2 CVE-2026-76781 and policykit-1 CVE-2026-85498 were introduced by our own back-ports; the policykit-1 one is harmless.
      • expat: the CVE-2025-59375 backport in DLA 4807-1 is compiled out, because XML_GE is never defined.
      • xen: DLA 4818-1’s XSA-491 fix makes XSA-510 reachable.
      • gegl: the CVE-2026-2049/2050 back-port in ELA 1650-1 rejects valid RLE .hdr files.
      • log4cxx: DLA 4322-1 broke UTF-8 in JSONLayout output. That one is functional, not security.
    • Helped correct a set of triages and let the Debian Security team know:
      • ruby-json CVE-2026-71847: the vulnerable code was never in a released Debian version.
      • openssh CVE-2026-55654: only affects a Red Hat-specific GSSAPI patch.
      • three libxml2 issues that don’t affect trixie either.
      • the stunnel4 rename above.
      • trixie <no-dsa> lines on jsch, node-qs, and ruby-loofah, where trixie’s version doesn’t have the vulnerable feature at all.
    • Independently found a security issue in rclone and reported it privately upstream through a GitHub security advisory. Upstream already had a report for the same issue, so they folded mine into the existing advisory and credited me as a co-reporter.
    • Also found some bugs in the additional-data tooling, e.g. cve-ad --package P --severity tbd wipes the CVE-level severity, and the schema doesn’t validate package-level entries at all.
  • [E/LTS] Monitored discussions on mailing lists, IRC, and all the documentation updates.

  • [E/LTS] Attended the monthly LTS meeting on IRC. Meeting notes here.


Until next time.
:wq for today.

  •  

Steinar H. Gunderson: Decompilation patterns, part 7: if to condition

A variation of the pattern from yesterday; say you have:

if (x == 3) {
    y = 0;
} else {
    y = 1;
}

When these are zero and one, sometimes this will give a better match, since booleans are evaluated as such:

y = (x != 3);

It's rare to have something else than zero or one work for this pattern (e.g. you would rarely write y = (x != 3) * 2 + 1).

  •  

Tim Retout: Reading my solar inverter over RS485

For over ten years, the only way I have had of knowing what our solar panels are doing has been an impulse monitor on the generation meter, counting the flashes of its LED. It has always been a bit flaky due to battery changes or loose connections, and there has never been a way to see solar generation alongside the energy used by the rest of the house. This week I have fixed that, by building a small ESPHome sensor which talks directly to the inverter. I am still reeling slightly: with AI assistance, it took under a week from idea to working implementation, and it is a project I would certainly never have attempted otherwise. The result is zeversolar-esphome.

The inverter is a Zeversolar Zeverlution 3680, which has an RS485 port but no Wi-Fi or Ethernet module. It doesn’t speak Modbus; it uses Eversolar’s own master/slave protocol, which nobody has officially documented but which several people have reverse-engineered over the years (credit to eversolar-monitor, Heliograph and others). Manufacturer support for Eversolar/Zeversolar inverters apparently ended in December 2019 when the company went out of business.

The rating plate on the side of the inverter, reading Model: Zeverlution 3680, with its input and output ratings and safety symbols.

The rating plate on my inverter.

A while ago I had looked into what ports were available on this inverter with a view to connecting some sort of monitoring, but I had abandoned it as “too hard”. While working on some Home Assistant configuration, Claude suggested the idea again, but similarly wrote it off initially. I encouraged it to explore a bit further, and supplied the model number of the inverter, at which point the picture got a lot more promising. After a bit of back-and-forth about hardware, we settled on an M5Stack Atom Lite on an Atomic RS485 Base. The main attraction was that it already comes in a case, so I didn’t need to design (or, more likely, bodge) an enclosure.

While I waited for the parts to arrive, Claude wrote the firmware: an ESPHome external component built around a small, dependency-free C++ driver, with host-side unit tests against byte captures that other people had published from other models. I found it slightly surreal to have a tested protocol driver before owning any hardware to run it on.

Cables

The parts came before the tools I needed to get into the inverter safely (a DC clamp meter and a T25 screwdriver bit), so in the meantime I made up an RS485 cable - this uses an RJ45 connection at one end, and some custom wiring at the other. My first attempt was with some CAT 6, but (as Claude had pointed out and I had ignored) its solid-core conductors are much harder to twist together. So I gave up and sacrificed an old CAT 5e patch lead instead, which went much better.

The cut end of a white CAT 5e cable, with its twisted pairs pushed into an orange four-way screw-terminal plug.

The custom end of the cable, before being taped up.

The risky bit

On a Zeverlution, the RJ45 sockets are inside the wiring compartment, which means taking the cover off to install the monitor. The manual addresses this part to qualified electricians. So the step I was most nervous about was not the software at all, but safely isolating the inverter.

The inverter with its cover removed, showing large capacitors along the top, a green circuit board with a small LCD display, and cable glands along the bottom edge.

Inside the inverter, with the cover off.

I did this with appropriate caution, following the instructions from the manual carefully, and also waiting until after dark just in case. Now that I understand how the DC clips from the panels work, I can see how to do this safely during daytime too – but hopefully this won’t be necessary.

A yellow RJ45 plug in one of the two network sockets on the inverter's circuit board, with its white cable running out through a cable gland in the base.

Plugged in, and threaded through the cable gland.

Warning: if you’re not confident, I would always advise to get an electrician to do this bit. Do what I say, not what I do.

Debugging over Wi-Fi

Once the device was installed, the nice thing about ESPHome is that I never need to go back in the loft again to update it – it reflashes over Wi-Fi. I’ve taken full advantage of this for debugging, and for reading the wire protocol directly from the logs.

A hand holding the small grey M5Stack Atom Lite on its RS485 base, with the inverter cable taped into the screw terminals on top and its status LED glowing green.

The finished device. Green means generating.

Separately, I’ve used Claude to integrate the new sensors into Home Assistant. Solar generation finally sits in the Energy dashboard next to the rest of the house’s usage, which was the whole point.

Reflections

This was a fun, quick project, and it solved a problem that has eluded me for a decade. I want to be honest about how much of that is down to the AI: I would not have attempted any of this on my own. I could not have told you the protocol existed, never mind implemented it. My contribution was everything involving a screwdriver, and ordering some hardware.

  •  
❌