[PATCH v2] Append time zone to output of date and time
by HAGIO KAZUHITO(萩尾 一仁)
Currently it's not easy to distinguish which time zone the output of
DATE uses:
crash> sys | grep DATE
DATE: Thu Nov 29 06:44:02 2018
Let's introduce ctime_tz() function like ctime() but explicitly appends
the time zone to its result string.
DATE: Thu Nov 29 06:44:02 JST 2018
Resolves: https://github.com/crash-utility/crash/issues/62
Suggested-by: Jacob Wen <jian.w.wen(a)oracle.com>
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
v1 -> v2
- Add comment about the fallbacks in ctime_tz()
- Add NULL check on timep
defs.h | 1 +
help.c | 3 +--
kernel.c | 16 ++++++----------
tools.c | 32 ++++++++++++++++++++++++++++++++
4 files changed, 40 insertions(+), 12 deletions(-)
diff --git a/defs.h b/defs.h
index 17e98763362b..e7dec7c672a6 100644
--- a/defs.h
+++ b/defs.h
@@ -5096,6 +5096,7 @@ char *strdupbuf(char *);
void sigsetup(int, void *, struct sigaction *, struct sigaction *);
#define SIGACTION(s, h, a, o) sigsetup(s, h, a, o)
char *convert_time(ulonglong, char *);
+char *ctime_tz(time_t *);
void stall(ulong);
char *pages_to_size(ulong, char *);
int clean_arg(void);
diff --git a/help.c b/help.c
index b707cfa58826..d3427a36829f 100644
--- a/help.c
+++ b/help.c
@@ -9299,8 +9299,7 @@ display_README(void)
fprintf(fp, " GNU gdb %s\n", pc->gdb_version);
} else if (STREQ(README[i], README_DATE)) {
time(&time_now);
- fprintf(fp, " DATE: %s\n",
- strip_linefeeds(ctime(&time_now)));
+ fprintf(fp, " DATE: %s\n", ctime_tz(&time_now));
} else if (STREQ(README[i], README_HELP_MENU)) {
display_help_screen(" ");
} else if (STREQ(README[i], README_GPL_INFO)) {
diff --git a/kernel.c b/kernel.c
index f179375f2d3d..92bfe6329900 100644
--- a/kernel.c
+++ b/kernel.c
@@ -225,10 +225,9 @@ kernel_init()
get_xtime(&kt->date);
if (CRASHDEBUG(1))
fprintf(fp, "xtime timespec.tv_sec: %lx: %s\n",
- kt->date.tv_sec, strip_linefeeds(ctime(&kt->date.tv_sec)));
+ kt->date.tv_sec, ctime_tz(&kt->date.tv_sec));
if (kt->flags2 & GET_TIMESTAMP) {
- fprintf(fp, "%s\n\n",
- strip_linefeeds(ctime(&kt->date.tv_sec)));
+ fprintf(fp, "%s\n\n", ctime_tz(&kt->date.tv_sec));
clean_exit(0);
}
@@ -5178,7 +5177,7 @@ dump_log_entry(char *logptr, int msg_flags)
rem = (ulonglong)ts_nsec % (ulonglong)1000000000;
if (msg_flags & SHOW_LOG_CTIME) {
time_t t = kt->boot_date.tv_sec + nanos;
- sprintf(buf, "[%s] ", strip_linefeeds(ctime(&t)));
+ sprintf(buf, "[%s] ", ctime_tz(&t));
}
else
sprintf(buf, "[%5lld.%06ld] ", nanos, rem/1000);
@@ -5553,8 +5552,7 @@ display_sys_stats(void)
if (ACTIVE())
get_xtime(&kt->date);
- fprintf(fp, " DATE: %s\n",
- strip_linefeeds(ctime(&kt->date.tv_sec)));
+ fprintf(fp, " DATE: %s\n", ctime_tz(&kt->date.tv_sec));
fprintf(fp, " UPTIME: %s\n", get_uptime(buf, NULL));
fprintf(fp, "LOAD AVERAGE: %s\n", get_loadavg(buf));
fprintf(fp, " TASKS: %ld\n", RUNNING_TASKS());
@@ -6043,10 +6041,8 @@ dump_kernel_table(int verbose)
kt->source_tree : "(not used)");
if (!(pc->flags & KERNEL_DEBUG_QUERY) && ACTIVE())
get_xtime(&kt->date);
- fprintf(fp, " date: %s\n",
- strip_linefeeds(ctime(&kt->date.tv_sec)));
- fprintf(fp, " boot_ date: %s\n",
- strip_linefeeds(ctime(&kt->boot_date.tv_sec)));
+ fprintf(fp, " date: %s\n", ctime_tz(&kt->date.tv_sec));
+ fprintf(fp, " boot_date: %s\n", ctime_tz(&kt->boot_date.tv_sec));
fprintf(fp, " proc_version: %s\n", strip_linefeeds(kt->proc_version));
fprintf(fp, " new_utsname: \n");
fprintf(fp, " .sysname: %s\n", uts->sysname);
diff --git a/tools.c b/tools.c
index 85c81668e40e..89352b1dc5f5 100644
--- a/tools.c
+++ b/tools.c
@@ -6318,6 +6318,38 @@ convert_time(ulonglong count, char *buf)
}
/*
+ * Convert a calendar time into a null-terminated string like ctime(), but
+ * the result string contains the time zone string and does not ends with a
+ * linefeed ('\n'). If localtime() or strftime() fails, fail back to return
+ * POSIX time (seconds since the Epoch) or ctime() string respectively.
+ *
+ * NOTE: The return value points to a statically allocated string which is
+ * overwritten by subsequent calls.
+ */
+char *
+ctime_tz(time_t *timep)
+{
+ static char buf[64];
+ struct tm *tm;
+ size_t size;
+
+ if (!timep)
+ return NULL;
+
+ tm = localtime(timep);
+ if (!tm) {
+ snprintf(buf, sizeof(buf), "%ld", *timep);
+ return buf;
+ }
+
+ size = strftime(buf, sizeof(buf), "%a %b %e %T %Z %Y", tm);
+ if (!size)
+ return strip_linefeeds(ctime(timep));
+
+ return buf;
+}
+
+/*
* Stall for a number of microseconds.
*/
void
--
1.8.3.1
4 years, 2 months
[PATCH] Fix "kmem -i" option on Linux 5.9-rc1 and later kernels
by HAGIO KAZUHITO(萩尾 一仁)
On kernels that contain commit 1008fe6dc36d ("block: remove the all_bdevs
list"), without the patch, the "kmem -i" option fails halfway with the
error message 'kmem: cannot resolve: "all_bdevs"'.
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
# sorry, resending this because I sent with inappropriate setting..
defs.h | 2 ++
memory.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
symbols.c | 4 ++++
3 files changed, 64 insertions(+)
diff --git a/defs.h b/defs.h
index 17e98763362b..dfc09bc86618 100644
--- a/defs.h
+++ b/defs.h
@@ -2089,6 +2089,8 @@ struct offset_table { /* stash of commonly-used offsets */
long size_class_size;
long gendisk_private_data;
long zram_table_entry;
+ long super_block_s_inodes;
+ long inode_i_sb_list;
};
struct size_table { /* stash of commonly-used sizes */
diff --git a/memory.c b/memory.c
index 2bea1288251a..c951827162cb 100644
--- a/memory.c
+++ b/memory.c
@@ -252,6 +252,7 @@ static ulonglong get_vm_flags(char *);
static void PG_reserved_flag_init(void);
static void PG_slab_flag_init(void);
static ulong nr_blockdev_pages(void);
+static ulong nr_blockdev_pages_v2(void);
void sparse_mem_init(void);
void dump_mem_sections(int);
void dump_memory_blocks(int);
@@ -501,6 +502,9 @@ vm_init(void)
if (INVALID_MEMBER(address_space_nrpages))
MEMBER_OFFSET_INIT(address_space_nrpages, "address_space", "__nrpages");
+ MEMBER_OFFSET_INIT(super_block_s_inodes, "super_block", "s_inodes");
+ MEMBER_OFFSET_INIT(inode_i_sb_list, "inode", "i_sb_list");
+
MEMBER_OFFSET_INIT(gendisk_major, "gendisk", "major");
MEMBER_OFFSET_INIT(gendisk_fops, "gendisk", "fops");
MEMBER_OFFSET_INIT(gendisk_disk_name, "gendisk", "disk_name");
@@ -8608,6 +8612,9 @@ nr_blockdev_pages(void)
ulong nrpages;
char *block_device_buf, *inode_buf, *address_space_buf;
+ if (!kernel_symbol_exists("all_bdevs"))
+ return nr_blockdev_pages_v2();
+
ld = &list_data;
BZERO(ld, sizeof(struct list_data));
get_symbol_data("all_bdevs", sizeof(void *), &ld->start);
@@ -8652,6 +8659,57 @@ nr_blockdev_pages(void)
}
/*
+ * Emulate 5.9 nr_blockdev_pages() function.
+ */
+static ulong
+nr_blockdev_pages_v2(void)
+{
+ struct list_data list_data, *ld;
+ ulong bd_sb, address_space;
+ ulong nrpages;
+ int i, inode_count;
+ char *inode_buf, *address_space_buf;
+
+ ld = &list_data;
+ BZERO(ld, sizeof(struct list_data));
+
+ get_symbol_data("blockdev_superblock", sizeof(void *), &bd_sb);
+ readmem(bd_sb + OFFSET(super_block_s_inodes), KVADDR, &ld->start,
+ sizeof(ulong), "blockdev_superblock.s_inodes", FAULT_ON_ERROR);
+
+ if (empty_list(ld->start))
+ return 0;
+ ld->flags |= LIST_ALLOCATE;
+ ld->end = bd_sb + OFFSET(super_block_s_inodes);
+ ld->list_head_offset = OFFSET(inode_i_sb_list);
+
+ inode_buf = GETBUF(SIZE(inode));
+ address_space_buf = GETBUF(SIZE(address_space));
+
+ inode_count = do_list(ld);
+
+ /*
+ * go through the s_inodes list, emulating:
+ *
+ * ret += inode->i_mapping->nrpages;
+ */
+ for (i = nrpages = 0; i < inode_count; i++) {
+ readmem(ld->list_ptr[i], KVADDR, inode_buf, SIZE(inode), "inode buffer",
+ FAULT_ON_ERROR);
+ address_space = ULONG(inode_buf + OFFSET(inode_i_mapping));
+ readmem(address_space, KVADDR, address_space_buf, SIZE(address_space),
+ "address_space buffer", FAULT_ON_ERROR);
+ nrpages += ULONG(address_space_buf + OFFSET(address_space_nrpages));
+ }
+
+ FREEBUF(ld->list_ptr);
+ FREEBUF(inode_buf);
+ FREEBUF(address_space_buf);
+
+ return nrpages;
+}
+
+/*
* dump_vmlist() displays information from the vmlist.
*/
diff --git a/symbols.c b/symbols.c
index 2fecaee093a2..123ed00913e1 100644
--- a/symbols.c
+++ b/symbols.c
@@ -9452,6 +9452,8 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(inode_i_fop));
fprintf(fp, " inode_i_mapping: %ld\n",
OFFSET(inode_i_mapping));
+ fprintf(fp, " inode_i_sb_list: %ld\n",
+ OFFSET(inode_i_sb_list));
fprintf(fp, " vfsmount_mnt_next: %ld\n",
OFFSET(vfsmount_mnt_next));
@@ -9488,6 +9490,8 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(super_block_s_type));
fprintf(fp, " super_block_s_files: %ld\n",
OFFSET(super_block_s_files));
+ fprintf(fp, " super_block_s_inodes: %ld\n",
+ OFFSET(super_block_s_inodes));
fprintf(fp, " nlm_file_f_file: %ld\n",
OFFSET(nlm_file_f_file));
--
1.8.3.1
4 years, 2 months
[PATCH] Fix "irq -a" option on Linux 4.3 or later kernels
by HAGIO KAZUHITO(萩尾 一仁)
On kernels that contain commit 9df872faa7e1 ("genirq: Move field
'affinity' from irq_data into irq_common_data"), without the patch,
the "irq -a" option cannot work with the message "irq: -a option not
supported or applicable on this architecture or kernel".
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
defs.h | 3 +++
kernel.c | 18 +++++++++++++-----
symbols.c | 5 +++++
3 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/defs.h b/defs.h
index 17e98763362b..ad91bfe184fc 100644
--- a/defs.h
+++ b/defs.h
@@ -2089,6 +2089,8 @@ struct offset_table { /* stash of commonly-used offsets */
long size_class_size;
long gendisk_private_data;
long zram_table_entry;
+ long irq_common_data_affinity;
+ long irq_desc_irq_common_data;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2247,6 +2249,7 @@ struct size_table { /* stash of commonly-used sizes */
long xarray;
long xa_node;
long zram_table_entry;
+ long irq_common_data;
};
struct array_table {
diff --git a/kernel.c b/kernel.c
index 5ed602108b87..15f9ab4b8449 100644
--- a/kernel.c
+++ b/kernel.c
@@ -550,6 +550,12 @@ kernel_init()
MEMBER_OFFSET_INIT(irq_desc_irq_data, "irq_desc", "irq_data");
}
+ STRUCT_SIZE_INIT(irq_common_data, "irq_common_data");
+ if (VALID_STRUCT(irq_common_data)) {
+ MEMBER_OFFSET_INIT(irq_common_data_affinity, "irq_common_data", "affinity");
+ MEMBER_OFFSET_INIT(irq_desc_irq_common_data, "irq_desc", "irq_common_data");
+ }
+
STRUCT_SIZE_INIT(irq_cpustat_t, "irq_cpustat_t");
MEMBER_OFFSET_INIT(irq_cpustat_t___softirq_active,
"irq_cpustat_t", "__softirq_active");
@@ -6331,10 +6337,9 @@ cmd_irq(void)
if (!machdep->get_irq_affinity)
option_not_supported(c);
- if (VALID_STRUCT(irq_data)) {
- if (INVALID_MEMBER(irq_data_affinity))
- option_not_supported(c);
- } else if (INVALID_MEMBER(irq_desc_t_affinity))
+ if (INVALID_MEMBER(irq_data_affinity) &&
+ INVALID_MEMBER(irq_common_data_affinity) &&
+ INVALID_MEMBER(irq_desc_t_affinity))
option_not_supported(c);
if ((nr_irqs = machdep->nr_irqs) == 0)
@@ -7096,7 +7101,10 @@ generic_get_irq_affinity(int irq)
len = DIV_ROUND_UP(kt->cpus, BITS_PER_LONG) * sizeof(ulong);
affinity = (ulong *)GETBUF(len);
- if (VALID_STRUCT(irq_data))
+ if (VALID_MEMBER(irq_common_data_affinity))
+ tmp_addr = irq_desc_addr + OFFSET(irq_desc_irq_common_data)
+ + OFFSET(irq_common_data_affinity);
+ else if (VALID_MEMBER(irq_data_affinity))
tmp_addr = irq_desc_addr + \
OFFSET(irq_data_affinity);
else
diff --git a/symbols.c b/symbols.c
index 2fecaee093a2..d18c88f2f3b0 100644
--- a/symbols.c
+++ b/symbols.c
@@ -9310,8 +9310,12 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(irq_data_chip));
fprintf(fp, " irq_data_affinity: %ld\n",
OFFSET(irq_data_affinity));
+ fprintf(fp, " irq_common_data_affinity: %ld\n",
+ OFFSET(irq_common_data_affinity));
fprintf(fp, " irq_desc_irq_data: %ld\n",
OFFSET(irq_desc_irq_data));
+ fprintf(fp, " irq_desc_irq_common_data: %ld\n",
+ OFFSET(irq_desc_irq_common_data));
fprintf(fp, " kernel_stat_irqs: %ld\n",
OFFSET(kernel_stat_irqs));
@@ -10663,6 +10667,7 @@ dump_offset_table(char *spec, ulong makestruct)
fprintf(fp, " runqueue: %ld\n", SIZE(runqueue));
fprintf(fp, " irq_desc_t: %ld\n", SIZE(irq_desc_t));
fprintf(fp, " irq_data: %ld\n", SIZE(irq_data));
+ fprintf(fp, " irq_common_data: %ld\n", SIZE(irq_common_data));
fprintf(fp, " task_union: %ld\n", SIZE(task_union));
fprintf(fp, " thread_union: %ld\n", SIZE(thread_union));
fprintf(fp, " prio_array: %ld\n", SIZE(prio_array));
--
1.8.3.1
4 years, 2 months
[PATCH v3] Basic support for PaX's split module layout
by Mathias Krause
PaX and grsecurity kernels split module memory into dedicated r/x and
r/w mappings using '*_rw' and '*_rx' named member variables in 'struct
module'. To add basic support for such kernels detect the split layout
by testing for the corresponding structure members and use these
instead.
So far we limit ourself to only track module code mappings for such
kernels as adding support for separate data mappings violates lots of
invariants in the rest of our code base, thereby would require a major
rework. However, with that patch applied, module code references can be
resolved in backtraces, memory and code dumps, which makes it already
very useful for analyzing such kernels.
Signed-off-by: Mathias Krause <minipli(a)grsecurity.net>
---
v3:
- dump offsets unconditional
- fix indention of 'module_init_size' offset dump
v2:
- add members to end of struct offset_table
- add offsets to dump_offset_table()
defs.h | 13 +++++++++++
kernel.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++----
symbols.c | 38 ++++++++++++++++++++++---------
3 files changed, 103 insertions(+), 16 deletions(-)
diff --git a/defs.h b/defs.h
index 17e98763362b..ae860448ab15 100644
--- a/defs.h
+++ b/defs.h
@@ -654,12 +654,15 @@ struct new_utsname {
#define TIMER_BASES (0x20ULL)
#define IRQ_DESC_TREE_RADIX (0x40ULL)
#define IRQ_DESC_TREE_XARRAY (0x80ULL)
+#define KMOD_PAX (0x100ULL)
#define XEN() (kt->flags & ARCH_XEN)
#define OPENVZ() (kt->flags & ARCH_OPENVZ)
#define PVOPS() (kt->flags & ARCH_PVOPS)
#define PVOPS_XEN() (kt->flags & ARCH_PVOPS_XEN)
+#define PAX_MODULE_SPLIT() (kt->flags2 & KMOD_PAX)
+
#define XEN_MACHINE_TO_MFN(m) ((ulonglong)(m) >> PAGESHIFT())
#define XEN_PFN_TO_PSEUDO(p) ((ulonglong)(p) << PAGESHIFT())
@@ -2089,6 +2092,14 @@ struct offset_table { /* stash of commonly-used offsets */
long size_class_size;
long gendisk_private_data;
long zram_table_entry;
+ long module_core_size_rw;
+ long module_core_size_rx;
+ long module_init_size_rw;
+ long module_init_size_rx;
+ long module_module_core_rw;
+ long module_module_core_rx;
+ long module_module_init_rw;
+ long module_module_init_rx;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2313,6 +2324,8 @@ struct array_table {
* in the offset table, size table or array_table.
*/
#define OFFSET(X) (OFFSET_verify(offset_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X))
+#define MODULE_OFFSET(X,Y) (PAX_MODULE_SPLIT() ? OFFSET(Y) : OFFSET(X))
+#define MODULE_OFFSET2(X,T) MODULE_OFFSET(X, X##_##T)
#define SIZE(X) (SIZE_verify(size_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X))
#define INVALID_OFFSET (-1)
#define INVALID_MEMBER(X) (offset_table.X == INVALID_OFFSET)
diff --git a/kernel.c b/kernel.c
index f179375f2d3d..f0268adccd4a 100644
--- a/kernel.c
+++ b/kernel.c
@@ -3540,6 +3540,62 @@ module_init(void)
"module_core");
MEMBER_OFFSET_INIT(module_module_init, "module",
"module_init");
+ } else if (MEMBER_EXISTS("module", "module_core_rx")) {
+ if (CRASHDEBUG(1))
+ error(INFO, "PaX module layout detected.\n");
+ kt->flags2 |= KMOD_PAX;
+
+ MEMBER_OFFSET_INIT(module_core_size_rw, "module",
+ "core_size_rw");
+ MEMBER_OFFSET_INIT(module_core_size_rx, "module",
+ "core_size_rx");
+
+ MEMBER_OFFSET_INIT(module_init_size_rw, "module",
+ "init_size_rw");
+ MEMBER_OFFSET_INIT(module_init_size_rx, "module",
+ "init_size_rx");
+
+ MEMBER_OFFSET_INIT(module_module_core_rw, "module",
+ "module_core_rw");
+ MEMBER_OFFSET_INIT(module_module_core_rx, "module",
+ "module_core_rx");
+
+ MEMBER_OFFSET_INIT(module_module_init_rw, "module",
+ "module_init_rw");
+ MEMBER_OFFSET_INIT(module_module_init_rx, "module",
+ "module_init_rx");
+ } else if (MEMBER_EXISTS("module_layout", "base_rx")) {
+ if (CRASHDEBUG(1))
+ error(INFO, "PaX module layout detected.\n");
+ kt->flags2 |= KMOD_PAX;
+
+ ASSIGN_OFFSET(module_core_size_rw) =
+ MEMBER_OFFSET("module", "core_layout") +
+ MEMBER_OFFSET("module_layout", "size_rw");
+ ASSIGN_OFFSET(module_core_size_rx) =
+ MEMBER_OFFSET("module", "core_layout") +
+ MEMBER_OFFSET("module_layout", "size_rx");
+
+ ASSIGN_OFFSET(module_init_size_rw) =
+ MEMBER_OFFSET("module", "init_layout") +
+ MEMBER_OFFSET("module_layout", "size_rw");
+ ASSIGN_OFFSET(module_init_size_rx) =
+ MEMBER_OFFSET("module", "init_layout") +
+ MEMBER_OFFSET("module_layout", "size_rx");
+
+ ASSIGN_OFFSET(module_module_core_rw) =
+ MEMBER_OFFSET("module", "core_layout") +
+ MEMBER_OFFSET("module_layout", "base_rw");
+ ASSIGN_OFFSET(module_module_core_rx) =
+ MEMBER_OFFSET("module", "core_layout") +
+ MEMBER_OFFSET("module_layout", "base_rx");
+
+ ASSIGN_OFFSET(module_module_init_rw) =
+ MEMBER_OFFSET("module", "init_layout") +
+ MEMBER_OFFSET("module_layout", "base_rw");
+ ASSIGN_OFFSET(module_module_init_rx) =
+ MEMBER_OFFSET("module", "init_layout") +
+ MEMBER_OFFSET("module_layout", "base_rx");
} else {
ASSIGN_OFFSET(module_core_size) =
MEMBER_OFFSET("module", "core_layout") +
@@ -3682,10 +3738,10 @@ module_init(void)
case KALLSYMS_V2:
if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) {
numksyms = UINT(modbuf + OFFSET(module_num_symtab));
- size = UINT(modbuf + OFFSET(module_core_size));
+ size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx));
} else {
numksyms = ULONG(modbuf + OFFSET(module_num_symtab));
- size = ULONG(modbuf + OFFSET(module_core_size));
+ size = ULONG(modbuf + MODULE_OFFSET2(module_core_size, rx));
}
if (!size) {
@@ -3792,7 +3848,7 @@ verify_modules(void)
break;
case KMOD_V2:
mod_base = ULONG(modbuf +
- OFFSET(module_module_core));
+ MODULE_OFFSET2(module_module_core, rx));
break;
}
@@ -3816,10 +3872,10 @@ verify_modules(void)
OFFSET(module_name);
if (THIS_KERNEL_VERSION >= LINUX(2,6,27))
mod_size = UINT(modbuf +
- OFFSET(module_core_size));
+ MODULE_OFFSET2(module_core_size, rx));
else
mod_size = ULONG(modbuf +
- OFFSET(module_core_size));
+ MODULE_OFFSET2(module_core_size, rx));
if (strlen(module_name) < MAX_MOD_NAME)
strcpy(buf, module_name);
else
@@ -5997,6 +6053,8 @@ dump_kernel_table(int verbose)
fprintf(fp, "%sIRQ_DESC_TREE_RADIX", others++ ? "|" : "");
if (kt->flags2 & IRQ_DESC_TREE_XARRAY)
fprintf(fp, "%sIRQ_DESC_TREE_XARRAY", others++ ? "|" : "");
+ if (kt->flags2 & KMOD_PAX)
+ fprintf(fp, "%sKMOD_PAX", others++ ? "|" : "");
fprintf(fp, ")\n");
fprintf(fp, " stext: %lx\n", kt->stext);
diff --git a/symbols.c b/symbols.c
index 2fecaee093a2..311fdb7df29e 100644
--- a/symbols.c
+++ b/symbols.c
@@ -1766,17 +1766,17 @@ store_module_symbols_v2(ulong total, int mods_installed)
if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) {
nksyms = UINT(modbuf + OFFSET(module_num_symtab));
- size = UINT(modbuf + OFFSET(module_core_size));
+ size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx));
} else {
nksyms = ULONG(modbuf + OFFSET(module_num_symtab));
- size = ULONG(modbuf + OFFSET(module_core_size));
+ size = ULONG(modbuf + MODULE_OFFSET2(module_core_size, rx));
}
mod_name = modbuf + OFFSET(module_name);
lm = &st->load_modules[m++];
BZERO(lm, sizeof(struct load_module));
- lm->mod_base = ULONG(modbuf + OFFSET(module_module_core));
+ lm->mod_base = ULONG(modbuf + MODULE_OFFSET2(module_module_core, rx));
lm->module_struct = mod;
lm->mod_size = size;
if (strlen(mod_name) < MAX_MOD_NAME)
@@ -1795,23 +1795,23 @@ store_module_symbols_v2(ulong total, int mods_installed)
lm->mod_flags = MOD_EXT_SYMS;
lm->mod_ext_symcnt = mcnt;
lm->mod_init_module_ptr = ULONG(modbuf +
- OFFSET(module_module_init));
+ MODULE_OFFSET2(module_module_init, rx));
if (VALID_MEMBER(module_percpu))
lm->mod_percpu = ULONG(modbuf + OFFSET(module_percpu));
if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) {
lm->mod_etext_guess = lm->mod_base +
- UINT(modbuf + OFFSET(module_core_text_size));
+ UINT(modbuf + MODULE_OFFSET(module_core_text_size, module_core_size_rx));
lm->mod_init_size =
- UINT(modbuf + OFFSET(module_init_size));
+ UINT(modbuf + MODULE_OFFSET2(module_init_size, rx));
lm->mod_init_text_size =
- UINT(modbuf + OFFSET(module_init_text_size));
+ UINT(modbuf + MODULE_OFFSET(module_init_text_size, module_init_size_rx));
} else {
lm->mod_etext_guess = lm->mod_base +
- ULONG(modbuf + OFFSET(module_core_text_size));
+ ULONG(modbuf + MODULE_OFFSET(module_core_text_size, module_core_size_rx));
lm->mod_init_size =
- ULONG(modbuf + OFFSET(module_init_size));
+ ULONG(modbuf + MODULE_OFFSET2(module_init_size, rx));
lm->mod_init_text_size =
- ULONG(modbuf + OFFSET(module_init_text_size));
+ ULONG(modbuf + MODULE_OFFSET(module_init_text_size, module_init_size_rx));
}
lm->mod_text_start = lm->mod_base;
@@ -9119,12 +9119,28 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(module_core_size));
fprintf(fp, " module_core_text_size: %ld\n",
OFFSET(module_core_text_size));
- fprintf(fp, " module_init_size: %ld\n",
+ fprintf(fp, " module_init_size: %ld\n",
OFFSET(module_init_size));
fprintf(fp, " module_init_text_size: %ld\n",
OFFSET(module_init_text_size));
fprintf(fp, " module_module_init: %ld\n",
OFFSET(module_module_init));
+ fprintf(fp, " module_module_core_rx: %ld\n",
+ OFFSET(module_module_core_rx));
+ fprintf(fp, " module_module_core_rw: %ld\n",
+ OFFSET(module_module_core_rw));
+ fprintf(fp, " module_core_size_rx: %ld\n",
+ OFFSET(module_core_size_rx));
+ fprintf(fp, " module_core_size_rw: %ld\n",
+ OFFSET(module_core_size_rw));
+ fprintf(fp, " module_module_init_rx: %ld\n",
+ OFFSET(module_module_init_rx));
+ fprintf(fp, " module_module_init_rw: %ld\n",
+ OFFSET(module_module_init_rw));
+ fprintf(fp, " module_init_size_rx: %ld\n",
+ OFFSET(module_init_size_rx));
+ fprintf(fp, " module_init_size_rw: %ld\n",
+ OFFSET(module_init_size_rw));
fprintf(fp, " module_num_symtab: %ld\n",
OFFSET(module_num_symtab));
fprintf(fp, " module_symtab: %ld\n",
--
2.20.1
4 years, 2 months
[PATCH] x86_64_exception_frame only performs EFRAME_VERIFY if it is the only flag
by David Mair
Calls to x86_64_exception_frame() with combined items set in the flags
argument that include EFRAME_VERIFY do not have the EFRAME_VERIFY
operation performed. I have some cores where multiple cases of
attempting to read a not-present pt_regs end a single PID backtrace with
a failure. One instance has the pt_regs read overrunning stacktop
because the pt_regs is not present and the level's stack position is
closer to stacktop than the size of a pt_regs. That results in a
backtrace failing before complete with a "seek error" at the start of
page after stacktop:
crash> bt 7456
PID: 7456 TASK: ffff933fdb960000 CPU: 0 COMMAND: "sh"
#0 [fffffe0000009e58] crash_nmi_callback at ffffffff93260e93
...
#9 [ffffaea5c0003f80] hrtimer_interrupt at ffffffff933313d5
bt: seek error: kernel virtual address: ffffaea5c0004000 type: "pt_regs"
crash>
The correct backtrace would reach level #12 with no seek error.
The condition to perform the EFRAME_VERIFY operation tests if the flags
value equals EFRAME_VERIFY, not if the value includes EFRAME_VERIFY. The
call to x86_64_exception_frame() in x86_64_print_stack_entry() performed
when eframe_check >= 0 supplies a flags value of EFRAME_PRINT |
EFRAME_VERIFY.
In the bt example above backtrace reaches level #9, 128 bytes from the
top of the current stack's pages in an IRQ stack and with a function
name ending in "_interrupt". This leads to x86_64_print_stack_entry()
setting eframe_check to zero and x86_64_exception_frame() being called
with flags EFRAME_PRINT | EFRAME_VERIFY. x86_64_exception_frame()
doesn't perform the verify because flags is not just EFRAME_VERIFY. An
attempt is made to read 168 bytes (SIZE(pt_regs) - 8 bytes) from a
position 128 bytes from the top of the stack. The stack in question is
followed by a not-present page and the read fails attempting to read
from the page following stacktop.
Signed-off-by: David Mair <dmair(a)suse.com>
---
diff --git a/x86_64.c b/x86_64.c
index fc05e8a..cc870e0 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -4418,7 +4418,7 @@ x86_64_exception_frame(ulong flags, ulong kvaddr,
char *local,
long err;
char buf[BUFSIZE];
- if (flags == EFRAME_VERIFY) {
+ if (flags & EFRAME_VERIFY) {
if (!accessible(kvaddr) ||
!accessible(kvaddr + SIZE(pt_regs) - sizeof(long)))
return FALSE;
4 years, 2 months
Extensions ABI compatibility
by Mathias Krause
Hi list,
during development of the PaX module patch[1], Lianbo pointed out an
issue about adding new members to struct offset_table. They should be
added to the end to ensure binary compatibility with already compiled
extensions, as these won't be aware of the new members and, even worse,
might be using wrong offsets within the offset_table if we didn't. As
this seems to be rather fragile, here's a proposal to make it less so.
To not blindly make already compiled extensions misbehave by using the
wrong offsets when new members get added in the middle of shared types,
we need to have some validation step, preferably during extension
registration to catch these.
If we want to keep binary compatibility, we need to add members to the
end. That's a rule maintainers can enforce but as we all make mistakes,
code can help us here. Changing a shared data structure has, at least,
implications on its size. So we can use this as a base to build checks
on. If the size of a data structure used during compilation of an
extension differs from the size of that same data structure as seen
within 'crash', we have an ABI issue. The response should be, at least,
a warning to inform the user to recompile its extension to ensure ABI
compatibility. Another option would be to decline loading the extension
but that might be inconvenient for users, if we indeed made sure to add
members only at the end of the involved data structures.
These checks can be implemented "transparently" as sketched in the
attached patch. It changes register_extension() to be a macro that
stores the sizes of critical types in a data structure that gets passed
to _register_extension() which is implemented in 'crash' and will do the
size checks against its version of the involved types.
The patch also takes care about backward compatibility by providing a
stub register_extension() function that passes a NULL structure, as all
current extension modules refer to register_extension() instead of the
newly introduced _register_extension().
Open TODOs:
1/ Compile a list of all types we want to protect and add checks for
these.
2/ Put these types into a 'shared.h' header file and use that
exclusively within extensions -- maybe even enforce it.
Do we want to follow that approach or look for alternatives?
Regards,
Mathias
[1]: https://www.redhat.com/archives/crash-utility/2020-August/msg00024.html
4 years, 3 months
Suggestion: Testing of crash patches before submissions
by David Wysochanski
Hi all,
Recently I found a regression and also in the past have seen other
regressions. I am not sure what tests are currently run or expected
for patches.
Since this project has transitioned away from the original author, and
there are many contributors, it may be more important to have some
tests in the project, especially for trickier areas, uncommon options,
and unique vmcores. There are also numerous ways to validate patches
in a CI system now. I started building one but then realized it
probably should be done inside the upstream project if possible.
Thanks.
4 years, 3 months
[PATCH v2] Basic support for PaX's split module layout
by Mathias Krause
PaX and grsecurity kernels split module memory into dedicated r/x and
r/w mappings using '*_rw' and '*_rx' named member variables in 'struct
module'. To add basic support for such kernels detect the split layout
by testing for the corresponding structure members and use these
instead.
So far we limit ourself to only track module code mappings for such
kernels as adding support for separate data mappings violates lots of
invariants in the rest of our code base, thereby would require a major
rework. However, with that patch applied, module code references can be
resolved in backtraces, memory and code dumps, which makes it already
very useful for analyzing such kernels.
Signed-off-by: Mathias Krause <minipli(a)grsecurity.net>
---
v2:
- add members to end of struct offset_table
- add offsets to dump_offset_table()
defs.h | 13 +++++++++++
kernel.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++----
symbols.c | 63 +++++++++++++++++++++++++++++++++------------------
3 files changed, 117 insertions(+), 27 deletions(-)
diff --git a/defs.h b/defs.h
index 17e98763362b..ae860448ab15 100644
--- a/defs.h
+++ b/defs.h
@@ -654,12 +654,15 @@ struct new_utsname {
#define TIMER_BASES (0x20ULL)
#define IRQ_DESC_TREE_RADIX (0x40ULL)
#define IRQ_DESC_TREE_XARRAY (0x80ULL)
+#define KMOD_PAX (0x100ULL)
#define XEN() (kt->flags & ARCH_XEN)
#define OPENVZ() (kt->flags & ARCH_OPENVZ)
#define PVOPS() (kt->flags & ARCH_PVOPS)
#define PVOPS_XEN() (kt->flags & ARCH_PVOPS_XEN)
+#define PAX_MODULE_SPLIT() (kt->flags2 & KMOD_PAX)
+
#define XEN_MACHINE_TO_MFN(m) ((ulonglong)(m) >> PAGESHIFT())
#define XEN_PFN_TO_PSEUDO(p) ((ulonglong)(p) << PAGESHIFT())
@@ -2089,6 +2092,14 @@ struct offset_table { /* stash of commonly-used offsets */
long size_class_size;
long gendisk_private_data;
long zram_table_entry;
+ long module_core_size_rw;
+ long module_core_size_rx;
+ long module_init_size_rw;
+ long module_init_size_rx;
+ long module_module_core_rw;
+ long module_module_core_rx;
+ long module_module_init_rw;
+ long module_module_init_rx;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2313,6 +2324,8 @@ struct array_table {
* in the offset table, size table or array_table.
*/
#define OFFSET(X) (OFFSET_verify(offset_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X))
+#define MODULE_OFFSET(X,Y) (PAX_MODULE_SPLIT() ? OFFSET(Y) : OFFSET(X))
+#define MODULE_OFFSET2(X,T) MODULE_OFFSET(X, X##_##T)
#define SIZE(X) (SIZE_verify(size_table.X, (char *)__FUNCTION__, __FILE__, __LINE__, #X))
#define INVALID_OFFSET (-1)
#define INVALID_MEMBER(X) (offset_table.X == INVALID_OFFSET)
diff --git a/kernel.c b/kernel.c
index f179375f2d3d..f0268adccd4a 100644
--- a/kernel.c
+++ b/kernel.c
@@ -3540,6 +3540,62 @@ module_init(void)
"module_core");
MEMBER_OFFSET_INIT(module_module_init, "module",
"module_init");
+ } else if (MEMBER_EXISTS("module", "module_core_rx")) {
+ if (CRASHDEBUG(1))
+ error(INFO, "PaX module layout detected.\n");
+ kt->flags2 |= KMOD_PAX;
+
+ MEMBER_OFFSET_INIT(module_core_size_rw, "module",
+ "core_size_rw");
+ MEMBER_OFFSET_INIT(module_core_size_rx, "module",
+ "core_size_rx");
+
+ MEMBER_OFFSET_INIT(module_init_size_rw, "module",
+ "init_size_rw");
+ MEMBER_OFFSET_INIT(module_init_size_rx, "module",
+ "init_size_rx");
+
+ MEMBER_OFFSET_INIT(module_module_core_rw, "module",
+ "module_core_rw");
+ MEMBER_OFFSET_INIT(module_module_core_rx, "module",
+ "module_core_rx");
+
+ MEMBER_OFFSET_INIT(module_module_init_rw, "module",
+ "module_init_rw");
+ MEMBER_OFFSET_INIT(module_module_init_rx, "module",
+ "module_init_rx");
+ } else if (MEMBER_EXISTS("module_layout", "base_rx")) {
+ if (CRASHDEBUG(1))
+ error(INFO, "PaX module layout detected.\n");
+ kt->flags2 |= KMOD_PAX;
+
+ ASSIGN_OFFSET(module_core_size_rw) =
+ MEMBER_OFFSET("module", "core_layout") +
+ MEMBER_OFFSET("module_layout", "size_rw");
+ ASSIGN_OFFSET(module_core_size_rx) =
+ MEMBER_OFFSET("module", "core_layout") +
+ MEMBER_OFFSET("module_layout", "size_rx");
+
+ ASSIGN_OFFSET(module_init_size_rw) =
+ MEMBER_OFFSET("module", "init_layout") +
+ MEMBER_OFFSET("module_layout", "size_rw");
+ ASSIGN_OFFSET(module_init_size_rx) =
+ MEMBER_OFFSET("module", "init_layout") +
+ MEMBER_OFFSET("module_layout", "size_rx");
+
+ ASSIGN_OFFSET(module_module_core_rw) =
+ MEMBER_OFFSET("module", "core_layout") +
+ MEMBER_OFFSET("module_layout", "base_rw");
+ ASSIGN_OFFSET(module_module_core_rx) =
+ MEMBER_OFFSET("module", "core_layout") +
+ MEMBER_OFFSET("module_layout", "base_rx");
+
+ ASSIGN_OFFSET(module_module_init_rw) =
+ MEMBER_OFFSET("module", "init_layout") +
+ MEMBER_OFFSET("module_layout", "base_rw");
+ ASSIGN_OFFSET(module_module_init_rx) =
+ MEMBER_OFFSET("module", "init_layout") +
+ MEMBER_OFFSET("module_layout", "base_rx");
} else {
ASSIGN_OFFSET(module_core_size) =
MEMBER_OFFSET("module", "core_layout") +
@@ -3682,10 +3738,10 @@ module_init(void)
case KALLSYMS_V2:
if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) {
numksyms = UINT(modbuf + OFFSET(module_num_symtab));
- size = UINT(modbuf + OFFSET(module_core_size));
+ size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx));
} else {
numksyms = ULONG(modbuf + OFFSET(module_num_symtab));
- size = ULONG(modbuf + OFFSET(module_core_size));
+ size = ULONG(modbuf + MODULE_OFFSET2(module_core_size, rx));
}
if (!size) {
@@ -3792,7 +3848,7 @@ verify_modules(void)
break;
case KMOD_V2:
mod_base = ULONG(modbuf +
- OFFSET(module_module_core));
+ MODULE_OFFSET2(module_module_core, rx));
break;
}
@@ -3816,10 +3872,10 @@ verify_modules(void)
OFFSET(module_name);
if (THIS_KERNEL_VERSION >= LINUX(2,6,27))
mod_size = UINT(modbuf +
- OFFSET(module_core_size));
+ MODULE_OFFSET2(module_core_size, rx));
else
mod_size = ULONG(modbuf +
- OFFSET(module_core_size));
+ MODULE_OFFSET2(module_core_size, rx));
if (strlen(module_name) < MAX_MOD_NAME)
strcpy(buf, module_name);
else
@@ -5997,6 +6053,8 @@ dump_kernel_table(int verbose)
fprintf(fp, "%sIRQ_DESC_TREE_RADIX", others++ ? "|" : "");
if (kt->flags2 & IRQ_DESC_TREE_XARRAY)
fprintf(fp, "%sIRQ_DESC_TREE_XARRAY", others++ ? "|" : "");
+ if (kt->flags2 & KMOD_PAX)
+ fprintf(fp, "%sKMOD_PAX", others++ ? "|" : "");
fprintf(fp, ")\n");
fprintf(fp, " stext: %lx\n", kt->stext);
diff --git a/symbols.c b/symbols.c
index 2fecaee093a2..9a80e8a585d1 100644
--- a/symbols.c
+++ b/symbols.c
@@ -1766,17 +1766,17 @@ store_module_symbols_v2(ulong total, int mods_installed)
if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) {
nksyms = UINT(modbuf + OFFSET(module_num_symtab));
- size = UINT(modbuf + OFFSET(module_core_size));
+ size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx));
} else {
nksyms = ULONG(modbuf + OFFSET(module_num_symtab));
- size = ULONG(modbuf + OFFSET(module_core_size));
+ size = ULONG(modbuf + MODULE_OFFSET2(module_core_size, rx));
}
mod_name = modbuf + OFFSET(module_name);
lm = &st->load_modules[m++];
BZERO(lm, sizeof(struct load_module));
- lm->mod_base = ULONG(modbuf + OFFSET(module_module_core));
+ lm->mod_base = ULONG(modbuf + MODULE_OFFSET2(module_module_core, rx));
lm->module_struct = mod;
lm->mod_size = size;
if (strlen(mod_name) < MAX_MOD_NAME)
@@ -1795,23 +1795,23 @@ store_module_symbols_v2(ulong total, int mods_installed)
lm->mod_flags = MOD_EXT_SYMS;
lm->mod_ext_symcnt = mcnt;
lm->mod_init_module_ptr = ULONG(modbuf +
- OFFSET(module_module_init));
+ MODULE_OFFSET2(module_module_init, rx));
if (VALID_MEMBER(module_percpu))
lm->mod_percpu = ULONG(modbuf + OFFSET(module_percpu));
if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) {
lm->mod_etext_guess = lm->mod_base +
- UINT(modbuf + OFFSET(module_core_text_size));
+ UINT(modbuf + MODULE_OFFSET(module_core_text_size, module_core_size_rx));
lm->mod_init_size =
- UINT(modbuf + OFFSET(module_init_size));
+ UINT(modbuf + MODULE_OFFSET2(module_init_size, rx));
lm->mod_init_text_size =
- UINT(modbuf + OFFSET(module_init_text_size));
+ UINT(modbuf + MODULE_OFFSET(module_init_text_size, module_init_size_rx));
} else {
lm->mod_etext_guess = lm->mod_base +
- ULONG(modbuf + OFFSET(module_core_text_size));
+ ULONG(modbuf + MODULE_OFFSET(module_core_text_size, module_core_size_rx));
lm->mod_init_size =
- ULONG(modbuf + OFFSET(module_init_size));
+ ULONG(modbuf + MODULE_OFFSET2(module_init_size, rx));
lm->mod_init_text_size =
- ULONG(modbuf + OFFSET(module_init_text_size));
+ ULONG(modbuf + MODULE_OFFSET(module_init_text_size, module_init_size_rx));
}
lm->mod_text_start = lm->mod_base;
@@ -9113,18 +9113,37 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(module_num_gpl_syms));
fprintf(fp, " module_list: %ld\n",
OFFSET(module_list));
- fprintf(fp, " module_module_core: %ld\n",
- OFFSET(module_module_core));
- fprintf(fp, " module_core_size: %ld\n",
- OFFSET(module_core_size));
- fprintf(fp, " module_core_text_size: %ld\n",
- OFFSET(module_core_text_size));
- fprintf(fp, " module_init_size: %ld\n",
- OFFSET(module_init_size));
- fprintf(fp, " module_init_text_size: %ld\n",
- OFFSET(module_init_text_size));
- fprintf(fp, " module_module_init: %ld\n",
- OFFSET(module_module_init));
+ if (PAX_MODULE_SPLIT()) {
+ fprintf(fp, " module_module_core_rx: %ld\n",
+ OFFSET(module_module_core_rx));
+ fprintf(fp, " module_module_core_rw: %ld\n",
+ OFFSET(module_module_core_rw));
+ fprintf(fp, " module_core_size_rx: %ld\n",
+ OFFSET(module_core_size_rx));
+ fprintf(fp, " module_core_size_rw: %ld\n",
+ OFFSET(module_core_size_rw));
+ fprintf(fp, " module_module_init_rx: %ld\n",
+ OFFSET(module_module_init_rx));
+ fprintf(fp, " module_module_init_rw: %ld\n",
+ OFFSET(module_module_init_rw));
+ fprintf(fp, " module_init_size_rx: %ld\n",
+ OFFSET(module_init_size_rx));
+ fprintf(fp, " module_init_size_rw: %ld\n",
+ OFFSET(module_init_size_rw));
+ } else {
+ fprintf(fp, " module_module_core: %ld\n",
+ OFFSET(module_module_core));
+ fprintf(fp, " module_core_size: %ld\n",
+ OFFSET(module_core_size));
+ fprintf(fp, " module_core_text_size: %ld\n",
+ OFFSET(module_core_text_size));
+ fprintf(fp, " module_init_size: %ld\n",
+ OFFSET(module_init_size));
+ fprintf(fp, " module_init_text_size: %ld\n",
+ OFFSET(module_init_text_size));
+ fprintf(fp, " module_module_init: %ld\n",
+ OFFSET(module_module_init));
+ }
fprintf(fp, " module_num_symtab: %ld\n",
OFFSET(module_num_symtab));
fprintf(fp, " module_symtab: %ld\n",
--
2.20.1
4 years, 3 months
[PATCH] Append time zone to output of date and time
by HAGIO KAZUHITO(萩尾 一仁)
Currently it's not easy to distinguish which time zone the output of
DATE uses:
crash> sys | grep DATE
DATE: Thu Nov 29 06:44:02 2018
Let's introduce ctime_tz() function like ctime() but explicitly appends
the time zone to its result string.
DATE: Thu Nov 29 06:44:02 JST 2018
Resolves: https://github.com/crash-utility/crash/issues/62
Suggested-by: Jacob Wen <jian.w.wen(a)oracle.com>
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
defs.h | 1 +
help.c | 3 +--
kernel.c | 16 ++++++----------
tools.c | 28 ++++++++++++++++++++++++++++
4 files changed, 36 insertions(+), 12 deletions(-)
diff --git a/defs.h b/defs.h
index 17e98763362b..e7dec7c672a6 100644
--- a/defs.h
+++ b/defs.h
@@ -5096,6 +5096,7 @@ char *strdupbuf(char *);
void sigsetup(int, void *, struct sigaction *, struct sigaction *);
#define SIGACTION(s, h, a, o) sigsetup(s, h, a, o)
char *convert_time(ulonglong, char *);
+char *ctime_tz(time_t *);
void stall(ulong);
char *pages_to_size(ulong, char *);
int clean_arg(void);
diff --git a/help.c b/help.c
index b707cfa58826..d3427a36829f 100644
--- a/help.c
+++ b/help.c
@@ -9299,8 +9299,7 @@ display_README(void)
fprintf(fp, " GNU gdb %s\n", pc->gdb_version);
} else if (STREQ(README[i], README_DATE)) {
time(&time_now);
- fprintf(fp, " DATE: %s\n",
- strip_linefeeds(ctime(&time_now)));
+ fprintf(fp, " DATE: %s\n", ctime_tz(&time_now));
} else if (STREQ(README[i], README_HELP_MENU)) {
display_help_screen(" ");
} else if (STREQ(README[i], README_GPL_INFO)) {
diff --git a/kernel.c b/kernel.c
index f179375f2d3d..92bfe6329900 100644
--- a/kernel.c
+++ b/kernel.c
@@ -225,10 +225,9 @@ kernel_init()
get_xtime(&kt->date);
if (CRASHDEBUG(1))
fprintf(fp, "xtime timespec.tv_sec: %lx: %s\n",
- kt->date.tv_sec, strip_linefeeds(ctime(&kt->date.tv_sec)));
+ kt->date.tv_sec, ctime_tz(&kt->date.tv_sec));
if (kt->flags2 & GET_TIMESTAMP) {
- fprintf(fp, "%s\n\n",
- strip_linefeeds(ctime(&kt->date.tv_sec)));
+ fprintf(fp, "%s\n\n", ctime_tz(&kt->date.tv_sec));
clean_exit(0);
}
@@ -5178,7 +5177,7 @@ dump_log_entry(char *logptr, int msg_flags)
rem = (ulonglong)ts_nsec % (ulonglong)1000000000;
if (msg_flags & SHOW_LOG_CTIME) {
time_t t = kt->boot_date.tv_sec + nanos;
- sprintf(buf, "[%s] ", strip_linefeeds(ctime(&t)));
+ sprintf(buf, "[%s] ", ctime_tz(&t));
}
else
sprintf(buf, "[%5lld.%06ld] ", nanos, rem/1000);
@@ -5553,8 +5552,7 @@ display_sys_stats(void)
if (ACTIVE())
get_xtime(&kt->date);
- fprintf(fp, " DATE: %s\n",
- strip_linefeeds(ctime(&kt->date.tv_sec)));
+ fprintf(fp, " DATE: %s\n", ctime_tz(&kt->date.tv_sec));
fprintf(fp, " UPTIME: %s\n", get_uptime(buf, NULL));
fprintf(fp, "LOAD AVERAGE: %s\n", get_loadavg(buf));
fprintf(fp, " TASKS: %ld\n", RUNNING_TASKS());
@@ -6043,10 +6041,8 @@ dump_kernel_table(int verbose)
kt->source_tree : "(not used)");
if (!(pc->flags & KERNEL_DEBUG_QUERY) && ACTIVE())
get_xtime(&kt->date);
- fprintf(fp, " date: %s\n",
- strip_linefeeds(ctime(&kt->date.tv_sec)));
- fprintf(fp, " boot_ date: %s\n",
- strip_linefeeds(ctime(&kt->boot_date.tv_sec)));
+ fprintf(fp, " date: %s\n", ctime_tz(&kt->date.tv_sec));
+ fprintf(fp, " boot_date: %s\n", ctime_tz(&kt->boot_date.tv_sec));
fprintf(fp, " proc_version: %s\n", strip_linefeeds(kt->proc_version));
fprintf(fp, " new_utsname: \n");
fprintf(fp, " .sysname: %s\n", uts->sysname);
diff --git a/tools.c b/tools.c
index 85c81668e40e..4654e7458a3e 100644
--- a/tools.c
+++ b/tools.c
@@ -6318,6 +6318,34 @@ convert_time(ulonglong count, char *buf)
}
/*
+ * Convert a calendar time into a null-terminated string like ctime(), but
+ * the result string contains the time zone string and does not ends with a
+ * linefeed ('\n').
+ *
+ * NOTE: The return value points to a statically allocated string which is
+ * overwritten by subsequent calls.
+ */
+char *
+ctime_tz(time_t *timep)
+{
+ static char buf[64];
+ struct tm *tm;
+ size_t size;
+
+ tm = localtime(timep);
+ if (!tm) {
+ snprintf(buf, sizeof(buf), "%ld", *timep);
+ return buf;
+ }
+
+ size = strftime(buf, sizeof(buf), "%a %b %e %T %Z %Y", tm);
+ if (!size)
+ return strip_linefeeds(ctime(timep));
+
+ return buf;
+}
+
+/*
* Stall for a number of microseconds.
*/
void
--
1.8.3.1
4 years, 3 months
Re: [Crash-utility] [PATCH v4] Fix "log" command when crash is started with "--minimal" option
by lijiang
在 2020年08月18日 00:00, crash-utility-request(a)redhat.com 写道:
>> -----Original Message-----
>> From: crash-utility-bounces(a)redhat.com <crash-utility-bounces(a)redhat.com> On Behalf Of Dave Wysochanski
>> Sent: Monday, August 17, 2020 4:20 AM
>> To: crash-utility(a)redhat.com
>> Subject: [Crash-utility] [PATCH v4] Fix "log" command when crash is started with "--minimal" option
>>
>> Commit c86250bce29f introduced the useful '-T' option to print the
>> log timestamp in human-readable form. However, this option does
>> not work when crash is invoked with '--minimal' mode, and if tried,
>> crash will spin at 100% and continuously crash at a divide by 0
>> because machdep->hz == 0.
>>
>> Fix this by disallowing this option in minimal mode. In addition,
>> only calculate the logic to calculate kt->boot_date.tv_sec
>> when this option is enabled.
>>
>> Fixes: c86250bce29f ("Introduction of the "log -T" option...")
>> Signed-off-by: Dave Wysochanski <dwysocha(a)redhat.com>
>> Reviewed-by: Wang Long <w(a)laoqinren.net>
>> Tested-by: Mathias Krause <minipli(a)grsecurity.net>
>> Reviewed-by: Lianbo Jiang <lijiang(a)redhat.com>
>> ---
>> kernel.c | 21 ++++++++++++++-------
>> 1 file changed, 14 insertions(+), 7 deletions(-)
>>
>> diff --git a/kernel.c b/kernel.c
>> index 5ed6021..9aa1d4d 100644
>> --- a/kernel.c
>> +++ b/kernel.c
>> @@ -4939,13 +4939,20 @@ cmd_log(void)
>> if (argerrs)
>> cmd_usage(pc->curcmd, SYNOPSIS);
>>
>> - if (kt->boot_date.tv_sec == 0) {
>> - ulonglong uptime_jiffies;
>> - ulong uptime_sec;
>> - get_uptime(NULL, &uptime_jiffies);
>> - uptime_sec = (uptime_jiffies)/(ulonglong)machdep->hz;
>> - kt->boot_date.tv_sec = kt->date.tv_sec - uptime_sec;
>> - kt->boot_date.tv_nsec = 0;
>> + if (msg_flags & SHOW_LOG_CTIME) {
>> + if (pc->flags & MINIMAL_MODE) {
>> + error(WARNING, "log: option 'T' not available in minimal mode\n");
> ^^^^^
> This extra "log: " is not needed:
>
> crash> log -T
> log: WARNING: log: option 'T' not available in minimal mode
>
> Lianbo, would you remove it when applying? Otherwise,
>
Sure, applied. Thanks for the fix, Dave Wysochanski.
Lianbo
> Acked-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
>
> Thanks,
> Kazu
>
>
4 years, 3 months