1999-03-03 Roland McGrath <roland@baalperazim.frob.com>

* sysdeps/mach/hurd/bits/fcntl.h 
[__USE_GNU] (O_NOFOLLOW, O_DIRECTORY): New macros. 
* hurd/hurdlookup.c (__hurd_file_name_lookup): If O_NOFOLLOW is set, 
set O_NOTRANS as well. 
(__hurd_file_name_lookup_retry): At successful end of lookup, 
if O_NOFOLLOW set, io_stat the resultant port and fail with ENOENT if 
it is a translated node not owned by root. 
(__hurd_file_name_lookup): If O_DIRECTORY is set, put a trailing slash 
on the file name passed to LOOKUP.
This commit is contained in:
Roland McGrath 1999-03-03 00:31:05 +00:00
parent 9af2e76f29
commit 791cfdb726
2 changed files with 71 additions and 13 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1992, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
/* Copyright (C) 1992, 93, 94, 95, 96, 97, 99 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -55,12 +55,10 @@ __hurd_file_name_lookup (error_t (*use_init_port)
error_t err;
enum retry_type doretry;
char retryname[1024]; /* XXX string_t LOSES! */
int startport;
error_t lookup_op (mach_port_t startdir)
{
while (file_name[0] == '/')
file_name++;
return lookup_error ((*lookup) (startdir, file_name, flags, mode,
&doretry, retryname, result));
}
@ -68,13 +66,40 @@ __hurd_file_name_lookup (error_t (*use_init_port)
if (! lookup)
lookup = __dir_lookup;
err = (*use_init_port) (file_name[0] == '/'
? INIT_PORT_CRDIR : INIT_PORT_CWDIR,
&lookup_op);
startport = (file_name[0] == '/') ? INIT_PORT_CRDIR : INIT_PORT_CWDIR;
while (file_name[0] == '/')
file_name++;
#if 0 /* ?? XXX Linux 2.2.1 does this. */
if ((flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
flags |= O_NOFOLLOW;
#endif
if (flags & O_NOFOLLOW) /* See comments below about O_NOFOLLOW. */
flags |= O_NOTRANS;
if (flags & O_DIRECTORY)
{
/* The caller wants to require that the file we look up is a directory.
We can do this without an extra RPC by appending a trailing slash
to the file name we look up. */
size_t len = strlen (file_name);
if (len == 0)
file_name = "/";
else if (file_name[len - 1] != '/')
{
char *n = alloca (len + 2);
memcpy (n, file_name, len);
n[len] = '/';
n[len + 1] = '\0';
file_name = n;
}
}
err = (*use_init_port) (startport, &lookup_op);
if (! err)
err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port, lookup,
doretry, retryname, flags, mode,
result);
err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
lookup, doretry, retryname,
flags, mode, result);
return err;
}
@ -85,7 +110,8 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
(int which, error_t (*operate) (file_t)),
file_t (*get_dtable_port) (int fd),
error_t (*lookup)
(file_t dir, char *name, int flags, mode_t mode,
(file_t dir, char *name,
int flags, mode_t mode,
retry_type *do_retry, string_t retry_name,
mach_port_t *result),
enum retry_type doretry,
@ -152,9 +178,38 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
translator a chance to make a new port for us. */
doretry == FS_RETRY_NORMAL)
{
if (flags & O_NOFOLLOW)
{
/* In Linux, O_NOFOLLOW means to reject symlinks. If we
did an O_NOLINK lookup above and io_stat here to check
for S_IFLNK, a translator like firmlink could easily
spoof this check by not showing S_IFLNK, but in fact
redirecting the lookup to some other name
(i.e. opening the very same holes a symlink would).
Instead we do an O_NOTRANS lookup above, and stat the
underlying node: if it has a translator set, and its
owner is not root (st_uid 0) then we reject it.
Since the motivation for this feature is security, and
that security presumes we trust the containing
directory, this check approximates the security of
refusing symlinks while accepting mount points.
Note that we actually permit something Linux doesn't:
we follow root-owned symlinks; if that is deemed
undesireable, we can add a final check for that
one exception to our general translator-based rule. */
struct stat st;
err = __io_stat (*result, &st);
if (!err
&& st.st_uid != 0
&& (st.st_mode & (S_IPTRANS|S_IATRANS)))
err = ENOENT;
}
/* We got a successful translation. Now apply any open-time
action flags we were passed. */
if (flags & O_TRUNC)
if (!err && (flags & O_TRUNC)) /* Asked to truncate the file. */
err = __file_set_size (*result, 0);
if (err)

View File

@ -1,5 +1,5 @@
/* O_*, F_*, FD_* bit values for GNU.
Copyright (C) 1993, 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
Copyright (C) 1993,94,96,97,98,99 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -52,6 +52,9 @@
#ifdef __USE_GNU
# define O_NOLINK 0x0040 /* No name mappings on final component. */
# define O_NOTRANS 0x0080 /* No translator on final component. */
# define O_NOFOLLOW 0x00100000 /* Produce ENOENT if file is a symlink. */
# define O_DIRECTORY 0x00200000 /* Produce ENOTDIR if not a directory. */
#endif