From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 56FB21C29 for ; Wed, 23 Nov 2022 09:36:13 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id C5C2BC433D6; Wed, 23 Nov 2022 09:36:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1669196173; bh=rgv76EAj6y1TwWLL6HPev9a2GTSvsfHAMNWgjMhrsdE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nihAW5HVoH8uN/DaXo2lmCMS0qC6BPN/ytl3leGejoyS1kjWdigxLrc0s1+HGAnoP ZfSe0luzITgciaWY4/sA2/aJBgziGz0Wp5ZlWxlTmyZZnIbJFhDNPdPZkw1qJiaauE epvT0JsQyogu5z3rskkmNuM28/+xseiXSMsoG3+Q= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Mikulas Patocka , Mike Snitzer Subject: [PATCH 5.15 140/181] dm ioctl: fix misbehavior if list_versions races with module loading Date: Wed, 23 Nov 2022 09:51:43 +0100 Message-Id: <20221123084608.396027201@linuxfoundation.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221123084602.707860461@linuxfoundation.org> References: <20221123084602.707860461@linuxfoundation.org> User-Agent: quilt/0.67 Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Mikulas Patocka commit 4fe1ec995483737f3d2a14c3fe1d8fe634972979 upstream. __list_versions will first estimate the required space using the "dm_target_iterate(list_version_get_needed, &needed)" call and then will fill the space using the "dm_target_iterate(list_version_get_info, &iter_info)" call. Each of these calls locks the targets using the "down_read(&_lock)" and "up_read(&_lock)" calls, however between the first and second "dm_target_iterate" there is no lock held and the target modules can be loaded at this point, so the second "dm_target_iterate" call may need more space than what was the first "dm_target_iterate" returned. The code tries to handle this overflow (see the beginning of list_version_get_info), however this handling is incorrect. The code sets "param->data_size = param->data_start + needed" and "iter_info.end = (char *)vers+len" - "needed" is the size returned by the first dm_target_iterate call; "len" is the size of the buffer allocated by userspace. "len" may be greater than "needed"; in this case, the code will write up to "len" bytes into the buffer, however param->data_size is set to "needed", so it may write data past the param->data_size value. The ioctl interface copies only up to param->data_size into userspace, thus part of the result will be truncated. Fix this bug by setting "iter_info.end = (char *)vers + needed;" - this guarantees that the second "dm_target_iterate" call will write only up to the "needed" buffer and it will exit with "DM_BUFFER_FULL_FLAG" if it overflows the "needed" space - in this case, userspace will allocate a larger buffer and retry. Note that there is also a bug in list_version_get_needed - we need to add "strlen(tt->name) + 1" to the needed size, not "strlen(tt->name)". Cc: stable@vger.kernel.org Signed-off-by: Mikulas Patocka Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-ioctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -655,7 +655,7 @@ static void list_version_get_needed(stru size_t *needed = needed_param; *needed += sizeof(struct dm_target_versions); - *needed += strlen(tt->name); + *needed += strlen(tt->name) + 1; *needed += ALIGN_MASK; } @@ -720,7 +720,7 @@ static int __list_versions(struct dm_ioc iter_info.old_vers = NULL; iter_info.vers = vers; iter_info.flags = 0; - iter_info.end = (char *)vers+len; + iter_info.end = (char *)vers + needed; /* * Now loop through filling out the names & versions.