From: Viacheslav Dubeyko Date: Wed, 4 Jun 2025 22:41:06 +0000 (-0700) Subject: ceph: fix overflowed value issue in ceph_submit_write() X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=9233d2c1fd2d072e9d85e14c2adb804df28c8c23;p=ceph-client.git ceph: fix overflowed value issue in ceph_submit_write() The Coverity Scan service has detected overflowed value issue in ceph_submit_write() [1]. The CID 1646339 defect contains explanation: "The overflowed value due to arithmetic on constants is too small or unexpectedly negative, causing incorrect computations. In ceph_submit_write: Integer overflow occurs in arithmetic on constant operands (CWE-190)". This patch adds a check ceph_wbc->locked_pages on equality to zero and it exits function if it has zero value. Also, it introduces a processed_pages variable with the goal of assigning the number of processed pages and checking this number on equality to zero. The check of processed_pages variable on equality to zero should protect from overflowed value of index that selects page in ceph_wbc->pages[index] array. [1] https://scan5.scan.coverity.com/#/project-view/64304/10063?selectedIssue=1646339 Signed-off-by: Viacheslav Dubeyko --- diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 5a5751156f8b..a4ffa2b63184 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1418,6 +1418,7 @@ int ceph_submit_write(struct address_space *mapping, bool caching = ceph_is_cache_enabled(inode); u64 offset; u64 len; + unsigned processed_pages; unsigned i; new_request: @@ -1445,6 +1446,9 @@ new_request: BUG_ON(IS_ERR(req)); } + if (ceph_wbc->locked_pages == 0) + return -EINVAL; + page = ceph_wbc->pages[ceph_wbc->locked_pages - 1]; BUG_ON(len < ceph_fscrypt_page_offset(page) + thp_size(page) - offset); @@ -1481,6 +1485,7 @@ new_request: len = 0; ceph_wbc->data_pages = ceph_wbc->pages; ceph_wbc->op_idx = 0; + processed_pages = 0; for (i = 0; i < ceph_wbc->locked_pages; i++) { u64 cur_offset; @@ -1524,19 +1529,22 @@ new_request: ceph_set_page_fscache(page); len += thp_size(page); + processed_pages++; } ceph_fscache_write_to_cache(inode, offset, len, caching); if (ceph_wbc->size_stable) { len = min(len, ceph_wbc->i_size - offset); - } else if (i == ceph_wbc->locked_pages) { + } else if (processed_pages > 0 && + processed_pages == ceph_wbc->locked_pages) { /* writepages_finish() clears writeback pages * according to the data length, so make sure * data length covers all locked pages */ u64 min_len = len + 1 - thp_size(page); + unsigned index = processed_pages - 1; len = get_writepages_data_length(inode, - ceph_wbc->pages[i - 1], + ceph_wbc->pages[index], offset); len = max(len, min_len); } @@ -1561,17 +1569,17 @@ new_request: BUG_ON(ceph_wbc->op_idx + 1 != req->r_num_ops); ceph_wbc->from_pool = false; - if (i < ceph_wbc->locked_pages) { + if (processed_pages < ceph_wbc->locked_pages) { BUG_ON(ceph_wbc->num_ops <= req->r_num_ops); ceph_wbc->num_ops -= req->r_num_ops; - ceph_wbc->locked_pages -= i; + ceph_wbc->locked_pages -= processed_pages; /* allocate new pages array for next request */ ceph_wbc->data_pages = ceph_wbc->pages; __ceph_allocate_page_array(ceph_wbc, ceph_wbc->locked_pages); - memcpy(ceph_wbc->pages, ceph_wbc->data_pages + i, + memcpy(ceph_wbc->pages, ceph_wbc->data_pages + processed_pages, ceph_wbc->locked_pages * sizeof(*ceph_wbc->pages)); - memset(ceph_wbc->data_pages + i, 0, + memset(ceph_wbc->data_pages + processed_pages, 0, ceph_wbc->locked_pages * sizeof(*ceph_wbc->pages)); } else { BUG_ON(ceph_wbc->num_ops != req->r_num_ops); @@ -1583,7 +1591,7 @@ new_request: ceph_osdc_start_request(&fsc->client->osdc, req); req = NULL; - wbc->nr_to_write -= i; + wbc->nr_to_write -= processed_pages; if (ceph_wbc->pages) goto new_request;