2005-03-09 23:58:52

by Nick Stoughton

[permalink] [raw]
Subject: link(2) and symlinks

On Linux, the link() system call does not dereference symbolic links: if
oldpath is a symbolic link, then newpath is created as a new hard link
to the same symbolic link file. (In other words, newpath is also a
symbolic link to the same file that oldpath refers to.) E.g. (using
shell commands to demonstrate):
$ > a
$ ln -s a b
$ ln b c
ln: `b': warning: making a hard link to a symbolic link is not portable
$ ls -li [abc]
230342 -rw-rw-r-- 1 nick nick 0 Mar 9 15:00 a
230504 lrwxrwxrwx 2 nick nick 1 Mar 9 15:01 b -> a
230504 lrwxrwxrwx 2 nick nick 1 Mar 9 15:01 c -> a


This behavior does not conform to POSIX, which says that all functions
that perform pathname resolution should dereference symbolic links
unless otherwise specified (and there is no exception specified for
link()). (POSIX says that resolution of the final component of a
pathname shall be considered complete if "the function is required to
act on the symbolic link itself, or certain arguments direct that the
function act on the symbolic link itself." In other words (in my
reading), unless the function specification says explicitly that the
function should act on a symbolic link, then the function should
dereference symbolic links. The specification of link() makes no
statement that it should act on symbolic links rather than the pathnames
to which they refer.)

Most Unix implementations behave in the manner specified by POSIX. One
notable exception is Solaris 8 (I don't know about later Solarises).
That implementation shows the same behavior as Linux by default, but the
SUSv3-conformant behavior is obtainable using c89 on that
implementation.

The Linux behavior is clearly deliberate:
(from fs/namei.c)
/*
* Hardlinks are often used in delicate situations. We avoid
* security-related surprises by not following symlinks on the
* newname. --KAB
*
* We don't follow them on the oldname either to be compatible
* with linux 2.0, and to avoid hard-linking to directories
* and other special files. --ADM
*/
asmlinkage long sys_link(const char __user * oldname, const char __user
* newname)
{
...

Would a patch to provide POSIX conforming behavior under some
conditional case (e.g. if /proc/sys/posix has value 1) ever be accepted?

I'm not a list subscriber, so please cc me in any discussion, thanks!
--
Nick Stoughton USENIX/FSG Standards Liaison
[email protected] (510) 388 1413


2005-03-10 02:00:12

by Andries Brouwer

[permalink] [raw]
Subject: Re: link(2) and symlinks

On Wed, Mar 09, 2005 at 03:14:36PM -0800, Nick Stoughton wrote:
> On Linux, the link() system call does not dereference symbolic links
>
> This behavior does not conform to POSIX
>
> Most Unix implementations behave in the manner specified by POSIX. One
> notable exception is Solaris 8 (I don't know about later Solarises).
>
> Would a patch to provide POSIX conforming behavior under some
> conditional case (e.g. if /proc/sys/posix has value 1) ever be accepted?

It sounds like a bad idea to have name resolution semantics dependent
upon some external variable. The result would be that nobody could be
sure anymore what the link() system call will do.

(Also, POSIX does not describe the kernel interface - it describes
a C interface. It would be possible for a libc to arrange that a
different link() routine was used.
Use of personality(2) does not sound like a good idea.)

((Maybe it would be beter to change POSIX here. Submit a defect report
and make the result of hard-linking to a symlink unspecified.
Since Linux and Solaris are non-POSIX here, programmers of portable
programs cannot rely on POSIX anyway. Moreover, the Linux/Solaris behaviour
sounds entirely reasonable, preferable in fact above the POSIX behaviour.))

Andries

2005-03-10 17:56:11

by Gunnar Ritter

[permalink] [raw]
Subject: Re: link(2) and symlinks

Andries Brouwer <[email protected]> wrote:

> On Wed, Mar 09, 2005 at 03:14:36PM -0800, Nick Stoughton wrote:
> > Most Unix implementations behave in the manner specified by POSIX. One
> > notable exception is Solaris 8 (I don't know about later Solarises).

It's still the same on Solaris 10. /usr/bin/ln behaves like Linux, and
/usr/xpg4/bin/ln behaves like POSIX.

> > Would a patch to provide POSIX conforming behavior under some
> > conditional case (e.g. if /proc/sys/posix has value 1) ever be accepted?
> It sounds like a bad idea to have name resolution semantics dependent
> upon some external variable. The result would be that nobody could be
> sure anymore what the link() system call will do.

I second that.

> (Also, POSIX does not describe the kernel interface - it describes
> a C interface. It would be possible for a libc to arrange that a
> different link() routine was used.
> Use of personality(2) does not sound like a good idea.)

The Solaris implementation of the POSIX behavior is done mostly
in userspace, as running truss with /usr/xpg4/bin/ln shows. The
actual link system call seems to be always the same one, with a
Linux-like behavior. /usr/xpg4/bin/ln only invokes resolvepath()
(a realpath()-like system call) first.

> ((Maybe it would be beter to change POSIX here. Submit a defect report
> and make the result of hard-linking to a symlink unspecified.
> Since Linux and Solaris are non-POSIX here, programmers of portable
> programs cannot rely on POSIX anyway.

In the standards sense of portability, they can; the formally conforming
Solaris environment behaves as POSIX specifies, and Linux has never been
formally conforming to POSIX.1-2001 anyway.

> Moreover, the Linux/Solaris behaviour sounds entirely reasonable,
> preferable in fact above the POSIX behaviour.))

I personally agree, but I doubt our opinion matters much.

Gunnar