Bug 290556 - [cd9660] VOP_GETATTR() returns incorrect size for symbolic links
Summary: [cd9660] VOP_GETATTR() returns incorrect size for symbolic links
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 16.0-CURRENT
Hardware: Any Any
: --- Affects Many People
Assignee: Dag-Erling Smørgrav
URL: https://reviews.freebsd.org/D53598
Keywords:
Depends on:
Blocks:
 
Reported: 2025-10-27 06:00 UTC by Markus Stoff
Modified: 2025-11-14 14:46 UTC (History)
3 users (show)

See Also:
des: mfc-stable15+
des: mfc-stable14+
des: mfc-stable13+


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Markus Stoff 2025-10-27 06:00:47 UTC
PROBLEM

When creating a tarball from files on _some_ cd9660 filesystems (e.g. created by xorrisofs(1)), all symbolic links will be stripped of their link target:

Expected:

    lrwxr-xr-x  0 root   wheel       0 27 Okt. 05:41 ./symlink-1 -> /some/fqfn
    lrwxr-xr-x  0 root   wheel       0 27 Okt. 05:41 ./symlink-2 -> ../relpath
    lrwxr-xr-x  0 root   wheel       0 27 Okt. 05:41 ./symlink-3 -> symlink-1

Found:

    lrwxr-xr-x  0 root   wheel       0 27 Okt. 05:41 ./symlink-1 ->  
    lrwxr-xr-x  0 root   wheel       0 27 Okt. 05:41 ./symlink-2 ->  
    lrwxr-xr-x  0 root   wheel       0 27 Okt. 05:41 ./symlink-3 ->  


ANALYSIS

Even if tar(1) drops the symlink target when reading from a cd9660 filesystem, it does extract them correctly from the device node or ISO image themselves.

Note that this error does not occur when the ISO has been created with makefs(8):

    makefs -t cd9660 -o rockridge -o label=TARPIT /tmp/tarpit.iso /tmp/tarpit

It does, however, occur when the image is created by xorrisofs(1):

    xorrisofs -rock -volid TARPIT -o /tmp/tarpit.iso /tmp/tarpit


HOW TO REPRODUCE

    # We need xorrisofs(1)
    pkg install -y xorriso

    # Create ISO image with symlinks
    mkdir /tmp/tarpit
    ln -s /some/fqfn /tmp/tarpit/symlink-1
    ln -s ../relpath /tmp/tarpit/symlink-2
    ln -s symlink-1 /tmp/tarpit/symlink-3
    xorrisofs -rock -volid TARPIT -o /tmp/tarpit.iso /tmp/tarpit

    # Mount ISO image
    dev=$(mdconfig /tmp/tarpit.iso)
    mount -t cd9660 /dev/iso9660/TARPIT

    # Validate filesystem contents
    ls -l /mnt
    # total 0
    # lrwxr-xr-x  1 root wheel 0 27 Okt. 05:41 symlink-1 -> /some/fqfn
    # lrwxr-xr-x  1 root wheel 0 27 Okt. 05:41 symlink-2 -> ../relpath
    # lrwxr-xr-x  1 root wheel 0 27 Okt. 05:41 symlink-3 -> symlink-1

    # Produces broken symlinks with the target component stripped away
    tar cf - -C /mnt . | tar tvf -
    # drwxr-xr-x  0 root   wheel       0 27 Okt. 05:41 ./
    # lrwxr-xr-x  0 root   wheel       0 27 Okt. 05:41 ./symlink-1 -> 
    # lrwxr-xr-x  0 root   wheel       0 27 Okt. 05:41 ./symlink-2 -> 
    # lrwxr-xr-x  0 root   wheel       0 27 Okt. 05:41 ./symlink-3 -> 

    # Produces intact symlinks (directly from ISO device or image)
    tar tvf /dev/iso9660/TARPIT
    tar tvf /tmp/tarpit.iso
    # drwxr-xr-x  2 0      0        2048 27 Okt. 05:41 .
    # lrwxr-xr-x  1 0      0           0 27 Okt. 05:41 symlink-1 -> /some/fqfn
    # lrwxr-xr-x  1 0      0           0 27 Okt. 05:41 symlink-2 -> ../relpath
    # lrwxr-xr-x  1 0      0           0 27 Okt. 05:41 symlink-3 -> symlink-1

    # Cleanup
    umount /mnt
    mdconfig -d -u "${dev#md}"
Comment 1 Michael Osipov freebsd_committer freebsd_triage 2025-10-27 12:56:17 UTC
Have you tested upstream: https://github.com/libarchive/libarchive/releases/tag/v3.8.2?
Comment 2 Markus Stoff 2025-10-29 07:04:05 UTC
(In reply to Michael Osipov from comment #1)

I have now - it has the exact same behavior.
Comment 3 Michael Osipov freebsd_committer freebsd_triage 2025-10-29 08:58:20 UTC
(In reply to Markus Stoff from comment #2)

Then I would recommend to report it upstream first.
Comment 4 Dag-Erling Smørgrav freebsd_committer freebsd_triage 2025-10-31 16:27:21 UTC
Can you please attach the ISO?
Comment 5 Dag-Erling Smørgrav freebsd_committer freebsd_triage 2025-11-05 18:28:20 UTC
This is a FreeBSD kernel bug, not a libarchive bug:

$ stat -f%z,%Y /tmp/tarpit/symlink-1 /mnt/symlink-1
10,/some/fqfn
0,/some/fqfn

POSIX states that fstatat() / lstat() on a symbolic link shall set st_size to the length of the target of the symbolic link, including the terminating null character.  There is code in cd9660_getattr() in sys/fs/cd9660/cd9660_vnops.c to handle that, but it clearly does not work.  Most programs (stat, readlink, ls...) don't notice because they use a fixed-size buffer for readlink(), but libarchive trusts the result of fstatat() and ends up allocating a zero-length buffer, and therefore getting a zero-length answer.
Comment 6 commit-hook freebsd_committer freebsd_triage 2025-11-10 13:59:09 UTC
A commit in branch main references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=978aaa72f3196f5489630052762cac5a7863e774

commit 978aaa72f3196f5489630052762cac5a7863e774
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2025-11-10 13:58:11 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2025-11-10 13:58:20 +0000

    cd9660: Unbreak symbolic links

    Since the introduction of permission masks, cd9660_getattr() returns a
    size of zero for all symbolic links, because the code to retrieve the
    length of the link target (as required by POSIX) is dead, since we strip
    away the type bits before we try to use them to identify the file as a
    link.  Address this by checking the vnode type instead.

    PR:             290556
    MFC after:      3 days
    Fixes:          82f2275b73e5 ("cd9660: Add support for mask,dirmask,uid,gid options")
    Reviewed by:    olce
    Differential Revision:  https://reviews.freebsd.org/D53598

 sys/fs/cd9660/cd9660_vnops.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Comment 7 commit-hook freebsd_committer freebsd_triage 2025-11-14 14:44:08 UTC
A commit in branch stable/15 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=1b51ad67cd0a85aea8351f86c6a724037eadc1fd

commit 1b51ad67cd0a85aea8351f86c6a724037eadc1fd
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2025-11-10 13:58:11 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2025-11-14 14:43:26 +0000

    cd9660: Unbreak symbolic links

    Since the introduction of permission masks, cd9660_getattr() returns a
    size of zero for all symbolic links, because the code to retrieve the
    length of the link target (as required by POSIX) is dead, since we strip
    away the type bits before we try to use them to identify the file as a
    link.  Address this by checking the vnode type instead.

    PR:             290556
    MFC after:      3 days
    Fixes:          82f2275b73e5 ("cd9660: Add support for mask,dirmask,uid,gid options")
    Reviewed by:    olce
    Differential Revision:  https://reviews.freebsd.org/D53598

    (cherry picked from commit 978aaa72f3196f5489630052762cac5a7863e774)

 sys/fs/cd9660/cd9660_vnops.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Comment 8 commit-hook freebsd_committer freebsd_triage 2025-11-14 14:44:09 UTC
A commit in branch stable/14 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=0f910af019691bb829ebc8aef868e1d97c379462

commit 0f910af019691bb829ebc8aef868e1d97c379462
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2025-11-10 13:58:11 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2025-11-14 14:43:38 +0000

    cd9660: Unbreak symbolic links

    Since the introduction of permission masks, cd9660_getattr() returns a
    size of zero for all symbolic links, because the code to retrieve the
    length of the link target (as required by POSIX) is dead, since we strip
    away the type bits before we try to use them to identify the file as a
    link.  Address this by checking the vnode type instead.

    PR:             290556
    MFC after:      3 days
    Fixes:          82f2275b73e5 ("cd9660: Add support for mask,dirmask,uid,gid options")
    Reviewed by:    olce
    Differential Revision:  https://reviews.freebsd.org/D53598

    (cherry picked from commit 978aaa72f3196f5489630052762cac5a7863e774)

 sys/fs/cd9660/cd9660_vnops.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Comment 9 commit-hook freebsd_committer freebsd_triage 2025-11-14 14:45:10 UTC
A commit in branch stable/13 references this bug:

URL: https://cgit.FreeBSD.org/src/commit/?id=3e8d5f36082414373462743d775db005daf07339

commit 3e8d5f36082414373462743d775db005daf07339
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2025-11-10 13:58:11 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2025-11-14 14:43:53 +0000

    cd9660: Unbreak symbolic links

    Since the introduction of permission masks, cd9660_getattr() returns a
    size of zero for all symbolic links, because the code to retrieve the
    length of the link target (as required by POSIX) is dead, since we strip
    away the type bits before we try to use them to identify the file as a
    link.  Address this by checking the vnode type instead.

    PR:             290556
    MFC after:      3 days
    Fixes:          82f2275b73e5 ("cd9660: Add support for mask,dirmask,uid,gid options")
    Reviewed by:    olce
    Differential Revision:  https://reviews.freebsd.org/D53598

    (cherry picked from commit 978aaa72f3196f5489630052762cac5a7863e774)

 sys/fs/cd9660/cd9660_vnops.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)