realpath "//" -> EISDIR

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

realpath "//" -> EISDIR

Christian Weisgerber
gmake's regression tests fail the checks for its built-in realpath
function, which led me to this:

  2537 realpath CALL  __realpath(0x7f7ffffbfd6b,0x7f7ffffbf750)
  2537 realpath NAMI  "//"
  2537 realpath RET   __realpath -1 errno 21 Is a directory

That doesn't seem right.

Very recent, unmodified -current.

OpenBSD 6.5-current (GENERIC.MP) #0: Sun Aug  4 17:56:50 CEST 2019
    [hidden email]:/sys/arch/amd64/compile/GENERIC.MP

--
Christian "naddy" Weisgerber                          [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: realpath "//" -> EISDIR

Alexander Bluhm
On Mon, Aug 05, 2019 at 04:22:00PM +0200, Christian Weisgerber wrote:
>   2537 realpath CALL  __realpath(0x7f7ffffbfd6b,0x7f7ffffbf750)
>   2537 realpath NAMI  "//"
>   2537 realpath RET   __realpath -1 errno 21 Is a directory

It looks like the special case for the root directory is not taken.
unveil(2) has the same bug.

ok?

bluhm

Index: kern/vfs_syscalls.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.331
diff -u -p -r1.331 vfs_syscalls.c
--- kern/vfs_syscalls.c 5 Aug 2019 15:13:43 -0000 1.331
+++ kern/vfs_syscalls.c 5 Aug 2019 17:48:30 -0000
@@ -869,7 +869,7 @@ sys___realpath(struct proc *p, void *v,
  syscallarg(const char *) pathname;
  syscallarg(char *) resolved;
  } */ *uap = v;
- char *pathname;
+ char *pathname, *c;
  char *rpbuf;
  struct nameidata nd;
  size_t pathlen;
@@ -923,7 +923,13 @@ sys___realpath(struct proc *p, void *v,
  free(cwdbuf, M_TEMP, cwdlen);
  }

- if (pathlen == 2 && pathname[0] == '/')
+ /* find root "/" or "//" */
+ for (c = pathname; *c != '\0'; c++) {
+ if (*c != '/')
+ break;
+ }
+ if (*c == '\0')
+ /* root directory */
  NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME | REALPATH,
     UIO_SYSSPACE, pathname, p);
  else
@@ -969,7 +975,7 @@ sys_unveil(struct proc *p, void *v, regi
  syscallarg(const char *) path;
  syscallarg(const char *) permissions;
  } */ *uap = v;
- char pathname[MAXPATHLEN];
+ char pathname[MAXPATHLEN], *c;
  struct nameidata nd;
  size_t pathlen;
  char permissions[5];
@@ -998,7 +1004,13 @@ sys_unveil(struct proc *p, void *v, regi
  if (pathlen < 2)
  return EINVAL;

- if (pathlen == 2 && pathname[0] == '/')
+ /* find root "/" or "//" */
+ for (c = pathname; *c != '\0'; c++) {
+ if (*c != '/')
+ break;
+ }
+ if (*c == '\0')
+ /* root directory */
  NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME,
     UIO_SYSSPACE, pathname, p);
  else

Reply | Threaded
Open this post in threaded view
|

Re: realpath "//" -> EISDIR

Sebastian Benoit-3
Alexander Bluhm([hidden email]) on 2019.08.05 19:52:01 +0200:
> On Mon, Aug 05, 2019 at 04:22:00PM +0200, Christian Weisgerber wrote:
> >   2537 realpath CALL  __realpath(0x7f7ffffbfd6b,0x7f7ffffbf750)
> >   2537 realpath NAMI  "//"
> >   2537 realpath RET   __realpath -1 errno 21 Is a directory
>
> It looks like the special case for the root directory is not taken.
> unveil(2) has the same bug.
>
> ok?

reads ok and fixes the gmake regression tests:

   594 Tests in 120 Categories Complete ... No Failures :-)

/Benno

> bluhm
>
> Index: kern/vfs_syscalls.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/kern/vfs_syscalls.c,v
> retrieving revision 1.331
> diff -u -p -r1.331 vfs_syscalls.c
> --- kern/vfs_syscalls.c 5 Aug 2019 15:13:43 -0000 1.331
> +++ kern/vfs_syscalls.c 5 Aug 2019 17:48:30 -0000
> @@ -869,7 +869,7 @@ sys___realpath(struct proc *p, void *v,
>   syscallarg(const char *) pathname;
>   syscallarg(char *) resolved;
>   } */ *uap = v;
> - char *pathname;
> + char *pathname, *c;
>   char *rpbuf;
>   struct nameidata nd;
>   size_t pathlen;
> @@ -923,7 +923,13 @@ sys___realpath(struct proc *p, void *v,
>   free(cwdbuf, M_TEMP, cwdlen);
>   }
>
> - if (pathlen == 2 && pathname[0] == '/')
> + /* find root "/" or "//" */
> + for (c = pathname; *c != '\0'; c++) {
> + if (*c != '/')
> + break;
> + }
> + if (*c == '\0')
> + /* root directory */
>   NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME | REALPATH,
>      UIO_SYSSPACE, pathname, p);
>   else
> @@ -969,7 +975,7 @@ sys_unveil(struct proc *p, void *v, regi
>   syscallarg(const char *) path;
>   syscallarg(const char *) permissions;
>   } */ *uap = v;
> - char pathname[MAXPATHLEN];
> + char pathname[MAXPATHLEN], *c;
>   struct nameidata nd;
>   size_t pathlen;
>   char permissions[5];
> @@ -998,7 +1004,13 @@ sys_unveil(struct proc *p, void *v, regi
>   if (pathlen < 2)
>   return EINVAL;
>
> - if (pathlen == 2 && pathname[0] == '/')
> + /* find root "/" or "//" */
> + for (c = pathname; *c != '\0'; c++) {
> + if (*c != '/')
> + break;
> + }
> + if (*c == '\0')
> + /* root directory */
>   NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME,
>      UIO_SYSSPACE, pathname, p);
>   else
>