[meta-virtualization][PATCH] image-oci: don't preserve ownership in directories/files/host layer copies

[email protected] Sat, 2 May 2026 14:01:40 -0700
Newsgroups org.yoctoproject.lists.meta-virtualization
Message-ID <[email protected]>
From: Tim Orling <[email protected]>

The multi-layer 'directories', 'files', and 'host' branches in IMAGE_CMD:oci
copy delta content into the OCI bundle rootfs with 'cp -a'. 'cp -a' implies
'--preserve=all', which calls lchown() on the destination to copy ownership
from the source. When a directories/files layer copies a symbolic link whose
target does not exist at build time (for example, the '/dev/stdout' and
'/dev/stderr' log forwarding symlinks used by the official nginx Docker
image), lchown() can return EINVAL under pseudo and 'cp' aborts with:

    cp: failed to preserve ownership for .../var/log/nginx/access.log: Invalid argument

failing the whole do_image_oci task.

The single-layer rootfs copy already handles this correctly:

    cp -r -a --no-preserve=ownership ${IMAGE_ROOTFS}/* $image_bundle_name/rootfs

and the multi-layer 'packages' branch uses 'rsync -a --no-owner --no-group'
for the same reason. Bring the three remaining cp -a sites in line by adding
'--no-preserve=ownership'. Ownership inside an OCI image is set by umoci
based on the image config and source ownership has no meaning for symlinks
to runtime device nodes anyway, so dropping preservation is the correct
behaviour.

Reproduce: declare a directories: layer that copies a path containing a
symlink to '/dev/stdout' or '/dev/stderr' (e.g. a postprocess that creates
/var/log/nginx/{access,error}.log -> /dev/{stdout,stderr} to mirror the
upstream nginx Docker image).

Signed-off-by: Tim Orling <[email protected]>
---
 classes/image-oci-umoci.inc | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/classes/image-oci-umoci.inc b/classes/image-oci-umoci.inc
index bad6c5d0..a033d73a 100644
--- a/classes/image-oci-umoci.inc
+++ b/classes/image-oci-umoci.inc
@@ -611,7 +611,7 @@ IMAGE_CMD:oci() {
                             oci_dst_file="$image_bundle_name/rootfs$oci_rel_path"
                             if [ ! -e "$oci_dst_file" ]; then
                                 mkdir -p "$(dirname "$oci_dst_file")"
-                                cp -a "$oci_src_file" "$oci_dst_file"
+                                cp -a --no-preserve=ownership "$oci_src_file" "$oci_dst_file"
                                 oci_delta_copied=$(expr $oci_delta_copied + 1)
                             else
                                 oci_delta_skipped=$(expr $oci_delta_skipped + 1)
@@ -638,7 +638,7 @@ IMAGE_CMD:oci() {
                         oci_dst_file="$image_bundle_name/rootfs$oci_file"
                         if [ ! -e "$oci_dst_file" ]; then
                             mkdir -p "$(dirname "$oci_dst_file")"
-                            cp -a "${IMAGE_ROOTFS}$oci_file" "$oci_dst_file"
+                            cp -a --no-preserve=ownership "${IMAGE_ROOTFS}$oci_file" "$oci_dst_file"
                             bbnote "OCI: Added file $oci_file"
                         else
                             bbnote "OCI: Skipped file $oci_file (already in bundle)"
@@ -657,7 +657,7 @@ IMAGE_CMD:oci() {
                     oci_host_dst="${oci_host_pair##*:}"
                     if [ -e "$oci_host_src" ]; then
                         mkdir -p "$image_bundle_name/rootfs$(dirname $oci_host_dst)"
-                        cp -a "$oci_host_src" "$image_bundle_name/rootfs$oci_host_dst"
+                        cp -a --no-preserve=ownership "$oci_host_src" "$image_bundle_name/rootfs$oci_host_dst"
                         bbnote "OCI: Added from host: $oci_host_src -> $oci_host_dst"
                     else
                         bbfatal "OCI: Host path not found: $oci_host_src"
-- 
2.47.3