]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: David Teigland <teigland@redhat.com> |
2 | commit 1fecb1c4b62881e3689ba2dcf93072ae301b597c | |
3 | Author: David Teigland <teigland@redhat.com> | |
4 | Date: Wed Mar 4 11:17:23 2009 -0600 | |
5 | Subject: dlm: fix length calculation in compat code | |
6 | ||
7 | Using offsetof() to calculate name length does not work because | |
8 | it does not produce consistent results with with structure packing. | |
9 | This caused memcpy to corrupt memory by copying 4 extra bytes off | |
10 | the end of the buffer on 64 bit kernels with 32 bit userspace | |
11 | (the only case where this 32/64 compat code is used). | |
12 | ||
13 | The fix is to calculate name length directly from the start instead | |
14 | of trying to derive it later using count and offsetof. | |
15 | ||
16 | Signed-off-by: David Teigland <teigland@redhat.com> | |
17 | Signed-off-by: Coly Li <coly.li@suse.de> | |
18 | ||
19 | diff --git a/fs/dlm/user.c b/fs/dlm/user.c | |
20 | index 065149e..ebce994 100644 | |
21 | --- a/fs/dlm/user.c | |
22 | +++ b/fs/dlm/user.c | |
23 | @@ -1,5 +1,5 @@ | |
24 | /* | |
25 | - * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. | |
26 | + * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved. | |
27 | * | |
28 | * This copyrighted material is made available to anyone wishing to use, | |
29 | * modify, copy, or redistribute it subject to the terms and conditions | |
30 | @@ -84,7 +84,7 @@ struct dlm_lock_result32 { | |
31 | ||
32 | static void compat_input(struct dlm_write_request *kb, | |
33 | struct dlm_write_request32 *kb32, | |
34 | - size_t count) | |
35 | + int namelen) | |
36 | { | |
37 | kb->version[0] = kb32->version[0]; | |
38 | kb->version[1] = kb32->version[1]; | |
39 | @@ -96,8 +96,7 @@ static void compat_input(struct dlm_write_request *kb, | |
40 | kb->cmd == DLM_USER_REMOVE_LOCKSPACE) { | |
41 | kb->i.lspace.flags = kb32->i.lspace.flags; | |
42 | kb->i.lspace.minor = kb32->i.lspace.minor; | |
43 | - memcpy(kb->i.lspace.name, kb32->i.lspace.name, count - | |
44 | - offsetof(struct dlm_write_request32, i.lspace.name)); | |
45 | + memcpy(kb->i.lspace.name, kb32->i.lspace.name, namelen); | |
46 | } else if (kb->cmd == DLM_USER_PURGE) { | |
47 | kb->i.purge.nodeid = kb32->i.purge.nodeid; | |
48 | kb->i.purge.pid = kb32->i.purge.pid; | |
49 | @@ -115,8 +114,7 @@ static void compat_input(struct dlm_write_request *kb, | |
50 | kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr; | |
51 | kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb; | |
52 | memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN); | |
53 | - memcpy(kb->i.lock.name, kb32->i.lock.name, count - | |
54 | - offsetof(struct dlm_write_request32, i.lock.name)); | |
55 | + memcpy(kb->i.lock.name, kb32->i.lock.name, namelen); | |
56 | } | |
57 | } | |
58 | ||
59 | @@ -539,9 +537,16 @@ static ssize_t device_write(struct file *file, const char __user *buf, | |
60 | #ifdef CONFIG_COMPAT | |
61 | if (!kbuf->is64bit) { | |
62 | struct dlm_write_request32 *k32buf; | |
63 | + int namelen = 0; | |
64 | + | |
65 | + if (count > sizeof(struct dlm_write_request32)) | |
66 | + namelen = count - sizeof(struct dlm_write_request32); | |
67 | + | |
68 | k32buf = (struct dlm_write_request32 *)kbuf; | |
69 | - kbuf = kmalloc(count + 1 + (sizeof(struct dlm_write_request) - | |
70 | - sizeof(struct dlm_write_request32)), GFP_KERNEL); | |
71 | + | |
72 | + /* add 1 after namelen so that the name string is terminated */ | |
73 | + kbuf = kzalloc(sizeof(struct dlm_write_request) + namelen + 1, | |
74 | + GFP_KERNEL); | |
75 | if (!kbuf) { | |
76 | kfree(k32buf); | |
77 | return -ENOMEM; | |
78 | @@ -549,7 +554,8 @@ static ssize_t device_write(struct file *file, const char __user *buf, | |
79 | ||
80 | if (proc) | |
81 | set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags); | |
82 | - compat_input(kbuf, k32buf, count + 1); | |
83 | + | |
84 | + compat_input(kbuf, k32buf, namelen); | |
85 | kfree(k32buf); | |
86 | } | |
87 | #endif |