Switch to new CVE patchset

This commit is contained in:
Tad 2017-11-07 17:32:46 -05:00
parent 57ce42402b
commit 11c7037780
1215 changed files with 60697 additions and 14533 deletions

View File

@ -0,0 +1,345 @@
From 77ad483f7b82d944aae5b944cd28e923a5293668 Mon Sep 17 00:00:00 2001
From: Ravi Aravamudhan <aravamud@codeaurora.org>
Date: Thu, 15 Nov 2012 16:04:04 -0800
Subject: diag: Improve handling of IOCTLs
DIAG kernel driver interacts with user space processes using
IOCTLS. This change adds conditions to avoid potential integer
over/underflow, incorrect buffer copy.
CVE-2012-4220
CVE-2012-4221
Change-Id: Ic1e815051ae9544c911c9a5bd0c9218c1225f6d5
CRs-Fixed: 385352
CRs-Fixed: 385349
Signed-off-by: Shalabh Jain <shalabhj@codeaurora.org>
---
drivers/char/diag/diagchar.h | 1 +
drivers/char/diag/diagchar_core.c | 188 ++++++++++++++++++++++++++++----------
2 files changed, 142 insertions(+), 47 deletions(-)
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 28d0565..de3cf522 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -29,6 +29,7 @@
#define IN_BUF_SIZE 16384
#define MAX_IN_BUF_SIZE 32768
#define MAX_SYNC_OBJ_NAME_SIZE 32
+#define UINT32_MAX UINT_MAX
/* Size of the buffer used for deframing a packet
reveived from the PC tool*/
#define HDLC_MAX 4096
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 19c6ed2..7b17ce4 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -358,7 +358,7 @@ void diag_clear_reg(int proc_num)
}
void diag_add_reg(int j, struct bindpkt_params *params,
- int *success, int *count_entries)
+ int *success, unsigned int *count_entries)
{
*success = 1;
driver->table[j].cmd_code = params->cmd_code;
@@ -399,79 +399,153 @@ inline uint16_t diag_get_remote_device_mask(void) { return 0; }
long diagchar_ioctl(struct file *filp,
unsigned int iocmd, unsigned long ioarg)
{
- int i, j, count_entries = 0, temp;
- int success = -1;
+ int i, j, temp, success = -1, status;
+ unsigned int count_entries = 0, interim_count = 0;
void *temp_buf;
uint16_t support_list = 0;
- struct diag_dci_client_tbl *params =
- kzalloc(sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
+ struct diag_dci_client_tbl *dci_params;
struct diag_dci_health_stats stats;
- int status;
if (iocmd == DIAG_IOCTL_COMMAND_REG) {
- struct bindpkt_params_per_process *pkt_params =
- (struct bindpkt_params_per_process *) ioarg;
+ struct bindpkt_params_per_process pkt_params;
+ struct bindpkt_params *params;
+ struct bindpkt_params *head_params;
+ if (copy_from_user(&pkt_params, (void *)ioarg,
+ sizeof(struct bindpkt_params_per_process))) {
+ return -EFAULT;
+ }
+ if ((UINT32_MAX/sizeof(struct bindpkt_params)) <
+ pkt_params.count) {
+ pr_warning("diag: integer overflow while multiply\n");
+ return -EFAULT;
+ }
+ params = kzalloc(pkt_params.count*sizeof(
+ struct bindpkt_params), GFP_KERNEL);
+ if (!params) {
+ pr_err("diag: unable to alloc memory\n");
+ return -ENOMEM;
+ } else
+ head_params = params;
+
+ if (copy_from_user(params, pkt_params.params,
+ pkt_params.count*sizeof(struct bindpkt_params))) {
+ kfree(head_params);
+ return -EFAULT;
+ }
mutex_lock(&driver->diagchar_mutex);
for (i = 0; i < diag_max_reg; i++) {
if (driver->table[i].process_id == 0) {
- diag_add_reg(i, pkt_params->params,
- &success, &count_entries);
- if (pkt_params->count > count_entries) {
- pkt_params->params++;
+ diag_add_reg(i, params, &success,
+ &count_entries);
+ if (pkt_params.count > count_entries) {
+ params++;
} else {
mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
return success;
}
}
}
if (i < diag_threshold_reg) {
/* Increase table size by amount required */
- diag_max_reg += pkt_params->count -
+ if (pkt_params.count >= count_entries) {
+ interim_count = pkt_params.count -
count_entries;
+ } else {
+ pr_warning("diag: error in params count\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
+ if (UINT32_MAX - diag_max_reg >=
+ interim_count) {
+ diag_max_reg += interim_count;
+ } else {
+ pr_warning("diag: Integer overflow\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
/* Make sure size doesnt go beyond threshold */
if (diag_max_reg > diag_threshold_reg) {
diag_max_reg = diag_threshold_reg;
pr_info("diag: best case memory allocation\n");
}
+ if (UINT32_MAX/sizeof(struct diag_master_table) <
+ diag_max_reg) {
+ pr_warning("diag: integer overflow\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
temp_buf = krealloc(driver->table,
diag_max_reg*sizeof(struct
diag_master_table), GFP_KERNEL);
if (!temp_buf) {
- diag_max_reg -= pkt_params->count -
- count_entries;
- pr_alert("diag: Insufficient memory for reg.");
+ pr_alert("diag: Insufficient memory for reg.\n");
mutex_unlock(&driver->diagchar_mutex);
+
+ if (pkt_params.count >= count_entries) {
+ interim_count = pkt_params.count -
+ count_entries;
+ } else {
+ pr_warning("diag: params count error\n");
+ mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
+ return -EFAULT;
+ }
+ if (diag_max_reg >= interim_count) {
+ diag_max_reg -= interim_count;
+ } else {
+ pr_warning("diag: Integer underflow\n");
+ mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
+ return -EFAULT;
+ }
+ kfree(head_params);
return 0;
} else {
driver->table = temp_buf;
}
for (j = i; j < diag_max_reg; j++) {
- diag_add_reg(j, pkt_params->params,
- &success, &count_entries);
- if (pkt_params->count > count_entries) {
- pkt_params->params++;
+ diag_add_reg(j, params, &success,
+ &count_entries);
+ if (pkt_params.count > count_entries) {
+ params++;
} else {
mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
return success;
}
}
+ kfree(head_params);
mutex_unlock(&driver->diagchar_mutex);
} else {
mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
pr_err("Max size reached, Pkt Registration failed for"
" Process %d", current->tgid);
}
success = 0;
} else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) {
- struct diagpkt_delay_params *delay_params =
- (struct diagpkt_delay_params *) ioarg;
-
- if ((delay_params->rsp_ptr) &&
- (delay_params->size == sizeof(delayed_rsp_id)) &&
- (delay_params->num_bytes_ptr)) {
- *((uint16_t *)delay_params->rsp_ptr) =
- DIAGPKT_NEXT_DELAYED_RSP_ID(delayed_rsp_id);
- *(delay_params->num_bytes_ptr) = sizeof(delayed_rsp_id);
+ struct diagpkt_delay_params delay_params;
+ uint16_t interim_rsp_id;
+ int interim_size;
+ if (copy_from_user(&delay_params, (void *)ioarg,
+ sizeof(struct diagpkt_delay_params)))
+ return -EFAULT;
+ if ((delay_params.rsp_ptr) &&
+ (delay_params.size == sizeof(delayed_rsp_id)) &&
+ (delay_params.num_bytes_ptr)) {
+ interim_rsp_id = DIAGPKT_NEXT_DELAYED_RSP_ID(
+ delayed_rsp_id);
+ if (copy_to_user((void *)delay_params.rsp_ptr,
+ &interim_rsp_id, sizeof(uint16_t)))
+ return -EFAULT;
+ interim_size = sizeof(delayed_rsp_id);
+ if (copy_to_user((void *)delay_params.num_bytes_ptr,
+ &interim_size, sizeof(int)))
+ return -EFAULT;
success = 0;
}
} else if (iocmd == DIAG_IOCTL_DCI_REG) {
@@ -479,7 +553,13 @@ long diagchar_ioctl(struct file *filp,
return DIAG_DCI_NO_REG;
if (driver->num_dci_client >= MAX_DCI_CLIENTS)
return DIAG_DCI_NO_REG;
- if (copy_from_user(params, (void *)ioarg,
+ dci_params = kzalloc(sizeof(struct diag_dci_client_tbl),
+ GFP_KERNEL);
+ if (dci_params == NULL) {
+ pr_err("diag: unable to alloc memory\n");
+ return -ENOMEM;
+ }
+ if (copy_from_user(dci_params, (void *)ioarg,
sizeof(struct diag_dci_client_tbl)))
return -EFAULT;
mutex_lock(&driver->dci_mutex);
@@ -492,9 +572,9 @@ long diagchar_ioctl(struct file *filp,
if (driver->dci_client_tbl[i].client == NULL) {
driver->dci_client_tbl[i].client = current;
driver->dci_client_tbl[i].list =
- params->list;
+ dci_params->list;
driver->dci_client_tbl[i].signal_type =
- params->signal_type;
+ dci_params->signal_type;
create_dci_log_mask_tbl(driver->
dci_client_tbl[i].dci_log_mask);
create_dci_event_mask_tbl(driver->
@@ -512,6 +592,7 @@ long diagchar_ioctl(struct file *filp,
}
}
mutex_unlock(&driver->dci_mutex);
+ kfree(dci_params);
return driver->dci_client_id;
} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
success = -1;
@@ -536,25 +617,29 @@ long diagchar_ioctl(struct file *filp,
} else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) {
if (driver->ch_dci)
support_list = support_list | DIAG_CON_MPSS;
- *(uint16_t *)ioarg = support_list;
+ if (copy_to_user((void *)ioarg, &support_list,
+ sizeof(uint16_t)))
+ return -EFAULT;
return DIAG_DCI_NO_ERROR;
} else if (iocmd == DIAG_IOCTL_DCI_HEALTH_STATS) {
if (copy_from_user(&stats, (void *)ioarg,
sizeof(struct diag_dci_health_stats)))
return -EFAULT;
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- params = &(driver->dci_client_tbl[i]);
- if (params->client &&
- params->client->tgid == current->tgid) {
- stats.dropped_logs = params->dropped_logs;
- stats.dropped_events = params->dropped_events;
- stats.received_logs = params->received_logs;
- stats.received_events = params->received_events;
+ dci_params = &(driver->dci_client_tbl[i]);
+ if (dci_params->client &&
+ dci_params->client->tgid == current->tgid) {
+ stats.dropped_logs = dci_params->dropped_logs;
+ stats.dropped_events =
+ dci_params->dropped_events;
+ stats.received_logs = dci_params->received_logs;
+ stats.received_events =
+ dci_params->received_events;
if (stats.reset_status) {
- params->dropped_logs = 0;
- params->dropped_events = 0;
- params->received_logs = 0;
- params->received_events = 0;
+ dci_params->dropped_logs = 0;
+ dci_params->dropped_events = 0;
+ dci_params->received_logs = 0;
+ dci_params->received_events = 0;
}
break;
}
@@ -567,7 +652,7 @@ long diagchar_ioctl(struct file *filp,
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
break;
- if (i == -1)
+ if (i == driver->num_clients)
return -EINVAL;
driver->data_ready[i] |= DEINIT_TYPE;
wake_up_interruptible(&driver->wait_q);
@@ -1068,7 +1153,7 @@ static int diagchar_write(struct file *file, const char __user *buf,
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
void *buf_copy = NULL;
- int payload_size;
+ unsigned int payload_size;
#ifdef CONFIG_DIAG_OVER_USB
if (((driver->logging_mode == USB_MODE) && (!driver->usb_connected)) ||
(driver->logging_mode == NO_LOGGING_MODE)) {
@@ -1079,8 +1164,17 @@ static int diagchar_write(struct file *file, const char __user *buf,
/* Get the packet type F3/log/event/Pkt response */
err = copy_from_user((&pkt_type), buf, 4);
/* First 4 bytes indicate the type of payload - ignore these */
+ if (count < 4) {
+ pr_err("diag: Client sending short data\n");
+ return -EBADMSG;
+ }
payload_size = count - 4;
-
+ if (payload_size > USER_SPACE_DATA) {
+ pr_err("diag: Dropping packet, packet payload size crosses 8KB limit. Current payload size %d\n",
+ payload_size);
+ driver->dropped_count++;
+ return -EBADMSG;
+ }
if (pkt_type == DCI_DATA_TYPE) {
err = copy_from_user(driver->user_space_data, buf + 4,
payload_size);
--
cgit v1.1

View File

@ -0,0 +1,345 @@
From 77ad483f7b82d944aae5b944cd28e923a5293668 Mon Sep 17 00:00:00 2001
From: Ravi Aravamudhan <aravamud@codeaurora.org>
Date: Thu, 15 Nov 2012 16:04:04 -0800
Subject: diag: Improve handling of IOCTLs
DIAG kernel driver interacts with user space processes using
IOCTLS. This change adds conditions to avoid potential integer
over/underflow, incorrect buffer copy.
CVE-2012-4220
CVE-2012-4221
Change-Id: Ic1e815051ae9544c911c9a5bd0c9218c1225f6d5
CRs-Fixed: 385352
CRs-Fixed: 385349
Signed-off-by: Shalabh Jain <shalabhj@codeaurora.org>
---
drivers/char/diag/diagchar.h | 1 +
drivers/char/diag/diagchar_core.c | 188 ++++++++++++++++++++++++++++----------
2 files changed, 142 insertions(+), 47 deletions(-)
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 28d0565..de3cf522 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -29,6 +29,7 @@
#define IN_BUF_SIZE 16384
#define MAX_IN_BUF_SIZE 32768
#define MAX_SYNC_OBJ_NAME_SIZE 32
+#define UINT32_MAX UINT_MAX
/* Size of the buffer used for deframing a packet
reveived from the PC tool*/
#define HDLC_MAX 4096
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 19c6ed2..7b17ce4 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -358,7 +358,7 @@ void diag_clear_reg(int proc_num)
}
void diag_add_reg(int j, struct bindpkt_params *params,
- int *success, int *count_entries)
+ int *success, unsigned int *count_entries)
{
*success = 1;
driver->table[j].cmd_code = params->cmd_code;
@@ -399,79 +399,153 @@ inline uint16_t diag_get_remote_device_mask(void) { return 0; }
long diagchar_ioctl(struct file *filp,
unsigned int iocmd, unsigned long ioarg)
{
- int i, j, count_entries = 0, temp;
- int success = -1;
+ int i, j, temp, success = -1, status;
+ unsigned int count_entries = 0, interim_count = 0;
void *temp_buf;
uint16_t support_list = 0;
- struct diag_dci_client_tbl *params =
- kzalloc(sizeof(struct diag_dci_client_tbl), GFP_KERNEL);
+ struct diag_dci_client_tbl *dci_params;
struct diag_dci_health_stats stats;
- int status;
if (iocmd == DIAG_IOCTL_COMMAND_REG) {
- struct bindpkt_params_per_process *pkt_params =
- (struct bindpkt_params_per_process *) ioarg;
+ struct bindpkt_params_per_process pkt_params;
+ struct bindpkt_params *params;
+ struct bindpkt_params *head_params;
+ if (copy_from_user(&pkt_params, (void *)ioarg,
+ sizeof(struct bindpkt_params_per_process))) {
+ return -EFAULT;
+ }
+ if ((UINT32_MAX/sizeof(struct bindpkt_params)) <
+ pkt_params.count) {
+ pr_warning("diag: integer overflow while multiply\n");
+ return -EFAULT;
+ }
+ params = kzalloc(pkt_params.count*sizeof(
+ struct bindpkt_params), GFP_KERNEL);
+ if (!params) {
+ pr_err("diag: unable to alloc memory\n");
+ return -ENOMEM;
+ } else
+ head_params = params;
+
+ if (copy_from_user(params, pkt_params.params,
+ pkt_params.count*sizeof(struct bindpkt_params))) {
+ kfree(head_params);
+ return -EFAULT;
+ }
mutex_lock(&driver->diagchar_mutex);
for (i = 0; i < diag_max_reg; i++) {
if (driver->table[i].process_id == 0) {
- diag_add_reg(i, pkt_params->params,
- &success, &count_entries);
- if (pkt_params->count > count_entries) {
- pkt_params->params++;
+ diag_add_reg(i, params, &success,
+ &count_entries);
+ if (pkt_params.count > count_entries) {
+ params++;
} else {
mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
return success;
}
}
}
if (i < diag_threshold_reg) {
/* Increase table size by amount required */
- diag_max_reg += pkt_params->count -
+ if (pkt_params.count >= count_entries) {
+ interim_count = pkt_params.count -
count_entries;
+ } else {
+ pr_warning("diag: error in params count\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
+ if (UINT32_MAX - diag_max_reg >=
+ interim_count) {
+ diag_max_reg += interim_count;
+ } else {
+ pr_warning("diag: Integer overflow\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
/* Make sure size doesnt go beyond threshold */
if (diag_max_reg > diag_threshold_reg) {
diag_max_reg = diag_threshold_reg;
pr_info("diag: best case memory allocation\n");
}
+ if (UINT32_MAX/sizeof(struct diag_master_table) <
+ diag_max_reg) {
+ pr_warning("diag: integer overflow\n");
+ kfree(head_params);
+ mutex_unlock(&driver->diagchar_mutex);
+ return -EFAULT;
+ }
temp_buf = krealloc(driver->table,
diag_max_reg*sizeof(struct
diag_master_table), GFP_KERNEL);
if (!temp_buf) {
- diag_max_reg -= pkt_params->count -
- count_entries;
- pr_alert("diag: Insufficient memory for reg.");
+ pr_alert("diag: Insufficient memory for reg.\n");
mutex_unlock(&driver->diagchar_mutex);
+
+ if (pkt_params.count >= count_entries) {
+ interim_count = pkt_params.count -
+ count_entries;
+ } else {
+ pr_warning("diag: params count error\n");
+ mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
+ return -EFAULT;
+ }
+ if (diag_max_reg >= interim_count) {
+ diag_max_reg -= interim_count;
+ } else {
+ pr_warning("diag: Integer underflow\n");
+ mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
+ return -EFAULT;
+ }
+ kfree(head_params);
return 0;
} else {
driver->table = temp_buf;
}
for (j = i; j < diag_max_reg; j++) {
- diag_add_reg(j, pkt_params->params,
- &success, &count_entries);
- if (pkt_params->count > count_entries) {
- pkt_params->params++;
+ diag_add_reg(j, params, &success,
+ &count_entries);
+ if (pkt_params.count > count_entries) {
+ params++;
} else {
mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
return success;
}
}
+ kfree(head_params);
mutex_unlock(&driver->diagchar_mutex);
} else {
mutex_unlock(&driver->diagchar_mutex);
+ kfree(head_params);
pr_err("Max size reached, Pkt Registration failed for"
" Process %d", current->tgid);
}
success = 0;
} else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) {
- struct diagpkt_delay_params *delay_params =
- (struct diagpkt_delay_params *) ioarg;
-
- if ((delay_params->rsp_ptr) &&
- (delay_params->size == sizeof(delayed_rsp_id)) &&
- (delay_params->num_bytes_ptr)) {
- *((uint16_t *)delay_params->rsp_ptr) =
- DIAGPKT_NEXT_DELAYED_RSP_ID(delayed_rsp_id);
- *(delay_params->num_bytes_ptr) = sizeof(delayed_rsp_id);
+ struct diagpkt_delay_params delay_params;
+ uint16_t interim_rsp_id;
+ int interim_size;
+ if (copy_from_user(&delay_params, (void *)ioarg,
+ sizeof(struct diagpkt_delay_params)))
+ return -EFAULT;
+ if ((delay_params.rsp_ptr) &&
+ (delay_params.size == sizeof(delayed_rsp_id)) &&
+ (delay_params.num_bytes_ptr)) {
+ interim_rsp_id = DIAGPKT_NEXT_DELAYED_RSP_ID(
+ delayed_rsp_id);
+ if (copy_to_user((void *)delay_params.rsp_ptr,
+ &interim_rsp_id, sizeof(uint16_t)))
+ return -EFAULT;
+ interim_size = sizeof(delayed_rsp_id);
+ if (copy_to_user((void *)delay_params.num_bytes_ptr,
+ &interim_size, sizeof(int)))
+ return -EFAULT;
success = 0;
}
} else if (iocmd == DIAG_IOCTL_DCI_REG) {
@@ -479,7 +553,13 @@ long diagchar_ioctl(struct file *filp,
return DIAG_DCI_NO_REG;
if (driver->num_dci_client >= MAX_DCI_CLIENTS)
return DIAG_DCI_NO_REG;
- if (copy_from_user(params, (void *)ioarg,
+ dci_params = kzalloc(sizeof(struct diag_dci_client_tbl),
+ GFP_KERNEL);
+ if (dci_params == NULL) {
+ pr_err("diag: unable to alloc memory\n");
+ return -ENOMEM;
+ }
+ if (copy_from_user(dci_params, (void *)ioarg,
sizeof(struct diag_dci_client_tbl)))
return -EFAULT;
mutex_lock(&driver->dci_mutex);
@@ -492,9 +572,9 @@ long diagchar_ioctl(struct file *filp,
if (driver->dci_client_tbl[i].client == NULL) {
driver->dci_client_tbl[i].client = current;
driver->dci_client_tbl[i].list =
- params->list;
+ dci_params->list;
driver->dci_client_tbl[i].signal_type =
- params->signal_type;
+ dci_params->signal_type;
create_dci_log_mask_tbl(driver->
dci_client_tbl[i].dci_log_mask);
create_dci_event_mask_tbl(driver->
@@ -512,6 +592,7 @@ long diagchar_ioctl(struct file *filp,
}
}
mutex_unlock(&driver->dci_mutex);
+ kfree(dci_params);
return driver->dci_client_id;
} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
success = -1;
@@ -536,25 +617,29 @@ long diagchar_ioctl(struct file *filp,
} else if (iocmd == DIAG_IOCTL_DCI_SUPPORT) {
if (driver->ch_dci)
support_list = support_list | DIAG_CON_MPSS;
- *(uint16_t *)ioarg = support_list;
+ if (copy_to_user((void *)ioarg, &support_list,
+ sizeof(uint16_t)))
+ return -EFAULT;
return DIAG_DCI_NO_ERROR;
} else if (iocmd == DIAG_IOCTL_DCI_HEALTH_STATS) {
if (copy_from_user(&stats, (void *)ioarg,
sizeof(struct diag_dci_health_stats)))
return -EFAULT;
for (i = 0; i < MAX_DCI_CLIENTS; i++) {
- params = &(driver->dci_client_tbl[i]);
- if (params->client &&
- params->client->tgid == current->tgid) {
- stats.dropped_logs = params->dropped_logs;
- stats.dropped_events = params->dropped_events;
- stats.received_logs = params->received_logs;
- stats.received_events = params->received_events;
+ dci_params = &(driver->dci_client_tbl[i]);
+ if (dci_params->client &&
+ dci_params->client->tgid == current->tgid) {
+ stats.dropped_logs = dci_params->dropped_logs;
+ stats.dropped_events =
+ dci_params->dropped_events;
+ stats.received_logs = dci_params->received_logs;
+ stats.received_events =
+ dci_params->received_events;
if (stats.reset_status) {
- params->dropped_logs = 0;
- params->dropped_events = 0;
- params->received_logs = 0;
- params->received_events = 0;
+ dci_params->dropped_logs = 0;
+ dci_params->dropped_events = 0;
+ dci_params->received_logs = 0;
+ dci_params->received_events = 0;
}
break;
}
@@ -567,7 +652,7 @@ long diagchar_ioctl(struct file *filp,
for (i = 0; i < driver->num_clients; i++)
if (driver->client_map[i].pid == current->tgid)
break;
- if (i == -1)
+ if (i == driver->num_clients)
return -EINVAL;
driver->data_ready[i] |= DEINIT_TYPE;
wake_up_interruptible(&driver->wait_q);
@@ -1068,7 +1153,7 @@ static int diagchar_write(struct file *file, const char __user *buf,
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
void *buf_copy = NULL;
- int payload_size;
+ unsigned int payload_size;
#ifdef CONFIG_DIAG_OVER_USB
if (((driver->logging_mode == USB_MODE) && (!driver->usb_connected)) ||
(driver->logging_mode == NO_LOGGING_MODE)) {
@@ -1079,8 +1164,17 @@ static int diagchar_write(struct file *file, const char __user *buf,
/* Get the packet type F3/log/event/Pkt response */
err = copy_from_user((&pkt_type), buf, 4);
/* First 4 bytes indicate the type of payload - ignore these */
+ if (count < 4) {
+ pr_err("diag: Client sending short data\n");
+ return -EBADMSG;
+ }
payload_size = count - 4;
-
+ if (payload_size > USER_SPACE_DATA) {
+ pr_err("diag: Dropping packet, packet payload size crosses 8KB limit. Current payload size %d\n",
+ payload_size);
+ driver->dropped_count++;
+ return -EBADMSG;
+ }
if (pkt_type == DCI_DATA_TYPE) {
err = copy_from_user(driver->user_space_data, buf + 4,
payload_size);
--
cgit v1.1

View File

@ -0,0 +1,65 @@
From 1e76f61bb001b93795a227f8f808104b6c10b048 Mon Sep 17 00:00:00 2001
From: Jordan Crouse <jcrouse@codeaurora.org>
Date: Wed, 8 Aug 2012 13:24:21 -0600
Subject: msm: kgsl: Detect and avoid malformed ioctl codes
Because we were using _IO_NR, one could construct a malformed ioctl
code that would avoid allocating memory yet go to a function that
expected that memory. Still use _IO_NR to index the array of ioctls,
but check that the full values match before jumping to the helper
function.
CRs-fixed: 385592
Change-Id: Ic0dedbaded469035bd0a2bb0f20fecb2a3045ca5
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
---
drivers/gpu/msm/kgsl.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 57a0e2b..53eff77 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2176,7 +2176,7 @@ static const struct {
static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
struct kgsl_device_private *dev_priv = filep->private_data;
- unsigned int nr = _IOC_NR(cmd);
+ unsigned int nr;
kgsl_ioctl_func_t func;
int lock, ret;
char ustack[64];
@@ -2192,6 +2192,8 @@ static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
else if (cmd == IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_OLD)
cmd = IOCTL_KGSL_CMDSTREAM_READTIMESTAMP;
+ nr = _IOC_NR(cmd);
+
if (cmd & (IOC_IN | IOC_OUT)) {
if (_IOC_SIZE(cmd) < sizeof(ustack))
uptr = ustack;
@@ -2216,7 +2218,20 @@ static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
}
if (nr < ARRAY_SIZE(kgsl_ioctl_funcs) &&
- kgsl_ioctl_funcs[nr].func != NULL) {
+ kgsl_ioctl_funcs[nr].func != NULL) {
+
+ /*
+ * Make sure that nobody tried to send us a malformed ioctl code
+ * with a valid NR but bogus flags
+ */
+
+ if (kgsl_ioctl_funcs[nr].cmd != cmd) {
+ KGSL_DRV_ERR(dev_priv->device,
+ "Malformed ioctl code %08x\n", cmd);
+ ret = -ENOIOCTLCMD;
+ goto done;
+ }
+
func = kgsl_ioctl_funcs[nr].func;
lock = kgsl_ioctl_funcs[nr].lock;
} else {
--
cgit v1.1

View File

@ -1,31 +0,0 @@
From 81ce573830e9d5531531b3ec778c58e6b9167bcd Mon Sep 17 00:00:00 2001
From: Dan Carpenter <dan.carpenter@oracle.com>
Date: Wed, 5 Sep 2012 15:32:18 +0300
Subject: [PATCH] ALSA: compress_core: integer overflow in
snd_compr_allocate_buffer()
These are 32 bit values that come from the user, we need to check for
integer overflows or we could end up allocating a smaller buffer than
expected.
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
sound/core/compress_offload.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index eb60cb8dbb8a6..68fe02c7400a2 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -407,6 +407,10 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
unsigned int buffer_size;
void *buffer;
+ if (params->buffer.fragment_size == 0 ||
+ params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size)
+ return -EINVAL;
+
buffer_size = params->buffer.fragment_size * params->buffer.fragments;
if (stream->ops->copy) {
buffer = NULL;

View File

@ -0,0 +1,52 @@
From 24b51892b863ad23a9fcb2a28a45e5cc15c2f3b5 Mon Sep 17 00:00:00 2001
From: Manoj Rao <manojraj@codeaurora.org>
Date: Tue, 16 Apr 2013 17:42:38 -0700
Subject: mdss: mdss_fb: remove mmio access through mmap
Disable access to mm io and add
appropriate range checks to ensure valid accesses
through framebuffer mmap. This prevents illegal
access into memory.
Change-Id: Ic6e47ec726d330d48ce9a7a708418492a553543b
CRs-Fixed: 474706
Signed-off-by: Manoj Rao <manojraj@codeaurora.org>
---
drivers/video/msm/mdss/mdss_fb.c | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index e2d8cf6..f42df2a 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -669,22 +669,16 @@ static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
}
mdss_fb_pan_idle(mfd);
- if (off >= len) {
- /* memory mapped io */
- off -= len;
- if (info->var.accel_flags) {
- mutex_unlock(&info->lock);
- return -EINVAL;
- }
- start = info->fix.mmio_start;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
- }
/* Set VM flags. */
start &= PAGE_MASK;
- if ((vma->vm_end - vma->vm_start + off) > len)
+ if ((vma->vm_end <= vma->vm_start) ||
+ (off >= len) ||
+ ((vma->vm_end - vma->vm_start) > (len - off)))
return -EINVAL;
off += start;
+ if (off < start)
+ return -EINVAL;
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO | VM_RESERVED;
--
cgit v1.1

View File

@ -0,0 +1,64 @@
From 7e9785f78415d32e0b17b1d296a172b66e0d2ab7 Mon Sep 17 00:00:00 2001
From: Manoj Rao <manojraj@codeaurora.org>
Date: Fri, 12 Apr 2013 18:37:14 -0700
Subject: msm: msm_fb: remove mmio access through mmap
Disable access to mm io and add
appropriate range checks to ensure valid accesses
through framebuffer mmap. This prevents illegal
access into memory.
CRs-Fixed: 474706
Change-Id: If25166f2732433ef967e99c716440030b567aae9
Signed-off-by: Manoj Rao <manojraj@codeaurora.org>
(cherry picked from commit b571bef36cf51f9bb4cd1ad3ba23e3cee6d1d3cb)
Conflicts:
drivers/video/msm/msm_fb.c
Signed-off-by: Raviteja <adimur@codeaurora.org>
---
drivers/video/msm/msm_fb.c | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 7d11fa9..2b626a0 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1004,22 +1004,20 @@ static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma)
u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
- if (off >= len) {
- /* memory mapped io */
- off -= len;
- if (info->var.accel_flags) {
- mutex_unlock(&info->lock);
- return -EINVAL;
- }
- start = info->fix.mmio_start;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
- }
+ if (!start)
+ return -EINVAL;
+
+ if ((vma->vm_end <= vma->vm_start) ||
+ (off >= len) ||
+ ((vma->vm_end - vma->vm_start) > (len - off)))
+ return -EINVAL;
/* Set VM flags. */
start &= PAGE_MASK;
- if ((vma->vm_end - vma->vm_start + off) > len)
- return -EINVAL;
off += start;
+ if (off < start)
+ return -EINVAL;
+
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO | VM_RESERVED;
--
cgit v1.1

View File

@ -0,0 +1,56 @@
From cdde1a87792a52274763eb006d326ca254ec3c63 Mon Sep 17 00:00:00 2001
From: Manoj Rao <manojraj@codeaurora.org>
Date: Fri, 12 Apr 2013 18:37:14 -0700
Subject: msm: msm_fb: remove mmio access through mmap
Disable access to mm io and add
appropriate range checks to ensure valid accesses
through framebuffer mmap. This prevents illegal
access into memory.
CRs-Fixed: 474706
Change-Id: If25166f2732433ef967e99c716440030b567aae9
Signed-off-by: Manoj Rao <manojraj@codeaurora.org>
---
drivers/video/msm/msm_fb.c | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index adf50ed..9efe766 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1166,23 +1166,18 @@ static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma)
if (!start)
return -EINVAL;
- msm_fb_pan_idle(mfd);
- if (off >= len) {
- /* memory mapped io */
- off -= len;
- if (info->var.accel_flags) {
- mutex_unlock(&info->lock);
- return -EINVAL;
- }
- start = info->fix.mmio_start;
- len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
- }
+ if ((vma->vm_end <= vma->vm_start) ||
+ (off >= len) ||
+ ((vma->vm_end - vma->vm_start) > (len - off)))
+ return -EINVAL;
+ msm_fb_pan_idle(mfd);
/* Set VM flags. */
start &= PAGE_MASK;
- if ((vma->vm_end - vma->vm_start + off) > len)
- return -EINVAL;
off += start;
+ if (off < start)
+ return -EINVAL;
+
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO | VM_RESERVED;
--
cgit v1.1

View File

@ -0,0 +1,32 @@
From b44d5f71da7d2c44a7575376c582f9f1cde1cf6d Mon Sep 17 00:00:00 2001
From: Ben Romberger <bromberg@codeaurora.org>
Date: Wed, 3 Apr 2013 16:20:18 -0700
Subject: ASoC: msm: Add size safety check to ACDB driver
Check that the size sent by userspace is not larger
then the internal amount allowed. This protects
against overflowing the stack due to an invalid size.
Change-Id: I4a5b5ca5212bea32b671027d68a66367c5d4c4e7
CRs-fixed: 470222
Signed-off-by: Ben Romberger <bromberg@codeaurora.org>
---
sound/soc/msm/qdsp6v2/audio_acdb.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 16d6e81c..b2a469b 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -1064,7 +1064,7 @@ static long acdb_ioctl(struct file *f,
goto done;
}
- if (size <= 0) {
+ if ((size <= 0) || (size > sizeof(data))) {
pr_err("%s: Invalid size sent to driver: %d\n",
__func__, size);
result = -EFAULT;
--
cgit v1.1

View File

@ -0,0 +1,32 @@
From 76fb3e419e2b149292c3adf1e9171e2b542831bf Mon Sep 17 00:00:00 2001
From: Ben Romberger <bromberg@codeaurora.org>
Date: Wed, 8 May 2013 12:46:26 -0700
Subject: msm: audio: qdsp6v2: Add size safety check to ACDB driver
Check that the size sent by userspace is not larger
then the internal amount allowed. This protects
against overflowing the stack due to an invalid size.
Change-Id: I8230fdb00a7b57d398929e8ab0eb6587476f3db1
CRs-fixed: 470222
Signed-off-by: Ben Romberger <bromberg@codeaurora.org>
---
arch/arm/mach-msm/qdsp6v2/audio_acdb.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index 8efd808..aad14be 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -770,7 +770,7 @@ static long acdb_ioctl(struct file *f,
goto done;
}
- if (size <= 0) {
+ if ((size <= 0) || (size > sizeof(data))) {
pr_err("%s: Invalid size sent to driver: %d\n",
__func__, size);
result = -EFAULT;
--
cgit v1.1

View File

@ -0,0 +1,125 @@
From 8c5300aec8cd9882b89e9d169680221541da0d7f Mon Sep 17 00:00:00 2001
From: Monika Alekhya <malekh@codeaurora.org>
Date: Fri, 28 Jun 2013 18:23:40 +0530
Subject: msm:camera: Fix overflow issue in ioctl_hw_cmds function
'len' is of type signed int 32bit,but the assigned value
may exceed maximum unsigned int32 range.Add overflow check
and graceful exit if 'm'exceeds UINT32_MAX value.
Change-Id: I38f0d10a0cb44d08d0054f91044fc891c246ebd1
CRs-Fixed: 493314
Signed-off-by: Monika Alekhya <malekh@codeaurora.org>
---
drivers/media/video/msm/gemini/msm_gemini_sync.c | 9 ++++++++-
drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c | 10 ++++++++--
drivers/media/video/msm/mercury/msm_mercury_sync.c | 10 ++++++++--
3 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.c b/drivers/media/video/msm/gemini/msm_gemini_sync.c
index ef727fd..f5089ae 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.c
@@ -23,6 +23,7 @@
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
+# define UINT32_MAX (4294967295U)
static int release_buf;
/* size is based on 4k page size */
@@ -804,7 +805,7 @@ int msm_gemini_ioctl_hw_cmds(struct msm_gemini_device *pgmn_dev,
void * __user arg)
{
int is_copy_to_user;
- int len;
+ uint32_t len;
uint32_t m;
struct msm_gemini_hw_cmds *hw_cmds_p;
struct msm_gemini_hw_cmd *hw_cmd_p;
@@ -813,6 +814,12 @@ int msm_gemini_ioctl_hw_cmds(struct msm_gemini_device *pgmn_dev,
GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
return -EFAULT;
}
+ if ((m == 0) || (m > ((UINT32_MAX-sizeof(struct msm_gemini_hw_cmds))/
+ sizeof(struct msm_gemini_hw_cmd)))) {
+ GMN_PR_ERR("%s:%d] outof range of hwcmds\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
len = sizeof(struct msm_gemini_hw_cmds) +
sizeof(struct msm_gemini_hw_cmd) * (m - 1);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
index 6ac4a5e..4a81fa6 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_sync.c
@@ -22,6 +22,7 @@
#include "msm_jpeg_platform.h"
#include "msm_jpeg_common.h"
+#define UINT32_MAX (4294967295U)
static int release_buf;
inline void msm_jpeg_q_init(char const *name, struct msm_jpeg_q *q_p)
@@ -631,7 +632,7 @@ int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev,
void * __user arg)
{
int is_copy_to_user;
- int len;
+ uint32_t len;
uint32_t m;
struct msm_jpeg_hw_cmds *hw_cmds_p;
struct msm_jpeg_hw_cmd *hw_cmd_p;
@@ -640,7 +641,12 @@ int msm_jpeg_ioctl_hw_cmds(struct msm_jpeg_device *pgmn_dev,
JPEG_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
return -EFAULT;
}
-
+ if ((m == 0) || (m > ((UINT32_MAX-sizeof(struct msm_jpeg_hw_cmds))/
+ sizeof(struct msm_jpeg_hw_cmd)))) {
+ JPEG_PR_ERR("%s:%d] outof range of hwcmds\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
len = sizeof(struct msm_jpeg_hw_cmds) +
sizeof(struct msm_jpeg_hw_cmd) * (m - 1);
hw_cmds_p = kmalloc(len, GFP_KERNEL);
diff --git a/drivers/media/video/msm/mercury/msm_mercury_sync.c b/drivers/media/video/msm/mercury/msm_mercury_sync.c
index 9293aad..fe74a0a 100644
--- a/drivers/media/video/msm/mercury/msm_mercury_sync.c
+++ b/drivers/media/video/msm/mercury/msm_mercury_sync.c
@@ -24,6 +24,7 @@
#include "msm_mercury_macros.h"
#include "msm_mercury_hw_reg.h"
+#define UINT32_MAX (4294967295U)
static struct msm_mercury_core_buf out_buf_local;
static struct msm_mercury_core_buf in_buf_local;
@@ -470,7 +471,7 @@ int msm_mercury_ioctl_hw_cmds(struct msm_mercury_device *pmercury_dev,
void * __user arg)
{
int is_copy_to_user;
- int len;
+ uint32_t len;
uint32_t m;
struct msm_mercury_hw_cmds *hw_cmds_p;
struct msm_mercury_hw_cmd *hw_cmd_p;
@@ -479,7 +480,12 @@ int msm_mercury_ioctl_hw_cmds(struct msm_mercury_device *pmercury_dev,
MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
return -EFAULT;
}
-
+ if ((m == 0) || (m > ((UINT32_MAX-sizeof(struct msm_mercury_hw_cmds))/
+ sizeof(struct msm_mercury_hw_cmd)))) {
+ MCR_PR_ERR("%s:%d] outof range of hwcmds\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
len = sizeof(struct msm_mercury_hw_cmds) +
sizeof(struct msm_mercury_hw_cmd) * (m - 1);
hw_cmds_p = kmalloc(len, GFP_KERNEL);
--
cgit v1.1

View File

@ -0,0 +1,101 @@
From 81947189009afcfac17d1106101260c660421265 Mon Sep 17 00:00:00 2001
From: Monika Alekhya <malekh@codeaurora.org>
Date: Tue, 11 Jun 2013 19:32:27 +0530
Subject: msm:camera: Fix signedness issue in hw_exec_cmds
In hw_exec_cmds()second argument m_cmds should be
of type unsigned interger
Change-Id: Idad2eb1a59481f3fe9f90221ff2061e8dae57013
CRs-Fixed: 493314
Signed-off-by: Monika Alekhya <malekh@codeaurora.org>
---
drivers/media/video/msm/gemini/msm_gemini_hw.c | 2 +-
drivers/media/video/msm/gemini/msm_gemini_hw.h | 2 +-
drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c | 2 +-
drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h | 2 +-
drivers/media/video/msm/mercury/msm_mercury_hw.c | 2 +-
drivers/media/video/msm/mercury/msm_mercury_hw.h | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/media/video/msm/gemini/msm_gemini_hw.c b/drivers/media/video/msm/gemini/msm_gemini_hw.c
index 116edcf..99b76be 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_hw.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_hw.c
@@ -432,7 +432,7 @@ void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us)
}
}
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds)
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, uint32_t m_cmds)
{
int is_copy_to_user = -1;
uint32_t data;
diff --git a/drivers/media/video/msm/gemini/msm_gemini_hw.h b/drivers/media/video/msm/gemini/msm_gemini_hw.h
index 0abd4c4..23d31ef 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_hw.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_hw.h
@@ -94,7 +94,7 @@ uint32_t msm_gemini_hw_read(struct msm_gemini_hw_cmd *hw_cmd_p);
void msm_gemini_hw_write(struct msm_gemini_hw_cmd *hw_cmd_p);
int msm_gemini_hw_wait(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
void msm_gemini_hw_delay(struct msm_gemini_hw_cmd *hw_cmd_p, int m_us);
-int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, int m_cmds);
+int msm_gemini_hw_exec_cmds(struct msm_gemini_hw_cmd *hw_cmd_p, uint32_t m_cmds);
void msm_gemini_hw_region_dump(int size);
void msm_gemini_io_dump(int size);
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
index 0bfb6a8..d92caab 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.c
@@ -295,7 +295,7 @@ void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us)
}
}
-int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds)
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds)
{
int is_copy_to_user = -1;
uint32_t data;
diff --git a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
index 73a0e27..5545115 100644
--- a/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
+++ b/drivers/media/video/msm/jpeg_10/msm_jpeg_hw.h
@@ -94,7 +94,7 @@ uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p);
void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p);
int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us);
void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us);
-int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_cmds);
+int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds);
void msm_jpeg_hw_region_dump(int size);
void msm_jpeg_io_dump(int size);
diff --git a/drivers/media/video/msm/mercury/msm_mercury_hw.c b/drivers/media/video/msm/mercury/msm_mercury_hw.c
index 244c038..a940dd6 100644
--- a/drivers/media/video/msm/mercury/msm_mercury_hw.c
+++ b/drivers/media/video/msm/mercury/msm_mercury_hw.c
@@ -263,7 +263,7 @@ void msm_mercury_hw_delay(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us)
}
}
-int msm_mercury_hw_exec_cmds(struct msm_mercury_hw_cmd *hw_cmd_p, int m_cmds)
+int msm_mercury_hw_exec_cmds(struct msm_mercury_hw_cmd *hw_cmd_p, uint32_t m_cmds)
{
int is_copy_to_user = -1;
uint32_t data;
diff --git a/drivers/media/video/msm/mercury/msm_mercury_hw.h b/drivers/media/video/msm/mercury/msm_mercury_hw.h
index 54fc818..f69d8ba 100644
--- a/drivers/media/video/msm/mercury/msm_mercury_hw.h
+++ b/drivers/media/video/msm/mercury/msm_mercury_hw.h
@@ -55,7 +55,7 @@ uint32_t msm_mercury_hw_read(struct msm_mercury_hw_cmd *hw_cmd_p);
void msm_mercury_hw_write(struct msm_mercury_hw_cmd *hw_cmd_p);
int msm_mercury_hw_wait(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us);
void msm_mercury_hw_delay(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us);
-int msm_mercury_hw_exec_cmds(struct msm_mercury_hw_cmd *hw_cmd_p, int m_cmds);
+int msm_mercury_hw_exec_cmds(struct msm_mercury_hw_cmd *hw_cmd_p, uint32_t m_cmds);
void msm_mercury_hw_region_dump(int size);
--
cgit v1.1

View File

@ -0,0 +1,150 @@
From 4256415b296348ff16cd17a5b8f8dce4dea37328 Mon Sep 17 00:00:00 2001
From: Larry Bassel <lbassel@codeaurora.org>
Date: Mon, 29 Jul 2013 13:43:17 -0700
Subject: msm: Make CONFIG_STRICT_MEMORY_RWX even stricter
If CONFIG_STRICT_MEMORY_RWX was set, the first section (containing
the kernel page table and the initial code) and the section
containing the init code were both given RWX permission, which is
a potential security hole.
Pad the first section after the initial code (which will never
be executed when the MMU is on) to make the rest of the kernel
text start in the second section and make the first section RW.
Move some data which had ended up in the "init text"
section into the "init data" one, as this is RW, not RX.
Make the "init text" RX.
We will not free the section containing the "init text",
because if we do, the kernel will allocate memory for RW data there.
Change-Id: I6ca5f4e07342c374246f04a3fee18042fd47c33b
CRs-fixed: 513919
Signed-off-by: Larry Bassel <lbassel@codeaurora.org>
---
arch/arm/kernel/vmlinux.lds.S | 12 +++++++-----
arch/arm/mm/init.c | 9 +++++++++
arch/arm/mm/mmu.c | 15 +++++++--------
3 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index ae59e5a..0bf55ae 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -93,6 +93,9 @@ SECTIONS
_text = .;
HEAD_TEXT
}
+#ifdef CONFIG_STRICT_MEMORY_RWX
+ . = ALIGN(1<<SECTION_SHIFT);
+#endif
.text : { /* Real text segment */
_stext = .; /* Text and read-only data */
@@ -115,10 +118,10 @@ SECTIONS
*(.got) /* Global offset table */
ARM_CPU_KEEP(PROC_INFO)
}
+
#ifdef CONFIG_STRICT_MEMORY_RWX
. = ALIGN(1<<SECTION_SHIFT);
#endif
-
RO_DATA(PAGE_SIZE)
#ifdef CONFIG_ARM_UNWIND
@@ -156,6 +159,9 @@ SECTIONS
.init.proc.info : {
ARM_CPU_DISCARD(PROC_INFO)
}
+#ifdef CONFIG_STRICT_MEMORY_RWX
+ . = ALIGN(1<<SECTION_SHIFT);
+#endif
.init.arch.info : {
__arch_info_begin = .;
*(.arch.info.init)
@@ -190,10 +196,6 @@ SECTIONS
INIT_RAM_FS
}
#ifndef CONFIG_XIP_KERNEL
-#ifdef CONFIG_STRICT_MEMORY_RWX
- . = ALIGN(1<<SECTION_SHIFT);
-#endif
- __init_data = .;
.exit.data : {
ARM_EXIT_KEEP(EXIT_DATA)
}
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 34cb153..e82ea2b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -909,6 +909,14 @@ void free_initmem(void)
"TCM link");
#endif
+#ifdef CONFIG_STRICT_MEMORY_RWX
+ poison_init_mem((char *)__arch_info_begin,
+ __init_end - (char *)__arch_info_begin);
+ reclaimed_initmem = free_area(__phys_to_pfn(__pa(__arch_info_begin)),
+ __phys_to_pfn(__pa(__init_end)),
+ "init");
+ totalram_pages += reclaimed_initmem;
+#else
poison_init_mem(__init_begin, __init_end - __init_begin);
if (!machine_is_integrator() && !machine_is_cintegrator()) {
reclaimed_initmem = free_area(__phys_to_pfn(__pa(__init_begin)),
@@ -916,6 +924,7 @@ void free_initmem(void)
"init");
totalram_pages += reclaimed_initmem;
}
+#endif
}
#ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index c2efc34..e5a60a9 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1379,8 +1379,6 @@ void mem_text_write_kernel_word(unsigned long *addr, unsigned long word)
}
EXPORT_SYMBOL(mem_text_write_kernel_word);
-extern char __init_data[];
-
static void __init map_lowmem(void)
{
struct memblock_region *reg;
@@ -1401,7 +1399,7 @@ static void __init map_lowmem(void)
#ifdef CONFIG_STRICT_MEMORY_RWX
if (start <= __pa(_text) && __pa(_text) < end) {
map.length = SECTION_SIZE;
- map.type = MT_MEMORY;
+ map.type = MT_MEMORY_RW;
create_mapping(&map);
@@ -1421,14 +1419,15 @@ static void __init map_lowmem(void)
map.pfn = __phys_to_pfn(__pa(__init_begin));
map.virtual = (unsigned long)__init_begin;
- map.length = __init_data - __init_begin;
- map.type = MT_MEMORY;
+ map.length = (char *)__arch_info_begin - __init_begin;
+ map.type = MT_MEMORY_RX;
create_mapping(&map);
- map.pfn = __phys_to_pfn(__pa(__init_data));
- map.virtual = (unsigned long)__init_data;
- map.length = __phys_to_virt(end) - (unsigned int)__init_data;
+ map.pfn = __phys_to_pfn(__pa(__arch_info_begin));
+ map.virtual = (unsigned long)__arch_info_begin;
+ map.length = __phys_to_virt(end) -
+ (unsigned long)__arch_info_begin;
map.type = MT_MEMORY_RW;
} else {
map.length = end - start;
--
cgit v1.1

View File

@ -0,0 +1,34 @@
From c9c81836ee44db9974007d34cf2aaeb1a51a8d45 Mon Sep 17 00:00:00 2001
From: Hariram Purushothaman <hpurus@codeaurora.org>
Date: Fri, 9 Aug 2013 11:21:50 -0700
Subject: msm: camera: Bound check length for Dequeue stream buff info
Bound check the length param from user space given to
copy_from_user function to avoid any invalid memory access.
Change-Id: I926509a5fffd49cfc0130d182f246fbb9335b60e
CRs-Fixed: 519124
Signed-off-by: Hariram Purushothaman <hpurus@codeaurora.org>
---
drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
index d302131..3aaff78 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/vpe/msm_vpe.c
@@ -1323,6 +1323,11 @@ static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
struct msm_vpe_buff_queue_info_t *buff_queue_info;
VPE_DBG("VIDIOC_MSM_VPE_DEQUEUE_STREAM_BUFF_INFO\n");
+ if (ioctl_ptr->len != sizeof(uint32_t)) {
+ pr_err("%s:%d Invalid len\n", __func__, __LINE__);
+ mutex_unlock(&vpe_dev->mutex);
+ return -EINVAL;
+ }
rc = (copy_from_user(&identity,
(void __user *)ioctl_ptr->ioctl_ptr,
--
cgit v1.1

View File

@ -0,0 +1,33 @@
From 28385b9c3054c91dca1aa194ffa750550c50f3ce Mon Sep 17 00:00:00 2001
From: Seemanta Dutta <seemanta@codeaurora.org>
Date: Fri, 26 Jul 2013 13:39:05 -0700
Subject: msm: camera: Add lower and upper bounds check in msm_cpp.c ioctl()
Add a check for upper and lower bounds in msm_cpp_subdev_ioctl() for
command code VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO.
CRs-fixed: 518731
Change-Id: I72996e13b7370a3b49f645297c52a118775b2b12
Signed-off-by: Seemanta Dutta <seemanta@codeaurora.org>
---
drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 822c0c8..8c8570d 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1536,6 +1536,10 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd,
uint32_t identity;
struct msm_cpp_buff_queue_info_t *buff_queue_info;
+ if ((ioctl_ptr->len == 0) ||
+ (ioctl_ptr->len > sizeof(uint32_t)))
+ return -EINVAL;
+
rc = (copy_from_user(&identity,
(void __user *)ioctl_ptr->ioctl_ptr,
ioctl_ptr->len) ? -EFAULT : 0);
--
cgit v1.1

View File

@ -0,0 +1,50 @@
From 8604847927f952cc8e773b97eca24e1060a570f2 Mon Sep 17 00:00:00 2001
From: Seemanta Dutta <seemanta@codeaurora.org>
Date: Thu, 25 Jul 2013 18:01:32 -0700
Subject: msm: camera: Fix uninitialized memory returned to userspace
Local structures have not been initialized to all zeroes, so fix
this by setting them to all zeroes to prevent uninitialized memory
being copied to userspace.
CRs-fixed: 518478
Change-Id: I6e76355c3f854514def1bd18dcc5c3ef6db38f16
Signed-off-by: Seemanta Dutta <seemanta@codeaurora.org>
---
drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c | 3 ++-
drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c b/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c
index 9293aad..e6483c1 100644
--- a/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c
+++ b/drivers/media/platform/msm/camera_v1/mercury/msm_mercury_sync.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, 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
@@ -196,6 +196,7 @@ int msm_mercury_evt_get(struct msm_mercury_device *pmercury_dev,
int rc = 0;
MCR_DBG("(%d)%s() Enter\n", __LINE__, __func__);
+ memset(&ctrl_cmd, 0, sizeof(ctrl_cmd));
ctrl_cmd.type = (uint32_t)msm_mercury_q_wait(&pmercury_dev->evt_q);
rc = copy_to_user(arg, &ctrl_cmd, sizeof(ctrl_cmd));
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
index aa6f034..debbf03 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_sync.c
@@ -221,6 +221,7 @@ int msm_jpeg_evt_get(struct msm_jpeg_device *pgmn_dev,
return -EAGAIN;
}
+ memset(&ctrl_cmd, 0, sizeof(ctrl_cmd));
ctrl_cmd.type = buf_p->vbuf.type;
kfree(buf_p);
--
cgit v1.1

View File

@ -0,0 +1,300 @@
From f53bcf29a6e7a66b3d935b8d562fa00829261f05 Mon Sep 17 00:00:00 2001
From: Bingzhe Cai <bingzhec@codeaurora.org>
Date: Tue, 24 Sep 2013 01:42:12 +0800
Subject: input: touchpanel: fix security issues in GT915 driver
There are multiple buffer overflow and input validation issues
in Goodix gt915 driver, fix these issues by adding data length
check and change file system node mode.
CRs-Fixed: 526101
Change-Id: I5173fc1ca021fd45c939c7c8a4f460651330de5b
Signed-off-by: Bingzhe Cai <bingzhec@codeaurora.org>
---
drivers/input/touchscreen/gt9xx/goodix_tool.c | 110 +++++++++++++++++++-------
1 file changed, 83 insertions(+), 27 deletions(-)
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
index bdac3fd..aa8159f 100644
--- a/drivers/input/touchscreen/gt9xx/goodix_tool.c
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -22,6 +22,7 @@
*/
#include "gt9xx.h"
+#include <linux/mutex.h>
#define DATA_LENGTH_UINT 512
#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8 *))
@@ -53,6 +54,8 @@ static struct i2c_client *gt_client;
static struct proc_dir_entry *goodix_proc_entry;
+static struct mutex lock;
+
static s32 goodix_tool_write(struct file *filp, const char __user *buff,
unsigned long len, void *data);
static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
@@ -188,7 +191,7 @@ static void unregister_i2c_func(void)
s32 init_wr_node(struct i2c_client *client)
{
- s32 i;
+ u8 i;
gt_client = client;
memset(&cmd_head, 0, sizeof(cmd_head));
@@ -202,8 +205,8 @@ s32 init_wr_node(struct i2c_client *client)
i--;
}
if (i) {
- DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
- GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
+ DATA_LENGTH = i * DATA_LENGTH_UINT;
+ dev_dbg(&client->dev, "Applied memory size:%d.", DATA_LENGTH);
} else {
GTP_ERROR("Apply for memory failed.");
return FAIL;
@@ -214,8 +217,9 @@ s32 init_wr_node(struct i2c_client *client)
register_i2c_func();
+ mutex_init(&lock);
tool_set_proc_name(procname);
- goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
+ goodix_proc_entry = create_proc_entry(procname, 0660, NULL);
if (goodix_proc_entry == NULL) {
GTP_ERROR("Couldn't create proc entry!");
return FAIL;
@@ -334,9 +338,13 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
GTP_DEBUG_FUNC();
GTP_DEBUG_ARRAY((u8 *)buff, len);
+ mutex_lock(&lock);
ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
- if (ret)
+ if (ret) {
GTP_ERROR("copy_from_user failed.");
+ ret = -EACCES;
+ goto exit;
+ }
GTP_DEBUG("wr :0x%02x.", cmd_head.wr);
GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
@@ -354,6 +362,19 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
GTP_DEBUG("len:%d.", (s32)len);
GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
+ if (cmd_head.data_len > (DATA_LENGTH - GTP_ADDR_LENGTH)) {
+ pr_err("data len %d > data buff %d, rejected!\n",
+ cmd_head.data_len, (DATA_LENGTH - GTP_ADDR_LENGTH));
+ ret = -EINVAL;
+ goto exit;
+ }
+ if (cmd_head.addr_len > GTP_ADDR_LENGTH) {
+ pr_err(" addr len %d > data buff %d, rejected!\n",
+ cmd_head.addr_len, GTP_ADDR_LENGTH);
+ ret = -EINVAL;
+ goto exit;
+ }
+
if (cmd_head.wr == 1) {
/* copy_from_user(&cmd_head.data[cmd_head.addr_len],
&buff[CMD_HEAD_LENGTH], cmd_head.data_len); */
@@ -373,7 +394,8 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
if (cmd_head.flag == 1) {
if (FAIL == comfirm()) {
GTP_ERROR("[WRITE]Comfirm fail!");
- return FAIL;
+ ret = -EINVAL;
+ goto exit;
}
} else if (cmd_head.flag == 2) {
/* Need interrupt! */
@@ -382,7 +404,8 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
cmd_head.data_len + cmd_head.addr_len) <= 0) {
GTP_ERROR("[WRITE]Write data failed!");
- return FAIL;
+ ret = -EIO;
+ goto exit;
}
GTP_DEBUG_ARRAY(
@@ -391,7 +414,8 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
if (cmd_head.delay)
msleep(cmd_head.delay);
- return cmd_head.data_len + CMD_HEAD_LENGTH;
+ ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+ goto exit;
} else if (cmd_head.wr == 3) { /* Write ic type */
ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
@@ -399,30 +423,40 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
if (ret)
GTP_ERROR("copy_from_user failed.");
+ if (cmd_head.data_len > sizeof(IC_TYPE)) {
+ pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
+ cmd_head.data_len, sizeof(IC_TYPE));
+ ret = -EINVAL;
+ goto exit;
+ }
memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
register_i2c_func();
- return cmd_head.data_len + CMD_HEAD_LENGTH;
- } else if (cmd_head.wr == 3) {
+ ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+ goto exit;
+ } else if (cmd_head.wr == 5) {
/* memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); */
- return cmd_head.data_len + CMD_HEAD_LENGTH;
+ ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+ goto exit;
} else if (cmd_head.wr == 7) { /* disable irq! */
gtp_irq_disable(i2c_get_clientdata(gt_client));
#if GTP_ESD_PROTECT
gtp_esd_switch(gt_client, SWITCH_OFF);
#endif
- return CMD_HEAD_LENGTH;
+ ret = CMD_HEAD_LENGTH;
+ goto exit;
} else if (cmd_head.wr == 9) { /* enable irq! */
gtp_irq_enable(i2c_get_clientdata(gt_client));
#if GTP_ESD_PROTECT
gtp_esd_switch(gt_client, SWITCH_ON);
#endif
- return CMD_HEAD_LENGTH;
+ ret = CMD_HEAD_LENGTH;
+ goto exit;
} else if (cmd_head.wr == 17) {
struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
@@ -436,27 +470,41 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
ts->gtp_rawdiff_mode = false;
GTP_DEBUG("gtp leave rawdiff.");
}
- return CMD_HEAD_LENGTH;
+ ret = CMD_HEAD_LENGTH;
+ goto exit;
}
#ifdef UPDATE_FUNCTIONS
else if (cmd_head.wr == 11) { /* Enter update mode! */
- if (FAIL == gup_enter_update_mode(gt_client))
- return FAIL;
+ if (FAIL == gup_enter_update_mode(gt_client)) {
+ ret = -EBUSY;
+ goto exit;
+ }
} else if (cmd_head.wr == 13) { /* Leave update mode! */
gup_leave_update_mode();
} else if (cmd_head.wr == 15) { /* Update firmware! */
show_len = 0;
total_len = 0;
+ if (cmd_head.data_len + 1 > DATA_LENGTH) {
+ pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
+ cmd_head.data_len + 1, DATA_LENGTH);
+ ret = -EINVAL;
+ goto exit;
+ }
memset(cmd_head.data, 0, cmd_head.data_len + 1);
memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH],
cmd_head.data_len);
- if (FAIL == gup_update_proc((void *)cmd_head.data))
- return FAIL;
+ if (FAIL == gup_update_proc((void *)cmd_head.data)) {
+ ret = -EBUSY;
+ goto exit;
+ }
}
#endif
+ ret = CMD_HEAD_LENGTH;
- return CMD_HEAD_LENGTH;
+exit:
+ mutex_unlock(&lock);
+ return ret;
}
/*******************************************************
@@ -470,10 +518,14 @@ Output:
static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
+ s32 ret;
GTP_DEBUG_FUNC();
+ mutex_lock(&lock);
if (cmd_head.wr % 2) {
- return FAIL;
+ pr_err("<< [READ]command head wrong\n");
+ ret = -EINVAL;
+ goto exit;
} else if (!cmd_head.wr) {
u16 len = 0;
s16 data_len = 0;
@@ -482,7 +534,8 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
if (cmd_head.flag == 1) {
if (FAIL == comfirm()) {
GTP_ERROR("[READ]Comfirm fail!");
- return FAIL;
+ ret = -EINVAL;
+ goto exit;
}
} else if (cmd_head.flag == 2) {
/* Need interrupt! */
@@ -505,11 +558,12 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
else
len = data_len;
- data_len -= DATA_LENGTH;
+ data_len -= len;
if (tool_i2c_read(cmd_head.data, len) <= 0) {
GTP_ERROR("[READ]Read data failed!");
- return FAIL;
+ ret = -EINVAL;
+ goto exit;
}
memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH],
len);
@@ -525,15 +579,14 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
GTP_DEBUG("Return ic type:%s len:%d.", page,
(s32)cmd_head.data_len);
- return cmd_head.data_len;
+ ret = cmd_head.data_len;
+ goto exit;
/* return sizeof(IC_TYPE_NAME); */
} else if (cmd_head.wr == 4) {
page[0] = show_len >> 8;
page[1] = show_len & 0xff;
page[2] = total_len >> 8;
page[3] = total_len & 0xff;
-
- return cmd_head.data_len;
} else if (6 == cmd_head.wr) {
/* Read error code! */
} else if (8 == cmd_head.wr) { /*Read driver version */
@@ -544,6 +597,9 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
memcpy(page, GTP_DRIVER_VERSION, tmp_len);
page[tmp_len] = 0;
}
+ ret = cmd_head.data_len;
- return cmd_head.data_len;
+exit:
+ mutex_unlock(&lock);
+ return ret;
}
--
cgit v1.1

View File

@ -0,0 +1,300 @@
From f53bcf29a6e7a66b3d935b8d562fa00829261f05 Mon Sep 17 00:00:00 2001
From: Bingzhe Cai <bingzhec@codeaurora.org>
Date: Tue, 24 Sep 2013 01:42:12 +0800
Subject: input: touchpanel: fix security issues in GT915 driver
There are multiple buffer overflow and input validation issues
in Goodix gt915 driver, fix these issues by adding data length
check and change file system node mode.
CRs-Fixed: 526101
Change-Id: I5173fc1ca021fd45c939c7c8a4f460651330de5b
Signed-off-by: Bingzhe Cai <bingzhec@codeaurora.org>
---
drivers/input/touchscreen/gt9xx/goodix_tool.c | 110 +++++++++++++++++++-------
1 file changed, 83 insertions(+), 27 deletions(-)
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
index bdac3fd..aa8159f 100644
--- a/drivers/input/touchscreen/gt9xx/goodix_tool.c
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -22,6 +22,7 @@
*/
#include "gt9xx.h"
+#include <linux/mutex.h>
#define DATA_LENGTH_UINT 512
#define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8 *))
@@ -53,6 +54,8 @@ static struct i2c_client *gt_client;
static struct proc_dir_entry *goodix_proc_entry;
+static struct mutex lock;
+
static s32 goodix_tool_write(struct file *filp, const char __user *buff,
unsigned long len, void *data);
static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
@@ -188,7 +191,7 @@ static void unregister_i2c_func(void)
s32 init_wr_node(struct i2c_client *client)
{
- s32 i;
+ u8 i;
gt_client = client;
memset(&cmd_head, 0, sizeof(cmd_head));
@@ -202,8 +205,8 @@ s32 init_wr_node(struct i2c_client *client)
i--;
}
if (i) {
- DATA_LENGTH = i * DATA_LENGTH_UINT + GTP_ADDR_LENGTH;
- GTP_INFO("Applied memory size:%d.", DATA_LENGTH);
+ DATA_LENGTH = i * DATA_LENGTH_UINT;
+ dev_dbg(&client->dev, "Applied memory size:%d.", DATA_LENGTH);
} else {
GTP_ERROR("Apply for memory failed.");
return FAIL;
@@ -214,8 +217,9 @@ s32 init_wr_node(struct i2c_client *client)
register_i2c_func();
+ mutex_init(&lock);
tool_set_proc_name(procname);
- goodix_proc_entry = create_proc_entry(procname, 0666, NULL);
+ goodix_proc_entry = create_proc_entry(procname, 0660, NULL);
if (goodix_proc_entry == NULL) {
GTP_ERROR("Couldn't create proc entry!");
return FAIL;
@@ -334,9 +338,13 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
GTP_DEBUG_FUNC();
GTP_DEBUG_ARRAY((u8 *)buff, len);
+ mutex_lock(&lock);
ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
- if (ret)
+ if (ret) {
GTP_ERROR("copy_from_user failed.");
+ ret = -EACCES;
+ goto exit;
+ }
GTP_DEBUG("wr :0x%02x.", cmd_head.wr);
GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
@@ -354,6 +362,19 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
GTP_DEBUG("len:%d.", (s32)len);
GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
+ if (cmd_head.data_len > (DATA_LENGTH - GTP_ADDR_LENGTH)) {
+ pr_err("data len %d > data buff %d, rejected!\n",
+ cmd_head.data_len, (DATA_LENGTH - GTP_ADDR_LENGTH));
+ ret = -EINVAL;
+ goto exit;
+ }
+ if (cmd_head.addr_len > GTP_ADDR_LENGTH) {
+ pr_err(" addr len %d > data buff %d, rejected!\n",
+ cmd_head.addr_len, GTP_ADDR_LENGTH);
+ ret = -EINVAL;
+ goto exit;
+ }
+
if (cmd_head.wr == 1) {
/* copy_from_user(&cmd_head.data[cmd_head.addr_len],
&buff[CMD_HEAD_LENGTH], cmd_head.data_len); */
@@ -373,7 +394,8 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
if (cmd_head.flag == 1) {
if (FAIL == comfirm()) {
GTP_ERROR("[WRITE]Comfirm fail!");
- return FAIL;
+ ret = -EINVAL;
+ goto exit;
}
} else if (cmd_head.flag == 2) {
/* Need interrupt! */
@@ -382,7 +404,8 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
cmd_head.data_len + cmd_head.addr_len) <= 0) {
GTP_ERROR("[WRITE]Write data failed!");
- return FAIL;
+ ret = -EIO;
+ goto exit;
}
GTP_DEBUG_ARRAY(
@@ -391,7 +414,8 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
if (cmd_head.delay)
msleep(cmd_head.delay);
- return cmd_head.data_len + CMD_HEAD_LENGTH;
+ ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+ goto exit;
} else if (cmd_head.wr == 3) { /* Write ic type */
ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
@@ -399,30 +423,40 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
if (ret)
GTP_ERROR("copy_from_user failed.");
+ if (cmd_head.data_len > sizeof(IC_TYPE)) {
+ pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
+ cmd_head.data_len, sizeof(IC_TYPE));
+ ret = -EINVAL;
+ goto exit;
+ }
memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
register_i2c_func();
- return cmd_head.data_len + CMD_HEAD_LENGTH;
- } else if (cmd_head.wr == 3) {
+ ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+ goto exit;
+ } else if (cmd_head.wr == 5) {
/* memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); */
- return cmd_head.data_len + CMD_HEAD_LENGTH;
+ ret = cmd_head.data_len + CMD_HEAD_LENGTH;
+ goto exit;
} else if (cmd_head.wr == 7) { /* disable irq! */
gtp_irq_disable(i2c_get_clientdata(gt_client));
#if GTP_ESD_PROTECT
gtp_esd_switch(gt_client, SWITCH_OFF);
#endif
- return CMD_HEAD_LENGTH;
+ ret = CMD_HEAD_LENGTH;
+ goto exit;
} else if (cmd_head.wr == 9) { /* enable irq! */
gtp_irq_enable(i2c_get_clientdata(gt_client));
#if GTP_ESD_PROTECT
gtp_esd_switch(gt_client, SWITCH_ON);
#endif
- return CMD_HEAD_LENGTH;
+ ret = CMD_HEAD_LENGTH;
+ goto exit;
} else if (cmd_head.wr == 17) {
struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
@@ -436,27 +470,41 @@ static s32 goodix_tool_write(struct file *filp, const char __user *buff,
ts->gtp_rawdiff_mode = false;
GTP_DEBUG("gtp leave rawdiff.");
}
- return CMD_HEAD_LENGTH;
+ ret = CMD_HEAD_LENGTH;
+ goto exit;
}
#ifdef UPDATE_FUNCTIONS
else if (cmd_head.wr == 11) { /* Enter update mode! */
- if (FAIL == gup_enter_update_mode(gt_client))
- return FAIL;
+ if (FAIL == gup_enter_update_mode(gt_client)) {
+ ret = -EBUSY;
+ goto exit;
+ }
} else if (cmd_head.wr == 13) { /* Leave update mode! */
gup_leave_update_mode();
} else if (cmd_head.wr == 15) { /* Update firmware! */
show_len = 0;
total_len = 0;
+ if (cmd_head.data_len + 1 > DATA_LENGTH) {
+ pr_err("<<-GTP->> data len %d > data buff %d, rejected!\n",
+ cmd_head.data_len + 1, DATA_LENGTH);
+ ret = -EINVAL;
+ goto exit;
+ }
memset(cmd_head.data, 0, cmd_head.data_len + 1);
memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH],
cmd_head.data_len);
- if (FAIL == gup_update_proc((void *)cmd_head.data))
- return FAIL;
+ if (FAIL == gup_update_proc((void *)cmd_head.data)) {
+ ret = -EBUSY;
+ goto exit;
+ }
}
#endif
+ ret = CMD_HEAD_LENGTH;
- return CMD_HEAD_LENGTH;
+exit:
+ mutex_unlock(&lock);
+ return ret;
}
/*******************************************************
@@ -470,10 +518,14 @@ Output:
static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
{
+ s32 ret;
GTP_DEBUG_FUNC();
+ mutex_lock(&lock);
if (cmd_head.wr % 2) {
- return FAIL;
+ pr_err("<< [READ]command head wrong\n");
+ ret = -EINVAL;
+ goto exit;
} else if (!cmd_head.wr) {
u16 len = 0;
s16 data_len = 0;
@@ -482,7 +534,8 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
if (cmd_head.flag == 1) {
if (FAIL == comfirm()) {
GTP_ERROR("[READ]Comfirm fail!");
- return FAIL;
+ ret = -EINVAL;
+ goto exit;
}
} else if (cmd_head.flag == 2) {
/* Need interrupt! */
@@ -505,11 +558,12 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
else
len = data_len;
- data_len -= DATA_LENGTH;
+ data_len -= len;
if (tool_i2c_read(cmd_head.data, len) <= 0) {
GTP_ERROR("[READ]Read data failed!");
- return FAIL;
+ ret = -EINVAL;
+ goto exit;
}
memcpy(&page[loc], &cmd_head.data[GTP_ADDR_LENGTH],
len);
@@ -525,15 +579,14 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
GTP_DEBUG("Return ic type:%s len:%d.", page,
(s32)cmd_head.data_len);
- return cmd_head.data_len;
+ ret = cmd_head.data_len;
+ goto exit;
/* return sizeof(IC_TYPE_NAME); */
} else if (cmd_head.wr == 4) {
page[0] = show_len >> 8;
page[1] = show_len & 0xff;
page[2] = total_len >> 8;
page[3] = total_len & 0xff;
-
- return cmd_head.data_len;
} else if (6 == cmd_head.wr) {
/* Read error code! */
} else if (8 == cmd_head.wr) { /*Read driver version */
@@ -544,6 +597,9 @@ static s32 goodix_tool_read(char *page, char **start, off_t off, int count,
memcpy(page, GTP_DRIVER_VERSION, tmp_len);
page[tmp_len] = 0;
}
+ ret = cmd_head.data_len;
- return cmd_head.data_len;
+exit:
+ mutex_unlock(&lock);
+ return ret;
}
--
cgit v1.1

View File

@ -0,0 +1,39 @@
From 7beb04ea945a7178e61d935918d3cb152996b558 Mon Sep 17 00:00:00 2001
From: Alok Kediya <kediya@codeaurora.org>
Date: Mon, 9 Dec 2013 10:52:49 +0530
Subject: msm: camera: Added bounds check for index parameter
Bound check the index param from user space to avoid
any invalid memory access.
CRs-Fixed: 583366
Change-Id: I0f887bb8f1fa5a69a55e23dbb522b3bb694ad27f
Signed-off-by: Alok Kediya <kediya@codeaurora.org>
---
drivers/media/video/msm/server/msm_cam_server.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 5fc8e83..6e49082 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -1390,6 +1390,15 @@ static long msm_ioctl_server(struct file *file, void *fh,
}
mutex_lock(&g_server_dev.server_queue_lock);
+
+ if(u_isp_event.isp_data.ctrl.queue_idx < 0 ||
+ u_isp_event.isp_data.ctrl.queue_idx >= MAX_NUM_ACTIVE_CAMERA) {
+ pr_err("%s: Invalid index %d\n", __func__,
+ u_isp_event.isp_data.ctrl.queue_idx);
+ rc = -EINVAL;
+ return rc;
+ }
+
if (!g_server_dev.server_queue
[u_isp_event.isp_data.ctrl.queue_idx].queue_active) {
pr_err("%s: Invalid queue\n", __func__);
--
cgit v1.1

View File

@ -0,0 +1,67 @@
From 60e4af06161d91d5aeaa04c7d6e9f4345a6acdd4 Mon Sep 17 00:00:00 2001
From: Alok Kediya <kediya@codeaurora.org>
Date: Thu, 10 Oct 2013 12:11:01 +0530
Subject: msm:camera: Bounds and validity check for params
Check the range and validity of parameters before accessing.
CRs-fixed: 550607, 554434, 554436
Change-Id: I2d6aec4f9cb9385789c0df6a2c4abefe9e87539f
Signed-off-by: Alok Kediya <kediya@codeaurora.org>
---
drivers/media/video/msm/server/msm_cam_server.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 4bda7a3..5fc8e83 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -311,6 +311,13 @@ static int msm_ctrl_cmd_done(void *arg)
goto ctrl_cmd_done_error;
}
+ if(command->queue_idx < 0 ||
+ command->queue_idx >= MAX_NUM_ACTIVE_CAMERA) {
+ pr_err("%s: Invalid value OR index %d\n", __func__,
+ command->queue_idx);
+ goto ctrl_cmd_done_error;
+ }
+
if (!g_server_dev.server_queue[command->queue_idx].queue_active) {
pr_err("%s: Invalid queue\n", __func__);
goto ctrl_cmd_done_error;
@@ -339,7 +346,8 @@ static int msm_ctrl_cmd_done(void *arg)
max_control_command_size);
goto ctrl_cmd_done_error;
}
- if (copy_from_user(command->value, uptr, command->length)) {
+ if (copy_from_user(command->value, (void __user *)uptr,
+ command->length)) {
pr_err("%s: copy_from_user failed, size=%d\n",
__func__, sizeof(struct msm_ctrl_cmd));
goto ctrl_cmd_done_error;
@@ -2650,13 +2658,17 @@ int msm_server_send_ctrl(struct msm_ctrl_cmd *out,
struct msm_queue_cmd *event_qcmd;
struct msm_ctrl_cmd *ctrlcmd;
struct msm_cam_server_dev *server_dev = &g_server_dev;
- struct msm_device_queue *queue =
- &server_dev->server_queue[out->queue_idx].ctrl_q;
-
+ struct msm_device_queue *queue;
struct v4l2_event v4l2_evt;
struct msm_isp_event_ctrl *isp_event;
void *ctrlcmd_data;
+ if(out->queue_idx < 0 || out->queue_idx >= MAX_NUM_ACTIVE_CAMERA) {
+ pr_err("%s: Invalid index %d\n", __func__, out->queue_idx);
+ return -EINVAL;
+ }
+ queue = &server_dev->server_queue[out->queue_idx].ctrl_q;
+
event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
if (!event_qcmd) {
pr_err("%s Insufficient memory. return", __func__);
--
cgit v1.1

View File

@ -0,0 +1,253 @@
From 76565e3d786bed66f247c682bd9f591098522483 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Fri, 7 Sep 2012 18:22:28 +0100
Subject: ARM: 7527/1: uaccess: explicitly check __user pointer when
!CPU_USE_DOMAINS
The {get,put}_user macros don't perform range checking on the provided
__user address when !CPU_HAS_DOMAINS.
This patch reworks the out-of-line assembly accessors to check the user
address against a specified limit, returning -EFAULT if is is out of
range.
[will: changed get_user register allocation to match put_user]
[rmk: fixed building on older ARM architectures]
CRs-Fixed: 504011
Change-Id: I3818045a136fcdf72deb1371b132e090fd7ed643
Reported-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Cc: stable@vger.kernel.org
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Git-commit: 8404663f81d212918ff85f493649a7991209fa04
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Signed-off-by: Laura Abbott <lauraa@codeaurora.org>
---
arch/arm/include/asm/assembler.h | 8 ++++++++
arch/arm/include/asm/uaccess.h | 40 +++++++++++++++++++++++++++-------------
arch/arm/lib/getuser.S | 23 +++++++++++++++--------
arch/arm/lib/putuser.S | 6 ++++++
4 files changed, 56 insertions(+), 21 deletions(-)
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 03fb936..5c8b3bf4 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -320,4 +320,12 @@
.size \name , . - \name
.endm
+ .macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req
+#ifndef CONFIG_CPU_USE_DOMAINS
+ adds \tmp, \addr, #\size - 1
+ sbcccs \tmp, \tmp, \limit
+ bcs \bad
+#endif
+ .endm
+
#endif /* __ASM_ASSEMBLER_H__ */
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 71f6536..0a070e9 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -101,28 +101,39 @@ extern int __get_user_1(void *);
extern int __get_user_2(void *);
extern int __get_user_4(void *);
-#define __get_user_x(__r2,__p,__e,__s,__i...) \
+#define __GUP_CLOBBER_1 "lr", "cc"
+#ifdef CONFIG_CPU_USE_DOMAINS
+#define __GUP_CLOBBER_2 "ip", "lr", "cc"
+#else
+#define __GUP_CLOBBER_2 "lr", "cc"
+#endif
+#define __GUP_CLOBBER_4 "lr", "cc"
+
+#define __get_user_x(__r2,__p,__e,__l,__s) \
__asm__ __volatile__ ( \
__asmeq("%0", "r0") __asmeq("%1", "r2") \
+ __asmeq("%3", "r1") \
"bl __get_user_" #__s \
: "=&r" (__e), "=r" (__r2) \
- : "0" (__p) \
- : __i, "cc")
+ : "0" (__p), "r" (__l) \
+ : __GUP_CLOBBER_##__s)
#define get_user(x,p) \
({ \
+ unsigned long __limit = current_thread_info()->addr_limit - 1; \
register const typeof(*(p)) __user *__p asm("r0") = (p);\
register unsigned long __r2 asm("r2"); \
+ register unsigned long __l asm("r1") = __limit; \
register int __e asm("r0"); \
switch (sizeof(*(__p))) { \
case 1: \
- __get_user_x(__r2, __p, __e, 1, "lr"); \
- break; \
+ __get_user_x(__r2, __p, __e, __l, 1); \
+ break; \
case 2: \
- __get_user_x(__r2, __p, __e, 2, "r3", "lr"); \
+ __get_user_x(__r2, __p, __e, __l, 2); \
break; \
case 4: \
- __get_user_x(__r2, __p, __e, 4, "lr"); \
+ __get_user_x(__r2, __p, __e, __l, 4); \
break; \
default: __e = __get_user_bad(); break; \
} \
@@ -135,31 +146,34 @@ extern int __put_user_2(void *, unsigned int);
extern int __put_user_4(void *, unsigned int);
extern int __put_user_8(void *, unsigned long long);
-#define __put_user_x(__r2,__p,__e,__s) \
+#define __put_user_x(__r2,__p,__e,__l,__s) \
__asm__ __volatile__ ( \
__asmeq("%0", "r0") __asmeq("%2", "r2") \
+ __asmeq("%3", "r1") \
"bl __put_user_" #__s \
: "=&r" (__e) \
- : "0" (__p), "r" (__r2) \
+ : "0" (__p), "r" (__r2), "r" (__l) \
: "ip", "lr", "cc")
#define put_user(x,p) \
({ \
+ unsigned long __limit = current_thread_info()->addr_limit - 1; \
register const typeof(*(p)) __r2 asm("r2") = (x); \
register const typeof(*(p)) __user *__p asm("r0") = (p);\
+ register unsigned long __l asm("r1") = __limit; \
register int __e asm("r0"); \
switch (sizeof(*(__p))) { \
case 1: \
- __put_user_x(__r2, __p, __e, 1); \
+ __put_user_x(__r2, __p, __e, __l, 1); \
break; \
case 2: \
- __put_user_x(__r2, __p, __e, 2); \
+ __put_user_x(__r2, __p, __e, __l, 2); \
break; \
case 4: \
- __put_user_x(__r2, __p, __e, 4); \
+ __put_user_x(__r2, __p, __e, __l, 4); \
break; \
case 8: \
- __put_user_x(__r2, __p, __e, 8); \
+ __put_user_x(__r2, __p, __e, __l, 8); \
break; \
default: __e = __put_user_bad(); break; \
} \
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S
index 11093a7..9b06bb4 100644
--- a/arch/arm/lib/getuser.S
+++ b/arch/arm/lib/getuser.S
@@ -16,8 +16,9 @@
* __get_user_X
*
* Inputs: r0 contains the address
+ * r1 contains the address limit, which must be preserved
* Outputs: r0 is the error code
- * r2, r3 contains the zero-extended value
+ * r2 contains the zero-extended value
* lr corrupted
*
* No other registers must be altered. (see <asm/uaccess.h>
@@ -27,33 +28,39 @@
* Note also that it is intended that __get_user_bad is not global.
*/
#include <linux/linkage.h>
+#include <asm/assembler.h>
#include <asm/errno.h>
#include <asm/domain.h>
ENTRY(__get_user_1)
+ check_uaccess r0, 1, r1, r2, __get_user_bad
1: TUSER(ldrb) r2, [r0]
mov r0, #0
mov pc, lr
ENDPROC(__get_user_1)
ENTRY(__get_user_2)
-#ifdef CONFIG_THUMB2_KERNEL
-2: TUSER(ldrb) r2, [r0]
-3: TUSER(ldrb) r3, [r0, #1]
+ check_uaccess r0, 2, r1, r2, __get_user_bad
+#ifdef CONFIG_CPU_USE_DOMAINS
+rb .req ip
+2: ldrbt r2, [r0], #1
+3: ldrbt rb, [r0], #0
#else
-2: TUSER(ldrb) r2, [r0], #1
-3: TUSER(ldrb) r3, [r0]
+rb .req r0
+2: ldrb r2, [r0]
+3: ldrb rb, [r0, #1]
#endif
#ifndef __ARMEB__
- orr r2, r2, r3, lsl #8
+ orr r2, r2, rb, lsl #8
#else
- orr r2, r3, r2, lsl #8
+ orr r2, rb, r2, lsl #8
#endif
mov r0, #0
mov pc, lr
ENDPROC(__get_user_2)
ENTRY(__get_user_4)
+ check_uaccess r0, 4, r1, r2, __get_user_bad
4: TUSER(ldr) r2, [r0]
mov r0, #0
mov pc, lr
diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S
index 7db2599..3d73dcb9 100644
--- a/arch/arm/lib/putuser.S
+++ b/arch/arm/lib/putuser.S
@@ -16,6 +16,7 @@
* __put_user_X
*
* Inputs: r0 contains the address
+ * r1 contains the address limit, which must be preserved
* r2, r3 contains the value
* Outputs: r0 is the error code
* lr corrupted
@@ -27,16 +28,19 @@
* Note also that it is intended that __put_user_bad is not global.
*/
#include <linux/linkage.h>
+#include <asm/assembler.h>
#include <asm/errno.h>
#include <asm/domain.h>
ENTRY(__put_user_1)
+ check_uaccess r0, 1, r1, ip, __put_user_bad
1: TUSER(strb) r2, [r0]
mov r0, #0
mov pc, lr
ENDPROC(__put_user_1)
ENTRY(__put_user_2)
+ check_uaccess r0, 2, r1, ip, __put_user_bad
mov ip, r2, lsr #8
#ifdef CONFIG_THUMB2_KERNEL
#ifndef __ARMEB__
@@ -60,12 +64,14 @@ ENTRY(__put_user_2)
ENDPROC(__put_user_2)
ENTRY(__put_user_4)
+ check_uaccess r0, 4, r1, ip, __put_user_bad
4: TUSER(str) r2, [r0]
mov r0, #0
mov pc, lr
ENDPROC(__put_user_4)
ENTRY(__put_user_8)
+ check_uaccess r0, 8, r1, ip, __put_user_bad
#ifdef CONFIG_THUMB2_KERNEL
5: TUSER(str) r2, [r0]
6: TUSER(str) r3, [r0, #4]
--
cgit v1.1

View File

@ -0,0 +1,320 @@
From 7d267278a9ece963d77eefec61630223fce08c6c Mon Sep 17 00:00:00 2001
From: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Date: Fri, 20 Nov 2015 22:07:23 +0000
Subject: unix: avoid use-after-free in ep_remove_wait_queue
Rainer Weikusat <rweikusat@mobileactivedefense.com> writes:
An AF_UNIX datagram socket being the client in an n:1 association with
some server socket is only allowed to send messages to the server if the
receive queue of this socket contains at most sk_max_ack_backlog
datagrams. This implies that prospective writers might be forced to go
to sleep despite none of the message presently enqueued on the server
receive queue were sent by them. In order to ensure that these will be
woken up once space becomes again available, the present unix_dgram_poll
routine does a second sock_poll_wait call with the peer_wait wait queue
of the server socket as queue argument (unix_dgram_recvmsg does a wake
up on this queue after a datagram was received). This is inherently
problematic because the server socket is only guaranteed to remain alive
for as long as the client still holds a reference to it. In case the
connection is dissolved via connect or by the dead peer detection logic
in unix_dgram_sendmsg, the server socket may be freed despite "the
polling mechanism" (in particular, epoll) still has a pointer to the
corresponding peer_wait queue. There's no way to forcibly deregister a
wait queue with epoll.
Based on an idea by Jason Baron, the patch below changes the code such
that a wait_queue_t belonging to the client socket is enqueued on the
peer_wait queue of the server whenever the peer receive queue full
condition is detected by either a sendmsg or a poll. A wake up on the
peer queue is then relayed to the ordinary wait queue of the client
socket via wake function. The connection to the peer wait queue is again
dissolved if either a wake up is about to be relayed or the client
socket reconnects or a dead peer is detected or the client socket is
itself closed. This enables removing the second sock_poll_wait from
unix_dgram_poll, thus avoiding the use-after-free, while still ensuring
that no blocked writer sleeps forever.
Signed-off-by: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Fixes: ec0d215f9420 ("af_unix: fix 'poll for write'/connected DGRAM sockets")
Reviewed-by: Jason Baron <jbaron@akamai.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/unix/af_unix.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 164 insertions(+), 19 deletions(-)
(limited to 'net/unix/af_unix.c')
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 955ec15..4e95bdf 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -326,6 +326,118 @@ found:
return s;
}
+/* Support code for asymmetrically connected dgram sockets
+ *
+ * If a datagram socket is connected to a socket not itself connected
+ * to the first socket (eg, /dev/log), clients may only enqueue more
+ * messages if the present receive queue of the server socket is not
+ * "too large". This means there's a second writeability condition
+ * poll and sendmsg need to test. The dgram recv code will do a wake
+ * up on the peer_wait wait queue of a socket upon reception of a
+ * datagram which needs to be propagated to sleeping would-be writers
+ * since these might not have sent anything so far. This can't be
+ * accomplished via poll_wait because the lifetime of the server
+ * socket might be less than that of its clients if these break their
+ * association with it or if the server socket is closed while clients
+ * are still connected to it and there's no way to inform "a polling
+ * implementation" that it should let go of a certain wait queue
+ *
+ * In order to propagate a wake up, a wait_queue_t of the client
+ * socket is enqueued on the peer_wait queue of the server socket
+ * whose wake function does a wake_up on the ordinary client socket
+ * wait queue. This connection is established whenever a write (or
+ * poll for write) hit the flow control condition and broken when the
+ * association to the server socket is dissolved or after a wake up
+ * was relayed.
+ */
+
+static int unix_dgram_peer_wake_relay(wait_queue_t *q, unsigned mode, int flags,
+ void *key)
+{
+ struct unix_sock *u;
+ wait_queue_head_t *u_sleep;
+
+ u = container_of(q, struct unix_sock, peer_wake);
+
+ __remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait,
+ q);
+ u->peer_wake.private = NULL;
+
+ /* relaying can only happen while the wq still exists */
+ u_sleep = sk_sleep(&u->sk);
+ if (u_sleep)
+ wake_up_interruptible_poll(u_sleep, key);
+
+ return 0;
+}
+
+static int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other)
+{
+ struct unix_sock *u, *u_other;
+ int rc;
+
+ u = unix_sk(sk);
+ u_other = unix_sk(other);
+ rc = 0;
+ spin_lock(&u_other->peer_wait.lock);
+
+ if (!u->peer_wake.private) {
+ u->peer_wake.private = other;
+ __add_wait_queue(&u_other->peer_wait, &u->peer_wake);
+
+ rc = 1;
+ }
+
+ spin_unlock(&u_other->peer_wait.lock);
+ return rc;
+}
+
+static void unix_dgram_peer_wake_disconnect(struct sock *sk,
+ struct sock *other)
+{
+ struct unix_sock *u, *u_other;
+
+ u = unix_sk(sk);
+ u_other = unix_sk(other);
+ spin_lock(&u_other->peer_wait.lock);
+
+ if (u->peer_wake.private == other) {
+ __remove_wait_queue(&u_other->peer_wait, &u->peer_wake);
+ u->peer_wake.private = NULL;
+ }
+
+ spin_unlock(&u_other->peer_wait.lock);
+}
+
+static void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk,
+ struct sock *other)
+{
+ unix_dgram_peer_wake_disconnect(sk, other);
+ wake_up_interruptible_poll(sk_sleep(sk),
+ POLLOUT |
+ POLLWRNORM |
+ POLLWRBAND);
+}
+
+/* preconditions:
+ * - unix_peer(sk) == other
+ * - association is stable
+ */
+static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other)
+{
+ int connected;
+
+ connected = unix_dgram_peer_wake_connect(sk, other);
+
+ if (unix_recvq_full(other))
+ return 1;
+
+ if (connected)
+ unix_dgram_peer_wake_disconnect(sk, other);
+
+ return 0;
+}
+
static int unix_writable(const struct sock *sk)
{
return sk->sk_state != TCP_LISTEN &&
@@ -431,6 +543,8 @@ static void unix_release_sock(struct sock *sk, int embrion)
skpair->sk_state_change(skpair);
sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP);
}
+
+ unix_dgram_peer_wake_disconnect(sk, skpair);
sock_put(skpair); /* It may now die */
unix_peer(sk) = NULL;
}
@@ -666,6 +780,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern)
INIT_LIST_HEAD(&u->link);
mutex_init(&u->readlock); /* single task reading lock */
init_waitqueue_head(&u->peer_wait);
+ init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
unix_insert_socket(unix_sockets_unbound(sk), sk);
out:
if (sk == NULL)
@@ -1033,6 +1148,8 @@ restart:
if (unix_peer(sk)) {
struct sock *old_peer = unix_peer(sk);
unix_peer(sk) = other;
+ unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer);
+
unix_state_double_unlock(sk, other);
if (other != old_peer)
@@ -1472,6 +1589,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
struct scm_cookie scm;
int max_level;
int data_len = 0;
+ int sk_locked;
wait_for_unix_gc();
err = scm_send(sock, msg, &scm, false);
@@ -1550,12 +1668,14 @@ restart:
goto out_free;
}
+ sk_locked = 0;
unix_state_lock(other);
+restart_locked:
err = -EPERM;
if (!unix_may_send(sk, other))
goto out_unlock;
- if (sock_flag(other, SOCK_DEAD)) {
+ if (unlikely(sock_flag(other, SOCK_DEAD))) {
/*
* Check with 1003.1g - what should
* datagram error
@@ -1563,10 +1683,14 @@ restart:
unix_state_unlock(other);
sock_put(other);
+ if (!sk_locked)
+ unix_state_lock(sk);
+
err = 0;
- unix_state_lock(sk);
if (unix_peer(sk) == other) {
unix_peer(sk) = NULL;
+ unix_dgram_peer_wake_disconnect_wakeup(sk, other);
+
unix_state_unlock(sk);
unix_dgram_disconnected(sk, other);
@@ -1592,21 +1716,38 @@ restart:
goto out_unlock;
}
- if (unix_peer(other) != sk && unix_recvq_full(other)) {
- if (!timeo) {
- err = -EAGAIN;
- goto out_unlock;
+ if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) {
+ if (timeo) {
+ timeo = unix_wait_for_peer(other, timeo);
+
+ err = sock_intr_errno(timeo);
+ if (signal_pending(current))
+ goto out_free;
+
+ goto restart;
}
- timeo = unix_wait_for_peer(other, timeo);
+ if (!sk_locked) {
+ unix_state_unlock(other);
+ unix_state_double_lock(sk, other);
+ }
- err = sock_intr_errno(timeo);
- if (signal_pending(current))
- goto out_free;
+ if (unix_peer(sk) != other ||
+ unix_dgram_peer_wake_me(sk, other)) {
+ err = -EAGAIN;
+ sk_locked = 1;
+ goto out_unlock;
+ }
- goto restart;
+ if (!sk_locked) {
+ sk_locked = 1;
+ goto restart_locked;
+ }
}
+ if (unlikely(sk_locked))
+ unix_state_unlock(sk);
+
if (sock_flag(other, SOCK_RCVTSTAMP))
__net_timestamp(skb);
maybe_add_creds(skb, sock, other);
@@ -1620,6 +1761,8 @@ restart:
return len;
out_unlock:
+ if (sk_locked)
+ unix_state_unlock(sk);
unix_state_unlock(other);
out_free:
kfree_skb(skb);
@@ -2476,14 +2619,16 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
return mask;
writable = unix_writable(sk);
- other = unix_peer_get(sk);
- if (other) {
- if (unix_peer(other) != sk) {
- sock_poll_wait(file, &unix_sk(other)->peer_wait, wait);
- if (unix_recvq_full(other))
- writable = 0;
- }
- sock_put(other);
+ if (writable) {
+ unix_state_lock(sk);
+
+ other = unix_peer(sk);
+ if (other && unix_peer(other) != sk &&
+ unix_recvq_full(other) &&
+ unix_dgram_peer_wake_me(sk, other))
+ writable = 0;
+
+ unix_state_unlock(sk);
}
if (writable)
--
cgit v1.1

View File

@ -0,0 +1,181 @@
From 7613c9d520ee4d227e635f6db0270d4cf26102bc Mon Sep 17 00:00:00 2001
From: Jordan Crouse <jcrouse@codeaurora.org>
Date: Mon, 21 Apr 2014 15:04:54 -0600
Subject: msm: kgsl: Protect CP_STATE_DEBUG_INDEX
Put CP_STATE_DEBUG_INDEX and CP_STATE_DEBUG_DATA under protection
to keep it from being written from an IB1. Doing so however opens
up a subtle "feature" in the microcode: memory read opcodes turn off
protected mode in the microcode to do the read and then turns it
back on regardless of the initial state. This is a problem if the
memory read happens while protected mode is turned off and then we
try to access a protected register which then complains and goes boom.
To account for this irregularity explicitly turn back off protected
mode in all the places where we know this will be a problem.
Change-Id: Ic0dedbad1397ca9b80132241ac006560a615e042
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
---
drivers/gpu/msm/adreno.c | 24 +++++++++++++-----------
drivers/gpu/msm/adreno.h | 10 ++++++++++
drivers/gpu/msm/adreno_a3xx.c | 1 +
drivers/gpu/msm/kgsl_iommu.c | 16 ++++++++++++++++
4 files changed, 40 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 4b21218..9bd07c6 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1150,9 +1150,7 @@ static int adreno_iommu_setstate(struct kgsl_device *device,
uint32_t flags)
{
phys_addr_t pt_val;
- unsigned int link[230];
- unsigned int *cmds = &link[0];
- int sizedwords = 0;
+ unsigned int *link = NULL, *cmds;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int num_iommu_units;
struct kgsl_context *context;
@@ -1170,6 +1168,14 @@ static int adreno_iommu_setstate(struct kgsl_device *device,
if (context)
adreno_ctx = ADRENO_CONTEXT(context);
+ link = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (link == NULL) {
+ result = -ENOMEM;
+ goto done;
+ }
+
+ cmds = link;
+
result = kgsl_mmu_enable_clk(&device->mmu, KGSL_IOMMU_CONTEXT_USER);
if (result)
@@ -1192,17 +1198,11 @@ static int adreno_iommu_setstate(struct kgsl_device *device,
cmds += _adreno_iommu_setstate_v1(device, cmds, pt_val,
num_iommu_units, flags);
- sizedwords += (cmds - &link[0]);
- if (sizedwords == 0) {
- KGSL_DRV_ERR(device, "no commands generated\n");
- BUG();
- }
/* invalidate all base pointers */
*cmds++ = cp_type3_packet(CP_INVALIDATE_STATE, 1);
*cmds++ = 0x7fff;
- sizedwords += 2;
- if (sizedwords > (ARRAY_SIZE(link))) {
+ if ((unsigned int) (cmds - link) > (PAGE_SIZE / sizeof(unsigned int))) {
KGSL_DRV_ERR(device, "Temp command buffer overflow\n");
BUG();
}
@@ -1211,7 +1211,8 @@ static int adreno_iommu_setstate(struct kgsl_device *device,
* use the global timestamp for iommu clock disablement
*/
result = adreno_ringbuffer_issuecmds(device, adreno_ctx,
- KGSL_CMD_FLAGS_PMODE, &link[0], sizedwords);
+ KGSL_CMD_FLAGS_PMODE, link,
+ (unsigned int)(cmds - link));
/*
* On error disable the IOMMU clock right away otherwise turn it off
@@ -1225,6 +1226,7 @@ static int adreno_iommu_setstate(struct kgsl_device *device,
KGSL_IOMMU_CONTEXT_USER);
done:
+ kfree(link);
kgsl_context_put(context);
return result;
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 8e162ca..0b793fa 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -805,6 +805,11 @@ static inline int adreno_add_read_cmds(struct kgsl_device *device,
*cmds++ = val;
*cmds++ = 0xFFFFFFFF;
*cmds++ = 0xFFFFFFFF;
+
+ /* WAIT_REG_MEM turns back on protected mode - push it off */
+ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
cmds += __adreno_add_idle_indirect_cmds(cmds, nop_gpuaddr);
return cmds - start;
}
@@ -850,6 +855,11 @@ static inline int adreno_wait_reg_mem(unsigned int *cmds, unsigned int addr,
*cmds++ = val; /* ref val */
*cmds++ = mask;
*cmds++ = interval;
+
+ /* WAIT_REG_MEM turns back on protected mode - push it off */
+ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
return cmds - start;
}
/*
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 70ba50e..873a5c9 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2038,6 +2038,7 @@ static void a3xx_protect_init(struct kgsl_device *device)
/* CP registers */
adreno_set_protected_registers(device, &index, 0x1C0, 5);
+ adreno_set_protected_registers(device, &index, 0x1EC, 1);
adreno_set_protected_registers(device, &index, 0x1F6, 1);
adreno_set_protected_registers(device, &index, 0x1F8, 2);
adreno_set_protected_registers(device, &index, 0x45E, 2);
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index dba23b0..68b3420 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1036,6 +1036,10 @@ static unsigned int kgsl_iommu_sync_lock(struct kgsl_mmu *mmu,
*cmds++ = 0x1;
*cmds++ = 0x1;
+ /* WAIT_REG_MEM turns back on protected mode - push it off */
+ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
*cmds++ = cp_type3_packet(CP_MEM_WRITE, 2);
*cmds++ = lock_vars->turn;
*cmds++ = 0;
@@ -1050,11 +1054,19 @@ static unsigned int kgsl_iommu_sync_lock(struct kgsl_mmu *mmu,
*cmds++ = 0x1;
*cmds++ = 0x1;
+ /* WAIT_REG_MEM turns back on protected mode - push it off */
+ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
*cmds++ = cp_type3_packet(CP_TEST_TWO_MEMS, 3);
*cmds++ = lock_vars->flag[PROC_APPS];
*cmds++ = lock_vars->turn;
*cmds++ = 0;
+ /* TEST_TWO_MEMS turns back on protected mode - push it off */
+ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
cmds += adreno_add_idle_cmds(adreno_dev, cmds);
return cmds - start;
@@ -1092,6 +1104,10 @@ static unsigned int kgsl_iommu_sync_unlock(struct kgsl_mmu *mmu,
*cmds++ = 0x1;
*cmds++ = 0x1;
+ /* WAIT_REG_MEM turns back on protected mode - push it off */
+ *cmds++ = cp_type3_packet(CP_SET_PROTECTED_MODE, 1);
+ *cmds++ = 0;
+
cmds += adreno_add_idle_cmds(adreno_dev, cmds);
return cmds - start;
--
cgit v1.1

View File

@ -0,0 +1,31 @@
From d7d07936a166e7421a6308eec443b707a9678580 Mon Sep 17 00:00:00 2001
From: Jordan Crouse <jcrouse@codeaurora.org>
Date: Thu, 17 Apr 2014 10:05:21 -0600
Subject: msm: kgsl: Mark the IOMMU setstate memory as read only
Mark the IOMMU setstate memory as read only in the pagetable.
Change-Id: Ic0dedbadb19e499c749cd744c3e89be3bcb4c2a2
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
---
drivers/gpu/msm/kgsl_mmu.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 95aac09..eb6d76f 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -377,6 +377,10 @@ int kgsl_mmu_init(struct kgsl_device *device)
PAGE_SIZE);
if (status)
return status;
+
+ /* Mark the setstate memory as read only */
+ mmu->setstate_memory.flags |= KGSL_MEMFLAGS_GPUREADONLY;
+
kgsl_sharedmem_set(device, &mmu->setstate_memory, 0, 0,
mmu->setstate_memory.size);
--
cgit v1.1

View File

@ -0,0 +1,35 @@
From 832666bda9606623c3cff5b14873553f82ec1281 Mon Sep 17 00:00:00 2001
From: Suman Mukherjee <sumam@codeaurora.org>
Date: Tue, 9 Dec 2014 13:25:36 +0530
Subject: msm: camera: add check for csid_cid to prevent of overwrite memory
add sanity check for csid cid to ensute that we never read or write
outside csid_dev->mem buffer
Change-Id: Ic8f0d689fa176720ae3a3316f2ad27556ae7bde5
Signed-off-by: Suman Mukherjee <sumam@codeaurora.org>
---
drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 3596a12..53a5ed3 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -50,6 +50,13 @@ static int msm_csid_cid_lut(
return -EINVAL;
}
for (i = 0; i < csid_lut_params->num_cid && i < 16; i++) {
+ if (csid_lut_params->vc_cfg[i]->cid >=
+ csid_lut_params->num_cid ||
+ csid_lut_params->vc_cfg[i]->cid < 0) {
+ pr_err("%s: cid outside range %d\n",
+ __func__, csid_lut_params->vc_cfg[i]->cid);
+ return -EINVAL;
+ }
CDBG("%s lut params num_cid = %d, cid = %d, dt = %x, df = %d\n",
__func__,
csid_lut_params->num_cid,
--
cgit v1.1

View File

@ -0,0 +1,31 @@
From ee37138b8ceee6035c93756043eaac7eaa1c0948 Mon Sep 17 00:00:00 2001
From: Suman Mukherjee <sumam@codeaurora.org>
Date: Wed, 17 Dec 2014 10:00:49 +0530
Subject: msm: camera: ispif: Validate vfe_intf parameter
Validate vfe_intf parameter to avoid invalid register access.
Change-Id: Ie0b57071cc5fca1c48d3a5e2e7819f9af9ff544c
Signed-off-by: Suman Mukherjee <sumam@codeaurora.org>
---
drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 8f99ff6..d044c1d 100755
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -60,8 +60,8 @@ static void msm_ispif_io_dump_reg(struct ispif_device *ispif)
static inline int msm_ispif_is_intf_valid(uint32_t csid_version,
uint8_t intf_type)
{
- return (csid_version <= CSID_VERSION_V22 && intf_type != VFE0) ?
- false : true;
+ return ((csid_version <= CSID_VERSION_V22 && intf_type != VFE0) ||
+ (intf_type >= VFE_MAX)) ? false : true;
}
static struct msm_cam_clk_info ispif_8626_reset_clk_info[] = {
--
cgit v1.1

View File

@ -1,92 +0,0 @@
From d41eb74e53d94aba656ffda647d106808e636cd6 Mon Sep 17 00:00:00 2001
From: Mathias Krause <minipli@googlemail.com>
Date: Sun, 13 Apr 2014 18:23:33 +0200
Subject: filter: prevent nla extensions to peek beyond the end of the message
[ Upstream commit 05ab8f2647e4221cbdb3856dd7d32bd5407316b3 ]
The BPF_S_ANC_NLATTR and BPF_S_ANC_NLATTR_NEST extensions fail to check
for a minimal message length before testing the supplied offset to be
within the bounds of the message. This allows the subtraction of the nla
header to underflow and therefore -- as the data type is unsigned --
allowing far to big offset and length values for the search of the
netlink attribute.
The remainder calculation for the BPF_S_ANC_NLATTR_NEST extension is
also wrong. It has the minuend and subtrahend mixed up, therefore
calculates a huge length value, allowing to overrun the end of the
message while looking for the netlink attribute.
The following three BPF snippets will trigger the bugs when attached to
a UNIX datagram socket and parsing a message with length 1, 2 or 3.
,-[ PoC for missing size check in BPF_S_ANC_NLATTR ]--
| ld #0x87654321
| ldx #42
| ld #nla
| ret a
`---
,-[ PoC for the same bug in BPF_S_ANC_NLATTR_NEST ]--
| ld #0x87654321
| ldx #42
| ld #nlan
| ret a
`---
,-[ PoC for wrong remainder calculation in BPF_S_ANC_NLATTR_NEST ]--
| ; (needs a fake netlink header at offset 0)
| ld #0
| ldx #42
| ld #nlan
| ret a
`---
Fix the first issue by ensuring the message length fulfills the minimal
size constrains of a nla header. Fix the second bug by getting the math
for the remainder calculation right.
Fixes: 4738c1db15 ("[SKFILTER]: Add SKF_ADF_NLATTR instruction")
Fixes: d214c7537b ("filter: add SKF_AD_NLATTR_NEST to look for nested..")
Cc: Patrick McHardy <kaber@trash.net>
Cc: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Mathias Krause <minipli@googlemail.com>
Acked-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
[bwh: Fix misplacement of the first check due to a bug in the patch program]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
net/core/filter.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/net/core/filter.c b/net/core/filter.c
index 5dea452..9c88080 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -320,6 +320,8 @@ load_b:
if (skb_is_nonlinear(skb))
return 0;
+ if (skb->len < sizeof(struct nlattr))
+ return 0;
if (A > skb->len - sizeof(struct nlattr))
return 0;
@@ -336,11 +338,13 @@ load_b:
if (skb_is_nonlinear(skb))
return 0;
+ if (skb->len < sizeof(struct nlattr))
+ return 0;
if (A > skb->len - sizeof(struct nlattr))
return 0;
nla = (struct nlattr *)&skb->data[A];
- if (nla->nla_len > A - skb->len)
+ if (nla->nla_len > skb->len - A)
return 0;
nla = nla_find_nested(nla, X);
--
cgit v1.1

View File

@ -0,0 +1,66 @@
From 68c459daa22a26d6ca8f169baef6605ca8a285f2 Mon Sep 17 00:00:00 2001
From: Alok Kediya <kediya@codeaurora.org>
Date: Tue, 9 Dec 2014 12:53:29 +0530
Subject: msm: camera: isp: Validate reg_offset and len parameters
Validate reg_offset and len parameters before consuming to
avoid invalid register access.
Change-Id: I07676a6d10a9945fb0b99ebfd147075f896fbfab
Signed-off-by: Alok Kediya <kediya@codeaurora.org>
---
.../platform/msm/camera_v2/isp/msm_isp_util.c | 36 +++++++++++++++++++---
1 file changed, 31 insertions(+), 5 deletions(-)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 12fd081..620c01a 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -495,13 +495,39 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
uint32_t *cfg_data, uint32_t cmd_len)
{
switch (reg_cfg_cmd->cmd_type) {
- case VFE_WRITE: {
- if (resource_size(vfe_dev->vfe_mem) <
- (reg_cfg_cmd->u.rw_info.reg_offset +
- reg_cfg_cmd->u.rw_info.len)) {
- pr_err("%s: VFE_WRITE: Invalid length\n", __func__);
+ case VFE_WRITE:
+ case VFE_READ: {
+ if ((reg_cfg_cmd->u.rw_info.reg_offset >
+ (UINT_MAX - reg_cfg_cmd->u.rw_info.len)) ||
+ ((reg_cfg_cmd->u.rw_info.reg_offset +
+ reg_cfg_cmd->u.rw_info.len) >
+ resource_size(vfe_dev->vfe_mem))) {
+ pr_err("%s:%d reg_offset %d len %d res %d\n",
+ __func__, __LINE__,
+ reg_cfg_cmd->u.rw_info.reg_offset,
+ reg_cfg_cmd->u.rw_info.len,
+ (uint32_t)resource_size(vfe_dev->vfe_mem));
return -EINVAL;
}
+
+ if ((reg_cfg_cmd->u.rw_info.cmd_data_offset >
+ (UINT_MAX - reg_cfg_cmd->u.rw_info.len)) ||
+ ((reg_cfg_cmd->u.rw_info.cmd_data_offset +
+ reg_cfg_cmd->u.rw_info.len) > cmd_len)) {
+ pr_err("%s:%d cmd_data_offset %d len %d cmd_len %d\n",
+ __func__, __LINE__,
+ reg_cfg_cmd->u.rw_info.cmd_data_offset,
+ reg_cfg_cmd->u.rw_info.len, cmd_len);
+ return -EINVAL;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ switch (reg_cfg_cmd->cmd_type) {
+ case VFE_WRITE: {
msm_camera_io_memcpy(vfe_dev->vfe_base +
reg_cfg_cmd->u.rw_info.reg_offset,
cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4,
--
cgit v1.1

View File

@ -0,0 +1,94 @@
From b9470692c228608ef0ec60747ac2732ad7ffedf0 Mon Sep 17 00:00:00 2001
From: Mona Hossain <mhossain@codeaurora.org>
Date: Thu, 9 Oct 2014 12:00:03 -0700
Subject: qseecom: Add boundary checks for offset within message.
Qseecom driver does not have boundary checks for offset within the
message. So this patch add checks to validate the offsets sent by
client to modify data within the command request message and it
should not exceed the memory allocated for that message.
Change-Id: I29bfbdc154eebb4f3f4bfbb31789562e37fa5886
Signed-off-by: Mona Hossain <mhossain@codeaurora.org>
Signed-off-by: Mallikarjuna Reddy Amireddy <mamire@codeaurora.org>
---
drivers/misc/qseecom.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 3a93469..b091acd 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1525,6 +1525,30 @@ static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
return ret;
}
+int boundary_checks_offset(struct qseecom_send_modfd_cmd_req *cmd_req,
+ struct qseecom_send_modfd_listener_resp *lstnr_resp,
+ struct qseecom_dev_handle *data, bool listener_svc,
+ int i) {
+ int ret = 0;
+
+ if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
+ if (cmd_req->ifd_data[i].cmd_buf_offset >
+ cmd_req->cmd_req_len - sizeof(uint32_t)) {
+ pr_err("Invalid offset 0x%x\n",
+ cmd_req->ifd_data[i].cmd_buf_offset);
+ return ++ret;
+ }
+ } else if ((listener_svc) && (lstnr_resp->ifd_data[i].fd > 0)) {
+ if (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ lstnr_resp->resp_len - sizeof(uint32_t)) {
+ pr_err("Invalid offset 0x%x\n",
+ lstnr_resp->ifd_data[i].cmd_buf_offset);
+ return ++ret;
+ }
+ }
+ return ret;
+}
+
static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
struct qseecom_dev_handle *data,
bool listener_svc)
@@ -1598,6 +1622,10 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
if (sg_ptr->nents == 1) {
uint32_t *update;
update = (uint32_t *) field;
+
+ if (boundary_checks_offset(cmd_req, lstnr_resp, data,
+ listener_svc, i))
+ goto err;
if (cleanup)
*update = 0;
else
@@ -1607,6 +1635,27 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
} else {
struct qseecom_sg_entry *update;
int j = 0;
+
+ if ((!listener_svc) && (cmd_req->ifd_data[i].fd > 0)) {
+ if (cmd_req->ifd_data[i].cmd_buf_offset >
+ cmd_req->cmd_req_len -
+ sizeof(struct qseecom_sg_entry)) {
+ pr_err("Invalid offset = 0x%x\n",
+ cmd_req->ifd_data[i].
+ cmd_buf_offset);
+ goto err;
+ }
+ } else if ((listener_svc) &&
+ (lstnr_resp->ifd_data[i].fd > 0)) {
+ if (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ lstnr_resp->resp_len -
+ sizeof(struct qseecom_sg_entry)) {
+ pr_err("Invalid offset = 0x%x\n",
+ lstnr_resp->ifd_data[i].
+ cmd_buf_offset);
+ goto err;
+ }
+ }
update = (struct qseecom_sg_entry *) field;
for (j = 0; j < sg_ptr->nents; j++) {
if (cleanup) {
--
cgit v1.1

View File

@ -0,0 +1,383 @@
From e909d95e6bded328e388d5b8d123297bbbb70728 Mon Sep 17 00:00:00 2001
From: Mona Hossain <mhossain@codeaurora.org>
Date: Mon, 3 Nov 2014 17:05:48 -0800
Subject: qseecom: Add checks for send_cmd inputs
Improve user input validation across send cmd APIs. Add new
API __validate_send_cmd_inputs() to validate all user provided
inputs.
Change-Id: Ibbb0c0e7e5483f653bd59b927562b63c1e43c365
Signed-off-by: Mona Hossain <mhossain@codeaurora.org>
---
drivers/misc/qseecom.c | 221 ++++++++++++++++++++++++++++++-------------------
1 file changed, 134 insertions(+), 87 deletions(-)
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 65001c5..244f1bf 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -981,7 +981,7 @@ static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
}
if (req_mode > HIGH) {
pr_err("Invalid bandwidth mode (%d)\n", req_mode);
- return ret;
+ return -EINVAL;
}
/*
@@ -1834,24 +1834,16 @@ exit:
return ret;
}
-static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
+static int __validate_send_cmd_inputs(struct qseecom_dev_handle *data,
struct qseecom_send_cmd_req *req)
-{
- int ret = 0;
- u32 reqd_len_sb_in = 0;
- struct qseecom_client_send_data_ireq send_data_req;
- struct qseecom_command_scm_resp resp;
- unsigned long flags;
- struct qseecom_registered_app_list *ptr_app;
- bool found_app = false;
- int name_len = 0;
+{
if (!data || !data->client.ihandle) {
pr_err("Client or client handle is not initialized\n");
return -EINVAL;
}
-
- if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
+ if (((req->resp_buf == NULL) && (req->resp_len != 0)) ||
+ (req->cmd_req_buf == NULL)) {
pr_err("cmd buffer or response buffer is null\n");
return -EINVAL;
}
@@ -1862,8 +1854,6 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
pr_err("cmd buffer address not within shared bufffer\n");
return -EINVAL;
}
-
-
if (((uintptr_t)req->resp_buf <
data->client.user_virt_sb_base) ||
((uintptr_t)req->resp_buf >=
@@ -1871,27 +1861,62 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
pr_err("response buffer address not within shared bufffer\n");
return -EINVAL;
}
-
- if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
- req->cmd_req_len > data->client.sb_length ||
- req->resp_len > data->client.sb_length) {
- pr_err("cmd buffer length or response buffer length not valid\n");
+ if ((req->cmd_req_len == 0) ||
+ (req->cmd_req_len > data->client.sb_length) ||
+ (req->resp_len > data->client.sb_length)) {
+ pr_err("cmd buf length or response buf length not valid\n");
return -EINVAL;
}
-
if (req->cmd_req_len > UINT_MAX - req->resp_len) {
- pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
+ pr_err("Integer overflow detected in req_len & rsp_len\n");
return -EINVAL;
}
- reqd_len_sb_in = req->cmd_req_len + req->resp_len;
- if (reqd_len_sb_in > data->client.sb_length) {
+ if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
pr_debug("Not enough memory to fit cmd_buf.\n");
pr_debug("resp_buf. Required: %u, Available: %zu\n",
- reqd_len_sb_in, data->client.sb_length);
+ (req->cmd_req_len + req->resp_len),
+ data->client.sb_length);
return -ENOMEM;
}
+ if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
+ pr_err("Integer overflow in req_len & cmd_req_buf\n");
+ return -EINVAL;
+ }
+ if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
+ pr_err("Integer overflow in resp_len & resp_buf\n");
+ return -EINVAL;
+ }
+ if (data->client.user_virt_sb_base >
+ (ULONG_MAX - data->client.sb_length)) {
+ pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
+ return -EINVAL;
+ }
+ if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
+ ((uintptr_t)data->client.user_virt_sb_base +
+ data->client.sb_length)) ||
+ (((uintptr_t)req->resp_buf + req->resp_len) >
+ ((uintptr_t)data->client.user_virt_sb_base +
+ data->client.sb_length))) {
+ pr_err("cmd buf or resp buf is out of shared buffer region\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
+ struct qseecom_send_cmd_req *req)
+{
+ int ret = 0;
+ u32 reqd_len_sb_in = 0;
+ struct qseecom_client_send_data_ireq send_data_req;
+ struct qseecom_command_scm_resp resp;
+ unsigned long flags;
+ struct qseecom_registered_app_list *ptr_app;
+ bool found_app = false;
+ int name_len = 0;
+
+ reqd_len_sb_in = req->cmd_req_len + req->resp_len;
/* find app_id & img_name from list */
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
@@ -1965,6 +1990,10 @@ static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
pr_err("copy_from_user failed\n");
return ret;
}
+
+ if (__validate_send_cmd_inputs(data, &req))
+ return -EINVAL;
+
ret = __qseecom_send_cmd(data, &req);
if (ret)
@@ -1973,50 +2002,54 @@ static int qseecom_send_cmd(struct qseecom_dev_handle *data, void __user *argp)
return ret;
}
-int boundary_checks_offset(struct qseecom_send_modfd_cmd_req *req,
+int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *req,
struct qseecom_send_modfd_listener_resp *lstnr_resp,
struct qseecom_dev_handle *data, bool qteec,
int i) {
- int ret = 0;
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(req->ifd_data[i].fd > 0)) {
if (qteec) {
- if (req->ifd_data[i].cmd_buf_offset >
- req->cmd_req_len - TWO * sizeof(uint32_t)) {
- pr_err("Invalid offset 0x%x\n",
+ if ((req->cmd_req_len < (TWO * sizeof(uint32_t))) ||
+ (req->ifd_data[i].cmd_buf_offset >
+ req->cmd_req_len - (TWO * sizeof(uint32_t)))) {
+ pr_err("Invalid offset (QTEEC req len) 0x%x\n",
req->ifd_data[i].cmd_buf_offset);
- return ++ret;
+ return -EINVAL;
}
} else {
- if (req->ifd_data[i].cmd_buf_offset >
- req->cmd_req_len - sizeof(uint32_t)) {
- pr_err("Invalid offset 0x%x\n",
+ if ((req->cmd_req_len < sizeof(uint32_t)) ||
+ (req->ifd_data[i].cmd_buf_offset >
+ req->cmd_req_len - sizeof(uint32_t))) {
+ pr_err("Invalid offset (req len) 0x%x\n",
req->ifd_data[i].cmd_buf_offset);
- return ++ret;
+ return -EINVAL;
}
}
} else if ((data->type == QSEECOM_LISTENER_SERVICE) &&
(lstnr_resp->ifd_data[i].fd > 0)) {
if (qteec) {
- if (lstnr_resp->ifd_data[i].cmd_buf_offset >
- lstnr_resp->resp_len - TWO * sizeof(uint32_t)) {
- pr_err("Invalid offset 0x%x\n",
+ if ((lstnr_resp->resp_len < TWO * sizeof(uint32_t)) ||
+ (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ lstnr_resp->resp_len - TWO*sizeof(uint32_t))) {
+ pr_err("Invalid offset (QTEEC resp len) 0x%x\n",
lstnr_resp->ifd_data[i].cmd_buf_offset);
- return ++ret;
+ return -EINVAL;
}
} else {
- if (lstnr_resp->ifd_data[i].cmd_buf_offset >
- lstnr_resp->resp_len - sizeof(uint32_t)) {
- pr_err("Invalid offset 0x%x\n",
+ if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
+ (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ lstnr_resp->resp_len - sizeof(uint32_t))) {
+ pr_err("Invalid offset (lstnr resp len) 0x%x\n",
lstnr_resp->ifd_data[i].cmd_buf_offset);
- return ++ret;
+ return -EINVAL;
}
}
}
- return ret;
+ return 0;
}
+#define SG_ENTRY_SZ sizeof(struct qseecom_sg_entry)
static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
struct qseecom_dev_handle *data, bool qteec)
{
@@ -2095,7 +2128,7 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
uint32_t *update;
update = (uint32_t *) field;
- if (boundary_checks_offset(req, lstnr_resp, data,
+ if (__boundary_checks_offset(req, lstnr_resp, data,
qteec, i))
goto err;
if (cleanup)
@@ -2112,22 +2145,25 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(req->ifd_data[i].fd > 0)) {
- if (req->ifd_data[i].cmd_buf_offset >
- req->cmd_req_len -
- sizeof(struct qseecom_sg_entry)) {
+
+ if ((req->cmd_req_len <
+ SG_ENTRY_SZ * sg_ptr->nents) ||
+ (req->ifd_data[i].cmd_buf_offset >
+ (req->cmd_req_len -
+ SG_ENTRY_SZ * sg_ptr->nents))) {
pr_err("Invalid offset = 0x%x\n",
- req->ifd_data[i].
- cmd_buf_offset);
+ req->ifd_data[i].cmd_buf_offset);
goto err;
}
+
} else if ((data->type == QSEECOM_LISTENER_SERVICE) &&
(lstnr_resp->ifd_data[i].fd > 0)) {
- if (lstnr_resp->ifd_data[i].cmd_buf_offset >
- lstnr_resp->resp_len -
- sizeof(struct qseecom_sg_entry)) {
- pr_err("Invalid offset = 0x%x\n",
- lstnr_resp->ifd_data[i].
- cmd_buf_offset);
+
+ if ((lstnr_resp->resp_len <
+ SG_ENTRY_SZ * sg_ptr->nents) ||
+ (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ (lstnr_resp->resp_len -
+ SG_ENTRY_SZ * sg_ptr->nents))) {
goto err;
}
}
@@ -2179,37 +2215,14 @@ static int qseecom_send_modfd_cmd(struct qseecom_dev_handle *data,
return ret;
}
- if (req.cmd_req_buf == NULL || req.resp_buf == NULL) {
- pr_err("cmd buffer or response buffer is null\n");
- return -EINVAL;
- }
- if (((uintptr_t)req.cmd_req_buf <
- data->client.user_virt_sb_base) ||
- ((uintptr_t)req.cmd_req_buf >=
- (data->client.user_virt_sb_base + data->client.sb_length))) {
- pr_err("cmd buffer address not within shared bufffer\n");
- return -EINVAL;
- }
-
- if (((uintptr_t)req.resp_buf <
- data->client.user_virt_sb_base) ||
- ((uintptr_t)req.resp_buf >=
- (data->client.user_virt_sb_base + data->client.sb_length))) {
- pr_err("response buffer address not within shared bufffer\n");
- return -EINVAL;
- }
-
- if (req.cmd_req_len == 0 || req.cmd_req_len > data->client.sb_length ||
- req.resp_len > data->client.sb_length) {
- pr_err("cmd or response buffer length not valid\n");
- return -EINVAL;
- }
-
send_cmd_req.cmd_req_buf = req.cmd_req_buf;
send_cmd_req.cmd_req_len = req.cmd_req_len;
send_cmd_req.resp_buf = req.resp_buf;
send_cmd_req.resp_len = req.resp_len;
+ if (__validate_send_cmd_inputs(data, &send_cmd_req))
+ return -EINVAL;
+
/* validate offsets */
for (i = 0; i < MAX_ION_FD; i++) {
if (req.ifd_data[i].cmd_buf_offset >= req.cmd_req_len) {
@@ -2897,6 +2910,9 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
req.cmd_req_buf = send_buf;
req.resp_buf = resp_buf;
+ if (__validate_send_cmd_inputs(data, &req))
+ return -EINVAL;
+
mutex_lock(&app_access_lock);
atomic_inc(&data->ioctl_count);
if (qseecom.support_bus_scaling) {
@@ -4111,6 +4127,19 @@ static int qseecom_save_partition_hash(void __user *argp)
static int __qseecom_qteec_validate_msg(struct qseecom_dev_handle *data,
struct qseecom_qteec_req *req)
{
+
+ if (req->req_len > UINT_MAX - req->resp_len) {
+ pr_err("Integer overflow detected in req_len & rsp_len\n");
+ return -EINVAL;
+ }
+
+ if (req->req_len + req->resp_len > data->client.sb_length) {
+ pr_debug("Not enough memory to fit cmd_buf.\n");
+ pr_debug("resp_buf. Required: %u, Available: %zu\n",
+ (req->req_len + req->resp_len), data->client.sb_length);
+ return -ENOMEM;
+ }
+
if (req->req_ptr == NULL || req->resp_ptr == NULL) {
pr_err("cmd buffer or response buffer is null\n");
return -EINVAL;
@@ -4131,15 +4160,33 @@ static int __qseecom_qteec_validate_msg(struct qseecom_dev_handle *data,
return -EINVAL;
}
- if ((req->req_len == 0) || (req->resp_len == 0) ||
- req->req_len > data->client.sb_length ||
- req->resp_len > data->client.sb_length) {
+ if ((req->req_len == 0) || (req->resp_len == 0)) {
pr_err("cmd buf lengtgh/response buf length not valid\n");
return -EINVAL;
}
- if (req->req_len > UINT_MAX - req->resp_len) {
- pr_err("Integer overflow detected in req_len/rsp_len, exit\n");
+ if ((uintptr_t)req->req_ptr > (ULONG_MAX - req->req_len)) {
+ pr_err("Integer overflow in req_len & req_ptr\n");
+ return -EINVAL;
+ }
+
+ if ((uintptr_t)req->resp_ptr > (ULONG_MAX - req->resp_len)) {
+ pr_err("Integer overflow in resp_len & resp_ptr\n");
+ return -EINVAL;
+ }
+
+ if (data->client.user_virt_sb_base >
+ (ULONG_MAX - data->client.sb_length)) {
+ pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
+ return -EINVAL;
+ }
+ if ((((uintptr_t)req->req_ptr + req->req_len) >
+ ((uintptr_t)data->client.user_virt_sb_base +
+ data->client.sb_length)) ||
+ (((uintptr_t)req->resp_ptr + req->resp_len) >
+ ((uintptr_t)data->client.user_virt_sb_base +
+ data->client.sb_length))) {
+ pr_err("cmd buf or resp buf is out of shared buffer region\n");
return -EINVAL;
}
return 0;
--
cgit v1.1

View File

@ -0,0 +1,308 @@
From 8ad163e831a2b2c30551edb360f168a604cdb0bb Mon Sep 17 00:00:00 2001
From: Alok Kediya <kediya@codeaurora.org>
Date: Fri, 12 Dec 2014 04:20:59 -0800
Subject: msm: camera: isp: Validate input parameter for vfe_write and vfe_read
Validate input parameters for read and write operations in vfe to
ensure operations are performed within vfe register boundary and
within structure limits passed by caller.
Change-Id: If3719de65b32773c2b6ff904da76a951dbfb11eb
Signed-off-by: Alok Kediya <kediya@codeaurora.org>
---
.../platform/msm/camera_v2/isp/msm_isp_util.c | 162 ++++++++++++++-------
.../msm/camera_v2/sensor/io/msm_camera_io_util.c | 11 ++
.../msm/camera_v2/sensor/io/msm_camera_io_util.h | 2 +
3 files changed, 119 insertions(+), 56 deletions(-)
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 620c01a..e1b79ce 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -494,9 +494,24 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
struct msm_vfe_reg_cfg_cmd *reg_cfg_cmd,
uint32_t *cfg_data, uint32_t cmd_len)
{
+ if (!vfe_dev || !reg_cfg_cmd) {
+ pr_err("%s:%d failed: vfe_dev %p reg_cfg_cmd %p\n", __func__,
+ __LINE__, vfe_dev, reg_cfg_cmd);
+ return -EINVAL;
+ }
+ if ((reg_cfg_cmd->cmd_type != VFE_CFG_MASK) &&
+ (!cfg_data || !cmd_len)) {
+ pr_err("%s:%d failed: cmd type %d cfg_data %p cmd_len %d\n",
+ __func__, __LINE__, reg_cfg_cmd->cmd_type, cfg_data,
+ cmd_len);
+ return -EINVAL;
+ }
+
+ /* Validate input parameters */
switch (reg_cfg_cmd->cmd_type) {
case VFE_WRITE:
- case VFE_READ: {
+ case VFE_READ:
+ case VFE_WRITE_MB: {
if ((reg_cfg_cmd->u.rw_info.reg_offset >
(UINT_MAX - reg_cfg_cmd->u.rw_info.len)) ||
((reg_cfg_cmd->u.rw_info.reg_offset +
@@ -522,6 +537,58 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
}
break;
}
+
+ case VFE_WRITE_DMI_16BIT:
+ case VFE_WRITE_DMI_32BIT:
+ case VFE_WRITE_DMI_64BIT:
+ case VFE_READ_DMI_16BIT:
+ case VFE_READ_DMI_32BIT:
+ case VFE_READ_DMI_64BIT: {
+ if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) {
+ if ((reg_cfg_cmd->u.dmi_info.hi_tbl_offset <=
+ reg_cfg_cmd->u.dmi_info.lo_tbl_offset) ||
+ (reg_cfg_cmd->u.dmi_info.hi_tbl_offset -
+ reg_cfg_cmd->u.dmi_info.lo_tbl_offset !=
+ (sizeof(uint32_t)))) {
+ pr_err("%s:%d hi %d lo %d\n",
+ __func__, __LINE__,
+ reg_cfg_cmd->u.dmi_info.hi_tbl_offset,
+ reg_cfg_cmd->u.dmi_info.hi_tbl_offset);
+ return -EINVAL;
+ }
+ if (reg_cfg_cmd->u.dmi_info.len <= sizeof(uint32_t)) {
+ pr_err("%s:%d len %d\n",
+ __func__, __LINE__,
+ reg_cfg_cmd->u.dmi_info.len);
+ return -EINVAL;
+ }
+ if (((UINT_MAX -
+ reg_cfg_cmd->u.dmi_info.hi_tbl_offset) <
+ (reg_cfg_cmd->u.dmi_info.len -
+ sizeof(uint32_t))) ||
+ ((reg_cfg_cmd->u.dmi_info.hi_tbl_offset +
+ reg_cfg_cmd->u.dmi_info.len -
+ sizeof(uint32_t)) > cmd_len)) {
+ pr_err("%s:%d hi_tbl_offset %d len %d cmd %d\n",
+ __func__, __LINE__,
+ reg_cfg_cmd->u.dmi_info.hi_tbl_offset,
+ reg_cfg_cmd->u.dmi_info.len, cmd_len);
+ return -EINVAL;
+ }
+ }
+ if ((reg_cfg_cmd->u.dmi_info.lo_tbl_offset >
+ (UINT_MAX - reg_cfg_cmd->u.dmi_info.len)) ||
+ ((reg_cfg_cmd->u.dmi_info.lo_tbl_offset +
+ reg_cfg_cmd->u.dmi_info.len) > cmd_len)) {
+ pr_err("%s:%d lo_tbl_offset %d len %d cmd_len %d\n",
+ __func__, __LINE__,
+ reg_cfg_cmd->u.dmi_info.lo_tbl_offset,
+ reg_cfg_cmd->u.dmi_info.len, cmd_len);
+ return -EINVAL;
+ }
+ break;
+ }
+
default:
break;
}
@@ -535,39 +602,27 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
break;
}
case VFE_WRITE_MB: {
- uint32_t *data_ptr = cfg_data +
- reg_cfg_cmd->u.rw_info.cmd_data_offset/4;
-
- if ((UINT_MAX - sizeof(*data_ptr) <
- reg_cfg_cmd->u.rw_info.reg_offset) ||
- (resource_size(vfe_dev->vfe_mem) <
- reg_cfg_cmd->u.rw_info.reg_offset +
- sizeof(*data_ptr))) {
- pr_err("%s: VFE_WRITE_MB: Invalid length\n", __func__);
- return -EINVAL;
- }
- msm_camera_io_w_mb(*data_ptr, vfe_dev->vfe_base +
- reg_cfg_cmd->u.rw_info.reg_offset);
+ msm_camera_io_memcpy_mb(vfe_dev->vfe_base +
+ reg_cfg_cmd->u.rw_info.reg_offset,
+ cfg_data + reg_cfg_cmd->u.rw_info.cmd_data_offset/4,
+ reg_cfg_cmd->u.rw_info.len);
break;
}
case VFE_CFG_MASK: {
uint32_t temp;
- if (resource_size(vfe_dev->vfe_mem) <
- reg_cfg_cmd->u.mask_info.reg_offset)
- return -EINVAL;
- temp = msm_camera_io_r(vfe_dev->vfe_base +
- reg_cfg_cmd->u.mask_info.reg_offset);
-
- temp &= ~reg_cfg_cmd->u.mask_info.mask;
- temp |= reg_cfg_cmd->u.mask_info.val;
if ((UINT_MAX - sizeof(temp) <
- reg_cfg_cmd->u.mask_info.reg_offset) ||
+ reg_cfg_cmd->u.mask_info.reg_offset) ||
(resource_size(vfe_dev->vfe_mem) <
reg_cfg_cmd->u.mask_info.reg_offset +
sizeof(temp))) {
pr_err("%s: VFE_CFG_MASK: Invalid length\n", __func__);
return -EINVAL;
}
+ temp = msm_camera_io_r(vfe_dev->vfe_base +
+ reg_cfg_cmd->u.mask_info.reg_offset);
+
+ temp &= ~reg_cfg_cmd->u.mask_info.mask;
+ temp |= reg_cfg_cmd->u.mask_info.val;
msm_camera_io_w(temp, vfe_dev->vfe_base +
reg_cfg_cmd->u.mask_info.reg_offset);
break;
@@ -579,22 +634,9 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL;
uint32_t hi_val, lo_val, lo_val1;
if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT) {
- if ((UINT_MAX - reg_cfg_cmd->u.dmi_info.hi_tbl_offset <
- reg_cfg_cmd->u.dmi_info.len) ||
- (reg_cfg_cmd->u.dmi_info.hi_tbl_offset +
- reg_cfg_cmd->u.dmi_info.len > cmd_len)) {
- pr_err("Invalid Hi Table out of bounds\n");
- return -EINVAL;
- }
hi_tbl_ptr = cfg_data +
reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4;
}
-
- if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset +
- reg_cfg_cmd->u.dmi_info.len > cmd_len) {
- pr_err("Invalid Lo Table out of bounds\n");
- return -EINVAL;
- }
lo_tbl_ptr = cfg_data +
reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4;
if (reg_cfg_cmd->cmd_type == VFE_WRITE_DMI_64BIT)
@@ -627,30 +669,18 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
uint32_t *hi_tbl_ptr = NULL, *lo_tbl_ptr = NULL;
uint32_t hi_val, lo_val, lo_val1;
if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) {
- if (reg_cfg_cmd->u.dmi_info.hi_tbl_offset +
- reg_cfg_cmd->u.dmi_info.len > cmd_len) {
- pr_err("Invalid Hi Table out of bounds\n");
- return -EINVAL;
- }
hi_tbl_ptr = cfg_data +
reg_cfg_cmd->u.dmi_info.hi_tbl_offset/4;
}
- if (reg_cfg_cmd->u.dmi_info.lo_tbl_offset +
- reg_cfg_cmd->u.dmi_info.len > cmd_len) {
- pr_err("Invalid Lo Table out of bounds\n");
- return -EINVAL;
- }
lo_tbl_ptr = cfg_data +
reg_cfg_cmd->u.dmi_info.lo_tbl_offset/4;
- for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) {
- if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) {
- hi_val = msm_camera_io_r(vfe_dev->vfe_base +
- vfe_dev->hw_info->dmi_reg_offset);
- *hi_tbl_ptr++ = hi_val;
- }
+ if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT)
+ reg_cfg_cmd->u.dmi_info.len =
+ reg_cfg_cmd->u.dmi_info.len / 2;
+ for (i = 0; i < reg_cfg_cmd->u.dmi_info.len/4; i++) {
lo_val = msm_camera_io_r(vfe_dev->vfe_base +
vfe_dev->hw_info->dmi_reg_offset + 0x4);
@@ -660,6 +690,13 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
lo_val |= lo_val1 << 16;
}
*lo_tbl_ptr++ = lo_val;
+ if (reg_cfg_cmd->cmd_type == VFE_READ_DMI_64BIT) {
+ hi_val = msm_camera_io_r(vfe_dev->vfe_base +
+ vfe_dev->hw_info->dmi_reg_offset);
+ *hi_tbl_ptr = hi_val;
+ hi_tbl_ptr += 2;
+ lo_tbl_ptr++;
+ }
}
break;
}
@@ -698,7 +735,7 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
if ((data_ptr < cfg_data) ||
(UINT_MAX / sizeof(*data_ptr) <
(data_ptr - cfg_data)) ||
- (sizeof(*data_ptr) * (data_ptr - cfg_data) >
+ (sizeof(*data_ptr) * (data_ptr - cfg_data) >=
cmd_len))
return -EINVAL;
*data_ptr++ = msm_camera_io_r(vfe_dev->vfe_base +
@@ -707,9 +744,16 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
}
break;
}
- case GET_SOC_HW_VER:
- *cfg_data = vfe_dev->soc_hw_version;
- break;
+ case GET_SOC_HW_VER: {
+ if (cmd_len < sizeof(uint32_t)) {
+ pr_err("%s:%d failed: invalid cmd len %u exp %zu\n",
+ __func__, __LINE__, cmd_len,
+ sizeof(uint32_t));
+ return -EINVAL;
+ }
+ *cfg_data = vfe_dev->soc_hw_version;
+ break;
+ }
case GET_MAX_CLK_RATE: {
int rc = 0;
@@ -728,6 +772,12 @@ static int msm_isp_send_hw_cmd(struct vfe_device *vfe_dev,
break;
}
case SET_WM_UB_SIZE: {
+ if (cmd_len < sizeof(uint32_t)) {
+ pr_err("%s:%d failed: invalid cmd len %u exp %zu\n",
+ __func__, __LINE__, cmd_len,
+ sizeof(uint32_t));
+ return -EINVAL;
+ }
vfe_dev->vfe_ub_size = *cfg_data;
break;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
index 46a0542..7d369ff 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
@@ -107,6 +107,17 @@ void msm_camera_io_memcpy(void __iomem *dest_addr,
msm_camera_io_dump(dest_addr, len);
}
+void msm_camera_io_memcpy_mb(void __iomem *dest_addr,
+ void __iomem *src_addr, u32 len)
+{
+ int i;
+ u32 *d = (u32 *) dest_addr;
+ u32 *s = (u32 *) src_addr;
+
+ for (i = 0; i < (len / 4); i++)
+ msm_camera_io_w_mb(*s++, d++);
+}
+
int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info,
struct msm_cam_clk_info *clk_src_info, int num_clk)
{
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h
index 2e6f809..90925a9 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.h
@@ -28,6 +28,8 @@ u32 msm_camera_io_r_mb(void __iomem *addr);
void msm_camera_io_dump(void __iomem *addr, int size);
void msm_camera_io_memcpy(void __iomem *dest_addr,
void __iomem *src_addr, u32 len);
+void msm_camera_io_memcpy_mb(void __iomem *dest_addr,
+ void __iomem *src_addr, u32 len);
int msm_cam_clk_sel_src(struct device *dev, struct msm_cam_clk_info *clk_info,
struct msm_cam_clk_info *clk_src_info, int num_clk);
int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
--
cgit v1.1

View File

@ -1,90 +0,0 @@
From 0e2e43eca302b31f64ebfe4734fd2cc7358c4555 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Wed, 18 Jun 2014 13:32:32 +0200
Subject: ALSA: control: Fix replacing user controls
commit 82262a46627bebb0febcc26664746c25cef08563 upstream.
There are two issues with the current implementation for replacing user
controls. The first is that the code does not check if the control is actually a
user control and neither does it check if the control is owned by the process
that tries to remove it. That allows userspace applications to remove arbitrary
controls, which can cause a user after free if a for example a driver does not
expect a control to be removed from under its feed.
The second issue is that on one hand when a control is replaced the
user_ctl_count limit is not checked and on the other hand the user_ctl_count is
increased (even though the number of user controls does not change). This allows
userspace, once the user_ctl_count limit as been reached, to repeatedly replace
a control until user_ctl_count overflows. Once that happens new controls can be
added effectively bypassing the user_ctl_count limit.
Both issues can be fixed by instead of open-coding the removal of the control
that is to be replaced to use snd_ctl_remove_user_ctl(). This function does
proper permission checks as well as decrements user_ctl_count after the control
has been removed.
Note that by using snd_ctl_remove_user_ctl() the check which returns -EBUSY at
beginning of the function if the control already exists is removed. This is not
a problem though since the check is quite useless, because the lock that is
protecting the control list is released between the check and before adding the
new control to the list, which means that it is possible that a different
control with the same settings is added to the list after the check. Luckily
there is another check that is done while holding the lock in snd_ctl_add(), so
we'll rely on that to make sure that the same control is not added twice.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Jaroslav Kysela <perex@perex.cz>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
sound/core/control.c | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)
diff --git a/sound/core/control.c b/sound/core/control.c
index 920ea56..caa949e 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1151,8 +1151,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
struct user_element *ue;
int idx, err;
- if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
- return -ENOMEM;
if (info->count < 1)
return -EINVAL;
access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
@@ -1161,21 +1159,16 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
info->id.numid = 0;
memset(&kctl, 0, sizeof(kctl));
- down_write(&card->controls_rwsem);
- _kctl = snd_ctl_find_id(card, &info->id);
- err = 0;
- if (_kctl) {
- if (replace)
- err = snd_ctl_remove(card, _kctl);
- else
- err = -EBUSY;
- } else {
- if (replace)
- err = -ENOENT;
+
+ if (replace) {
+ err = snd_ctl_remove_user_ctl(file, &info->id);
+ if (err)
+ return err;
}
- up_write(&card->controls_rwsem);
- if (err < 0)
- return err;
+
+ if (card->user_ctl_count >= MAX_USER_CONTROLS)
+ return -ENOMEM;
+
memcpy(&kctl.id, &info->id, sizeof(info->id));
kctl.count = info->owner ? info->owner : 1;
access |= SNDRV_CTL_ELEM_ACCESS_USER;
--
cgit v1.1

View File

@ -1,27 +0,0 @@
From 08ede038a738f22c1b3425051175e1d627d8dd43 Mon Sep 17 00:00:00 2001
From: Lu Guanqun <guanqun.lu@intel.com>
Date: Wed, 24 Aug 2011 14:45:10 +0800
Subject: [PATCH] ALSA: core: release the constraint check for replace ops
Suppose the ALSA card already has a number of MAX_USER_CONTROLS controls, and
the user wants to replace one, it should not fail at this condition check.
Signed-off-by: Lu Guanqun <guanqun.lu@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
sound/core/control.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/core/control.c b/sound/core/control.c
index 7f2b3a7eabb2b..dc2a44048c850 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1073,7 +1073,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
struct user_element *ue;
int idx, err;
- if (card->user_ctl_count >= MAX_USER_CONTROLS)
+ if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
return -ENOMEM;
if (info->count < 1)
return -EINVAL;

View File

@ -1,7 +1,7 @@
From 82262a46627bebb0febcc26664746c25cef08563 Mon Sep 17 00:00:00 2001 From 82262a46627bebb0febcc26664746c25cef08563 Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de> From: Lars-Peter Clausen <lars@metafoo.de>
Date: Wed, 18 Jun 2014 13:32:32 +0200 Date: Wed, 18 Jun 2014 13:32:32 +0200
Subject: [PATCH] ALSA: control: Fix replacing user controls Subject: ALSA: control: Fix replacing user controls
There are two issues with the current implementation for replacing user There are two issues with the current implementation for replacing user
controls. The first is that the code does not check if the control is actually a controls. The first is that the code does not check if the control is actually a
@ -40,7 +40,7 @@ Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 file changed, 9 insertions(+), 16 deletions(-) 1 file changed, 9 insertions(+), 16 deletions(-)
diff --git a/sound/core/control.c b/sound/core/control.c diff --git a/sound/core/control.c b/sound/core/control.c
index 00ab034f5fcbe..1f413c2865113 100644 index 00ab034..1f413c2 100644
--- a/sound/core/control.c --- a/sound/core/control.c
+++ b/sound/core/control.c +++ b/sound/core/control.c
@@ -1154,8 +1154,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, @@ -1154,8 +1154,6 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
@ -83,3 +83,6 @@ index 00ab034f5fcbe..1f413c2865113 100644
memcpy(&kctl.id, &info->id, sizeof(info->id)); memcpy(&kctl.id, &info->id, sizeof(info->id));
kctl.count = info->owner ? info->owner : 1; kctl.count = info->owner ? info->owner : 1;
access |= SNDRV_CTL_ELEM_ACCESS_USER; access |= SNDRV_CTL_ELEM_ACCESS_USER;
--
cgit v1.1

View File

@ -1,39 +0,0 @@
From f7500568b7633324e7c4282bb8baa3ff3f17fd7a Mon Sep 17 00:00:00 2001
From: Lars-Peter Clausen <lars@metafoo.de>
Date: Wed, 18 Jun 2014 13:32:35 +0200
Subject: ALSA: control: Make sure that id->index does not overflow
commit 883a1d49f0d77d30012f114b2e19fc141beb3e8e upstream.
The ALSA control code expects that the range of assigned indices to a control is
continuous and does not overflow. Currently there are no checks to enforce this.
If a control with a overflowing index range is created that control becomes
effectively inaccessible and unremovable since snd_ctl_find_id() will not be
able to find it. This patch adds a check that makes sure that controls with a
overflowing index range can not be created.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Jaroslav Kysela <perex@perex.cz>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
sound/core/control.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/sound/core/control.c b/sound/core/control.c
index d3f17de..9210594 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -341,6 +341,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
if (snd_BUG_ON(!card || !kcontrol->info))
goto error;
id = kcontrol->id;
+ if (id.index > UINT_MAX - kcontrol->count)
+ goto error;
+
down_write(&card->controls_rwsem);
if (snd_ctl_find_id(card, &id)) {
up_write(&card->controls_rwsem);
--
cgit v1.1

View File

@ -1,56 +0,0 @@
From c7b18cdf1887e8ce91e04342cfd2d8fe1630be92 Mon Sep 17 00:00:00 2001
From: Johannes Berg <johannes.berg@intel.com>
Date: Sat, 1 Feb 2014 00:16:23 +0100
Subject: mac80211: fix fragmentation code, particularly for encryption
commit 338f977f4eb441e69bb9a46eaa0ac715c931a67f upstream.
The "new" fragmentation code (since my rewrite almost 5 years ago)
erroneously sets skb->len rather than using skb_trim() to adjust
the length of the first fragment after copying out all the others.
This leaves the skb tail pointer pointing to after where the data
originally ended, and thus causes the encryption MIC to be written
at that point, rather than where it belongs: immediately after the
data.
The impact of this is that if software encryption is done, then
a) encryption doesn't work for the first fragment, the connection
becomes unusable as the first fragment will never be properly
verified at the receiver, the MIC is practically guaranteed to
be wrong
b) we leak up to 8 bytes of plaintext (!) of the packet out into
the air
This is only mitigated by the fact that many devices are capable
of doing encryption in hardware, in which case this can't happen
as the tail pointer is irrelevant in that case. Additionally,
fragmentation is not used very frequently and would normally have
to be configured manually.
Fix this by using skb_trim() properly.
Fixes: 2de8e0d999b8 ("mac80211: rewrite fragmentation")
Reported-by: Jouni Malinen <j@w1.fi>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
net/mac80211/tx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 4ff35bf..5186f8b 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -884,7 +884,7 @@ static int ieee80211_fragment(struct ieee80211_local *local,
pos += fraglen;
}
- skb->len = hdrlen + per_fragm;
+ skb_trim(skb, hdrlen + per_fragm);
return 0;
}
--
cgit v1.1

View File

@ -0,0 +1,16 @@
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 8f3e2de..41baa1f 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -554,11 +554,6 @@
CFI_RESTORE_STATE
ldt_ss:
- larl PT_OLDSS(%esp), %eax
- jnz restore_nocheck
- testl $0x00400000, %eax # returning to 32bit stack?
- jnz restore_nocheck # allright, normal return
-
#ifdef CONFIG_PARAVIRT
/*
* The kernel can't run on a non-flat stack if paravirt mode

View File

@ -0,0 +1 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC9lbnRyeV8zMi5TIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzMyLlMKaW5kZXggOGYzZTJkZS4uNDFiYWExZiAxMDA2NDQKLS0tIGEvYXJjaC94ODYva2VybmVsL2VudHJ5XzMyLlMKKysrIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzMyLlMKQEAgLTU1NCwxMSArNTU0LDYgQEAKIAogCUNGSV9SRVNUT1JFX1NUQVRFCiBsZHRfc3M6Ci0JbGFybCBQVF9PTERTUyglZXNwKSwgJWVheAotCWpueiByZXN0b3JlX25vY2hlY2sKLQl0ZXN0bCAkMHgwMDQwMDAwMCwgJWVheAkJIyByZXR1cm5pbmcgdG8gMzJiaXQgc3RhY2s/Ci0Jam56IHJlc3RvcmVfbm9jaGVjawkJIyBhbGxyaWdodCwgbm9ybWFsIHJldHVybgotCiAjaWZkZWYgQ09ORklHX1BBUkFWSVJUCiAJLyoKIAkgKiBUaGUga2VybmVsIGNhbid0IHJ1biBvbiBhIG5vbi1mbGF0IHN0YWNrIGlmIHBhcmF2aXJ0IG1vZGUK

View File

@ -0,0 +1,519 @@
diff --git a/Documentation/x86/x86_64/mm.txt b/Documentation/x86/x86_64/mm.txt
index 881582f..bd43704 100644
--- a/Documentation/x86/x86_64/mm.txt
+++ b/Documentation/x86/x86_64/mm.txt
@@ -12,6 +12,8 @@
ffffe90000000000 - ffffe9ffffffffff (=40 bits) hole
ffffea0000000000 - ffffeaffffffffff (=40 bits) virtual memory map (1TB)
... unused hole ...
+ffffff0000000000 - ffffff7fffffffff (=39 bits) %esp fixup stacks
+... unused hole ...
ffffffff80000000 - ffffffffa0000000 (=512 MB) kernel text mapping, from phys 0
ffffffffa0000000 - ffffffffff5fffff (=1525 MB) module mapping space
ffffffffff600000 - ffffffffffdfffff (=8 MB) vsyscalls
diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h
index 2d88344..b1609f2 100644
--- a/arch/x86/include/asm/pgtable_64_types.h
+++ b/arch/x86/include/asm/pgtable_64_types.h
@@ -61,6 +61,8 @@
#define MODULES_VADDR _AC(0xffffffffa0000000, UL)
#define MODULES_END _AC(0xffffffffff000000, UL)
#define MODULES_LEN (MODULES_END - MODULES_VADDR)
+#define ESPFIX_PGD_ENTRY _AC(-2, UL)
+#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << PGDIR_SHIFT)
#define EARLY_DYNAMIC_PAGE_TABLES 64
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index b7bf350..93797d1 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -60,6 +60,9 @@
static inline void x86_ce4100_early_setup(void) { }
#endif
+extern void init_espfix_bsp(void);
+extern void init_espfix_ap(void);
+
#ifndef _SETUP
/*
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 7bd3bd3..0fde293 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -27,6 +27,7 @@
obj-y += syscall_$(BITS).o
obj-$(CONFIG_X86_64) += vsyscall_64.o
obj-$(CONFIG_X86_64) += vsyscall_emu_64.o
+obj-$(CONFIG_X86_64) += espfix_64.o
obj-y += bootflag.o e820.o
obj-y += pci-dma.o quirks.o topology.o kdebugfs.o
obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 7272089..75ccdc1 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -58,6 +58,7 @@
#include <asm/asm.h>
#include <asm/context_tracking.h>
#include <asm/smap.h>
+#include <asm/pgtable_types.h>
#include <linux/err.h>
/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
@@ -1055,8 +1056,16 @@
RESTORE_ARGS 1,8,1
irq_return:
+ /*
+ * Are we returning to a stack segment from the LDT? Note: in
+ * 64-bit mode SS:RSP on the exception stack is always valid.
+ */
+ testb $4,(SS-RIP)(%rsp)
+ jnz irq_return_ldt
+
+irq_return_iret:
INTERRUPT_RETURN
- _ASM_EXTABLE(irq_return, bad_iret)
+ _ASM_EXTABLE(irq_return_iret, bad_iret)
#ifdef CONFIG_PARAVIRT
ENTRY(native_iret)
@@ -1064,6 +1073,30 @@
_ASM_EXTABLE(native_iret, bad_iret)
#endif
+irq_return_ldt:
+ pushq_cfi %rax
+ pushq_cfi %rdi
+ SWAPGS
+ movq PER_CPU_VAR(espfix_waddr),%rdi
+ movq %rax,(0*8)(%rdi) /* RAX */
+ movq (2*8)(%rsp),%rax /* RIP */
+ movq %rax,(1*8)(%rdi)
+ movq (3*8)(%rsp),%rax /* CS */
+ movq %rax,(2*8)(%rdi)
+ movq (4*8)(%rsp),%rax /* RFLAGS */
+ movq %rax,(3*8)(%rdi)
+ movq (6*8)(%rsp),%rax /* SS */
+ movq %rax,(5*8)(%rdi)
+ movq (5*8)(%rsp),%rax /* RSP */
+ movq %rax,(4*8)(%rdi)
+ andl $0xffff0000,%eax
+ popq_cfi %rdi
+ orq PER_CPU_VAR(espfix_stack),%rax
+ SWAPGS
+ movq %rax,%rsp
+ popq_cfi %rax
+ jmp irq_return_iret
+
.section .fixup,"ax"
bad_iret:
/*
@@ -1127,9 +1160,41 @@
call preempt_schedule_irq
jmp exit_intr
#endif
-
CFI_ENDPROC
END(common_interrupt)
+
+ /*
+ * If IRET takes a fault on the espfix stack, then we
+ * end up promoting it to a doublefault. In that case,
+ * modify the stack to make it look like we just entered
+ * the #GP handler from user space, similar to bad_iret.
+ */
+ ALIGN
+__do_double_fault:
+ XCPT_FRAME 1 RDI+8
+ movq RSP(%rdi),%rax /* Trap on the espfix stack? */
+ sarq $PGDIR_SHIFT,%rax
+ cmpl $ESPFIX_PGD_ENTRY,%eax
+ jne do_double_fault /* No, just deliver the fault */
+ cmpl $__KERNEL_CS,CS(%rdi)
+ jne do_double_fault
+ movq RIP(%rdi),%rax
+ cmpq $irq_return_iret,%rax
+#ifdef CONFIG_PARAVIRT
+ je 1f
+ cmpq $native_iret,%rax
+#endif
+ jne do_double_fault /* This shouldn't happen... */
+1:
+ movq PER_CPU_VAR(kernel_stack),%rax
+ subq $(6*8-KERNEL_STACK_OFFSET),%rax /* Reset to original stack */
+ movq %rax,RSP(%rdi)
+ movq $0,(%rax) /* Missing (lost) #GP error code */
+ movq $general_protection,RIP(%rdi)
+ retq
+ CFI_ENDPROC
+END(__do_double_fault)
+
/*
* End of kprobes section
*/
@@ -1298,7 +1363,7 @@
zeroentry bounds do_bounds
zeroentry invalid_op do_invalid_op
zeroentry device_not_available do_device_not_available
-paranoiderrorentry double_fault do_double_fault
+paranoiderrorentry double_fault __do_double_fault
zeroentry coprocessor_segment_overrun do_coprocessor_segment_overrun
errorentry invalid_TSS do_invalid_TSS
errorentry segment_not_present do_segment_not_present
@@ -1585,7 +1650,7 @@
*/
error_kernelspace:
incl %ebx
- leaq irq_return(%rip),%rcx
+ leaq irq_return_iret(%rip),%rcx
cmpq %rcx,RIP+8(%rsp)
je error_swapgs
movl %ecx,%eax /* zero extend */
diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c
new file mode 100644
index 0000000..8a64da3
--- /dev/null
+++ b/arch/x86/kernel/espfix_64.c
@@ -0,0 +1,208 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2014 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * The IRET instruction, when returning to a 16-bit segment, only
+ * restores the bottom 16 bits of the user space stack pointer. This
+ * causes some 16-bit software to break, but it also leaks kernel state
+ * to user space.
+ *
+ * This works around this by creating percpu "ministacks", each of which
+ * is mapped 2^16 times 64K apart. When we detect that the return SS is
+ * on the LDT, we copy the IRET frame to the ministack and use the
+ * relevant alias to return to userspace. The ministacks are mapped
+ * readonly, so if the IRET fault we promote #GP to #DF which is an IST
+ * vector and thus has its own stack; we then do the fixup in the #DF
+ * handler.
+ *
+ * This file sets up the ministacks and the related page tables. The
+ * actual ministack invocation is in entry_64.S.
+ */
+
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <linux/gfp.h>
+#include <linux/random.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/setup.h>
+
+/*
+ * Note: we only need 6*8 = 48 bytes for the espfix stack, but round
+ * it up to a cache line to avoid unnecessary sharing.
+ */
+#define ESPFIX_STACK_SIZE (8*8UL)
+#define ESPFIX_STACKS_PER_PAGE (PAGE_SIZE/ESPFIX_STACK_SIZE)
+
+/* There is address space for how many espfix pages? */
+#define ESPFIX_PAGE_SPACE (1UL << (PGDIR_SHIFT-PAGE_SHIFT-16))
+
+#define ESPFIX_MAX_CPUS (ESPFIX_STACKS_PER_PAGE * ESPFIX_PAGE_SPACE)
+#if CONFIG_NR_CPUS > ESPFIX_MAX_CPUS
+# error "Need more than one PGD for the ESPFIX hack"
+#endif
+
+#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
+
+/* This contains the *bottom* address of the espfix stack */
+DEFINE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack);
+DEFINE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr);
+
+/* Initialization mutex - should this be a spinlock? */
+static DEFINE_MUTEX(espfix_init_mutex);
+
+/* Page allocation bitmap - each page serves ESPFIX_STACKS_PER_PAGE CPUs */
+#define ESPFIX_MAX_PAGES DIV_ROUND_UP(CONFIG_NR_CPUS, ESPFIX_STACKS_PER_PAGE)
+static void *espfix_pages[ESPFIX_MAX_PAGES];
+
+static __page_aligned_bss pud_t espfix_pud_page[PTRS_PER_PUD]
+ __aligned(PAGE_SIZE);
+
+static unsigned int page_random, slot_random;
+
+/*
+ * This returns the bottom address of the espfix stack for a specific CPU.
+ * The math allows for a non-power-of-two ESPFIX_STACK_SIZE, in which case
+ * we have to account for some amount of padding at the end of each page.
+ */
+static inline unsigned long espfix_base_addr(unsigned int cpu)
+{
+ unsigned long page, slot;
+ unsigned long addr;
+
+ page = (cpu / ESPFIX_STACKS_PER_PAGE) ^ page_random;
+ slot = (cpu + slot_random) % ESPFIX_STACKS_PER_PAGE;
+ addr = (page << PAGE_SHIFT) + (slot * ESPFIX_STACK_SIZE);
+ addr = (addr & 0xffffUL) | ((addr & ~0xffffUL) << 16);
+ addr += ESPFIX_BASE_ADDR;
+ return addr;
+}
+
+#define PTE_STRIDE (65536/PAGE_SIZE)
+#define ESPFIX_PTE_CLONES (PTRS_PER_PTE/PTE_STRIDE)
+#define ESPFIX_PMD_CLONES PTRS_PER_PMD
+#define ESPFIX_PUD_CLONES (65536/(ESPFIX_PTE_CLONES*ESPFIX_PMD_CLONES))
+
+#define PGTABLE_PROT ((_KERNPG_TABLE & ~_PAGE_RW) | _PAGE_NX)
+
+static void init_espfix_random(void)
+{
+ unsigned long rand;
+
+ /*
+ * This is run before the entropy pools are initialized,
+ * but this is hopefully better than nothing.
+ */
+ if (!arch_get_random_long(&rand)) {
+ /* The constant is an arbitrary large prime */
+ rdtscll(rand);
+ rand *= 0xc345c6b72fd16123UL;
+ }
+
+ slot_random = rand % ESPFIX_STACKS_PER_PAGE;
+ page_random = (rand / ESPFIX_STACKS_PER_PAGE)
+ & (ESPFIX_PAGE_SPACE - 1);
+}
+
+void __init init_espfix_bsp(void)
+{
+ pgd_t *pgd_p;
+ pteval_t ptemask;
+
+ ptemask = __supported_pte_mask;
+
+ /* Install the espfix pud into the kernel page directory */
+ pgd_p = &init_level4_pgt[pgd_index(ESPFIX_BASE_ADDR)];
+ pgd_populate(&init_mm, pgd_p, (pud_t *)espfix_pud_page);
+
+ /* Randomize the locations */
+ init_espfix_random();
+
+ /* The rest is the same as for any other processor */
+ init_espfix_ap();
+}
+
+void init_espfix_ap(void)
+{
+ unsigned int cpu, page;
+ unsigned long addr;
+ pud_t pud, *pud_p;
+ pmd_t pmd, *pmd_p;
+ pte_t pte, *pte_p;
+ int n;
+ void *stack_page;
+ pteval_t ptemask;
+
+ /* We only have to do this once... */
+ if (likely(this_cpu_read(espfix_stack)))
+ return; /* Already initialized */
+
+ cpu = smp_processor_id();
+ addr = espfix_base_addr(cpu);
+ page = cpu/ESPFIX_STACKS_PER_PAGE;
+
+ /* Did another CPU already set this up? */
+ stack_page = ACCESS_ONCE(espfix_pages[page]);
+ if (likely(stack_page))
+ goto done;
+
+ mutex_lock(&espfix_init_mutex);
+
+ /* Did we race on the lock? */
+ stack_page = ACCESS_ONCE(espfix_pages[page]);
+ if (stack_page)
+ goto unlock_done;
+
+ ptemask = __supported_pte_mask;
+
+ pud_p = &espfix_pud_page[pud_index(addr)];
+ pud = *pud_p;
+ if (!pud_present(pud)) {
+ pmd_p = (pmd_t *)__get_free_page(PGALLOC_GFP);
+ pud = __pud(__pa(pmd_p) | (PGTABLE_PROT & ptemask));
+ paravirt_alloc_pud(&init_mm, __pa(pmd_p) >> PAGE_SHIFT);
+ for (n = 0; n < ESPFIX_PUD_CLONES; n++)
+ set_pud(&pud_p[n], pud);
+ }
+
+ pmd_p = pmd_offset(&pud, addr);
+ pmd = *pmd_p;
+ if (!pmd_present(pmd)) {
+ pte_p = (pte_t *)__get_free_page(PGALLOC_GFP);
+ pmd = __pmd(__pa(pte_p) | (PGTABLE_PROT & ptemask));
+ paravirt_alloc_pmd(&init_mm, __pa(pte_p) >> PAGE_SHIFT);
+ for (n = 0; n < ESPFIX_PMD_CLONES; n++)
+ set_pmd(&pmd_p[n], pmd);
+ }
+
+ pte_p = pte_offset_kernel(&pmd, addr);
+ stack_page = (void *)__get_free_page(GFP_KERNEL);
+ pte = __pte(__pa(stack_page) | (__PAGE_KERNEL_RO & ptemask));
+ paravirt_alloc_pte(&init_mm, __pa(stack_page) >> PAGE_SHIFT);
+ for (n = 0; n < ESPFIX_PTE_CLONES; n++)
+ set_pte(&pte_p[n*PTE_STRIDE], pte);
+
+ /* Job is done for this CPU and any CPU which shares this page */
+ ACCESS_ONCE(espfix_pages[page]) = stack_page;
+
+unlock_done:
+ mutex_unlock(&espfix_init_mutex);
+done:
+ this_cpu_write(espfix_stack, addr);
+ this_cpu_write(espfix_waddr, (unsigned long)stack_page
+ + (addr & ~PAGE_MASK));
+}
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index bfd348e..9f009cc 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -265,6 +265,13 @@
check_tsc_sync_target();
/*
+ * Enable the espfix hack for this CPU
+ */
+#ifdef CONFIG_X86_64
+ init_espfix_ap();
+#endif
+
+ /*
* We need to hold vector_lock so there the set of online cpus
* does not change while we are assigning vectors to cpus. Holding
* this lock ensures we don't half assign or remove an irq from a cpu.
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index 0002a3a..e04e677 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -30,11 +30,13 @@
unsigned long start_address;
unsigned long current_address;
const struct addr_marker *marker;
+ unsigned long lines;
};
struct addr_marker {
unsigned long start_address;
const char *name;
+ unsigned long max_lines;
};
/* indices for address_markers; keep sync'd w/ address_markers below */
@@ -45,6 +47,7 @@
LOW_KERNEL_NR,
VMALLOC_START_NR,
VMEMMAP_START_NR,
+ ESPFIX_START_NR,
HIGH_KERNEL_NR,
MODULES_VADDR_NR,
MODULES_END_NR,
@@ -67,6 +70,7 @@
{ PAGE_OFFSET, "Low Kernel Mapping" },
{ VMALLOC_START, "vmalloc() Area" },
{ VMEMMAP_START, "Vmemmap" },
+ { ESPFIX_BASE_ADDR, "ESPfix Area", 16 },
{ __START_KERNEL_map, "High Kernel Mapping" },
{ MODULES_VADDR, "Modules" },
{ MODULES_END, "End Modules" },
@@ -163,7 +167,7 @@
pgprot_t new_prot, int level)
{
pgprotval_t prot, cur;
- static const char units[] = "KMGTPE";
+ static const char units[] = "BKMGTPE";
/*
* If we have a "break" in the series, we need to flush the state that
@@ -178,6 +182,7 @@
st->current_prot = new_prot;
st->level = level;
st->marker = address_markers;
+ st->lines = 0;
seq_printf(m, "---[ %s ]---\n", st->marker->name);
} else if (prot != cur || level != st->level ||
st->current_address >= st->marker[1].start_address) {
@@ -188,17 +193,21 @@
/*
* Now print the actual finished series
*/
- seq_printf(m, "0x%0*lx-0x%0*lx ",
- width, st->start_address,
- width, st->current_address);
+ if (!st->marker->max_lines ||
+ st->lines < st->marker->max_lines) {
+ seq_printf(m, "0x%0*lx-0x%0*lx ",
+ width, st->start_address,
+ width, st->current_address);
- delta = (st->current_address - st->start_address) >> 10;
- while (!(delta & 1023) && unit[1]) {
- delta >>= 10;
- unit++;
+ delta = (st->current_address - st->start_address);
+ while (!(delta & 1023) && unit[1]) {
+ delta >>= 10;
+ unit++;
+ }
+ seq_printf(m, "%9lu%c ", delta, *unit);
+ printk_prot(m, st->current_prot, st->level);
}
- seq_printf(m, "%9lu%c ", delta, *unit);
- printk_prot(m, st->current_prot, st->level);
+ st->lines++;
/*
* We print markers for special areas of address space,
@@ -206,7 +215,15 @@
* This helps in the interpretation.
*/
if (st->current_address >= st->marker[1].start_address) {
+ if (st->marker->max_lines &&
+ st->lines > st->marker->max_lines) {
+ unsigned long nskip =
+ st->lines - st->marker->max_lines;
+ seq_printf(m, "... %lu entr%s skipped ... \n",
+ nskip, nskip == 1 ? "y" : "ies");
+ }
st->marker++;
+ st->lines = 0;
seq_printf(m, "---[ %s ]---\n", st->marker->name);
}
diff --git a/init/main.c b/init/main.c
index 9484f4b..a9e4a76 100644
--- a/init/main.c
+++ b/init/main.c
@@ -605,6 +605,10 @@
if (efi_enabled(EFI_RUNTIME_SERVICES))
efi_enter_virtual_mode();
#endif
+#ifdef CONFIG_X86_64
+ /* Should be run before the first non-init thread is created */
+ init_espfix_bsp();
+#endif
thread_info_cache_init();
cred_init();
fork_init(totalram_pages);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,52 @@
diff --git a/arch/x86/include/asm/espfix.h b/arch/x86/include/asm/espfix.h
new file mode 100644
index 0000000..729051c
--- /dev/null
+++ b/arch/x86/include/asm/espfix.h
@@ -0,0 +1,16 @@
+#ifdef _ASM_X86_ESPFIX_H
+#define _ASM_X86_ESPFIX_H
+
+#ifdef CONFIG_X86_64
+
+#include <asm/percpu.h>
+
+DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack);
+DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr);
+
+extern void init_espfix_bsp(void);
+extern void init_espfix_ap(void);
+
+#endif /* CONFIG_X86_64 */
+
+#endif /* _ASM_X86_ESPFIX_H */
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index 93797d1..2e327f1 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -60,11 +60,10 @@
static inline void x86_ce4100_early_setup(void) { }
#endif
-extern void init_espfix_bsp(void);
-extern void init_espfix_ap(void);
-
#ifndef _SETUP
+#include <asm/espfix.h>
+
/*
* This is set up by the setup-routine at boot-time
*/
diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c
index 8a64da3..6afbb16 100644
--- a/arch/x86/kernel/espfix_64.c
+++ b/arch/x86/kernel/espfix_64.c
@@ -40,6 +40,7 @@
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/setup.h>
+#include <asm/espfix.h>
/*
* Note: we only need 6*8 = 48 bytes for the espfix stack, but round

View File

@ -0,0 +1 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL2VzcGZpeC5oIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vZXNwZml4LmgKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uNzI5MDUxYwotLS0gL2Rldi9udWxsCisrKyBiL2FyY2gveDg2L2luY2x1ZGUvYXNtL2VzcGZpeC5oCkBAIC0wLDAgKzEsMTYgQEAKKyNpZmRlZiBfQVNNX1g4Nl9FU1BGSVhfSAorI2RlZmluZSBfQVNNX1g4Nl9FU1BGSVhfSAorCisjaWZkZWYgQ09ORklHX1g4Nl82NAorCisjaW5jbHVkZSA8YXNtL3BlcmNwdS5oPgorCitERUNMQVJFX1BFUl9DUFVfUkVBRF9NT1NUTFkodW5zaWduZWQgbG9uZywgZXNwZml4X3N0YWNrKTsKK0RFQ0xBUkVfUEVSX0NQVV9SRUFEX01PU1RMWSh1bnNpZ25lZCBsb25nLCBlc3BmaXhfd2FkZHIpOworCitleHRlcm4gdm9pZCBpbml0X2VzcGZpeF9ic3Aodm9pZCk7CitleHRlcm4gdm9pZCBpbml0X2VzcGZpeF9hcCh2b2lkKTsKKworI2VuZGlmIC8qIENPTkZJR19YODZfNjQgKi8KKworI2VuZGlmIC8qIF9BU01fWDg2X0VTUEZJWF9IICovCmRpZmYgLS1naXQgYS9hcmNoL3g4Ni9pbmNsdWRlL2FzbS9zZXR1cC5oIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vc2V0dXAuaAppbmRleCA5Mzc5N2QxLi4yZTMyN2YxIDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9pbmNsdWRlL2FzbS9zZXR1cC5oCisrKyBiL2FyY2gveDg2L2luY2x1ZGUvYXNtL3NldHVwLmgKQEAgLTYwLDExICs2MCwxMCBAQAogc3RhdGljIGlubGluZSB2b2lkIHg4Nl9jZTQxMDBfZWFybHlfc2V0dXAodm9pZCkgeyB9CiAjZW5kaWYKIAotZXh0ZXJuIHZvaWQgaW5pdF9lc3BmaXhfYnNwKHZvaWQpOwotZXh0ZXJuIHZvaWQgaW5pdF9lc3BmaXhfYXAodm9pZCk7Ci0KICNpZm5kZWYgX1NFVFVQCiAKKyNpbmNsdWRlIDxhc20vZXNwZml4Lmg+CisKIC8qCiAgKiBUaGlzIGlzIHNldCB1cCBieSB0aGUgc2V0dXAtcm91dGluZSBhdCBib290LXRpbWUKICAqLwpkaWZmIC0tZ2l0IGEvYXJjaC94ODYva2VybmVsL2VzcGZpeF82NC5jIGIvYXJjaC94ODYva2VybmVsL2VzcGZpeF82NC5jCmluZGV4IDhhNjRkYTMuLjZhZmJiMTYgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC9lc3BmaXhfNjQuYworKysgYi9hcmNoL3g4Ni9rZXJuZWwvZXNwZml4XzY0LmMKQEAgLTQwLDYgKzQwLDcgQEAKICNpbmNsdWRlIDxhc20vcGd0YWJsZS5oPgogI2luY2x1ZGUgPGFzbS9wZ2FsbG9jLmg+CiAjaW5jbHVkZSA8YXNtL3NldHVwLmg+CisjaW5jbHVkZSA8YXNtL2VzcGZpeC5oPgogCiAvKgogICogTm90ZTogd2Ugb25seSBuZWVkIDYqOCA9IDQ4IGJ5dGVzIGZvciB0aGUgZXNwZml4IHN0YWNrLCBidXQgcm91bmQK

View File

@ -0,0 +1,10 @@
diff --git a/arch/x86/include/asm/espfix.h b/arch/x86/include/asm/espfix.h
index 729051c..99efebb 100644
--- a/arch/x86/include/asm/espfix.h
+++ b/arch/x86/include/asm/espfix.h
@@ -1,4 +1,4 @@
-#ifdef _ASM_X86_ESPFIX_H
+#ifndef _ASM_X86_ESPFIX_H
#define _ASM_X86_ESPFIX_H
#ifdef CONFIG_X86_64

View File

@ -0,0 +1 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL2VzcGZpeC5oIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vZXNwZml4LmgKaW5kZXggNzI5MDUxYy4uOTllZmViYiAxMDA2NDQKLS0tIGEvYXJjaC94ODYvaW5jbHVkZS9hc20vZXNwZml4LmgKKysrIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vZXNwZml4LmgKQEAgLTEsNCArMSw0IEBACi0jaWZkZWYgX0FTTV9YODZfRVNQRklYX0gKKyNpZm5kZWYgX0FTTV9YODZfRVNQRklYX0gKICNkZWZpbmUgX0FTTV9YODZfRVNQRklYX0gKIAogI2lmZGVmIENPTkZJR19YODZfNjQK

View File

@ -0,0 +1,54 @@
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 4b20846..520cde8 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -972,6 +972,10 @@
XFree86 to initialize some video cards via BIOS. Disabling this
option saves about 6k.
+config X86_ESPFIX64
+ def_bool y
+ depends on X86_64
+
config TOSHIBA
tristate "Toshiba Laptop support"
depends on X86_32
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 0fde293..111eb35 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -27,7 +27,7 @@
obj-y += syscall_$(BITS).o
obj-$(CONFIG_X86_64) += vsyscall_64.o
obj-$(CONFIG_X86_64) += vsyscall_emu_64.o
-obj-$(CONFIG_X86_64) += espfix_64.o
+obj-$(CONFIG_X86_ESPFIX64) += espfix_64.o
obj-y += bootflag.o e820.o
obj-y += pci-dma.o quirks.o topology.o kdebugfs.o
obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 9f009cc..fe86275 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -267,7 +267,7 @@
/*
* Enable the espfix hack for this CPU
*/
-#ifdef CONFIG_X86_64
+#ifdef CONFIG_X86_ESPFIX64
init_espfix_ap();
#endif
diff --git a/init/main.c b/init/main.c
index a9e4a76..544cccf 100644
--- a/init/main.c
+++ b/init/main.c
@@ -605,7 +605,7 @@
if (efi_enabled(EFI_RUNTIME_SERVICES))
efi_enter_virtual_mode();
#endif
-#ifdef CONFIG_X86_64
+#ifdef CONFIG_X86_ESPFIX64
/* Should be run before the first non-init thread is created */
init_espfix_bsp();
#endif

View File

@ -0,0 +1 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L0tjb25maWcgYi9hcmNoL3g4Ni9LY29uZmlnCmluZGV4IDRiMjA4NDYuLjUyMGNkZTggMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L0tjb25maWcKKysrIGIvYXJjaC94ODYvS2NvbmZpZwpAQCAtOTcyLDYgKzk3MiwxMCBAQAogCSAgWEZyZWU4NiB0byBpbml0aWFsaXplIHNvbWUgdmlkZW8gY2FyZHMgdmlhIEJJT1MuIERpc2FibGluZyB0aGlzCiAJICBvcHRpb24gc2F2ZXMgYWJvdXQgNmsuCiAKK2NvbmZpZyBYODZfRVNQRklYNjQKKwlkZWZfYm9vbCB5CisJZGVwZW5kcyBvbiBYODZfNjQKKwogY29uZmlnIFRPU0hJQkEKIAl0cmlzdGF0ZSAiVG9zaGliYSBMYXB0b3Agc3VwcG9ydCIKIAlkZXBlbmRzIG9uIFg4Nl8zMgpkaWZmIC0tZ2l0IGEvYXJjaC94ODYva2VybmVsL01ha2VmaWxlIGIvYXJjaC94ODYva2VybmVsL01ha2VmaWxlCmluZGV4IDBmZGUyOTMuLjExMWViMzUgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC9NYWtlZmlsZQorKysgYi9hcmNoL3g4Ni9rZXJuZWwvTWFrZWZpbGUKQEAgLTI3LDcgKzI3LDcgQEAKIG9iai15CQkJKz0gc3lzY2FsbF8kKEJJVFMpLm8KIG9iai0kKENPTkZJR19YODZfNjQpCSs9IHZzeXNjYWxsXzY0Lm8KIG9iai0kKENPTkZJR19YODZfNjQpCSs9IHZzeXNjYWxsX2VtdV82NC5vCi1vYmotJChDT05GSUdfWDg2XzY0KQkrPSBlc3BmaXhfNjQubworb2JqLSQoQ09ORklHX1g4Nl9FU1BGSVg2NCkJKz0gZXNwZml4XzY0Lm8KIG9iai15CQkJKz0gYm9vdGZsYWcubyBlODIwLm8KIG9iai15CQkJKz0gcGNpLWRtYS5vIHF1aXJrcy5vIHRvcG9sb2d5Lm8ga2RlYnVnZnMubwogb2JqLXkJCQkrPSBhbHRlcm5hdGl2ZS5vIGk4MjUzLm8gcGNpLW5vbW11Lm8gaHdfYnJlYWtwb2ludC5vCmRpZmYgLS1naXQgYS9hcmNoL3g4Ni9rZXJuZWwvc21wYm9vdC5jIGIvYXJjaC94ODYva2VybmVsL3NtcGJvb3QuYwppbmRleCA5ZjAwOWNjLi5mZTg2Mjc1IDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9rZXJuZWwvc21wYm9vdC5jCisrKyBiL2FyY2gveDg2L2tlcm5lbC9zbXBib290LmMKQEAgLTI2Nyw3ICsyNjcsNyBAQAogCS8qCiAJICogRW5hYmxlIHRoZSBlc3BmaXggaGFjayBmb3IgdGhpcyBDUFUKIAkgKi8KLSNpZmRlZiBDT05GSUdfWDg2XzY0CisjaWZkZWYgQ09ORklHX1g4Nl9FU1BGSVg2NAogCWluaXRfZXNwZml4X2FwKCk7CiAjZW5kaWYKIApkaWZmIC0tZ2l0IGEvaW5pdC9tYWluLmMgYi9pbml0L21haW4uYwppbmRleCBhOWU0YTc2Li41NDRjY2NmIDEwMDY0NAotLS0gYS9pbml0L21haW4uYworKysgYi9pbml0L21haW4uYwpAQCAtNjA1LDcgKzYwNSw3IEBACiAJaWYgKGVmaV9lbmFibGVkKEVGSV9SVU5USU1FX1NFUlZJQ0VTKSkKIAkJZWZpX2VudGVyX3ZpcnR1YWxfbW9kZSgpOwogI2VuZGlmCi0jaWZkZWYgQ09ORklHX1g4Nl82NAorI2lmZGVmIENPTkZJR19YODZfRVNQRklYNjQKIAkvKiBTaG91bGQgYmUgcnVuIGJlZm9yZSB0aGUgZmlyc3Qgbm9uLWluaXQgdGhyZWFkIGlzIGNyZWF0ZWQgKi8KIAlpbml0X2VzcGZpeF9ic3AoKTsKICNlbmRpZgo=

View File

@ -0,0 +1,195 @@
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 520cde8..2b6c572 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -967,14 +967,27 @@
default y
depends on X86_32
---help---
- This option is required by programs like DOSEMU to run 16-bit legacy
- code on X86 processors. It also may be needed by software like
- XFree86 to initialize some video cards via BIOS. Disabling this
- option saves about 6k.
+ This option is required by programs like DOSEMU to run
+ 16-bit real mode legacy code on x86 processors. It also may
+ be needed by software like XFree86 to initialize some video
+ cards via BIOS. Disabling this option saves about 6K.
+
+config X86_16BIT
+ bool "Enable support for 16-bit segments" if EXPERT
+ default y
+ ---help---
+ This option is required by programs like Wine to run 16-bit
+ protected mode legacy code on x86 processors. Disabling
+ this option saves about 300 bytes on i386, or around 6K text
+ plus 16K runtime memory on x86-64,
+
+config X86_ESPFIX32
+ def_bool y
+ depends on X86_16BIT && X86_32
config X86_ESPFIX64
def_bool y
- depends on X86_64
+ depends on X86_16BIT && X86_64
config TOSHIBA
tristate "Toshiba Laptop support"
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 41baa1f..e758e2f 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -530,6 +530,7 @@
restore_all:
TRACE_IRQS_IRET
restore_all_notrace:
+#ifdef CONFIG_X86_ESPFIX32
movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
# Warning: PT_OLDSS(%esp) contains the wrong/random values if we
# are returning to the kernel.
@@ -540,6 +541,7 @@
cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax
CFI_REMEMBER_STATE
je ldt_ss # returning to user-space with LDT SS
+#endif
restore_nocheck:
RESTORE_REGS 4 # skip orig_eax/error_code
irq_return:
@@ -552,6 +554,7 @@
.previous
_ASM_EXTABLE(irq_return,iret_exc)
+#ifdef CONFIG_X86_ESPFIX32
CFI_RESTORE_STATE
ldt_ss:
#ifdef CONFIG_PARAVIRT
@@ -595,6 +598,7 @@
lss (%esp), %esp /* switch to espfix segment */
CFI_ADJUST_CFA_OFFSET -8
jmp restore_nocheck
+#endif
CFI_ENDPROC
ENDPROC(system_call)
@@ -702,6 +706,7 @@
* the high word of the segment base from the GDT and swiches to the
* normal stack and adjusts ESP with the matching offset.
*/
+#ifdef CONFIG_X86_ESPFIX32
/* fixup the stack */
mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */
mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
@@ -711,8 +716,10 @@
pushl_cfi %eax
lss (%esp), %esp /* switch to the normal stack segment */
CFI_ADJUST_CFA_OFFSET -8
+#endif
.endm
.macro UNWIND_ESPFIX_STACK
+#ifdef CONFIG_X86_ESPFIX32
movl %ss, %eax
/* see if on espfix stack */
cmpw $__ESPFIX_SS, %ax
@@ -723,6 +730,7 @@
/* switch to normal stack */
FIXUP_ESPFIX_STACK
27:
+#endif
.endm
/*
@@ -1330,11 +1338,13 @@
ENTRY(nmi)
RING0_INT_FRAME
ASM_CLAC
+#ifdef CONFIG_X86_ESPFIX32
pushl_cfi %eax
movl %ss, %eax
cmpw $__ESPFIX_SS, %ax
popl_cfi %eax
je nmi_espfix_stack
+#endif
cmpl $ia32_sysenter_target,(%esp)
je nmi_stack_fixup
pushl_cfi %eax
@@ -1374,6 +1384,7 @@
FIX_STACK 24, nmi_stack_correct, 1
jmp nmi_stack_correct
+#ifdef CONFIG_X86_ESPFIX32
nmi_espfix_stack:
/* We have a RING0_INT_FRAME here.
*
@@ -1395,6 +1406,7 @@
lss 12+4(%esp), %esp # back to espfix stack
CFI_ADJUST_CFA_OFFSET -24
jmp irq_return
+#endif
CFI_ENDPROC
END(nmi)
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 75ccdc1..f9315d9 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1060,8 +1060,10 @@
* Are we returning to a stack segment from the LDT? Note: in
* 64-bit mode SS:RSP on the exception stack is always valid.
*/
+#ifdef CONFIG_X86_ESPFIX64
testb $4,(SS-RIP)(%rsp)
jnz irq_return_ldt
+#endif
irq_return_iret:
INTERRUPT_RETURN
@@ -1073,6 +1075,7 @@
_ASM_EXTABLE(native_iret, bad_iret)
#endif
+#ifdef CONFIG_X86_ESPFIX64
irq_return_ldt:
pushq_cfi %rax
pushq_cfi %rdi
@@ -1096,6 +1099,7 @@
movq %rax,%rsp
popq_cfi %rax
jmp irq_return_iret
+#endif
.section .fixup,"ax"
bad_iret:
@@ -1169,6 +1173,7 @@
* modify the stack to make it look like we just entered
* the #GP handler from user space, similar to bad_iret.
*/
+#ifdef CONFIG_X86_ESPFIX64
ALIGN
__do_double_fault:
XCPT_FRAME 1 RDI+8
@@ -1194,6 +1199,9 @@
retq
CFI_ENDPROC
END(__do_double_fault)
+#else
+# define __do_double_fault do_double_fault
+#endif
/*
* End of kprobes section
diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
index ebc9873..c37886d 100644
--- a/arch/x86/kernel/ldt.c
+++ b/arch/x86/kernel/ldt.c
@@ -229,6 +229,11 @@
}
}
+ if (!IS_ENABLED(CONFIG_X86_16BIT) && !ldt_info.seg_32bit) {
+ error = -EINVAL;
+ goto out_unlock;
+ }
+
fill_ldt(&ldt, &ldt_info);
if (oldmode)
ldt.avl = 0;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,105 @@
diff --git a/arch/x86/include/asm/irqflags.h b/arch/x86/include/asm/irqflags.h
index bba3cf8..0a8b519 100644
--- a/arch/x86/include/asm/irqflags.h
+++ b/arch/x86/include/asm/irqflags.h
@@ -129,7 +129,7 @@
#define PARAVIRT_ADJUST_EXCEPTION_FRAME /* */
-#define INTERRUPT_RETURN iretq
+#define INTERRUPT_RETURN jmp native_iret
#define USERGS_SYSRET64 \
swapgs; \
sysretq;
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index f9315d9..db230f8 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1056,27 +1056,24 @@
RESTORE_ARGS 1,8,1
irq_return:
+ INTERRUPT_RETURN
+
+ENTRY(native_iret)
/*
* Are we returning to a stack segment from the LDT? Note: in
* 64-bit mode SS:RSP on the exception stack is always valid.
*/
#ifdef CONFIG_X86_ESPFIX64
testb $4,(SS-RIP)(%rsp)
- jnz irq_return_ldt
+ jnz native_irq_return_ldt
#endif
-irq_return_iret:
- INTERRUPT_RETURN
- _ASM_EXTABLE(irq_return_iret, bad_iret)
-
-#ifdef CONFIG_PARAVIRT
-ENTRY(native_iret)
+native_irq_return_iret:
iretq
- _ASM_EXTABLE(native_iret, bad_iret)
-#endif
+ _ASM_EXTABLE(native_irq_return_iret, bad_iret)
#ifdef CONFIG_X86_ESPFIX64
-irq_return_ldt:
+native_irq_return_ldt:
pushq_cfi %rax
pushq_cfi %rdi
SWAPGS
@@ -1098,7 +1095,7 @@
SWAPGS
movq %rax,%rsp
popq_cfi %rax
- jmp irq_return_iret
+ jmp native_irq_return_iret
#endif
.section .fixup,"ax"
@@ -1184,13 +1181,8 @@
cmpl $__KERNEL_CS,CS(%rdi)
jne do_double_fault
movq RIP(%rdi),%rax
- cmpq $irq_return_iret,%rax
-#ifdef CONFIG_PARAVIRT
- je 1f
- cmpq $native_iret,%rax
-#endif
+ cmpq $native_irq_return_iret,%rax
jne do_double_fault /* This shouldn't happen... */
-1:
movq PER_CPU_VAR(kernel_stack),%rax
subq $(6*8-KERNEL_STACK_OFFSET),%rax /* Reset to original stack */
movq %rax,RSP(%rdi)
@@ -1658,7 +1650,7 @@
*/
error_kernelspace:
incl %ebx
- leaq irq_return_iret(%rip),%rcx
+ leaq native_irq_return_iret(%rip),%rcx
cmpq %rcx,RIP+8(%rsp)
je error_swapgs
movl %ecx,%eax /* zero extend */
diff --git a/arch/x86/kernel/paravirt_patch_64.c b/arch/x86/kernel/paravirt_patch_64.c
index 3f08f34..a1da673 100644
--- a/arch/x86/kernel/paravirt_patch_64.c
+++ b/arch/x86/kernel/paravirt_patch_64.c
@@ -6,7 +6,6 @@
DEF_NATIVE(pv_irq_ops, irq_enable, "sti");
DEF_NATIVE(pv_irq_ops, restore_fl, "pushq %rdi; popfq");
DEF_NATIVE(pv_irq_ops, save_fl, "pushfq; popq %rax");
-DEF_NATIVE(pv_cpu_ops, iret, "iretq");
DEF_NATIVE(pv_mmu_ops, read_cr2, "movq %cr2, %rax");
DEF_NATIVE(pv_mmu_ops, read_cr3, "movq %cr3, %rax");
DEF_NATIVE(pv_mmu_ops, write_cr3, "movq %rdi, %cr3");
@@ -50,7 +49,6 @@
PATCH_SITE(pv_irq_ops, save_fl);
PATCH_SITE(pv_irq_ops, irq_enable);
PATCH_SITE(pv_irq_ops, irq_disable);
- PATCH_SITE(pv_cpu_ops, iret);
PATCH_SITE(pv_cpu_ops, irq_enable_sysexit);
PATCH_SITE(pv_cpu_ops, usergs_sysret32);
PATCH_SITE(pv_cpu_ops, usergs_sysret64);

View File

@ -0,0 +1 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL2lycWZsYWdzLmggYi9hcmNoL3g4Ni9pbmNsdWRlL2FzbS9pcnFmbGFncy5oCmluZGV4IGJiYTNjZjguLjBhOGI1MTkgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL2lycWZsYWdzLmgKKysrIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vaXJxZmxhZ3MuaApAQCAtMTI5LDcgKzEyOSw3IEBACiAKICNkZWZpbmUgUEFSQVZJUlRfQURKVVNUX0VYQ0VQVElPTl9GUkFNRQkvKiAgKi8KIAotI2RlZmluZSBJTlRFUlJVUFRfUkVUVVJOCWlyZXRxCisjZGVmaW5lIElOVEVSUlVQVF9SRVRVUk4Jam1wIG5hdGl2ZV9pcmV0CiAjZGVmaW5lIFVTRVJHU19TWVNSRVQ2NAkJCQlcCiAJc3dhcGdzOwkJCQkJXAogCXN5c3JldHE7CmRpZmYgLS1naXQgYS9hcmNoL3g4Ni9rZXJuZWwvZW50cnlfNjQuUyBiL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TCmluZGV4IGY5MzE1ZDkuLmRiMjMwZjggMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TCisrKyBiL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TCkBAIC0xMDU2LDI3ICsxMDU2LDI0IEBACiAJUkVTVE9SRV9BUkdTIDEsOCwxCiAKIGlycV9yZXR1cm46CisJSU5URVJSVVBUX1JFVFVSTgorCitFTlRSWShuYXRpdmVfaXJldCkKIAkvKgogCSAqIEFyZSB3ZSByZXR1cm5pbmcgdG8gYSBzdGFjayBzZWdtZW50IGZyb20gdGhlIExEVD8gIE5vdGU6IGluCiAJICogNjQtYml0IG1vZGUgU1M6UlNQIG9uIHRoZSBleGNlcHRpb24gc3RhY2sgaXMgYWx3YXlzIHZhbGlkLgogCSAqLwogI2lmZGVmIENPTkZJR19YODZfRVNQRklYNjQKIAl0ZXN0YiAkNCwoU1MtUklQKSglcnNwKQotCWpueiBpcnFfcmV0dXJuX2xkdAorCWpueiBuYXRpdmVfaXJxX3JldHVybl9sZHQKICNlbmRpZgogCi1pcnFfcmV0dXJuX2lyZXQ6Ci0JSU5URVJSVVBUX1JFVFVSTgotCV9BU01fRVhUQUJMRShpcnFfcmV0dXJuX2lyZXQsIGJhZF9pcmV0KQotCi0jaWZkZWYgQ09ORklHX1BBUkFWSVJUCi1FTlRSWShuYXRpdmVfaXJldCkKK25hdGl2ZV9pcnFfcmV0dXJuX2lyZXQ6CiAJaXJldHEKLQlfQVNNX0VYVEFCTEUobmF0aXZlX2lyZXQsIGJhZF9pcmV0KQotI2VuZGlmCisJX0FTTV9FWFRBQkxFKG5hdGl2ZV9pcnFfcmV0dXJuX2lyZXQsIGJhZF9pcmV0KQogCiAjaWZkZWYgQ09ORklHX1g4Nl9FU1BGSVg2NAotaXJxX3JldHVybl9sZHQ6CituYXRpdmVfaXJxX3JldHVybl9sZHQ6CiAJcHVzaHFfY2ZpICVyYXgKIAlwdXNocV9jZmkgJXJkaQogCVNXQVBHUwpAQCAtMTA5OCw3ICsxMDk1LDcgQEAKIAlTV0FQR1MKIAltb3ZxICVyYXgsJXJzcAogCXBvcHFfY2ZpICVyYXgKLQlqbXAgaXJxX3JldHVybl9pcmV0CisJam1wIG5hdGl2ZV9pcnFfcmV0dXJuX2lyZXQKICNlbmRpZgogCiAJLnNlY3Rpb24gLmZpeHVwLCJheCIKQEAgLTExODQsMTMgKzExODEsOCBAQAogCWNtcGwgJF9fS0VSTkVMX0NTLENTKCVyZGkpCiAJam5lIGRvX2RvdWJsZV9mYXVsdAogCW1vdnEgUklQKCVyZGkpLCVyYXgKLQljbXBxICRpcnFfcmV0dXJuX2lyZXQsJXJheAotI2lmZGVmIENPTkZJR19QQVJBVklSVAotCWplIDFmCi0JY21wcSAkbmF0aXZlX2lyZXQsJXJheAotI2VuZGlmCisJY21wcSAkbmF0aXZlX2lycV9yZXR1cm5faXJldCwlcmF4CiAJam5lIGRvX2RvdWJsZV9mYXVsdAkJLyogVGhpcyBzaG91bGRuJ3QgaGFwcGVuLi4uICovCi0xOgogCW1vdnEgUEVSX0NQVV9WQVIoa2VybmVsX3N0YWNrKSwlcmF4CiAJc3VicSAkKDYqOC1LRVJORUxfU1RBQ0tfT0ZGU0VUKSwlcmF4CS8qIFJlc2V0IHRvIG9yaWdpbmFsIHN0YWNrICovCiAJbW92cSAlcmF4LFJTUCglcmRpKQpAQCAtMTY1OCw3ICsxNjUwLDcgQEAKICAqLwogZXJyb3Jfa2VybmVsc3BhY2U6CiAJaW5jbCAlZWJ4Ci0JbGVhcSBpcnFfcmV0dXJuX2lyZXQoJXJpcCksJXJjeAorCWxlYXEgbmF0aXZlX2lycV9yZXR1cm5faXJldCglcmlwKSwlcmN4CiAJY21wcSAlcmN4LFJJUCs4KCVyc3ApCiAJamUgZXJyb3Jfc3dhcGdzCiAJbW92bCAlZWN4LCVlYXgJLyogemVybyBleHRlbmQgKi8KZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC9wYXJhdmlydF9wYXRjaF82NC5jIGIvYXJjaC94ODYva2VybmVsL3BhcmF2aXJ0X3BhdGNoXzY0LmMKaW5kZXggM2YwOGYzNC4uYTFkYTY3MyAxMDA2NDQKLS0tIGEvYXJjaC94ODYva2VybmVsL3BhcmF2aXJ0X3BhdGNoXzY0LmMKKysrIGIvYXJjaC94ODYva2VybmVsL3BhcmF2aXJ0X3BhdGNoXzY0LmMKQEAgLTYsNyArNiw2IEBACiBERUZfTkFUSVZFKHB2X2lycV9vcHMsIGlycV9lbmFibGUsICJzdGkiKTsKIERFRl9OQVRJVkUocHZfaXJxX29wcywgcmVzdG9yZV9mbCwgInB1c2hxICVyZGk7IHBvcGZxIik7CiBERUZfTkFUSVZFKHB2X2lycV9vcHMsIHNhdmVfZmwsICJwdXNoZnE7IHBvcHEgJXJheCIpOwotREVGX05BVElWRShwdl9jcHVfb3BzLCBpcmV0LCAiaXJldHEiKTsKIERFRl9OQVRJVkUocHZfbW11X29wcywgcmVhZF9jcjIsICJtb3ZxICVjcjIsICVyYXgiKTsKIERFRl9OQVRJVkUocHZfbW11X29wcywgcmVhZF9jcjMsICJtb3ZxICVjcjMsICVyYXgiKTsKIERFRl9OQVRJVkUocHZfbW11X29wcywgd3JpdGVfY3IzLCAibW92cSAlcmRpLCAlY3IzIik7CkBAIC01MCw3ICs0OSw2IEBACiAJCVBBVENIX1NJVEUocHZfaXJxX29wcywgc2F2ZV9mbCk7CiAJCVBBVENIX1NJVEUocHZfaXJxX29wcywgaXJxX2VuYWJsZSk7CiAJCVBBVENIX1NJVEUocHZfaXJxX29wcywgaXJxX2Rpc2FibGUpOwotCQlQQVRDSF9TSVRFKHB2X2NwdV9vcHMsIGlyZXQpOwogCQlQQVRDSF9TSVRFKHB2X2NwdV9vcHMsIGlycV9lbmFibGVfc3lzZXhpdCk7CiAJCVBBVENIX1NJVEUocHZfY3B1X29wcywgdXNlcmdzX3N5c3JldDMyKTsKIAkJUEFUQ0hfU0lURShwdl9jcHVfb3BzLCB1c2VyZ3Nfc3lzcmV0NjQpOwo=

View File

@ -0,0 +1,30 @@
diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c
index 6afbb16..94d857f 100644
--- a/arch/x86/kernel/espfix_64.c
+++ b/arch/x86/kernel/espfix_64.c
@@ -175,7 +175,7 @@
if (!pud_present(pud)) {
pmd_p = (pmd_t *)__get_free_page(PGALLOC_GFP);
pud = __pud(__pa(pmd_p) | (PGTABLE_PROT & ptemask));
- paravirt_alloc_pud(&init_mm, __pa(pmd_p) >> PAGE_SHIFT);
+ paravirt_alloc_pmd(&init_mm, __pa(pmd_p) >> PAGE_SHIFT);
for (n = 0; n < ESPFIX_PUD_CLONES; n++)
set_pud(&pud_p[n], pud);
}
@@ -185,7 +185,7 @@
if (!pmd_present(pmd)) {
pte_p = (pte_t *)__get_free_page(PGALLOC_GFP);
pmd = __pmd(__pa(pte_p) | (PGTABLE_PROT & ptemask));
- paravirt_alloc_pmd(&init_mm, __pa(pte_p) >> PAGE_SHIFT);
+ paravirt_alloc_pte(&init_mm, __pa(pte_p) >> PAGE_SHIFT);
for (n = 0; n < ESPFIX_PMD_CLONES; n++)
set_pmd(&pmd_p[n], pmd);
}
@@ -193,7 +193,6 @@
pte_p = pte_offset_kernel(&pmd, addr);
stack_page = (void *)__get_free_page(GFP_KERNEL);
pte = __pte(__pa(stack_page) | (__PAGE_KERNEL_RO & ptemask));
- paravirt_alloc_pte(&init_mm, __pa(stack_page) >> PAGE_SHIFT);
for (n = 0; n < ESPFIX_PTE_CLONES; n++)
set_pte(&pte_p[n*PTE_STRIDE], pte);

View File

@ -0,0 +1 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC9lc3BmaXhfNjQuYyBiL2FyY2gveDg2L2tlcm5lbC9lc3BmaXhfNjQuYwppbmRleCA2YWZiYjE2Li45NGQ4NTdmIDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9rZXJuZWwvZXNwZml4XzY0LmMKKysrIGIvYXJjaC94ODYva2VybmVsL2VzcGZpeF82NC5jCkBAIC0xNzUsNyArMTc1LDcgQEAKIAlpZiAoIXB1ZF9wcmVzZW50KHB1ZCkpIHsKIAkJcG1kX3AgPSAocG1kX3QgKilfX2dldF9mcmVlX3BhZ2UoUEdBTExPQ19HRlApOwogCQlwdWQgPSBfX3B1ZChfX3BhKHBtZF9wKSB8IChQR1RBQkxFX1BST1QgJiBwdGVtYXNrKSk7Ci0JCXBhcmF2aXJ0X2FsbG9jX3B1ZCgmaW5pdF9tbSwgX19wYShwbWRfcCkgPj4gUEFHRV9TSElGVCk7CisJCXBhcmF2aXJ0X2FsbG9jX3BtZCgmaW5pdF9tbSwgX19wYShwbWRfcCkgPj4gUEFHRV9TSElGVCk7CiAJCWZvciAobiA9IDA7IG4gPCBFU1BGSVhfUFVEX0NMT05FUzsgbisrKQogCQkJc2V0X3B1ZCgmcHVkX3Bbbl0sIHB1ZCk7CiAJfQpAQCAtMTg1LDcgKzE4NSw3IEBACiAJaWYgKCFwbWRfcHJlc2VudChwbWQpKSB7CiAJCXB0ZV9wID0gKHB0ZV90ICopX19nZXRfZnJlZV9wYWdlKFBHQUxMT0NfR0ZQKTsKIAkJcG1kID0gX19wbWQoX19wYShwdGVfcCkgfCAoUEdUQUJMRV9QUk9UICYgcHRlbWFzaykpOwotCQlwYXJhdmlydF9hbGxvY19wbWQoJmluaXRfbW0sIF9fcGEocHRlX3ApID4+IFBBR0VfU0hJRlQpOworCQlwYXJhdmlydF9hbGxvY19wdGUoJmluaXRfbW0sIF9fcGEocHRlX3ApID4+IFBBR0VfU0hJRlQpOwogCQlmb3IgKG4gPSAwOyBuIDwgRVNQRklYX1BNRF9DTE9ORVM7IG4rKykKIAkJCXNldF9wbWQoJnBtZF9wW25dLCBwbWQpOwogCX0KQEAgLTE5Myw3ICsxOTMsNiBAQAogCXB0ZV9wID0gcHRlX29mZnNldF9rZXJuZWwoJnBtZCwgYWRkcik7CiAJc3RhY2tfcGFnZSA9ICh2b2lkICopX19nZXRfZnJlZV9wYWdlKEdGUF9LRVJORUwpOwogCXB0ZSA9IF9fcHRlKF9fcGEoc3RhY2tfcGFnZSkgfCAoX19QQUdFX0tFUk5FTF9STyAmIHB0ZW1hc2spKTsKLQlwYXJhdmlydF9hbGxvY19wdGUoJmluaXRfbW0sIF9fcGEoc3RhY2tfcGFnZSkgPj4gUEFHRV9TSElGVCk7CiAJZm9yIChuID0gMDsgbiA8IEVTUEZJWF9QVEVfQ0xPTkVTOyBuKyspCiAJCXNldF9wdGUoJnB0ZV9wW24qUFRFX1NUUklERV0sIHB0ZSk7CiAK

View File

@ -0,0 +1,94 @@
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index db230f8..1a454d0 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1068,6 +1068,7 @@
jnz native_irq_return_ldt
#endif
+.global native_irq_return_iret
native_irq_return_iret:
iretq
_ASM_EXTABLE(native_irq_return_iret, bad_iret)
@@ -1164,37 +1165,6 @@
CFI_ENDPROC
END(common_interrupt)
- /*
- * If IRET takes a fault on the espfix stack, then we
- * end up promoting it to a doublefault. In that case,
- * modify the stack to make it look like we just entered
- * the #GP handler from user space, similar to bad_iret.
- */
-#ifdef CONFIG_X86_ESPFIX64
- ALIGN
-__do_double_fault:
- XCPT_FRAME 1 RDI+8
- movq RSP(%rdi),%rax /* Trap on the espfix stack? */
- sarq $PGDIR_SHIFT,%rax
- cmpl $ESPFIX_PGD_ENTRY,%eax
- jne do_double_fault /* No, just deliver the fault */
- cmpl $__KERNEL_CS,CS(%rdi)
- jne do_double_fault
- movq RIP(%rdi),%rax
- cmpq $native_irq_return_iret,%rax
- jne do_double_fault /* This shouldn't happen... */
- movq PER_CPU_VAR(kernel_stack),%rax
- subq $(6*8-KERNEL_STACK_OFFSET),%rax /* Reset to original stack */
- movq %rax,RSP(%rdi)
- movq $0,(%rax) /* Missing (lost) #GP error code */
- movq $general_protection,RIP(%rdi)
- retq
- CFI_ENDPROC
-END(__do_double_fault)
-#else
-# define __do_double_fault do_double_fault
-#endif
-
/*
* End of kprobes section
*/
@@ -1363,7 +1333,7 @@
zeroentry bounds do_bounds
zeroentry invalid_op do_invalid_op
zeroentry device_not_available do_device_not_available
-paranoiderrorentry double_fault __do_double_fault
+paranoiderrorentry double_fault do_double_fault
zeroentry coprocessor_segment_overrun do_coprocessor_segment_overrun
errorentry invalid_TSS do_invalid_TSS
errorentry segment_not_present do_segment_not_present
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 772e2a8..74e0801 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -247,6 +247,30 @@
static const char str[] = "double fault";
struct task_struct *tsk = current;
+#ifdef CONFIG_X86_ESPFIX64
+ extern unsigned char native_irq_return_iret[];
+
+ /*
+ * If IRET takes a non-IST fault on the espfix64 stack, then we
+ * end up promoting it to a doublefault. In that case, modify
+ * the stack to make it look like we just entered the #GP
+ * handler from user space, similar to bad_iret.
+ */
+ if (((long)regs->sp >> PGDIR_SHIFT) == ESPFIX_PGD_ENTRY &&
+ regs->cs == __KERNEL_CS &&
+ regs->ip == (unsigned long)native_irq_return_iret)
+ {
+ struct pt_regs *normal_regs = task_pt_regs(current);
+
+ /* Fake a #GP(0) from userspace. */
+ memmove(&normal_regs->ip, (void *)regs->sp, 5*8);
+ normal_regs->orig_ax = 0; /* Missing (lost) #GP error code */
+ regs->ip = (unsigned long)general_protection;
+ regs->sp = (unsigned long)&normal_regs->orig_ax;
+ return;
+ }
+#endif
+
exception_enter();
/* Return not checked because double check cannot be ignored */
notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);

View File

@ -0,0 +1 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKaW5kZXggZGIyMzBmOC4uMWE0NTRkMCAxMDA2NDQKLS0tIGEvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKKysrIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKQEAgLTEwNjgsNiArMTA2OCw3IEBACiAJam56IG5hdGl2ZV9pcnFfcmV0dXJuX2xkdAogI2VuZGlmCiAKKy5nbG9iYWwgbmF0aXZlX2lycV9yZXR1cm5faXJldAogbmF0aXZlX2lycV9yZXR1cm5faXJldDoKIAlpcmV0cQogCV9BU01fRVhUQUJMRShuYXRpdmVfaXJxX3JldHVybl9pcmV0LCBiYWRfaXJldCkKQEAgLTExNjQsMzcgKzExNjUsNiBAQAogCUNGSV9FTkRQUk9DCiBFTkQoY29tbW9uX2ludGVycnVwdCkKIAotCS8qCi0JICogSWYgSVJFVCB0YWtlcyBhIGZhdWx0IG9uIHRoZSBlc3BmaXggc3RhY2ssIHRoZW4gd2UKLQkgKiBlbmQgdXAgcHJvbW90aW5nIGl0IHRvIGEgZG91YmxlZmF1bHQuICBJbiB0aGF0IGNhc2UsCi0JICogbW9kaWZ5IHRoZSBzdGFjayB0byBtYWtlIGl0IGxvb2sgbGlrZSB3ZSBqdXN0IGVudGVyZWQKLQkgKiB0aGUgI0dQIGhhbmRsZXIgZnJvbSB1c2VyIHNwYWNlLCBzaW1pbGFyIHRvIGJhZF9pcmV0LgotCSAqLwotI2lmZGVmIENPTkZJR19YODZfRVNQRklYNjQKLQlBTElHTgotX19kb19kb3VibGVfZmF1bHQ6Ci0JWENQVF9GUkFNRSAxIFJESSs4Ci0JbW92cSBSU1AoJXJkaSksJXJheAkJLyogVHJhcCBvbiB0aGUgZXNwZml4IHN0YWNrPyAqLwotCXNhcnEgJFBHRElSX1NISUZULCVyYXgKLQljbXBsICRFU1BGSVhfUEdEX0VOVFJZLCVlYXgKLQlqbmUgZG9fZG91YmxlX2ZhdWx0CQkvKiBObywganVzdCBkZWxpdmVyIHRoZSBmYXVsdCAqLwotCWNtcGwgJF9fS0VSTkVMX0NTLENTKCVyZGkpCi0Jam5lIGRvX2RvdWJsZV9mYXVsdAotCW1vdnEgUklQKCVyZGkpLCVyYXgKLQljbXBxICRuYXRpdmVfaXJxX3JldHVybl9pcmV0LCVyYXgKLQlqbmUgZG9fZG91YmxlX2ZhdWx0CQkvKiBUaGlzIHNob3VsZG4ndCBoYXBwZW4uLi4gKi8KLQltb3ZxIFBFUl9DUFVfVkFSKGtlcm5lbF9zdGFjayksJXJheAotCXN1YnEgJCg2KjgtS0VSTkVMX1NUQUNLX09GRlNFVCksJXJheAkvKiBSZXNldCB0byBvcmlnaW5hbCBzdGFjayAqLwotCW1vdnEgJXJheCxSU1AoJXJkaSkKLQltb3ZxICQwLCglcmF4KQkJCS8qIE1pc3NpbmcgKGxvc3QpICNHUCBlcnJvciBjb2RlICovCi0JbW92cSAkZ2VuZXJhbF9wcm90ZWN0aW9uLFJJUCglcmRpKQotCXJldHEKLQlDRklfRU5EUFJPQwotRU5EKF9fZG9fZG91YmxlX2ZhdWx0KQotI2Vsc2UKLSMgZGVmaW5lIF9fZG9fZG91YmxlX2ZhdWx0IGRvX2RvdWJsZV9mYXVsdAotI2VuZGlmCi0KIC8qCiAgKiBFbmQgb2Yga3Byb2JlcyBzZWN0aW9uCiAgKi8KQEAgLTEzNjMsNyArMTMzMyw3IEBACiB6ZXJvZW50cnkgYm91bmRzIGRvX2JvdW5kcwogemVyb2VudHJ5IGludmFsaWRfb3AgZG9faW52YWxpZF9vcAogemVyb2VudHJ5IGRldmljZV9ub3RfYXZhaWxhYmxlIGRvX2RldmljZV9ub3RfYXZhaWxhYmxlCi1wYXJhbm9pZGVycm9yZW50cnkgZG91YmxlX2ZhdWx0IF9fZG9fZG91YmxlX2ZhdWx0CitwYXJhbm9pZGVycm9yZW50cnkgZG91YmxlX2ZhdWx0IGRvX2RvdWJsZV9mYXVsdAogemVyb2VudHJ5IGNvcHJvY2Vzc29yX3NlZ21lbnRfb3ZlcnJ1biBkb19jb3Byb2Nlc3Nvcl9zZWdtZW50X292ZXJydW4KIGVycm9yZW50cnkgaW52YWxpZF9UU1MgZG9faW52YWxpZF9UU1MKIGVycm9yZW50cnkgc2VnbWVudF9ub3RfcHJlc2VudCBkb19zZWdtZW50X25vdF9wcmVzZW50CmRpZmYgLS1naXQgYS9hcmNoL3g4Ni9rZXJuZWwvdHJhcHMuYyBiL2FyY2gveDg2L2tlcm5lbC90cmFwcy5jCmluZGV4IDc3MmUyYTguLjc0ZTA4MDEgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC90cmFwcy5jCisrKyBiL2FyY2gveDg2L2tlcm5lbC90cmFwcy5jCkBAIC0yNDcsNiArMjQ3LDMwIEBACiAJc3RhdGljIGNvbnN0IGNoYXIgc3RyW10gPSAiZG91YmxlIGZhdWx0IjsKIAlzdHJ1Y3QgdGFza19zdHJ1Y3QgKnRzayA9IGN1cnJlbnQ7CiAKKyNpZmRlZiBDT05GSUdfWDg2X0VTUEZJWDY0CisJZXh0ZXJuIHVuc2lnbmVkIGNoYXIgbmF0aXZlX2lycV9yZXR1cm5faXJldFtdOworCisJLyoKKwkgKiBJZiBJUkVUIHRha2VzIGEgbm9uLUlTVCBmYXVsdCBvbiB0aGUgZXNwZml4NjQgc3RhY2ssIHRoZW4gd2UKKwkgKiBlbmQgdXAgcHJvbW90aW5nIGl0IHRvIGEgZG91YmxlZmF1bHQuICBJbiB0aGF0IGNhc2UsIG1vZGlmeQorCSAqIHRoZSBzdGFjayB0byBtYWtlIGl0IGxvb2sgbGlrZSB3ZSBqdXN0IGVudGVyZWQgdGhlICNHUAorCSAqIGhhbmRsZXIgZnJvbSB1c2VyIHNwYWNlLCBzaW1pbGFyIHRvIGJhZF9pcmV0LgorCSAqLworCWlmICgoKGxvbmcpcmVncy0+c3AgPj4gUEdESVJfU0hJRlQpID09IEVTUEZJWF9QR0RfRU5UUlkgJiYKKwkJcmVncy0+Y3MgPT0gX19LRVJORUxfQ1MgJiYKKwkJcmVncy0+aXAgPT0gKHVuc2lnbmVkIGxvbmcpbmF0aXZlX2lycV9yZXR1cm5faXJldCkKKwl7CisJCXN0cnVjdCBwdF9yZWdzICpub3JtYWxfcmVncyA9IHRhc2tfcHRfcmVncyhjdXJyZW50KTsKKworCQkvKiBGYWtlIGEgI0dQKDApIGZyb20gdXNlcnNwYWNlLiAqLworCQltZW1tb3ZlKCZub3JtYWxfcmVncy0+aXAsICh2b2lkICopcmVncy0+c3AsIDUqOCk7CisJCW5vcm1hbF9yZWdzLT5vcmlnX2F4ID0gMDsgIC8qIE1pc3NpbmcgKGxvc3QpICNHUCBlcnJvciBjb2RlICovCisJCXJlZ3MtPmlwID0gKHVuc2lnbmVkIGxvbmcpZ2VuZXJhbF9wcm90ZWN0aW9uOworCQlyZWdzLT5zcCA9ICh1bnNpZ25lZCBsb25nKSZub3JtYWxfcmVncy0+b3JpZ19heDsKKwkJcmV0dXJuOworCX0KKyNlbmRpZgorCiAJZXhjZXB0aW9uX2VudGVyKCk7CiAJLyogUmV0dXJuIG5vdCBjaGVja2VkIGJlY2F1c2UgZG91YmxlIGNoZWNrIGNhbm5vdCBiZSBpZ25vcmVkICovCiAJbm90aWZ5X2RpZShESUVfVFJBUCwgc3RyLCByZWdzLCBlcnJvcl9jb2RlLCBYODZfVFJBUF9ERiwgU0lHU0VHVik7Cg==

View File

@ -0,0 +1,101 @@
diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h
index ef17af0..4376b45 100644
--- a/arch/x86/include/asm/page_32_types.h
+++ b/arch/x86/include/asm/page_32_types.h
@@ -18,7 +18,6 @@
#define THREAD_SIZE_ORDER 1
#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
-#define STACKFAULT_STACK 0
#define DOUBLEFAULT_STACK 1
#define NMI_STACK 0
#define DEBUG_STACK 0
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
index 6c896fb..970f309 100644
--- a/arch/x86/include/asm/page_64_types.h
+++ b/arch/x86/include/asm/page_64_types.h
@@ -14,12 +14,11 @@
#define IRQ_STACK_ORDER 2
#define IRQ_STACK_SIZE (PAGE_SIZE << IRQ_STACK_ORDER)
-#define STACKFAULT_STACK 1
-#define DOUBLEFAULT_STACK 2
-#define NMI_STACK 3
-#define DEBUG_STACK 4
-#define MCE_STACK 5
-#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */
+#define DOUBLEFAULT_STACK 1
+#define NMI_STACK 2
+#define DEBUG_STACK 3
+#define MCE_STACK 4
+#define N_EXCEPTION_STACKS 4 /* hw limit: 7 */
#define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT)
#define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1))
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index addb207..66e274a 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -24,7 +24,6 @@
[ DEBUG_STACK-1 ] = "#DB",
[ NMI_STACK-1 ] = "NMI",
[ DOUBLEFAULT_STACK-1 ] = "#DF",
- [ STACKFAULT_STACK-1 ] = "#SS",
[ MCE_STACK-1 ] = "#MC",
#if DEBUG_STKSZ > EXCEPTION_STKSZ
[ N_EXCEPTION_STACKS ...
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 1a454d0..50e5e59 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1503,7 +1503,7 @@
paranoidzeroentry_ist debug do_debug DEBUG_STACK
paranoidzeroentry_ist int3 do_int3 DEBUG_STACK
-paranoiderrorentry stack_segment do_stack_segment
+errorentry stack_segment do_stack_segment
#ifdef CONFIG_XEN
zeroentry xen_debug do_debug
zeroentry xen_int3 do_int3
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 74e0801..00a2873 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -220,28 +220,12 @@
coprocessor_segment_overrun)
DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(X86_TRAP_NP, SIGBUS, "segment not present", segment_not_present)
-#ifdef CONFIG_X86_32
DO_ERROR(X86_TRAP_SS, SIGBUS, "stack segment", stack_segment)
-#endif
DO_ERROR_INFO(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check,
BUS_ADRALN, 0)
#ifdef CONFIG_X86_64
/* Runs on IST stack */
-dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
-{
- enum ctx_state prev_state;
-
- prev_state = exception_enter();
- if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
- X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) {
- preempt_conditional_sti(regs);
- do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
- preempt_conditional_cli(regs);
- }
- exception_exit(prev_state);
-}
-
dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
{
static const char str[] = "double fault";
@@ -769,7 +753,7 @@
set_intr_gate(X86_TRAP_OLD_MF, &coprocessor_segment_overrun);
set_intr_gate(X86_TRAP_TS, &invalid_TSS);
set_intr_gate(X86_TRAP_NP, &segment_not_present);
- set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK);
+ set_intr_gate(X86_TRAP_SS, stack_segment);
set_intr_gate(X86_TRAP_GP, &general_protection);
set_intr_gate(X86_TRAP_SPURIOUS, &spurious_interrupt_bug);
set_intr_gate(X86_TRAP_MF, &coprocessor_error);

View File

@ -0,0 +1 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL3BhZ2VfMzJfdHlwZXMuaCBiL2FyY2gveDg2L2luY2x1ZGUvYXNtL3BhZ2VfMzJfdHlwZXMuaAppbmRleCBlZjE3YWYwLi40Mzc2YjQ1IDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9pbmNsdWRlL2FzbS9wYWdlXzMyX3R5cGVzLmgKKysrIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vcGFnZV8zMl90eXBlcy5oCkBAIC0xOCw3ICsxOCw2IEBACiAjZGVmaW5lIFRIUkVBRF9TSVpFX09SREVSCTEKICNkZWZpbmUgVEhSRUFEX1NJWkUJCShQQUdFX1NJWkUgPDwgVEhSRUFEX1NJWkVfT1JERVIpCiAKLSNkZWZpbmUgU1RBQ0tGQVVMVF9TVEFDSyAwCiAjZGVmaW5lIERPVUJMRUZBVUxUX1NUQUNLIDEKICNkZWZpbmUgTk1JX1NUQUNLIDAKICNkZWZpbmUgREVCVUdfU1RBQ0sgMApkaWZmIC0tZ2l0IGEvYXJjaC94ODYvaW5jbHVkZS9hc20vcGFnZV82NF90eXBlcy5oIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vcGFnZV82NF90eXBlcy5oCmluZGV4IDZjODk2ZmIuLjk3MGYzMDkgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL3BhZ2VfNjRfdHlwZXMuaAorKysgYi9hcmNoL3g4Ni9pbmNsdWRlL2FzbS9wYWdlXzY0X3R5cGVzLmgKQEAgLTE0LDEyICsxNCwxMSBAQAogI2RlZmluZSBJUlFfU1RBQ0tfT1JERVIgMgogI2RlZmluZSBJUlFfU1RBQ0tfU0laRSAoUEFHRV9TSVpFIDw8IElSUV9TVEFDS19PUkRFUikKIAotI2RlZmluZSBTVEFDS0ZBVUxUX1NUQUNLIDEKLSNkZWZpbmUgRE9VQkxFRkFVTFRfU1RBQ0sgMgotI2RlZmluZSBOTUlfU1RBQ0sgMwotI2RlZmluZSBERUJVR19TVEFDSyA0Ci0jZGVmaW5lIE1DRV9TVEFDSyA1Ci0jZGVmaW5lIE5fRVhDRVBUSU9OX1NUQUNLUyA1ICAvKiBodyBsaW1pdDogNyAqLworI2RlZmluZSBET1VCTEVGQVVMVF9TVEFDSyAxCisjZGVmaW5lIE5NSV9TVEFDSyAyCisjZGVmaW5lIERFQlVHX1NUQUNLIDMKKyNkZWZpbmUgTUNFX1NUQUNLIDQKKyNkZWZpbmUgTl9FWENFUFRJT05fU1RBQ0tTIDQgIC8qIGh3IGxpbWl0OiA3ICovCiAKICNkZWZpbmUgUFVEX1BBR0VfU0laRQkJKF9BQygxLCBVTCkgPDwgUFVEX1NISUZUKQogI2RlZmluZSBQVURfUEFHRV9NQVNLCQkofihQVURfUEFHRV9TSVpFLTEpKQpkaWZmIC0tZ2l0IGEvYXJjaC94ODYva2VybmVsL2R1bXBzdGFja182NC5jIGIvYXJjaC94ODYva2VybmVsL2R1bXBzdGFja182NC5jCmluZGV4IGFkZGIyMDcuLjY2ZTI3NGEgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC9kdW1wc3RhY2tfNjQuYworKysgYi9hcmNoL3g4Ni9rZXJuZWwvZHVtcHN0YWNrXzY0LmMKQEAgLTI0LDcgKzI0LDYgQEAKIAkJWyBERUJVR19TVEFDSy0xCQkJXQk9ICIjREIiLAogCQlbIE5NSV9TVEFDSy0xCQkJXQk9ICJOTUkiLAogCQlbIERPVUJMRUZBVUxUX1NUQUNLLTEJCV0JPSAiI0RGIiwKLQkJWyBTVEFDS0ZBVUxUX1NUQUNLLTEJCV0JPSAiI1NTIiwKIAkJWyBNQ0VfU1RBQ0stMQkJCV0JPSAiI01DIiwKICNpZiBERUJVR19TVEtTWiA+IEVYQ0VQVElPTl9TVEtTWgogCQlbIE5fRVhDRVBUSU9OX1NUQUNLUyAuLi4KZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKaW5kZXggMWE0NTRkMC4uNTBlNWU1OSAxMDA2NDQKLS0tIGEvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKKysrIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKQEAgLTE1MDMsNyArMTUwMyw3IEBACiAKIHBhcmFub2lkemVyb2VudHJ5X2lzdCBkZWJ1ZyBkb19kZWJ1ZyBERUJVR19TVEFDSwogcGFyYW5vaWR6ZXJvZW50cnlfaXN0IGludDMgZG9faW50MyBERUJVR19TVEFDSwotcGFyYW5vaWRlcnJvcmVudHJ5IHN0YWNrX3NlZ21lbnQgZG9fc3RhY2tfc2VnbWVudAorZXJyb3JlbnRyeSBzdGFja19zZWdtZW50IGRvX3N0YWNrX3NlZ21lbnQKICNpZmRlZiBDT05GSUdfWEVOCiB6ZXJvZW50cnkgeGVuX2RlYnVnIGRvX2RlYnVnCiB6ZXJvZW50cnkgeGVuX2ludDMgZG9faW50MwpkaWZmIC0tZ2l0IGEvYXJjaC94ODYva2VybmVsL3RyYXBzLmMgYi9hcmNoL3g4Ni9rZXJuZWwvdHJhcHMuYwppbmRleCA3NGUwODAxLi4wMGEyODczIDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9rZXJuZWwvdHJhcHMuYworKysgYi9hcmNoL3g4Ni9rZXJuZWwvdHJhcHMuYwpAQCAtMjIwLDI4ICsyMjAsMTIgQEAKIAkJY29wcm9jZXNzb3Jfc2VnbWVudF9vdmVycnVuKQogRE9fRVJST1IoWDg2X1RSQVBfVFMsIFNJR1NFR1YsICJpbnZhbGlkIFRTUyIsIGludmFsaWRfVFNTKQogRE9fRVJST1IoWDg2X1RSQVBfTlAsIFNJR0JVUywgInNlZ21lbnQgbm90IHByZXNlbnQiLCBzZWdtZW50X25vdF9wcmVzZW50KQotI2lmZGVmIENPTkZJR19YODZfMzIKIERPX0VSUk9SKFg4Nl9UUkFQX1NTLCBTSUdCVVMsICJzdGFjayBzZWdtZW50Iiwgc3RhY2tfc2VnbWVudCkKLSNlbmRpZgogRE9fRVJST1JfSU5GTyhYODZfVFJBUF9BQywgU0lHQlVTLCAiYWxpZ25tZW50IGNoZWNrIiwgYWxpZ25tZW50X2NoZWNrLAogCQlCVVNfQURSQUxOLCAwKQogCiAjaWZkZWYgQ09ORklHX1g4Nl82NAogLyogUnVucyBvbiBJU1Qgc3RhY2sgKi8KLWRvdHJhcGxpbmthZ2Ugdm9pZCBkb19zdGFja19zZWdtZW50KHN0cnVjdCBwdF9yZWdzICpyZWdzLCBsb25nIGVycm9yX2NvZGUpCi17Ci0JZW51bSBjdHhfc3RhdGUgcHJldl9zdGF0ZTsKLQotCXByZXZfc3RhdGUgPSBleGNlcHRpb25fZW50ZXIoKTsKLQlpZiAobm90aWZ5X2RpZShESUVfVFJBUCwgInN0YWNrIHNlZ21lbnQiLCByZWdzLCBlcnJvcl9jb2RlLAotCQkgICAgICAgWDg2X1RSQVBfU1MsIFNJR0JVUykgIT0gTk9USUZZX1NUT1ApIHsKLQkJcHJlZW1wdF9jb25kaXRpb25hbF9zdGkocmVncyk7Ci0JCWRvX3RyYXAoWDg2X1RSQVBfU1MsIFNJR0JVUywgInN0YWNrIHNlZ21lbnQiLCByZWdzLCBlcnJvcl9jb2RlLCBOVUxMKTsKLQkJcHJlZW1wdF9jb25kaXRpb25hbF9jbGkocmVncyk7Ci0JfQotCWV4Y2VwdGlvbl9leGl0KHByZXZfc3RhdGUpOwotfQotCiBkb3RyYXBsaW5rYWdlIHZvaWQgZG9fZG91YmxlX2ZhdWx0KHN0cnVjdCBwdF9yZWdzICpyZWdzLCBsb25nIGVycm9yX2NvZGUpCiB7CiAJc3RhdGljIGNvbnN0IGNoYXIgc3RyW10gPSAiZG91YmxlIGZhdWx0IjsKQEAgLTc2OSw3ICs3NTMsNyBAQAogCXNldF9pbnRyX2dhdGUoWDg2X1RSQVBfT0xEX01GLCAmY29wcm9jZXNzb3Jfc2VnbWVudF9vdmVycnVuKTsKIAlzZXRfaW50cl9nYXRlKFg4Nl9UUkFQX1RTLCAmaW52YWxpZF9UU1MpOwogCXNldF9pbnRyX2dhdGUoWDg2X1RSQVBfTlAsICZzZWdtZW50X25vdF9wcmVzZW50KTsKLQlzZXRfaW50cl9nYXRlX2lzdChYODZfVFJBUF9TUywgJnN0YWNrX3NlZ21lbnQsIFNUQUNLRkFVTFRfU1RBQ0spOworCXNldF9pbnRyX2dhdGUoWDg2X1RSQVBfU1MsIHN0YWNrX3NlZ21lbnQpOwogCXNldF9pbnRyX2dhdGUoWDg2X1RSQVBfR1AsICZnZW5lcmFsX3Byb3RlY3Rpb24pOwogCXNldF9pbnRyX2dhdGUoWDg2X1RSQVBfU1BVUklPVVMsICZzcHVyaW91c19pbnRlcnJ1cHRfYnVnKTsKIAlzZXRfaW50cl9nYXRlKFg4Nl9UUkFQX01GLCAmY29wcm9jZXNzb3JfZXJyb3IpOwo=

View File

@ -0,0 +1,55 @@
diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c
index f7fec09..e7650bd 100644
--- a/arch/x86/kernel/tls.c
+++ b/arch/x86/kernel/tls.c
@@ -27,6 +27,21 @@
return -ESRCH;
}
+static bool tls_desc_okay(const struct user_desc *info)
+{
+ if (LDT_empty(info))
+ return true;
+
+ /*
+ * espfix is required for 16-bit data segments, but espfix
+ * only works for LDT segments.
+ */
+ if (!info->seg_32bit)
+ return false;
+
+ return true;
+}
+
static void set_tls_desc(struct task_struct *p, int idx,
const struct user_desc *info, int n)
{
@@ -66,6 +81,9 @@
if (copy_from_user(&info, u_info, sizeof(info)))
return -EFAULT;
+ if (!tls_desc_okay(&info))
+ return -EINVAL;
+
if (idx == -1)
idx = info.entry_number;
@@ -192,6 +210,7 @@
{
struct user_desc infobuf[GDT_ENTRY_TLS_ENTRIES];
const struct user_desc *info;
+ int i;
if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) ||
(pos % sizeof(struct user_desc)) != 0 ||
@@ -205,6 +224,10 @@
else
info = infobuf;
+ for (i = 0; i < count / sizeof(struct user_desc); i++)
+ if (!tls_desc_okay(info + i))
+ return -EINVAL;
+
set_tls_desc(target,
GDT_ENTRY_TLS_MIN + (pos / sizeof(struct user_desc)),
info, count / sizeof(struct user_desc));

View File

@ -0,0 +1 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC90bHMuYyBiL2FyY2gveDg2L2tlcm5lbC90bHMuYwppbmRleCBmN2ZlYzA5Li5lNzY1MGJkIDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9rZXJuZWwvdGxzLmMKKysrIGIvYXJjaC94ODYva2VybmVsL3Rscy5jCkBAIC0yNyw2ICsyNywyMSBAQAogCXJldHVybiAtRVNSQ0g7CiB9CiAKK3N0YXRpYyBib29sIHRsc19kZXNjX29rYXkoY29uc3Qgc3RydWN0IHVzZXJfZGVzYyAqaW5mbykKK3sKKwlpZiAoTERUX2VtcHR5KGluZm8pKQorCQlyZXR1cm4gdHJ1ZTsKKworCS8qCisJICogZXNwZml4IGlzIHJlcXVpcmVkIGZvciAxNi1iaXQgZGF0YSBzZWdtZW50cywgYnV0IGVzcGZpeAorCSAqIG9ubHkgd29ya3MgZm9yIExEVCBzZWdtZW50cy4KKwkgKi8KKwlpZiAoIWluZm8tPnNlZ18zMmJpdCkKKwkJcmV0dXJuIGZhbHNlOworCisJcmV0dXJuIHRydWU7Cit9CisKIHN0YXRpYyB2b2lkIHNldF90bHNfZGVzYyhzdHJ1Y3QgdGFza19zdHJ1Y3QgKnAsIGludCBpZHgsCiAJCQkgY29uc3Qgc3RydWN0IHVzZXJfZGVzYyAqaW5mbywgaW50IG4pCiB7CkBAIC02Niw2ICs4MSw5IEBACiAJaWYgKGNvcHlfZnJvbV91c2VyKCZpbmZvLCB1X2luZm8sIHNpemVvZihpbmZvKSkpCiAJCXJldHVybiAtRUZBVUxUOwogCisJaWYgKCF0bHNfZGVzY19va2F5KCZpbmZvKSkKKwkJcmV0dXJuIC1FSU5WQUw7CisKIAlpZiAoaWR4ID09IC0xKQogCQlpZHggPSBpbmZvLmVudHJ5X251bWJlcjsKIApAQCAtMTkyLDYgKzIxMCw3IEBACiB7CiAJc3RydWN0IHVzZXJfZGVzYyBpbmZvYnVmW0dEVF9FTlRSWV9UTFNfRU5UUklFU107CiAJY29uc3Qgc3RydWN0IHVzZXJfZGVzYyAqaW5mbzsKKwlpbnQgaTsKIAogCWlmIChwb3MgPj0gR0RUX0VOVFJZX1RMU19FTlRSSUVTICogc2l6ZW9mKHN0cnVjdCB1c2VyX2Rlc2MpIHx8CiAJICAgIChwb3MgJSBzaXplb2Yoc3RydWN0IHVzZXJfZGVzYykpICE9IDAgfHwKQEAgLTIwNSw2ICsyMjQsMTAgQEAKIAllbHNlCiAJCWluZm8gPSBpbmZvYnVmOwogCisJZm9yIChpID0gMDsgaSA8IGNvdW50IC8gc2l6ZW9mKHN0cnVjdCB1c2VyX2Rlc2MpOyBpKyspCisJCWlmICghdGxzX2Rlc2Nfb2theShpbmZvICsgaSkpCisJCQlyZXR1cm4gLUVJTlZBTDsKKwogCXNldF90bHNfZGVzYyh0YXJnZXQsCiAJCSAgICAgR0RUX0VOVFJZX1RMU19NSU4gKyAocG9zIC8gc2l6ZW9mKHN0cnVjdCB1c2VyX2Rlc2MpKSwKIAkJICAgICBpbmZvLCBjb3VudCAvIHNpemVvZihzdHJ1Y3QgdXNlcl9kZXNjKSk7Cg==

View File

@ -1,57 +0,0 @@
From 212c4d33ca83e2144064fe9c2911607fbed5386f Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz>
Date: Mon, 15 Dec 2014 14:22:46 +0100
Subject: isofs: Fix infinite looping over CE entries
commit f54e18f1b831c92f6512d2eedb224cd63d607d3d upstream.
Rock Ridge extensions define so called Continuation Entries (CE) which
define where is further space with Rock Ridge data. Corrupted isofs
image can contain arbitrarily long chain of these, including a one
containing loop and thus causing kernel to end in an infinite loop when
traversing these entries.
Limit the traversal to 32 entries which should be more than enough space
to store all the Rock Ridge data.
Reported-by: P J P <ppandit@redhat.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
fs/isofs/rock.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index ee62cc0..26859de 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -30,6 +30,7 @@ struct rock_state {
int cont_size;
int cont_extent;
int cont_offset;
+ int cont_loops;
struct inode *inode;
};
@@ -73,6 +74,9 @@ static void init_rock_state(struct rock_state *rs, struct inode *inode)
rs->inode = inode;
}
+/* Maximum number of Rock Ridge continuation entries */
+#define RR_MAX_CE_ENTRIES 32
+
/*
* Returns 0 if the caller should continue scanning, 1 if the scan must end
* and -ve on error.
@@ -105,6 +109,8 @@ static int rock_continue(struct rock_state *rs)
goto out;
}
ret = -EIO;
+ if (++rs->cont_loops >= RR_MAX_CE_ENTRIES)
+ goto out;
bh = sb_bread(rs->inode->i_sb, rs->cont_extent);
if (bh) {
memcpy(rs->buffer, bh->b_data + rs->cont_offset,
--
cgit v1.1

View File

@ -1,7 +1,7 @@
From f54e18f1b831c92f6512d2eedb224cd63d607d3d Mon Sep 17 00:00:00 2001 From f54e18f1b831c92f6512d2eedb224cd63d607d3d Mon Sep 17 00:00:00 2001
From: Jan Kara <jack@suse.cz> From: Jan Kara <jack@suse.cz>
Date: Mon, 15 Dec 2014 14:22:46 +0100 Date: Mon, 15 Dec 2014 14:22:46 +0100
Subject: [PATCH] isofs: Fix infinite looping over CE entries Subject: isofs: Fix infinite looping over CE entries
Rock Ridge extensions define so called Continuation Entries (CE) which Rock Ridge extensions define so called Continuation Entries (CE) which
define where is further space with Rock Ridge data. Corrupted isofs define where is further space with Rock Ridge data. Corrupted isofs
@ -20,7 +20,7 @@ Signed-off-by: Jan Kara <jack@suse.cz>
1 file changed, 6 insertions(+) 1 file changed, 6 insertions(+)
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index f488bbae541ac..bb63254ed8486 100644 index f488bba..bb63254 100644
--- a/fs/isofs/rock.c --- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c +++ b/fs/isofs/rock.c
@@ -30,6 +30,7 @@ struct rock_state { @@ -30,6 +30,7 @@ struct rock_state {
@ -50,3 +50,6 @@ index f488bbae541ac..bb63254ed8486 100644
bh = sb_bread(rs->inode->i_sb, rs->cont_extent); bh = sb_bread(rs->inode->i_sb, rs->cont_extent);
if (bh) { if (bh) {
memcpy(rs->buffer, bh->b_data + rs->cont_offset, memcpy(rs->buffer, bh->b_data + rs->cont_offset,
--
cgit v1.1

View File

@ -1,51 +0,0 @@
From dc4a2f40de419c01b538c87f6bdfc15d574d9f7e Mon Sep 17 00:00:00 2001
From: Sasha Levin <sasha.levin@oracle.com>
Date: Mon, 29 Dec 2014 09:39:01 -0500
Subject: KEYS: close race between key lookup and freeing
commit a3a8784454692dd72e5d5d34dcdab17b4420e74c upstream.
When a key is being garbage collected, it's key->user would get put before
the ->destroy() callback is called, where the key is removed from it's
respective tracking structures.
This leaves a key hanging in a semi-invalid state which leaves a window open
for a different task to try an access key->user. An example is
find_keyring_by_name() which would dereference key->user for a key that is
in the process of being garbage collected (where key->user was freed but
->destroy() wasn't called yet - so it's still present in the linked list).
This would cause either a panic, or corrupt memory.
Fixes CVE-2014-9529.
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
Signed-off-by: David Howells <dhowells@redhat.com>
[bwh: Backported to 3.2: adjust indentation]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
security/keys/gc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/security/keys/gc.c b/security/keys/gc.c
index bf4d8da..2e2395d 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -186,12 +186,12 @@ static noinline void key_gc_unused_key(struct key *key)
if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
atomic_dec(&key->user->nikeys);
- key_user_put(key->user);
-
/* now throw away the key memory */
if (key->type->destroy)
key->type->destroy(key);
+ key_user_put(key->user);
+
kfree(key->description);
#ifdef KEY_DEBUGGING
--
cgit v1.1

View File

@ -1,7 +1,7 @@
From a3a8784454692dd72e5d5d34dcdab17b4420e74c Mon Sep 17 00:00:00 2001 From a3a8784454692dd72e5d5d34dcdab17b4420e74c Mon Sep 17 00:00:00 2001
From: Sasha Levin <sasha.levin@oracle.com> From: Sasha Levin <sasha.levin@oracle.com>
Date: Mon, 29 Dec 2014 09:39:01 -0500 Date: Mon, 29 Dec 2014 09:39:01 -0500
Subject: [PATCH] KEYS: close race between key lookup and freeing Subject: KEYS: close race between key lookup and freeing
When a key is being garbage collected, it's key->user would get put before When a key is being garbage collected, it's key->user would get put before
the ->destroy() callback is called, where the key is removed from it's the ->destroy() callback is called, where the key is removed from it's
@ -24,7 +24,7 @@ Signed-off-by: David Howells <dhowells@redhat.com>
1 file changed, 2 insertions(+), 2 deletions(-) 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/security/keys/gc.c b/security/keys/gc.c diff --git a/security/keys/gc.c b/security/keys/gc.c
index 9609a7f0faea2..c7952375ac532 100644 index 9609a7f..c795237 100644
--- a/security/keys/gc.c --- a/security/keys/gc.c
+++ b/security/keys/gc.c +++ b/security/keys/gc.c
@@ -148,12 +148,12 @@ static noinline void key_gc_unused_keys(struct list_head *keys) @@ -148,12 +148,12 @@ static noinline void key_gc_unused_keys(struct list_head *keys)
@ -42,3 +42,6 @@ index 9609a7f0faea2..c7952375ac532 100644
kfree(key->description); kfree(key->description);
#ifdef KEY_DEBUGGING #ifdef KEY_DEBUGGING
--
cgit v1.1

Some files were not shown because too many files have changed in this diff Show More