sysupdate: apply user xattrs listed in UAPI.16 manifests to installed instances

UAPI.16 file objects may carry an "extendedAttributes" field. When
installing a file or directory from a source with a UAPI.16 manifest,
let's apply the extended attributes in the "user" namespace listed there
to the inode we create, so that they are retained on the target.

This is done on a best-effort basis: if the file system does not support
extended attributes, or setting them fails for other reasons, this is
logged but not fatal, the instance is fully usable without them.
This commit is contained in:
Lennart Poettering committed 2026-11-05 10:36:42 +01:00
1 parent e9385e2508
commit 33acdda954
6 files changed
+74

No files matched your search

+6
View File
@@ -758,6 +758,12 @@
resources, as well as inline data that is encoded, must consist of the file and nothing else, other
such sources are ignored.</para>
<para>The extended attributes in the <literal>user</literal> namespace listed in the
<literal>extendedAttributes</literal> field of a file object of a UAPI.16 manifest are applied to the
file or directory created when installing it. This is done on a best-effort basis: if the file system
does not support extended attributes, or they cannot be set for other reasons, the instance is
installed without them.</para>
<xi:include href="version-info.xml" xpointer="v263"/></listitem>
</varlistentry>
+1
View File
@@ -97,6 +97,7 @@ typedef struct Tpm2Handle Tpm2Handle;
typedef struct Tpm2PCRValue Tpm2PCRValue;
typedef struct Uapi16Contents Uapi16Contents;
typedef struct Uapi16Object Uapi16Object;
typedef struct Uapi16Xattr Uapi16Xattr;
typedef struct UnitInfo UnitInfo;
typedef struct UnitResult UnitResult;
typedef struct UserRecord UserRecord;
+2
View File
@@ -63,5 +63,7 @@ Instance *instance_free(Instance *i) {
uapi16_contents_done(s);
free(i->sources);
uapi16_xattr_array_free(i->user_xattrs, i->n_user_xattrs);
return mfree(i);
}
+5
View File
@@ -53,6 +53,11 @@ struct Instance {
Uapi16Contents *sources;
size_t n_sources;
/* The "user" extended attributes listed in the manifest (for web backed sources), which we apply
* to the inode we create when installing the instance */
Uapi16Xattr *user_xattrs;
size_t n_user_xattrs;
/* The current state of this instance */
bool is_partial;
bool is_pending;
+5
View File
@@ -899,6 +899,11 @@ static int uapi16_process_object(Uapi16Object *object, size_t index, void *userd
instance->n_sources = object->n_contents;
object->n_contents = 0;
/* Similar, for the extended attributes to apply when installing */
instance->user_xattrs = TAKE_PTR(object->user_xattrs);
instance->n_user_xattrs = object->n_user_xattrs;
object->n_user_xattrs = 0;
return 0;
}
+55
View File
@@ -51,6 +51,7 @@
#include "sysupdate-transfer.h"
#include "time-util.h"
#include "web-util.h"
#include "xattr-util.h"
/* Default value for InstancesMax= for fs object targets */
#define DEFAULT_FILE_INSTANCES_MAX 3
@@ -1835,6 +1836,54 @@ static int transfer_acquire_source(
t, i, cb, userdata);
}
static int instance_apply_user_xattrs(Instance *i, const char *path) {
int r;
assert(i);
assert(path);
/* Applies the user extended attributes listed in the manifest to the installed inode, so that they
* are retained on the target. Failing to do so is not fatal, the instance is fully usable without
* them. Returns > 0 if any attribute was applied. */
if (i->n_user_xattrs == 0)
return 0;
_cleanup_close_ int fd = xopenat(AT_FDCWD, path, O_PATH|O_NOFOLLOW);
if (fd < 0) {
log_warning_errno(fd, "Failed to open '%s' to apply extended attributes, ignoring: %m", path);
return 0;
}
bool applied = false;
FOREACH_ARRAY(x, i->user_xattrs, i->n_user_xattrs) {
_cleanup_free_ char *n = strjoin("user.", x->name);
if (!n)
return log_oom();
r = xsetxattr_full(
fd,
/* path= */ NULL,
AT_EMPTY_PATH,
n,
x->value.iov_base,
x->value.iov_len,
/* xattr_flags= */ 0);
if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) {
log_notice_errno(r, "File system backing '%s' does not support extended attributes, not applying them: %m", path);
break;
}
if (r < 0) {
log_warning_errno(r, "Failed to set extended attribute '%s' on '%s', ignoring: %m", n, path);
continue;
}
applied = true;
}
return applied;
}
int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, TransferProgress cb, void *userdata) {
char offset[DECIMAL_STR_MAX(uint64_t)+1], max_size[DECIMAL_STR_MAX(uint64_t)+1];
const char *where = NULL;
@@ -2074,6 +2123,12 @@ int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, Tra
need_sync = true;
}
r = instance_apply_user_xattrs(i, t->temporary_partial_path);
if (r < 0)
return r;
if (r > 0)
need_sync = true;
/* Synchronize */
if (t->context->sync && need_sync) {
if (t->target.type == RESOURCE_REGULAR_FILE)