| From 0e717b3cde059ed0f2c9595b455ecfef4a6e4369 Mon Sep 17 00:00:00 2001 |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| Date: Mon, 18 Apr 2011 10:35:30 -0700 |
| Subject: [PATCH] next_pidmap: fix overflow condition |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| commit c78193e9c7bcbf25b8237ad0dec82f805c4ea69b upstream. |
| |
| next_pidmap() just quietly accepted whatever 'last' pid that was passed |
| in, which is not all that safe when one of the users is /proc. |
| |
| Admittedly the proc code should do some sanity checking on the range |
| (and that will be the next commit), but that doesn't mean that the |
| helper functions should just do that pidmap pointer arithmetic without |
| checking the range of its arguments. |
| |
| So clamp 'last' to PID_MAX_LIMIT. The fact that we then do "last+1" |
| doesn't really matter, the for-loop does check against the end of the |
| pidmap array properly (it's only the actual pointer arithmetic overflow |
| case we need to worry about, and going one bit beyond isn't going to |
| overflow). |
| |
| [ Use PID_MAX_LIMIT rather than pid_max as per Eric Biederman ] |
| |
| Reported-by: Tavis Ormandy <taviso@cmpxchg8b.com> |
| Analyzed-by: Robert Święcki <robert@swiecki.net> |
| Cc: Eric W. Biederman <ebiederm@xmission.com> |
| Cc: Pavel Emelyanov <xemul@openvz.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/include/linux/pid.h b/include/linux/pid.h |
| index 49f1c2f..ec9f2df 100644 |
| --- a/include/linux/pid.h |
| +++ b/include/linux/pid.h |
| @@ -117,7 +117,7 @@ extern struct pid *find_vpid(int nr); |
| */ |
| extern struct pid *find_get_pid(int nr); |
| extern struct pid *find_ge_pid(int nr, struct pid_namespace *); |
| -int next_pidmap(struct pid_namespace *pid_ns, int last); |
| +int next_pidmap(struct pid_namespace *pid_ns, unsigned int last); |
| |
| extern struct pid *alloc_pid(struct pid_namespace *ns); |
| extern void free_pid(struct pid *pid); |
| diff --git a/kernel/pid.c b/kernel/pid.c |
| index aebb30d..af8dbf7 100644 |
| --- a/kernel/pid.c |
| +++ b/kernel/pid.c |
| @@ -183,11 +183,14 @@ static int alloc_pidmap(struct pid_namespace *pid_ns) |
| return -1; |
| } |
| |
| -int next_pidmap(struct pid_namespace *pid_ns, int last) |
| +int next_pidmap(struct pid_namespace *pid_ns, unsigned int last) |
| { |
| int offset; |
| struct pidmap *map, *end; |
| |
| + if (last >= PID_MAX_LIMIT) |
| + return -1; |
| + |
| offset = (last + 1) & BITS_PER_PAGE_MASK; |
| map = &pid_ns->pidmap[(last + 1)/BITS_PER_PAGE]; |
| end = &pid_ns->pidmap[PIDMAP_ENTRIES]; |
| -- |
| 1.7.4.4 |
| |