Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

taskstats: don't allow duplicate entries in listener mode

Currently a single process may register exit handlers unlimited times.
It may lead to a bloated listeners chain and very slow process
terminations.

Eg after 10KK sent TASKSTATS_CMD_ATTR_REGISTER_CPUMASKs ~300 Mb of
kernel memory is stolen for the handlers chain and "time id" shows 2-7
seconds instead of normal 0.003. It makes it possible to exhaust all
kernel memory and to eat much of CPU time by triggerring numerous exits
on a single CPU.

The patch limits the number of times a single process may register
itself on a single CPU to one.

One little issue is kept unfixed - as taskstats_exit() is called before
exit_files() in do_exit(), the orphaned listener entry (if it was not
explicitly deregistered) is kept until the next someone's exit() and
implicit deregistration in send_cpu_listeners(). So, if a process
registered itself as a listener exits and the next spawned process gets
the same pid, it would inherit taskstats attributes.

Signed-off-by: Vasiliy Kulikov <segooon@gmail.com>
Cc: Balbir Singh <bsingharora@gmail.com>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Vasiliy Kulikov and committed by
Linus Torvalds
26c4caea 08142579

+12 -3
+12 -3
kernel/taskstats.c
··· 285 285 static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd) 286 286 { 287 287 struct listener_list *listeners; 288 - struct listener *s, *tmp; 288 + struct listener *s, *tmp, *s2; 289 289 unsigned int cpu; 290 290 291 291 if (!cpumask_subset(mask, cpu_possible_mask)) 292 292 return -EINVAL; 293 293 294 + s = NULL; 294 295 if (isadd == REGISTER) { 295 296 for_each_cpu(cpu, mask) { 296 - s = kmalloc_node(sizeof(struct listener), GFP_KERNEL, 297 - cpu_to_node(cpu)); 297 + if (!s) 298 + s = kmalloc_node(sizeof(struct listener), 299 + GFP_KERNEL, cpu_to_node(cpu)); 298 300 if (!s) 299 301 goto cleanup; 300 302 s->pid = pid; ··· 305 303 306 304 listeners = &per_cpu(listener_array, cpu); 307 305 down_write(&listeners->sem); 306 + list_for_each_entry_safe(s2, tmp, &listeners->list, list) { 307 + if (s2->pid == pid) 308 + goto next_cpu; 309 + } 308 310 list_add(&s->list, &listeners->list); 311 + s = NULL; 312 + next_cpu: 309 313 up_write(&listeners->sem); 310 314 } 315 + kfree(s); 311 316 return 0; 312 317 } 313 318