Hello, In Gnulib 8f5547126aedc70a9c2cdb7c63829c87c3d71df1, qcopy_acl's USE_XATTR branch tests source_desc <= 0 || dest_desc <= 0 when choosing between attr_copy_file and attr_copy_fd. A descriptor of zero is valid, so this can use pathnames instead of the already-open objects, contrary to the function's documented descriptor semantics.
The proposal below changes only that validity test. Negative descriptors retain the existing pathname fallback. It does not address mixed pathname/descriptor calls or the POSIX default-ACL helpers. Reproduction outline (all fixtures owned by the same ordinary UID): 1. On an ACL-capable Linux filesystem, create source, destination and decoy files with distinct nontrivial access ACLs, and open them. 2. Rename the source, retaining its open descriptor, and replace the original source name with a symlink to the decoy. Use dup2 to put the source descriptor at zero, closing its former descriptor. 3. Call qcopy_acl with these source/destination names and valid descriptors, and the original source's st_mode. Compare the opened destination's ACL with the opened source's ACL; also check that the decoy ACL is unchanged. 4. In a separate fresh fixture, instead replace the destination name and put its descriptor at zero. Repeat the same checks. 5. Repeat both cases with positive descriptors as controls; also test stable pathname-only calls with both descriptors set to -1. With real Gnulib objects, USE_ACL=1 and USE_XATTR=1: - Source descriptor zero: before the patch, qcopy_acl returned 0 but the destination ACL did not match the opened source. Afterward it returned 0 and the ACL checks passed. - Destination descriptor zero: before the patch, qcopy_acl returned -1 and the checks failed. Afterward it returned 0 and the checks passed. This case is not evidence of arbitrary-target modification. - Positive-descriptor replacement controls, stable pathname-only control and an ordinary directory default-ACL control passed both before and after. - The six existing copy-acl/set-mode-acl test scripts passed before and after: 6 PASS, 0 FAIL, 0 SKIP each time. A restored-baseline repeat and a fresh build reproduced the same results. Environment: Linux ext4, UID 1000, libacl 2.3.2-2+b1, libattr 2.5.2-3. The linux/amd64 binaries ran through user-mode emulation on an ARM64 host. No syscall mocks, link wrappers or LD_PRELOAD were used. The private test container had no network, capabilities or business data. This is a deterministic API/object-identity test, not a probabilistic race or a cross-user privilege-escalation demonstration. I am not claiming a new CVE or a demonstrated exploit through any downstream CLI. Four separate default-ACL/mixed-descriptor diagnostics still fail and are being raised separately as an RFC; the overall downstream release gate remains on HOLD. I checked the current Savannah HEAD (unchanged at the revision above), recent relevant source history and public mailing-list/search results. I did not find an equivalent fd=0 fix in that bounded search; private reports and unindexed mail may exist. The related 2025 NFSv4 fix retains this validity test: https://lists.gnu.org/archive/html/bug-gnulib/2025-05/msg00123.html AI assistance was used to prepare this one-line proposal. No generated test harness or larger implementation is being submitted. Please advise if additional contribution paperwork is required. Thanks, Eric Cai * lib/qcopy-acl.c (qcopy_acl): Treat descriptor zero as valid when choosing descriptor-based attribute copying. --- lib/qcopy-acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/qcopy-acl.c b/lib/qcopy-acl.c --- a/lib/qcopy-acl.c +++ b/lib/qcopy-acl.c @@ -89,7 +89,7 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name, to copy */ if (ret == 0) { - ret = source_desc <= 0 || dest_desc <= 0 + ret = source_desc < 0 || dest_desc < 0 ? attr_copy_file (src_name, dst_name, is_attr_permissions, NULL) : attr_copy_fd (src_name, source_desc, dst_name, dest_desc, is_attr_permissions, NULL);
