if (jc) kfree(jc); 
kfree(jc); 
static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){	int                             i;	struct cryptocop_private        *dev = filp->private_data;	struct strcop_crypto_op         *crp_oper = (struct strcop_crypto_op *)arg;	struct strcop_crypto_op         oper = {0};	int                             err = 0;	struct cryptocop_operation      *cop = NULL;	struct ioctl_job_cb_ctx         *jc = NULL;	struct page                     **inpages = NULL;	struct page                     **outpages = NULL;	int                             noinpages = 0;	int                             nooutpages = 0;	struct cryptocop_desc           descs[5]; /* Max 5 descriptors are needed, there are three transforms that						   * can get connected/disconnected on different places in the indata. */	struct cryptocop_desc_cfg       dcfgs[5*3];	int                             desc_ix = 0;	int                             dcfg_ix = 0;	struct cryptocop_tfrm_cfg       ciph_tcfg = {0};	struct cryptocop_tfrm_cfg       digest_tcfg = {0};	struct cryptocop_tfrm_cfg       csum_tcfg = {0};	unsigned char                   *digest_result = NULL;	int                             digest_length = 0;	int                             cblocklen = 0;	unsigned char                   csum_result[CSUM_BLOCK_LENGTH];	struct cryptocop_session        *sess;	int    iovlen = 0;	int    iovix = 0;	int    pageix = 0;	int    pageoffset = 0;	size_t prev_ix = 0;	size_t next_ix;	int    cipher_active, digest_active, csum_active;	int    end_digest, end_csum;	int    digest_done = 0;	int    cipher_done = 0;	int    csum_done = 0;	DEBUG(printk("cryptocop_ioctl_process\n"));	if (!access_ok(VERIFY_WRITE, crp_oper, sizeof(struct strcop_crypto_op))){		DEBUG_API(printk("cryptocop_ioctl_process: !access_ok crp_oper!\n"));		return -EFAULT;	}	if (copy_from_user(&oper, crp_oper, sizeof(struct strcop_crypto_op))) {		DEBUG_API(printk("cryptocop_ioctl_process: copy_from_user\n"));		return -EFAULT;	}	DEBUG(print_strcop_crypto_op(&oper));	while (dev && dev->sid != oper.ses_id) dev = dev->next;	if (!dev){		DEBUG_API(printk("cryptocop_ioctl_process: session %lld not found\n", oper.ses_id));		return -EINVAL;	}	/* Check buffers. */	if (((oper.indata + oper.inlen) < oper.indata) || ((oper.cipher_outdata + oper.cipher_outlen) < oper.cipher_outdata)){		DEBUG_API(printk("cryptocop_ioctl_process: user buffers wrapped around, bad user!\n"));		return -EINVAL;	}	if (!access_ok(VERIFY_WRITE, oper.cipher_outdata, oper.cipher_outlen)){		DEBUG_API(printk("cryptocop_ioctl_process: !access_ok out data!\n"));		return -EFAULT;	}	if (!access_ok(VERIFY_READ, oper.indata, oper.inlen)){		DEBUG_API(printk("cryptocop_ioctl_process: !access_ok in data!\n"));		return -EFAULT;	}	cop = kmalloc(sizeof(struct cryptocop_operation), GFP_KERNEL);	if (!cop) {		DEBUG_API(printk("cryptocop_ioctl_process: kmalloc\n"));		return -ENOMEM;	}	jc = kmalloc(sizeof(struct ioctl_job_cb_ctx), GFP_KERNEL);	if (!jc) {		DEBUG_API(printk("cryptocop_ioctl_process: kmalloc\n"));		err = -ENOMEM;		goto error_cleanup;	}	jc->processed = 0;	cop->cb_data = jc;	cop->cb = ioctl_process_job_callback;	cop->operation_status = 0;	cop->use_dmalists = 0;	cop->in_interrupt = 0;	cop->fast_callback = 0;	cop->tfrm_op.tfrm_cfg = NULL;	cop->tfrm_op.desc = NULL;	cop->tfrm_op.indata = NULL;	cop->tfrm_op.incount = 0;	cop->tfrm_op.inlen = 0;	cop->tfrm_op.outdata = NULL;	cop->tfrm_op.outcount = 0;	cop->tfrm_op.outlen = 0;	sess = get_session(oper.ses_id);	if (!sess){		DEBUG_API(printk("cryptocop_ioctl_process: bad session id.\n"));		kfree(cop);		kfree(jc);		return -EINVAL;	}	if (oper.do_cipher) {		unsigned int                    cipher_outlen = 0;		struct cryptocop_transform_ctx  *tc = get_transform_ctx(sess, CRYPTOCOP_IOCTL_CIPHER_TID);		if (!tc) {			DEBUG_API(printk("cryptocop_ioctl_process: no cipher transform in session.\n"));			err = -EINVAL;			goto error_cleanup;		}		ciph_tcfg.tid = CRYPTOCOP_IOCTL_CIPHER_TID;		ciph_tcfg.inject_ix = 0;		ciph_tcfg.flags = 0;		if ((oper.cipher_start < 0) || (oper.cipher_len <= 0) || (oper.cipher_start > oper.inlen) || ((oper.cipher_start + oper.cipher_len) > oper.inlen)){			DEBUG_API(printk("cryptocop_ioctl_process: bad cipher length\n"));			kfree(cop);			kfree(jc);			return -EINVAL;		}		cblocklen = tc->init.alg == cryptocop_alg_aes ? AES_BLOCK_LENGTH : DES_BLOCK_LENGTH;		if (oper.cipher_len % cblocklen) {			kfree(cop);			kfree(jc);			DEBUG_API(printk("cryptocop_ioctl_process: cipher inlength not multiple of block length.\n"));			return -EINVAL;		}		cipher_outlen = oper.cipher_len;		if (tc->init.cipher_mode == cryptocop_cipher_mode_cbc){			if (oper.cipher_explicit) {				ciph_tcfg.flags |= CRYPTOCOP_EXPLICIT_IV;				memcpy(ciph_tcfg.iv, oper.cipher_iv, cblocklen);			} else {				cipher_outlen = oper.cipher_len - cblocklen;			}		} else {			if (oper.cipher_explicit){				kfree(cop);				kfree(jc);				DEBUG_API(printk("cryptocop_ioctl_process: explicit_iv when not CBC mode\n"));				return -EINVAL;			}		}		if (oper.cipher_outlen != cipher_outlen) {			kfree(cop);			kfree(jc);			DEBUG_API(printk("cryptocop_ioctl_process: cipher_outlen incorrect, should be %d not %d.\n", cipher_outlen, oper.cipher_outlen));			return -EINVAL;		}		if (oper.decrypt){			ciph_tcfg.flags |= CRYPTOCOP_DECRYPT;		} else {			ciph_tcfg.flags |= CRYPTOCOP_ENCRYPT;		}		ciph_tcfg.next = cop->tfrm_op.tfrm_cfg;		cop->tfrm_op.tfrm_cfg = &ciph_tcfg;	}	if (oper.do_digest){		struct cryptocop_transform_ctx *tc = get_transform_ctx(sess, CRYPTOCOP_IOCTL_DIGEST_TID);		if (!tc) {			DEBUG_API(printk("cryptocop_ioctl_process: no digest transform in session.\n"));			err = -EINVAL;			goto error_cleanup;		}		digest_length = tc->init.alg == cryptocop_alg_md5 ? 16 : 20;		digest_result = kmalloc(digest_length, GFP_KERNEL);		if (!digest_result) {			DEBUG_API(printk("cryptocop_ioctl_process: kmalloc digest_result\n"));			err = -EINVAL;			goto error_cleanup;		}		DEBUG(memset(digest_result, 0xff, digest_length));		digest_tcfg.tid = CRYPTOCOP_IOCTL_DIGEST_TID;		digest_tcfg.inject_ix = 0;		ciph_tcfg.inject_ix += digest_length;		if ((oper.digest_start < 0) || (oper.digest_len <= 0) || (oper.digest_start > oper.inlen) || ((oper.digest_start + oper.digest_len) > oper.inlen)){			DEBUG_API(printk("cryptocop_ioctl_process: bad digest length\n"));			err = -EINVAL;			goto error_cleanup;		}		digest_tcfg.next = cop->tfrm_op.tfrm_cfg;		cop->tfrm_op.tfrm_cfg = &digest_tcfg;	}	if (oper.do_csum){		csum_tcfg.tid = CRYPTOCOP_IOCTL_CSUM_TID;		csum_tcfg.inject_ix = digest_length;		ciph_tcfg.inject_ix += 2;		if ((oper.csum_start < 0) || (oper.csum_len <= 0) || (oper.csum_start > oper.inlen) || ((oper.csum_start + oper.csum_len) > oper.inlen)){			DEBUG_API(printk("cryptocop_ioctl_process: bad csum length\n"));			kfree(cop);			kfree(jc);			return -EINVAL;		}		csum_tcfg.next = cop->tfrm_op.tfrm_cfg;		cop->tfrm_op.tfrm_cfg = &csum_tcfg;	}	prev_ix = first_cfg_change_ix(&oper);	if (prev_ix > oper.inlen) {		DEBUG_API(printk("cryptocop_ioctl_process: length mismatch\n"));		nooutpages = noinpages = 0;		err = -EINVAL;		goto error_cleanup;	}	DEBUG(printk("cryptocop_ioctl_process: inlen=%d, cipher_outlen=%d\n", oper.inlen, oper.cipher_outlen));	/* Map user pages for in and out data of the operation. */	noinpages = (((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK) + oper.inlen - 1 - prev_ix + ~PAGE_MASK) >> PAGE_SHIFT;	DEBUG(printk("cryptocop_ioctl_process: noinpages=%d\n", noinpages));	inpages = kmalloc(noinpages * sizeof(struct page*), GFP_KERNEL);	if (!inpages){		DEBUG_API(printk("cryptocop_ioctl_process: kmalloc inpages\n"));		nooutpages = noinpages = 0;		err = -ENOMEM;		goto error_cleanup;	}	if (oper.do_cipher){		nooutpages = (((unsigned long int)oper.cipher_outdata & ~PAGE_MASK) + oper.cipher_outlen - 1 + ~PAGE_MASK) >> PAGE_SHIFT;		DEBUG(printk("cryptocop_ioctl_process: nooutpages=%d\n", nooutpages));		outpages = kmalloc(nooutpages * sizeof(struct page*), GFP_KERNEL);		if (!outpages){			DEBUG_API(printk("cryptocop_ioctl_process: kmalloc outpages\n"));			nooutpages = noinpages = 0;			err = -ENOMEM;			goto error_cleanup;		}	}	/* Acquire the mm page semaphore. */	down_read(&current->mm->mmap_sem);	err = get_user_pages(current,			     current->mm,			     (unsigned long int)(oper.indata + prev_ix),			     noinpages,			     0,  /* read access only for in data */			     0, /* no force */			     inpages,			     NULL);	if (err < 0) {		up_read(&current->mm->mmap_sem);		nooutpages = noinpages = 0;		DEBUG_API(printk("cryptocop_ioctl_process: get_user_pages indata\n"));		goto error_cleanup;	}	noinpages = err;	if (oper.do_cipher){		err = get_user_pages(current,				     current->mm,				     (unsigned long int)oper.cipher_outdata,				     nooutpages,				     1, /* write access for out data */				     0, /* no force */				     outpages,				     NULL);		up_read(&current->mm->mmap_sem);		if (err < 0) {			nooutpages = 0;			DEBUG_API(printk("cryptocop_ioctl_process: get_user_pages outdata\n"));			goto error_cleanup;		}		nooutpages = err;	} else {		up_read(&current->mm->mmap_sem);	}	/* Add 6 to nooutpages to make room for possibly inserted buffers for storing digest and	 * csum output and splits when units are (dis-)connected. */	cop->tfrm_op.indata = kmalloc((noinpages) * sizeof(struct iovec), GFP_KERNEL);	cop->tfrm_op.outdata = kmalloc((6 + nooutpages) * sizeof(struct iovec), GFP_KERNEL);	if (!cop->tfrm_op.indata || !cop->tfrm_op.outdata) {		DEBUG_API(printk("cryptocop_ioctl_process: kmalloc iovecs\n"));		err = -ENOMEM;		goto error_cleanup;	}	cop->tfrm_op.inlen = oper.inlen - prev_ix;	cop->tfrm_op.outlen = 0;	if (oper.do_cipher) cop->tfrm_op.outlen += oper.cipher_outlen;	if (oper.do_digest) cop->tfrm_op.outlen += digest_length;	if (oper.do_csum) cop->tfrm_op.outlen += 2;	/* Setup the in iovecs. */	cop->tfrm_op.incount = noinpages;	if (noinpages > 1){		size_t tmplen = cop->tfrm_op.inlen;		cop->tfrm_op.indata[0].iov_len = PAGE_SIZE - ((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK);		cop->tfrm_op.indata[0].iov_base = (unsigned char*)page_address(inpages[0]) + ((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK);		tmplen -= cop->tfrm_op.indata[0].iov_len;		for (i = 1; i<noinpages; i++){			cop->tfrm_op.indata[i].iov_len = tmplen < PAGE_SIZE ? tmplen : PAGE_SIZE;			cop->tfrm_op.indata[i].iov_base = (unsigned char*)page_address(inpages[i]);			tmplen -= PAGE_SIZE;		}	} else {		cop->tfrm_op.indata[0].iov_len = oper.inlen - prev_ix;		cop->tfrm_op.indata[0].iov_base = (unsigned char*)page_address(inpages[0]) + ((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK);	}	iovlen = nooutpages + 6;	pageoffset = oper.do_cipher ? ((unsigned long int)oper.cipher_outdata & ~PAGE_MASK) : 0;	next_ix = next_cfg_change_ix(&oper, prev_ix);	if (prev_ix == next_ix){		DEBUG_API(printk("cryptocop_ioctl_process: length configuration broken.\n"));		err = -EINVAL;  /* This should be impossible barring bugs. */		goto error_cleanup;	}	while (prev_ix != next_ix){		end_digest = end_csum = cipher_active = digest_active = csum_active = 0;		descs[desc_ix].cfg = NULL;		descs[desc_ix].length = next_ix - prev_ix;		if (oper.do_cipher && (oper.cipher_start < next_ix) && (prev_ix < (oper.cipher_start + oper.cipher_len))) {			dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_CIPHER_TID;			dcfgs[dcfg_ix].src = cryptocop_source_dma;			cipher_active = 1;			if (next_ix == (oper.cipher_start + oper.cipher_len)){				cipher_done = 1;				dcfgs[dcfg_ix].last = 1;			} else {				dcfgs[dcfg_ix].last = 0;			}			dcfgs[dcfg_ix].next = descs[desc_ix].cfg;			descs[desc_ix].cfg = &dcfgs[dcfg_ix];			++dcfg_ix;		}		if (oper.do_digest && (oper.digest_start < next_ix) && (prev_ix < (oper.digest_start + oper.digest_len))) {			digest_active = 1;			dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_DIGEST_TID;			dcfgs[dcfg_ix].src = cryptocop_source_dma;			if (next_ix == (oper.digest_start + oper.digest_len)){				assert(!digest_done);				digest_done = 1;				dcfgs[dcfg_ix].last = 1;			} else {				dcfgs[dcfg_ix].last = 0;			}			dcfgs[dcfg_ix].next = descs[desc_ix].cfg;			descs[desc_ix].cfg = &dcfgs[dcfg_ix];			++dcfg_ix;		}		if (oper.do_csum && (oper.csum_start < next_ix) && (prev_ix < (oper.csum_start + oper.csum_len))){			csum_active = 1;			dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_CSUM_TID;			dcfgs[dcfg_ix].src = cryptocop_source_dma;			if (next_ix == (oper.csum_start + oper.csum_len)){				csum_done = 1;				dcfgs[dcfg_ix].last = 1;			} else {				dcfgs[dcfg_ix].last = 0;			}			dcfgs[dcfg_ix].next = descs[desc_ix].cfg;			descs[desc_ix].cfg = &dcfgs[dcfg_ix];			++dcfg_ix;		}		if (!descs[desc_ix].cfg){			DEBUG_API(printk("cryptocop_ioctl_process: data segment %d (%d to %d) had no active transforms\n", desc_ix, prev_ix, next_ix));			err = -EINVAL;			goto error_cleanup;		}		descs[desc_ix].next = &(descs[desc_ix]) + 1;		++desc_ix;		prev_ix = next_ix;		next_ix = next_cfg_change_ix(&oper, prev_ix);	}	if (desc_ix > 0){		descs[desc_ix-1].next = NULL;	} else {		descs[0].next = NULL;	}	if (oper.do_digest) {		DEBUG(printk("cryptocop_ioctl_process: mapping %d byte digest output to iovec %d\n", digest_length, iovix));		/* Add outdata iovec, length == <length of type of digest> */		cop->tfrm_op.outdata[iovix].iov_base = digest_result;		cop->tfrm_op.outdata[iovix].iov_len = digest_length;		++iovix;	}	if (oper.do_csum) {		/* Add outdata iovec, length == 2, the length of csum. */		DEBUG(printk("cryptocop_ioctl_process: mapping 2 byte csum output to iovec %d\n", iovix));		/* Add outdata iovec, length == <length of type of digest> */		cop->tfrm_op.outdata[iovix].iov_base = csum_result;		cop->tfrm_op.outdata[iovix].iov_len = 2;		++iovix;	}	if (oper.do_cipher) {		if (!map_pages_to_iovec(cop->tfrm_op.outdata, iovlen, &iovix, outpages, nooutpages, &pageix, &pageoffset, oper.cipher_outlen)){			DEBUG_API(printk("cryptocop_ioctl_process: failed to map pages to iovec.\n"));			err = -ENOSYS; /* This should be impossible barring bugs. */			goto error_cleanup;		}	}	DEBUG(printk("cryptocop_ioctl_process: setting cop->tfrm_op.outcount %d\n", iovix));	cop->tfrm_op.outcount = iovix;	assert(iovix <= (nooutpages + 6));	cop->sid = oper.ses_id;	cop->tfrm_op.desc = &descs[0];	DEBUG(printk("cryptocop_ioctl_process: inserting job, cb_data=0x%p\n", cop->cb_data));	if ((err = cryptocop_job_queue_insert_user_job(cop)) != 0) {		DEBUG_API(printk("cryptocop_ioctl_process: insert job %d\n", err));		err = -EINVAL;		goto error_cleanup;	}	DEBUG(printk("cryptocop_ioctl_process: begin wait for result\n"));	wait_event(cryptocop_ioc_process_wq, (jc->processed != 0));	DEBUG(printk("cryptocop_ioctl_process: end wait for result\n"));        if (!jc->processed){		printk(KERN_WARNING "cryptocop_ioctl_process: job not processed at completion\n");		err = -EIO;		goto error_cleanup;	}	/* Job process done.  Cipher output should already be correct in job so no post processing of outdata. */	DEBUG(printk("cryptocop_ioctl_process: operation_status = %d\n", cop->operation_status));	if (cop->operation_status == 0){		if (oper.do_digest){			DEBUG(printk("cryptocop_ioctl_process: copy %d bytes digest to user\n", digest_length));			err = copy_to_user((unsigned char*)crp_oper + offsetof(struct strcop_crypto_op, digest), digest_result, digest_length);			if (0 != err){				DEBUG_API(printk("cryptocop_ioctl_process: copy_to_user, digest length %d, err %d\n", digest_length, err));				err = -EFAULT;				goto error_cleanup;			}		}		if (oper.do_csum){			DEBUG(printk("cryptocop_ioctl_process: copy 2 bytes checksum to user\n"));			err = copy_to_user((unsigned char*)crp_oper + offsetof(struct strcop_crypto_op, csum), csum_result, 2);			if (0 != err){				DEBUG_API(printk("cryptocop_ioctl_process: copy_to_user, csum, err %d\n", err));				err = -EFAULT;				goto error_cleanup;			}		}		err = 0;	} else {		DEBUG(printk("cryptocop_ioctl_process: returning err = operation_status = %d\n", cop->operation_status));		err = cop->operation_status;	} error_cleanup:	/* Release page caches. */	for (i = 0; i < noinpages; i++){		put_page(inpages[i]);	}	for (i = 0; i < nooutpages; i++){		int spdl_err;		/* Mark output pages dirty. */		spdl_err = set_page_dirty_lock(outpages[i]);		DEBUG(if (spdl_err)printk("cryptocop_ioctl_process: set_page_dirty_lock returned %d\n", spdl_err));	}	for (i = 0; i < nooutpages; i++){		put_page(outpages[i]);	}	if (digest_result) kfree(digest_result);	if (inpages) kfree(inpages);	if (outpages) kfree(outpages);	if (cop){		if (cop->tfrm_op.indata) kfree(cop->tfrm_op.indata);		if (cop->tfrm_op.outdata) kfree(cop->tfrm_op.outdata);		kfree(cop);	}	if (jc) kfree(jc);	DEBUG(print_lock_status());	return err;}
4520	/local/tlutelli/issta_data/temp/c/2005_temp/2005/4520/b2325fe1b7e5654fac9e9419423aa2c58a3dbd83/cryptocop.c/buggy/arch/cris/arch-v32/drivers/cryptocop.c