Skip to content

Commit 4f227cc

Browse files
committed
Merge branch 'master' into reject-duplicate-devices-in-request-message
2 parents 30b2e5f + 546cb6a commit 4f227cc

75 files changed

Lines changed: 3474 additions & 172 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci-test.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ jobs:
160160
matrix:
161161
build-config:
162162
- { system: "ubuntu-26.04-64", runs-on: '["ubuntu-latest"]', os: ubuntu, os-version: '26.04' }
163-
- { system: "ubuntu-25.10-64", runs-on: '["ubuntu-latest"]', os: ubuntu, os-version: '25.10' }
164163
- { system: "ubuntu-25.04-64", runs-on: '["ubuntu-latest"]', os: ubuntu, os-version: '25.04' }
165164
- { system: "ubuntu-24.04-64", runs-on: '["ubuntu-latest"]', os: ubuntu, os-version: '24.04' }
166165
- { system: "ubuntu-22.04-64", runs-on: '["ubuntu-latest"]', os: ubuntu, os-version: '22.04' }

.github/workflows/data-fundamental-systems.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
},
2727
{
2828
"runs-on": "['self-hosted', 'spread-enabled']",
29-
"group": "ubuntu-daily",
29+
"group": "ubuntu-resolute",
3030
"backend": "openstack",
3131
"systems": "ubuntu-26.04-64",
3232
"tasks": "tests/...",

.github/workflows/data-non-fundamental-systems.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,15 @@
116116
"runs-on": "['self-hosted', 'spread-enabled']",
117117
"group": "ubuntu-deb",
118118
"backend": "openstack",
119-
"systems": "ubuntu-24.04-64",
119+
"systems": "ubuntu-24.04-64 ubuntu-26.04-64",
120120
"tasks": "tests/...",
121121
"rules": "main"
122122
},
123123
{
124124
"runs-on": "['self-hosted', 'spread-enabled']",
125-
"group": "ubuntu-interim",
125+
"group": "ubuntu-daily",
126126
"backend": "openstack",
127-
"systems": "ubuntu-25.10-64",
127+
"systems": "ubuntu-26.10-64",
128128
"tasks": "tests/...",
129129
"rules": "main"
130130
},
@@ -162,9 +162,9 @@
162162
},
163163
{
164164
"runs-on": "['ubuntu-latest']",
165-
"group": "questing (garden)",
165+
"group": "stonking (garden)",
166166
"backend": "garden",
167-
"systems": "ubuntu-25.10-64",
167+
"systems": "ubuntu-26.10-64",
168168
"tasks": "tests/main/microk8s-smoke tests/main/download-timeout tests/main/snap-network-errors tests/main/snapd-snap:lxd tests/main/apparmor-prompting-support tests/main/proxy",
169169
"rules": ""
170170
},

boot/assets.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,11 @@ type EncryptionSetup struct {
290290
checkResult *secboot.PreinstallCheckResult
291291
}
292292

293+
func (e *EncryptionSetup) PrimaryKey() []byte {
294+
osutil.MustBeTestBinary("cannot use EncryptionSetup.PrimaryKey outside of tests")
295+
return e.primaryKey
296+
}
297+
293298
// BootAssets identifies the trusted assets that may be accepted in
294299
// boot chains and the method to update the boot entry.
295300
type BootAssets interface {

cmd/configure.ac

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ AC_SYS_LARGEFILE
2323
AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h sys/mount.h unistd.h])
2424
AC_CHECK_HEADERS([sys/quota.h], [], [AC_MSG_ERROR(sys/quota.h unavailable)])
2525
AC_CHECK_HEADERS([xfs/xqm.h], [], [AC_MSG_ERROR(xfs/xqm.h unavailable)])
26+
# Check for linux/nsfs.h, used for namespace probing workarounds (optional)
27+
AC_CHECK_HEADERS([linux/nsfs.h])
2628

2729
# Checks for typedefs, structures, and compiler characteristics.
2830
AC_CHECK_HEADER_STDBOOL

cmd/snap-confine/ns-support-test.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,119 @@ static void test_nsfs_fs_id(void) {
132132
g_assert_cmpint(buf.f_type, ==, NSFS_MAGIC);
133133
}
134134

135+
// Check that sc_running_kernel_is_6_18() agrees with a straightforward
136+
// uname(2) reading done independently here, so that the two never drift
137+
// apart from each other on whatever kernel the test happens to run on.
138+
static void test_sc_running_kernel_is_6_18(void) {
139+
struct utsname uts;
140+
g_assert_cmpint(uname(&uts), ==, 0);
141+
int major = 0, minor = 0;
142+
g_assert_cmpint(sscanf(uts.release, "%d.%d", &major, &minor), ==, 2);
143+
bool expected = major == 6 && minor == 18;
144+
g_assert_cmpint(sc_running_kernel_is_6_18(), ==, expected);
145+
}
146+
147+
// Check that sc_ensure_mount_ns_id_ordered() enforces its precondition that
148+
// a helper process has already been forked for this group.
149+
static void test_sc_ensure_mount_ns_id_ordered_no_helper(void) {
150+
struct sc_mount_ns *group = sc_alloc_mount_ns();
151+
g_test_queue_free(group);
152+
153+
if (g_test_subprocess()) {
154+
sc_ensure_mount_ns_id_ordered(group);
155+
g_assert_not_reached();
156+
}
157+
g_test_trap_subprocess(NULL, 0, 0);
158+
g_test_trap_assert_failed();
159+
g_test_trap_assert_stderr("*precondition failed: we don't have a helper process*");
160+
}
161+
162+
// Check that sc_read_mnt_ns_id() dies on a genuine ioctl failure (as opposed
163+
// to ENOTTY/EINVAL, which mean "not supported" and are reported via a false
164+
// return instead, see the comment above the function).
165+
static void test_sc_read_mnt_ns_id_bad_fd(void) {
166+
if (g_test_subprocess()) {
167+
uint64_t ns_id = 0;
168+
// -1 is never a valid file descriptor, so the ioctl below fails with
169+
// EBADF, which sc_read_mnt_ns_id() must treat as a real error.
170+
sc_read_mnt_ns_id(-1, &ns_id);
171+
g_assert_not_reached();
172+
}
173+
g_test_trap_subprocess(NULL, 0, 0);
174+
g_test_trap_assert_failed();
175+
g_test_trap_assert_stderr("*cannot query mount namespace id*");
176+
}
177+
178+
// Check that sc_read_mnt_ns_id() can read our own, real mount namespace id.
179+
// This exercises the ioctl wrapper without needing any special privilege:
180+
// every process can read /proc/self/ns/mnt.
181+
static void test_sc_read_mnt_ns_id_self(void) {
182+
int fd = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
183+
g_assert_cmpint(fd, !=, -1);
184+
uint64_t ns_id = 0;
185+
bool supported = sc_read_mnt_ns_id(fd, &ns_id);
186+
close(fd);
187+
if (!supported) {
188+
// NS_GET_ID is unavailable on kernels older than the ones affected
189+
// by the ordering bug this whole file works around.
190+
g_test_skip("NS_GET_ID is not supported by this kernel");
191+
return;
192+
}
193+
g_assert_cmpuint(ns_id, !=, 0);
194+
}
195+
196+
// Check the common case end-to-end: a helper forked just before we unshare
197+
// a fresh mount namespace should, overwhelmingly, already be ordered before
198+
// it, and sc_ensure_mount_ns_id_ordered() should return without needing to
199+
// exercise its CPU-sweep fallback (which, if it did trigger, would still be
200+
// expected to terminate -- see the comment above the function). On kernels
201+
// outside the affected 6.18.y series this is a no-op by construction (see
202+
// sc_running_kernel_is_6_18()), so the test still passes there, it just
203+
// doesn't exercise anything beyond that early return.
204+
//
205+
// This needs real CAP_SYS_ADMIN in the same user namespace as the helper
206+
// process, like the real code always has by the time it gets here: using
207+
// unshare(CLONE_NEWUSER) to fake privilege, as some other tests in this
208+
// suite do to run unprivileged, does not work here specifically, because it
209+
// would leave the helper behind in a different (the real, original) user
210+
// namespace, and opening its /proc/<pid>/ns/mnt across that boundary fails
211+
// with EACCES regardless of what capabilities we hold in our new one.
212+
static void test_sc_ensure_mount_ns_id_ordered_common_case(void) {
213+
if (geteuid() != 0) {
214+
g_test_skip("this test only runs as root");
215+
return;
216+
}
217+
218+
struct sc_mount_ns *group = sc_alloc_mount_ns();
219+
g_test_queue_free(group);
220+
221+
pid_t pid = fork();
222+
g_assert_cmpint(pid, !=, -1);
223+
if (pid == 0) {
224+
// helper: stay in the namespace we were forked in and wait to be
225+
// killed by the parent.
226+
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
227+
pause();
228+
_exit(0);
229+
}
230+
group->child = pid;
231+
232+
g_assert_cmpint(unshare(CLONE_NEWNS), ==, 0);
233+
234+
sc_ensure_mount_ns_id_ordered(group);
235+
236+
kill(pid, SIGKILL);
237+
int status = 0;
238+
waitpid(pid, &status, 0);
239+
}
240+
135241
static void __attribute__((constructor)) init(void) {
136242
g_test_add_func("/ns/sc_alloc_mount_ns", test_sc_alloc_mount_ns);
137243
g_test_add_func("/ns/sc_open_mount_ns", test_sc_open_mount_ns);
138244
g_test_add_func("/ns/nsfs_fs_id", test_nsfs_fs_id);
245+
g_test_add_func("/ns/sc_running_kernel_is_6_18", test_sc_running_kernel_is_6_18);
246+
g_test_add_func("/ns/sc_ensure_mount_ns_id_ordered_no_helper", test_sc_ensure_mount_ns_id_ordered_no_helper);
247+
g_test_add_func("/ns/sc_read_mnt_ns_id_bad_fd", test_sc_read_mnt_ns_id_bad_fd);
248+
g_test_add_func("/ns/sc_read_mnt_ns_id_self", test_sc_read_mnt_ns_id_self);
249+
g_test_add_func("/ns/sc_ensure_mount_ns_id_ordered_common_case", test_sc_ensure_mount_ns_id_ordered_common_case);
139250
}

0 commit comments

Comments
 (0)