summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2012-03-02 10:43:48 -0800
committerWilly Tarreau <w@1wt.eu>2012-03-17 11:14:50 +0100
commitfe8b46f4a788b8433237757cb941c6cdf5c0ed5d (patch)
tree7420b1b2005aaf7e764e6482c3348dfc6b7dc99e
parent559d6c822ef8336d2e8428432543576f59b2de3a (diff)
downloadlwn-fe8b46f4a788b8433237757cb941c6cdf5c0ed5d.tar.gz
lwn-fe8b46f4a788b8433237757cb941c6cdf5c0ed5d.zip
regset: Prevent null pointer reference on readonly regsets
commit c8e252586f8d5de906385d8cf6385fee289a825e upstream. The regset common infrastructure assumed that regsets would always have .get and .set methods, but not necessarily .active methods. Unfortunately people have since written regsets without .set methods. Rather than putting in stub functions everywhere, handle regsets with null .get or .set methods explicitly. Signed-off-by: H. Peter Anvin <hpa@zytor.com> Reviewed-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Roland McGrath <roland@hack.frob.com> Cc: <stable@vger.kernel.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r--fs/binfmt_elf.c2
-rw-r--r--include/linux/regset.h6
2 files changed, 7 insertions, 1 deletions
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 1ed37ba72343..a64fde6c626e 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1452,7 +1452,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,
for (i = 1; i < view->n; ++i) {
const struct user_regset *regset = &view->regsets[i];
do_thread_regset_writeback(t->task, regset);
- if (regset->core_note_type &&
+ if (regset->core_note_type && regset->get &&
(!regset->active || regset->active(t->task, regset))) {
int ret;
size_t size = regset->n * regset->size;
diff --git a/include/linux/regset.h b/include/linux/regset.h
index 8abee6556223..5150fd16ef93 100644
--- a/include/linux/regset.h
+++ b/include/linux/regset.h
@@ -335,6 +335,9 @@ static inline int copy_regset_to_user(struct task_struct *target,
{
const struct user_regset *regset = &view->regsets[setno];
+ if (!regset->get)
+ return -EOPNOTSUPP;
+
if (!access_ok(VERIFY_WRITE, data, size))
return -EIO;
@@ -358,6 +361,9 @@ static inline int copy_regset_from_user(struct task_struct *target,
{
const struct user_regset *regset = &view->regsets[setno];
+ if (!regset->set)
+ return -EOPNOTSUPP;
+
if (!access_ok(VERIFY_READ, data, size))
return -EIO;