Your message dated Sat, 14 Mar 2026 11:48:35 +0000
with message-id <[email protected]>
and subject line Released with 13.4
has caused the Debian Bug report #1129554,
regarding trixie-pu: package lxc/1:6.0.4-4+deb13u2
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
1129554: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1129554
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: trixie
User: [email protected]
Usertags: pu
X-Debbugs-Cc: [email protected], [email protected]
Control: affects -1 + src:lxc

[ Reason ]
Fix two bugs affecting the version of lxc in trixie:

  * Cherry-pick upstream fix for data corruption during heavy IO on PTS
  * Update lxc-default-with-nesting apparmor profile

[ Impact ]
Users running lxc in trixie currently encounter small but annoying
bugs. The apparmor profile update in particular will resolve may issues
with running hardened systemd services within unprivilged containers.

[ Tests ]
The PTS data corruption patch has been heavily tested upstream, and
I've personally tested/verified the apparmor profile update.

[ Risks ]
Minor/none -- one targeted fix cherry-picked from the upstream git repo
and a simple apparmor profile update.

[ Checklist ]
  [*] *all* changes are documented in the d/changelog
  [*] I reviewed all changes and I approve them
  [*] attach debdiff against the package in (old)stable
  [*] the issue is verified as fixed in unstable

[ Changes ]
Two patches as outlined above.

[ Other info ]
The source debdiff is attached.
diff -Nru lxc-6.0.4/debian/changelog lxc-6.0.4/debian/changelog
--- lxc-6.0.4/debian/changelog	2025-12-26 19:02:22.000000000 +0000
+++ lxc-6.0.4/debian/changelog	2026-03-02 19:05:00.000000000 +0000
@@ -1,3 +1,10 @@
+lxc (1:6.0.4-4+deb13u2) trixie; urgency=medium
+
+  * Cherry-pick upstream fix for data corruption during heavy IO on PTS
+  * Update lxc-default-with-nesting apparmor profile (Closes: #1111087)
+
+ -- Mathias Gibbens <[email protected]>  Mon, 02 Mar 2026 19:05:00 +0000
+
 lxc (1:6.0.4-4+deb13u1) trixie; urgency=medium
 
   [ Frost ]
diff -Nru lxc-6.0.4/debian/patches/0001-nesting-Extend-mount-permissions-in-apparmor-to-allo.patch lxc-6.0.4/debian/patches/0001-nesting-Extend-mount-permissions-in-apparmor-to-allo.patch
--- lxc-6.0.4/debian/patches/0001-nesting-Extend-mount-permissions-in-apparmor-to-allo.patch	2025-12-26 19:02:22.000000000 +0000
+++ lxc-6.0.4/debian/patches/0001-nesting-Extend-mount-permissions-in-apparmor-to-allo.patch	2026-03-02 19:05:00.000000000 +0000
@@ -9,22 +9,26 @@
 It's only added in nesting profile as it could pose security risks on
 privileged containers.
 
+mount options=(rw,rbind) -> /run/systemd/mount-rootfs/,
+mount options=(rw,rbind) -> /run/systemd/mount-rootfs/**,
 mount options=(rw,rbind) -> /run/systemd/unit-root/,
 mount options=(rw,rbind) -> /run/systemd/unit-root/**,
 mount options=(rw,rshared) -> /,
 mount options=(rw,nosuid,nodev,noexec) proc -> /run/systemd/unit-root/proc/,
 ---
- config/apparmor/profiles/lxc-default-with-nesting | 4 ++++
- 1 file changed, 4 insertions(+)
+ config/apparmor/profiles/lxc-default-with-nesting | 6 ++++++
+ 1 file changed, 6 insertions(+)
 
 diff --git a/config/apparmor/profiles/lxc-default-with-nesting b/config/apparmor/profiles/lxc-default-with-nesting
-index cd198be..01562a9 100644
+index cd198be..55b17c8 100644
 --- a/config/apparmor/profiles/lxc-default-with-nesting
 +++ b/config/apparmor/profiles/lxc-default-with-nesting
-@@ -10,6 +10,10 @@ profile lxc-container-default-with-nesting flags=(attach_disconnected,mediate_de
+@@ -10,6 +10,12 @@ profile lxc-container-default-with-nesting flags=(attach_disconnected,mediate_de
    mount fstype=proc -> /var/cache/lxc/**,
    mount fstype=sysfs -> /var/cache/lxc/**,
    mount options=(rw,bind),
++  mount options=(rw,rbind) -> /run/systemd/mount-rootfs/,
++  mount options=(rw,rbind) -> /run/systemd/mount-rootfs/**,
 +  mount options=(rw,rbind) -> /run/systemd/unit-root/,
 +  mount options=(rw,rbind) -> /run/systemd/unit-root/**,
 +  mount options=(rw,rshared) -> /,
diff -Nru lxc-6.0.4/debian/patches/0105-cherry-pick-fix-heavy-io-pts.patch lxc-6.0.4/debian/patches/0105-cherry-pick-fix-heavy-io-pts.patch
--- lxc-6.0.4/debian/patches/0105-cherry-pick-fix-heavy-io-pts.patch	1970-01-01 00:00:00.000000000 +0000
+++ lxc-6.0.4/debian/patches/0105-cherry-pick-fix-heavy-io-pts.patch	2026-03-02 19:05:00.000000000 +0000
@@ -0,0 +1,335 @@
+From 4cb9884ed7d3ca98ccd9bf2abbd508255b4e1fb7 Mon Sep 17 00:00:00 2001
+From: DreamConnected <[email protected]>
+Date: Sun, 26 Oct 2025 13:28:13 +0800
+Subject: [PATCH 1/2] lxc/{terminal, file_utils}: ensure complete data writes
+ in ptx/peer io handlers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Previously, lxc_write_nointr could return without writing all data
+when write() returned EAGAIN/EWOULDBLOCK due to buffer full conditions.
+
+This change:
+- Implements a loop to continue writing until all data is sent
+- Handles EINTR, EAGAIN, and EWOULDBLOCK errors appropriately
+- Uses poll() to wait for fd to become ready when blocked
+- Maintains backward compatibility while fixing partial write issues
+
+Signed-off-by: DreamConnected <[email protected]>
+[ alex ]
+- introduce a separate helper lxc_write_all and use it only in ptx/peer
+  io handlers
+- cleanup the code a bit
+Signed-off-by: Alexander Mikhalitsyn <[email protected]>
+---
+ src/lxc/file_utils.c | 86 ++++++++++++++++++++++++++++++++++++++++++++
+ src/lxc/file_utils.h |  2 ++
+ src/lxc/terminal.c   |  4 +--
+ 3 files changed, 90 insertions(+), 2 deletions(-)
+
+diff --git a/src/lxc/file_utils.c b/src/lxc/file_utils.c
+index e8bf9321b0..ea54939f30 100644
+--- a/src/lxc/file_utils.c
++++ b/src/lxc/file_utils.c
+@@ -11,6 +11,7 @@
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <time.h>
++#include <poll.h>
+ 
+ #include "file_utils.h"
+ #include "macro.h"
+@@ -147,6 +148,91 @@ ssize_t lxc_read_try_buf_at(int dfd, const char *path, void *buf, size_t count)
+ 	return ret;
+ }
+ 
++static int __lxc_wait_for_io_ready(int fd, int event, int timeout_ms)
++{
++	int ret;
++	struct pollfd pfd = {
++		.fd = fd,
++		.events = event,
++		.revents = 0
++	};
++
++	do {
++		ret = poll(&pfd, 1, timeout_ms);
++	} while (ret < 0 && errno == EINTR);
++
++	if (ret < 0)
++		return -errno;
++
++	if (ret == 0)
++		return -ETIMEDOUT;
++
++	if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
++		if (pfd.revents & POLLERR)
++			return -EPIPE;
++		if (pfd.revents & POLLHUP)
++			return -EPIPE;
++		if (pfd.revents & POLLNVAL)
++			return -EBADF;
++	}
++
++	if (!(pfd.revents & event))
++		return -EAGAIN;
++
++	return ret;
++}
++
++ssize_t lxc_write_all(int fd, const void *buf, size_t count)
++{
++	ssize_t left_to_write = count;
++	const char *ptr = buf;
++	int flags;
++
++	flags = fcntl(fd, F_GETFL);
++	if (flags < 0)
++		return ret_set_errno(-1, errno);
++
++	/* only non-blocking fds are allowed */
++	if (!(flags & O_NONBLOCK))
++		return ret_set_errno(-1, EINVAL);
++
++	while (left_to_write > 0) {
++		int ret = write(fd, ptr, left_to_write);
++
++		if (ret > 0) {
++			left_to_write -= ret;
++			ptr += ret;
++			continue;
++		}
++
++		if (ret == 0)
++			break;
++
++		/* ret < 0 */
++		if (errno == EINTR)
++			continue;
++
++		if (errno == EAGAIN) {
++			int pret = __lxc_wait_for_io_ready(fd, POLLOUT, 5000);
++
++			/* we've got an event on fd */
++			if (pret > 0)
++				continue;
++
++			if (pret == -ETIMEDOUT)
++				break;
++
++			if (pret < 0)
++				return ret_set_errno(-1, -pret);
++		}
++
++		/* some other error */
++		return ret_set_errno(-1, errno);
++	}
++
++	return count - left_to_write;
++}
++
+ ssize_t lxc_write_nointr(int fd, const void *buf, size_t count)
+ {
+ 	ssize_t ret;
+diff --git a/src/lxc/file_utils.h b/src/lxc/file_utils.h
+index 4fcaa47855..7d277dad33 100644
+--- a/src/lxc/file_utils.h
++++ b/src/lxc/file_utils.h
+@@ -35,6 +35,8 @@ __hidden extern int lxc_read_from_file(const char *filename, void *buf, size_t c
+     __access_w(2, 3);
+ 
+ /* send and receive buffers completely */
++__hidden extern ssize_t lxc_write_all(int fd, const void *buf, size_t count) __access_r(2, 3);
++
+ __hidden extern ssize_t lxc_write_nointr(int fd, const void *buf, size_t count) __access_r(2, 3);
+ 
+ __hidden extern ssize_t lxc_pwrite_nointr(int fd, const void *buf, size_t count, off_t offset)
+diff --git a/src/lxc/terminal.c b/src/lxc/terminal.c
+index 86fe785b6c..d066c2b9ee 100644
+--- a/src/lxc/terminal.c
++++ b/src/lxc/terminal.c
+@@ -338,7 +338,7 @@ static int lxc_terminal_ptx_io(struct lxc_terminal *terminal)
+ 	w_rbuf = w_log = 0;
+ 	/* write to peer first */
+ 	if (terminal->peer >= 0)
+-		w = lxc_write_nointr(terminal->peer, buf, r);
++		w = lxc_write_all(terminal->peer, buf, r);
+ 
+ 	/* write to terminal ringbuffer */
+ 	if (terminal->buffer_size > 0)
+@@ -375,7 +375,7 @@ static int lxc_terminal_peer_io(struct lxc_terminal *terminal)
+ 		return -1;
+ 	}
+ 
+-	w = lxc_write_nointr(terminal->ptx, buf, r);
++	w = lxc_write_all(terminal->ptx, buf, r);
+ 	if (w != r)
+ 		WARN("Short write on terminal r:%d != w:%d", r, w);
+ 
+
+From 97bd7699c79493f32fcee0f976b6c397cf0f0ad5 Mon Sep 17 00:00:00 2001
+From: Alexander Mikhalitsyn <[email protected]>
+Date: Wed, 21 Jan 2026 18:20:30 +0100
+Subject: [PATCH 2/2] tests/lxc-attach: ensure no data corruption happens
+ during heavy IO on pts
+
+Signed-off-by: Alexander Mikhalitsyn <[email protected]>
+---
+ src/tests/lxc-test-lxc-attach | 65 ++++++++++++++++++++++++++++++++---
+ 1 file changed, 61 insertions(+), 4 deletions(-)
+
+diff --git a/src/tests/lxc-test-lxc-attach b/src/tests/lxc-test-lxc-attach
+index 49289df5d3..720545f994 100755
+--- a/src/tests/lxc-test-lxc-attach
++++ b/src/tests/lxc-test-lxc-attach
+@@ -58,6 +58,7 @@ for i in $(seq 1 100); do
+ 	if [ "$attach" != "busy" ]; then
+ 		FAIL "lxc-attach -n busy -- hostname"
+ 	fi
++	rm -f "${ATTACH_LOG}"
+ done
+ 
+ # stdin  --> /dev/null
+@@ -67,6 +68,7 @@ attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- hostname < /dev/null
+ if [ "$attach" != "busy" ]; then
+         FAIL "lxc-attach -n busy -- hostname < /dev/null"
+ fi
++rm -f "${ATTACH_LOG}"
+ 
+ # stdin  --> attached to pty
+ # stdout --> /dev/null
+@@ -75,6 +77,7 @@ attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- hostname > /dev/null
+ if [ -n "$attach" ]; then
+         FAIL "lxc-attach -n busy -- hostname > /dev/null"
+ fi
++rm -f "${ATTACH_LOG}"
+ 
+ # stdin  --> attached to pty
+ # stdout --> attached to pty
+@@ -83,6 +86,7 @@ attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- hostname 2> /dev/null
+ if [ "$attach" != "busy" ]; then
+         FAIL "lxc-attach -n busy -- hostname 2> /dev/null < /dev/null"
+ fi
++rm -f "${ATTACH_LOG}"
+ 
+ # stdin  --> /dev/null
+ # stdout --> attached to pty
+@@ -91,6 +95,7 @@ attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- hostname 2> /dev/null
+ if [ "$attach" != "busy" ]; then
+         FAIL "lxc-attach -n busy -- hostname 2> /dev/null < /dev/null"
+ fi
++rm -f "${ATTACH_LOG}"
+ 
+ # Use a synthetic reproducer in container to produce output on stderr. stdout on
+ # the host gets redirect to /dev/null. We should still be able to receive
+@@ -104,6 +109,7 @@ attach=$( ( lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- sh -c 'hostname >&
+ if [ "$attach" != "busy" ]; then
+         FAIL "lxc-attach -n busy -- sh -c 'hostname >&2' > /dev/null"
+ fi
++rm -f "${ATTACH_LOG}"
+ 
+ # Use a synthetic reproducer in container to produce output on stderr. stderr on
+ # the host gets redirect to /dev/null. We should not receive output on stderr on
+@@ -116,7 +122,7 @@ attach=$( ( lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- sh -c 'hostname >&
+ if [ -n "$attach" ]; then
+         FAIL "lxc-attach -n busy -- sh -c 'hostname >&2' 2> /dev/null"
+ fi
+-
++rm -f "${ATTACH_LOG}"
+ 
+ # stdin  --> attached to pty
+ # stdout --> /dev/null
+@@ -126,7 +132,7 @@ attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- sh -c 'rm 2>&1' > /de
+ if [ -n "$attach" ]; then
+         FAIL "lxc-attach -n busy -- sh -c 'rm 2>&1' > /dev/null"
+ fi
+-
++rm -f "${ATTACH_LOG}"
+ 
+ # - stdin  --> attached to pty
+ # - stdout --> attached to pty
+@@ -136,6 +142,7 @@ attach=$(lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- sh -c 'rm 2>&1' 2> /d
+ if [ -z "$attach" ]; then
+         FAIL "lxc-attach -n busy -- sh -c 'rm 2>&1' 2> /dev/null"
+ fi
++rm -f "${ATTACH_LOG}"
+ 
+ # stdin  --> $in
+ # stdout --> attached to pty
+@@ -144,6 +151,7 @@ attach=$(echo hostname | lxc-attach -n busy -l trace -o "${ATTACH_LOG}" -- || FA
+ if [ "$attach" != "busy" ]; then
+         FAIL "echo hostname | lxc-attach -n busy --"
+ fi
++rm -f "${ATTACH_LOG}"
+ 
+ # stdin  --> attached to pty
+ # stdout --> $out
+@@ -158,7 +166,7 @@ if [ "$outcontent" != "OUT" ] || [ "$errcontent" != "ERR" ]; then
+         FAIL "lxc-attach -n busy -- sh -c 'echo OUT; echo ERR >&2' > $out 2> $err"
+ fi
+ 
+-rm -f $out $err
++rm -f $out $err "${ATTACH_LOG}"
+ 
+ # stdin  --> $in
+ # stdout --> $out
+@@ -174,8 +182,57 @@ if [ "$outcontent" != "busy" ] || [ -z "$errcontent" ]; then
+         FAIL "echo 'hostname; rm' | lxc-attach -n busy > $out 2> $err"
+ fi
+ 
+-rm -f $out $err
++rm -f $out $err "${ATTACH_LOG}"
++
++#
++# This testcase covers cases like:
++# https://github.com/lxc/lxc/issues/4546
++# https://discuss.linuxcontainers.org/t/lxc-attach-long-output-stops-suddenly-possible-bug/22031
++# https://discuss.linuxcontainers.org/t/fixing-forgejo-runners-lxc-logging/25918
++#
++# Idea is simple, we simulate a heavy IO and write relatively large amount of data to overfill
++# pts device buffers, then ensure data integrity.
++#
++# We need to use "script" tool to allocate TTYs properly, otherwise we don't go into a
++# problematic LXC code-path we want to cover.
++#
++# Also, I had to introduce two synthetic sleeps: one before issuing commands to busybox shell inside
++# a container and another one after.
++#
++# First one is needed, because LXC looses some pieces of terminal device input during
++# lxc-attach command initialization because of tcsetattr(fd, TCSAFLUSH, &newtios) call
++# (see https://github.com/lxc/lxc/blob/5d9839bc1316fa185d8c29b90982684b32e3dfa7/src/lxc/terminal.c#L523)
++# I would replace TCSAFLUSH with TCSANOW to avoid TTY buffer flush (and I tested that it helps),
++# but taking into account that this code is here since 2010
++# (see https://github.com/lxc/lxc/commit/e0dc0de76ed1ad9e284a37bd01268227d4eae8c9)
++# I decided to keep it like it is for now (FIXME?).
++#
++# Second sleep is needed because of a bug in busybox, unfortunately, without this sleep,
++# busybox fails to react on the host pipe write-end closure (after full command submission)
++# and continues to poll infinitely. This sleep makes pipe closure even to be separated from
++# a heavy IO and avoids this bug.
++#
++
++# Check test dependencies
++command -v script >/dev/null 2>&1 || { echo "'script' command is missing" >&2; exit 1; }
++busybox dd --help >/dev/null 2>&1 || FAIL "missing busybox's dd applet"
++busybox hexdump --help >/dev/null 2>&1 || FAIL "missing busybox's hexdump applet"
++busybox tee --help >/dev/null 2>&1 || FAIL "missing busybox's tee applet"
++
++out=$(mktemp /tmp/out_XXXX)
++BS=1000000
++( sleep 3; echo "echo DATASTART ; dd if=/dev/urandom bs=$BS count=1 status=none | hexdump | tee /root/large-data.txt ; echo DATAEND" ; sleep 1 ) | \
++	script -q -e -c "lxc-attach -n busy -l trace -o \"${ATTACH_LOG}\"" | \
++	sed -n '/DATASTART/,/DATAEND/{/DATASTART/d;/DATAEND/d;s/[\r\n]*$//;p}' > $out
++
++[ $(stat -c%s $out) -gt $BS ] || FAIL "generated file size is too small"
++cmp -s /var/lib/lxc/busy/rootfs/root/large-data.txt $out || FAIL "data corruption detected"
++
++md5sum /var/lib/lxc/busy/rootfs/root/large-data.txt $out
++ls -lah /var/lib/lxc/busy/rootfs/root/large-data.txt
++rm -f /var/lib/lxc/busy/rootfs/root/large-data.txt $out "${ATTACH_LOG}"
+ 
++# Cleanup stage
+ lxc-destroy -n busy -f
+ rm -f "${ATTACH_LOG}" || true
+ 
diff -Nru lxc-6.0.4/debian/patches/series lxc-6.0.4/debian/patches/series
--- lxc-6.0.4/debian/patches/series	2025-12-26 19:02:22.000000000 +0000
+++ lxc-6.0.4/debian/patches/series	2026-03-02 19:05:00.000000000 +0000
@@ -7,3 +7,4 @@
 0102-cherry-pick-apparmor-generation.patch
 0103-cherry-pick-fix-dbus-reboots.patch
 0104-Add-lxc-net-as-dependency-in-sysvinit-script.patch
+0105-cherry-pick-fix-heavy-io-pts.patch

Attachment: signature.asc
Description: This is a digitally signed message part


--- End Message ---
--- Begin Message ---
Package: release.debian.org
Version: 13.4

This update has been released as part of Debian 13.4.

--- End Message ---

Reply via email to