[rds-devel] Linux RDS socket : OOB Write in rds_message_alloc_sgs()
Santosh Shilimkar
santosh.shilimkar at oracle.com
Tue Jan 2 09:38:33 PST 2018
The fix is in mainline and marked for stable but am not sure
if it will get back-ported all the way.
https://patchwork.kernel.org/patch/10128783/
On 1/2/2018 8:23 AM, Mohamed Ghannam wrote:
> Hi,
>
> I reported this bug a while ago and still have no answer, so this mail
> is just a reminder and making sure that it's been well received,
>
> Cheers,
> Mohamed
>
> 2017-12-17 12:44 GMT+00:00 Mohamed Ghannam <simo.ghannam at gmail.com
> <mailto:simo.ghannam at gmail.com>>:
>
> Hi,
>
> Here is a bug I found in RDS socket, it's an Out of bound write
> The vulnerability affects Linux Kernel from v2.6.29-rc6 to the
> latest version, it's been introduced in this commit
> eff5f53bef75c0864a5da06bb688939092b848dc
>
> The vulnerability occurs when we deal with ancullary data (through
> cmsghdr)
>
> int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t
> payload_len)
> {
> ...
>
> /* size of rm including all sgs */
> ret = rds_rm_size(msg, payload_len);<--- (1)
> if (ret < 0)
> goto out;
> ...
> ...
> ret = rds_cmsg_send(rs, rm, msg, &allocated_mr);<----- (3)
> ...
> }
>
> ---
> int rds_rdma_extra_size(struct rds_rdma_args *args)
> {
> ...
> int tot_pages = 0;
> ...
> local_vec = (struct rds_iovec __user *)(unsigned long)
> args->local_vec_addr;
>
> /* figure out the number of pages in the vector */
> for (i = 0; i < args->nr_local; i++) {<---- (3)
> if (copy_from_user(&vec, &local_vec[i],
> sizeof(struct rds_iovec)))
> return -EFAULT;
>
> ...
> /* skipped */
> }
>
> return tot_pages * sizeof(struct scatterlist); <----- (4) :
> tot_pages = 0;
> }
> ----
> (1) - rds_rm_size() does some sanity checks and return the number of
> pages should be allocated for the buffer.
> (2) - rds_cmsg_send() parse the cmsghdr structure and call the
> appropriate function to handle the packet
> (3) - in rds_rm_size() calls rds_rdma_extra_size(), when
> cmsg->cmsg_types has RDS_CMSG_RDMA_ARGS , args is a user
> controllable object, these line of codes (in the loop) are never
> reached when nr_local = 0
> (4) - if we put nr_local to zero the former function returns 0 due
> tot_page= 0;
>
> int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
> struct cmsghdr *cmsg)
> {
> ...
>
> op->op_sg = rds_message_alloc_sgs(rm, nr_pages); <---- (5)
> if (!op->op_sg) {
> ret = -ENOMEM;
> goto out;
> }
> ...
> ...
> }
> ---
>
> void sg_init_table(struct scatterlist *sgl, unsigned int nents)
> {
> memset(sgl, 0, sizeof(*sgl) * nents);
> #ifdef CONFIG_DEBUG_SG
> {
> unsigned int i;
> for (i = 0; i < nents; i++)
> sgl[i].sg_magic = SG_MAGIC;
> }
> #endif
> sg_mark_end(&sgl[nents - 1]);<----- (6)
> }
>
> (5) - rds_message_alloc_sgs() allocates pages for DMA , and keep in
> mind that nr_pages still has 0
> (6) - sg_init_table is called from rds_message_alloc_sgs(), it tries
> to initialize the buffer for the incoming packets, the function
> doesn't check 'nents' variable (which is nr_pages=0) .
> by decrementing nents by 1, it gives huge invalid integer (integer
> underflow) which is used as index in the scatterlist array,
>
>
> I've attached also a proof of concept code that crashes the kernel
> as well as the panic log
>
> Bests,
> Mohamed
>
>
>
>
>
More information about the rds-devel
mailing list