diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-11-18 09:23:08 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-11-18 09:34:36 -0500 |
commit | 10db4ef7b9a65b86e4d047671a1886f4c101a859 (patch) | |
tree | 2d47105e6cf1e88c5a83def331c5d6302578e607 /arch/x86/kernel/ds.c | |
parent | 93ce99e849433ede4ce8b410b749dc0cad1100b2 (diff) |
x86, PEBS/DS: fix code flow in ds_request()
this compiler warning:
arch/x86/kernel/ds.c: In function 'ds_request':
arch/x86/kernel/ds.c:368: warning: 'context' may be used uninitialized in this function
Shows that the code flow in ds_request() is buggy - it goes into
the unlock+release-context path even when the context is not allocated
yet.
First allocate the context, then do the other checks.
Also, take care with GFP allocations under the ds_lock spinlock.
Cc: <stable@kernel.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/ds.c')
-rw-r--r-- | arch/x86/kernel/ds.c | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c index ac1d5b0586b..d1a121443bd 100644 --- a/arch/x86/kernel/ds.c +++ b/arch/x86/kernel/ds.c | |||
@@ -236,17 +236,33 @@ static inline struct ds_context *ds_alloc_context(struct task_struct *task) | |||
236 | struct ds_context *context = *p_context; | 236 | struct ds_context *context = *p_context; |
237 | 237 | ||
238 | if (!context) { | 238 | if (!context) { |
239 | spin_unlock(&ds_lock); | ||
240 | |||
239 | context = kzalloc(sizeof(*context), GFP_KERNEL); | 241 | context = kzalloc(sizeof(*context), GFP_KERNEL); |
240 | 242 | ||
241 | if (!context) | 243 | if (!context) { |
244 | spin_lock(&ds_lock); | ||
242 | return NULL; | 245 | return NULL; |
246 | } | ||
243 | 247 | ||
244 | context->ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL); | 248 | context->ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL); |
245 | if (!context->ds) { | 249 | if (!context->ds) { |
246 | kfree(context); | 250 | kfree(context); |
251 | spin_lock(&ds_lock); | ||
247 | return NULL; | 252 | return NULL; |
248 | } | 253 | } |
249 | 254 | ||
255 | spin_lock(&ds_lock); | ||
256 | /* | ||
257 | * Check for race - another CPU could have allocated | ||
258 | * it meanwhile: | ||
259 | */ | ||
260 | if (*p_context) { | ||
261 | kfree(context->ds); | ||
262 | kfree(context); | ||
263 | return *p_context; | ||
264 | } | ||
265 | |||
250 | *p_context = context; | 266 | *p_context = context; |
251 | 267 | ||
252 | context->this = p_context; | 268 | context->this = p_context; |
@@ -384,15 +400,15 @@ static int ds_request(struct task_struct *task, void *base, size_t size, | |||
384 | 400 | ||
385 | spin_lock(&ds_lock); | 401 | spin_lock(&ds_lock); |
386 | 402 | ||
387 | error = -EPERM; | ||
388 | if (!check_tracer(task)) | ||
389 | goto out_unlock; | ||
390 | |||
391 | error = -ENOMEM; | 403 | error = -ENOMEM; |
392 | context = ds_alloc_context(task); | 404 | context = ds_alloc_context(task); |
393 | if (!context) | 405 | if (!context) |
394 | goto out_unlock; | 406 | goto out_unlock; |
395 | 407 | ||
408 | error = -EPERM; | ||
409 | if (!check_tracer(task)) | ||
410 | goto out_unlock; | ||
411 | |||
396 | error = -EALREADY; | 412 | error = -EALREADY; |
397 | if (context->owner[qual] == current) | 413 | if (context->owner[qual] == current) |
398 | goto out_unlock; | 414 | goto out_unlock; |