All of lore.kernel.org
 help / color / mirror / Atom feed
* Naming O_TMPFILE files
@ 2016-09-21 11:50 Florian Weimer
  2016-09-23  8:41 ` Florian Weimer
  0 siblings, 1 reply; 5+ messages in thread
From: Florian Weimer @ 2016-09-21 11:50 UTC (permalink / raw)
  To: linux-man, Linux API, Linux FS Devel, aneesh.kumar, Alexander Viro

[-- Attachment #1: Type: text/plain, Size: 2423 bytes --]

AT_EMPTY_PATH is supposed to be able to give names to files created with 
O_TMPFILE unless O_EXCL was specified at creation time.

However, since this commit

commit 11a7b371b64ef39fc5fb1b6f2218eef7c4d035e3
Author: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Date:   Sat Jan 29 18:43:42 2011 +0530

fs: allow AT_EMPTY_PATH in linkat(), limit that to CAP_DAC_READ_SEARCH

linkat bails out early with AT_EMPTY_PATH and !CAP_DAC_READ_SEARCH, 
never looking at O_EXCL.

The /proc/self/fd kludge works for unprivileged users, but only if 
*both* paths use AT_FDCWD.  It fails if the first path uses a real 
descriptor for /proc/self/fd, or if the second path uses a real 
descriptor for the current directory, or both.  For privileged users, 
only AT_EMPTY_PATH case with an AT_FDCWD target works.

The attached test program prints under a non-privileged user:

error: linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH):
   No such file or directory
error: linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH):
   No such file or directory
success: linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW)
error: linkat (AT_FDCWD, proc_name, current_fd, out_name, 
AT_SYMLINK_FOLLOW):
   No such file or directory
error: linkat (proc_fd, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
   No such file or directory
error: linkat (proc_fd, proc_name, current_fd, out_name, AT_SYMLINK_FOLLOW):
   No such file or directory
successes: 1, failures: 5

And under a privileged user:

success: linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH)
error: linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH):
   No such file or directory
error: linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
   No such file or directory
error: linkat (AT_FDCWD, proc_name, current_fd, out_name, 
AT_SYMLINK_FOLLOW):
   No such file or directory
error: linkat (proc_fd, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
   No such file or directory
error: linkat (proc_fd, proc_name, current_fd, out_name, AT_SYMLINK_FOLLOW):
   No such file or directory
successes: 1, failures: 5

(Seen on tmpfs and XFS, 4.7.x kernels.)

I double-checked with strace, and the test case does not appear to be 
broken.  But the exhibited behavior is truly bizarre, and it means that 
it is very difficult to give a name to an O_TMPFILE file.

Is this really the intended behavior?  Has it always been this way?

Thanks,
Florian

[-- Attachment #2: linkat.c --]
[-- Type: text/x-csrc, Size: 1997 bytes --]

#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include <stdio.h>

static int failures;
static int successes;

#define CHECK(ret)                              \
  do                                            \
    if ((ret) < 0)                              \
      {                                         \
        printf ("error: %s:\n  %m\n", #ret);    \
        ++failures;                             \
      }                                         \
    else                                        \
      {                                         \
        printf ("success: %s\n", #ret);         \
        ++successes;                            \
      }                                         \
  while (0)

int
main (void)
{
  const char *const out_name = "linkat.out";
  unlink (out_name);

  int fd = open (".", O_RDWR | O_TMPFILE, 0);
  if (fd < 0)
    err (1, "open");
  int current_fd = open (".", O_RDONLY | O_DIRECTORY);
  if (current_fd < 0)
    err (1, "open (O_DIRECTORY)");
  int proc_fd = open ("/proc/self/fd", O_RDONLY | O_DIRECTORY);
  if (proc_fd < 0)
    err (1, "open (O_DIRECTORY)");

  CHECK (linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH));
  unlink (out_name);
  CHECK (linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH));
  unlink (out_name);

  char proc_name[100];
  snprintf (proc_name, sizeof (proc_name), "/proc/self/fd/%d", fd);

  CHECK (linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name,
                 AT_SYMLINK_FOLLOW));
  unlink (out_name);
  CHECK (linkat (AT_FDCWD, proc_name, current_fd, out_name,
                 AT_SYMLINK_FOLLOW));
  unlink (out_name);

  snprintf (proc_name, sizeof (proc_name), "%d", fd);
  CHECK (linkat (proc_fd, proc_name, AT_FDCWD, out_name,
                 AT_SYMLINK_FOLLOW));
  unlink (out_name);
  CHECK (linkat (proc_fd, proc_name, current_fd, out_name,
                 AT_SYMLINK_FOLLOW));
  unlink (out_name);

  printf ("successes: %d, failures: %d\n", successes, failures);

  return 0;
}

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Naming O_TMPFILE files
  2016-09-21 11:50 Naming O_TMPFILE files Florian Weimer
@ 2016-09-23  8:41 ` Florian Weimer
  2016-09-26  8:11   ` Michael Kerrisk (man-pages)
  0 siblings, 1 reply; 5+ messages in thread
From: Florian Weimer @ 2016-09-23  8:41 UTC (permalink / raw)
  To: linux-man, Linux API, Linux FS Devel, aneesh.kumar, Alexander Viro

[-- Attachment #1: Type: text/plain, Size: 2685 bytes --]

On 09/21/2016 01:50 PM, Florian Weimer wrote:
> AT_EMPTY_PATH is supposed to be able to give names to files created with
> O_TMPFILE unless O_EXCL was specified at creation time.
>
> However, since this commit
>
> commit 11a7b371b64ef39fc5fb1b6f2218eef7c4d035e3
> Author: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> Date:   Sat Jan 29 18:43:42 2011 +0530
>
> fs: allow AT_EMPTY_PATH in linkat(), limit that to CAP_DAC_READ_SEARCH
>
> linkat bails out early with AT_EMPTY_PATH and !CAP_DAC_READ_SEARCH,
> never looking at O_EXCL.
>
> The /proc/self/fd kludge works for unprivileged users, but only if
> *both* paths use AT_FDCWD.  It fails if the first path uses a real
> descriptor for /proc/self/fd, or if the second path uses a real
> descriptor for the current directory, or both.  For privileged users,
> only AT_EMPTY_PATH case with an AT_FDCWD target works.
>
> The attached test program prints under a non-privileged user:
>
> error: linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH):
>   No such file or directory
> error: linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH):
>   No such file or directory
> success: linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name,
> AT_SYMLINK_FOLLOW)
> error: linkat (AT_FDCWD, proc_name, current_fd, out_name,
> AT_SYMLINK_FOLLOW):
>   No such file or directory
> error: linkat (proc_fd, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>   No such file or directory
> error: linkat (proc_fd, proc_name, current_fd, out_name,
> AT_SYMLINK_FOLLOW):
>   No such file or directory
> successes: 1, failures: 5
>
> And under a privileged user:
>
> success: linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH)
> error: linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH):
>   No such file or directory
> error: linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>   No such file or directory
> error: linkat (AT_FDCWD, proc_name, current_fd, out_name,
> AT_SYMLINK_FOLLOW):
>   No such file or directory
> error: linkat (proc_fd, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>   No such file or directory
> error: linkat (proc_fd, proc_name, current_fd, out_name,
> AT_SYMLINK_FOLLOW):
>   No such file or directory
> successes: 1, failures: 5
>
> (Seen on tmpfs and XFS, 4.7.x kernels.)
>
> I double-checked with strace, and the test case does not appear to be
> broken.  But the exhibited behavior is truly bizarre, and it means that
> it is very difficult to give a name to an O_TMPFILE file.

The test case is broken because it does not account for the fact that an 
O_TMPFILE file can only be linked once in this way.  This is still a bit 
counter-intuitive, but it means that O_TMPFILE works.

Florian


[-- Attachment #2: linkat.c --]
[-- Type: text/x-csrc, Size: 2192 bytes --]

#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include <stdio.h>

static int failures;
static int successes;

#define CHECK(ret)                              \
  do                                            \
    if ((ret) < 0)                              \
      {                                         \
        printf ("error: %s:\n  %m\n", #ret);    \
        ++failures;                             \
      }                                         \
    else                                        \
      {                                         \
        printf ("success: %s\n", #ret);         \
        ++successes;                            \
      }                                         \
  while (0)

static const char *const out_name = "linkat.out";

void
setup_fd (int *pfd)
{
  if (*pfd >= 0)
    close (*pfd);
  *pfd = open (".", O_RDWR | O_TMPFILE, 0);
  if (*pfd < 0)
    err (1, "open");
}

int
main (void)
{
  unlink (out_name);

  int current_fd = open (".", O_RDONLY | O_DIRECTORY);
  if (current_fd < 0)
    err (1, "open (O_DIRECTORY)");
  int proc_fd = open ("/proc/self/fd", O_RDONLY | O_DIRECTORY);
  if (proc_fd < 0)
    err (1, "open (O_DIRECTORY)");

  int fd = -1;
  setup_fd (&fd);
  CHECK (linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH));
  unlink (out_name);
  setup_fd (&fd);
  CHECK (linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH));
  unlink (out_name);

  char proc_name[100];
  snprintf (proc_name, sizeof (proc_name), "/proc/self/fd/%d", fd);

  setup_fd (&fd);
  CHECK (linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name,
                 AT_SYMLINK_FOLLOW));
  unlink (out_name);
  setup_fd (&fd);
  CHECK (linkat (AT_FDCWD, proc_name, current_fd, out_name,
                 AT_SYMLINK_FOLLOW));
  unlink (out_name);

  snprintf (proc_name, sizeof (proc_name), "%d", fd);
  setup_fd (&fd);
  CHECK (linkat (proc_fd, proc_name, AT_FDCWD, out_name,
                 AT_SYMLINK_FOLLOW));
  unlink (out_name);
  setup_fd (&fd);
  CHECK (linkat (proc_fd, proc_name, current_fd, out_name,
                 AT_SYMLINK_FOLLOW));
  unlink (out_name);

  printf ("successes: %d, failures: %d\n", successes, failures);

  return 0;
}


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Naming O_TMPFILE files
  2016-09-23  8:41 ` Florian Weimer
@ 2016-09-26  8:11   ` Michael Kerrisk (man-pages)
  2016-09-26 15:11       ` Florian Weimer
  0 siblings, 1 reply; 5+ messages in thread
From: Michael Kerrisk (man-pages) @ 2016-09-26  8:11 UTC (permalink / raw)
  To: Florian Weimer, linux-man, Linux API, Linux FS Devel,
	aneesh.kumar, Alexander Viro
  Cc: mtk.manpages

On 09/23/2016 10:41 AM, Florian Weimer wrote:
> On 09/21/2016 01:50 PM, Florian Weimer wrote:
>> AT_EMPTY_PATH is supposed to be able to give names to files created with
>> O_TMPFILE unless O_EXCL was specified at creation time.
>>
>> However, since this commit
>>
>> commit 11a7b371b64ef39fc5fb1b6f2218eef7c4d035e3
>> Author: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
>> Date:   Sat Jan 29 18:43:42 2011 +0530
>>
>> fs: allow AT_EMPTY_PATH in linkat(), limit that to CAP_DAC_READ_SEARCH
>>
>> linkat bails out early with AT_EMPTY_PATH and !CAP_DAC_READ_SEARCH,
>> never looking at O_EXCL.
>>
>> The /proc/self/fd kludge works for unprivileged users, but only if
>> *both* paths use AT_FDCWD.  It fails if the first path uses a real
>> descriptor for /proc/self/fd, or if the second path uses a real
>> descriptor for the current directory, or both.  For privileged users,
>> only AT_EMPTY_PATH case with an AT_FDCWD target works.
>>
>> The attached test program prints under a non-privileged user:
>>
>> error: linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH):
>>   No such file or directory
>> error: linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH):
>>   No such file or directory
>> success: linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name,
>> AT_SYMLINK_FOLLOW)
>> error: linkat (AT_FDCWD, proc_name, current_fd, out_name,
>> AT_SYMLINK_FOLLOW):
>>   No such file or directory
>> error: linkat (proc_fd, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>>   No such file or directory
>> error: linkat (proc_fd, proc_name, current_fd, out_name,
>> AT_SYMLINK_FOLLOW):
>>   No such file or directory
>> successes: 1, failures: 5
>>
>> And under a privileged user:
>>
>> success: linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH)
>> error: linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH):
>>   No such file or directory
>> error: linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>>   No such file or directory
>> error: linkat (AT_FDCWD, proc_name, current_fd, out_name,
>> AT_SYMLINK_FOLLOW):
>>   No such file or directory
>> error: linkat (proc_fd, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>>   No such file or directory
>> error: linkat (proc_fd, proc_name, current_fd, out_name,
>> AT_SYMLINK_FOLLOW):
>>   No such file or directory
>> successes: 1, failures: 5
>>
>> (Seen on tmpfs and XFS, 4.7.x kernels.)
>>
>> I double-checked with strace, and the test case does not appear to be
>> broken.  But the exhibited behavior is truly bizarre, and it means that
>> it is very difficult to give a name to an O_TMPFILE file.
> 
> The test case is broken because it does not account for the fact that an 
> O_TMPFILE file can only be linked once in this way.  This is still a bit 
> counter-intuitive, but it means that O_TMPFILE works.

Florian, could you elaborate on the "can only be linked once in 
this way"? In my experiments, it's possible to link multiple times 
to the O_TMPFILE file.

Cheers,

Michael



-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Naming O_TMPFILE files
  2016-09-26  8:11   ` Michael Kerrisk (man-pages)
@ 2016-09-26 15:11       ` Florian Weimer
  0 siblings, 0 replies; 5+ messages in thread
From: Florian Weimer @ 2016-09-26 15:11 UTC (permalink / raw)
  To: Michael Kerrisk (man-pages)
  Cc: Florian Weimer, linux-man, Linux API, Linux FS Devel,
	aneesh.kumar, Alexander Viro

* Michael Kerrisk:

> On 09/23/2016 10:41 AM, Florian Weimer wrote:
>>> The attached test program prints under a non-privileged user:
>>>
>>> error: linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH):
>>>   No such file or directory
>>> error: linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH):
>>>   No such file or directory
>>> success: linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name,
>>> AT_SYMLINK_FOLLOW)
>>> error: linkat (AT_FDCWD, proc_name, current_fd, out_name,
>>> AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> error: linkat (proc_fd, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> error: linkat (proc_fd, proc_name, current_fd, out_name,
>>> AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> successes: 1, failures: 5
>>>
>>> And under a privileged user:
>>>
>>> success: linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH)
>>> error: linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH):
>>>   No such file or directory
>>> error: linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> error: linkat (AT_FDCWD, proc_name, current_fd, out_name,
>>> AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> error: linkat (proc_fd, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> error: linkat (proc_fd, proc_name, current_fd, out_name,
>>> AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> successes: 1, failures: 5
>>>
>>> (Seen on tmpfs and XFS, 4.7.x kernels.)
>>>
>>> I double-checked with strace, and the test case does not appear to be
>>> broken.  But the exhibited behavior is truly bizarre, and it means that
>>> it is very difficult to give a name to an O_TMPFILE file.
>> 
>> The test case is broken because it does not account for the fact that an 
>> O_TMPFILE file can only be linked once in this way.  This is still a bit 
>> counter-intuitive, but it means that O_TMPFILE works.
>
> Florian, could you elaborate on the "can only be linked once in 
> this way"? In my experiments, it's possible to link multiple times 
> to the O_TMPFILE file.

It's in the quoted bits above.  After the first success, subsequent
attempts at linking the same file descriptor (with AT_EMPTY_PATH or
the /proc/self/fd kludge) fail.  This is what confused me so much, and
makes the behavior seem extremely erratic.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Naming O_TMPFILE files
@ 2016-09-26 15:11       ` Florian Weimer
  0 siblings, 0 replies; 5+ messages in thread
From: Florian Weimer @ 2016-09-26 15:11 UTC (permalink / raw)
  To: Michael Kerrisk (man-pages)
  Cc: Florian Weimer, linux-man, Linux API, Linux FS Devel,
	aneesh.kumar, Alexander Viro

* Michael Kerrisk:

> On 09/23/2016 10:41 AM, Florian Weimer wrote:
>>> The attached test program prints under a non-privileged user:
>>>
>>> error: linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH):
>>>   No such file or directory
>>> error: linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH):
>>>   No such file or directory
>>> success: linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name,
>>> AT_SYMLINK_FOLLOW)
>>> error: linkat (AT_FDCWD, proc_name, current_fd, out_name,
>>> AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> error: linkat (proc_fd, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> error: linkat (proc_fd, proc_name, current_fd, out_name,
>>> AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> successes: 1, failures: 5
>>>
>>> And under a privileged user:
>>>
>>> success: linkat (fd, "", AT_FDCWD, out_name, AT_EMPTY_PATH)
>>> error: linkat (fd, "", current_fd, out_name, AT_EMPTY_PATH):
>>>   No such file or directory
>>> error: linkat (AT_FDCWD, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> error: linkat (AT_FDCWD, proc_name, current_fd, out_name,
>>> AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> error: linkat (proc_fd, proc_name, AT_FDCWD, out_name, AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> error: linkat (proc_fd, proc_name, current_fd, out_name,
>>> AT_SYMLINK_FOLLOW):
>>>   No such file or directory
>>> successes: 1, failures: 5
>>>
>>> (Seen on tmpfs and XFS, 4.7.x kernels.)
>>>
>>> I double-checked with strace, and the test case does not appear to be
>>> broken.  But the exhibited behavior is truly bizarre, and it means that
>>> it is very difficult to give a name to an O_TMPFILE file.
>> 
>> The test case is broken because it does not account for the fact that an 
>> O_TMPFILE file can only be linked once in this way.  This is still a bit 
>> counter-intuitive, but it means that O_TMPFILE works.
>
> Florian, could you elaborate on the "can only be linked once in 
> this way"? In my experiments, it's possible to link multiple times 
> to the O_TMPFILE file.

It's in the quoted bits above.  After the first success, subsequent
attempts at linking the same file descriptor (with AT_EMPTY_PATH or
the /proc/self/fd kludge) fail.  This is what confused me so much, and
makes the behavior seem extremely erratic.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-09-26 15:11 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-21 11:50 Naming O_TMPFILE files Florian Weimer
2016-09-23  8:41 ` Florian Weimer
2016-09-26  8:11   ` Michael Kerrisk (man-pages)
2016-09-26 15:11     ` Florian Weimer
2016-09-26 15:11       ` Florian Weimer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.