All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dan Carpenter <dan.carpenter@oracle.com>
To: lustre-devel@lists.lustre.org
Subject: [lustre-devel] [bug report] staging: add Lustre file system client support
Date: Tue, 6 Dec 2016 14:02:59 +0300	[thread overview]
Message-ID: <20161206110259.GG8244@mwanda> (raw)
In-Reply-To: <C7AE2AE0-89E7-49F6-B7C8-8BCF0F957045@intel.com>

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

  reply	other threads:[~2016-12-06 11:02 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-23 12:29 [lustre-devel] [bug report] staging: add Lustre file system client support Dan Carpenter
2016-12-05 23:43 ` Oleg Drokin
2016-12-06 11:02   ` Dan Carpenter [this message]
2016-12-06 15:44     ` Oleg Drokin
2016-12-06 18:37       ` Dan Carpenter
2016-12-06 19:10         ` Oleg Drokin
2016-12-06 19:19           ` Dan Carpenter
2016-12-06 20:14           ` Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161206110259.GG8244@mwanda \
    --to=dan.carpenter@oracle.com \
    --cc=lustre-devel@lists.lustre.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.