* posix/unistd.h: Move declaration of __libc_enable_secure to...
	* include/unistd.h: ...here.

	* elf/dl-open.c (dl_open_worker): If DST is used in SUID program punt.
	* elf/dl-deps.c (expand_dst): Likewise.

	* elf/dynamic-link.h: Set DT_SYMBOLIC, DT_TEXTREL, and DT_BIND_NOW
	based on DT_FLAGS value.

	* elf/do-lookup.h: Remove reference_name parameter, add undef_map.
	Add test for symbols marked STV_HIDDEN.
	* elf/dl-lookup.c (_dl_lookup_symbol): Remove reference_name parameter,
	add undef_map.  Compute reference_name locally.  Update call to
	do_lookup.
	(_dl_lookup_symbol_skip): Likewise.
	(_dl_lookup_versioned_symbol): Likewise.
	(_dl_lookup_versioned_symbol_skip): Likewise.
	* elf/dl-libc.c: Update call to _dl_lookup_*symbol.
	* elf/dl-runtime.c: Likewise.
	* elf/dl-sym.c: Likewise.
	* elf/dl-symbol.c: Likewise.
	* elf/ldsodefs.h: Adjust prototypes.

	* elf/dl-reloc.c (RESOLV): Add test for STV_PROTECTED flag set and
	handle appropriately.  Add comment about DT_TEXTREL.
	* elf/dl-runtime.c: Likewise.
This commit is contained in:
Ulrich Drepper 1999-07-23 22:58:50 +00:00
parent fc9cfb28c0
commit 06535ae948
14 changed files with 194 additions and 113 deletions

View File

@ -13,6 +13,33 @@
DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ.
Add DF_ORIGIN, DF_SYMBOLIC, DF_TEXTREL, and DF_BIND_NOW.
* posix/unistd.h: Move declaration of __libc_enable_secure to...
* include/unistd.h: ...here.
* elf/dl-open.c (dl_open_worker): If DST is used in SUID program punt.
* elf/dl-deps.c (expand_dst): Likewise.
* elf/dynamic-link.h: Set DT_SYMBOLIC, DT_TEXTREL, and DT_BIND_NOW
based on DT_FLAGS value.
* elf/do-lookup.h: Remove reference_name parameter, add undef_map.
Add test for symbols marked STV_HIDDEN.
* elf/dl-lookup.c (_dl_lookup_symbol): Remove reference_name parameter,
add undef_map. Compute reference_name locally. Update call to
do_lookup.
(_dl_lookup_symbol_skip): Likewise.
(_dl_lookup_versioned_symbol): Likewise.
(_dl_lookup_versioned_symbol_skip): Likewise.
* elf/dl-libc.c: Update call to _dl_lookup_*symbol.
* elf/dl-runtime.c: Likewise.
* elf/dl-sym.c: Likewise.
* elf/dl-symbol.c: Likewise.
* elf/ldsodefs.h: Adjust prototypes.
* elf/dl-reloc.c (RESOLV): Add test for STV_PROTECTED flag set and
handle appropriately. Add comment about DT_TEXTREL.
* elf/dl-runtime.c: Likewise.
1999-07-21 Roland McGrath <roland@baalperazim.frob.com>
* elf/dl-reloc.c (_dl_reloc_bad_type): New function.

View File

@ -22,6 +22,7 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <elf/ldsodefs.h>
@ -96,9 +97,15 @@ struct list
\
if (__cnt != 0) \
{ \
char *__newp = (char *) alloca (DL_DST_REQUIRED (l, __str, \
strlen (__str), \
__cnt)); \
char *__newp; \
\
/* DST must not appear in SUID/SGID programs. */ \
if (__libc_enable_secure) \
_dl_signal_error (0, __str, \
"DST not allowed in SUID/SGID programs"); \
\
__newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str), \
__cnt)); \
\
__result = DL_DST_SUBSTITUTE (l, __str, __newp, 0); \
\

View File

@ -82,9 +82,8 @@ do_dlsym (void *ptr)
{
struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
args->ref = NULL;
args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
args->map->l_local_scope,
args->map->l_name, 0);
args->loadbase = _dl_lookup_symbol (args->name, args->map, &args->ref,
args->map->l_local_scope, 0);
}
static void

View File

@ -75,11 +75,11 @@ unsigned long int _dl_num_relocations;
ElfW(Addr)
internal_function
_dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
struct r_scope_elem *symbol_scope[],
const char *reference_name,
_dl_lookup_symbol (const char *undef_name, struct link_map *undef_map,
const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
int reloc_type)
{
const char *reference_name = undef_map ? undef_map->l_name : NULL;
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope;
@ -88,8 +88,8 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
/* Search the relevant loaded objects for a definition. */
for (scope = symbol_scope; *scope; ++scope)
if (do_lookup (undef_name, hash, *ref, &current_value,
*scope, 0, reference_name, NULL, reloc_type))
if (do_lookup (undef_name, undef_map, hash, *ref, &current_value,
*scope, 0, NULL, reloc_type))
break;
if (current_value.s == NULL)
@ -125,11 +125,12 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
SKIP_MAP is only skipped. */
ElfW(Addr)
internal_function
_dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
_dl_lookup_symbol_skip (const char *undef_name,
struct link_map *undef_map, const ElfW(Sym) **ref,
struct r_scope_elem *symbol_scope[],
const char *reference_name,
struct link_map *skip_map)
{
const char *reference_name = undef_map ? undef_map->l_name : NULL;
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope;
@ -143,11 +144,11 @@ _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
assert (i < (*scope)->r_nduplist);
if (i >= (*scope)->r_nlist
|| ! do_lookup (undef_name, hash, *ref, &current_value,
*scope, i, reference_name, skip_map, 0))
|| ! do_lookup (undef_name, undef_map, hash, *ref, &current_value,
*scope, i, skip_map, 0))
while (*++scope)
if (do_lookup (undef_name, hash, *ref, &current_value,
*scope, 0, reference_name, skip_map, 0))
if (do_lookup (undef_name, undef_map, hash, *ref, &current_value,
*scope, 0, skip_map, 0))
break;
if (current_value.s == NULL)
@ -177,12 +178,13 @@ _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
XXX We'll see whether we need this separate function. */
ElfW(Addr)
internal_function
_dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
_dl_lookup_versioned_symbol (const char *undef_name,
struct link_map *undef_map, const ElfW(Sym) **ref,
struct r_scope_elem *symbol_scope[],
const char *reference_name,
const struct r_found_version *version,
int reloc_type)
{
const char *reference_name = undef_map ? undef_map->l_name : NULL;
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope;
@ -192,8 +194,8 @@ _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
/* Search the relevant loaded objects for a definition. */
for (scope = symbol_scope; *scope; ++scope)
{
int res = do_lookup_versioned (undef_name, hash, *ref, &current_value,
*scope, 0, reference_name, version, NULL,
int res = do_lookup_versioned (undef_name, undef_map, hash, *ref,
&current_value, *scope, 0, version, NULL,
reloc_type);
if (res > 0)
break;
@ -250,12 +252,13 @@ _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
ElfW(Addr)
internal_function
_dl_lookup_versioned_symbol_skip (const char *undef_name,
struct link_map *undef_map,
const ElfW(Sym) **ref,
struct r_scope_elem *symbol_scope[],
const char *reference_name,
const struct r_found_version *version,
struct link_map *skip_map)
{
const char *reference_name = undef_map ? undef_map->l_name : NULL;
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope;
@ -269,11 +272,13 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
assert (i < (*scope)->r_nduplist);
if (i >= (*scope)->r_nlist
|| ! do_lookup_versioned (undef_name, hash, *ref, &current_value, *scope,
i, reference_name, version, skip_map, 0))
|| ! do_lookup_versioned (undef_name, undef_map, hash, *ref,
&current_value, *scope, i, version, skip_map,
0))
while (*++scope)
if (do_lookup_versioned (undef_name, hash, *ref, &current_value, *scope,
0, reference_name, version, skip_map, 0))
if (do_lookup_versioned (undef_name, undef_map, hash, *ref,
&current_value, *scope, 0, version, skip_map,
0))
break;
if (current_value.s == NULL)

View File

@ -20,9 +20,10 @@
#include <assert.h>
#include <dlfcn.h>
#include <errno.h>
#include <libintl.h>
#include <stdlib.h>
#include <string.h>
#include <libintl.h>
#include <unistd.h>
#include <sys/mman.h> /* Check whether MAP_COPY is defined. */
#include <sys/param.h>
#include <bits/libc-lock.h>
@ -100,6 +101,12 @@ dl_open_worker (void *a)
struct link_map *call_map;
char *new_file;
/* DSTs must not appear in SUID/SGID programs. */
if (__libc_enable_secure)
/* This is an error. */
_dl_signal_error (0, "dlopen",
"DST not allowed in SUID/SGID programs");
/* We have to find out from which object the caller is calling.
Find the highest-addressed object that ADDRESS is not below. */
call_map = NULL;

View File

@ -71,11 +71,13 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
/* This macro is used as a callback from the ELF_DYNAMIC_RELOCATE code. */
#define RESOLVE(ref, version, flags) \
((version) != NULL && (version)->hash != 0 \
? _dl_lookup_versioned_symbol (strtab + (*ref)->st_name, (ref), scope, \
l->l_name, (version), (flags)) \
: _dl_lookup_symbol (strtab + (*ref)->st_name, (ref), scope, \
l->l_name, (flags)))
(ELFW(ST_VISIBILITY) ((*ref)->st_other) != STV_PROTECTED \
? ((version) != NULL && (version)->hash != 0 \
? _dl_lookup_versioned_symbol (strtab + (*ref)->st_name, l, (ref), \
scope, (version), (flags)) \
: _dl_lookup_symbol (strtab + (*ref)->st_name, l, (ref), scope, \
(flags))) \
: l->l_addr)
#include "dynamic-link.h"
ELF_DYNAMIC_RELOCATE (l, lazy, consider_profiling);
@ -96,6 +98,9 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
/* Mark the object so we know this work has been done. */
l->l_relocated = 1;
/* DT_TEXTREL is now in level 2 and might phase out at some time.
But we rewrite the DT_FLAGS entry to make testing easier and
therefore it will be available at all time. */
if (l->l_info[DT_TEXTREL])
{
/* Undo the protection change we made before relocating. */

View File

@ -66,32 +66,40 @@ fixup (
/* Sanity check that we're really looking at a PLT relocation. */
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
/* Look up the target symbol. */
switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
/* Look up the target symbol. If the symbol is marked STV_PROTEXTED
don't look in the global scope. */
if (ELFW(ST_VISIBILITY) (sym->st_other) != STV_PROTECTED)
{
default:
{
const ElfW(Half) *vernum =
(const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
const struct r_found_version *version = &l->l_versions[ndx];
if (version->hash != 0)
switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
{
default:
{
value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
&sym, l->l_scope, l->l_name,
version, ELF_MACHINE_JMP_SLOT);
break;
}
}
case 0:
value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
l->l_name, ELF_MACHINE_JMP_SLOT);
}
const ElfW(Half) *vernum =
(const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
const struct r_found_version *version = &l->l_versions[ndx];
/* Currently value contains the base load address of the object
that defines sym. Now add in the symbol offset. */
value = (sym ? value + sym->st_value : 0);
if (version->hash != 0)
{
value = _dl_lookup_versioned_symbol(strtab + sym->st_name, l,
&sym, l->l_scope, version,
ELF_MACHINE_JMP_SLOT);
break;
}
}
case 0:
value = _dl_lookup_symbol (strtab + sym->st_name, l, &sym,
l->l_scope, ELF_MACHINE_JMP_SLOT);
}
/* Currently value contains the base load address of the object
that defines sym. Now add in the symbol offset. */
value = (sym ? value + sym->st_value : 0);
}
else
/* We already found the symbol. The module (and therefore its load
address) is also known. */
value = l->l_addr + sym->st_value;
/* And now perhaps the relocation addend. */
value = elf_machine_plt_value (l, reloc, value);
@ -141,33 +149,41 @@ profile_fixup (
/* Sanity check that we're really looking at a PLT relocation. */
assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
/* Look up the target symbol. */
switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
/* Look up the target symbol. If the symbol is marked STV_PROTEXTED
don't look in the global scope. */
if (ELFW(ST_VISIBILITY) (sym->st_other) != STV_PROTECTED)
{
default:
{
const ElfW(Half) *vernum =
(const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
const struct r_found_version *version = &l->l_versions[ndx];
if (version->hash != 0)
switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
{
default:
{
value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
&sym, l->l_scope,
l->l_name, version,
ELF_MACHINE_JMP_SLOT);
break;
}
}
case 0:
value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
l->l_name, ELF_MACHINE_JMP_SLOT);
}
const ElfW(Half) *vernum =
(const void *) l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr;
ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)];
const struct r_found_version *version = &l->l_versions[ndx];
/* Currently value contains the base load address of the object
that defines sym. Now add in the symbol offset. */
value = (sym ? value + sym->st_value : 0);
if (version->hash != 0)
{
value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
l, &sym, l->l_scope,
version,
ELF_MACHINE_JMP_SLOT);
break;
}
}
case 0:
value = _dl_lookup_symbol (strtab + sym->st_name, l, &sym,
l->l_scope, ELF_MACHINE_JMP_SLOT);
}
/* Currently value contains the base load address of the object
that defines sym. Now add in the symbol offset. */
value = (sym ? value + sym->st_value : 0);
}
else
/* We already found the symbol. The module (and therefore its load
address) is also known. */
value = l->l_addr + sym->st_value;
/* And now perhaps the relocation addend. */
value = elf_machine_plt_value (l, reloc, value);

View File

@ -34,7 +34,7 @@ _dl_sym (void *handle, const char *name, void *who)
if (handle == RTLD_DEFAULT)
/* Search the global scope. */
loadbase = _dl_lookup_symbol (name, &ref, _dl_global_scope, NULL, 0);
loadbase = _dl_lookup_symbol (name, NULL, &ref, _dl_global_scope, 0);
else if (handle == RTLD_NEXT)
{
struct link_map *l, *match;
@ -54,15 +54,14 @@ RTLD_NEXT used in code not dynamically loaded"));
while (l->l_loader)
l = l->l_loader;
loadbase = _dl_lookup_symbol_skip (name, &ref, l->l_local_scope,
NULL, match);
loadbase = _dl_lookup_symbol_skip (name, l, &ref, l->l_local_scope,
match);
}
else
{
/* Search the scope of the given object. */
struct link_map *map = handle;
loadbase = _dl_lookup_symbol (name, &ref, map->l_local_scope,
map->l_name, 0);
loadbase = _dl_lookup_symbol (name, map, &ref, map->l_local_scope, 0);
}
if (loadbase)
@ -88,8 +87,8 @@ _dl_vsym (void *handle, const char *name, const char *version, void *who)
if (handle == RTLD_DEFAULT)
/* Search the global scope. */
loadbase = _dl_lookup_versioned_symbol (name, &ref, _dl_global_scope,
NULL, &vers, 0);
loadbase = _dl_lookup_versioned_symbol (name, NULL, &ref, _dl_global_scope,
&vers, 0);
else if (handle == RTLD_NEXT)
{
struct link_map *l, *match;
@ -109,17 +108,16 @@ RTLD_NEXT used in code not dynamically loaded"));
while (l->l_loader)
l = l->l_loader;
loadbase = _dl_lookup_versioned_symbol_skip (name, &ref,
loadbase = _dl_lookup_versioned_symbol_skip (name, l, &ref,
l->l_local_scope,
NULL, &vers, match);
&vers, match);
}
else
{
/* Search the scope of the given object. */
struct link_map *map = handle;
loadbase = _dl_lookup_versioned_symbol (name, &ref,
map->l_local_scope,
map->l_name, &vers, 0);
loadbase = _dl_lookup_versioned_symbol (name, map, &ref,
map->l_local_scope, &vers, 0);
}
if (loadbase)

View File

@ -1,5 +1,5 @@
/* Look up a symbol's run-time value in the scope of a loaded object.
Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc.
Copyright (C) 1995, 1996, 1998, 1999 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
@ -28,7 +28,6 @@ _dl_symbol_value (struct link_map *map, const char *name)
{
ElfW(Addr) loadbase;
const ElfW(Sym) *ref = NULL;
loadbase = _dl_lookup_symbol (name, &ref, map->l_local_scope, map->l_name,
0);
loadbase = _dl_lookup_symbol (name, map, &ref, map->l_local_scope, 0);
return loadbase + ref->st_value;
}

View File

@ -29,10 +29,10 @@
found the symbol, the value 0 if nothing is found and < 0 if
something bad happened. */
static inline int
FCT (const char *undef_name, unsigned long int hash,
const ElfW(Sym) *ref, struct sym_val *result,
struct r_scope_elem *scope, size_t i, const char *reference_name,
ARG struct link_map *skip, int reloc_type)
FCT (const char *undef_name, struct link_map *undef_map,
unsigned long int hash, const ElfW(Sym) *ref, struct sym_val *result,
struct r_scope_elem *scope, size_t i, ARG struct link_map *skip,
int reloc_type)
{
struct link_map **list = scope->r_list;
size_t n = scope->r_nlist;
@ -154,7 +154,12 @@ FCT (const char *undef_name, unsigned long int hash,
sym = num_versions == 1 ? versioned_sym : NULL;
#endif
if (sym != NULL)
if (sym != NULL
/* Don't allow binding if the symbol is hidden. When processor
specific definitions for STV_INTERNAL are defined we might
have to extend this conditional. */
&& (ELFW(ST_VISIBILITY) (sym->st_other) != STV_HIDDEN
|| map == undef_map))
{
found_it:
switch (ELFW(ST_BIND) (sym->st_info))

View File

@ -93,6 +93,19 @@ elf_get_dynamic_info (ElfW(Dyn) *dyn, ElfW(Addr) l_addr,
info[DT_JMPREL]->d_un.d_ptr += l_addr;
if (info[VERSYMIDX (DT_VERSYM)] != NULL)
info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr;
if (info[DT_FLAGS] != NULL)
{
/* Flags are used. Translate to the old form where available.
Since these l_info entries are only tested for NULL pointers it
is ok if they point to the DT_FLAGS entry. */
ElfW(Word) flags = info[DT_FLAGS]->d_un.d_val;
if (flags & DF_SYMBOLIC)
info[DT_SYMBOLIC] = info[DT_FLAGS];
if (flags & DF_TEXTREL)
info[DT_TEXTREL] = info[DT_FLAGS];
if (flags & DF_BIND_NOW)
info[DT_BIND_NOW] = info[DT_FLAGS];
}
}
#ifdef RESOLVE

View File

@ -260,35 +260,35 @@ extern void _dl_setup_hash (struct link_map *map) internal_function;
the `elf_machine_lookup_*_p' macros in dl-machine.h to affect which
symbols can be chosen. */
extern ElfW(Addr) _dl_lookup_symbol (const char *undef,
struct link_map *undef_map,
const ElfW(Sym) **sym,
struct r_scope_elem *symbol_scope[],
const char *reference_name,
int reloc_type)
internal_function;
/* Lookup versioned symbol. */
extern ElfW(Addr) _dl_lookup_versioned_symbol (const char *undef,
struct link_map *undef_map,
const ElfW(Sym) **sym,
struct r_scope_elem *symbol_scope[],
const char *reference_name,
const struct r_found_version *version,
int reloc_type)
internal_function;
/* For handling RTLD_NEXT we must be able to skip shared objects. */
extern ElfW(Addr) _dl_lookup_symbol_skip (const char *undef,
struct link_map *undef_map,
const ElfW(Sym) **sym,
struct r_scope_elem *symbol_scope[],
const char *reference_name,
struct link_map *skip_this)
internal_function;
/* For handling RTLD_NEXT with versioned symbols we must be able to
skip shared objects. */
extern ElfW(Addr) _dl_lookup_versioned_symbol_skip (const char *undef,
struct link_map *undef_map,
const ElfW(Sym) **sym,
struct r_scope_elem *symbol_scope[],
const char *reference_name,
const struct r_found_version *version,
struct link_map *skip_this)
internal_function;

View File

@ -63,4 +63,13 @@ extern int __profil __P ((unsigned short int *__sample_buffer, size_t __size,
size_t __offset, unsigned int __scale));
extern int __getdtablesize __P ((void));
extern int __brk __P ((__ptr_t __addr));
/* This variable is set nonzero at startup if the process's effective
IDs differ from its real IDs, or it is otherwise indicated that
extra security should be used. When this is set the dynamic linker
and some functions contained in the C library ignore various
environment variables that normally affect them. */
extern int __libc_enable_secure;
#endif

View File

@ -927,16 +927,7 @@ extern int lockf64 __P ((int __fd, int __cmd, __off64_t __len));
({ long int __result; \
do __result = (long int) (expression); \
while (__result == -1L && errno == EINTR); \
__result; })) \
/* This variable is set nonzero at startup if the process's effective
IDs differ from its real IDs, or it is otherwise indicated that
extra security should be used. When this is set the dynamic linker
and some functions contained in the C library ignore various
environment variables that normally affect them. */
extern int __libc_enable_secure;
__result; }))
#endif
#if defined __USE_POSIX199309 || defined __USE_UNIX98