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

proc: save 2 atomic ops on write to "/proc/*/attr/*"

Code checks if write is done by current to its own attributes.
For that get/put pair is unnecessary as it can be done under RCU.

Note: rcu_read_unlock() can be done even earlier since pointer to a task
is not dereferenced. It depends if /proc code should look scary or not:

rcu_read_lock();
task = pid_task(...);
rcu_read_unlock();
if (!task)
return -ESRCH;
if (task != current)
return -EACCESS:

P.S.: rename "length" variable. Code like this

length = -EINVAL;

should not exist.

Link: http://lkml.kernel.org/r/20180627200218.GF18113@avx2
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Alexey Dobriyan and committed by
Linus Torvalds
41089b6d a44937fe

+19 -19
+19 -19
fs/proc/base.c
··· 2517 2517 size_t count, loff_t *ppos) 2518 2518 { 2519 2519 struct inode * inode = file_inode(file); 2520 + struct task_struct *task; 2520 2521 void *page; 2521 - ssize_t length; 2522 - struct task_struct *task = get_proc_task(inode); 2522 + int rv; 2523 2523 2524 - length = -ESRCH; 2525 - if (!task) 2526 - goto out_no_task; 2527 - 2524 + rcu_read_lock(); 2525 + task = pid_task(proc_pid(inode), PIDTYPE_PID); 2526 + if (!task) { 2527 + rcu_read_unlock(); 2528 + return -ESRCH; 2529 + } 2528 2530 /* A task may only write its own attributes. */ 2529 - length = -EACCES; 2530 - if (current != task) 2531 - goto out; 2531 + if (current != task) { 2532 + rcu_read_unlock(); 2533 + return -EACCES; 2534 + } 2535 + rcu_read_unlock(); 2532 2536 2533 2537 if (count > PAGE_SIZE) 2534 2538 count = PAGE_SIZE; 2535 2539 2536 2540 /* No partial writes. */ 2537 - length = -EINVAL; 2538 2541 if (*ppos != 0) 2539 - goto out; 2542 + return -EINVAL; 2540 2543 2541 2544 page = memdup_user(buf, count); 2542 2545 if (IS_ERR(page)) { 2543 - length = PTR_ERR(page); 2546 + rv = PTR_ERR(page); 2544 2547 goto out; 2545 2548 } 2546 2549 2547 2550 /* Guard against adverse ptrace interaction */ 2548 - length = mutex_lock_interruptible(&current->signal->cred_guard_mutex); 2549 - if (length < 0) 2551 + rv = mutex_lock_interruptible(&current->signal->cred_guard_mutex); 2552 + if (rv < 0) 2550 2553 goto out_free; 2551 2554 2552 - length = security_setprocattr(file->f_path.dentry->d_name.name, 2553 - page, count); 2555 + rv = security_setprocattr(file->f_path.dentry->d_name.name, page, count); 2554 2556 mutex_unlock(&current->signal->cred_guard_mutex); 2555 2557 out_free: 2556 2558 kfree(page); 2557 2559 out: 2558 - put_task_struct(task); 2559 - out_no_task: 2560 - return length; 2560 + return rv; 2561 2561 } 2562 2562 2563 2563 static const struct file_operations proc_pid_attr_operations = {