[PATCH rdma-rc] IB/core: Fix potential NULL pointer dereference in pkey cache

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Jack Morgenstein <jackm@xxxxxxxxxxxxxxxxxx>

The IB core pkey cache is populated by procedure ib_cache_update().
Initially, the pkey cache pointer is NULL. ib_cache_update allocates
a buffer and populates it with the device's pkeys, via repeated calls
to procedure ib_query_pkey().

If there is a failure in populating the pkey buffer via ib_query_pkey(),
ib_cache_update does not replace the old pkey buffer cache with the
updated one -- it leaves the old cache as is.

Since initially the pkey buffer cache is NULL, when calling
ib_cache_update the first time, a failure in ib_query_pkey() will cause
the pkey buffer cache pointer to remain NULL.

In this situation, any calls subsequent to ib_get_cached_pkey(),
ib_find_cached_pkey(), or ib_find_cached_pkey_exact() will try to
dereference the NULL pkey cache pointer, causing a kernel panic.

Fix this by testing if the cache pointer is NULL. If yes,
return -ENOENT.

Fixes: 8faea9fd4a39 ("RDMA/cache: Move the cache per-port data into the main ib_port_data")
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Jack Morgenstein <jackm@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Leon Romanovsky <leonro@xxxxxxxxxxxx>
---
 drivers/infiniband/core/cache.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index 717b798cddad..4263a482ecab 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -1054,11 +1054,17 @@ int ib_get_cached_pkey(struct ib_device *device,
 
 	cache = device->port_data[port_num].cache.pkey;
 
+	if (!cache) {
+		ret = -ENOENT;
+		goto out;
+	}
+
 	if (index < 0 || index >= cache->table_len)
 		ret = -EINVAL;
 	else
 		*pkey = cache->table[index];
 
+out:
 	read_unlock_irqrestore(&device->cache_lock, flags);
 
 	return ret;
@@ -1101,6 +1107,8 @@ int ib_find_cached_pkey(struct ib_device *device,
 	cache = device->port_data[port_num].cache.pkey;
 
 	*index = -1;
+	if (!cache)
+		goto out;
 
 	for (i = 0; i < cache->table_len; ++i)
 		if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) {
@@ -1117,6 +1125,7 @@ int ib_find_cached_pkey(struct ib_device *device,
 		ret = 0;
 	}
 
+out:
 	read_unlock_irqrestore(&device->cache_lock, flags);
 
 	return ret;
@@ -1141,6 +1150,8 @@ int ib_find_exact_cached_pkey(struct ib_device *device,
 	cache = device->port_data[port_num].cache.pkey;
 
 	*index = -1;
+	if (!cache)
+		goto out;
 
 	for (i = 0; i < cache->table_len; ++i)
 		if (cache->table[i] == pkey) {
@@ -1149,6 +1160,7 @@ int ib_find_exact_cached_pkey(struct ib_device *device,
 			break;
 		}
 
+out:
 	read_unlock_irqrestore(&device->cache_lock, flags);
 
 	return ret;
-- 
2.25.3




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux