|
|
Subscribe / Log in / New account

Debian Technical Committee overrides systemd change

By Joe Brockmeier
October 13, 2025

Debian packagers have a great deal of latitude when it comes to the configuration of the software they package; they may opt, for example, to disable default features in software that they feel are a security hazard. However, packagers are expected to ensure that their packages comply with Debian Policy, regardless of the upstream's preferences. If a packager fails to comply with the policy, the Debian Technical Committee (TC) can step in to override them, which it has done in the case of a recent systemd change that broke several programs that depend on a world-writable /run/lock directory.

The Filesystem Hierarchy Standard (FHS) specifies that the /var/lock directory should be used to store lock files for devices and other resources shared by multiple applications. On Debian, /var/lock is a symbolic link to /run/lock. The /run directory is created as a tmpfs filesystem specifically for run-time files by systemd-tmpfiles during system startup.

Debian Policy still cites the FHS, even though the FHS has gone unmaintained for more than a decade. The specification was not so much finished as abandoned after FHS 3.0 was released—though there is a slow-moving effort to revive and revise the standard as FHS 4.0, it has not yet produced any results. Meanwhile, in the absence of a current standard, systemd has spun off its file-hierarchy documentation to the Linux Userspace API (UAPI) Group as a specification. LWN covered that development in August, related to Fedora's search for an FHS successor.

Locking up /run/lock

The /run/lock directory was deprecated in Systemd v258; rather than dropping the directory entirely, though, the project has changed the default to making /run/lock writable only by root, which is stricter than the permissions Debian had shipped with previously rather than making it world-writable as in the past. The plan is to get rid of /run/lock entirely in the v259 release, though users (or distributions) can still retain the legacy behavior by adding a configuration file in /etc/tmpfiles.d to override systemd's defaults and create the directory with the desired permissions.

The Debian project just released a new stable version, Debian 13 ("trixie"), in August, and work has begun on Debian 14 ("forky"). The current stable version of Debian shipped with systemd v257, so users on stable will not be affected by these changes. But v258 has entered Debian unstable where the change to /run/lock broke other software, such as the Unix-to-Unix Copy program (UUCP) and the cu utility. Use of the directory is not limited to vintage utilities; Zbigniew Jędrzejewski-Szmek objected to removing /var/lock in v259 as it would break alsa-utils and create additional work for distributions:

Doing this would this way just creat a foottrap for distributions: if they notice the change, they'll just create a local override, so we get a more complicated system in total with zero benefit to anyone. If they miss it, things will be broken for a while until users report it. And then they'll add the override.

On August 13, Marco d'Itri—who is listed as a maintainer of the systemd package—filed a bug against the uucp package reporting that systemd v258-rc1-1 had broken uucico, along with filing a bug against the systemd package, which cited the FHS entry for /var/lock. He said that a compromise might be to make the directory writable by the dialout group rather than world-writable. He also mentioned that there was a previous effort in 2014 to modernize software that uses UUCP-style locks to use flock() instead, but it stalled out.

"Dead and severely outdated"

Rather than temporarily reverting the behavior, systemd maintainer Luca Boccassi argued that a world-writable directory in /run is a security risk. Any process could write as much as it wanted to /run, which could effectively DoS the system by exhausting space or inodes; filling up /run would then cause critical services, such as udev, to stop working. The FHS, he said, is "dead and severely outdated".

The issue had already been discussed by the systemd project; Lennart Poettering had responded that he did not see the point of /var/lock "in the modern world", but distributions were free to do as they see fit:

Consider this more a passing of the baton from upstream systemd to downstreams: if your distro wants this kind of legacy interface, then just add this via a distro-specific tmpfiles drop-in. But there's no point really in forcing anyone who has a more forward-looking view of the world to still carry that dir.

Poettering argued that distributions could make their own choices, though it made him shudder to think of allowing unprivileged programs to fill up a directory. Boccassi echoed that sentiment in his response to the Debian systemd bug. Any package could ship a configuration for tmpfiles.d to create the directory and assume responsibility for it as well:

I certainly won't try to stop anyone wishing to do it, but also I do not wish for these old workarounds to ship in this package either.

There's ~2 years time until Forky ships, and that should be plenty of time to either add this workaround elsewhere, or fix remaining programs to use BSD locks, or both, so I'm not going to hold back the new version from testing for this niche case, sorry.

Boccassi closed the bug with the "WONTFIX" tag.

Debian Policy

On September 1, d'Itri responded that upstream systemd's opinion was not relevant in this case. Debian policy requires the directory for lock files of serial devices, though he had also opened a bug to revisit that, since the practice of using /var/lock for serial-device locks dates back to the 1980s. However, /var/lock is provided by systemd, so he reasoned that it is a systemd bug unless another package was identified to take ownership of creating the directory. "But you cannot just decide that the policy violation does not exist."

Thorsten Alteholz opened a bug with Debian's Technical Committee on September 15. He asked for advice on how to proceed since the systemd bug had been marked WONTFIX.

So what do you recommend how to go on from here? Change Debian policy (as asked in #1111839), revert the change in systemd, find a Debian wide solution or let every package maintainer implement their own solution?

Bdale Garbee weighed in on the bug as well. He said that he uses cu "almost constantly for interacting with embedded serial consoles on devices a USB connection away from my laptop". He was frustrated with the change imposed by systemd "with no warning", and looked forward to the TC's response.

On September 24, Matthew Vernon responded to the bug, with a CC to the systemd maintainer alias. He said that it seemed that Debian Policy required FHS compliance, "at least until we come up with a transition plan", and asked if systemd would please revert the change. There was no response from any of the systemd maintainers.

Override

Vernon updated the bug on September 29, and said that the TC had discussed the situation at its last meeting. The conclusion was that systemd should comply with policy, and thus FHS. He included a draft ballot text that the TC would vote on, which noted that the committee was "sympathetic" to the argument that flock() would be a better solution, but that "an important part of the role of a Debian Developer is ensuring that software in Debian complies with Debian Policy". A final ballot for the committee to consider was posted on October 2.

The ballot contained three options; all three required that the systemd package provide /var/lock "with relaxed enough permissions that existing Debian software that uses /var/lock for system-wide locks of serial devices (and similar purposes) works again". The committee would exercise its power under the Debian Constitution to override the systemd maintainers. The options were:

1) This change to systemd must persist until a satisfactory migration of impacted software has occurred and Policy updated accordingly.

2) This change to systemd must persist until Policy has been updated to allow otherwise.

3) This change to systemd must persist until the TC allows otherwise, which the TC expects to do once a suitable transition plan has been agreed.

Vernon replied on October 6 to say that a decision had been reached and that option one had won.

Unlocking

Debian's continued use of UUCP-style locking does seem to be more than a little bit dated. The FHS 3.0 is clearly reaching the end of its useful life, if not actually expired.

As a comparison, Fedora's uucp package has a patch to use lockdev instead. The upcoming Fedora 43 release includes systemd v258, and /run/lock is not world-writable. It seems like Debian could borrow Fedora's approach for the uucp package, though that would not solve the problem for any other Debian packages affected by the /run/lock change. There is also third-party software to consider, of course.

To date, Boccassi has not responded to the conversation; I emailed d'Itri to ask why he did not make the change himself, since he was aware of the bug. He replied on October 13 and said that "a maintainer cannot force a decision on another maintainer." Since he and Boccassi disagreed about the change it was left to the TC to decide. He said that he planned to prepare a merge request to implement the TC's decision, "as I have already agreed with Luca", within the week.



to post comments

Progress with a Plan

Posted Oct 13, 2025 19:34 UTC (Mon) by honschu (subscriber, #61008) [Link] (12 responses)

Yes, systemd wants to move ahead. Yes, tools still rely on FHS. Breakage hurts and legacy drags - let's stay connected through the shared aim of a great OS: fix for users now, publish a plan, and phase out UUCP-style locking cleanly.

Progress with a Plan

Posted Oct 13, 2025 20:49 UTC (Mon) by mb (subscriber, #50428) [Link] (10 responses)

>fix for users now

That is not possible for users without source code.
What is your plan for those?

Progress with a Plan

Posted Oct 13, 2025 21:49 UTC (Mon) by edgewood (subscriber, #1123) [Link] (7 responses)

Perhaps to document how to add "a configuration file in /etc/tmpfiles.d to override systemd's defaults and create the directory with the desired permissions“.

There's a difference between slowing down a reasonable change to give open source programs a chance to get updates and never making it because closed source programs can't update.

Progress with a Plan

Posted Oct 14, 2025 0:41 UTC (Tue) by smurf (subscriber, #17840) [Link]

That would be too easy, apparently.

Progress with a Plan

Posted Oct 14, 2025 1:25 UTC (Tue) by mjg59 (subscriber, #23239) [Link] (4 responses)

It's more complicated than that - the issue includes different apps trying to access the serial port. If app A locks using flock() and app B locks using /run/lock then both can try accessing the port simultaneously. Bridging the two probably involves making it be a FUSE filesystem that then flock()s the right thing.

Progress with a Plan

Posted Oct 14, 2025 1:32 UTC (Tue) by josh (subscriber, #17465) [Link] (3 responses)

For any software that can be modified, bridging the two is as simple as "do both, in a well-defined order, to be compatible with software that hasn't yet transitioned to flock; if you can't get the traditional lock because it's taken, handle that as the lock being held; if you can't get the traditional lock because you don't have permission to the directory, ignore it".

Progress with a Plan

Posted Oct 15, 2025 2:38 UTC (Wed) by Hello71 (subscriber, #103412) [Link] (2 responses)

your algorithm only works if the modern program is started after the legacy program. in the reverse order, they will both obtain the lock.

Progress with a Plan

Posted Oct 15, 2025 3:12 UTC (Wed) by josh (subscriber, #17465) [Link] (1 responses)

No, it works in any of the possible orderings:

1) Modern flock, modern traditional lock, legacy traditional lock: The modern program has the lock, the legacy program waits until the modern program is done.

2) Modern flock, legacy traditional lock, modern traditional lock: the legacy program has the lock, the modern program is waiting on the traditional lock before it can run.

3) Legacy traditional lock, modern flock, modern traditional lock: The legacy program has the lock, the modern program is waiting on the traditional lock before it can run.

Progress with a Plan

Posted Oct 16, 2025 13:17 UTC (Thu) by edeloget (subscriber, #88392) [Link]

But then it won't work if two modern programs implement the locks in different orders. So such a change would require upstreams to at least agree on the lock order and widely publicize their decision. I'm not sure this is as easy as it sounds.

Progress with a Plan

Posted Oct 19, 2025 7:20 UTC (Sun) by thoeme (subscriber, #2871) [Link]

Interesting, openSuSE 15.6 has the same issue, and as I am using minicom with various serial ports on an almost daily base as a standard user, this behaviour was/is rather annoying. I of course "fixed" this with quick go+rw /var/lock as "root", which held until the next reboot.

>add "a configuration file in /etc/tmpfiles.d to override systemd's defaults
I wasn't aware of that possibility, something to check next monday at work.

Progress with a Plan

Posted Oct 13, 2025 21:58 UTC (Mon) by tux3 (subscriber, #101245) [Link] (1 responses)

Well, beyond the specifics of this particular systemd change, are those binary-only packages part of the OS, or do they come from an external vendor?
If you get updates from your third-party vendor, I suppose you'd talk to them to learn what the plan is.
More times than I'd like I've been held back from updating the distribution for the sake of enterprise-quality vendor tools.

There are also historical artifacts that don't receive updates, don't have a source to patch, and don't have a community fixing the binary directly. The kernel doesn't break those too often, so for containers have worked nicely, as a little time capsule.

But third-party binaries aren't really participating in this whole free software distribution project. You can't really plan around people who are doing their own thing and throwing opaque blobs over the wall every so often.

Re: Progress with a Plan

Posted Oct 14, 2025 5:02 UTC (Tue) by notriddle (subscriber, #130608) [Link]

> You can't really plan around people who are doing their own thing and throwing opaque blobs over the wall every so often.

You can, but you end up heavily limiting the amount of shared data that different subsystems/services/apps can see. Mere blocking isn't enough, because (1) this tends to result in systems that don't work when the permission is turned off, because that code path isn't tested (2) the existence of the file might be sensitive information in and of itself (3) what happens if two systems both think they should be able to use the same name for their things?

This also means any change of behavior that's visible to the blob has to be opt-in.

That's not how UNIX was designed. That's not even how Windows was designed, though MS has haphazardly added application-level namespacing features to patch around specific, widespread breakages. Hardened web browsers like Tor actually go in the right direction, but they only try to protect sites from each other: new APIs provided by the browser itself are dumped directly into the global namespace, and though they avoid adding anything that will cause widespread breakage, it's still possible for new browser-provided APIs to break a site by existing.

Other than hardware virtualization systems like MAME, does anything actually do better on backwards compat than web browsers?

Progress with a Plan

Posted Oct 13, 2025 21:38 UTC (Mon) by dmv (subscriber, #168800) [Link]

Yeah, honestly, when I read the title, I was thinking oh Lord, what drama is brewing in Debian-land now? But reading the story, it all looks fairly reasonable from both sides. And it’s a good example, I think, of how the infamously clunky bureaucratic processes of Debian align with and reinforce what makes Debian unique: its insistence on democratic processes, even where it would’ve been easier just to steamroll systemd packaging here (note the comment at the end in response to that question: because that’s now how things are supposed to work here). I know there are 1 million complaints, including from people who have deeply contributed to Debian and then become disillusioned with its processes, but I think this shows them in a good light.

What is the actual technical solution here?

Posted Oct 13, 2025 22:22 UTC (Mon) by skissane (subscriber, #38675) [Link] (1 responses)

I'm assuming it is just going to be that when Debian packages systemd, they add a /etc/tmpfiles.d config by default to restore world-writeable /run/lock?

Maybe I'm reading it wrong, but I came away from this article unclear what the final decision was.

What is the actual technical solution here?

Posted Oct 13, 2025 22:38 UTC (Mon) by mjg59 (subscriber, #23239) [Link]

The decision was around policy rather than mechanism - the maintainers are free to achieve the outcome through any technical approach they want.

New Package

Posted Oct 14, 2025 6:59 UTC (Tue) by stephanlachnit (subscriber, #151361) [Link]

I am a bit surprised why introducing a new package which contains the new tmpfiles config file? Then uucp et al can just depend on it and it can be gradually tackled without impacting the systemd package.

Single partition setups

Posted Oct 14, 2025 7:36 UTC (Tue) by rgb (guest, #57129) [Link] (4 responses)

Aren't now most systems installed with a single unified partition by default anyway, in which case making /var/lock read-only for general users isn't really helping anything at all? Having a reserved disk quota for root should be much more effective. Looks like a storm in a theoretical teacup. But I guess you have to start somewhere.

Single partition setups

Posted Oct 14, 2025 7:59 UTC (Tue) by MaZe (subscriber, #53908) [Link] (3 responses)

I believe nowadays stuff like this has a tendency to be a dedicated tmpfs mountpoint.
At least on my Fedora, /var/lock is -> /run/lock, and /run is tmpfs.

Single partition setups

Posted Oct 14, 2025 9:27 UTC (Tue) by rgb (guest, #57129) [Link]

On my NixOS setup only /run/keys is ramfs, but good point anyhow.

Single partition setups

Posted Oct 14, 2025 11:14 UTC (Tue) by aragilar (subscriber, #122569) [Link]

Same on my Debian systems (with / and /home being different partitions on lvm, which I think is the default, or at least one of the suggested options?).

Single partition setups

Posted Oct 14, 2025 12:38 UTC (Tue) by Jonno (subscriber, #49613) [Link]

On my Debian oldstable system /run/lock is a tmpfs separate from /run, and limited to 5 MiB (i.e. mounted with -O "nosuid,nodev,noexec,size=5120k"), which to my mind solves the DoS concerns (as at least only programs using /run/lock are affected, not any other program using /run). I didn't do anything special to get this, so I'm not sure where it comes from, but somehow reverting to this behaviour sound reasonable to me.

And if there is any problematic tmpfs mount in your typical Linux system it would be /dev/shm, as it has the same fs permissions, but mounted without noexec or any significant size restriction...

Quota?

Posted Oct 14, 2025 12:16 UTC (Tue) by eru (subscriber, #2753) [Link]

shudder to think of allowing unprivileged programs to fill up a directory

Wouldn't setting a quota for /run/lock be a solution to this concern? Same for other shared directories for temporaries.

Why not a separate tmpfs?

Posted Oct 14, 2025 12:27 UTC (Tue) by gray_-_wolf (subscriber, #131074) [Link] (2 responses)

If the worries are non-priviledged programs filling up /run, why just not make /run/lock a separate tmpfs, with reasonable size limits? Should that not protect against the inodes and space exhaustion while being significantly less nuclear option?

Why not a separate tmpfs?

Posted Oct 14, 2025 20:46 UTC (Tue) by fw (subscriber, #26023) [Link] (1 responses)

This was what Debian had before: https://salsa.debian.org/systemd-team/systemd/-/commit/7e...

The revert did not bring back the separate mount point, though: https://salsa.debian.org/systemd-team/systemd/-/commit/92...

I don't know why things are done this way.

Why not a separate tmpfs?

Posted Oct 15, 2025 3:19 UTC (Wed) by lutchann (subscriber, #8872) [Link]

I get that sometimes you have to agitate to move things forward, but I feel like the discussion could have acknowledged the history of the issue with more honesty.

Why was this a policy debate at all?

Posted Oct 15, 2025 3:49 UTC (Wed) by raven667 (subscriber, #5198) [Link] (1 responses)

I am going to reiterate what others have said, it seems like having this hardcoded in systemd is not required and the technical mechanism which creates /var/lock -> /run/lock is entirely a matter of configuration, fully supported by systemd without hardcoding anything, using systemd-tmpfiles. I'm fine with removing this from the main systemd software and leaving it up to local configuration, systemd is used on all sorts of different systems, not just servers/desktops which care about FHS, and having only the parts which are necessary for systemd to function hardcoded makes sense to me, leave everything else up to config. It seems like nothing needs to be reverted in systemd, unless the goal is not technical but social to prove that Debian can *make* the systemd project do/notdo something, if you can just drop a tmpfiles config in the package. Am I missing something, or does that about sum it up?

Why was this a policy debate at all?

Posted Oct 15, 2025 4:01 UTC (Wed) by mjg59 (subscriber, #23239) [Link]

There's no requirement on upstream systemd at all - this is purely about how it's packaged in Debian.

flock() versus lock file semantics

Posted Oct 16, 2025 7:44 UTC (Thu) by gdt (subscriber, #6284) [Link] (3 responses)

Does flock() even work for the task of locking serial port usage? Consider a serial port to a dumb modem with RS-232 control lines.

The device /dev/ttyS0 is open()ed and flock(, LOCK_EX) applied. The terminal program now has exclusive use of the modem and proceeds to use it. Later a line condition causes Data Carrier Detect to drop. The way to reinitiate the modem link is to close() and re-open() the device file: this will drop and then re-assert the Data Terminal Ready line, which makes the modem re-attempt a connection.

So with flock() there is a race condition which does not exist with a lock file: can the terminal program re-open() and re-flock() the device faster than the competition?

The semantics of the lock file is "This program desires to use the serial device". That desire can remain even if the serial port is close()ed. The semantics of flock()ing the device cannot survive a close().

flock() versus lock file semantics

Posted Oct 16, 2025 12:31 UTC (Thu) by chris_se (subscriber, #99706) [Link] (2 responses)

> The device /dev/ttyS0 is open()ed and flock(, LOCK_EX) applied. The terminal program now has exclusive use of the modem and proceeds to use it. Later a line condition causes Data Carrier Detect to drop. The way to reinitiate the modem link is to close() and re-open() the device file: this will drop and then re-assert the Data Terminal Ready line, which makes the modem re-attempt a connection.

You can set the status of the DTR line via TIOCM_DTR on an open device, see also <https://man7.org/linux/man-pages/man2/TIOCMSET.2const.html>. There is no need to close the serial device. This is completely race-free.

I don't think lockfiles are a good idea in any way, shape or form, because especially with modern containerization solutions, the only guarantee you have as a program is that if you can open() and flock() the device, you are allowed access to it. With containers you might not even see the same lock directory as the rest of the system (or another container), whereas you might have access to the same serial device.

Hence I completely agree that getting rid of /var/lock and /run/lock is the right thing to do, it's just that in the current state of affairs this change should be coordinated with other software before the lock directory is phased out, so I do agree with Debian's TC's decision here.

Side note:

Actually, flock(, LOCK_EX) by itself is not sufficient to properly lock a serial port: every time a port is opened on Linux, at least some of the port's settings are reset to their defaults, even if it's already open. So the proper thing to do in my opinion is:

1) First flock(fd, LOCK_EX) it to avoid races
2) second ioctl(fd, TIOCEXCL) to prevent further opens

You need both LOCK_EX and TIOCEXCL: TIOCEXCL prevents the open() command from other processes from working, so that other programs can't open the same device while your program is handling it, preventing some settings to be reset. flock() is still needed regardless, because otherwise you might have a race condition where process A calls open(), then process B calls open(), then process A calls ioctl(), and then process B calls ioctl(), and they both succeed (they would only prevent a process C from calling open() thereafter, the ioctls will both succeed), so use the flock() to avoid that specific race as well.

(Caveat: TIOCEXCL doesn't help against root, but ideally you should run as little stuff as possible as root anyway.)

flock() versus lock file semantics

Posted Oct 20, 2025 2:45 UTC (Mon) by gdt (subscriber, #6284) [Link] (1 responses)

> You can set the status of the DTR line via TIOCM_DTR on an open device

That changes the semantics of the end of a login session from a dial-in modem. The user terminates the shell, and that file close brings down DTR, clearing down the call. To adjust to this behaviour every shell will need to be updated.

Whereas currently the system boot can create a lock file for every dial-in line to prevent its use by programs looking for a dial-out line.

flock() versus lock file semantics

Posted Oct 20, 2025 16:11 UTC (Mon) by hmh (subscriber, #3838) [Link]

These two posts are about the best take-home on the whole issue thus far IMHO (along with the reminder that the old way of setting up /var/lock had it as a separate 5MiB-maximum tmpfs, which is desirable over a default-limit tmpfs).

It is worth considering that using /var/lock to ensure dial-in and dial-out separation, or any other "reservation" can, in the end, be decently implemented by naming the serial devices you want for dial-out differently from the ones for dial-in, etc (udev/mdev/etc are perfectly capable of being configured to do so). Giving it a good UX might not be that easy, though, and going distro-specific here is a major loss.

The point about how classical tty-like devices behave ties in with the way other components (like the shells) work when plugged to a tty is very valuable.


Copyright © 2025, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds