mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-04 19:00:09 +00:00
Merge branch release/2.30/master into ibm/2.30/master
This commit is contained in:
commit
60c67613ea
126
ChangeLog
126
ChangeLog
@ -1,3 +1,129 @@
|
||||
2019-08-15 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #24899]
|
||||
* sysdeps/gnu/bits/utmpx.h (struct utmpx): Add
|
||||
__attribute_nonstring__ to ut_line, ut_id, ut_user, ut_host.
|
||||
* sysdeps/unix/sysv/linux/s390/bits/utmpx.h (struct utmpx):
|
||||
Likewise.
|
||||
* sysdeps/gnu/bits/utmp.h (struct utmp): Add
|
||||
__attribute_nonstring__ to ut_id.
|
||||
* sysdeps/unix/sysv/linux/s390/bits/utmpx.h (struct utmp):
|
||||
Likewise.
|
||||
|
||||
2019-08-28 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #24902]
|
||||
* login/Makefile (tests): Add tst-pututxline-lockfail.
|
||||
(tst-pututxline-lockfail): Link with -lpthread.
|
||||
* login/utmp_file.c (internal_getut_r): Remove buffer argument.
|
||||
(__libc_getutid_r): Adjust.
|
||||
(__libc_pututline): Likewise. Check for file_offset == -1.
|
||||
* login/tst-pututxline-lockfail.c: New file.
|
||||
|
||||
2019-08-15 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #24880]
|
||||
* login/utmp_file.c (file_locking_failed): Use struct flock64.
|
||||
(file_locking_unlock): Likewise.
|
||||
|
||||
2019-08-15 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #24879]
|
||||
login: Disarm timer after utmp lock acquisition.
|
||||
* login/utmp_file.c (struct file_locking): Remove.
|
||||
(try_file_lock): Adjust.
|
||||
(file_lock_restore): Remove function.
|
||||
(__libc_getutent_r): .
|
||||
(internal_getut_r): Likewise.
|
||||
(__libc_getutline_r): Likewise.
|
||||
(__libc_pututline): Likewise.
|
||||
(__libc_updwtmp): Likewise.
|
||||
|
||||
2019-08-15 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* login/utmp_file.c (__libc_updwtmp): Unlock the right file
|
||||
descriptor.
|
||||
* login/Makefile (tests): Add tst-updwtmpx.
|
||||
* login/tst-updwtmpx.c: New file.
|
||||
|
||||
2019-08-13 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* login/utmp_file.c (LOCK_FILE, LOCKING_FAILED, UNLOCK_FILE):
|
||||
Remove macros.
|
||||
(struct file_locking): New.
|
||||
(try_file_lock, file_unlock, file_lock_restore): New functions.
|
||||
(__libc_getutent_r): Use the new functions.
|
||||
(internal_getut_r): Likewise.
|
||||
(__libc_getutline_r): Likewise.
|
||||
(__libc_pututline): Likewise.
|
||||
(__libc_updwtmp): Likewise.
|
||||
|
||||
2019-08-13 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* login/getutid_r.c (__getutid_r): _HAVE_UT_ID and _HAVE_UT_TYPE
|
||||
are always true.
|
||||
* login/getutmp.c (getutmp): _HAVE_UT_TYPE, _HAVE_UT_PID,
|
||||
_HAVE_UT_ID, _HAVE_UT_HOST, _HAVE_UT_TV are always true.
|
||||
* login/getutmpx.c (getutmpx): Likewise.
|
||||
* login/login.c (login): _HAVE_UT_TYPE, _HAVE_UT_PID are always
|
||||
true.
|
||||
* login/logout.c (logout): _HAVE_UT_TYPE, _HAVE_UT_HOST,
|
||||
_HAVE_UT_TV are always true.
|
||||
* login/logwtmp.c (logwtmp): _HAVE_UT_PID, _HAVE_UT_TYPE,
|
||||
_HAVE_UT_HOST, _HAVE_UT_TV are always true.
|
||||
* login/tst-utmp.c: _HAVE_UT_TYPE, _HAVE_UT_TV are always true.
|
||||
* login/utmp_file.c (__libc_setutent): _HAVE_UT_TYPE, _HAVE_UT_ID
|
||||
are always true.
|
||||
(internal_getut_r): _HAVE_UT_TYPE is always true.
|
||||
(__libc_pututline): Likewise.
|
||||
* login/programs/utmpdump.c (print_entry): Assume that
|
||||
_HAVE_UT_TYPE, _HAVE_UT_PID, _HAVE_UT_ID, _HAVE_UT_HOST,
|
||||
_HAVE_UT_TV are always true.
|
||||
* sysdeps/generic/utmp-equal.h (__utmp_equal): _HAVE_UT_TYPE,
|
||||
_HAVE_UT_ID are always true.
|
||||
* sysdeps/gnu/bits/utmp.h: Move to ...
|
||||
* bits/utmp.h: ... here, replacing the old file.
|
||||
|
||||
2019-08-05 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #23518]
|
||||
* login/uptmp-private.h (struct ufuncs): Remove definition.
|
||||
(__libc_utmp_file_functions, __libc_utmp_unknown_functions)
|
||||
(__libc_utmp_jump_table): Remove declarations.
|
||||
(__libc_setutent, __libc_getutent_r, __libc_getutid_r)
|
||||
(__libc_getutline_r, __libc_pututline, __libc_endutent)
|
||||
(__libc_updwtmp): Declare.
|
||||
* login/getutent_r.c (__libc_utmp_unknown_functions)
|
||||
(__libc_utmp_jump_table, setutent_unknown, getutent_r_unknown)
|
||||
(getutid_r_unknown, getutline_r_unknown, pututline_unknown)
|
||||
(endutent_unknown): Remove definitions.
|
||||
(__setutent): Call __libc_setutent.
|
||||
(__getutent_r): Call __libc_getutent_r.
|
||||
(__pututline): Call __libc_pututline.
|
||||
(__endutent): Call __libc_endutent.
|
||||
* login/getutid_r.c (__getutid_r): Call __libc_getutid_r.
|
||||
* login/getutline_r.c (__getutline_r): Call __libc_getutline_r.
|
||||
* login/updwtmp.c (__updwtmp): Call __libc_updwtmp.
|
||||
* login/utmp_file.c (__libc_utmp_file_functions): Remove definition
|
||||
(__libc_setutent): Rename from stetutent_file. Drop static.
|
||||
(maybe_setutent): New function.
|
||||
(__libc_getutent_r): Rename from getutent_r_file. Drop static.
|
||||
Check for initialization.
|
||||
(__libc_getutid_r): Rename from getutid_r_file. Drop static.
|
||||
Check for initialization.
|
||||
(__libc_getutline_r): Rename from getutline_r_file. Drop static.
|
||||
Check for initialization.
|
||||
(__libc_pututline): Rename from pututline_file. Drop static.
|
||||
Check for initialization.
|
||||
(__libc_endutent): Rename from endutent_file. Drop static. Check
|
||||
for initialization.
|
||||
(__libc_updwtmp): Rename from updwtmp_file. Drop static.
|
||||
* login/utmpname.c (__utmpname): Call __libc_endutent.
|
||||
* sysdeps/unix/getlogin_r (__getlogin_r): Call __libc_setutent,
|
||||
__libc_getutlien_r, __libc_endutent.
|
||||
* manual/users.texi (Who Logged In, Manipulating the Database):
|
||||
Adjust.
|
||||
|
||||
2019-08-15 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* malloc/Makefile (tests): Only add tst-mxfast for
|
||||
|
10
NEWS
10
NEWS
@ -17,13 +17,23 @@ CVE-2019-19126: ld.so failed to ignore the LD_PREFER_MAP_32BIT_EXEC
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[23518] login: Remove utmp backend jump tables
|
||||
[24682] localedata: zh_CN first weekday should be Monday per GB/T
|
||||
7408-2005
|
||||
[24867] malloc: Remove unwanted leading whitespace in malloc_info
|
||||
[24879] login: Disarm timer after utmp lock acquisition
|
||||
[24880] login: Use struct flock64 in utmp
|
||||
[24882] login: Acquire write lock early in pututline
|
||||
[24986] alpha: new getegid, geteuid and getppid syscalls used
|
||||
unconditionally
|
||||
[24899] login: Add nonstring attributes to struct utmp, struct utmpx
|
||||
[24902] login: pututxline could fail to overwrite existing entries
|
||||
[25189] Don't use a custom wrapper macro around __has_include
|
||||
[25203] libio: Disable vtable validation for pre-2.1 interposed handles
|
||||
[25204] Ignore LD_PREFER_MAP_32BIT_EXEC for SUID programs
|
||||
[25225] ld.so fails to link on x86 if GCC defaults to -fcf-protection
|
||||
[25232] No const correctness for strchr et al. for Clang++
|
||||
[25401] Remove incorrect alloc_size attribute from pvalloc
|
||||
|
||||
|
||||
Version 2.30
|
||||
|
104
bits/utmp.h
104
bits/utmp.h
@ -1,4 +1,4 @@
|
||||
/* The `struct utmp' type, describing entries in the utmp file. Generic/BSDish
|
||||
/* The `struct utmp' type, describing entries in the utmp file.
|
||||
Copyright (C) 1993-2019 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
@ -21,29 +21,107 @@
|
||||
#endif
|
||||
|
||||
#include <paths.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <bits/wordsize.h>
|
||||
|
||||
|
||||
#define UT_NAMESIZE 8
|
||||
#define UT_LINESIZE 8
|
||||
#define UT_HOSTSIZE 16
|
||||
#define UT_LINESIZE 32
|
||||
#define UT_NAMESIZE 32
|
||||
#define UT_HOSTSIZE 256
|
||||
|
||||
|
||||
/* The structure describing an entry in the database of
|
||||
previous logins. */
|
||||
struct lastlog
|
||||
{
|
||||
time_t ll_time;
|
||||
#if __WORDSIZE_TIME64_COMPAT32
|
||||
int32_t ll_time;
|
||||
#else
|
||||
__time_t ll_time;
|
||||
#endif
|
||||
char ll_line[UT_LINESIZE];
|
||||
char ll_host[UT_HOSTSIZE];
|
||||
};
|
||||
|
||||
struct utmp
|
||||
|
||||
/* The structure describing the status of a terminated process. This
|
||||
type is used in `struct utmp' below. */
|
||||
struct exit_status
|
||||
{
|
||||
char ut_line[UT_LINESIZE];
|
||||
char ut_user[UT_NAMESIZE];
|
||||
#define ut_name ut_user
|
||||
char ut_host[UT_HOSTSIZE];
|
||||
long int ut_time;
|
||||
short int e_termination; /* Process termination status. */
|
||||
short int e_exit; /* Process exit status. */
|
||||
};
|
||||
|
||||
|
||||
#define _HAVE_UT_HOST 1 /* We have the ut_host field. */
|
||||
/* The structure describing an entry in the user accounting database. */
|
||||
struct utmp
|
||||
{
|
||||
short int ut_type; /* Type of login. */
|
||||
pid_t ut_pid; /* Process ID of login process. */
|
||||
char ut_line[UT_LINESIZE]
|
||||
__attribute_nonstring__; /* Devicename. */
|
||||
char ut_id[4]
|
||||
__attribute_nonstring__; /* Inittab ID. */
|
||||
char ut_user[UT_NAMESIZE]
|
||||
__attribute_nonstring__; /* Username. */
|
||||
char ut_host[UT_HOSTSIZE]
|
||||
__attribute_nonstring__; /* Hostname for remote login. */
|
||||
struct exit_status ut_exit; /* Exit status of a process marked
|
||||
as DEAD_PROCESS. */
|
||||
/* The ut_session and ut_tv fields must be the same size when compiled
|
||||
32- and 64-bit. This allows data files and shared memory to be
|
||||
shared between 32- and 64-bit applications. */
|
||||
#if __WORDSIZE_TIME64_COMPAT32
|
||||
int32_t ut_session; /* Session ID, used for windowing. */
|
||||
struct
|
||||
{
|
||||
int32_t tv_sec; /* Seconds. */
|
||||
int32_t tv_usec; /* Microseconds. */
|
||||
} ut_tv; /* Time entry was made. */
|
||||
#else
|
||||
long int ut_session; /* Session ID, used for windowing. */
|
||||
struct timeval ut_tv; /* Time entry was made. */
|
||||
#endif
|
||||
|
||||
int32_t ut_addr_v6[4]; /* Internet address of remote host. */
|
||||
char __glibc_reserved[20]; /* Reserved for future use. */
|
||||
};
|
||||
|
||||
/* Backwards compatibility hacks. */
|
||||
#define ut_name ut_user
|
||||
#ifndef _NO_UT_TIME
|
||||
/* We have a problem here: `ut_time' is also used otherwise. Define
|
||||
_NO_UT_TIME if the compiler complains. */
|
||||
# define ut_time ut_tv.tv_sec
|
||||
#endif
|
||||
#define ut_xtime ut_tv.tv_sec
|
||||
#define ut_addr ut_addr_v6[0]
|
||||
|
||||
|
||||
/* Values for the `ut_type' field of a `struct utmp'. */
|
||||
#define EMPTY 0 /* No valid user accounting information. */
|
||||
|
||||
#define RUN_LVL 1 /* The system's runlevel. */
|
||||
#define BOOT_TIME 2 /* Time of system boot. */
|
||||
#define NEW_TIME 3 /* Time after system clock changed. */
|
||||
#define OLD_TIME 4 /* Time when system clock changed. */
|
||||
|
||||
#define INIT_PROCESS 5 /* Process spawned by the init process. */
|
||||
#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */
|
||||
#define USER_PROCESS 7 /* Normal process. */
|
||||
#define DEAD_PROCESS 8 /* Terminated process. */
|
||||
|
||||
#define ACCOUNTING 9
|
||||
|
||||
/* Old Linux name for the EMPTY type. */
|
||||
#define UT_UNKNOWN EMPTY
|
||||
|
||||
|
||||
/* Tell the user that we have a modern system with UT_HOST, UT_PID,
|
||||
UT_TYPE, UT_ID and UT_TV fields. */
|
||||
#define _HAVE_UT_TYPE 1
|
||||
#define _HAVE_UT_PID 1
|
||||
#define _HAVE_UT_ID 1
|
||||
#define _HAVE_UT_TV 1
|
||||
#define _HAVE_UT_HOST 1
|
||||
|
23
configure
vendored
23
configure
vendored
@ -3777,11 +3777,32 @@ else
|
||||
fi
|
||||
|
||||
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
#ifndef __CET__
|
||||
#error no CET compiler support
|
||||
#endif
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"; then :
|
||||
libc_cv_compiler_default_cet=yes
|
||||
else
|
||||
libc_cv_compiler_default_cet=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
||||
|
||||
# Check whether --enable-cet was given.
|
||||
if test "${enable_cet+set}" = set; then :
|
||||
enableval=$enable_cet; enable_cet=$enableval
|
||||
else
|
||||
enable_cet=no
|
||||
enable_cet=$libc_cv_compiler_default_cet
|
||||
fi
|
||||
|
||||
|
||||
|
@ -472,11 +472,18 @@ AC_ARG_ENABLE([mathvec],
|
||||
[build_mathvec=$enableval],
|
||||
[build_mathvec=notset])
|
||||
|
||||
AC_TRY_COMPILE([], [
|
||||
#ifndef __CET__
|
||||
# error no CET compiler support
|
||||
#endif],
|
||||
[libc_cv_compiler_default_cet=yes],
|
||||
[libc_cv_compiler_default_cet=no])
|
||||
|
||||
AC_ARG_ENABLE([cet],
|
||||
AC_HELP_STRING([--enable-cet],
|
||||
[enable Intel Control-flow Enforcement Technology (CET), x86 only]),
|
||||
[enable_cet=$enableval],
|
||||
[enable_cet=no])
|
||||
[enable_cet=$libc_cv_compiler_default_cet])
|
||||
|
||||
# We keep the original values in `$config_*' and never modify them, so we
|
||||
# can write them unchanged into config.make. Everything else uses
|
||||
|
@ -83,6 +83,11 @@ _IO_check_libio (void)
|
||||
= stderr->_vtable_offset =
|
||||
((int) sizeof (struct _IO_FILE)
|
||||
- (int) sizeof (struct _IO_FILE_complete));
|
||||
|
||||
if (_IO_stdin_.vtable != &_IO_old_file_jumps
|
||||
|| _IO_stdout_.vtable != &_IO_old_file_jumps
|
||||
|| _IO_stderr_.vtable != &_IO_old_file_jumps)
|
||||
IO_set_accept_foreign_vtables (&_IO_vtable_check);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,8 @@ endif
|
||||
subdir-dirs = programs
|
||||
vpath %.c programs
|
||||
|
||||
tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin
|
||||
tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
|
||||
tst-pututxline-lockfail tst-pututxline-cache
|
||||
|
||||
# Build the -lutil library with these extra functions.
|
||||
extra-libs := libutil
|
||||
@ -71,3 +72,6 @@ endif
|
||||
$(inst_libexecdir)/pt_chown: $(objpfx)pt_chown $(+force)
|
||||
$(make-target-directory)
|
||||
-$(INSTALL_PROGRAM) -m 4755 -o root $< $@
|
||||
|
||||
$(objpfx)tst-pututxline-lockfail: $(shared-thread-library)
|
||||
$(objpfx)tst-pututxline-cache: $(shared-thread-library)
|
||||
|
@ -23,115 +23,16 @@
|
||||
|
||||
#include "utmp-private.h"
|
||||
|
||||
|
||||
/* Functions defined here. */
|
||||
static int setutent_unknown (void);
|
||||
static int getutent_r_unknown (struct utmp *buffer, struct utmp **result);
|
||||
static int getutid_r_unknown (const struct utmp *line, struct utmp *buffer,
|
||||
struct utmp **result);
|
||||
static int getutline_r_unknown (const struct utmp *id, struct utmp *buffer,
|
||||
struct utmp **result);
|
||||
static struct utmp *pututline_unknown (const struct utmp *data);
|
||||
static void endutent_unknown (void);
|
||||
|
||||
/* Initial Jump table. */
|
||||
const struct utfuncs __libc_utmp_unknown_functions =
|
||||
{
|
||||
setutent_unknown,
|
||||
getutent_r_unknown,
|
||||
getutid_r_unknown,
|
||||
getutline_r_unknown,
|
||||
pututline_unknown,
|
||||
endutent_unknown,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Currently selected backend. */
|
||||
const struct utfuncs *__libc_utmp_jump_table = &__libc_utmp_unknown_functions;
|
||||
|
||||
/* We need to protect the opening of the file. */
|
||||
__libc_lock_define_initialized (, __libc_utmp_lock attribute_hidden)
|
||||
|
||||
|
||||
static int
|
||||
setutent_unknown (void)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = (*__libc_utmp_file_functions.setutent) ();
|
||||
if (result)
|
||||
__libc_utmp_jump_table = &__libc_utmp_file_functions;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getutent_r_unknown (struct utmp *buffer, struct utmp **result)
|
||||
{
|
||||
/* The backend was not yet initialized. */
|
||||
if (setutent_unknown ())
|
||||
return (*__libc_utmp_jump_table->getutent_r) (buffer, result);
|
||||
|
||||
/* Not available. */
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getutid_r_unknown (const struct utmp *id, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
{
|
||||
/* The backend was not yet initialized. */
|
||||
if (setutent_unknown ())
|
||||
return (*__libc_utmp_jump_table->getutid_r) (id, buffer, result);
|
||||
|
||||
/* Not available. */
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getutline_r_unknown (const struct utmp *line, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
{
|
||||
/* The backend was not yet initialized. */
|
||||
if (setutent_unknown ())
|
||||
return (*__libc_utmp_jump_table->getutline_r) (line, buffer, result);
|
||||
|
||||
/* Not available. */
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static struct utmp *
|
||||
pututline_unknown (const struct utmp *data)
|
||||
{
|
||||
/* The backend was not yet initialized. */
|
||||
if (setutent_unknown ())
|
||||
return (*__libc_utmp_jump_table->pututline) (data);
|
||||
|
||||
/* Not available. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
endutent_unknown (void)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
__setutent (void)
|
||||
{
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
(*__libc_utmp_jump_table->setutent) ();
|
||||
__libc_setutent ();
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
}
|
||||
@ -145,7 +46,7 @@ __getutent_r (struct utmp *buffer, struct utmp **result)
|
||||
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
retval = (*__libc_utmp_jump_table->getutent_r) (buffer, result);
|
||||
retval = __libc_getutent_r (buffer, result);
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
|
||||
@ -162,7 +63,7 @@ __pututline (const struct utmp *data)
|
||||
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
buffer = (*__libc_utmp_jump_table->pututline) (data);
|
||||
buffer = __libc_pututline (data);
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
|
||||
@ -177,8 +78,7 @@ __endutent (void)
|
||||
{
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
(*__libc_utmp_jump_table->endutent) ();
|
||||
__libc_utmp_jump_table = &__libc_utmp_unknown_functions;
|
||||
__libc_endutent ();
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ __libc_lock_define (extern, __libc_utmp_lock attribute_hidden)
|
||||
int
|
||||
__getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
|
||||
{
|
||||
#if (_HAVE_UT_ID - 0) && (_HAVE_UT_TYPE - 0)
|
||||
int retval;
|
||||
|
||||
/* Test whether ID has any of the legal types. */
|
||||
@ -49,15 +48,11 @@ __getutid_r (const struct utmp *id, struct utmp *buffer, struct utmp **result)
|
||||
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
retval = (*__libc_utmp_jump_table->getutid_r) (id, buffer, result);
|
||||
retval = __libc_getutid_r (id, buffer, result);
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
|
||||
return retval;
|
||||
#else /* !_HAVE_UT_ID && !_HAVE_UT_TYPE */
|
||||
__set_errno (ENOSYS);
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
libc_hidden_def (__getutid_r)
|
||||
weak_alias (__getutid_r, getutid_r)
|
||||
|
@ -36,7 +36,7 @@ __getutline_r (const struct utmp *line, struct utmp *buffer,
|
||||
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
retval = (*__libc_utmp_jump_table->getutline_r) (line, buffer, result);
|
||||
retval = __libc_getutline_r (line, buffer, result);
|
||||
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
|
||||
|
@ -23,23 +23,11 @@
|
||||
void
|
||||
getutmp (const struct utmpx *utmpx, struct utmp *utmp)
|
||||
{
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
utmp->ut_type = utmpx->ut_type;
|
||||
#endif
|
||||
#if _HAVE_UT_PID - 0
|
||||
utmp->ut_pid = utmpx->ut_pid;
|
||||
#endif
|
||||
memcpy (utmp->ut_line, utmpx->ut_line, sizeof (utmp->ut_line));
|
||||
memcpy (utmp->ut_user, utmpx->ut_user, sizeof (utmp->ut_user));
|
||||
#if _HAVE_UT_ID - 0
|
||||
memcpy (utmp->ut_id, utmpx->ut_id, sizeof (utmp->ut_id));
|
||||
#endif
|
||||
#if _HAVE_UT_HOST - 0
|
||||
memcpy (utmp->ut_host, utmpx->ut_host, sizeof (utmp->ut_host));
|
||||
#endif
|
||||
#if _HAVE_UT_TV - 0
|
||||
utmp->ut_tv = utmpx->ut_tv;
|
||||
#else
|
||||
utmp->ut_time = utmpx->ut_time;
|
||||
#endif
|
||||
}
|
||||
|
@ -24,24 +24,11 @@ void
|
||||
getutmpx (const struct utmp *utmp, struct utmpx *utmpx)
|
||||
{
|
||||
memset (utmpx, 0, sizeof (struct utmpx));
|
||||
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
utmpx->ut_type = utmp->ut_type;
|
||||
#endif
|
||||
#if _HAVE_UT_PID - 0
|
||||
utmpx->ut_pid = utmp->ut_pid;
|
||||
#endif
|
||||
memcpy (utmpx->ut_line, utmp->ut_line, sizeof (utmp->ut_line));
|
||||
memcpy (utmpx->ut_user, utmp->ut_user, sizeof (utmp->ut_user));
|
||||
#if _HAVE_UT_ID - 0
|
||||
memcpy (utmpx->ut_id, utmp->ut_id, sizeof (utmp->ut_id));
|
||||
#endif
|
||||
#if _HAVE_UT_HOST - 0
|
||||
memcpy (utmpx->ut_host, utmp->ut_host, sizeof (utmp->ut_host));
|
||||
#endif
|
||||
#if _HAVE_UT_TV - 0
|
||||
utmpx->ut_tv = utmp->ut_tv;
|
||||
#else
|
||||
utmpx->ut_time = utmp->ut_time;
|
||||
#endif
|
||||
}
|
||||
|
@ -91,12 +91,8 @@ login (const struct utmp *ut)
|
||||
struct utmp copy = *ut;
|
||||
|
||||
/* Fill in those fields we supply. */
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
copy.ut_type = USER_PROCESS;
|
||||
#endif
|
||||
#if _HAVE_UT_PID - 0
|
||||
copy.ut_pid = getpid ();
|
||||
#endif
|
||||
|
||||
/* Seek tty. */
|
||||
found_tty = tty_name (STDIN_FILENO, &tty, sizeof (_tty));
|
||||
|
@ -36,9 +36,7 @@ logout (const char *line)
|
||||
setutent ();
|
||||
|
||||
/* Fill in search information. */
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
tmp.ut_type = USER_PROCESS;
|
||||
#endif
|
||||
strncpy (tmp.ut_line, line, sizeof tmp.ut_line);
|
||||
|
||||
/* Read the record. */
|
||||
@ -46,20 +44,12 @@ logout (const char *line)
|
||||
{
|
||||
/* Clear information about who & from where. */
|
||||
memset (ut->ut_name, '\0', sizeof ut->ut_name);
|
||||
#if _HAVE_UT_HOST - 0
|
||||
memset (ut->ut_host, '\0', sizeof ut->ut_host);
|
||||
#endif
|
||||
#if _HAVE_UT_TV - 0
|
||||
struct timeval tv;
|
||||
__gettimeofday (&tv, NULL);
|
||||
ut->ut_tv.tv_sec = tv.tv_sec;
|
||||
ut->ut_tv.tv_usec = tv.tv_usec;
|
||||
#else
|
||||
ut->ut_time = time (NULL);
|
||||
#endif
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
ut->ut_type = DEAD_PROCESS;
|
||||
#endif
|
||||
|
||||
if (pututline (ut) != NULL)
|
||||
result = 1;
|
||||
|
@ -30,26 +30,16 @@ logwtmp (const char *line, const char *name, const char *host)
|
||||
|
||||
/* Set information in new entry. */
|
||||
memset (&ut, 0, sizeof (ut));
|
||||
#if _HAVE_UT_PID - 0
|
||||
ut.ut_pid = getpid ();
|
||||
#endif
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
ut.ut_type = name[0] ? USER_PROCESS : DEAD_PROCESS;
|
||||
#endif
|
||||
strncpy (ut.ut_line, line, sizeof ut.ut_line);
|
||||
strncpy (ut.ut_name, name, sizeof ut.ut_name);
|
||||
#if _HAVE_UT_HOST - 0
|
||||
strncpy (ut.ut_host, host, sizeof ut.ut_host);
|
||||
#endif
|
||||
|
||||
#if _HAVE_UT_TV - 0
|
||||
struct timeval tv;
|
||||
__gettimeofday (&tv, NULL);
|
||||
ut.ut_tv.tv_sec = tv.tv_sec;
|
||||
ut.ut_tv.tv_usec = tv.tv_usec;
|
||||
#else
|
||||
ut.ut_time = time (NULL);
|
||||
#endif
|
||||
|
||||
updwtmp (_PATH_WTMP, &ut);
|
||||
}
|
||||
|
@ -37,47 +37,11 @@ print_entry (struct utmp *up)
|
||||
temp_tv.tv_sec = up->ut_tv.tv_sec;
|
||||
temp_tv.tv_usec = up->ut_tv.tv_usec;
|
||||
|
||||
(printf) (
|
||||
/* The format string. */
|
||||
#if _HAVE_UT_TYPE
|
||||
"[%d] "
|
||||
#endif
|
||||
#if _HAVE_UT_PID
|
||||
"[%05d] "
|
||||
#endif
|
||||
#if _HAVE_UT_ID
|
||||
"[%-4.4s] "
|
||||
#endif
|
||||
"[%-8.8s] [%-12.12s]"
|
||||
#if _HAVE_UT_HOST
|
||||
" [%-16.16s]"
|
||||
#endif
|
||||
" [%-15.15s]"
|
||||
#if _HAVE_UT_TV
|
||||
" [%ld]"
|
||||
#endif
|
||||
"\n"
|
||||
/* The arguments. */
|
||||
#if _HAVE_UT_TYPE
|
||||
, up->ut_type
|
||||
#endif
|
||||
#if _HAVE_UT_PID
|
||||
, up->ut_pid
|
||||
#endif
|
||||
#if _HAVE_UT_ID
|
||||
, up->ut_id
|
||||
#endif
|
||||
, up->ut_user, up->ut_line
|
||||
#if _HAVE_UT_HOST
|
||||
, up->ut_host
|
||||
#endif
|
||||
#if _HAVE_UT_TV
|
||||
, 4 + ctime (&temp_tv.tv_sec)
|
||||
, (long int) temp_tv.tv_usec
|
||||
#else
|
||||
, 4 + ctime (&up->ut_time)
|
||||
#endif
|
||||
);
|
||||
printf ("[%d] [%05d] [%-4.4s] [%-8.8s] [%-12.12s] [%-16.16s] [%-15.15s]"
|
||||
" [%ld]\n",
|
||||
up->ut_type, up->ut_pid, up->ut_id, up->ut_user, up->ut_line,
|
||||
up->ut_host, 4 + ctime (&temp_tv.tv_sec),
|
||||
(long int) temp_tv.tv_usec);
|
||||
}
|
||||
|
||||
int
|
||||
|
193
login/tst-pututxline-cache.c
Normal file
193
login/tst-pututxline-cache.c
Normal file
@ -0,0 +1,193 @@
|
||||
/* Test case for cache invalidation after concurrent write (bug 24882).
|
||||
Copyright (C) 2019 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
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This test writes an entry to the utmpx file, reads it (so that it
|
||||
is cached) in process1, and overwrites the same entry in process2
|
||||
with something that does not match the search criteria. At this
|
||||
point, the cache of the first process is stale, and when process1
|
||||
attempts to write a new record which would have gone to the same
|
||||
place (as indicated by the cache), it needs to realize that it has
|
||||
to pick a different slot because the old slot is now used for
|
||||
something else. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/namespace.h>
|
||||
#include <support/support.h>
|
||||
#include <support/temp_file.h>
|
||||
#include <support/xthread.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <utmp.h>
|
||||
#include <utmpx.h>
|
||||
|
||||
/* Set to the path of the utmp file. */
|
||||
static char *utmp_file;
|
||||
|
||||
/* Used to synchronize the subprocesses. The barrier itself is
|
||||
allocated in shared memory. */
|
||||
static pthread_barrier_t *barrier;
|
||||
|
||||
/* setutxent with error checking. */
|
||||
static void
|
||||
xsetutxent (void)
|
||||
{
|
||||
errno = 0;
|
||||
setutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
}
|
||||
|
||||
/* getutxent with error checking. */
|
||||
static struct utmpx *
|
||||
xgetutxent (void)
|
||||
{
|
||||
errno = 0;
|
||||
struct utmpx *result = getutxent ();
|
||||
if (result == NULL)
|
||||
FAIL_EXIT1 ("getutxent: %m");
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
put_entry (const char *id, pid_t pid, const char *user, const char *line)
|
||||
{
|
||||
struct utmpx ut =
|
||||
{
|
||||
.ut_type = LOGIN_PROCESS,
|
||||
.ut_pid = pid,
|
||||
.ut_host = "localhost",
|
||||
};
|
||||
strcpy (ut.ut_id, id);
|
||||
strncpy (ut.ut_user, user, sizeof (ut.ut_user));
|
||||
strncpy (ut.ut_line, line, sizeof (ut.ut_line));
|
||||
TEST_VERIFY (pututxline (&ut) != NULL);
|
||||
}
|
||||
|
||||
/* Use two cooperating subprocesses to avoid issues related to
|
||||
unlock-on-close semantics of POSIX advisory locks. */
|
||||
|
||||
static __attribute__ ((noreturn)) void
|
||||
process1 (void)
|
||||
{
|
||||
TEST_COMPARE (utmpname (utmp_file), 0);
|
||||
|
||||
/* Create an entry. */
|
||||
xsetutxent ();
|
||||
put_entry ("1", 101, "root", "process1");
|
||||
|
||||
/* Retrieve the entry. This will fill the internal cache. */
|
||||
{
|
||||
errno = 0;
|
||||
setutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
struct utmpx ut =
|
||||
{
|
||||
.ut_type = LOGIN_PROCESS,
|
||||
.ut_line = "process1",
|
||||
};
|
||||
struct utmpx *result = getutxline (&ut);
|
||||
if (result == NULL)
|
||||
FAIL_EXIT1 ("getutxline (\"process1\"): %m");
|
||||
TEST_COMPARE (result->ut_pid, 101);
|
||||
}
|
||||
|
||||
/* Signal the other process to overwrite the entry. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Wait for the other process to complete the write operation. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Add another entry. Note: This time, there is no setutxent call. */
|
||||
put_entry ("1", 103, "root", "process1");
|
||||
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
static void
|
||||
process2 (void *closure)
|
||||
{
|
||||
/* Wait for the first process to write its entry. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Truncate the file. The glibc interface does not support
|
||||
re-purposing records, but an external expiration mechanism may
|
||||
trigger this. */
|
||||
TEST_COMPARE (truncate64 (utmp_file, 0), 0);
|
||||
|
||||
/* Write the replacement entry. */
|
||||
TEST_COMPARE (utmpname (utmp_file), 0);
|
||||
xsetutxent ();
|
||||
put_entry ("2", 102, "user", "process2");
|
||||
|
||||
/* Signal the other process that the entry has been replaced. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
xclose (create_temp_file ("tst-tumpx-cache-write-", &utmp_file));
|
||||
{
|
||||
pthread_barrierattr_t attr;
|
||||
xpthread_barrierattr_init (&attr);
|
||||
xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS);
|
||||
barrier = support_shared_allocate (sizeof (*barrier));
|
||||
xpthread_barrier_init (barrier, &attr, 2);
|
||||
}
|
||||
|
||||
/* Run both subprocesses in parallel. */
|
||||
{
|
||||
pid_t pid1 = xfork ();
|
||||
if (pid1 == 0)
|
||||
process1 ();
|
||||
support_isolate_in_subprocess (process2, NULL);
|
||||
int status;
|
||||
xwaitpid (pid1, &status, 0);
|
||||
TEST_COMPARE (status, 0);
|
||||
}
|
||||
|
||||
/* Check that the utmpx database contains the expected records. */
|
||||
{
|
||||
TEST_COMPARE (utmpname (utmp_file), 0);
|
||||
xsetutxent ();
|
||||
|
||||
struct utmpx *ut = xgetutxent ();
|
||||
TEST_COMPARE_STRING (ut->ut_id, "2");
|
||||
TEST_COMPARE (ut->ut_pid, 102);
|
||||
TEST_COMPARE_STRING (ut->ut_user, "user");
|
||||
TEST_COMPARE_STRING (ut->ut_line, "process2");
|
||||
|
||||
ut = xgetutxent ();
|
||||
TEST_COMPARE_STRING (ut->ut_id, "1");
|
||||
TEST_COMPARE (ut->ut_pid, 103);
|
||||
TEST_COMPARE_STRING (ut->ut_user, "root");
|
||||
TEST_COMPARE_STRING (ut->ut_line, "process1");
|
||||
|
||||
if (getutxent () != NULL)
|
||||
FAIL_EXIT1 ("additional utmpx entry");
|
||||
}
|
||||
|
||||
xpthread_barrier_destroy (barrier);
|
||||
support_shared_free (barrier);
|
||||
free (utmp_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
176
login/tst-pututxline-lockfail.c
Normal file
176
login/tst-pututxline-lockfail.c
Normal file
@ -0,0 +1,176 @@
|
||||
/* Test the lock upgrade path in tst-pututxline.
|
||||
Copyright (C) 2019 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
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* pututxline upgrades the read lock on the file to a write lock.
|
||||
This test verifies that if the lock upgrade fails, the utmp
|
||||
subsystem remains in a consistent state, so that pututxline can be
|
||||
called again. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <support/check.h>
|
||||
#include <support/namespace.h>
|
||||
#include <support/support.h>
|
||||
#include <support/temp_file.h>
|
||||
#include <support/xthread.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
#include <utmpx.h>
|
||||
|
||||
/* Path to the temporary utmp file. */
|
||||
static char *path;
|
||||
|
||||
/* Used to synchronize the subprocesses. The barrier itself is
|
||||
allocated in shared memory. */
|
||||
static pthread_barrier_t *barrier;
|
||||
|
||||
/* Use pututxline to write an entry for PID. */
|
||||
static struct utmpx *
|
||||
write_entry (pid_t pid)
|
||||
{
|
||||
struct utmpx ut =
|
||||
{
|
||||
.ut_type = LOGIN_PROCESS,
|
||||
.ut_id = "1",
|
||||
.ut_user = "root",
|
||||
.ut_pid = pid,
|
||||
.ut_line = "entry",
|
||||
.ut_host = "localhost",
|
||||
};
|
||||
return pututxline (&ut);
|
||||
}
|
||||
|
||||
/* Create the initial entry in a subprocess, so that the utmp
|
||||
subsystem in the original process is not disturbed. */
|
||||
static void
|
||||
subprocess_create_entry (void *closure)
|
||||
{
|
||||
TEST_COMPARE (utmpname (path), 0);
|
||||
TEST_VERIFY (write_entry (101) != NULL);
|
||||
}
|
||||
|
||||
/* Acquire an advisory read lock on PATH. */
|
||||
__attribute__ ((noreturn)) static void
|
||||
subprocess_lock_file (void)
|
||||
{
|
||||
int fd = xopen (path, O_RDONLY, 0);
|
||||
|
||||
struct flock64 fl =
|
||||
{
|
||||
.l_type = F_RDLCK,
|
||||
fl.l_whence = SEEK_SET,
|
||||
};
|
||||
TEST_COMPARE (fcntl64 (fd, F_SETLKW, &fl), 0);
|
||||
|
||||
/* Signal to the main process that the lock has been acquired. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Wait for the unlock request from the main process. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Implicitly unlock the file. */
|
||||
xclose (fd);
|
||||
|
||||
/* Overwrite the existing entry. */
|
||||
TEST_COMPARE (utmpname (path), 0);
|
||||
errno = 0;
|
||||
setutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
TEST_VERIFY (write_entry (102) != NULL);
|
||||
errno = 0;
|
||||
endutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
xclose (create_temp_file ("tst-pututxline-lockfail-", &path));
|
||||
|
||||
{
|
||||
pthread_barrierattr_t attr;
|
||||
xpthread_barrierattr_init (&attr);
|
||||
xpthread_barrierattr_setpshared (&attr, PTHREAD_SCOPE_PROCESS);
|
||||
barrier = support_shared_allocate (sizeof (*barrier));
|
||||
xpthread_barrier_init (barrier, &attr, 2);
|
||||
xpthread_barrierattr_destroy (&attr);
|
||||
}
|
||||
|
||||
/* Write the initial entry. */
|
||||
support_isolate_in_subprocess (subprocess_create_entry, NULL);
|
||||
|
||||
pid_t locker_pid = xfork ();
|
||||
if (locker_pid == 0)
|
||||
subprocess_lock_file ();
|
||||
|
||||
/* Wait for the file locking to complete. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Try to add another entry. This attempt will fail, with EINTR or
|
||||
EAGAIN. */
|
||||
TEST_COMPARE (utmpname (path), 0);
|
||||
TEST_VERIFY (write_entry (102) == NULL);
|
||||
if (errno != EINTR)
|
||||
TEST_COMPARE (errno, EAGAIN);
|
||||
|
||||
/* Signal the subprocess to overwrite the entry. */
|
||||
xpthread_barrier_wait (barrier);
|
||||
|
||||
/* Wait for write and unlock to complete. */
|
||||
{
|
||||
int status;
|
||||
xwaitpid (locker_pid, &status, 0);
|
||||
TEST_COMPARE (status, 0);
|
||||
}
|
||||
|
||||
/* The file is no longer locked, so this operation will succeed. */
|
||||
TEST_VERIFY (write_entry (103) != NULL);
|
||||
errno = 0;
|
||||
endutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
|
||||
/* Check that there is just one entry with the expected contents.
|
||||
If pututxline becomes desynchronized internally, the entry is not
|
||||
overwritten (bug 24902). */
|
||||
errno = 0;
|
||||
setutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
struct utmpx *ut = getutxent ();
|
||||
TEST_VERIFY_EXIT (ut != NULL);
|
||||
TEST_COMPARE (ut->ut_type, LOGIN_PROCESS);
|
||||
TEST_COMPARE_STRING (ut->ut_id, "1");
|
||||
TEST_COMPARE_STRING (ut->ut_user, "root");
|
||||
TEST_COMPARE (ut->ut_pid, 103);
|
||||
TEST_COMPARE_STRING (ut->ut_line, "entry");
|
||||
TEST_COMPARE_STRING (ut->ut_host, "localhost");
|
||||
TEST_VERIFY (getutxent () == NULL);
|
||||
errno = 0;
|
||||
endutxent ();
|
||||
TEST_COMPARE (errno, 0);
|
||||
|
||||
xpthread_barrier_destroy (barrier);
|
||||
support_shared_free (barrier);
|
||||
free (path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
112
login/tst-updwtmpx.c
Normal file
112
login/tst-updwtmpx.c
Normal file
@ -0,0 +1,112 @@
|
||||
/* Basic test coverage for updwtmpx.
|
||||
Copyright (C) 2019 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
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This program runs a series of tests. Each one calls updwtmpx
|
||||
twice, to write two records, optionally with misalignment in the
|
||||
file, and reads back the results. */
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <support/check.h>
|
||||
#include <support/descriptors.h>
|
||||
#include <support/support.h>
|
||||
#include <support/temp_file.h>
|
||||
#include <support/test-driver.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <unistd.h>
|
||||
#include <utmpx.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* Two entries filled with an arbitrary bit pattern. */
|
||||
struct utmpx entries[2];
|
||||
unsigned char pad;
|
||||
{
|
||||
unsigned char *p = (unsigned char *) &entries[0];
|
||||
for (size_t i = 0; i < sizeof (entries); ++i)
|
||||
{
|
||||
p[i] = i;
|
||||
}
|
||||
/* Make sure that the first and second entry and the padding are
|
||||
different. */
|
||||
p[sizeof (struct utmpx)] = p[0] + 1;
|
||||
pad = p[0] + 2;
|
||||
}
|
||||
|
||||
char *path;
|
||||
int fd = create_temp_file ("tst-updwtmpx-", &path);
|
||||
|
||||
/* Used to check that updwtmpx does not leave an open file
|
||||
descriptor around. */
|
||||
struct support_descriptors *descriptors = support_descriptors_list ();
|
||||
|
||||
/* updwtmpx is expected to remove misalignment. Optionally insert
|
||||
one byte of misalignment at the start and in the middle (after
|
||||
the first entry). */
|
||||
for (int misaligned_start = 0; misaligned_start < 2; ++misaligned_start)
|
||||
for (int misaligned_middle = 0; misaligned_middle < 2; ++misaligned_middle)
|
||||
{
|
||||
if (test_verbose > 0)
|
||||
printf ("info: misaligned_start=%d misaligned_middle=%d\n",
|
||||
misaligned_start, misaligned_middle);
|
||||
|
||||
xftruncate (fd, 0);
|
||||
TEST_COMPARE (pwrite64 (fd, &pad, misaligned_start, 0),
|
||||
misaligned_start);
|
||||
|
||||
/* Write first entry and check it. */
|
||||
errno = 0;
|
||||
updwtmpx (path, &entries[0]);
|
||||
TEST_COMPARE (errno, 0);
|
||||
support_descriptors_check (descriptors);
|
||||
TEST_COMPARE (xlseek (fd, 0, SEEK_END), sizeof (struct utmpx));
|
||||
struct utmpx buffer;
|
||||
TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0),
|
||||
sizeof (buffer));
|
||||
TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]),
|
||||
&buffer, sizeof (buffer));
|
||||
|
||||
/* Middle mis-alignmet. */
|
||||
TEST_COMPARE (pwrite64 (fd, &pad, misaligned_middle,
|
||||
sizeof (struct utmpx)), misaligned_middle);
|
||||
|
||||
/* Write second entry and check both entries. */
|
||||
errno = 0;
|
||||
updwtmpx (path, &entries[1]);
|
||||
TEST_COMPARE (errno, 0);
|
||||
support_descriptors_check (descriptors);
|
||||
TEST_COMPARE (xlseek (fd, 0, SEEK_END), 2 * sizeof (struct utmpx));
|
||||
TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), 0),
|
||||
sizeof (buffer));
|
||||
TEST_COMPARE_BLOB (&entries[0], sizeof (entries[0]),
|
||||
&buffer, sizeof (buffer));
|
||||
TEST_COMPARE (pread64 (fd, &buffer, sizeof (buffer), sizeof (buffer)),
|
||||
sizeof (buffer));
|
||||
TEST_COMPARE_BLOB (&entries[1], sizeof (entries[1]),
|
||||
&buffer, sizeof (buffer));
|
||||
}
|
||||
|
||||
support_descriptors_free (descriptors);
|
||||
free (path);
|
||||
xclose (fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
@ -39,8 +39,6 @@
|
||||
#endif
|
||||
|
||||
|
||||
#if defined UTMPX || _HAVE_UT_TYPE
|
||||
|
||||
/* Prototype for our test function. */
|
||||
static int do_test (int argc, char *argv[]);
|
||||
|
||||
@ -75,11 +73,7 @@ do_prepare (int argc, char *argv[])
|
||||
|
||||
struct utmp entry[] =
|
||||
{
|
||||
#if defined UTMPX || _HAVE_UT_TV
|
||||
#define UT(a) .ut_tv = { .tv_sec = (a)}
|
||||
#else
|
||||
#define UT(a) .ut_time = (a)
|
||||
#endif
|
||||
|
||||
{ .ut_type = BOOT_TIME, .ut_pid = 1, UT(1000) },
|
||||
{ .ut_type = RUN_LVL, .ut_pid = 1, UT(2000) },
|
||||
@ -167,11 +161,7 @@ simulate_login (const char *line, const char *user)
|
||||
entry[n].ut_pid = (entry_pid += 27);
|
||||
entry[n].ut_type = USER_PROCESS;
|
||||
strncpy (entry[n].ut_user, user, sizeof (entry[n].ut_user));
|
||||
#if defined UTMPX || _HAVE_UT_TV - 0
|
||||
entry[n].ut_tv.tv_sec = (entry_time += 1000);
|
||||
#else
|
||||
entry[n].ut_time = (entry_time += 1000);
|
||||
#endif
|
||||
setutent ();
|
||||
|
||||
if (pututline (&entry[n]) == NULL)
|
||||
@ -201,11 +191,7 @@ simulate_logout (const char *line)
|
||||
{
|
||||
entry[n].ut_type = DEAD_PROCESS;
|
||||
strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user));
|
||||
#if defined UTMPX || _HAVE_UT_TV - 0
|
||||
entry[n].ut_tv.tv_sec = (entry_time += 1000);
|
||||
#else
|
||||
entry[n].ut_time = (entry_time += 1000);
|
||||
#endif
|
||||
setutent ();
|
||||
|
||||
if (pututline (&entry[n]) == NULL)
|
||||
@ -390,14 +376,3 @@ do_test (int argc, char *argv[])
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* No field 'ut_type' in struct utmp. */
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -29,7 +29,7 @@ __updwtmp (const char *wtmp_file, const struct utmp *utmp)
|
||||
{
|
||||
const char *file_name = TRANSFORM_UTMP_FILE_NAME (wtmp_file);
|
||||
|
||||
(*__libc_utmp_file_functions.updwtmp) (file_name, utmp);
|
||||
__libc_updwtmp (file_name, utmp);
|
||||
}
|
||||
libc_hidden_def (__updwtmp)
|
||||
weak_alias (__updwtmp, updwtmp)
|
||||
|
@ -24,24 +24,17 @@
|
||||
#include <utmp.h>
|
||||
#include <libc-lock.h>
|
||||
|
||||
/* The structure describing the functions in a backend. */
|
||||
struct utfuncs
|
||||
{
|
||||
int (*setutent) (void);
|
||||
int (*getutent_r) (struct utmp *, struct utmp **);
|
||||
int (*getutid_r) (const struct utmp *, struct utmp *, struct utmp **);
|
||||
int (*getutline_r) (const struct utmp *, struct utmp *, struct utmp **);
|
||||
struct utmp *(*pututline) (const struct utmp *);
|
||||
void (*endutent) (void);
|
||||
int (*updwtmp) (const char *, const struct utmp *);
|
||||
};
|
||||
|
||||
/* The tables from the services. */
|
||||
extern const struct utfuncs __libc_utmp_file_functions attribute_hidden;
|
||||
extern const struct utfuncs __libc_utmp_unknown_functions attribute_hidden;
|
||||
|
||||
/* Currently selected backend. */
|
||||
extern const struct utfuncs *__libc_utmp_jump_table attribute_hidden;
|
||||
/* These functions check for initialization, but not perform any
|
||||
locking. */
|
||||
int __libc_setutent (void) attribute_hidden;
|
||||
int __libc_getutent_r (struct utmp *, struct utmp **) attribute_hidden;
|
||||
int __libc_getutid_r (const struct utmp *, struct utmp *, struct utmp **)
|
||||
attribute_hidden;
|
||||
int __libc_getutline_r (const struct utmp *, struct utmp *, struct utmp **)
|
||||
attribute_hidden;
|
||||
struct utmp *__libc_pututline (const struct utmp *) attribute_hidden;
|
||||
void __libc_endutent (void) attribute_hidden;
|
||||
int __libc_updwtmp (const char *, const struct utmp *) attribute_hidden;
|
||||
|
||||
/* Current file name. */
|
||||
extern const char *__libc_utmp_file_name attribute_hidden;
|
||||
|
@ -43,6 +43,25 @@ static off64_t file_offset;
|
||||
/* Cache for the last read entry. */
|
||||
static struct utmp last_entry;
|
||||
|
||||
/* Returns true if *ENTRY matches last_entry, based on
|
||||
data->ut_type. */
|
||||
static bool
|
||||
matches_last_entry (const struct utmp *data)
|
||||
{
|
||||
if (file_offset <= 0)
|
||||
/* Nothing has been read. last_entry is stale and cannot match. */
|
||||
return false;
|
||||
|
||||
if (data->ut_type == RUN_LVL
|
||||
|| data->ut_type == BOOT_TIME
|
||||
|| data->ut_type == OLD_TIME
|
||||
|| data->ut_type == NEW_TIME)
|
||||
/* For some entry types, only a type match is required. */
|
||||
return data->ut_type == last_entry.ut_type;
|
||||
else
|
||||
/* For the process-related entries, a full match is needed. */
|
||||
return __utmp_equal (&last_entry, data);
|
||||
}
|
||||
|
||||
/* Locking timeout. */
|
||||
#ifndef TIMEOUT
|
||||
@ -52,90 +71,70 @@ static struct utmp last_entry;
|
||||
/* Do-nothing handler for locking timeout. */
|
||||
static void timeout_handler (int signum) {};
|
||||
|
||||
/* LOCK_FILE(fd, type) failure_statement
|
||||
attempts to get a lock on the utmp file referenced by FD. If it fails,
|
||||
the failure_statement is executed, otherwise it is skipped.
|
||||
LOCKING_FAILED()
|
||||
jumps into the UNLOCK_FILE macro and ensures cleanup of LOCK_FILE.
|
||||
UNLOCK_FILE(fd)
|
||||
unlocks the utmp file referenced by FD and performs the cleanup of
|
||||
LOCK_FILE.
|
||||
*/
|
||||
#define LOCK_FILE(fd, type) \
|
||||
{ \
|
||||
struct flock fl; \
|
||||
struct sigaction action, old_action; \
|
||||
unsigned int old_timeout; \
|
||||
\
|
||||
/* Cancel any existing alarm. */ \
|
||||
old_timeout = alarm (0); \
|
||||
\
|
||||
/* Establish signal handler. */ \
|
||||
action.sa_handler = timeout_handler; \
|
||||
__sigemptyset (&action.sa_mask); \
|
||||
action.sa_flags = 0; \
|
||||
__sigaction (SIGALRM, &action, &old_action); \
|
||||
\
|
||||
alarm (TIMEOUT); \
|
||||
\
|
||||
/* Try to get the lock. */ \
|
||||
memset (&fl, '\0', sizeof (struct flock)); \
|
||||
fl.l_type = (type); \
|
||||
fl.l_whence = SEEK_SET; \
|
||||
if (__fcntl64_nocancel ((fd), F_SETLKW, &fl) < 0)
|
||||
|
||||
#define LOCKING_FAILED() \
|
||||
goto unalarm_return
|
||||
/* try_file_lock (LOCKING, FD, TYPE) returns true if the locking
|
||||
operation failed and recovery needs to be performed.
|
||||
|
||||
#define UNLOCK_FILE(fd) \
|
||||
/* Unlock the file. */ \
|
||||
fl.l_type = F_UNLCK; \
|
||||
__fcntl64_nocancel ((fd), F_SETLKW, &fl); \
|
||||
\
|
||||
unalarm_return: \
|
||||
/* Reset the signal handler and alarm. We must reset the alarm \
|
||||
before resetting the handler so our alarm does not generate a \
|
||||
spurious SIGALRM seen by the user. However, we cannot just set \
|
||||
the user's old alarm before restoring the handler, because then \
|
||||
it's possible our handler could catch the user alarm's SIGARLM \
|
||||
and then the user would never see the signal he expected. */ \
|
||||
alarm (0); \
|
||||
__sigaction (SIGALRM, &old_action, NULL); \
|
||||
if (old_timeout != 0) \
|
||||
alarm (old_timeout); \
|
||||
} while (0)
|
||||
file_unlock (FD) removes the lock (which must have been
|
||||
successfully acquired). */
|
||||
|
||||
|
||||
/* Functions defined here. */
|
||||
static int setutent_file (void);
|
||||
static int getutent_r_file (struct utmp *buffer, struct utmp **result);
|
||||
static int getutid_r_file (const struct utmp *key, struct utmp *buffer,
|
||||
struct utmp **result);
|
||||
static int getutline_r_file (const struct utmp *key, struct utmp *buffer,
|
||||
struct utmp **result);
|
||||
static struct utmp *pututline_file (const struct utmp *data);
|
||||
static void endutent_file (void);
|
||||
static int updwtmp_file (const char *file, const struct utmp *utmp);
|
||||
|
||||
/* Jump table for file functions. */
|
||||
const struct utfuncs __libc_utmp_file_functions =
|
||||
static bool
|
||||
try_file_lock (int fd, int type)
|
||||
{
|
||||
setutent_file,
|
||||
getutent_r_file,
|
||||
getutid_r_file,
|
||||
getutline_r_file,
|
||||
pututline_file,
|
||||
endutent_file,
|
||||
updwtmp_file
|
||||
};
|
||||
/* Cancel any existing alarm. */
|
||||
int old_timeout = alarm (0);
|
||||
|
||||
/* Establish signal handler. */
|
||||
struct sigaction old_action;
|
||||
struct sigaction action;
|
||||
action.sa_handler = timeout_handler;
|
||||
__sigemptyset (&action.sa_mask);
|
||||
action.sa_flags = 0;
|
||||
__sigaction (SIGALRM, &action, &old_action);
|
||||
|
||||
alarm (TIMEOUT);
|
||||
|
||||
/* Try to get the lock. */
|
||||
struct flock64 fl =
|
||||
{
|
||||
.l_type = type,
|
||||
.l_whence = SEEK_SET,
|
||||
};
|
||||
|
||||
bool status = __fcntl64_nocancel (fd, F_SETLKW, &fl) < 0;
|
||||
int saved_errno = errno;
|
||||
|
||||
/* Reset the signal handler and alarm. We must reset the alarm
|
||||
before resetting the handler so our alarm does not generate a
|
||||
spurious SIGALRM seen by the user. However, we cannot just set
|
||||
the user's old alarm before restoring the handler, because then
|
||||
it's possible our handler could catch the user alarm's SIGARLM and
|
||||
then the user would never see the signal he expected. */
|
||||
alarm (0);
|
||||
__sigaction (SIGALRM, &old_action, NULL);
|
||||
if (old_timeout != 0)
|
||||
alarm (old_timeout);
|
||||
|
||||
__set_errno (saved_errno);
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
file_unlock (int fd)
|
||||
{
|
||||
struct flock64 fl =
|
||||
{
|
||||
.l_type = F_UNLCK,
|
||||
};
|
||||
__fcntl64_nocancel (fd, F_SETLKW, &fl);
|
||||
}
|
||||
|
||||
#ifndef TRANSFORM_UTMP_FILE_NAME
|
||||
# define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
|
||||
#endif
|
||||
|
||||
static int
|
||||
setutent_file (void)
|
||||
int
|
||||
__libc_setutent (void)
|
||||
{
|
||||
if (file_fd < 0)
|
||||
{
|
||||
@ -153,56 +152,68 @@ setutent_file (void)
|
||||
__lseek64 (file_fd, 0, SEEK_SET);
|
||||
file_offset = 0;
|
||||
|
||||
/* Make sure the entry won't match. */
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
last_entry.ut_type = -1;
|
||||
#else
|
||||
last_entry.ut_line[0] = '\177';
|
||||
# if _HAVE_UT_ID - 0
|
||||
last_entry.ut_id[0] = '\0';
|
||||
# endif
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
getutent_r_file (struct utmp *buffer, struct utmp **result)
|
||||
/* Preform initialization if necessary. */
|
||||
static bool
|
||||
maybe_setutent (void)
|
||||
{
|
||||
ssize_t nbytes;
|
||||
return file_fd >= 0 || __libc_setutent ();
|
||||
}
|
||||
|
||||
assert (file_fd >= 0);
|
||||
/* Reads the entry at file_offset, storing it in last_entry and
|
||||
updating file_offset on success. Returns -1 for a read error, 0
|
||||
for EOF, and 1 for a successful read. last_entry and file_offset
|
||||
are only updated on a successful and complete read. */
|
||||
static ssize_t
|
||||
read_last_entry (void)
|
||||
{
|
||||
struct utmp buffer;
|
||||
ssize_t nbytes = __pread64_nocancel (file_fd, &buffer, sizeof (buffer),
|
||||
file_offset);
|
||||
if (nbytes < 0)
|
||||
return -1;
|
||||
else if (nbytes != sizeof (buffer))
|
||||
/* Assume EOF. */
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
last_entry = buffer;
|
||||
file_offset += sizeof (buffer);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_offset == -1l)
|
||||
int
|
||||
__libc_getutent_r (struct utmp *buffer, struct utmp **result)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
|
||||
if (!maybe_setutent ())
|
||||
{
|
||||
/* Not available. */
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_FILE (file_fd, F_RDLCK)
|
||||
if (try_file_lock (file_fd, F_RDLCK))
|
||||
return -1;
|
||||
|
||||
ssize_t nbytes = read_last_entry ();
|
||||
file_unlock (file_fd);
|
||||
|
||||
if (nbytes <= 0) /* Read error or EOF. */
|
||||
{
|
||||
nbytes = 0;
|
||||
LOCKING_FAILED ();
|
||||
}
|
||||
|
||||
/* Read the next entry. */
|
||||
nbytes = __read_nocancel (file_fd, &last_entry, sizeof (struct utmp));
|
||||
|
||||
UNLOCK_FILE (file_fd);
|
||||
|
||||
if (nbytes != sizeof (struct utmp))
|
||||
{
|
||||
if (nbytes != 0)
|
||||
file_offset = -1l;
|
||||
if (nbytes == 0)
|
||||
/* errno should be unchanged to indicate success. A premature
|
||||
EOF is treated like an EOF (missing complete record at the
|
||||
end). */
|
||||
__set_errno (saved_errno);
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update position pointer. */
|
||||
file_offset += sizeof (struct utmp);
|
||||
|
||||
memcpy (buffer, &last_entry, sizeof (struct utmp));
|
||||
*result = buffer;
|
||||
|
||||
@ -210,82 +221,55 @@ getutent_r_file (struct utmp *buffer, struct utmp **result)
|
||||
}
|
||||
|
||||
|
||||
/* Search for *ID, updating last_entry and file_offset. Return 0 on
|
||||
success and -1 on failure. Does not perform locking; for that see
|
||||
internal_getut_r below. */
|
||||
static int
|
||||
internal_getut_r (const struct utmp *id, struct utmp *buffer,
|
||||
bool *lock_failed)
|
||||
internal_getut_nolock (const struct utmp *id)
|
||||
{
|
||||
int result = -1;
|
||||
while (1)
|
||||
{
|
||||
ssize_t nbytes = read_last_entry ();
|
||||
if (nbytes < 0)
|
||||
return -1;
|
||||
if (nbytes == 0)
|
||||
{
|
||||
/* End of file reached. */
|
||||
__set_errno (ESRCH);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_FILE (file_fd, F_RDLCK)
|
||||
if (matches_last_entry (id))
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Search for *ID, updating last_entry and file_offset. Return 0 on
|
||||
success and -1 on failure. If the locking operation failed, write
|
||||
true to *LOCK_FAILED. */
|
||||
static int
|
||||
internal_getut_r (const struct utmp *id, bool *lock_failed)
|
||||
{
|
||||
if (try_file_lock (file_fd, F_RDLCK))
|
||||
{
|
||||
*lock_failed = true;
|
||||
LOCKING_FAILED ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
|
||||
|| id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
|
||||
{
|
||||
/* Search for next entry with type RUN_LVL, BOOT_TIME,
|
||||
OLD_TIME, or NEW_TIME. */
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Read the next entry. */
|
||||
if (__read_nocancel (file_fd, buffer, sizeof (struct utmp))
|
||||
!= sizeof (struct utmp))
|
||||
{
|
||||
__set_errno (ESRCH);
|
||||
file_offset = -1l;
|
||||
goto unlock_return;
|
||||
}
|
||||
file_offset += sizeof (struct utmp);
|
||||
|
||||
if (id->ut_type == buffer->ut_type)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* _HAVE_UT_TYPE */
|
||||
{
|
||||
/* Search for the next entry with the specified ID and with type
|
||||
INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Read the next entry. */
|
||||
if (__read_nocancel (file_fd, buffer, sizeof (struct utmp))
|
||||
!= sizeof (struct utmp))
|
||||
{
|
||||
__set_errno (ESRCH);
|
||||
file_offset = -1l;
|
||||
goto unlock_return;
|
||||
}
|
||||
file_offset += sizeof (struct utmp);
|
||||
|
||||
if (__utmp_equal (buffer, id))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result = 0;
|
||||
|
||||
unlock_return:
|
||||
UNLOCK_FILE (file_fd);
|
||||
|
||||
int result = internal_getut_nolock (id);
|
||||
file_unlock (file_fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* For implementing this function we don't use the getutent_r function
|
||||
because we can avoid the reposition on every new entry this way. */
|
||||
static int
|
||||
getutid_r_file (const struct utmp *id, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
int
|
||||
__libc_getutid_r (const struct utmp *id, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
{
|
||||
assert (file_fd >= 0);
|
||||
|
||||
if (file_offset == -1l)
|
||||
if (!maybe_setutent ())
|
||||
{
|
||||
*result = NULL;
|
||||
return -1;
|
||||
@ -294,7 +278,7 @@ getutid_r_file (const struct utmp *id, struct utmp *buffer,
|
||||
/* We don't have to distinguish whether we can lock the file or
|
||||
whether there is no entry. */
|
||||
bool lock_failed = false;
|
||||
if (internal_getut_r (id, &last_entry, &lock_failed) < 0)
|
||||
if (internal_getut_r (id, &lock_failed) < 0)
|
||||
{
|
||||
*result = NULL;
|
||||
return -1;
|
||||
@ -306,69 +290,65 @@ getutid_r_file (const struct utmp *id, struct utmp *buffer,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* For implementing this function we don't use the getutent_r function
|
||||
because we can avoid the reposition on every new entry this way. */
|
||||
static int
|
||||
getutline_r_file (const struct utmp *line, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
int
|
||||
__libc_getutline_r (const struct utmp *line, struct utmp *buffer,
|
||||
struct utmp **result)
|
||||
{
|
||||
assert (file_fd >= 0);
|
||||
|
||||
if (file_offset == -1l)
|
||||
if (!maybe_setutent ())
|
||||
{
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCK_FILE (file_fd, F_RDLCK)
|
||||
if (try_file_lock (file_fd, F_RDLCK))
|
||||
{
|
||||
*result = NULL;
|
||||
LOCKING_FAILED ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Read the next entry. */
|
||||
if (__read_nocancel (file_fd, &last_entry, sizeof (struct utmp))
|
||||
!= sizeof (struct utmp))
|
||||
ssize_t nbytes = read_last_entry ();
|
||||
if (nbytes < 0)
|
||||
{
|
||||
__set_errno (ESRCH);
|
||||
file_offset = -1l;
|
||||
file_unlock (file_fd);
|
||||
*result = NULL;
|
||||
goto unlock_return;
|
||||
return -1;
|
||||
}
|
||||
if (nbytes == 0)
|
||||
{
|
||||
/* End of file reached. */
|
||||
file_unlock (file_fd);
|
||||
__set_errno (ESRCH);
|
||||
*result = NULL;
|
||||
return -1;
|
||||
}
|
||||
file_offset += sizeof (struct utmp);
|
||||
|
||||
/* Stop if we found a user or login entry. */
|
||||
if (
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
(last_entry.ut_type == USER_PROCESS
|
||||
if ((last_entry.ut_type == USER_PROCESS
|
||||
|| last_entry.ut_type == LOGIN_PROCESS)
|
||||
&&
|
||||
#endif
|
||||
!strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line))
|
||||
&& (strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line)
|
||||
== 0))
|
||||
break;
|
||||
}
|
||||
|
||||
file_unlock (file_fd);
|
||||
memcpy (buffer, &last_entry, sizeof (struct utmp));
|
||||
*result = buffer;
|
||||
|
||||
unlock_return:
|
||||
UNLOCK_FILE (file_fd);
|
||||
|
||||
return ((*result == NULL) ? -1 : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct utmp *
|
||||
pututline_file (const struct utmp *data)
|
||||
struct utmp *
|
||||
__libc_pututline (const struct utmp *data)
|
||||
{
|
||||
struct utmp buffer;
|
||||
struct utmp *pbuf;
|
||||
int found;
|
||||
if (!maybe_setutent ())
|
||||
return NULL;
|
||||
|
||||
assert (file_fd >= 0);
|
||||
struct utmp *pbuf;
|
||||
|
||||
if (! file_writable)
|
||||
{
|
||||
@ -380,8 +360,7 @@ pututline_file (const struct utmp *data)
|
||||
if (new_fd == -1)
|
||||
return NULL;
|
||||
|
||||
if (__lseek64 (new_fd, __lseek64 (file_fd, 0, SEEK_CUR), SEEK_SET) == -1
|
||||
|| __dup2 (new_fd, file_fd) < 0)
|
||||
if (__dup2 (new_fd, file_fd) < 0)
|
||||
{
|
||||
__close_nocancel_nostatus (new_fd);
|
||||
return NULL;
|
||||
@ -390,95 +369,96 @@ pututline_file (const struct utmp *data)
|
||||
file_writable = true;
|
||||
}
|
||||
|
||||
/* Find the correct place to insert the data. */
|
||||
if (file_offset > 0
|
||||
&& (
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
(last_entry.ut_type == data->ut_type
|
||||
&& (last_entry.ut_type == RUN_LVL
|
||||
|| last_entry.ut_type == BOOT_TIME
|
||||
|| last_entry.ut_type == OLD_TIME
|
||||
|| last_entry.ut_type == NEW_TIME))
|
||||
||
|
||||
#endif
|
||||
__utmp_equal (&last_entry, data)))
|
||||
found = 1;
|
||||
else
|
||||
{
|
||||
bool lock_failed = false;
|
||||
found = internal_getut_r (data, &buffer, &lock_failed);
|
||||
/* Exclude other writers before validating the cache. */
|
||||
if (try_file_lock (file_fd, F_WRLCK))
|
||||
return NULL;
|
||||
|
||||
if (__builtin_expect (lock_failed, false))
|
||||
/* Find the correct place to insert the data. */
|
||||
bool found = false;
|
||||
if (matches_last_entry (data))
|
||||
{
|
||||
/* Read back the entry under the write lock. */
|
||||
file_offset -= sizeof (last_entry);
|
||||
ssize_t nbytes = read_last_entry ();
|
||||
if (nbytes < 0)
|
||||
{
|
||||
__set_errno (EAGAIN);
|
||||
file_unlock (file_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nbytes == 0)
|
||||
/* End of file reached. */
|
||||
found = false;
|
||||
else
|
||||
found = matches_last_entry (data);
|
||||
}
|
||||
|
||||
LOCK_FILE (file_fd, F_WRLCK)
|
||||
{
|
||||
pbuf = NULL;
|
||||
LOCKING_FAILED ();
|
||||
}
|
||||
if (!found)
|
||||
/* Search forward for the entry. */
|
||||
found = internal_getut_nolock (data) >= 0;
|
||||
|
||||
if (found < 0)
|
||||
off64_t write_offset;
|
||||
if (!found)
|
||||
{
|
||||
/* We append the next entry. */
|
||||
file_offset = __lseek64 (file_fd, 0, SEEK_END);
|
||||
if (file_offset % sizeof (struct utmp) != 0)
|
||||
{
|
||||
file_offset -= file_offset % sizeof (struct utmp);
|
||||
__ftruncate64 (file_fd, file_offset);
|
||||
write_offset = __lseek64 (file_fd, 0, SEEK_END);
|
||||
|
||||
if (__lseek64 (file_fd, 0, SEEK_END) < 0)
|
||||
{
|
||||
pbuf = NULL;
|
||||
goto unlock_return;
|
||||
}
|
||||
}
|
||||
/* Round down to the next multiple of the entry size. This
|
||||
ensures any partially-written record is overwritten by the
|
||||
new record. */
|
||||
write_offset = (write_offset / sizeof (struct utmp)
|
||||
* sizeof (struct utmp));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We replace the just read entry. */
|
||||
file_offset -= sizeof (struct utmp);
|
||||
__lseek64 (file_fd, file_offset, SEEK_SET);
|
||||
}
|
||||
/* Overwrite last_entry. */
|
||||
write_offset = file_offset - sizeof (struct utmp);
|
||||
|
||||
/* Write the new data. */
|
||||
if (__write_nocancel (file_fd, data, sizeof (struct utmp))
|
||||
!= sizeof (struct utmp))
|
||||
ssize_t nbytes;
|
||||
if (__lseek64 (file_fd, write_offset, SEEK_SET) < 0
|
||||
|| (nbytes = __write_nocancel (file_fd, data, sizeof (struct utmp))) < 0)
|
||||
{
|
||||
/* There is no need to recover the file position because all
|
||||
reads use pread64, and any future write is preceded by
|
||||
another seek. */
|
||||
file_unlock (file_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nbytes != sizeof (struct utmp))
|
||||
{
|
||||
/* If we appended a new record this is only partially written.
|
||||
Remove it. */
|
||||
if (found < 0)
|
||||
(void) __ftruncate64 (file_fd, file_offset);
|
||||
pbuf = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
file_offset += sizeof (struct utmp);
|
||||
pbuf = (struct utmp *) data;
|
||||
if (!found)
|
||||
(void) __ftruncate64 (file_fd, write_offset);
|
||||
file_unlock (file_fd);
|
||||
/* Assume that the write failure was due to missing disk
|
||||
space. */
|
||||
__set_errno (ENOSPC);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unlock_return:
|
||||
UNLOCK_FILE (file_fd);
|
||||
file_unlock (file_fd);
|
||||
file_offset = write_offset + sizeof (struct utmp);
|
||||
pbuf = (struct utmp *) data;
|
||||
|
||||
return pbuf;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
endutent_file (void)
|
||||
void
|
||||
__libc_endutent (void)
|
||||
{
|
||||
assert (file_fd >= 0);
|
||||
|
||||
__close_nocancel_nostatus (file_fd);
|
||||
file_fd = -1;
|
||||
if (file_fd >= 0)
|
||||
{
|
||||
__close_nocancel_nostatus (file_fd);
|
||||
file_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
updwtmp_file (const char *file, const struct utmp *utmp)
|
||||
int
|
||||
__libc_updwtmp (const char *file, const struct utmp *utmp)
|
||||
{
|
||||
int result = -1;
|
||||
off64_t offset;
|
||||
@ -489,8 +469,11 @@ updwtmp_file (const char *file, const struct utmp *utmp)
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
LOCK_FILE (fd, F_WRLCK)
|
||||
LOCKING_FAILED ();
|
||||
if (try_file_lock (fd, F_WRLCK))
|
||||
{
|
||||
__close_nocancel_nostatus (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remember original size of log file. */
|
||||
offset = __lseek64 (fd, 0, SEEK_END);
|
||||
@ -516,7 +499,7 @@ updwtmp_file (const char *file, const struct utmp *utmp)
|
||||
result = 0;
|
||||
|
||||
unlock_return:
|
||||
UNLOCK_FILE (fd);
|
||||
file_unlock (fd);
|
||||
|
||||
/* Close WTMP file. */
|
||||
__close_nocancel_nostatus (fd);
|
||||
|
@ -42,8 +42,7 @@ __utmpname (const char *file)
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
|
||||
/* Close the old file. */
|
||||
(*__libc_utmp_jump_table->endutent) ();
|
||||
__libc_utmp_jump_table = &__libc_utmp_unknown_functions;
|
||||
__libc_endutent ();
|
||||
|
||||
if (strcmp (file, __libc_utmp_file_name) != 0)
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ headers := $(dist-headers) obstack.h mcheck.h
|
||||
tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
|
||||
tst-mcheck tst-mallocfork tst-trim1 \
|
||||
tst-malloc-usable tst-realloc tst-reallocarray tst-posix_memalign \
|
||||
tst-pvalloc tst-memalign tst-mallopt \
|
||||
tst-pvalloc tst-pvalloc-fortify tst-memalign tst-mallopt \
|
||||
tst-malloc-backtrace tst-malloc-thread-exit \
|
||||
tst-malloc-thread-fail tst-malloc-fork-deadlock \
|
||||
tst-mallocfork2 \
|
||||
|
@ -71,8 +71,7 @@ extern void *valloc (size_t __size) __THROW __attribute_malloc__
|
||||
|
||||
/* Equivalent to valloc(minimum-page-that-holds(n)), that is, round up
|
||||
__size to nearest pagesize. */
|
||||
extern void *pvalloc (size_t __size) __THROW __attribute_malloc__
|
||||
__attribute_alloc_size__ ((1)) __wur;
|
||||
extern void *pvalloc (size_t __size) __THROW __attribute_malloc__ __wur;
|
||||
|
||||
/* Underlying allocation function; successive calls should return
|
||||
contiguous pieces of memory. */
|
||||
|
48
malloc/tst-pvalloc-fortify.c
Normal file
48
malloc/tst-pvalloc-fortify.c
Normal file
@ -0,0 +1,48 @@
|
||||
/* Test fortify-source allocation size handling in pvalloc (bug 25401).
|
||||
Copyright (C) 2020 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
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#undef _FORTIFY_SOURCE
|
||||
#define _FORTIFY_SOURCE 2
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <support/check.h>
|
||||
#include <support/xunistd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
/* The test below assumes that pvalloc rounds up the allocation size
|
||||
to at least 8. */
|
||||
TEST_VERIFY (xsysconf (_SC_PAGESIZE) >= 8);
|
||||
|
||||
void *p = pvalloc (5);
|
||||
TEST_VERIFY_EXIT (p != NULL);
|
||||
|
||||
/* This is valid assuming the page size is at least 8 because
|
||||
pvalloc rounds up the allocation size to a multiple of the page
|
||||
size. Due to bug 25041, this used to trigger a compiler
|
||||
warning. */
|
||||
strcpy (p, "abcdefg");
|
||||
|
||||
asm ("" : : "g" (p) : "memory"); /* Optimization barrier. */
|
||||
TEST_VERIFY (malloc_usable_size (p) >= xsysconf (_SC_PAGESIZE));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
@ -894,9 +894,9 @@ The @code{getlogin} function is declared in @file{unistd.h}, while
|
||||
@c ttyname_r dup @ascuheap @acsmem @acsfd
|
||||
@c strncpy dup ok
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->setutent dup @mtasurace:utent @acsfd
|
||||
@c *libc_utmp_jump_table->getutline_r dup @mtasurace:utent @mtascusig:ALRM @mtascutimer
|
||||
@c *libc_utmp_jump_table->endutent dup @mtasurace:utent @asulock @aculock
|
||||
@c __libc_setutent dup @mtasurace:utent @acsfd
|
||||
@c __libc_getutline_r dup @mtasurace:utent @mtascusig:ALRM @mtascutimer
|
||||
@c __libc_endutent dup @mtasurace:utent @asulock @aculock
|
||||
@c libc_lock_unlock dup ok
|
||||
@c strlen dup ok
|
||||
@c memcpy dup ok
|
||||
@ -1111,7 +1111,7 @@ compatibility only, @file{utmp.h} defines @code{ut_time} as an alias for
|
||||
|
||||
@c setutent @mtasurace:utent @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->setutent @mtasurace:utent @acsfd
|
||||
@c __libc_setutent @mtasurace:utent @acsfd
|
||||
@c setutent_unknown @mtasurace:utent @acsfd
|
||||
@c *libc_utmp_file_functions.setutent = setutent_file @mtasurace:utent @acsfd
|
||||
@c open_not_cancel_2 dup @acsfd
|
||||
@ -1152,7 +1152,7 @@ A null pointer is returned in case no further entry is available.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
|
||||
@c endutent @mtasurace:utent @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->endutent @mtasurace:utent @acsfd
|
||||
@c __libc_endutent @mtasurace:utent @acsfd
|
||||
@c endutent_unknown ok
|
||||
@c endutent_file @mtasurace:utent @acsfd
|
||||
@c close_not_cancel_no_status dup @acsfd
|
||||
@ -1230,7 +1230,7 @@ over again.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
|
||||
@c pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c __libc_pututline @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c pututline_unknown @mtasurace:utent @acsfd
|
||||
@c setutent_unknown dup @mtasurace:utent @acsfd
|
||||
@c pututline_file @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@ -1282,7 +1282,7 @@ user-provided buffer.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
|
||||
@c getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c __libc_getutent_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c getutent_r_unknown @mtasurace:utent @acsfd
|
||||
@c setutent_unknown dup @mtasurace:utent @acsfd
|
||||
@c getutent_r_file @mtasurace:utent @mtascusig:ALRM @mtascutimer
|
||||
@ -1319,7 +1319,7 @@ This function is a GNU extension.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
|
||||
@c getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c __libc_getutid_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c getutid_r_unknown @mtasurace:utent @acsfd
|
||||
@c setutent_unknown dup @mtasurace:utent @acsfd
|
||||
@c getutid_r_file @mtascusig:ALRM @mtascutimer
|
||||
@ -1349,7 +1349,7 @@ This function is a GNU extension.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent} @mtascusig{:ALRM} @mtascutimer{}}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}}
|
||||
@c getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @asulock @aculock @acsfd
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c __libc_getutline_r @mtasurace:utent @mtascusig:ALRM @mtascutimer @acsfd
|
||||
@c getutline_r_unknown @mtasurace:utent @acsfd
|
||||
@c setutent_unknown dup @mtasurace:utent @acsfd
|
||||
@c getutline_r_file @mtasurace:utent @mtascusig:ALRM @mtascutimer
|
||||
@ -1393,7 +1393,7 @@ be used.
|
||||
@safety{@prelim{}@mtunsafe{@mtasurace{:utent}}@asunsafe{@asulock{} @ascuheap{}}@acunsafe{@aculock{} @acsmem{}}}
|
||||
@c utmpname @mtasurace:utent @asulock @ascuheap @aculock @acsmem
|
||||
@c libc_lock_lock dup @asulock @aculock
|
||||
@c *libc_utmp_jump_table->endutent dup @mtasurace:utent
|
||||
@c __libc_endutent dup @mtasurace:utent
|
||||
@c strcmp dup ok
|
||||
@c free dup @ascuheap @acsmem
|
||||
@c strdup dup @ascuheap @acsmem
|
||||
|
@ -33,7 +33,8 @@ __BEGIN_DECLS
|
||||
#include <stddef.h>
|
||||
|
||||
/* Tell the caller that we provide correct C++ prototypes. */
|
||||
#if defined __cplusplus && __GNUC_PREREQ (4, 4)
|
||||
#if defined __cplusplus && (__GNUC_PREREQ (4, 4) \
|
||||
|| __glibc_clang_prereq (3, 5))
|
||||
# define __CORRECT_ISO_CPP_STRING_H_PROTO
|
||||
#endif
|
||||
|
||||
|
@ -139,16 +139,45 @@ check1 (void)
|
||||
static void
|
||||
check2 (void)
|
||||
{
|
||||
const char s1[] = ", enable_static, \0, enable_shared, ";
|
||||
const char s1_stack[] = ", enable_static, \0, enable_shared, ";
|
||||
const size_t s1_byte_count = 18;
|
||||
const char *s2_stack = &(s1_stack[s1_byte_count]);
|
||||
const size_t s2_byte_count = 18;
|
||||
char *exp_result;
|
||||
char *s2 = (void *) buf1 + page_size - 18;
|
||||
const size_t page_size_real = getpagesize ();
|
||||
|
||||
strcpy (s2, s1);
|
||||
exp_result = stupid_strstr (s1, s1 + 18);
|
||||
/* Haystack at end of page. The following page is protected. */
|
||||
char *s1_page_end = (void *) buf1 + page_size - s1_byte_count;
|
||||
strcpy (s1_page_end, s1_stack);
|
||||
|
||||
/* Haystack which crosses a page boundary.
|
||||
Note: page_size is at least 2 * getpagesize. See test_init. */
|
||||
char *s1_page_cross = (void *) buf1 + page_size_real - 8;
|
||||
strcpy (s1_page_cross, s1_stack);
|
||||
|
||||
/* Needle at end of page. The following page is protected. */
|
||||
char *s2_page_end = (void *) buf2 + page_size - s2_byte_count;
|
||||
strcpy (s2_page_end, s2_stack);
|
||||
|
||||
/* Needle which crosses a page boundary.
|
||||
Note: page_size is at least 2 * getpagesize. See test_init. */
|
||||
char *s2_page_cross = (void *) buf2 + page_size_real - 8;
|
||||
strcpy (s2_page_cross, s2_stack);
|
||||
|
||||
exp_result = stupid_strstr (s1_stack, s2_stack);
|
||||
FOR_EACH_IMPL (impl, 0)
|
||||
{
|
||||
check_result (impl, s1, s1 + 18, exp_result);
|
||||
check_result (impl, s2, s1 + 18, exp_result);
|
||||
check_result (impl, s1_stack, s2_stack, exp_result);
|
||||
check_result (impl, s1_stack, s2_page_end, exp_result);
|
||||
check_result (impl, s1_stack, s2_page_cross, exp_result);
|
||||
|
||||
check_result (impl, s1_page_end, s2_stack, exp_result);
|
||||
check_result (impl, s1_page_end, s2_page_end, exp_result);
|
||||
check_result (impl, s1_page_end, s2_page_cross, exp_result);
|
||||
|
||||
check_result (impl, s1_page_cross, s2_stack, exp_result);
|
||||
check_result (impl, s1_page_cross, s2_page_end, exp_result);
|
||||
check_result (impl, s1_page_cross, s2_page_cross, exp_result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,8 @@
|
||||
(void) __close (fd)
|
||||
#define __read_nocancel(fd, buf, n) \
|
||||
__read (fd, buf, n)
|
||||
#define __pread64_nocancel(fd, buf, count, offset) \
|
||||
__pread64 (fd, buf, count, offset)
|
||||
#define __write_nocancel(fd, buf, n) \
|
||||
__write (fd, buf, n)
|
||||
#define __writev_nocancel_nostatus(fd, iov, n) \
|
||||
|
@ -27,26 +27,16 @@
|
||||
static int
|
||||
__utmp_equal (const struct utmp *entry, const struct utmp *match)
|
||||
{
|
||||
return
|
||||
(
|
||||
#if _HAVE_UT_TYPE - 0
|
||||
(entry->ut_type == INIT_PROCESS
|
||||
|| entry->ut_type == LOGIN_PROCESS
|
||||
|| entry->ut_type == USER_PROCESS
|
||||
|| entry->ut_type == DEAD_PROCESS)
|
||||
&&
|
||||
(match->ut_type == INIT_PROCESS
|
||||
|| match->ut_type == LOGIN_PROCESS
|
||||
|| match->ut_type == USER_PROCESS
|
||||
|| match->ut_type == DEAD_PROCESS)
|
||||
&&
|
||||
#endif
|
||||
#if _HAVE_UT_ID - 0
|
||||
(entry->ut_id[0] && match->ut_id[0]
|
||||
? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
|
||||
: strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0)
|
||||
#else
|
||||
strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
|
||||
#endif
|
||||
);
|
||||
return (entry->ut_type == INIT_PROCESS
|
||||
|| entry->ut_type == LOGIN_PROCESS
|
||||
|| entry->ut_type == USER_PROCESS
|
||||
|| entry->ut_type == DEAD_PROCESS)
|
||||
&& (match->ut_type == INIT_PROCESS
|
||||
|| match->ut_type == LOGIN_PROCESS
|
||||
|| match->ut_type == USER_PROCESS
|
||||
|| match->ut_type == DEAD_PROCESS)
|
||||
&& (entry->ut_id[0] && match->ut_id[0]
|
||||
? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
|
||||
: (strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line)
|
||||
== 0));
|
||||
}
|
||||
|
@ -1,126 +0,0 @@
|
||||
/* The `struct utmp' type, describing entries in the utmp file. GNU version.
|
||||
Copyright (C) 1993-2019 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
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _UTMP_H
|
||||
# error "Never include <bits/utmp.h> directly; use <utmp.h> instead."
|
||||
#endif
|
||||
|
||||
#include <paths.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <bits/wordsize.h>
|
||||
|
||||
|
||||
#define UT_LINESIZE 32
|
||||
#define UT_NAMESIZE 32
|
||||
#define UT_HOSTSIZE 256
|
||||
|
||||
|
||||
/* The structure describing an entry in the database of
|
||||
previous logins. */
|
||||
struct lastlog
|
||||
{
|
||||
#if __WORDSIZE_TIME64_COMPAT32
|
||||
int32_t ll_time;
|
||||
#else
|
||||
__time_t ll_time;
|
||||
#endif
|
||||
char ll_line[UT_LINESIZE];
|
||||
char ll_host[UT_HOSTSIZE];
|
||||
};
|
||||
|
||||
|
||||
/* The structure describing the status of a terminated process. This
|
||||
type is used in `struct utmp' below. */
|
||||
struct exit_status
|
||||
{
|
||||
short int e_termination; /* Process termination status. */
|
||||
short int e_exit; /* Process exit status. */
|
||||
};
|
||||
|
||||
|
||||
/* The structure describing an entry in the user accounting database. */
|
||||
struct utmp
|
||||
{
|
||||
short int ut_type; /* Type of login. */
|
||||
pid_t ut_pid; /* Process ID of login process. */
|
||||
char ut_line[UT_LINESIZE]
|
||||
__attribute_nonstring__; /* Devicename. */
|
||||
char ut_id[4]; /* Inittab ID. */
|
||||
char ut_user[UT_NAMESIZE]
|
||||
__attribute_nonstring__; /* Username. */
|
||||
char ut_host[UT_HOSTSIZE]
|
||||
__attribute_nonstring__; /* Hostname for remote login. */
|
||||
struct exit_status ut_exit; /* Exit status of a process marked
|
||||
as DEAD_PROCESS. */
|
||||
/* The ut_session and ut_tv fields must be the same size when compiled
|
||||
32- and 64-bit. This allows data files and shared memory to be
|
||||
shared between 32- and 64-bit applications. */
|
||||
#if __WORDSIZE_TIME64_COMPAT32
|
||||
int32_t ut_session; /* Session ID, used for windowing. */
|
||||
struct
|
||||
{
|
||||
int32_t tv_sec; /* Seconds. */
|
||||
int32_t tv_usec; /* Microseconds. */
|
||||
} ut_tv; /* Time entry was made. */
|
||||
#else
|
||||
long int ut_session; /* Session ID, used for windowing. */
|
||||
struct timeval ut_tv; /* Time entry was made. */
|
||||
#endif
|
||||
|
||||
int32_t ut_addr_v6[4]; /* Internet address of remote host. */
|
||||
char __glibc_reserved[20]; /* Reserved for future use. */
|
||||
};
|
||||
|
||||
/* Backwards compatibility hacks. */
|
||||
#define ut_name ut_user
|
||||
#ifndef _NO_UT_TIME
|
||||
/* We have a problem here: `ut_time' is also used otherwise. Define
|
||||
_NO_UT_TIME if the compiler complains. */
|
||||
# define ut_time ut_tv.tv_sec
|
||||
#endif
|
||||
#define ut_xtime ut_tv.tv_sec
|
||||
#define ut_addr ut_addr_v6[0]
|
||||
|
||||
|
||||
/* Values for the `ut_type' field of a `struct utmp'. */
|
||||
#define EMPTY 0 /* No valid user accounting information. */
|
||||
|
||||
#define RUN_LVL 1 /* The system's runlevel. */
|
||||
#define BOOT_TIME 2 /* Time of system boot. */
|
||||
#define NEW_TIME 3 /* Time after system clock changed. */
|
||||
#define OLD_TIME 4 /* Time when system clock changed. */
|
||||
|
||||
#define INIT_PROCESS 5 /* Process spawned by the init process. */
|
||||
#define LOGIN_PROCESS 6 /* Session leader of a logged in user. */
|
||||
#define USER_PROCESS 7 /* Normal process. */
|
||||
#define DEAD_PROCESS 8 /* Terminated process. */
|
||||
|
||||
#define ACCOUNTING 9
|
||||
|
||||
/* Old Linux name for the EMPTY type. */
|
||||
#define UT_UNKNOWN EMPTY
|
||||
|
||||
|
||||
/* Tell the user that we have a modern system with UT_HOST, UT_PID,
|
||||
UT_TYPE, UT_ID and UT_TV fields. */
|
||||
#define _HAVE_UT_TYPE 1
|
||||
#define _HAVE_UT_PID 1
|
||||
#define _HAVE_UT_ID 1
|
||||
#define _HAVE_UT_TV 1
|
||||
#define _HAVE_UT_HOST 1
|
@ -56,10 +56,14 @@ struct utmpx
|
||||
{
|
||||
short int ut_type; /* Type of login. */
|
||||
__pid_t ut_pid; /* Process ID of login process. */
|
||||
char ut_line[__UT_LINESIZE]; /* Devicename. */
|
||||
char ut_id[4]; /* Inittab ID. */
|
||||
char ut_user[__UT_NAMESIZE]; /* Username. */
|
||||
char ut_host[__UT_HOSTSIZE]; /* Hostname for remote login. */
|
||||
char ut_line[__UT_LINESIZE]
|
||||
__attribute_nonstring__; /* Devicename. */
|
||||
char ut_id[4]
|
||||
__attribute_nonstring__; /* Inittab ID. */
|
||||
char ut_user[__UT_NAMESIZE]
|
||||
__attribute_nonstring__; /* Username. */
|
||||
char ut_host[__UT_HOSTSIZE]
|
||||
__attribute_nonstring__; /* Hostname for remote login. */
|
||||
struct __exit_status ut_exit; /* Exit status of a process marked
|
||||
as DEAD_PROCESS. */
|
||||
|
||||
|
@ -164,7 +164,7 @@ ENTRY(STRSTR_ARCH13)
|
||||
vfenezb %v19,%v18,%v18 /* Search zero in loaded needle bytes. */
|
||||
veclb %v19,%v21 /* Zero index <= max loaded byte index? */
|
||||
jle .Lneedle_loaded /* -> v18 contains full needle. */
|
||||
vl %v16,0(%r3) /* Load needle beyond page boundary. */
|
||||
vl %v18,0(%r3) /* Load needle beyond page boundary. */
|
||||
vfenezb %v19,%v18,%v18
|
||||
j .Lneedle_loaded
|
||||
END(STRSTR_ARCH13)
|
||||
|
@ -64,8 +64,8 @@ __getlogin_r (char *name, size_t name_len)
|
||||
held so that our search is thread-safe. */
|
||||
|
||||
__libc_lock_lock (__libc_utmp_lock);
|
||||
(*__libc_utmp_jump_table->setutent) ();
|
||||
result = (*__libc_utmp_jump_table->getutline_r) (&line, &buffer, &ut);
|
||||
__libc_setutent ();
|
||||
result = __libc_getutline_r (&line, &buffer, &ut);
|
||||
if (result < 0)
|
||||
{
|
||||
if (errno == ESRCH)
|
||||
@ -74,8 +74,7 @@ __getlogin_r (char *name, size_t name_len)
|
||||
else
|
||||
result = errno;
|
||||
}
|
||||
(*__libc_utmp_jump_table->endutent) ();
|
||||
__libc_utmp_jump_table = &__libc_utmp_unknown_functions;
|
||||
__libc_endutent ();
|
||||
__libc_lock_unlock (__libc_utmp_lock);
|
||||
|
||||
if (result == 0)
|
||||
|
@ -212,8 +212,8 @@ sysdep_routines += xstatconv internal_statvfs internal_statvfs64 \
|
||||
close_nocancel fcntl_nocancel nanosleep_nocancel \
|
||||
open_nocancel open64_nocancel \
|
||||
openat_nocancel openat64_nocancel \
|
||||
pause_nocancel read_nocancel waitpid_nocancel \
|
||||
write_nocancel statx_cp
|
||||
pause_nocancel read_nocancel pread64_nocancel \
|
||||
waitpid_nocancel write_nocancel statx_cp
|
||||
|
||||
sysdep_headers += bits/fcntl-linux.h
|
||||
|
||||
|
@ -182,6 +182,7 @@ libc {
|
||||
__syscall_rt_sigqueueinfo;
|
||||
__open_nocancel;
|
||||
__read_nocancel;
|
||||
__pread64_nocancel;
|
||||
__close_nocancel;
|
||||
__sigtimedwait;
|
||||
# functions used by nscd
|
||||
|
@ -43,6 +43,9 @@ __typeof (openat64) __openat64_nocancel;
|
||||
/* Non cancellable read syscall. */
|
||||
__typeof (__read) __read_nocancel;
|
||||
|
||||
/* Non cancellable pread syscall (LFS version). */
|
||||
__typeof (__pread64) __pread64_nocancel;
|
||||
|
||||
/* Uncancelable write. */
|
||||
__typeof (__write) __write_nocancel;
|
||||
|
||||
@ -84,6 +87,7 @@ hidden_proto (__open64_nocancel)
|
||||
hidden_proto (__openat_nocancel)
|
||||
hidden_proto (__openat64_nocancel)
|
||||
hidden_proto (__read_nocancel)
|
||||
hidden_proto (__pread64_nocancel)
|
||||
hidden_proto (__write_nocancel)
|
||||
hidden_proto (__close_nocancel)
|
||||
hidden_proto (__waitpid_nocancel)
|
||||
|
32
sysdeps/unix/sysv/linux/pread64_nocancel.c
Normal file
32
sysdeps/unix/sysv/linux/pread64_nocancel.c
Normal file
@ -0,0 +1,32 @@
|
||||
/* Linux pread64() syscall implementation -- non-cancellable.
|
||||
Copyright (C) 2019 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
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sysdep-cancel.h>
|
||||
#include <not-cancel.h>
|
||||
|
||||
#ifndef __NR_pread64
|
||||
# define __NR_pread64 __NR_pread
|
||||
#endif
|
||||
|
||||
ssize_t
|
||||
__pread64_nocancel (int fd, void *buf, size_t count, off64_t offset)
|
||||
{
|
||||
return INLINE_SYSCALL_CALL (pread64, fd, buf, count, SYSCALL_LL64_PRW (offset));
|
||||
}
|
||||
hidden_def (__pread64_nocancel)
|
@ -61,7 +61,8 @@ struct utmp
|
||||
pid_t ut_pid; /* Process ID of login process. */
|
||||
char ut_line[UT_LINESIZE]
|
||||
__attribute_nonstring__; /* Devicename. */
|
||||
char ut_id[4]; /* Inittab ID. */
|
||||
char ut_id[4]
|
||||
__attribute_nonstring__; /* Inittab ID. */
|
||||
char ut_user[UT_NAMESIZE]
|
||||
__attribute_nonstring__; /* Username. */
|
||||
char ut_host[UT_HOSTSIZE]
|
||||
|
@ -56,10 +56,14 @@ struct utmpx
|
||||
{
|
||||
short int ut_type; /* Type of login. */
|
||||
__pid_t ut_pid; /* Process ID of login process. */
|
||||
char ut_line[__UT_LINESIZE]; /* Devicename. */
|
||||
char ut_id[4]; /* Inittab ID. */
|
||||
char ut_user[__UT_NAMESIZE]; /* Username. */
|
||||
char ut_host[__UT_HOSTSIZE]; /* Hostname for remote login. */
|
||||
char ut_line[__UT_LINESIZE]
|
||||
__attribute_nonstring__; /* Devicename. */
|
||||
char ut_id[4]
|
||||
__attribute_nonstring__; /* Inittab ID. */
|
||||
char ut_user[__UT_NAMESIZE]
|
||||
__attribute_nonstring__; /* Username. */
|
||||
char ut_host[__UT_HOSTSIZE]
|
||||
__attribute_nonstring__; /* Hostname for remote login. */
|
||||
struct __exit_status ut_exit; /* Exit status of a process marked
|
||||
as DEAD_PROCESS. */
|
||||
|
||||
|
@ -160,8 +160,9 @@ do_test (void)
|
||||
fails |= test_wrp (EINVAL, poll, &pollfd, -1, 0);
|
||||
/* quotactl returns ENOSYS for kernels not configured with
|
||||
CONFIG_QUOTA, and may return EPERM if called within certain types
|
||||
of containers. */
|
||||
fails |= test_wrp2 (LIST (ENODEV, ENOSYS, EPERM),
|
||||
of containers. Linux 5.4 added additional argument validation
|
||||
and can return EINVAL. */
|
||||
fails |= test_wrp2 (LIST (ENODEV, ENOSYS, EPERM, EINVAL),
|
||||
quotactl, Q_GETINFO, NULL, -1, (caddr_t) &dqblk);
|
||||
fails |= test_wrp (EINVAL, sched_getparam, -1, &sch_param);
|
||||
fails |= test_wrp (EINVAL, sched_getscheduler, -1);
|
||||
|
Loading…
Reference in New Issue
Block a user