Skip to content

Commit 4c1d3d2

Browse files
committed
mi: fix get_log_page chunked offset check
In our get_log_page helper, we're incorrectly checking the requested chunk offset against the chunk len, rather than the overall length - this means we can't query anything but the first chunk. This change fixes this to check against the overall length instead, and adds an additional check to ensure we're not requesting more than the full data size. We also add a testcase for the chunking code. Reported-by: Hao Jiang <[email protected]> Signed-off-by: Jeremy Kerr <[email protected]>
1 parent 86edb55 commit 4c1d3d2

2 files changed

Lines changed: 82 additions & 1 deletion

File tree

src/nvme/mi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ static int __nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl,
498498
return -1;
499499
}
500500

501-
if (offset < 0 || offset >= len) {
501+
if (offset < 0 || offset >= args->len || offset + len > args->len) {
502502
errno = EINVAL;
503503
return -1;
504504
}

test/mi.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,86 @@ static void test_admin_sanitize_nvm(struct nvme_mi_ep *ep)
16991699
assert(!rc);
17001700
}
17011701

1702+
/* test that we set the correct offset and size on get_log() calls that
1703+
* are split into multiple requests */
1704+
struct log_data {
1705+
int n;
1706+
};
1707+
1708+
static int test_admin_get_log_split_cb(struct nvme_mi_ep *ep,
1709+
struct nvme_mi_req *req,
1710+
struct nvme_mi_resp *resp,
1711+
void *data)
1712+
{
1713+
struct log_data *ldata = data;
1714+
uint32_t len, off;
1715+
__u8 *rq_hdr;
1716+
1717+
assert(req->data_len == 0);
1718+
1719+
rq_hdr = (__u8 *)req->hdr;
1720+
1721+
assert(rq_hdr[4] == nvme_admin_get_log_page);
1722+
1723+
/* from the MI message's DOFST/DLEN fields */
1724+
off = rq_hdr[31] << 24 | rq_hdr[30] << 16 | rq_hdr[29] << 8 | rq_hdr[28];
1725+
len = rq_hdr[35] << 24 | rq_hdr[34] << 16 | rq_hdr[33] << 8 | rq_hdr[32];
1726+
1727+
/* we should have a full-sized start and middle, and a short end */
1728+
switch (ldata->n) {
1729+
case 0:
1730+
assert(len == 4096);
1731+
assert(off == 0);
1732+
break;
1733+
case 1:
1734+
assert(len == 4096);
1735+
assert(off == 4096);
1736+
break;
1737+
case 2:
1738+
assert(len == 4);
1739+
assert(off == 4096 * 2);
1740+
break;
1741+
default:
1742+
assert(0);
1743+
}
1744+
1745+
/* ensure we've sized the expected response correctly */
1746+
assert(resp->data_len == len);
1747+
memset(resp->data, ldata->n & 0xff, len);
1748+
1749+
test_transport_resp_calc_mic(resp);
1750+
1751+
ldata->n++;
1752+
1753+
return 0;
1754+
}
1755+
1756+
static void test_admin_get_log_split(struct nvme_mi_ep *ep)
1757+
{
1758+
unsigned char buf[4096 * 2 + 4];
1759+
struct nvme_get_log_args args;
1760+
struct log_data ldata;
1761+
nvme_mi_ctrl_t ctrl;
1762+
int rc;
1763+
1764+
ldata.n = 0;
1765+
test_set_transport_callback(ep, test_admin_get_log_split_cb, &ldata);
1766+
1767+
ctrl = nvme_mi_init_ctrl(ep, 5);
1768+
1769+
args.args_size = sizeof(args);
1770+
args.lid = 1;
1771+
args.log = buf;
1772+
args.len = sizeof(buf);
1773+
1774+
rc = nvme_mi_admin_get_log(ctrl, &args);
1775+
1776+
assert(!rc);
1777+
1778+
/* we should have sent three commands */
1779+
assert(ldata.n == 3);
1780+
}
1781+
17021782
#define DEFINE_TEST(name) { #name, test_ ## name }
17031783
struct test {
17041784
const char *name;
@@ -1738,6 +1818,7 @@ struct test {
17381818
DEFINE_TEST(admin_fw_commit),
17391819
DEFINE_TEST(admin_format_nvm),
17401820
DEFINE_TEST(admin_sanitize_nvm),
1821+
DEFINE_TEST(admin_get_log_split),
17411822
};
17421823

17431824
static void run_test(struct test *test, FILE *logfd, nvme_mi_ep_t ep)

0 commit comments

Comments
 (0)