Allow separate printing of struct user_desc.entry_number

Kernel reads only entry_number field in the beginning of the
get_thread_area syscall handler.  Let's replicate this behaviour.

* defs.h (enum user_desc_print_filter): New enumeration.
(print_user_desc): Add an argument for signalling which part of the
structure should be printed.
* clone.c (print_tls_arg): Update print_user_desc call.
* ldt.c (print_user_desc): Add filter argument.  Print entry_number on
entering and the rest on exiting. Store entering value of the
entry_number field in order to print the updated value in the impossible
case of changed entry_number value.
(SYS_FUNC(modify_ldt), SYS_FUNC(set_thread_area)): Update
print_user_desc call.
(SYS_FUNC(get_thread_area)): Call print_user_desc with
USER_DESC_ENTERING format argument on entering and with
USER_DESC_EXITING on exiting.
This commit is contained in:
Eugene Syromyatnikov 2018-01-08 18:41:30 +01:00 committed by Dmitry V. Levin
parent 1e23e9aab8
commit 0c7e458044
3 changed files with 100 additions and 22 deletions

View File

@ -84,7 +84,7 @@ print_tls_arg(struct tcb *const tcp, const kernel_ulong_t addr)
if (current_personality == 1)
# endif
{
print_user_desc(tcp, tcp->u_arg[ARG_TLS]);
print_user_desc(tcp, tcp->u_arg[ARG_TLS], USER_DESC_BOTH);
}
# if SUPPORTED_PERSONALITIES > 1
else

16
defs.h
View File

@ -768,7 +768,21 @@ extern void print_itimerval32(struct tcb *, kernel_ulong_t addr);
#endif
#ifdef HAVE_STRUCT_USER_DESC
extern void print_user_desc(struct tcb *, kernel_ulong_t addr);
/**
* Filter what to print from the point of view of the get_thread_area syscall.
* Kernel copies only entry_number field at first and then tries to write the
* whole structure.
*/
enum user_desc_print_filter {
/* Print the "entering" part of struct user_desc - entry_number. */
USER_DESC_ENTERING = 1,
/* Print the "exiting" part of the structure. */
USER_DESC_EXITING = 2,
USER_DESC_BOTH = USER_DESC_ENTERING | USER_DESC_EXITING,
};
extern void print_user_desc(struct tcb *, kernel_ulong_t addr,
enum user_desc_print_filter filter);
#endif
/* Strace log generation machinery.

104
ldt.c
View File

@ -42,30 +42,94 @@
# include "xstring.h"
void
print_user_desc(struct tcb *const tcp, const kernel_ulong_t addr)
print_user_desc(struct tcb *const tcp, const kernel_ulong_t addr,
enum user_desc_print_filter filter)
{
struct user_desc desc;
unsigned *entry_number = get_tcb_priv_data(tcp);
if (umove_or_printaddr(tcp, addr, &desc))
return;
switch (filter) {
case USER_DESC_ENTERING:
if (umove_or_printaddr(tcp, addr, &desc.entry_number))
return;
PRINT_FIELD_ID("{", desc, entry_number);
PRINT_FIELD_0X(", ", desc, base_addr);
PRINT_FIELD_0X(", ", desc, limit);
PRINT_FIELD_U_CAST(", ", desc, seg_32bit, unsigned int);
PRINT_FIELD_U_CAST(", ", desc, contents, unsigned int);
PRINT_FIELD_U_CAST(", ", desc, read_exec_only, unsigned int);
PRINT_FIELD_U_CAST(", ", desc, limit_in_pages, unsigned int);
PRINT_FIELD_U_CAST(", ", desc, seg_not_present, unsigned int);
PRINT_FIELD_U_CAST(", ", desc, useable, unsigned int);
break;
case USER_DESC_EXITING:
if (!addr || !verbose(tcp))
return;
if (syserror(tcp) || umove(tcp, addr, &desc)) {
if (entry_number)
tprints(", ...}");
return;
}
break;
case USER_DESC_BOTH:
if (umove_or_printaddr(tcp, addr, &desc))
return;
break;
}
if (filter & USER_DESC_ENTERING) {
PRINT_FIELD_ID("{", desc, entry_number);
/*
* If we don't print the whole structure now, let's save it for
* later.
*/
if (filter == USER_DESC_ENTERING) {
entry_number = xmalloc(sizeof(*entry_number));
*entry_number = desc.entry_number;
set_tcb_priv_data(tcp, entry_number, free);
}
}
if (filter & USER_DESC_EXITING) {
/*
* It should be the same in case of get_thread_area, but we can
* never be sure...
*/
if (filter == USER_DESC_EXITING) {
if (entry_number) {
if (*entry_number != desc.entry_number) {
if ((int) desc.entry_number == -1)
tprints(" => -1");
else
tprintf(" => %u",
desc.entry_number);
}
} else {
/*
* This is really strange. If we are here, it
* means that we failed on entering but somehow
* succeeded on exiting.
*/
PRINT_FIELD_ID(" => {", desc, entry_number);
}
}
PRINT_FIELD_0X(", ", desc, base_addr);
PRINT_FIELD_0X(", ", desc, limit);
PRINT_FIELD_U_CAST(", ", desc, seg_32bit, unsigned int);
PRINT_FIELD_U_CAST(", ", desc, contents, unsigned int);
PRINT_FIELD_U_CAST(", ", desc, read_exec_only, unsigned int);
PRINT_FIELD_U_CAST(", ", desc, limit_in_pages, unsigned int);
PRINT_FIELD_U_CAST(", ", desc, seg_not_present, unsigned int);
PRINT_FIELD_U_CAST(", ", desc, useable, unsigned int);
# ifdef HAVE_STRUCT_USER_DESC_LM
/* lm is totally ignored for 32-bit processes */
if (current_klongsize == 8)
PRINT_FIELD_U_CAST(", ", desc, lm, unsigned int);
/* lm is totally ignored for 32-bit processes */
if (current_klongsize == 8)
PRINT_FIELD_U_CAST(", ", desc, lm, unsigned int);
# endif /* HAVE_STRUCT_USER_DESC_LM */
tprints("}");
tprints("}");
}
}
SYS_FUNC(modify_ldt)
@ -75,7 +139,7 @@ SYS_FUNC(modify_ldt)
if (tcp->u_arg[2] != sizeof(struct user_desc))
printaddr(tcp->u_arg[1]);
else
print_user_desc(tcp, tcp->u_arg[1]);
print_user_desc(tcp, tcp->u_arg[1], USER_DESC_BOTH);
tprintf(", %" PRI_klu, tcp->u_arg[2]);
return 0;
@ -97,7 +161,7 @@ SYS_FUNC(modify_ldt)
SYS_FUNC(set_thread_area)
{
if (entering(tcp)) {
print_user_desc(tcp, tcp->u_arg[0]);
print_user_desc(tcp, tcp->u_arg[0], USER_DESC_BOTH);
} else {
struct user_desc desc;
@ -117,8 +181,8 @@ SYS_FUNC(set_thread_area)
SYS_FUNC(get_thread_area)
{
if (exiting(tcp))
print_user_desc(tcp, tcp->u_arg[0]);
print_user_desc(tcp, tcp->u_arg[0],
entering(tcp) ? USER_DESC_ENTERING : USER_DESC_EXITING);
return 0;
}