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

[PATCH 1/2] proc: fix inode number bogorithmetic

Id which proc gets from IDR for inode number and id which proc removes
from IDR do not match. E.g. 0x11a transforms into 0x8000011a.

Which stayed unnoticed for a long time because, surprise, idr_remove()
masks out that high bit before doing anything.

All of this due to "| ~MAX_ID_MASK" in release_inode_number().

I still don't understand how it's supposed to work, because "| ~MASK"
is not an inversion for "& MAX" operation.

So, use just one nice, working addition. Make start offset unsigned int,
while I'm at it. It's longness is not used anywhere.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

authored by

Alexey Dobriyan and committed by
Al Viro
67935df4 82666020

+9 -12
+9 -12
fs/proc/generic.c
··· 303 303 static DEFINE_IDR(proc_inum_idr); 304 304 static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ 305 305 306 - #define PROC_DYNAMIC_FIRST 0xF0000000UL 306 + #define PROC_DYNAMIC_FIRST 0xF0000000U 307 307 308 308 /* 309 309 * Return an inode number between PROC_DYNAMIC_FIRST and ··· 311 311 */ 312 312 static unsigned int get_inode_number(void) 313 313 { 314 - int i, inum = 0; 314 + unsigned int i; 315 315 int error; 316 316 317 317 retry: ··· 326 326 else if (error) 327 327 return 0; 328 328 329 - inum = (i & MAX_ID_MASK) + PROC_DYNAMIC_FIRST; 330 - 331 - /* inum will never be more than 0xf0ffffff, so no check 332 - * for overflow. 333 - */ 334 - 335 - return inum; 329 + if (i > UINT_MAX - PROC_DYNAMIC_FIRST) { 330 + spin_lock(&proc_inum_lock); 331 + idr_remove(&proc_inum_idr, i); 332 + spin_unlock(&proc_inum_lock); 333 + } 334 + return PROC_DYNAMIC_FIRST + i; 336 335 } 337 336 338 337 static void release_inode_number(unsigned int inum) 339 338 { 340 - int id = (inum - PROC_DYNAMIC_FIRST) | ~MAX_ID_MASK; 341 - 342 339 spin_lock(&proc_inum_lock); 343 - idr_remove(&proc_inum_idr, id); 340 + idr_remove(&proc_inum_idr, inum - PROC_DYNAMIC_FIRST); 344 341 spin_unlock(&proc_inum_lock); 345 342 } 346 343