mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-27 11:43:34 +08:00
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:
parent
9af2e76f29
commit
791cfdb726
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user