Skip to content

Commit b4e9c95

Browse files
author
Al Viro
committed
introduction of regset ->get() wrappers, switching ELF coredumps to those
Two new helpers: given a process and regset, dump into a buffer. regset_get() takes a buffer and size, regset_get_alloc() takes size and allocates a buffer. Return value in both cases is the amount of data actually dumped in case of success or -E... on error. In both cases the size is capped by regset->n * regset->size, so ->get() is called with offset 0 and size no more than what regset expects. binfmt_elf.c callers of ->get() are switched to using those; the other caller (copy_regset_to_user()) will need some preparations to switch. Signed-off-by: Al Viro <[email protected]>
1 parent b3a9e3b commit b4e9c95

File tree

4 files changed

+90
-29
lines changed

4 files changed

+90
-29
lines changed

fs/binfmt_elf.c

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,7 +1821,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
18211821
long signr, size_t *total)
18221822
{
18231823
unsigned int i;
1824-
unsigned int regset0_size = regset_size(t->task, &view->regsets[0]);
1824+
int regset0_size;
18251825

18261826
/*
18271827
* NT_PRSTATUS is the one special case, because the regset data
@@ -1830,8 +1830,10 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
18301830
* We assume that regset 0 is NT_PRSTATUS.
18311831
*/
18321832
fill_prstatus(&t->prstatus, t->task, signr);
1833-
(void) view->regsets[0].get(t->task, &view->regsets[0], 0, regset0_size,
1834-
&t->prstatus.pr_reg, NULL);
1833+
regset0_size = regset_get(t->task, &view->regsets[0],
1834+
sizeof(t->prstatus.pr_reg), &t->prstatus.pr_reg);
1835+
if (regset0_size < 0)
1836+
return 0;
18351837

18361838
fill_note(&t->notes[0], "CORE", NT_PRSTATUS,
18371839
PRSTATUS_SIZE(t->prstatus, regset0_size), &t->prstatus);
@@ -1846,32 +1848,28 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
18461848
*/
18471849
for (i = 1; i < view->n; ++i) {
18481850
const struct user_regset *regset = &view->regsets[i];
1851+
int note_type = regset->core_note_type;
1852+
bool is_fpreg = note_type == NT_PRFPREG;
1853+
void *data;
1854+
int ret;
1855+
18491856
do_thread_regset_writeback(t->task, regset);
1850-
if (regset->core_note_type && regset->get &&
1851-
(!regset->active || regset->active(t->task, regset) > 0)) {
1852-
int ret;
1853-
size_t size = regset_size(t->task, regset);
1854-
void *data = kzalloc(size, GFP_KERNEL);
1855-
if (unlikely(!data))
1856-
return 0;
1857-
ret = regset->get(t->task, regset,
1858-
0, size, data, NULL);
1859-
if (unlikely(ret))
1860-
kfree(data);
1861-
else {
1862-
if (regset->core_note_type != NT_PRFPREG)
1863-
fill_note(&t->notes[i], "LINUX",
1864-
regset->core_note_type,
1865-
size, data);
1866-
else {
1867-
SET_PR_FPVALID(&t->prstatus,
1868-
1, regset0_size);
1869-
fill_note(&t->notes[i], "CORE",
1870-
NT_PRFPREG, size, data);
1871-
}
1872-
*total += notesize(&t->notes[i]);
1873-
}
1874-
}
1857+
if (!note_type) // not for coredumps
1858+
continue;
1859+
if (regset->active && regset->active(t->task, regset) <= 0)
1860+
continue;
1861+
1862+
ret = regset_get_alloc(t->task, regset, ~0U, &data);
1863+
if (ret < 0)
1864+
continue;
1865+
1866+
if (is_fpreg)
1867+
SET_PR_FPVALID(&t->prstatus, 1, regset0_size);
1868+
1869+
fill_note(&t->notes[i], is_fpreg ? "CORE" : "LINUX",
1870+
note_type, ret, data);
1871+
1872+
*total += notesize(&t->notes[i]);
18751873
}
18761874

18771875
return 1;

include/linux/regset.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,15 @@ static inline int user_regset_copyin_ignore(unsigned int *pos,
353353
return 0;
354354
}
355355

356+
extern int regset_get(struct task_struct *target,
357+
const struct user_regset *regset,
358+
unsigned int size, void *data);
359+
360+
extern int regset_get_alloc(struct task_struct *target,
361+
const struct user_regset *regset,
362+
unsigned int size,
363+
void **data);
364+
356365
/**
357366
* copy_regset_to_user - fetch a thread's user_regset data into user memory
358367
* @target: thread to be examined

kernel/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ obj-y = fork.o exec_domain.o panic.o \
1010
extable.o params.o \
1111
kthread.o sys_ni.o nsproxy.o \
1212
notifier.o ksysfs.o cred.o reboot.o \
13-
async.o range.o smpboot.o ucount.o
13+
async.o range.o smpboot.o ucount.o regset.o
1414

1515
obj-$(CONFIG_MODULES) += kmod.o
1616
obj-$(CONFIG_MULTIUSER) += groups.o

kernel/regset.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
#include <linux/export.h>
3+
#include <linux/slab.h>
4+
#include <linux/regset.h>
5+
6+
static int __regset_get(struct task_struct *target,
7+
const struct user_regset *regset,
8+
unsigned int size,
9+
void **data)
10+
{
11+
void *p = *data, *to_free = NULL;
12+
int res;
13+
14+
if (!regset->get)
15+
return -EOPNOTSUPP;
16+
if (size > regset->n * regset->size)
17+
size = regset->n * regset->size;
18+
if (!p) {
19+
to_free = p = kzalloc(size, GFP_KERNEL);
20+
if (!p)
21+
return -ENOMEM;
22+
}
23+
res = regset->get(target, regset, 0, size, p, NULL);
24+
if (unlikely(res < 0)) {
25+
kfree(to_free);
26+
return res;
27+
}
28+
*data = p;
29+
if (regset->get_size) { // arm64-only kludge, will go away
30+
unsigned max_size = regset->get_size(target, regset);
31+
if (size > max_size)
32+
size = max_size;
33+
}
34+
return size;
35+
}
36+
37+
int regset_get(struct task_struct *target,
38+
const struct user_regset *regset,
39+
unsigned int size,
40+
void *data)
41+
{
42+
return __regset_get(target, regset, size, &data);
43+
}
44+
EXPORT_SYMBOL(regset_get);
45+
46+
int regset_get_alloc(struct task_struct *target,
47+
const struct user_regset *regset,
48+
unsigned int size,
49+
void **data)
50+
{
51+
*data = NULL;
52+
return __regset_get(target, regset, size, data);
53+
}
54+
EXPORT_SYMBOL(regset_get_alloc);

0 commit comments

Comments
 (0)