Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

symlink insecurity race

5 views
Skip to first unread message

John Kelly

unread,
Nov 25, 2009, 10:45:49 AM11/25/09
to

Suppose you need to create and/or overwrite your own file in a sticky
world writable diretory. If malicious user already created a symlink
with the same name, they can trick you into overwriting a different file
of your own.

I worked around the problem on Linux by using O_NOFOLLOW:

> flags = O_WRONLY | O_CREAT | O_NOFOLLOW | O_NONBLOCK;
> mode = S_IRUSR | S_IWUSR | S_IRGRP;
> if ((tn = open (lockfile, flags, mode)) != STDOUT_FILENO) {
> if (tn != -1) {
> errno = EPROTO;
> } else if (errno == ENXIO) {
> errno = EPERM;
> }
> fprintf (stderr, "failure opening STDOUT to %s: %s\n",
> lockfile, strerror (errno));
> exit (EXIT_FAILURE);
> }
> if ((flags = fcntl (STDOUT_FILENO, F_GETFL)) == -1) {
> fprintf (stderr, "failure getting flags for %s: %s\n",
> lockfile, strerror (errno));
> }
> if (fcntl (STDOUT_FILENO, F_SETFL, flags & ~O_NONBLOCK) == -1) {
> fprintf (stderr, "failure setting flags for %s: %s\n",
> lockfile, strerror (errno));
> }


To see the full working code, it's at:

http://www.beewyz.com/~jar/etcetera/computer/programming/project/dh/

My question is, how do you avoid symlink insecurity on platforms lacking
O_NOFOLLOW, while also avoiding all possible races? The race problem is
tricky, it seems to me.


--
Free Webmail
http://www.beewyz.com/freeaccounts.php

Casper H.S. Dik

unread,
Nov 25, 2009, 10:50:04 AM11/25/09
to
John Kelly <j...@isp2dial.com> writes:


>Suppose you need to create and/or overwrite your own file in a sticky
>world writable diretory. If malicious user already created a symlink
>with the same name, they can trick you into overwriting a different file
>of your own.

>My question is, how do you avoid symlink insecurity on platforms lacking
>O_NOFOLLOW, while also avoiding all possible races? The race problem is
>tricky, it seems to me.

I think it's easier than you think.


First you try to create the file using O_EXCL; if that works, you're done.

Else, you open the file without truncating it and you verify that
the file you just opened (fstat()) is the same as lstat())

Casper
--
Expressed in this posting are my opinions. They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.

John Kelly

unread,
Nov 25, 2009, 11:10:01 AM11/25/09
to
On 25 Nov 2009 15:50:04 GMT, Casper H.S. Dik <Caspe...@Sun.COM> wrote:

>>My question is, how do you avoid symlink insecurity on platforms lacking
>>O_NOFOLLOW, while also avoiding all possible races? The race problem is
>>tricky, it seems to me.
>
>I think it's easier than you think.
>
>
>First you try to create the file using O_EXCL; if that works, you're done.
>
>Else, you open the file without truncating it and you verify that
>the file you just opened (fstat()) is the same as lstat())

I considered that. But between the two actions, someone could delete
the file, and then you can't open the file you thought was there. I
suppose it's not a security concern, but it's an operational race you
have to code for, and report an error if it happens.

So I used O_NOFOLLOW to simplify the code.

But maybe your approach is the only way to have portable code.

Casper H.S. Dik

unread,
Nov 25, 2009, 11:17:34 AM11/25/09
to
John Kelly <j...@isp2dial.com> writes:

>On 25 Nov 2009 15:50:04 GMT, Casper H.S. Dik <Caspe...@Sun.COM> wrote:

>>>My question is, how do you avoid symlink insecurity on platforms lacking
>>>O_NOFOLLOW, while also avoiding all possible races? The race problem is
>>>tricky, it seems to me.
>>
>>I think it's easier than you think.
>>
>>
>>First you try to create the file using O_EXCL; if that works, you're done.
>>
>>Else, you open the file without truncating it and you verify that
>>the file you just opened (fstat()) is the same as lstat())

>I considered that. But between the two actions, someone could delete
>the file, and then you can't open the file you thought was there. I
>suppose it's not a security concern, but it's an operational race you
>have to code for, and report an error if it happens.


Just wrap it into a while loop :-)

John Kelly

unread,
Nov 25, 2009, 11:28:24 AM11/25/09
to
On 25 Nov 2009 16:17:34 GMT, Casper H.S. Dik <Caspe...@Sun.COM> wrote:

>John Kelly <j...@isp2dial.com> writes:
>
>>On 25 Nov 2009 15:50:04 GMT, Casper H.S. Dik <Caspe...@Sun.COM> wrote:
>
>>>>My question is, how do you avoid symlink insecurity on platforms lacking
>>>>O_NOFOLLOW, while also avoiding all possible races? The race problem is
>>>>tricky, it seems to me.
>>>
>>>I think it's easier than you think.
>>>
>>>
>>>First you try to create the file using O_EXCL; if that works, you're done.
>>>
>>>Else, you open the file without truncating it and you verify that
>>>the file you just opened (fstat()) is the same as lstat())
>
>>I considered that. But between the two actions, someone could delete
>>the file, and then you can't open the file you thought was there. I
>>suppose it's not a security concern, but it's an operational race you
>>have to code for, and report an error if it happens.
>
>
>Just wrap it into a while loop :-)

I don't know. What if the attacker could delete and recreate, in just
the right sequence, faster than your loop runs? Not likely, but to have
secure code, you need to consider even ridiculous possibilities.

I suppose you could try 7 times or so, and then bail out with an attack
warning message.

But man that's a lot of work. Maybe I'll just stick to Linux and forego
portability. :-)

William Ahern

unread,
Nov 25, 2009, 7:19:26 PM11/25/09
to
John Kelly <j...@isp2dial.com> wrote:
<snip>

> I suppose you could try 7 times or so, and then bail out with an attack
> warning message.
>
> But man that's a lot of work. Maybe I'll just stick to Linux and forego
> portability. :-)

O_NOFOLLOW is specified by POSIX, at least the latest version. It's also in
OpenBSD, which is the least common denominator for general purpose systems
in my book.

If you're going to be using /tmp (or the like) extensively--and anything
more than O_CREAT|O_EXCL is extensive IMO--it's better to create a
sub-directory and work out of there. The symlink problems disappear as long
as your umask is set appropriately prior to calling mkdir(2).

If you're using /tmp (or the like) for general IPC then perhaps you should
rethink the design. At a minimum it'd be best to create the sub-directory
with a random name so that your application cannot be DoS'd when trying to
create the directory. If you're not sure how you would communicate the
directory name to other processes, then that's a strong hint at a need for a
/var/[app] workspace.

John Kelly

unread,
Nov 25, 2009, 9:47:32 PM11/25/09
to
On Wed, 25 Nov 2009 16:19:26 -0800, William Ahern
<wil...@wilbur.25thandClement.com> wrote:

>O_NOFOLLOW is specified by POSIX, at least the latest version. It's also in
>OpenBSD, which is the least common denominator for general purpose systems
>in my book.

That's good to know. I think I'll just leave things the way they are
and wait for other platforms to catch up.


>If you're going to be using /tmp (or the like) extensively--and anything
>more than O_CREAT|O_EXCL is extensive IMO--it's better to create a
>sub-directory and work out of there. The symlink problems disappear as long
>as your umask is set appropriately prior to calling mkdir(2).
>
>If you're using /tmp (or the like) for general IPC then perhaps you should
>rethink the design. At a minimum it'd be best to create the sub-directory
>with a random name so that your application cannot be DoS'd when trying to
>create the directory. If you're not sure how you would communicate the
>directory name to other processes, then that's a strong hint at a need for a
>/var/[app] workspace.

My needs are a little different.

In the case of dh (daemon helper), I *want* all users to default to a
common directory that collects dh .pid files in one place, so the admin
can readily see who's running daemons. With a command option, the user
can opt out of the default .pid file location, but I still want to have
a common default directory for simple use cases.

For more info about dh:

http://www.beewyz.com/~jar/etcetera/computer/programming/project/dh/


--
Webmail, POP3, and SMTP
http://www.beewyz.com/freeaccounts.php

0 new messages