aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart Scott <stuartscott@google.com>2017-06-07 16:21:04 -0700
committerStuart Scott <stuartscott@google.com>2017-06-07 23:23:52 +0000
commit0facf2bf5a6094e4e6d47852b5f907d3d4b928bd (patch)
tree1d5f983e6cfb4bcbe432cac5a309d2df1729188e
parent17ac703739a8ed97807b8a618b8853cdee918a0d (diff)
parentb2fa897c8e86362946ec524ed47300164a33453d (diff)
Merge android-msm-shamu-3.10-security-next into android-msm-shamu-3.10android-7.1.1_r0.73android-7.1.1_r0.71
August 2017.1 Bug: 62368843 Change-Id: Ib9f3de66b10c435d60829d0e111fc68f71306fa5
-rw-r--r--drivers/crypto/msm/qcedev.c12
-rw-r--r--drivers/gpu/msm/kgsl.c2
-rw-r--r--drivers/net/wireless/bcmdhd/bcmevent.c27
-rw-r--r--[-rwxr-xr-x]drivers/net/wireless/bcmdhd/include/proto/bcmeth.h1
-rw-r--r--drivers/platform/msm/ipa/ipa_rt.c6
-rw-r--r--drivers/usb/gadget/f_qc_rndis.c130
-rw-r--r--fs/f2fs/super.c26
-rw-r--r--fs/timerfd.c17
-rw-r--r--include/linux/f2fs_fs.h6
9 files changed, 176 insertions, 51 deletions
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index ca2ed5bca52c..44bd52a86e67 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1828,6 +1828,12 @@ static long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
err = qcedev_hash_final(&qcedev_areq, handle);
if (err)
return err;
+
+ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+ pr_err("Invalid sha_ctxt.diglen %d\n",
+ handle->sha_ctxt.diglen);
+ return -EINVAL;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
@@ -1856,6 +1862,12 @@ static long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
err = qcedev_hash_final(&qcedev_areq, handle);
if (err)
return err;
+
+ if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
+ pr_err("Invalid sha_ctxt.diglen %d\n",
+ handle->sha_ctxt.diglen);
+ return -EINVAL;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 57e3ea36b3e4..a8464446bfe7 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2365,9 +2365,9 @@ long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv,
/* Commit the pointer to the context in context_idr */
write_lock(&device->context_lock);
idr_replace(&device->context_idr, context, context->id);
+ param->drawctxt_id = context->id;
write_unlock(&device->context_lock);
- param->drawctxt_id = context->id;
done:
kgsl_mutex_unlock(&device->mutex, &device->mutex_owner);
return result;
diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c
index b85f111bce18..7ed9739c0edd 100644
--- a/drivers/net/wireless/bcmdhd/bcmevent.c
+++ b/drivers/net/wireless/bcmdhd/bcmevent.c
@@ -209,12 +209,14 @@ int
is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
bcm_event_msg_u_t *out_event)
{
- uint16 len;
+ uint16 evlen;
uint16 subtype;
uint16 usr_subtype;
bcm_event_t *bcm_event;
uint8 *pktend;
+ uint8 *evend;
int err = BCME_OK;
+ uint32 data_len;
pktend = (uint8 *)pktdata + pktlen;
bcm_event = (bcm_event_t *)pktdata;
@@ -235,8 +237,9 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
}
/* check length in bcmeth_hdr */
- len = ntoh16_ua((void *)&bcm_event->bcm_hdr.length);
- if (((uint8 *)&bcm_event->bcm_hdr.version + len) > pktend) {
+ evlen = ntoh16_ua((void *)&bcm_event->bcm_hdr.length);
+ evend = (uint8 *)&bcm_event->bcm_hdr.version + evlen;
+ if (evend != pktend) {
err = BCME_BADLEN;
goto done;
}
@@ -257,13 +260,15 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
usr_subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.usr_subtype);
switch (usr_subtype) {
case BCMILCP_BCM_SUBTYPE_EVENT:
- if (pktlen < sizeof(bcm_event_t)) {
+ if ((pktlen < sizeof(bcm_event_t)) ||
+ (evend < ((uint8 *)bcm_event + sizeof(bcm_event_t)))) {
err = BCME_BADLEN;
goto done;
}
- len = sizeof(bcm_event_t) + ntoh32_ua((void *)&bcm_event->event.datalen);
- if ((uint8 *)pktdata + len > pktend) {
+ data_len = ntoh32_ua((void *)&bcm_event->event.datalen);
+ if ((sizeof(bcm_event_t) + data_len +
+ BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD) != pktlen) {
err = BCME_BADLEN;
goto done;
}
@@ -280,14 +285,16 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
break;
case BCMILCP_BCM_SUBTYPE_DNGLEVENT:
- if (pktlen < sizeof(bcm_dngl_event_t)) {
+ if (pktlen < sizeof(bcm_dngl_event_t) ||
+ (evend < ((uint8 *)bcm_event + sizeof(bcm_dngl_event_t)))) {
err = BCME_BADLEN;
goto done;
}
- len = sizeof(bcm_dngl_event_t) +
- ntoh16_ua((void *)&((bcm_dngl_event_t *)pktdata)->dngl_event.datalen);
- if ((uint8 *)pktdata + len > pktend) {
+ data_len = ntoh16_ua((void *)&((bcm_dngl_event_t *)pktdata)
+ ->dngl_event.datalen);
+ if ((sizeof(bcm_dngl_event_t) + data_len +
+ BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD) != pktlen) {
err = BCME_BADLEN;
goto done;
}
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
index 41c1b57443c7..756f594bc61d 100755..100644
--- a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
@@ -93,6 +93,7 @@
#define BCMILCP_BCM_SUBTYPE_DNGLEVENT 5
#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8
#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0
+#define BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD 2
/* These fields are stored in network order */
typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index d55274a54498..511a2dd18bc3 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -1145,6 +1145,10 @@ int ipa_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup)
mutex_lock(&ipa_ctx->lock);
entry = __ipa_add_rt_tbl(lookup->ip, lookup->name);
if (entry && entry->cookie == IPA_COOKIE) {
+ if (entry->ref_cnt == ((u32)~0U)) {
+ IPAERR("fail: ref count crossed limit\n");
+ goto ret;
+ }
entry->ref_cnt++;
lookup->hdl = entry->id;
@@ -1154,6 +1158,8 @@ int ipa_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup)
result = 0;
}
+
+ret:
mutex_unlock(&ipa_ctx->lock);
return result;
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 3bccfe8fc5a7..b7f37df6921d 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -81,7 +81,7 @@
*/
struct f_rndis_qc {
- struct qc_gether port;
+ struct qc_gether port;
u8 ctrl_id, data_id;
u8 ethaddr[ETH_ALEN];
u32 vendorID;
@@ -90,8 +90,8 @@ struct f_rndis_qc {
u32 max_pkt_size;
const char *manufacturer;
int config;
- atomic_t ioctl_excl;
- atomic_t open_excl;
+ atomic_t ioctl_excl;
+ atomic_t open_excl;
struct usb_ep *notify;
struct usb_request *notify_req;
@@ -101,6 +101,7 @@ struct f_rndis_qc {
};
static struct ipa_usb_init_params rndis_ipa_params;
+static spinlock_t rndis_lock;
static bool rndis_ipa_supported;
static void rndis_qc_open(struct qc_gether *geth);
@@ -548,11 +549,18 @@ static void rndis_qc_response_available(void *_rndis)
}
static void rndis_qc_response_complete(struct usb_ep *ep,
- struct usb_request *req)
+ struct usb_request *req)
{
struct f_rndis_qc *rndis = req->context;
int status = req->status;
- struct usb_composite_dev *cdev = rndis->port.func.config->cdev;
+ struct usb_composite_dev *cdev;
+
+ if (!rndis->port.func.config || !rndis->port.func.config->cdev) {
+ pr_err("%s(): cdev or config is NULL.\n", __func__);
+ return;
+ } else {
+ cdev = rndis->port.func.config->cdev;
+ }
/* after TX:
* - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control)
@@ -686,7 +694,7 @@ invalid:
static int rndis_qc_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
- struct f_rndis_qc *rndis = func_to_rndis_qc(f);
+ struct f_rndis_qc *rndis = func_to_rndis_qc(f);
struct usb_composite_dev *cdev = f->config->cdev;
/* we know alt == 0 */
@@ -1026,6 +1034,7 @@ static void
rndis_qc_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_rndis_qc *rndis = func_to_rndis_qc(f);
+ unsigned long flags;
pr_debug("rndis_qc_unbind: free");
bam_data_destroy(0);
@@ -1044,7 +1053,10 @@ rndis_qc_unbind(struct usb_configuration *c, struct usb_function *f)
rndis_ipa_supported = false;
}
+ spin_lock_irqsave(&rndis_lock, flags);
kfree(rndis);
+ _rndis_qc = NULL;
+ spin_unlock_irqrestore(&rndis_lock, flags);
}
bool is_rndis_ipa_supported(void)
@@ -1197,101 +1209,143 @@ rndis_qc_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
rndis->port.func.suspend = rndis_qc_suspend;
rndis->port.func.resume = rndis_qc_resume;
- _rndis_qc = rndis;
+ if (rndis->xport == USB_GADGET_XPORT_BAM2BAM_IPA) {
+ status = rndis_ipa_init(&rndis_ipa_params);
+ if (status) {
+ pr_err("%s: failed to init rndis_ipa\n", __func__);
+ goto fail;
+ }
+ }
status = usb_add_function(c, &rndis->port.func);
if (status) {
- kfree(rndis);
+ if (rndis->xport == USB_GADGET_XPORT_BAM2BAM_IPA)
+ rndis_ipa_cleanup(rndis_ipa_params.private);
goto fail;
}
- if (rndis->xport != USB_GADGET_XPORT_BAM2BAM_IPA)
- return status;
+ _rndis_qc = rndis;
+
+ return status;
- status = rndis_ipa_init(&rndis_ipa_params);
- if (status) {
- pr_err("%s: failed to initialize rndis_ipa\n", __func__);
- kfree(rndis);
- goto fail;
- } else {
- pr_debug("%s: rndis_ipa successful created\n", __func__);
- return status;
- }
fail:
+ kfree(rndis);
+ _rndis_qc = NULL;
rndis_exit();
return status;
}
static int rndis_qc_open_dev(struct inode *ip, struct file *fp)
{
+ int ret = 0;
+ unsigned long flags;
pr_info("Open rndis QC driver\n");
+ spin_lock_irqsave(&rndis_lock, flags);
if (!_rndis_qc) {
pr_err("rndis_qc_dev not created yet\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto fail;
}
if (rndis_qc_lock(&_rndis_qc->open_excl)) {
pr_err("Already opened\n");
- return -EBUSY;
+ ret = -EBUSY;
+ goto fail;
}
fp->private_data = _rndis_qc;
- pr_info("rndis QC file opened\n");
+fail:
+ spin_unlock_irqrestore(&rndis_lock, flags);
- return 0;
+ if (!ret)
+ pr_info("rndis QC file opened\n");
+
+ return ret;
}
static int rndis_qc_release_dev(struct inode *ip, struct file *fp)
{
- struct f_rndis_qc *rndis = fp->private_data;
-
+ unsigned long flags;
pr_info("Close rndis QC file");
- rndis_qc_unlock(&rndis->open_excl);
+ spin_lock_irqsave(&rndis_lock, flags);
+
+ if (!_rndis_qc) {
+ pr_err("rndis_qc_dev not present\n");
+ spin_unlock_irqrestore(&rndis_lock, flags);
+ return -ENODEV;
+ }
+ rndis_qc_unlock(&_rndis_qc->open_excl);
+ spin_unlock_irqrestore(&rndis_lock, flags);
return 0;
}
static long rndis_qc_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
{
- struct f_rndis_qc *rndis = fp->private_data;
+ u8 qc_max_pkt_per_xfer = 0;
+ u32 qc_max_pkt_size = 0;
int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rndis_lock, flags);
+ if (!_rndis_qc) {
+ pr_err("rndis_qc_dev not present\n");
+ ret = -ENODEV;
+ goto fail;
+ }
- pr_info("Received command %d", cmd);
+ qc_max_pkt_per_xfer = _rndis_qc->max_pkt_per_xfer;
+ qc_max_pkt_size = _rndis_qc->max_pkt_size;
- if (rndis_qc_lock(&rndis->ioctl_excl))
- return -EBUSY;
+ if (rndis_qc_lock(&_rndis_qc->ioctl_excl)) {
+ ret = -EBUSY;
+ goto fail;
+ }
+
+ spin_unlock_irqrestore(&rndis_lock, flags);
+
+ pr_info("Received command %d\n", cmd);
switch (cmd) {
case RNDIS_QC_GET_MAX_PKT_PER_XFER:
ret = copy_to_user((void __user *)arg,
- &rndis->max_pkt_per_xfer,
- sizeof(rndis->max_pkt_per_xfer));
+ &qc_max_pkt_per_xfer,
+ sizeof(qc_max_pkt_per_xfer));
if (ret) {
pr_err("copying to user space failed");
ret = -EFAULT;
}
pr_info("Sent max packets per xfer %d",
- rndis->max_pkt_per_xfer);
+ qc_max_pkt_per_xfer);
break;
case RNDIS_QC_GET_MAX_PKT_SIZE:
ret = copy_to_user((void __user *)arg,
- &rndis->max_pkt_size,
- sizeof(rndis->max_pkt_size));
+ &qc_max_pkt_size,
+ sizeof(qc_max_pkt_size));
if (ret) {
pr_err("copying to user space failed");
ret = -EFAULT;
}
pr_debug("Sent max packet size %d",
- rndis->max_pkt_size);
+ qc_max_pkt_size);
break;
default:
pr_err("Unsupported IOCTL");
ret = -EINVAL;
}
- rndis_qc_unlock(&rndis->ioctl_excl);
+ spin_lock_irqsave(&rndis_lock, flags);
+ if (!_rndis_qc) {
+ pr_err("rndis_qc_dev not present\n");
+ ret = -ENODEV;
+ goto fail;
+ }
+ rndis_qc_unlock(&_rndis_qc->ioctl_excl);
+
+fail:
+ spin_unlock_irqrestore(&rndis_lock, flags);
return ret;
}
@@ -1314,6 +1368,8 @@ static int rndis_qc_init(void)
pr_info("initialize rndis QC instance\n");
+ spin_lock_init(&rndis_lock);
+
ret = misc_register(&rndis_qc_device);
if (ret)
pr_err("rndis QC driver failed to register");
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 8555f7df82c7..8a7c3659a823 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -435,6 +435,14 @@ static int sanity_check_raw_super(struct super_block *sb,
f2fs_msg(sb, KERN_INFO, "Invalid log sectors per block");
return 1;
}
+
+ if (le32_to_cpu(raw_super->segment_count) > F2FS_MAX_SEGMENT) {
+ f2fs_msg(sb, KERN_INFO,
+ "Invalid segment count (%u)",
+ le32_to_cpu(raw_super->segment_count));
+ return 1;
+ }
+
return 0;
}
@@ -443,6 +451,8 @@ static int sanity_check_ckpt(struct f2fs_sb_info *sbi)
unsigned int total, fsmeta;
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+ unsigned int main_segs, blocks_per_seg;
+ int i;
total = le32_to_cpu(raw_super->segment_count);
fsmeta = le32_to_cpu(raw_super->segment_count_ckpt);
@@ -454,6 +464,22 @@ static int sanity_check_ckpt(struct f2fs_sb_info *sbi)
if (fsmeta >= total)
return 1;
+ main_segs = le32_to_cpu(sbi->raw_super->segment_count_main);
+ blocks_per_seg = sbi->blocks_per_seg;
+
+ for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
+ if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs ||
+ le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg) {
+ return 1;
+ }
+ }
+ for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) {
+ if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs ||
+ le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg) {
+ return 1;
+ }
+ }
+
if (is_set_ckpt_flags(ckpt, CP_ERROR_FLAG)) {
f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck");
return 1;
diff --git a/fs/timerfd.c b/fs/timerfd.c
index 929312180dd0..4ed3c8c0c24c 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -39,6 +39,7 @@ struct timerfd_ctx {
int clockid;
struct rcu_head rcu;
struct list_head clist;
+ spinlock_t cancel_lock;
bool might_cancel;
};
@@ -111,7 +112,7 @@ void timerfd_clock_was_set(void)
rcu_read_unlock();
}
-static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
+static void __timerfd_remove_cancel(struct timerfd_ctx *ctx)
{
if (ctx->might_cancel) {
ctx->might_cancel = false;
@@ -121,6 +122,13 @@ static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
}
}
+static void timerfd_remove_cancel(struct timerfd_ctx *ctx)
+{
+ spin_lock(&ctx->cancel_lock);
+ __timerfd_remove_cancel(ctx);
+ spin_unlock(&ctx->cancel_lock);
+}
+
static bool timerfd_canceled(struct timerfd_ctx *ctx)
{
if (!ctx->might_cancel || ctx->moffs.tv64 != KTIME_MAX)
@@ -131,6 +139,7 @@ static bool timerfd_canceled(struct timerfd_ctx *ctx)
static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
{
+ spin_lock(&ctx->cancel_lock);
if ((ctx->clockid == CLOCK_REALTIME ||
ctx->clockid == CLOCK_REALTIME_ALARM) &&
(flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
@@ -140,9 +149,10 @@ static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
list_add_rcu(&ctx->clist, &cancel_list);
spin_unlock(&cancel_lock);
}
- } else if (ctx->might_cancel) {
- timerfd_remove_cancel(ctx);
+ } else {
+ __timerfd_remove_cancel(ctx);
}
+ spin_unlock(&ctx->cancel_lock);
}
static ktime_t timerfd_get_remaining(struct timerfd_ctx *ctx)
@@ -325,6 +335,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
return -ENOMEM;
init_waitqueue_head(&ctx->wqh);
+ spin_lock_init(&ctx->cancel_lock);
ctx->clockid = clockid;
if (isalarm(ctx))
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index df6fab82f87e..fdb6cb9fe0bb 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -235,6 +235,12 @@ struct f2fs_nat_block {
#define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry))
/*
+ * F2FS uses 4 bytes to represent block address. As a result, supported size of
+ * disk is 16 TB and it equals to 16 * 1024 * 1024 / 2 segments.
+ */
+#define F2FS_MAX_SEGMENT ((16 * 1024 * 1024) / 2)
+
+/*
* Note that f2fs_sit_entry->vblocks has the following bit-field information.
* [15:10] : allocation type such as CURSEG_XXXX_TYPE
* [9:0] : valid block count