[lustre-devel] [bug report] staging: add Lustre file system client support
Dan Carpenter
dan.carpenter at oracle.com
Tue Dec 6 03:02:59 PST 2016
On Mon, Dec 05, 2016 at 06:43:37PM -0500, Oleg Drokin wrote:
>
> On Nov 23, 2016, at 7:29 AM, Dan Carpenter wrote:
>
> > Hi Lustre Devs,
> >
> > The patch d7e09d0397e8: "staging: add Lustre file system client
> > support" from May 2, 2013, leads to the following static checker
> > warning:
> >
> > drivers/staging/lustre/lnet/selftest/console.c:1336 lstcon_test_add()
> > error: 'paramlen' from user is not capped properly
> >
> > The story here, is that "paramlen" is capped but only if "param" is
> > non-NULL. This causes a problem.
> >
> > drivers/staging/lustre/lnet/selftest/console.c
> > 1311
> > 1312 LIBCFS_ALLOC(test, offsetof(struct lstcon_test, tes_param[paramlen]));
> >
> > We don't know that paramlen is non-NULL here. Because of integer
> > overflows we could end up allocating less than intended.
>
> I think this must be a false positive in this case?
>
> Before calling this function we do:
> LIBCFS_ALLOC(param, args->lstio_tes_param_len);
>
> in lst_test_add_ioctl(), so it's not any bigger than 128k (or kmalloc will fail).
> Even if kmalloc would allow more than 128k allocations,
> offsetof(struct lstcon_test, tes_param[0]) is bound to be a lot smaller than
> the baseline allocation address for kmalloc, and therefore integer overflow
> cannot happen at all.
>
I explained badly, and I typed the wrong variable names by mistake...
Here is the relevant code from the caller:
drivers/staging/lustre/lnet/selftest/conctl.c
710 static int lst_test_add_ioctl(lstio_test_args_t *args)
711 {
712 char *batch_name;
713 char *src_name = NULL;
714 char *dst_name = NULL;
715 void *param = NULL;
716 int ret = 0;
717 int rc = -ENOMEM;
718
719 if (!args->lstio_tes_resultp ||
720 !args->lstio_tes_retp ||
721 !args->lstio_tes_bat_name || /* no specified batch */
722 args->lstio_tes_bat_nmlen <= 0 ||
723 args->lstio_tes_bat_nmlen > LST_NAME_SIZE ||
724 !args->lstio_tes_sgrp_name || /* no source group */
725 args->lstio_tes_sgrp_nmlen <= 0 ||
726 args->lstio_tes_sgrp_nmlen > LST_NAME_SIZE ||
727 !args->lstio_tes_dgrp_name || /* no target group */
728 args->lstio_tes_dgrp_nmlen <= 0 ||
729 args->lstio_tes_dgrp_nmlen > LST_NAME_SIZE)
730 return -EINVAL;
731
732 if (!args->lstio_tes_loop || /* negative is infinite */
733 args->lstio_tes_concur <= 0 ||
734 args->lstio_tes_dist <= 0 ||
735 args->lstio_tes_span <= 0)
736 return -EINVAL;
737
738 /* have parameter, check if parameter length is valid */
739 if (args->lstio_tes_param &&
740 (args->lstio_tes_param_len <= 0 ||
741 args->lstio_tes_param_len >
742 PAGE_SIZE - sizeof(struct lstcon_test)))
743 return -EINVAL;
If we don't have a parameter then we don't check ->lstio_tes_param_len.
744
745 LIBCFS_ALLOC(batch_name, args->lstio_tes_bat_nmlen + 1);
746 if (!batch_name)
747 return rc;
748
749 LIBCFS_ALLOC(src_name, args->lstio_tes_sgrp_nmlen + 1);
750 if (!src_name)
751 goto out;
752
753 LIBCFS_ALLOC(dst_name, args->lstio_tes_dgrp_nmlen + 1);
754 if (!dst_name)
755 goto out;
756
757 if (args->lstio_tes_param) {
758 LIBCFS_ALLOC(param, args->lstio_tes_param_len);
759 if (!param)
760 goto out;
761 if (copy_from_user(param, args->lstio_tes_param,
762 args->lstio_tes_param_len)) {
763 rc = -EFAULT;
764 goto out;
765 }
766 }
This is the code that you mentioned. But we don't have a parameter so
it's not invoked.
767
768 rc = -EFAULT;
769 if (copy_from_user(batch_name, args->lstio_tes_bat_name,
770 args->lstio_tes_bat_nmlen) ||
771 copy_from_user(src_name, args->lstio_tes_sgrp_name,
772 args->lstio_tes_sgrp_nmlen) ||
773 copy_from_user(dst_name, args->lstio_tes_dgrp_name,
774 args->lstio_tes_dgrp_nmlen))
775 goto out;
776
777 rc = lstcon_test_add(batch_name, args->lstio_tes_type,
778 args->lstio_tes_loop, args->lstio_tes_concur,
779 args->lstio_tes_dist, args->lstio_tes_span,
780 src_name, dst_name, param,
781 args->lstio_tes_param_len,
782 &ret, args->lstio_tes_resultp);
Here we are using "args->lstio_tes_param_len" which could be any integer
value. "param" is NULL.
783
784 if (ret)
785 rc = (copy_to_user(args->lstio_tes_retp, &ret,
786 sizeof(ret))) ? -EFAULT : 0;
Now here is the code again from lstcon_test_add():
drivers/staging/lustre/lnet/selftest/console.c
1279 int
1280 lstcon_test_add(char *batch_name, int type, int loop,
1281 int concur, int dist, int span,
1282 char *src_name, char *dst_name,
1283 void *param, int paramlen, int *retp,
"param" is NULL and "paramlen" is any integer value.
1284 struct list_head __user *result_up)
1285 {
1286 struct lstcon_test *test = NULL;
1287 int rc;
1288 struct lstcon_group *src_grp = NULL;
1289 struct lstcon_group *dst_grp = NULL;
1290 struct lstcon_batch *batch = NULL;
1291
1292 /*
1293 * verify that a batch of the given name exists, and the groups
1294 * that will be part of the batch exist and have at least one
1295 * active node
1296 */
1297 rc = lstcon_verify_batch(batch_name, &batch);
1298 if (rc)
1299 goto out;
1300
1301 rc = lstcon_verify_group(src_name, &src_grp);
1302 if (rc)
1303 goto out;
1304
1305 rc = lstcon_verify_group(dst_name, &dst_grp);
1306 if (rc)
1307 goto out;
1308
1309 if (dst_grp->grp_userland)
1310 *retp = 1;
1311
1312 LIBCFS_ALLOC(test, offsetof(struct lstcon_test, tes_param[paramlen]));
If you pass "paramlen" as -4 then it will corrupt four bytes beyond the
end of what we allocated. We could pass paramlen = -108 and it would
return ZERO_SIZE_PTR (0x16) and oops.
1313 if (!test) {
1314 CERROR("Can't allocate test descriptor\n");
1315 rc = -ENOMEM;
1316
1317 goto out;
1318 }
1319
1320 test->tes_hdr.tsb_id = batch->bat_hdr.tsb_id;
1321 test->tes_batch = batch;
1322 test->tes_type = type;
1323 test->tes_oneside = 0; /* TODO */
1324 test->tes_loop = loop;
1325 test->tes_concur = concur;
1326 test->tes_stop_onerr = 1; /* TODO */
1327 test->tes_span = span;
1328 test->tes_dist = dist;
1329 test->tes_cliidx = 0; /* just used for creating RPC */
1330 test->tes_src_grp = src_grp;
1331 test->tes_dst_grp = dst_grp;
1332 INIT_LIST_HEAD(&test->tes_trans_list);
1333
regards,
dan carpenter
More information about the lustre-devel
mailing list