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 | |
| 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>
| -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 ac1d5b0586ba..d1a121443bde 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; |
