aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dlm
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2009-03-04 12:17:23 -0500
committerDavid Teigland <teigland@redhat.com>2009-03-11 13:23:59 -0400
commit1fecb1c4b62881e3689ba2dcf93072ae301b597c (patch)
treebd0a111ea40bfaa0697e7b0c341660cd970a23a3 /fs/dlm
parenta536e38125fe5da8ed49690f30c30a8f651cf1f5 (diff)
dlm: fix length calculation in compat code
Using offsetof() to calculate name length does not work because it does not produce consistent results with with structure packing. This caused memcpy to corrupt memory by copying 4 extra bytes off the end of the buffer on 64 bit kernels with 32 bit userspace (the only case where this 32/64 compat code is used). The fix is to calculate name length directly from the start instead of trying to derive it later using count and offsetof. Signed-off-by: David Teigland <teigland@redhat.com>
Diffstat (limited to 'fs/dlm')
-rw-r--r--fs/dlm/user.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index 065149e84f42..ebce994ab0b7 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved. 2 * Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved.
3 * 3 *
4 * This copyrighted material is made available to anyone wishing to use, 4 * This copyrighted material is made available to anyone wishing to use,
5 * modify, copy, or redistribute it subject to the terms and conditions 5 * modify, copy, or redistribute it subject to the terms and conditions
@@ -84,7 +84,7 @@ struct dlm_lock_result32 {
84 84
85static void compat_input(struct dlm_write_request *kb, 85static void compat_input(struct dlm_write_request *kb,
86 struct dlm_write_request32 *kb32, 86 struct dlm_write_request32 *kb32,
87 size_t count) 87 int namelen)
88{ 88{
89 kb->version[0] = kb32->version[0]; 89 kb->version[0] = kb32->version[0];
90 kb->version[1] = kb32->version[1]; 90 kb->version[1] = kb32->version[1];
@@ -96,8 +96,7 @@ static void compat_input(struct dlm_write_request *kb,
96 kb->cmd == DLM_USER_REMOVE_LOCKSPACE) { 96 kb->cmd == DLM_USER_REMOVE_LOCKSPACE) {
97 kb->i.lspace.flags = kb32->i.lspace.flags; 97 kb->i.lspace.flags = kb32->i.lspace.flags;
98 kb->i.lspace.minor = kb32->i.lspace.minor; 98 kb->i.lspace.minor = kb32->i.lspace.minor;
99 memcpy(kb->i.lspace.name, kb32->i.lspace.name, count - 99 memcpy(kb->i.lspace.name, kb32->i.lspace.name, namelen);
100 offsetof(struct dlm_write_request32, i.lspace.name));
101 } else if (kb->cmd == DLM_USER_PURGE) { 100 } else if (kb->cmd == DLM_USER_PURGE) {
102 kb->i.purge.nodeid = kb32->i.purge.nodeid; 101 kb->i.purge.nodeid = kb32->i.purge.nodeid;
103 kb->i.purge.pid = kb32->i.purge.pid; 102 kb->i.purge.pid = kb32->i.purge.pid;
@@ -115,8 +114,7 @@ static void compat_input(struct dlm_write_request *kb,
115 kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr; 114 kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr;
116 kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb; 115 kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb;
117 memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN); 116 memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN);
118 memcpy(kb->i.lock.name, kb32->i.lock.name, count - 117 memcpy(kb->i.lock.name, kb32->i.lock.name, namelen);
119 offsetof(struct dlm_write_request32, i.lock.name));
120 } 118 }
121} 119}
122 120
@@ -539,9 +537,16 @@ static ssize_t device_write(struct file *file, const char __user *buf,
539#ifdef CONFIG_COMPAT 537#ifdef CONFIG_COMPAT
540 if (!kbuf->is64bit) { 538 if (!kbuf->is64bit) {
541 struct dlm_write_request32 *k32buf; 539 struct dlm_write_request32 *k32buf;
540 int namelen = 0;
541
542 if (count > sizeof(struct dlm_write_request32))
543 namelen = count - sizeof(struct dlm_write_request32);
544
542 k32buf = (struct dlm_write_request32 *)kbuf; 545 k32buf = (struct dlm_write_request32 *)kbuf;
543 kbuf = kmalloc(count + 1 + (sizeof(struct dlm_write_request) - 546
544 sizeof(struct dlm_write_request32)), GFP_KERNEL); 547 /* add 1 after namelen so that the name string is terminated */
548 kbuf = kzalloc(sizeof(struct dlm_write_request) + namelen + 1,
549 GFP_KERNEL);
545 if (!kbuf) { 550 if (!kbuf) {
546 kfree(k32buf); 551 kfree(k32buf);
547 return -ENOMEM; 552 return -ENOMEM;
@@ -549,7 +554,8 @@ static ssize_t device_write(struct file *file, const char __user *buf,
549 554
550 if (proc) 555 if (proc)
551 set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags); 556 set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags);
552 compat_input(kbuf, k32buf, count + 1); 557
558 compat_input(kbuf, k32buf, namelen);
553 kfree(k32buf); 559 kfree(k32buf);
554 } 560 }
555#endif 561#endif