summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortruckman <truckman@FreeBSD.org>2014-05-12 04:27:10 +0000
committertruckman <truckman@FreeBSD.org>2014-05-12 04:27:10 +0000
commit767aadd2f0488e620b48656816358c402c82bb63 (patch)
tree5668e79b5ce7c6f8680b247444ca48f386152af6
parent69470d28bf26ee56ca50f7ff517ef29f908c108c (diff)
downloadFreeBSD-src-767aadd2f0488e620b48656816358c402c82bb63.zip
FreeBSD-src-767aadd2f0488e620b48656816358c402c82bb63.tar.gz
MFC r265363
Avoid unsigned integer overflow which can cause rman_reserve_resource_bound() to return incorrect results. Continue the initial search until the first viable region is found. Add a comment to explain the search termination test. PR: kern/188534 Reviewed by: jhb (previous version)
-rw-r--r--sys/kern/subr_rman.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/sys/kern/subr_rman.c b/sys/kern/subr_rman.c
index e43dfcf..30e97c3 100644
--- a/sys/kern/subr_rman.c
+++ b/sys/kern/subr_rman.c
@@ -456,7 +456,7 @@ rman_reserve_resource_bound(struct rman *rm, u_long start, u_long end,
mtx_lock(rm->rm_mtx);
for (r = TAILQ_FIRST(&rm->rm_list);
- r && r->r_end < start;
+ r && r->r_end < start + count - 1;
r = TAILQ_NEXT(r, r_link))
;
@@ -466,6 +466,11 @@ rman_reserve_resource_bound(struct rman *rm, u_long start, u_long end,
}
amask = (1ul << RF_ALIGNMENT(flags)) - 1;
+ if (start + amask < start) {
+ DPRINTF(("start+amask wrapped around\n"));
+ goto out;
+ }
+
/* If bound is 0, bmask will also be 0 */
bmask = ~(bound - 1);
/*
@@ -473,11 +478,20 @@ rman_reserve_resource_bound(struct rman *rm, u_long start, u_long end,
*/
for (s = r; s; s = TAILQ_NEXT(s, r_link)) {
DPRINTF(("considering [%#lx, %#lx]\n", s->r_start, s->r_end));
- if (s->r_start + count - 1 > end) {
+ /*
+ * The resource list is sorted, so there is no point in
+ * searching further once r_start is too large.
+ */
+ if (s->r_start > end - (count - 1)) {
DPRINTF(("s->r_start (%#lx) + count - 1> end (%#lx)\n",
s->r_start, end));
break;
}
+ if (s->r_start + amask < s->r_start) {
+ DPRINTF(("s->r_start (%#lx) + amask (%#lx) wrapped\n",
+ s->r_start, amask));
+ break;
+ }
if (s->r_flags & RF_ALLOCATED) {
DPRINTF(("region is allocated\n"));
continue;
OpenPOWER on IntegriCloud