What do you think? Is there a gaping hole in the logic that cannot
be repaired?
Kaz Kylheku <[email protected]> writes:
What do you think? Is there a gaping hole in the logic that cannot
be repaired?
I think the discussion needs a clear statement of threat model. A file
server (for instance, Samba) which has to expose a portion of the
filesystem namespace controlled by untrusted users is a different story
to a desktop application that only ever touches the current user’s
files.
A web server may run as a special web server user, _different_ from the owner(s) of the files and directories it serves. Your library will see
all those files and directories as untrusted:
root@araminta:/home/richard/junk/safepath# id
uid=0(root) gid=0(root) groups=0(root)
root@araminta:/home/richard/junk/safepath# ls -l testsp
-rwxrwxr-x 1 richard richard 68536 Jul 25 11:24 testsp
root@araminta:/home/richard/junk/safepath# ./testsp testsp
safepath_check("testsp") == path contains untrusted component
The web server might run as the same user as the owner of the files and directories it serves.
... but they will still be reported as safe if they are symlinks to
something secret:
richard@araminta:~/junk/safepath$ ls -l foo
lrwxrwxrwx 1 richard richard 29 Jul 25 11:33 foo -> /home/richard/.ssh/id_ed25519
richard@araminta:~/junk/safepath$ ./testsp foo
safepath_check("foo") == path appears safe
Another use case for path verification is unpacking an untrusted archive (e.g. tar or zip). All the files will be owned by the calling user so
your library will report them as trusted. But a symlink in the archive
could point at an important file and allow it to be overwritten.
(From memory) at least one device’s signed firmware updates were compromised by this - the update image and signature were contained in a
tar which was unpacked without any checks on symlinks, allowing
arbitrary files to be modified with an attacker-constructed tar
containing a symlink to a target file and then new contents for the
target file under the same name as the symlink. For example the target
file could be the public signing key trusted by the next phase of the firmware update:
richard@araminta:~/junk/safepath$ ls -l foo signing_key
lrwxrwxrwx 1 richard richard 11 Jul 25 12:06 foo -> signing_key
-rw-rw-r-- 1 richard richard 7 Jul 25 12:06 signing_key
richard@araminta:~/junk/safepath$ ./testsp foo
safepath_check("foo") == path appears safe
So your library doesn’t seem suitable for this use case either.
TLDR your library makes assumptions about both the trust placed in files owned by the current user and about which files are actually of
interest, and these assumptions are violated in many use cases.
The idea is that we walk a path component by component and validate that
what we have seen so far is "safe". If the path we have seen so far is "safe", and we can validate that the next component is safe, then the
path plust that component is also "safe".
The function performs its own symlink resolution; it doesn't rely
on the kernel. If "alpha" is a path which we believe to be "safe"
and the next components is "alpha/beta/omega", and "beta"
is a symlink, then because "alpha" is safe, we can trust readlink("alpha/beta"). That is, we can trust the link itself,
not necessarily what it points to. We can substitute that
ourselves. Say beta resolves to "gamma/delta". We produce "alpha/gamma/delta/omega". "alpha" is still safe, and so we
examine "gamma", and keep going. If "gamma" is a directory
which is not writable to any other user other than root, then
we can mark it safe, and proceed to delta.
This is all just induction. We start with some base hypothesis like
that we can safely examine either the "/" or "." directory, and
check its permissions, and find it to be safe.
I posted this to HackerNews; the Samba guy found it and commenting
on it, saying it doesn't work.
https://news.ycombinator.com/item?id=32216924
What do you think? Is there a gaping hole in the logic that cannot
be repaired?
Kaz Kylheku <[email protected]> writes:
[...]
The idea is that we walk a path component by component and validate that
what we have seen so far is "safe". If the path we have seen so far is
"safe", and we can validate that the next component is safe, then the
path plust that component is also "safe".
The function performs its own symlink resolution; it doesn't rely
on the kernel. If "alpha" is a path which we believe to be "safe"
and the next components is "alpha/beta/omega", and "beta"
is a symlink, then because "alpha" is safe, we can trust
readlink("alpha/beta"). That is, we can trust the link itself,
not necessarily what it points to. We can substitute that
ourselves. Say beta resolves to "gamma/delta". We produce
"alpha/gamma/delta/omega". "alpha" is still safe, and so we
examine "gamma", and keep going. If "gamma" is a directory
which is not writable to any other user other than root, then
we can mark it safe, and proceed to delta.
This is all just induction. We start with some base hypothesis like
that we can safely examine either the "/" or "." directory, and
check its permissions, and find it to be safe.
[...]
I posted this to HackerNews; the Samba guy found it and commenting
on it, saying it doesn't work.
https://news.ycombinator.com/item?id=32216924
What do you think? Is there a gaping hole in the logic that cannot
be repaired?
Provided I understood you correctly (I didn't look at the code), you're
right and Allison is wrong. OTOH, code referring to a directory via file descriptor used in one of the *at calls would be immune to any
modificiation of higher-level path components (as would code using the
more traditional method of sitting on some directory by making it the
cwd of the process).
On 2022-07-25, Rainer Weikusat <[email protected]> wrote:
Kaz Kylheku <[email protected]> writes:
[...]
The idea is that we walk a path component by component and validate that >>> what we have seen so far is "safe". If the path we have seen so far is
"safe", and we can validate that the next component is safe, then the
path plust that component is also "safe".
I posted this to HackerNews; the Samba guy found it and commenting
on it, saying it doesn't work.
https://news.ycombinator.com/item?id=32216924
What do you think? Is there a gaping hole in the logic that cannot
be repaired?
Provided I understood you correctly (I didn't look at the code), you're
right and Allison is wrong. OTOH, code referring to a directory via file
descriptor used in one of the *at calls would be immune to any
modificiation of higher-level path components (as would code using the
more traditional method of sitting on some directory by making it the
cwd of the process).
But if modification of higher-level path components is possible at all
then you didn't safely arrive at that directory in the first place.
On 2022-07-25, Richard Kettlewell <[email protected]d> wrote:[..]
A web server may run as a special web server user, _different_ from the
owner(s) of the files and directories it serves. Your library will see
all those files and directories as untrusted:
In this case, my library makes the right call. You are "root" or
"www-data" or whoever, of course a directory controlled by "richard"
is not safe.
TLDR your library makes assumptions about both the trust placed in files
owned by the current user and about which files are actually of
interest, and these assumptions are violated in many use cases.
The model is "this user can access anything in the namespace according to the OS permission model; we would like to protect them from trusting paths controlled by other users."
Security concepts fabricated by applications in user space, like
- out of a set of files accessible to a user, only certain files should be of
interest to a certain operation run by that user; or
- multi-user security is being simulated by an application running
in a single account's security context
where file system manipulations outside of the application's control are possible are either not fixable at all, or not in this way --- and we have to acknowledge that the existence of symlinks is a major source of difficulty
to coding these situations correctly.
Kaz Kylheku <[email protected]> writes:
Security concepts fabricated by applications in user space, like
- out of a set of files accessible to a user, only certain files should be of
interest to a certain operation run by that user; or
- multi-user security is being simulated by an application running
in a single account's security context
where file system manipulations outside of the application's control are
possible are either not fixable at all, or not in this way --- and we have to
acknowledge that the existence of symlinks is a major source of difficulty >> to coding these situations correctly.
As I understand it that’s more-or-less JRA’s point: the way symlinks escape the heirarchial structure of a filesystem makes it (at best) unreasonably hard to implement these higher-level security policies.
Kaz Kylheku <[email protected]> writes:
On 2022-07-25, Richard Kettlewell <[email protected]d> wrote:[..]
A web server may run as a special web server user, _different_ from the
owner(s) of the files and directories it serves. Your library will see
all those files and directories as untrusted:
In this case, my library makes the right call. You are "root" or
"www-data" or whoever, of course a directory controlled by "richard"
is not safe.
It’s not the right call for this use case (which is a common one among
web servers). The web server would only return errors. It would be
completely useless.
TLDR your library makes assumptions about both the trust placed in files >>> owned by the current user and about which files are actually of
interest, and these assumptions are violated in many use cases.
The model is "this user can access anything in the namespace according to the
OS permission model; we would like to protect them from trusting paths
controlled by other users."
What’s the concrete use case which fits that model? It feels like you’re solving a different problem to the one that people actually have.
Security concepts fabricated by applications in user space, like
- out of a set of files accessible to a user, only certain files should be of
interest to a certain operation run by that user; or
- multi-user security is being simulated by an application running
in a single account's security context
where file system manipulations outside of the application's control are
possible are either not fixable at all, or not in this way --- and we have to
acknowledge that the existence of symlinks is a major source of difficulty >> to coding these situations correctly.
As I understand it that’s more-or-less JRA’s point: the way symlinks
escape the heirarchial structure of a filesystem makes it (at best) unreasonably hard to implement these higher-level security policies.
Richard Kettlewell <[email protected]d> wrote:
Kaz Kylheku <[email protected]> writes:
On 2022-07-25, Richard Kettlewell <[email protected]d> wrote:[..]
A web server may run as a special web server user, _different_ from the >>>> owner(s) of the files and directories it serves. Your library will see >>>> all those files and directories as untrusted:
In this case, my library makes the right call. You are "root" or
"www-data" or whoever, of course a directory controlled by "richard"
is not safe.
It’s not the right call for this use case (which is a common one among
web servers). The web server would only return errors. It would be
completely useless.
That's making the right call, "I am loudly useless for the internal
security model you've invented in your application; don't use me".
TLDR your library makes assumptions about both the trust placed in files >>>> owned by the current user and about which files are actually of
interest, and these assumptions are violated in many use cases.
The model is "this user can access anything in the namespace according to the
OS permission model; we would like to protect them from trusting paths
controlled by other users."
What’s the concrete use case which fits that model? It feels like you’re >> solving a different problem to the one that people actually have.
The use case is extremely common: an application, runnning on behalf of
some user, wants to read a trusted file, such as a configuration file,
or program.
You use trusted paths all the time. For instance you probably run /usr/bin/grep from time to time. You trust it due to a belief that
not only us the grep executable owned by root and not writable to
anyone else, but that root controls the three path components above:
/, /usr, and /usr/bin.
You can call safepath_check("/usr/bin/grep"), and the idea is that
if it returns 1, and everything in taht function is coded right, you can trust that the permissions are sane: the path is not controlled by
anyone other than either root, or you (your effective ID).
Basically those are the two ways of using a Unix-like system safely:
- the silo model with everyone just using their own directory, or
certain kinds of shared directories that are owned by root, or else
- a system that is inaccesible for multi-user remote login, which runs a
dedicated application or application suite (exemplified by dedicated
servers) or, in in more recent decades, embedded systems running
Unix-likes.
Symlinks are not broken if you stick to these usage patterns.
So, LWN publishes an article
https://lwn.net/Articles/899543/
Some Sampba person working at Google claims that there is no
safe way of using symlinks; they are fundamentally broken and
wreck the whole POSIX filesystem API, rendering it insecure.
In response, I wrote a library function whose interface
looks like this:
/*
* safepatch_check error codes
*/
enum {
SAFEPATH_OK, /* path appears safe */
SAFEPATH_UNSAFE, /* path traversible, unsafe */
SAFEPATH_PERM, /* path not traversible due to perms */
SAFEPATH_NOENT, /* component other than last doesn't exist */
SAFEPATH_NOTDIR, /* interior path component isn't a directory */
SAFEPATH_INVAL, /* path is invalid */
SAFEPATH_NOMEM, /* out of memory */
SAFEPATH_LOOP, /* more than 8 levels of symlink */
SAFEPATH_TOOLONG, /* component or symlink target too long */
};
int safepath_check(const char *name);
const char *safepath_strerr(int err);
The git repository is here:
https://www.kylheku.com/cgit/safepath/about/
(Unfortunately, I don't yet have documentation or test cases, sorry.)
The idea is that we walk a path component by component and validate that
what we have seen so far is "safe". If the path we have seen so far is "safe", and we can validate that the next component is safe, then the
path plust that component is also "safe".
The function performs its own symlink resolution; it doesn't rely
on the kernel. If "alpha" is a path which we believe to be "safe"
and the next components is "alpha/beta/omega", and "beta"
is a symlink, then because "alpha" is safe, we can trust readlink("alpha/beta"). That is, we can trust the link itself,
not necessarily what it points to. We can substitute that
ourselves. Say beta resolves to "gamma/delta". We produce "alpha/gamma/delta/omega". "alpha" is still safe, and so we
examine "gamma", and keep going. If "gamma" is a directory
which is not writable to any other user other than root, then
we can mark it safe, and proceed to delta.
This is all just induction. We start with some base hypothesis like
that we can safely examine either the "/" or "." directory, and
check its permissions, and find it to be safe.
The inductive hypothesis is that if we can find some path to
be safe, we can evaluate the next component and validate whether
that is safe according to some cases, and then add it to the path.
Or else proclaim that it's not safe.
By induction, if we reach the end of the path, we have shown that
it's safe.
We can use system calls which use the entire left part of the path,
because since that is safe, we can trust it to be free of tampering.
I posted this to HackerNews; the Samba guy found it and commenting
on it, saying it doesn't work.
https://news.ycombinator.com/item?id=32216924
What do you think? Is there a gaping hole in the logic that cannot
be repaired?
Kaz Kylheku <[email protected]> wrote:
What do you think? Is there a gaping hole in the logic that cannot
be repaired?
From a cursory inspection it all looks sound.
On 2022-07-28, William Ahern wrote:
Kaz Kylheku <[email protected]> wrote:
What do you think? Is there a gaping hole in the logic that cannot
be repaired?
From a cursory inspection it all looks sound.
It's an interesting question, but I don't agree at all (Sorry, I'm on
team jra!).
It does have to handle TOCTOU, because an attacker can force you to
handle it, whether you want to or not.
You said you would be delighted to see an example, so here is one
example of using TOCTOU to defeat the testsp program:
1. You can create a root owned symlink to any directory you want like
this:
$ cd /tmp/evil
$ su &
$ ls -l /proc/$!/cwd
lrwxrwxrwx 1 root root 0 Jul 28 17:52 /proc/12657/cwd -> /tmp/evil
Tavis Ormandy <[email protected]> wrote:
On 2022-07-28, William Ahern wrote:
Kaz Kylheku <[email protected]> wrote:
What do you think? Is there a gaping hole in the logic that cannot
be repaired?
From a cursory inspection it all looks sound.
It's an interesting question, but I don't agree at all (Sorry, I'm on
team jra!).
It does have to handle TOCTOU, because an attacker can force you to
handle it, whether you want to or not.
You said you would be delighted to see an example, so here is one
example of using TOCTOU to defeat the testsp program:
1. You can create a root owned symlink to any directory you want like
this:
$ cd /tmp/evil
$ su &
$ ls -l /proc/$!/cwd
lrwxrwxrwx 1 root root 0 Jul 28 17:52 /proc/12657/cwd -> /tmp/evil
procfs strikes again!
Also once again proving how easy it is conflate lack of imagination with proof of security.
On 2022-07-28, William Ahern wrote:
Kaz Kylheku <[email protected]> wrote:
What do you think? Is there a gaping hole in the logic that cannot
be repaired?
From a cursory inspection it all looks sound.
It's an interesting question, but I don't agree at all (Sorry, I'm on
team jra!).
It does have to handle TOCTOU, because an attacker can force you to
handle it, whether you want to or not.
You said you would be delighted to see an example, so here is one
example of using TOCTOU to defeat the testsp program:
1. You can create a root owned symlink to any directory you want like
this:
$ cd /tmp/evil
$ su &
$ ls -l /proc/$!/cwd
lrwxrwxrwx 1 root root 0 Jul 28 17:52 /proc/12657/cwd -> /tmp/evil
2. You can change where this symlink points to by killing su, and then
spamming fork() until the pid is recycled. This can take a while
depending on pid_max.
Here is an example implementation, only tested on Linux:
https://gist.github.com/taviso/d7c2a3cb1896584f176e16fae3d59c64
This is a classic TOCTOU, the victim checked the path while it was safe,
then the attacker changed it before it was used.
You can absolutely do this. Here is another trick, you can create
hardlinks to root-owned relative symlinks.
Here is an example, find any relative symlink. I guess you can do
something like this:
$ find /etc -type l -user root -ls | grep -v -- '-> /'
On my system I have a bunch in /etc/ssl/certs, but it doesn't matter
where:
$ ls -l /etc/ssl/certs/76cb8f92.0
lrwxrwxrwx 1 root root 26 May 23 15:19 /etc/ssl/certs/76cb8f92.0 -> Cybertrust_Global_Root.pem
I can create a hardlink to that symlink:
$ ln /etc/ssl/certs/76cb8f92.0 foobar
$ stat foobar
File: foobar -> Cybertrust_Global_Root.pem
Size: 26 Blocks: 0 IO Block: 4096 symbolic link Device: 810h/2064d Inode: 30442 Links: 2
Access: (0777/lrwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
2. You can change where this symlink points to by killing su, and then
spamming fork() until the pid is recycled. This can take a while
depending on pid_max.
Here is an example implementation, only tested on Linux:
https://gist.github.com/taviso/d7c2a3cb1896584f176e16fae3d59c64
Thank you; this is exactly the feedback I'm looking for.
I will incorporate a fix into safepath_check against this.
This is a classic TOCTOU, the victim checked the path while it was safe,
then the attacker changed it before it was used.
If we fool root into pointing a symlink anywhere, that's already a
problem even in the absence of a TOCtoTOU. The attacker doesn't have
to change anything between the safepath_check and the access.
Basically whenever the safepath_check function encounters an absolute
path, either initially or via a symlink, it needs to check that path
against some unsafe patterns, like /proc/<digits>/cwd.
On 2022-07-28, William Ahern wrote:
Kaz Kylheku <[email protected]> wrote:
What do you think? Is there a gaping hole in the logic that cannot
be repaired?
From a cursory inspection it all looks sound.
It's an interesting question, but I don't agree at all (Sorry, I'm on
team jra!).
It does have to handle TOCTOU, because an attacker can force you to
handle it, whether you want to or not.
But, on Linux, I'm not able to hard link a root-owned file
into /tmp. I tried this:
# touch /tmp/foo # as root
/tmp $ ln foo bar # as myself
ln: failed to create hard link 'foo' => 'bar': Operation not permitted
On 2022-07-29, Tavis Ormandy <[email protected]> wrote:
So in effect, Linux, and possibly other systems with a similar
/proc system, provide a privileged service that compliantly creates
a root-owned symlink pointing wherever any unprivileged user wants;
the user just has to change to that directory and fire up a setuid executable, which lives however briefly.
Basically whenever the safepath_check function encounters an absolute
path, either initially or via a symlink, it needs to check that path
against some unsafe patterns, like /proc/<digits>/cwd.
I'm fully aware that /proc could be mounted anywhere, but I think won't bother with that possibility.
On 2022-07-29, Kaz Kylheku wrote:
But, on Linux, I'm not able to hard link a root-owned file
into /tmp. I tried this:
# touch /tmp/foo # as root
/tmp $ ln foo bar # as myself
ln: failed to create hard link 'foo' => 'bar': Operation not permitted
It's configurable, it's the fs.protected_hardlinks sysctl. AFAIK it's
not the default, your distro probably sets it.
On 2022-07-29, Kaz Kylheku <[email protected]> wrote:
Basically whenever the safepath_check function encounters an absolute
path, either initially or via a symlink, it needs to check that path
against some unsafe patterns, like /proc/<digits>/cwd.
Of course, that's not sufficient because of the many ways that same
object can be named, like:
/proc/net/../<digits>/fdinfo/../././cwd
On 2022-07-29, Tavis Ormandy <[email protected]> wrote:
On 2022-07-29, Kaz Kylheku wrote:
But, on Linux, I'm not able to hard link a root-owned file
into /tmp. I tried this:
# touch /tmp/foo # as root
/tmp $ ln foo bar # as myself
ln: failed to create hard link 'foo' => 'bar': Operation not permitted >>>
It's configurable, it's the fs.protected_hardlinks sysctl. AFAIK it's
not the default, your distro probably sets it.
Indeed it is; and the purpose of that sysctl is preventing exactly this
/tmp muckery.
Making that configurable at all seems like a poor decision, not to
speak of the which way it defaults.
Kaz Kylheku <[email protected]> writes:
On 2022-07-29, Tavis Ormandy <[email protected]> wrote:
On 2022-07-29, Kaz Kylheku wrote:
But, on Linux, I'm not able to hard link a root-owned file
into /tmp. I tried this:
# touch /tmp/foo # as root
/tmp $ ln foo bar # as myself
ln: failed to create hard link 'foo' => 'bar': Operation not permitted >>>>
It's configurable, it's the fs.protected_hardlinks sysctl. AFAIK it's
not the default, your distro probably sets it.
Indeed it is; and the purpose of that sysctl is preventing exactly this
/tmp muckery.
Making that configurable at all seems like a poor decision, not to
speak of the which way it defaults.
Sudden changes of semantics which have existed for a long time are
usually imprudent. People often don't appreciate "Of course, it doesn't
work. But look how secure it is!"
On 2022-07-29, Kaz Kylheku <[email protected]> wrote:
Basically whenever the safepath_check function encounters an absolute
path, either initially or via a symlink, it needs to check that path
against some unsafe patterns, like /proc/<digits>/cwd.
Of course, that's not sufficient because of the many ways that same
object can be named, like:
/proc/net/../<digits>/fdinfo/../././cwd
On 2022-07-29, Kaz Kylheku <[email protected]> wrote:
On 2022-07-29, Kaz Kylheku <[email protected]> wrote:
Basically whenever the safepath_check function encounters an absolute
path, either initially or via a symlink, it needs to check that path
against some unsafe patterns, like /proc/<digits>/cwd.
Of course, that's not sufficient because of the many ways that same
object can be named, like:
/proc/net/../<digits>/fdinfo/../././cwd
OK; there is an updated version, git hash 2f27d6c386daff041017b7aaec51d0e50e603a8e.
On 2022-07-30, Kaz Kylheku wrote:
On 2022-07-29, Kaz Kylheku <[email protected]> wrote:
On 2022-07-29, Kaz Kylheku <[email protected]> wrote:
Basically whenever the safepath_check function encounters an absolute
path, either initially or via a symlink, it needs to check that path
against some unsafe patterns, like /proc/<digits>/cwd.
Of course, that's not sufficient because of the many ways that same
object can be named, like:
/proc/net/../<digits>/fdinfo/../././cwd
OK; there is an updated version, git hash
2f27d6c386daff041017b7aaec51d0e50e603a8e.
I think it's buggy, it doesn't handle "messy" symlinks correctly.
A symlink can be "messy" foo -> bar/, or "clean" foo -> bar.
I also think there is a security bug with multi-level symlinks.
If you do something like
$ ln -s /etc foo
$ ln -s foo bar
I think checking "bar/passwd" will actually test "barpasswd". I realize
this was just a bug and not a design flaw. I can take a look after you
fix it if you like it.
Do you consider attacks in s[ug]id context valid, or do you want
to call that out of scope? :)
I think checking "bar/passwd" will actually test "barpasswd". I realize
this was just a bug and not a design flaw. I can take a look after you
fix it if you like it.
I put out two fixes; one for the buggy splicing (missing "+ 1"
in one fo the cases, causing the slash to be deleted).
I also revised the treatment of consecutive slashes, and trailing
slashes in link targets.
Do you consider attacks in s[ug]id context valid, or do you want
to call that out of scope? :)
I care more about setuid root than setuid non-root, and setuid
than setgid. :)
safepath_check("/dev/fd/3") == path appears safe
probably "if we are in /proc, and see a symlink, don't trust
it if root, or else if the target contains (deleted)".
On 2022-07-30, Tavis Ormandy <[email protected]> wrote:
safepath_check("/dev/fd/3") == path appears safe
because /dev/fd is a symlink, this is the same as /proc/self/fd/3.
On 2022-07-30, Kaz Kylheku wrote:
On 2022-07-30, Tavis Ormandy <[email protected]> wrote:
safepath_check("/dev/fd/3") == path appears safe
because /dev/fd is a symlink, this is the same as /proc/self/fd/3.
Of course, but I don't understand the point - you're rejecting this attack?
It's okay, just want to make sure I understand the rules!
If you want to make things harder for me you could also disallow /tmp,
use close_range() and also require the other fs.protected_* sysctls! I
think this makes it not very useful, but that was Jeremy's point, using symlinks safely is either hard or very restrictive!
On 2022-07-29, Rainer Weikusat <[email protected]> wrote:
Kaz Kylheku <[email protected]> writes:
On 2022-07-29, Tavis Ormandy <[email protected]> wrote:
On 2022-07-29, Kaz Kylheku wrote:
But, on Linux, I'm not able to hard link a root-owned file
into /tmp. I tried this:
# touch /tmp/foo # as root
/tmp $ ln foo bar # as myself
ln: failed to create hard link 'foo' => 'bar': Operation not permitted >>>>>
It's configurable, it's the fs.protected_hardlinks sysctl. AFAIK it's
not the default, your distro probably sets it.
Indeed it is; and the purpose of that sysctl is preventing exactly this
/tmp muckery.
Making that configurable at all seems like a poor decision, not to
speak of the which way it defaults.
Sudden changes of semantics which have existed for a long time are
usually imprudent. People often don't appreciate "Of course, it doesn't
work. But look how secure it is!"
But distros have turned this on and people don't even know about it.
I can hardly think of a valid use case for linking a file into /tmp
that you do not own!
Hard linking /your own file/ is allowed.
/tmp$ touch foo
/tmp$ ln foo bar
What is the use case for linking a file /that you do not own/ into
/tmp?
That's very dubious given how /tmp works; in /tmp you're supposed to
access your own stuff and keep out of anyone else's.
You cannot remove (i.e. unlink) an object from /tmp you don't own; why
would the opposite operation, link, be allowed?
The case pretty solid for ending the cautious period of configurability
and making it a hard-coded behavior.
| Sysop: | Keyop |
|---|---|
| Location: | Huddersfield, West Yorkshire, UK |
| Users: | 715 |
| Nodes: | 16 (0 / 16) |
| Uptime: | 162:55:42 |
| Calls: | 12,095 |
| Calls today: | 3 |
| Files: | 15,000 |
| Messages: | 6,517,780 |