This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libc/18203] New: realpath() does not handle unreachable paths correctly


https://sourceware.org/bugzilla/show_bug.cgi?id=18203

            Bug ID: 18203
           Summary: realpath() does not handle unreachable paths correctly
           Product: glibc
           Version: 2.19
            Status: NEW
          Severity: normal
          Priority: P2
         Component: libc
          Assignee: unassigned at sourceware dot org
          Reporter: jannhorn at googlemail dot com
                CC: drepper.fsp at gmail dot com

On Linux, getcwd(2) can succeed without returning an absolute path. I just
documented that in a man-pages patch I sent to the man-pages ML and maintainer,
a copy is at
<http://var.thejh.net/0001-getcwd.3-behavior-for-unreachable-cwd.patch>. This
behavior causes realpath to behave inconsistently when dealing with unreachable
paths:

$ cat getcwd.c
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>

int main(void) {
  unshare(CLONE_NEWUSER | CLONE_NEWNS);
  chdir("/usr");
  chroot("bin");

  printf("current directory: \"%s\"\n", get_current_dir_name());

  char *real = realpath(".", NULL);
  printf("realpath of .: \"%s\"\n", real ? real : "{none}");
  real = realpath("../home/jann/.ssh", NULL);
  printf("realpath of path: \"%s\"\n", real ? real : "{none}");

  return 0;
}
$ gcc -o getcwd getcwd.c 
$ ./getcwd
current directory: "(unreachable)/usr"
realpath of .: "(unreachable)/usr"
realpath of path: "{none}"
$ strace ./getcwd
[...]
unshare(CLONE_NEWNS|CLONE_NEWUSER)      = 0
chdir("/usr")                           = 0
chroot("bin")                           = 0
stat(".", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
stat("/media/wdgreen/home/jann/tmp", 0x7fff685a5af0) = -1 ENOENT (No such file
or directory)
brk(0)                                  = 0x7c6000
brk(0x7e8000)                           = 0x7e8000
getcwd("(unreachable)/usr", 4096)       = 18
brk(0x7e7000)                           = 0x7e7000
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0x7f58a5941000
write(1, "current directory: \"(unreachable"..., 39current directory:
"(unreachable)/usr"
) = 39
getcwd("(unreachable)/usr", 4096)       = 18
write(1, "realpath of .: \"(unreachable)/us"..., 35realpath of .:
"(unreachable)/usr"
) = 35
getcwd("(unreachable)/usr", 4096)       = 18
lstat("(unreachable)/home", 0x7fff685a5ac0) = -1 ENOENT (No such file or
directory)
write(1, "realpath of path: \"{none}\"\n", 27realpath of path: "{none}"
) = 27
exit_group(0)                           = ?
+++ exited with 0 +++

As you can see, realpath attempts to lstat() the unreachable path returned by
getcwd() in the last invocation. I think the sanest option to deal with this
would be to let realpath() error out if getcwd() returns a path that does not
start with a slash, but I'm not sure about which errno value to use. Maybe
ENOENT, with the reasoning "if it's not under the root, it doesn't really exist
to us"?

-- 
You are receiving this mail because:
You are on the CC list for the bug.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]