Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7804a135 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa: Prevent multiple header deletion from user space"

parents e985c737 a6a6e499
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -734,7 +734,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
			retval = -EINVAL;
			break;
		}
		if (ipa2_del_hdr((struct ipa_ioc_del_hdr *)param)) {
		if (ipa2_del_hdr_by_user((struct ipa_ioc_del_hdr *)param,
			true)) {
			retval = -EFAULT;
			break;
		}
@@ -1418,8 +1419,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
			retval = -EINVAL;
			break;
		}
		if (ipa2_del_hdr_proc_ctx(
			(struct ipa_ioc_del_hdr_proc_ctx *)param)) {
		if (ipa2_del_hdr_proc_ctx_by_user(
			(struct ipa_ioc_del_hdr_proc_ctx *)param, true)) {
			retval = -EFAULT;
			break;
		}
@@ -2801,7 +2802,7 @@ fail_schedule_delayed_work:
	if (ipa_ctx->dflt_v4_rt_rule_hdl)
		__ipa_del_rt_rule(ipa_ctx->dflt_v4_rt_rule_hdl);
	if (ipa_ctx->excp_hdr_hdl)
		__ipa_del_hdr(ipa_ctx->excp_hdr_hdl);
		__ipa_del_hdr(ipa_ctx->excp_hdr_hdl, false);
	ipa2_teardown_sys_pipe(ipa_ctx->clnt_hdl_cmd);
fail_cmd:
	return result;
@@ -2813,7 +2814,7 @@ static void ipa_teardown_apps_pipes(void)
	ipa2_teardown_sys_pipe(ipa_ctx->clnt_hdl_data_in);
	__ipa_del_rt_rule(ipa_ctx->dflt_v6_rt_rule_hdl);
	__ipa_del_rt_rule(ipa_ctx->dflt_v4_rt_rule_hdl);
	__ipa_del_hdr(ipa_ctx->excp_hdr_hdl);
	__ipa_del_hdr(ipa_ctx->excp_hdr_hdl, false);
	ipa2_teardown_sys_pipe(ipa_ctx->clnt_hdl_cmd);
}

+64 −15
Original line number Diff line number Diff line
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -805,7 +805,8 @@ error:
	return -EPERM;
}

static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl,
	bool release_hdr, bool by_user)
{
	struct ipa_hdr_proc_ctx_entry *entry;
	struct ipa_hdr_proc_ctx_tbl *htbl = &ipa_ctx->hdr_proc_ctx_tbl;
@@ -819,6 +820,14 @@ static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
	IPADBG("del ctx proc cnt=%d ofst=%d\n",
		htbl->proc_ctx_cnt, entry->offset_entry->offset);

	if (by_user && entry->user_deleted) {
		IPAERR("proc_ctx already deleted by user\n");
		return -EINVAL;
	}

	if (by_user)
		entry->user_deleted = true;

	if (--entry->ref_cnt) {
		IPADBG("proc_ctx_hdl %x ref_cnt %d\n",
			proc_ctx_hdl, entry->ref_cnt);
@@ -826,7 +835,7 @@ static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
	}

	if (release_hdr)
		__ipa_del_hdr(entry->hdr->id);
		__ipa_del_hdr(entry->hdr->id, false);

	/* move the offset entry to appropriate free list */
	list_move(&entry->offset_entry->link,
@@ -843,7 +852,7 @@ static int __ipa_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
}


int __ipa_del_hdr(u32 hdr_hdl)
int __ipa_del_hdr(u32 hdr_hdl, bool by_user)
{
	struct ipa_hdr_entry *entry;
	struct ipa_hdr_tbl *htbl = &ipa_ctx->hdr_tbl;
@@ -854,7 +863,7 @@ int __ipa_del_hdr(u32 hdr_hdl)
		return -EINVAL;
	}

	if (!entry || (entry->cookie != IPA_COOKIE)) {
	if (entry->cookie != IPA_COOKIE) {
		IPAERR("bad parm\n");
		return -EINVAL;
	}
@@ -866,6 +875,14 @@ int __ipa_del_hdr(u32 hdr_hdl)
		IPADBG("del hdr of sz=%d hdr_cnt=%d ofst=%d\n", entry->hdr_len,
			htbl->hdr_cnt, entry->offset_entry->offset);

	if (by_user && entry->user_deleted) {
		IPAERR("hdr already deleted by user\n");
		return -EINVAL;
	}

	if (by_user)
		entry->user_deleted = true;

	if (--entry->ref_cnt) {
		IPADBG("hdr_hdl %x ref_cnt %d\n", hdr_hdl, entry->ref_cnt);
		return 0;
@@ -876,7 +893,7 @@ int __ipa_del_hdr(u32 hdr_hdl)
			entry->phys_base,
			entry->hdr_len,
			DMA_TO_DEVICE);
		__ipa_del_hdr_proc_ctx(entry->proc_ctx->id, false);
		__ipa_del_hdr_proc_ctx(entry->proc_ctx->id, false, false);
	} else {
		/* move the offset entry to appropriate free list */
		list_move(&entry->offset_entry->link,
@@ -943,15 +960,16 @@ bail:
}

/**
 * ipa2_del_hdr() - Remove the specified headers from SW and optionally commit them
 * to IPA HW
 * ipa2_del_hdr_by_user() - Remove the specified headers
 * from SW and optionally commit them to IPA HW
 * @hdls:	[inout] set of headers to delete
 * @by_user:	Operation requested by user?
 *
 * Returns:	0 on success, negative on failure
 *
 * Note:	Should not be called from atomic context
 */
int ipa2_del_hdr(struct ipa_ioc_del_hdr *hdls)
int ipa2_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user)
{
	int i;
	int result = -EFAULT;
@@ -968,7 +986,7 @@ int ipa2_del_hdr(struct ipa_ioc_del_hdr *hdls)

	mutex_lock(&ipa_ctx->lock);
	for (i = 0; i < hdls->num_hdls; i++) {
		if (__ipa_del_hdr(hdls->hdl[i].hdl)) {
		if (__ipa_del_hdr(hdls->hdl[i].hdl, by_user)) {
			IPAERR("failed to del hdr %i\n", i);
			hdls->hdl[i].status = -1;
		} else {
@@ -988,6 +1006,20 @@ bail:
	return result;
}

/**
 * ipa2_del_hdr() - Remove the specified headers from SW and optionally commit them
 * to IPA HW
 * @hdls:	[inout] set of headers to delete
 *
 * Returns:	0 on success, negative on failure
 *
 * Note:	Should not be called from atomic context
 */
int ipa2_del_hdr(struct ipa_ioc_del_hdr *hdls)
{
	return ipa2_del_hdr_by_user(hdls, false);
}

/**
 * ipa2_add_hdr_proc_ctx() - add the specified headers to SW
 * and optionally commit them to IPA HW
@@ -1040,16 +1072,18 @@ bail:
}

/**
 * ipa2_del_hdr_proc_ctx() -
 * ipa2_del_hdr_proc_ctx_by_user() -
 * Remove the specified processing context headers from SW and
 * optionally commit them to IPA HW.
 * @hdls:	[inout] set of processing context headers to delete
 * @by_user:	Operation requested by user?
 *
 * Returns:	0 on success, negative on failure
 *
 * Note:	Should not be called from atomic context
 */
int ipa2_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls)
int ipa2_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls,
	bool by_user)
{
	int i;
	int result;
@@ -1068,7 +1102,7 @@ int ipa2_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls)

	mutex_lock(&ipa_ctx->lock);
	for (i = 0; i < hdls->num_hdls; i++) {
		if (__ipa_del_hdr_proc_ctx(hdls->hdl[i].hdl, true)) {
		if (__ipa_del_hdr_proc_ctx(hdls->hdl[i].hdl, true, by_user)) {
			IPAERR("failed to del hdr %i\n", i);
			hdls->hdl[i].status = -1;
		} else {
@@ -1088,6 +1122,21 @@ bail:
	return result;
}

/**
 * ipa2_del_hdr_proc_ctx() -
 * Remove the specified processing context headers from SW and
 * optionally commit them to IPA HW.
 * @hdls:	[inout] set of processing context headers to delete
 *
 * Returns:	0 on success, negative on failure
 *
 * Note:	Should not be called from atomic context
 */
int ipa2_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls)
{
	return ipa2_del_hdr_proc_ctx_by_user(hdls, false);
}

/**
 * ipa2_commit_hdr() - commit to IPA HW the current header table in SW
 *
@@ -1316,7 +1365,7 @@ int __ipa_release_hdr(u32 hdr_hdl)
{
	int result = 0;

	if (__ipa_del_hdr(hdr_hdl)) {
	if (__ipa_del_hdr(hdr_hdl, false)) {
		IPADBG("fail to del hdr %x\n", hdr_hdl);
		result = -EFAULT;
		goto bail;
@@ -1344,7 +1393,7 @@ int __ipa_release_hdr_proc_ctx(u32 proc_ctx_hdl)
{
	int result = 0;

	if (__ipa_del_hdr_proc_ctx(proc_ctx_hdl, true)) {
	if (__ipa_del_hdr_proc_ctx(proc_ctx_hdl, true, false)) {
		IPADBG("fail to del hdr %x\n", proc_ctx_hdl);
		result = -EFAULT;
		goto bail;
+11 −2
Original line number Diff line number Diff line
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -254,6 +254,7 @@ struct ipa_rt_tbl {
 * @id: header entry id
 * @is_eth2_ofst_valid: is eth2_ofst field valid?
 * @eth2_ofst: offset to start of Ethernet-II/802.3 header
 * @user_deleted: is the header deleted by the user?
 */
struct ipa_hdr_entry {
	struct list_head link;
@@ -271,6 +272,7 @@ struct ipa_hdr_entry {
	int id;
	u8 is_eth2_ofst_valid;
	u16 eth2_ofst;
	bool user_deleted;
};

/**
@@ -334,6 +336,7 @@ struct ipa_hdr_proc_ctx_add_hdr_cmd_seq {
 * @cookie: cookie used for validity check
 * @ref_cnt: reference counter of routing table
 * @id: processing context header entry id
 * @user_deleted: is the hdr processing context deleted by the user?
 */
struct ipa_hdr_proc_ctx_entry {
	struct list_head link;
@@ -343,6 +346,7 @@ struct ipa_hdr_proc_ctx_entry {
	u32 cookie;
	u32 ref_cnt;
	int id;
	bool user_deleted;
};

/**
@@ -1361,6 +1365,8 @@ int ipa2_add_hdr(struct ipa_ioc_add_hdr *hdrs);

int ipa2_del_hdr(struct ipa_ioc_del_hdr *hdls);

int ipa2_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user);

int ipa2_commit_hdr(void);

int ipa2_reset_hdr(void);
@@ -1378,6 +1384,9 @@ int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs);

int ipa2_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls);

int ipa2_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls,
	bool by_user);

/*
 * Routing
 */
@@ -1669,7 +1678,7 @@ int ipa2_active_clients_log_print_table(char *buf, int size);
void ipa2_active_clients_log_clear(void);
int ipa_interrupts_init(u32 ipa_irq, u32 ee, struct device *ipa_dev);
int __ipa_del_rt_rule(u32 rule_hdl);
int __ipa_del_hdr(u32 hdr_hdl);
int __ipa_del_hdr(u32 hdr_hdl, bool by_user);
int __ipa_release_hdr(u32 hdr_hdl);
int __ipa_release_hdr_proc_ctx(u32 proc_ctx_hdl);
int _ipa_read_gen_reg_v1_1(char *buff, int max_len);
+6 −5
Original line number Diff line number Diff line
@@ -784,7 +784,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
			retval = -EINVAL;
			break;
		}
		if (ipa3_del_hdr((struct ipa_ioc_del_hdr *)param)) {
		if (ipa3_del_hdr_by_user((struct ipa_ioc_del_hdr *)param,
			true)) {
			retval = -EFAULT;
			break;
		}
@@ -1553,8 +1554,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
			retval = -EINVAL;
			break;
		}
		if (ipa3_del_hdr_proc_ctx(
			(struct ipa_ioc_del_hdr_proc_ctx *)param)) {
		if (ipa3_del_hdr_proc_ctx_by_user(
			(struct ipa_ioc_del_hdr_proc_ctx *)param, true)) {
			retval = -EFAULT;
			break;
		}
@@ -3003,7 +3004,7 @@ fail_schedule_delayed_work:
	if (ipa3_ctx->dflt_v4_rt_rule_hdl)
		__ipa3_del_rt_rule(ipa3_ctx->dflt_v4_rt_rule_hdl);
	if (ipa3_ctx->excp_hdr_hdl)
		__ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl);
		__ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl, false);
	ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_cmd);
fail_cmd:
	return result;
@@ -3015,7 +3016,7 @@ static void ipa3_teardown_apps_pipes(void)
	ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_data_in);
	__ipa3_del_rt_rule(ipa3_ctx->dflt_v6_rt_rule_hdl);
	__ipa3_del_rt_rule(ipa3_ctx->dflt_v4_rt_rule_hdl);
	__ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl);
	__ipa3_del_hdr(ipa3_ctx->excp_hdr_hdl, false);
	ipa3_teardown_sys_pipe(ipa3_ctx->clnt_hdl_cmd);
}

+64 −15
Original line number Diff line number Diff line
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -573,7 +573,8 @@ error:
	return -EPERM;
}

static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl,
	bool release_hdr, bool by_user)
{
	struct ipa3_hdr_proc_ctx_entry *entry;
	struct ipa3_hdr_proc_ctx_tbl *htbl = &ipa3_ctx->hdr_proc_ctx_tbl;
@@ -587,6 +588,14 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
	IPADBG("del proc ctx cnt=%d ofst=%d\n",
		htbl->proc_ctx_cnt, entry->offset_entry->offset);

	if (by_user && entry->user_deleted) {
		IPAERR("proc_ctx already deleted by user\n");
		return -EINVAL;
	}

	if (by_user)
		entry->user_deleted = true;

	if (--entry->ref_cnt) {
		IPADBG("proc_ctx_hdl %x ref_cnt %d\n",
			proc_ctx_hdl, entry->ref_cnt);
@@ -594,7 +603,7 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
	}

	if (release_hdr)
		__ipa3_del_hdr(entry->hdr->id);
		__ipa3_del_hdr(entry->hdr->id, false);

	/* move the offset entry to appropriate free list */
	list_move(&entry->offset_entry->link,
@@ -611,7 +620,7 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl, bool release_hdr)
}


int __ipa3_del_hdr(u32 hdr_hdl)
int __ipa3_del_hdr(u32 hdr_hdl, bool by_user)
{
	struct ipa3_hdr_entry *entry;
	struct ipa3_hdr_tbl *htbl = &ipa3_ctx->hdr_tbl;
@@ -622,7 +631,7 @@ int __ipa3_del_hdr(u32 hdr_hdl)
		return -EINVAL;
	}

	if (!entry || (entry->cookie != IPA_COOKIE)) {
	if (entry->cookie != IPA_COOKIE) {
		IPAERR("bad parm\n");
		return -EINVAL;
	}
@@ -635,6 +644,14 @@ int __ipa3_del_hdr(u32 hdr_hdl)
			entry->hdr_len, htbl->hdr_cnt,
			entry->offset_entry->offset);

	if (by_user && entry->user_deleted) {
		IPAERR("proc_ctx already deleted by user\n");
		return -EINVAL;
	}

	if (by_user)
		entry->user_deleted = true;

	if (--entry->ref_cnt) {
		IPADBG("hdr_hdl %x ref_cnt %d\n", hdr_hdl, entry->ref_cnt);
		return 0;
@@ -645,7 +662,7 @@ int __ipa3_del_hdr(u32 hdr_hdl)
			entry->phys_base,
			entry->hdr_len,
			DMA_TO_DEVICE);
		__ipa3_del_hdr_proc_ctx(entry->proc_ctx->id, false);
		__ipa3_del_hdr_proc_ctx(entry->proc_ctx->id, false, false);
	} else {
		/* move the offset entry to appropriate free list */
		list_move(&entry->offset_entry->link,
@@ -707,15 +724,16 @@ bail:
}

/**
 * ipa3_del_hdr() - Remove the specified headers from SW and optionally commit them
 * to IPA HW
 * ipa3_del_hdr_by_user() - Remove the specified headers
 * from SW and optionally commit them to IPA HW
 * @hdls:	[inout] set of headers to delete
 * @by_user:	Operation requested by user?
 *
 * Returns:	0 on success, negative on failure
 *
 * Note:	Should not be called from atomic context
 */
int ipa3_del_hdr(struct ipa_ioc_del_hdr *hdls)
int ipa3_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user)
{
	int i;
	int result = -EFAULT;
@@ -727,7 +745,7 @@ int ipa3_del_hdr(struct ipa_ioc_del_hdr *hdls)

	mutex_lock(&ipa3_ctx->lock);
	for (i = 0; i < hdls->num_hdls; i++) {
		if (__ipa3_del_hdr(hdls->hdl[i].hdl)) {
		if (__ipa3_del_hdr(hdls->hdl[i].hdl, by_user)) {
			IPAERR("failed to del hdr %i\n", i);
			hdls->hdl[i].status = -1;
		} else {
@@ -747,6 +765,20 @@ bail:
	return result;
}

/**
 * ipa3_del_hdr() - Remove the specified headers from SW and optionally commit them
 * to IPA HW
 * @hdls:	[inout] set of headers to delete
 *
 * Returns:	0 on success, negative on failure
 *
 * Note:	Should not be called from atomic context
 */
int ipa3_del_hdr(struct ipa_ioc_del_hdr *hdls)
{
	return ipa3_del_hdr_by_user(hdls, false);
}

/**
 * ipa3_add_hdr_proc_ctx() - add the specified headers to SW
 * and optionally commit them to IPA HW
@@ -792,16 +824,18 @@ bail:
}

/**
 * ipa3_del_hdr_proc_ctx() -
 * ipa3_del_hdr_proc_ctx_by_user() -
 * Remove the specified processing context headers from SW and
 * optionally commit them to IPA HW.
 * @hdls:	[inout] set of processing context headers to delete
 * @by_user:	Operation requested by user?
 *
 * Returns:	0 on success, negative on failure
 *
 * Note:	Should not be called from atomic context
 */
int ipa3_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls)
int ipa3_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls,
	bool by_user)
{
	int i;
	int result;
@@ -813,7 +847,7 @@ int ipa3_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls)

	mutex_lock(&ipa3_ctx->lock);
	for (i = 0; i < hdls->num_hdls; i++) {
		if (__ipa3_del_hdr_proc_ctx(hdls->hdl[i].hdl, true)) {
		if (__ipa3_del_hdr_proc_ctx(hdls->hdl[i].hdl, true, by_user)) {
			IPAERR("failed to del hdr %i\n", i);
			hdls->hdl[i].status = -1;
		} else {
@@ -833,6 +867,21 @@ bail:
	return result;
}

/**
 * ipa3_del_hdr_proc_ctx() -
 * Remove the specified processing context headers from SW and
 * optionally commit them to IPA HW.
 * @hdls:	[inout] set of processing context headers to delete
 *
 * Returns:	0 on success, negative on failure
 *
 * Note:	Should not be called from atomic context
 */
int ipa3_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls)
{
	return ipa3_del_hdr_proc_ctx_by_user(hdls, false);
}

/**
 * ipa3_commit_hdr() - commit to IPA HW the current header table in SW
 *
@@ -1061,7 +1110,7 @@ int __ipa3_release_hdr(u32 hdr_hdl)
{
	int result = 0;

	if (__ipa3_del_hdr(hdr_hdl)) {
	if (__ipa3_del_hdr(hdr_hdl, false)) {
		IPADBG("fail to del hdr %x\n", hdr_hdl);
		result = -EFAULT;
		goto bail;
@@ -1089,7 +1138,7 @@ int __ipa3_release_hdr_proc_ctx(u32 proc_ctx_hdl)
{
	int result = 0;

	if (__ipa3_del_hdr_proc_ctx(proc_ctx_hdl, true)) {
	if (__ipa3_del_hdr_proc_ctx(proc_ctx_hdl, true, false)) {
		IPADBG("fail to del hdr %x\n", proc_ctx_hdl);
		result = -EFAULT;
		goto bail;
Loading