Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1742465 > unrolled thread
| Started by | Sergey Senozhatsky <sergey.senozhatsky@gmail.com> |
|---|---|
| First post | 2017-09-30 05:00 +0200 |
| Last post | 2017-09-30 05:00 +0200 |
| Articles | 3 — 1 participant |
Back to article view | Back to linux.kernel
[PATCHv3 0/7] printk/ia64/ppc64/parisc64: let's deprecate %pF/%pf printk specifiers Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2017-09-30 05:00 +0200
[PATCHv3 1/7] switch dereference_function_descriptor() to `unsigned long' Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2017-09-30 05:00 +0200
[PATCHv3 5/7] parisc64: Add .opd based function descriptor dereference Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2017-09-30 05:00 +0200
| From | Sergey Senozhatsky <sergey.senozhatsky@gmail.com> |
|---|---|
| Date | 2017-09-30 05:00 +0200 |
| Subject | [PATCHv3 0/7] printk/ia64/ppc64/parisc64: let's deprecate %pF/%pf printk specifiers |
| Message-ID | <uvgat-6zO-3@gated-at.bofh.it> |
Hello
Petr, could you please pick up the series?
==========================================================================
On some arches C function pointers are indirect and point to
a function descriptor, which contains the actual pointer to the code.
This mostly doesn't matter, except for cases when people want to print
out function pointers in symbolic format, because the usual '%pS/%ps'
does not work on those arches as expected. That's the reason why we
have '%pF/%pf', but since it's here because of a subtle ABI detail
specific to some arches (ppc64/ia64/parisc64) it's easy to misuse
'%pF/%pf' and '%pS/%ps' (see [1], for example).
This patch set attempts to move ia64/ppc64/parisc64 C function
pointer ABI details out of printk() to arch code. Function dereference
code now checks if a pointer belongs to a .opd ELF section and dereferences
that pointer only if it does. The kernel and modules have their own .opd
sections that's why I use two different ARCH functions: for kernel and
for module pointer dereference.
I planned to remove dereference_function_descriptor() entirely,
but then I discovered a bunch other uses cases (kgdbts, init/main.c,
extable, etc.), so I decided to keep dereference_function_descriptor()
around because the main point of this patch set is to deprecate %pF/%pf.
But at the same time, I think I can go further and handle both kernel
and module descriptor dereference in dereference_function_descriptor().
We need a module pointer for module .opd check, so that will come at an
extra cost of module lookup (may be there will some other issues along
the way, haven't checked it).
Right now we've got:
- dereference_function_descriptor(addr)
a generic (old) function. it simply attempts to dereference
whatever pointer we give it.
- dereference_kernel_function_descriptor(addr)
dereferences a kernel pointer if it's within the kernel's .opd
section.
- dereference_module_function_descriptor(module, addr)
dereference a module pointer if it's within the module's .opd
section.
v3:
-- picked up ACKs and Tested-by
-- tweaked checkpatch warning (Joe)
-- updated Documentation
v2:
-- convert dereference_function_descriptor() to unsigned long
-- fix kernel descriptor range checks (Helge)
-- fix parisc module descriptor range check (Helge)
-- fix ppc64 module range check
-- add checkpatch patch
Sergey Senozhatsky (7):
switch dereference_function_descriptor() to `unsigned long'
sections: split dereference_function_descriptor()
ia64: Add .opd based function descriptor dereference
powerpc64: Add .opd based function descriptor dereference
parisc64: Add .opd based function descriptor dereference
symbol lookup: use new kernel and module dereference functions
checkpatch: add pF/pf deprecation warning
Documentation/printk-formats.txt | 20 ++++++++++----------
arch/ia64/include/asm/sections.h | 16 ++++++++++++----
arch/ia64/kernel/module.c | 13 +++++++++++++
arch/ia64/kernel/vmlinux.lds.S | 2 ++
arch/parisc/boot/compressed/vmlinux.lds.S | 2 ++
arch/parisc/include/asm/sections.h | 4 +++-
arch/parisc/kernel/module.c | 17 +++++++++++++++++
arch/parisc/kernel/process.c | 15 ++++++++++++---
arch/parisc/kernel/vmlinux.lds.S | 2 ++
arch/parisc/mm/init.c | 4 ++--
arch/powerpc/include/asm/module.h | 3 +++
arch/powerpc/include/asm/sections.h | 17 ++++++++++++++---
arch/powerpc/kernel/module_64.c | 16 ++++++++++++++++
arch/powerpc/kernel/vmlinux.lds.S | 2 ++
drivers/misc/kgdbts.c | 2 +-
include/asm-generic/sections.h | 8 ++++++--
include/linux/moduleloader.h | 4 ++++
init/main.c | 2 +-
kernel/extable.c | 2 +-
kernel/kallsyms.c | 1 +
kernel/module.c | 9 ++++++++-
lib/vsprintf.c | 5 +----
scripts/checkpatch.pl | 11 +++++++++--
23 files changed, 142 insertions(+), 35 deletions(-)
--
2.14.2
[toc] | [next] | [standalone]
| From | Sergey Senozhatsky <sergey.senozhatsky@gmail.com> |
|---|---|
| Date | 2017-09-30 05:00 +0200 |
| Subject | [PATCHv3 1/7] switch dereference_function_descriptor() to `unsigned long' |
| Message-ID | <uvgau-6zO-17@gated-at.bofh.it> |
| In reply to | #1742465 |
Convert dereference_function_descriptor() to accept and return
`unsigned long'. There will be two new ARCH function for kernel
and module function pointer dereference, which will work with
`unsigned long', so the patch unifies interfaces.
Besides, dereference_function_descriptor() mostly work with
`unsigned long':
drivers/misc/kgdbts.c:
addr = (unsigned long) dereference_function_descriptor((void *)addr);
init/main.c:
addr = (unsigned long) dereference_function_descriptor(fn);
kernel/extable.c:
addr = (unsigned long) dereference_function_descriptor(ptr);
kernel/module.c:
unsigned long a = (unsigned long)dereference_function_descriptor(addr);
Convert dereference_function_descriptor() users tree-wide.
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Tested-by: Helge Deller <deller@gmx.de> # parisc64
Tested-by: Santosh Sivaraj <santosh@fossix.org> # powerpc64
Acked-by: Michael Ellerman <mpe@ellerman.id.au> # powerpc64
Tested-by: Tony Luck <tony.luck@intel.com> # ia64
---
arch/ia64/include/asm/sections.h | 6 +++---
arch/parisc/include/asm/sections.h | 2 +-
arch/parisc/kernel/process.c | 6 +++---
arch/parisc/mm/init.c | 4 ++--
arch/powerpc/include/asm/sections.h | 6 +++---
drivers/misc/kgdbts.c | 2 +-
init/main.c | 2 +-
kernel/extable.c | 2 +-
kernel/module.c | 2 +-
lib/vsprintf.c | 2 +-
10 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/arch/ia64/include/asm/sections.h b/arch/ia64/include/asm/sections.h
index 2ab2003698ef..de6bfa1ef8fb 100644
--- a/arch/ia64/include/asm/sections.h
+++ b/arch/ia64/include/asm/sections.h
@@ -27,13 +27,13 @@ extern char __start_unwind[], __end_unwind[];
extern char __start_ivt_text[], __end_ivt_text[];
#undef dereference_function_descriptor
-static inline void *dereference_function_descriptor(void *ptr)
+static inline unsigned long dereference_function_descriptor(unsigned long ptr)
{
- struct fdesc *desc = ptr;
+ struct fdesc *desc = (struct fdesc *)ptr;
void *p;
if (!probe_kernel_address(&desc->ip, p))
- ptr = p;
+ ptr = (unsigned long)p;
return ptr;
}
diff --git a/arch/parisc/include/asm/sections.h b/arch/parisc/include/asm/sections.h
index 9d13c3507ad6..59fbe0067112 100644
--- a/arch/parisc/include/asm/sections.h
+++ b/arch/parisc/include/asm/sections.h
@@ -6,7 +6,7 @@
#ifdef CONFIG_64BIT
#undef dereference_function_descriptor
-void *dereference_function_descriptor(void *);
+unsigned long dereference_function_descriptor(unsigned long);
#endif
#endif
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 30f92391a93e..d350aa913acc 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -267,13 +267,13 @@ get_wchan(struct task_struct *p)
}
#ifdef CONFIG_64BIT
-void *dereference_function_descriptor(void *ptr)
+unsigned long dereference_function_descriptor(unsigned long ptr)
{
- Elf64_Fdesc *desc = ptr;
+ Elf64_Fdesc *desc = (Elf64_Fdesc *)ptr;
void *p;
if (!probe_kernel_address(&desc->addr, p))
- ptr = p;
+ ptr = (unsigned long)p;
return ptr;
}
#endif
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index 1ca9a2b4239f..06e1b79e2946 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -389,10 +389,10 @@ static void __init setup_bootmem(void)
static int __init parisc_text_address(unsigned long vaddr)
{
static unsigned long head_ptr __initdata;
+ unsigned long addr = (unsigned long)&parisc_kernel_start;
if (!head_ptr)
- head_ptr = PAGE_MASK & (unsigned long)
- dereference_function_descriptor(&parisc_kernel_start);
+ head_ptr = PAGE_MASK & dereference_function_descriptor(addr);
return core_kernel_text(vaddr) || vaddr == head_ptr;
}
diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h
index 7902d6358854..67379b8945e8 100644
--- a/arch/powerpc/include/asm/sections.h
+++ b/arch/powerpc/include/asm/sections.h
@@ -66,13 +66,13 @@ static inline int overlaps_kvm_tmp(unsigned long start, unsigned long end)
#ifdef PPC64_ELF_ABI_v1
#undef dereference_function_descriptor
-static inline void *dereference_function_descriptor(void *ptr)
+static inline unsigned long dereference_function_descriptor(unsigned long ptr)
{
- struct ppc64_opd_entry *desc = ptr;
+ struct ppc64_opd_entry *desc = (struct ppc64_opd_entry *)ptr;
void *p;
if (!probe_kernel_address(&desc->funcaddr, p))
- ptr = p;
+ ptr = (unsigned long)p;
return ptr;
}
#endif /* PPC64_ELF_ABI_v1 */
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index fc7efedbc4be..6a5a159dfb75 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -225,7 +225,7 @@ static unsigned long lookup_addr(char *arg)
addr = (unsigned long)_do_fork;
else if (!strcmp(arg, "hw_break_val"))
addr = (unsigned long)&hw_break_val;
- addr = (unsigned long) dereference_function_descriptor((void *)addr);
+ addr = dereference_function_descriptor(addr);
return addr;
}
diff --git a/init/main.c b/init/main.c
index 83bdfa4750b1..ac56f7a4501f 100644
--- a/init/main.c
+++ b/init/main.c
@@ -764,7 +764,7 @@ static bool __init_or_module initcall_blacklisted(initcall_t fn)
if (list_empty(&blacklisted_initcalls))
return false;
- addr = (unsigned long) dereference_function_descriptor(fn);
+ addr = dereference_function_descriptor((unsigned long)fn);
sprint_symbol_no_offset(fn_name, addr);
/*
diff --git a/kernel/extable.c b/kernel/extable.c
index 9aa1cc41ecf7..e48d6ba4ce6c 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -167,7 +167,7 @@ int kernel_text_address(unsigned long addr)
int func_ptr_is_kernel_text(void *ptr)
{
unsigned long addr;
- addr = (unsigned long) dereference_function_descriptor(ptr);
+ addr = dereference_function_descriptor((unsigned long)ptr);
if (core_kernel_text(addr))
return 1;
return is_module_text_address(addr);
diff --git a/kernel/module.c b/kernel/module.c
index de66ec825992..ea77ab13bead 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1067,7 +1067,7 @@ EXPORT_SYMBOL(__symbol_put);
void symbol_put_addr(void *addr)
{
struct module *modaddr;
- unsigned long a = (unsigned long)dereference_function_descriptor(addr);
+ unsigned long a = dereference_function_descriptor((unsigned long)addr);
if (core_kernel_text(a))
return;
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 86c3385b9eb3..bcd906a39010 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1723,7 +1723,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
switch (*fmt) {
case 'F':
case 'f':
- ptr = dereference_function_descriptor(ptr);
+ ptr = (void *)dereference_function_descriptor((unsigned long)ptr);
/* Fallthrough */
case 'S':
case 's':
--
2.14.2
[toc] | [prev] | [next] | [standalone]
| From | Sergey Senozhatsky <sergey.senozhatsky@gmail.com> |
|---|---|
| Date | 2017-09-30 05:00 +0200 |
| Subject | [PATCHv3 5/7] parisc64: Add .opd based function descriptor dereference |
| Message-ID | <uvgau-6zO-15@gated-at.bofh.it> |
| In reply to | #1742465 |
We are moving towards separate kernel and module function descriptor
dereference callbacks. This patch enables it for parisc64.
For pointers that belong to the kernel
- Added __start_opd and __end_opd pointers, to track the kernel
.opd section address range;
- Added dereference_kernel_function_descriptor(). Now we
will dereference only function pointers that are within
[__start_opd, __end_opd];
For pointers that belong to a module
- Added dereference_module_function_descriptor() to handle module
function descriptor dereference. Now we will dereference only
pointers that are within [module->opd.start, module->opd.end].
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Signed-off-by: Helge Deller <deller@gmx.de>
Tested-by: Helge Deller <deller@gmx.de> # parisc64
Tested-by: Santosh Sivaraj <santosh@fossix.org> # powerpc64
Acked-by: Michael Ellerman <mpe@ellerman.id.au> # powerpc64
Tested-by: Tony Luck <tony.luck@intel.com> # ia64
---
arch/parisc/boot/compressed/vmlinux.lds.S | 2 ++
arch/parisc/include/asm/sections.h | 2 ++
arch/parisc/kernel/module.c | 17 +++++++++++++++++
arch/parisc/kernel/process.c | 9 +++++++++
arch/parisc/kernel/vmlinux.lds.S | 2 ++
5 files changed, 32 insertions(+)
diff --git a/arch/parisc/boot/compressed/vmlinux.lds.S b/arch/parisc/boot/compressed/vmlinux.lds.S
index a4ce3314e78e..4ebd4e65524c 100644
--- a/arch/parisc/boot/compressed/vmlinux.lds.S
+++ b/arch/parisc/boot/compressed/vmlinux.lds.S
@@ -29,7 +29,9 @@ SECTIONS
. = ALIGN(16);
/* Linkage tables */
.opd : {
+ __start_opd = .;
*(.opd)
+ __end_opd = .;
} PROVIDE (__gp = .);
.plt : {
*(.plt)
diff --git a/arch/parisc/include/asm/sections.h b/arch/parisc/include/asm/sections.h
index 59fbe0067112..845ddc9a3421 100644
--- a/arch/parisc/include/asm/sections.h
+++ b/arch/parisc/include/asm/sections.h
@@ -7,6 +7,8 @@
#ifdef CONFIG_64BIT
#undef dereference_function_descriptor
unsigned long dereference_function_descriptor(unsigned long);
+#undef dereference_kernel_function_descriptor
+unsigned long dereference_kernel_function_descriptor(unsigned long);
#endif
#endif
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index f1a76935a314..28f89b3dcc11 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -66,6 +66,7 @@
#include <asm/pgtable.h>
#include <asm/unwind.h>
+#include <asm/sections.h>
#if 0
#define DEBUGP printk
@@ -954,3 +955,19 @@ void module_arch_cleanup(struct module *mod)
{
deregister_unwind_table(mod);
}
+
+#ifdef CONFIG_64BIT
+unsigned long dereference_module_function_descriptor(struct module *mod,
+ unsigned long addr)
+{
+ unsigned long start_opd = (Elf64_Addr)mod->core_layout.base +
+ mod->arch.fdesc_offset;
+ unsigned long end_opd = start_opd +
+ mod->arch.fdesc_count * sizeof(Elf64_Fdesc);
+
+ if (addr < start_opd || addr >= end_opd)
+ return addr;
+
+ return dereference_function_descriptor(addr);
+}
+#endif
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index d350aa913acc..423bbfe90e2b 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -276,6 +276,15 @@ unsigned long dereference_function_descriptor(unsigned long ptr)
ptr = (unsigned long)p;
return ptr;
}
+
+unsigned long dereference_kernel_function_descriptor(unsigned long addr)
+{
+ if (addr < (unsigned long)__start_opd ||
+ addr >= (unsigned long)__end_opd)
+ return addr;
+
+ return dereference_function_descriptor(addr);
+}
#endif
static inline unsigned long brk_rnd(void)
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index ffe2cbf52d1a..ab030895dd1e 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -99,7 +99,9 @@ SECTIONS
. = ALIGN(16);
/* Linkage tables */
.opd : {
+ __start_opd = .;
*(.opd)
+ __end_opd = .;
} PROVIDE (__gp = .);
.plt : {
*(.plt)
--
2.14.2
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web