Move Linux patches out of repo

This commit is contained in:
Tad 2017-11-28 12:18:40 -05:00
parent 39337477bf
commit 30e0d5e980
1239 changed files with 0 additions and 181244 deletions

View File

@ -1,356 +0,0 @@
NOTE! This copyright does *not* cover user programs that use kernel
services by normal system calls - this is merely considered normal use
of the kernel, and does *not* fall under the heading of "derived work".
Also note that the GPL below is copyrighted by the Free Software
Foundation, but the instance of code that it refers to (the Linux
kernel) is copyrighted by me and others who actually wrote it.
Also note that the only valid version of the GPL as far as the kernel
is concerned is _this_ particular version of the license (ie v2, not
v2.2 or v3.x or whatever), unless explicitly otherwise stated.
Linus Torvalds
----------------------------------------
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that 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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -1,345 +0,0 @@
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

@ -1,345 +0,0 @@
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

@ -1,65 +0,0 @@
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,34 +0,0 @@
From 3e10986d1d698140747fcfc2761ec9cb64c1d582 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <edumazet@google.com>
Date: Mon, 24 Sep 2012 07:00:11 +0000
Subject: net: guard tcp_set_keepalive() to tcp sockets
Its possible to use RAW sockets to get a crash in
tcp_set_keepalive() / sk_reset_timer()
Fix is to make sure socket is a SOCK_STREAM one.
Reported-by: Dave Jones <davej@redhat.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/sock.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/core/sock.c b/net/core/sock.c
index 3057920..a6000fb 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -691,7 +691,8 @@ set_rcvbuf:
case SO_KEEPALIVE:
#ifdef CONFIG_INET
- if (sk->sk_protocol == IPPROTO_TCP)
+ if (sk->sk_protocol == IPPROTO_TCP &&
+ sk->sk_type == SOCK_STREAM)
tcp_set_keepalive(sk, valbool);
#endif
sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool);
--
cgit v1.1

View File

@ -1,73 +0,0 @@
From 20e1db19db5d6b9e4e83021595eab0dc8f107bef Mon Sep 17 00:00:00 2001
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu, 23 Aug 2012 02:09:11 +0000
Subject: netlink: fix possible spoofing from non-root processes
Non-root user-space processes can send Netlink messages to other
processes that are well-known for being subscribed to Netlink
asynchronous notifications. This allows ilegitimate non-root
process to send forged messages to Netlink subscribers.
The userspace process usually verifies the legitimate origin in
two ways:
a) Socket credentials. If UID != 0, then the message comes from
some ilegitimate process and the message needs to be dropped.
b) Netlink portID. In general, portID == 0 means that the origin
of the messages comes from the kernel. Thus, discarding any
message not coming from the kernel.
However, ctnetlink sets the portID in event messages that has
been triggered by some user-space process, eg. conntrack utility.
So other processes subscribed to ctnetlink events, eg. conntrackd,
know that the event was triggered by some user-space action.
Neither of the two ways to discard ilegitimate messages coming
from non-root processes can help for ctnetlink.
This patch adds capability validation in case that dst_pid is set
in netlink_sendmsg(). This approach is aggressive since existing
applications using any Netlink bus to deliver messages between
two user-space processes will break. Note that the exception is
NETLINK_USERSOCK, since it is reserved for netlink-to-netlink
userspace communication.
Still, if anyone wants that his Netlink bus allows netlink-to-netlink
userspace, then they can set NL_NONROOT_SEND. However, by default,
I don't think it makes sense to allow to use NETLINK_ROUTE to
communicate two processes that are sending no matter what information
that is not related to link/neighbouring/routing. They should be using
NETLINK_USERSOCK instead for that.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/netlink/af_netlink.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 1445d73..5270238 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1373,7 +1373,8 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
dst_pid = addr->nl_pid;
dst_group = ffs(addr->nl_groups);
err = -EPERM;
- if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND))
+ if ((dst_group || dst_pid) &&
+ !netlink_capable(sock, NL_NONROOT_SEND))
goto out;
} else {
dst_pid = nlk->dst_pid;
@@ -2147,6 +2148,7 @@ static void __init netlink_add_usersock_entry(void)
rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners);
nl_table[NETLINK_USERSOCK].module = THIS_MODULE;
nl_table[NETLINK_USERSOCK].registered = 1;
+ nl_table[NETLINK_USERSOCK].nl_nonroot = NL_NONROOT_SEND;
netlink_table_ungrab();
}
--
cgit v1.1

View File

@ -1,106 +0,0 @@
From a70b52ec1aaeaf60f4739edb1b422827cb6f3893 Mon Sep 17 00:00:00 2001
From: Linus Torvalds <torvalds@linux-foundation.org>
Date: Mon, 21 May 2012 16:06:20 -0700
Subject: vfs: make AIO use the proper rw_verify_area() area helpers
We had for some reason overlooked the AIO interface, and it didn't use
the proper rw_verify_area() helper function that checks (for example)
mandatory locking on the file, and that the size of the access doesn't
cause us to overflow the provided offset limits etc.
Instead, AIO did just the security_file_permission() thing (that
rw_verify_area() also does) directly.
This fixes it to do all the proper helper functions, which not only
means that now mandatory file locking works with AIO too, we can
actually remove lines of code.
Reported-by: Manish Honap <manish_honap_vit@yahoo.co.in>
Cc: stable@vger.kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
fs/aio.c | 30 ++++++++++++++----------------
1 file changed, 14 insertions(+), 16 deletions(-)
diff --git a/fs/aio.c b/fs/aio.c
index 67a6db3..e7f2fad 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1456,6 +1456,10 @@ static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb, bool compat)
if (ret < 0)
goto out;
+ ret = rw_verify_area(type, kiocb->ki_filp, &kiocb->ki_pos, ret);
+ if (ret < 0)
+ goto out;
+
kiocb->ki_nr_segs = kiocb->ki_nbytes;
kiocb->ki_cur_seg = 0;
/* ki_nbytes/left now reflect bytes instead of segs */
@@ -1467,11 +1471,17 @@ out:
return ret;
}
-static ssize_t aio_setup_single_vector(struct kiocb *kiocb)
+static ssize_t aio_setup_single_vector(int type, struct file * file, struct kiocb *kiocb)
{
+ int bytes;
+
+ bytes = rw_verify_area(type, file, &kiocb->ki_pos, kiocb->ki_left);
+ if (bytes < 0)
+ return bytes;
+
kiocb->ki_iovec = &kiocb->ki_inline_vec;
kiocb->ki_iovec->iov_base = kiocb->ki_buf;
- kiocb->ki_iovec->iov_len = kiocb->ki_left;
+ kiocb->ki_iovec->iov_len = bytes;
kiocb->ki_nr_segs = 1;
kiocb->ki_cur_seg = 0;
return 0;
@@ -1496,10 +1506,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
if (unlikely(!access_ok(VERIFY_WRITE, kiocb->ki_buf,
kiocb->ki_left)))
break;
- ret = security_file_permission(file, MAY_READ);
- if (unlikely(ret))
- break;
- ret = aio_setup_single_vector(kiocb);
+ ret = aio_setup_single_vector(READ, file, kiocb);
if (ret)
break;
ret = -EINVAL;
@@ -1514,10 +1521,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
if (unlikely(!access_ok(VERIFY_READ, kiocb->ki_buf,
kiocb->ki_left)))
break;
- ret = security_file_permission(file, MAY_WRITE);
- if (unlikely(ret))
- break;
- ret = aio_setup_single_vector(kiocb);
+ ret = aio_setup_single_vector(WRITE, file, kiocb);
if (ret)
break;
ret = -EINVAL;
@@ -1528,9 +1532,6 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
ret = -EBADF;
if (unlikely(!(file->f_mode & FMODE_READ)))
break;
- ret = security_file_permission(file, MAY_READ);
- if (unlikely(ret))
- break;
ret = aio_setup_vectored_rw(READ, kiocb, compat);
if (ret)
break;
@@ -1542,9 +1543,6 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
ret = -EBADF;
if (unlikely(!(file->f_mode & FMODE_WRITE)))
break;
- ret = security_file_permission(file, MAY_WRITE);
- if (unlikely(ret))
- break;
ret = aio_setup_vectored_rw(WRITE, kiocb, compat);
if (ret)
break;
--
cgit v1.1

View File

@ -1,31 +0,0 @@
From b35cc8225845112a616e3a2266d2fde5ab13d3ab 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

@ -1,66 +0,0 @@
From 4dc040a0b34890d2adc0d63da6e9bfb4eb791b19 Mon Sep 17 00:00:00 2001
From: Vinod Koul <vinod.koul@linux.intel.com>
Date: Mon, 17 Sep 2012 11:51:25 +0530
Subject: [PATCH] ALSA: compress - move the buffer check
Commit ALSA: compress_core: integer overflow in snd_compr_allocate_buffer()
added a new error check for input params.
this add new routine for input checks and moves buffer overflow check to this
new routine. This allows the error value to be propogated to user space
Signed-off-by: Vinod Koul <vinod.koul@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
sound/core/compress_offload.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index 68fe02c7400a2..bd7f28e892540 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -407,10 +407,6 @@ 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;
@@ -429,6 +425,16 @@ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
return 0;
}
+static int snd_compress_check_input(struct snd_compr_params *params)
+{
+ /* first let's check the buffer parameter's */
+ if (params->buffer.fragment_size == 0 ||
+ params->buffer.fragments > SIZE_MAX / params->buffer.fragment_size)
+ return -EINVAL;
+
+ return 0;
+}
+
static int
snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
{
@@ -447,11 +453,17 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
retval = -EFAULT;
goto out;
}
+
+ retval = snd_compress_check_input(params);
+ if (retval)
+ goto out;
+
retval = snd_compr_allocate_buffer(stream, params);
if (retval) {
retval = -ENOMEM;
goto out;
}
+
retval = stream->ops->set_params(stream, params);
if (retval)
goto out;

View File

@ -1,97 +0,0 @@
From 82981930125abfd39d7c8378a9cfdf5e1be2002b Mon Sep 17 00:00:00 2001
From: Eric Dumazet <edumazet@google.com>
Date: Thu, 26 Apr 2012 20:07:59 +0000
Subject: [PATCH] net: cleanups in sock_setsockopt()
Use min_t()/max_t() macros, reformat two comments, use !!test_bit() to
match !!sock_flag()
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/core/sock.c | 42 +++++++++++++++---------------------------
1 file changed, 15 insertions(+), 27 deletions(-)
diff --git a/net/core/sock.c b/net/core/sock.c
index 0431aaf7473a2..10605d2ec8606 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -577,23 +577,15 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
break;
case SO_SNDBUF:
/* Don't error on this BSD doesn't and if you think
- about it this is right. Otherwise apps have to
- play 'guess the biggest size' games. RCVBUF/SNDBUF
- are treated in BSD as hints */
-
- if (val > sysctl_wmem_max)
- val = sysctl_wmem_max;
+ * about it this is right. Otherwise apps have to
+ * play 'guess the biggest size' games. RCVBUF/SNDBUF
+ * are treated in BSD as hints
+ */
+ val = min_t(u32, val, sysctl_wmem_max);
set_sndbuf:
sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
- if ((val * 2) < SOCK_MIN_SNDBUF)
- sk->sk_sndbuf = SOCK_MIN_SNDBUF;
- else
- sk->sk_sndbuf = val * 2;
-
- /*
- * Wake up sending tasks if we
- * upped the value.
- */
+ sk->sk_sndbuf = max_t(u32, val * 2, SOCK_MIN_SNDBUF);
+ /* Wake up sending tasks if we upped the value. */
sk->sk_write_space(sk);
break;
@@ -606,12 +598,11 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
case SO_RCVBUF:
/* Don't error on this BSD doesn't and if you think
- about it this is right. Otherwise apps have to
- play 'guess the biggest size' games. RCVBUF/SNDBUF
- are treated in BSD as hints */
-
- if (val > sysctl_rmem_max)
- val = sysctl_rmem_max;
+ * about it this is right. Otherwise apps have to
+ * play 'guess the biggest size' games. RCVBUF/SNDBUF
+ * are treated in BSD as hints
+ */
+ val = min_t(u32, val, sysctl_rmem_max);
set_rcvbuf:
sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
/*
@@ -629,10 +620,7 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
* returning the value we actually used in getsockopt
* is the most desirable behavior.
*/
- if ((val * 2) < SOCK_MIN_RCVBUF)
- sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
- else
- sk->sk_rcvbuf = val * 2;
+ sk->sk_rcvbuf = max_t(u32, val * 2, SOCK_MIN_RCVBUF);
break;
case SO_RCVBUFFORCE:
@@ -975,7 +963,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;
case SO_PASSCRED:
- v.val = test_bit(SOCK_PASSCRED, &sock->flags) ? 1 : 0;
+ v.val = !!test_bit(SOCK_PASSCRED, &sock->flags);
break;
case SO_PEERCRED:
@@ -1010,7 +998,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
break;
case SO_PASSSEC:
- v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0;
+ v.val = !!test_bit(SOCK_PASSSEC, &sock->flags);
break;
case SO_PEERSEC:

View File

@ -1,48 +0,0 @@
From 016a3592cc34fa349235b5a8b48af5cece2cbfeb Mon Sep 17 00:00:00 2001
From: Theodore Ts'o <tytso@mit.edu>
Date: Thu, 27 Dec 2012 01:42:50 -0500
Subject: [PATCH] ext4: avoid hang when mounting non-journal filesystems with
orphan list
commit 0e9a9a1ad619e7e987815d20262d36a2f95717ca upstream.
When trying to mount a file system which does not contain a journal,
but which does have a orphan list containing an inode which needs to
be truncated, the mount call with hang forever in
ext4_orphan_cleanup() because ext4_orphan_del() will return
immediately without removing the inode from the orphan list, leading
to an uninterruptible loop in kernel code which will busy out one of
the CPU's on the system.
This can be trivially reproduced by trying to mount the file system
found in tests/f_orphan_extents_inode/image.gz from the e2fsprogs
source tree. If a malicious user were to put this on a USB stick, and
mount it on a Linux desktop which has automatic mounts enabled, this
could be considered a potential denial of service attack. (Not a big
deal in practice, but professional paranoids worry about such things,
and have even been known to allocate CVE numbers for such problems.)
-js: This is a fix for CVE-2013-2015.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Zheng Liu <wenqing.lz@taobao.com>
Acked-by: Jan Kara <jack@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/ext4/namei.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 9fb3fae4898a..54ad9a54cd89 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2054,7 +2054,8 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
int err = 0;
/* ext4_handle_valid() assumes a valid handle_t pointer */
- if (handle && !ext4_handle_valid(handle))
+ if (handle && !ext4_handle_valid(handle) &&
+ !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS))
return 0;
mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock);

View File

@ -1,52 +0,0 @@
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

@ -1,64 +0,0 @@
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

@ -1,56 +0,0 @@
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

@ -1,32 +0,0 @@
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

@ -1,32 +0,0 @@
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

@ -1,141 +0,0 @@
From a5a6cf8c405e826ff7ed1308dde72560c0ed4854 Mon Sep 17 00:00:00 2001
From: willy tarreau <w@1wt.eu>
Date: Sun, 10 Jan 2016 07:54:56 +0100
Subject: unix: properly account for FDs passed over unix sockets
commit 712f4aad406bb1ed67f3f98d04c044191f0ff593 upstream.
It is possible for a process to allocate and accumulate far more FDs than
the process' limit by sending them over a unix socket then closing them
to keep the process' fd count low.
This change addresses this problem by keeping track of the number of FDs
in flight per user and preventing non-privileged processes from having
more FDs in flight than their configured FD limit.
Reported-by: socketpair@gmail.com
Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Mitigates: CVE-2013-4312 (Linux 2.0+)
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: David S. Miller <davem@davemloft.net>
[carnil: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
include/linux/sched.h | 1 +
net/unix/af_unix.c | 24 ++++++++++++++++++++----
net/unix/garbage.c | 14 ++++++++++----
3 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9b9ac29..2bffa8a 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -709,6 +709,7 @@ struct user_struct {
unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */
#endif
unsigned long locked_shm; /* How many pages of mlocked shm ? */
+ unsigned long unix_inflight; /* How many files in flight in unix sockets */
#ifdef CONFIG_KEYS
struct key *uid_keyring; /* UID specific keyring */
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 6cb363d..6798b3c 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1472,6 +1472,21 @@ static void unix_destruct_scm(struct sk_buff *skb)
sock_wfree(skb);
}
+/*
+ * The "user->unix_inflight" variable is protected by the garbage
+ * collection lock, and we just read it locklessly here. If you go
+ * over the limit, there might be a tiny race in actually noticing
+ * it across threads. Tough.
+ */
+static inline bool too_many_unix_fds(struct task_struct *p)
+{
+ struct user_struct *user = current_user();
+
+ if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE)))
+ return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
+ return false;
+}
+
#define MAX_RECURSION_LEVEL 4
static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
@@ -1480,6 +1495,9 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
unsigned char max_level = 0;
int unix_sock_count = 0;
+ if (too_many_unix_fds(current))
+ return -ETOOMANYREFS;
+
for (i = scm->fp->count - 1; i >= 0; i--) {
struct sock *sk = unix_get_socket(scm->fp->fp[i]);
@@ -1501,10 +1519,8 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
if (!UNIXCB(skb).fp)
return -ENOMEM;
- if (unix_sock_count) {
- for (i = scm->fp->count - 1; i >= 0; i--)
- unix_inflight(scm->fp->fp[i]);
- }
+ for (i = scm->fp->count - 1; i >= 0; i--)
+ unix_inflight(scm->fp->fp[i]);
return max_level;
}
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 00d3e56..fd1a840 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -125,9 +125,11 @@ struct sock *unix_get_socket(struct file *filp)
void unix_inflight(struct file *fp)
{
struct sock *s = unix_get_socket(fp);
+
+ spin_lock(&unix_gc_lock);
+
if (s) {
struct unix_sock *u = unix_sk(s);
- spin_lock(&unix_gc_lock);
if (atomic_long_inc_return(&u->inflight) == 1) {
BUG_ON(!list_empty(&u->link));
list_add_tail(&u->link, &gc_inflight_list);
@@ -135,22 +137,26 @@ void unix_inflight(struct file *fp)
BUG_ON(list_empty(&u->link));
}
unix_tot_inflight++;
- spin_unlock(&unix_gc_lock);
}
+ fp->f_cred->user->unix_inflight++;
+ spin_unlock(&unix_gc_lock);
}
void unix_notinflight(struct file *fp)
{
struct sock *s = unix_get_socket(fp);
+
+ spin_lock(&unix_gc_lock);
+
if (s) {
struct unix_sock *u = unix_sk(s);
- spin_lock(&unix_gc_lock);
BUG_ON(list_empty(&u->link));
if (atomic_long_dec_and_test(&u->inflight))
list_del_init(&u->link);
unix_tot_inflight--;
- spin_unlock(&unix_gc_lock);
}
+ fp->f_cred->user->unix_inflight--;
+ spin_unlock(&unix_gc_lock);
}
static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
--
cgit v1.1

View File

@ -1,162 +0,0 @@
From 5ea820046ee399214221c0bb817eb35d304c9604 Mon Sep 17 00:00:00 2001
From: Hannes Frederic Sowa <hannes@stressinduktion.org>
Date: Wed, 3 Feb 2016 02:11:03 +0100
Subject: unix: correctly track in-flight fds in sending process user_struct
commit 415e3d3e90ce9e18727e8843ae343eda5a58fad6 upstream.
The commit referenced in the Fixes tag incorrectly accounted the number
of in-flight fds over a unix domain socket to the original opener
of the file-descriptor. This allows another process to arbitrary
deplete the original file-openers resource limit for the maximum of
open files. Instead the sending processes and its struct cred should
be credited.
To do so, we add a reference counted struct user_struct pointer to the
scm_fp_list and use it to account for the number of inflight unix fds.
Fixes: 712f4aad406bb1 ("unix: properly account for FDs passed over unix sockets")
Reported-by: David Herrmann <dh.herrmann@gmail.com>
Cc: David Herrmann <dh.herrmann@gmail.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
include/net/af_unix.h | 4 ++--
include/net/scm.h | 1 +
net/core/scm.c | 7 +++++++
net/unix/af_unix.c | 4 ++--
net/unix/garbage.c | 8 ++++----
5 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index f4842f7..a69bfee 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -6,8 +6,8 @@
#include <linux/mutex.h>
#include <net/sock.h>
-extern void unix_inflight(struct file *fp);
-extern void unix_notinflight(struct file *fp);
+extern void unix_inflight(struct user_struct *user, struct file *fp);
+extern void unix_notinflight(struct user_struct *user, struct file *fp);
extern void unix_gc(void);
extern void wait_for_unix_gc(void);
extern struct sock *unix_get_socket(struct file *filp);
diff --git a/include/net/scm.h b/include/net/scm.h
index 5da0a7b..9822a68 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -16,6 +16,7 @@ struct scm_fp_list {
struct list_head list;
short count;
short max;
+ struct user_struct *user;
struct file *fp[SCM_MAX_FD];
};
diff --git a/net/core/scm.c b/net/core/scm.c
index 51b4d52..9adabed 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -80,6 +80,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
*fplp = fpl;
fpl->count = 0;
fpl->max = SCM_MAX_FD;
+ fpl->user = NULL;
}
fpp = &fpl->fp[fpl->count];
@@ -100,6 +101,10 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
*fpp++ = file;
fpl->count++;
}
+
+ if (!fpl->user)
+ fpl->user = get_uid(current_user());
+
return num;
}
@@ -124,6 +129,7 @@ void __scm_destroy(struct scm_cookie *scm)
list_del(&fpl->list);
for (i=fpl->count-1; i>=0; i--)
fput(fpl->fp[i]);
+ free_uid(fpl->user);
kfree(fpl);
}
@@ -342,6 +348,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
for (i = 0; i < fpl->count; i++)
get_file(fpl->fp[i]);
new_fpl->max = new_fpl->count;
+ new_fpl->user = get_uid(fpl->user);
}
return new_fpl;
}
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 6798b3c..390e079 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1454,7 +1454,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
UNIXCB(skb).fp = NULL;
for (i = scm->fp->count-1; i >= 0; i--)
- unix_notinflight(scm->fp->fp[i]);
+ unix_notinflight(scm->fp->user, scm->fp->fp[i]);
}
static void unix_destruct_scm(struct sk_buff *skb)
@@ -1520,7 +1520,7 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
return -ENOMEM;
for (i = scm->fp->count - 1; i >= 0; i--)
- unix_inflight(scm->fp->fp[i]);
+ unix_inflight(scm->fp->user, scm->fp->fp[i]);
return max_level;
}
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index fd1a840..33a21260 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -122,7 +122,7 @@ struct sock *unix_get_socket(struct file *filp)
* descriptor if it is for an AF_UNIX socket.
*/
-void unix_inflight(struct file *fp)
+void unix_inflight(struct user_struct *user, struct file *fp)
{
struct sock *s = unix_get_socket(fp);
@@ -138,11 +138,11 @@ void unix_inflight(struct file *fp)
}
unix_tot_inflight++;
}
- fp->f_cred->user->unix_inflight++;
+ user->unix_inflight++;
spin_unlock(&unix_gc_lock);
}
-void unix_notinflight(struct file *fp)
+void unix_notinflight(struct user_struct *user, struct file *fp)
{
struct sock *s = unix_get_socket(fp);
@@ -155,7 +155,7 @@ void unix_notinflight(struct file *fp)
list_del_init(&u->link);
unix_tot_inflight--;
}
- fp->f_cred->user->unix_inflight--;
+ user->unix_inflight--;
spin_unlock(&unix_gc_lock);
}
--
cgit v1.1

View File

@ -1,140 +0,0 @@
From 712f4aad406bb1ed67f3f98d04c044191f0ff593 Mon Sep 17 00:00:00 2001
From: willy tarreau <w@1wt.eu>
Date: Sun, 10 Jan 2016 07:54:56 +0100
Subject: unix: properly account for FDs passed over unix sockets
It is possible for a process to allocate and accumulate far more FDs than
the process' limit by sending them over a unix socket then closing them
to keep the process' fd count low.
This change addresses this problem by keeping track of the number of FDs
in flight per user and preventing non-privileged processes from having
more FDs in flight than their configured FD limit.
Reported-by: socketpair@gmail.com
Reported-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Mitigates: CVE-2013-4312 (Linux 2.0+)
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/linux/sched.h | 1 +
net/unix/af_unix.c | 24 ++++++++++++++++++++----
net/unix/garbage.c | 13 ++++++++-----
3 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index edad7a4..fbf25f1 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -830,6 +830,7 @@ struct user_struct {
unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */
#endif
unsigned long locked_shm; /* How many pages of mlocked shm ? */
+ unsigned long unix_inflight; /* How many files in flight in unix sockets */
#ifdef CONFIG_KEYS
struct key *uid_keyring; /* UID specific keyring */
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index ef05cd9..e3f85bc 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1513,6 +1513,21 @@ static void unix_destruct_scm(struct sk_buff *skb)
sock_wfree(skb);
}
+/*
+ * The "user->unix_inflight" variable is protected by the garbage
+ * collection lock, and we just read it locklessly here. If you go
+ * over the limit, there might be a tiny race in actually noticing
+ * it across threads. Tough.
+ */
+static inline bool too_many_unix_fds(struct task_struct *p)
+{
+ struct user_struct *user = current_user();
+
+ if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE)))
+ return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
+ return false;
+}
+
#define MAX_RECURSION_LEVEL 4
static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
@@ -1521,6 +1536,9 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
unsigned char max_level = 0;
int unix_sock_count = 0;
+ if (too_many_unix_fds(current))
+ return -ETOOMANYREFS;
+
for (i = scm->fp->count - 1; i >= 0; i--) {
struct sock *sk = unix_get_socket(scm->fp->fp[i]);
@@ -1542,10 +1560,8 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
if (!UNIXCB(skb).fp)
return -ENOMEM;
- if (unix_sock_count) {
- for (i = scm->fp->count - 1; i >= 0; i--)
- unix_inflight(scm->fp->fp[i]);
- }
+ for (i = scm->fp->count - 1; i >= 0; i--)
+ unix_inflight(scm->fp->fp[i]);
return max_level;
}
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index a73a226..8fcdc22 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -120,11 +120,11 @@ void unix_inflight(struct file *fp)
{
struct sock *s = unix_get_socket(fp);
+ spin_lock(&unix_gc_lock);
+
if (s) {
struct unix_sock *u = unix_sk(s);
- spin_lock(&unix_gc_lock);
-
if (atomic_long_inc_return(&u->inflight) == 1) {
BUG_ON(!list_empty(&u->link));
list_add_tail(&u->link, &gc_inflight_list);
@@ -132,25 +132,28 @@ void unix_inflight(struct file *fp)
BUG_ON(list_empty(&u->link));
}
unix_tot_inflight++;
- spin_unlock(&unix_gc_lock);
}
+ fp->f_cred->user->unix_inflight++;
+ spin_unlock(&unix_gc_lock);
}
void unix_notinflight(struct file *fp)
{
struct sock *s = unix_get_socket(fp);
+ spin_lock(&unix_gc_lock);
+
if (s) {
struct unix_sock *u = unix_sk(s);
- spin_lock(&unix_gc_lock);
BUG_ON(list_empty(&u->link));
if (atomic_long_dec_and_test(&u->inflight))
list_del_init(&u->link);
unix_tot_inflight--;
- spin_unlock(&unix_gc_lock);
}
+ fp->f_cred->user->unix_inflight--;
+ spin_unlock(&unix_gc_lock);
}
static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
--
cgit v1.1

View File

@ -1,158 +0,0 @@
From 415e3d3e90ce9e18727e8843ae343eda5a58fad6 Mon Sep 17 00:00:00 2001
From: Hannes Frederic Sowa <hannes@stressinduktion.org>
Date: Wed, 3 Feb 2016 02:11:03 +0100
Subject: unix: correctly track in-flight fds in sending process user_struct
The commit referenced in the Fixes tag incorrectly accounted the number
of in-flight fds over a unix domain socket to the original opener
of the file-descriptor. This allows another process to arbitrary
deplete the original file-openers resource limit for the maximum of
open files. Instead the sending processes and its struct cred should
be credited.
To do so, we add a reference counted struct user_struct pointer to the
scm_fp_list and use it to account for the number of inflight unix fds.
Fixes: 712f4aad406bb1 ("unix: properly account for FDs passed over unix sockets")
Reported-by: David Herrmann <dh.herrmann@gmail.com>
Cc: David Herrmann <dh.herrmann@gmail.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/net/af_unix.h | 4 ++--
include/net/scm.h | 1 +
net/core/scm.c | 7 +++++++
net/unix/af_unix.c | 4 ++--
net/unix/garbage.c | 8 ++++----
5 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 2a91a05..9b4c418 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -6,8 +6,8 @@
#include <linux/mutex.h>
#include <net/sock.h>
-void unix_inflight(struct file *fp);
-void unix_notinflight(struct file *fp);
+void unix_inflight(struct user_struct *user, struct file *fp);
+void unix_notinflight(struct user_struct *user, struct file *fp);
void unix_gc(void);
void wait_for_unix_gc(void);
struct sock *unix_get_socket(struct file *filp);
diff --git a/include/net/scm.h b/include/net/scm.h
index 262532d..59fa93c 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -21,6 +21,7 @@ struct scm_creds {
struct scm_fp_list {
short count;
short max;
+ struct user_struct *user;
struct file *fp[SCM_MAX_FD];
};
diff --git a/net/core/scm.c b/net/core/scm.c
index 14596fb..2696aef 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -87,6 +87,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
*fplp = fpl;
fpl->count = 0;
fpl->max = SCM_MAX_FD;
+ fpl->user = NULL;
}
fpp = &fpl->fp[fpl->count];
@@ -107,6 +108,10 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
*fpp++ = file;
fpl->count++;
}
+
+ if (!fpl->user)
+ fpl->user = get_uid(current_user());
+
return num;
}
@@ -119,6 +124,7 @@ void __scm_destroy(struct scm_cookie *scm)
scm->fp = NULL;
for (i=fpl->count-1; i>=0; i--)
fput(fpl->fp[i]);
+ free_uid(fpl->user);
kfree(fpl);
}
}
@@ -336,6 +342,7 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
for (i = 0; i < fpl->count; i++)
get_file(fpl->fp[i]);
new_fpl->max = new_fpl->count;
+ new_fpl->user = get_uid(fpl->user);
}
return new_fpl;
}
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 49d5093..29be035 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1496,7 +1496,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
UNIXCB(skb).fp = NULL;
for (i = scm->fp->count-1; i >= 0; i--)
- unix_notinflight(scm->fp->fp[i]);
+ unix_notinflight(scm->fp->user, scm->fp->fp[i]);
}
static void unix_destruct_scm(struct sk_buff *skb)
@@ -1561,7 +1561,7 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
return -ENOMEM;
for (i = scm->fp->count - 1; i >= 0; i--)
- unix_inflight(scm->fp->fp[i]);
+ unix_inflight(scm->fp->user, scm->fp->fp[i]);
return max_level;
}
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 8fcdc22..6a0d485 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -116,7 +116,7 @@ struct sock *unix_get_socket(struct file *filp)
* descriptor if it is for an AF_UNIX socket.
*/
-void unix_inflight(struct file *fp)
+void unix_inflight(struct user_struct *user, struct file *fp)
{
struct sock *s = unix_get_socket(fp);
@@ -133,11 +133,11 @@ void unix_inflight(struct file *fp)
}
unix_tot_inflight++;
}
- fp->f_cred->user->unix_inflight++;
+ user->unix_inflight++;
spin_unlock(&unix_gc_lock);
}
-void unix_notinflight(struct file *fp)
+void unix_notinflight(struct user_struct *user, struct file *fp)
{
struct sock *s = unix_get_socket(fp);
@@ -152,7 +152,7 @@ void unix_notinflight(struct file *fp)
list_del_init(&u->link);
unix_tot_inflight--;
}
- fp->f_cred->user->unix_inflight--;
+ user->unix_inflight--;
spin_unlock(&unix_gc_lock);
}
--
cgit v1.1

View File

@ -1,125 +0,0 @@
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

@ -1,101 +0,0 @@
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

@ -1,150 +0,0 @@
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

@ -1,34 +0,0 @@
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

@ -1,33 +0,0 @@
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

@ -1,50 +0,0 @@
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

@ -1,300 +0,0 @@
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

@ -1,300 +0,0 @@
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

@ -1,39 +0,0 @@
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

@ -1,67 +0,0 @@
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

@ -1,253 +0,0 @@
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

@ -1,320 +0,0 @@
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

@ -1,334 +0,0 @@
From 8a292b04183e82d59721ab0893e4216010aa3db9 Mon Sep 17 00:00:00 2001
From: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Date: Fri, 20 Nov 2015 22:07:23 +0000
Subject: [PATCH] BACKPORT: 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>
Bug: 29119002
(cherry picked from commit 7d267278a9ece963d77eefec61630223fce08c6c)
Signed-off-by: Aarthi Thiruvengadam <athiru@google.com>
Change-Id: Ia374ee061195088f8c777940baa75cedbe897f4e
---
include/net/af_unix.h | 1 +
net/unix/af_unix.c | 183 ++++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 165 insertions(+), 19 deletions(-)
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index dbdfd2b0f3b3d..9120783132e71 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -62,6 +62,7 @@ struct unix_sock {
#define UNIX_GC_CANDIDATE 0
#define UNIX_GC_MAYBE_CYCLE 1
struct socket_wq peer_wq;
+ wait_queue_t peer_wake;
};
#define unix_sk(__sk) ((struct unix_sock *)__sk)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 924108f17b9a6..5e6323792a5e0 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -314,6 +314,118 @@ static struct sock *unix_find_socket_byinode(struct inode *i)
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 inline int unix_writable(struct sock *sk)
{
return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
@@ -418,6 +530,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;
}
@@ -651,6 +765,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock)
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)
@@ -1020,6 +1135,8 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
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)
@@ -1459,6 +1576,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
struct scm_cookie tmp_scm;
int max_level;
int data_len = 0;
+ int sk_locked;
if (NULL == siocb->scm)
siocb->scm = &tmp_scm;
@@ -1535,12 +1653,14 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
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
@@ -1548,10 +1668,14 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
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);
@@ -1577,21 +1701,38 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
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);
@@ -1605,6 +1746,8 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
return len;
out_unlock:
+ if (sk_locked)
+ unix_state_unlock(sk);
unix_state_unlock(other);
out_free:
kfree_skb(skb);
@@ -2243,14 +2386,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)

View File

@ -1,56 +0,0 @@
From 5bed19c9f463f9078063363779548c50aea271a0 Mon Sep 17 00:00:00 2001
From: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Date: Thu, 11 Feb 2016 19:37:27 +0000
Subject: [PATCH] UPSTREAM: af_unix: Guard against other == sk in
unix_dgram_sendmsg
(cherry picked from commit a5527dda344fff0514b7989ef7a755729769daa1)
The unix_dgram_sendmsg routine use the following test
if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) {
to determine if sk and other are in an n:1 association (either
established via connect or by using sendto to send messages to an
unrelated socket identified by address). This isn't correct as the
specified address could have been bound to the sending socket itself or
because this socket could have been connected to itself by the time of
the unix_peer_get but disconnected before the unix_state_lock(other). In
both cases, the if-block would be entered despite other == sk which
might either block the sender unintentionally or lead to trying to unlock
the same spin lock twice for a non-blocking send. Add a other != sk
check to guard against this.
Fixes: 7d267278a9ec ("unix: avoid use-after-free in ep_remove_wait_queue")
Reported-By: Philipp Hahn <pmhahn@pmhahn.de>
Signed-off-by: Rainer Weikusat <rweikusat@mobileactivedefense.com>
Tested-by: Philipp Hahn <pmhahn@pmhahn.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Fixes: Change-Id: Ia374ee061195088f8c777940baa75cedbe897f4e
("UPSTREAM: unix: avoid use-after-free in ep_remove_wait_queue")
Change-Id: I4ebef6a390df3487903b166b837e34c653e01cb2
Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
Bug: 29119002
---
net/unix/af_unix.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 5e6323792a5e0..204bee47aa10c 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1701,7 +1701,12 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
goto out_unlock;
}
- if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) {
+ /* other == sk && unix_peer(other) != sk if
+ * - unix_peer(sk) == NULL, destination address bound to sk
+ * - unix_peer(sk) == sk by time of get but disconnected before lock
+ */
+ if (other != sk &&
+ unlikely(unix_peer(other) != sk && unix_recvq_full(other))) {
if (timeo) {
timeo = unix_wait_for_peer(other, timeo);

View File

@ -1,84 +0,0 @@
From 1e5099713cefc67aa562f6d8fe43444f41baf52d Mon Sep 17 00:00:00 2001
From: Peter Hurley <peter@hurleysoftware.com>
Date: Sat, 3 May 2014 14:04:59 +0200
Subject: n_tty: Fix n_tty_write crash when echoing in raw mode
commit 4291086b1f081b869c6d79e5b7441633dc3ace00 upstream.
The tty atomic_write_lock does not provide an exclusion guarantee for
the tty driver if the termios settings are LECHO & !OPOST. And since
it is unexpected and not allowed to call TTY buffer helpers like
tty_insert_flip_string concurrently, this may lead to crashes when
concurrect writers call pty_write. In that case the following two
writers:
* the ECHOing from a workqueue and
* pty_write from the process
race and can overflow the corresponding TTY buffer like follows.
If we look into tty_insert_flip_string_fixed_flag, there is:
int space = __tty_buffer_request_room(port, goal, flags);
struct tty_buffer *tb = port->buf.tail;
...
memcpy(char_buf_ptr(tb, tb->used), chars, space);
...
tb->used += space;
so the race of the two can result in something like this:
A B
__tty_buffer_request_room
__tty_buffer_request_room
memcpy(buf(tb->used), ...)
tb->used += space;
memcpy(buf(tb->used), ...) ->BOOM
B's memcpy is past the tty_buffer due to the previous A's tb->used
increment.
Since the N_TTY line discipline input processing can output
concurrently with a tty write, obtain the N_TTY ldisc output_lock to
serialize echo output with normal tty writes. This ensures the tty
buffer helper tty_insert_flip_string is not called concurrently and
everything is fine.
Note that this is nicely reproducible by an ordinary user using
forkpty and some setup around that (raw termios + ECHO). And it is
present in kernels at least after commit
d945cb9cce20ac7143c2de8d88b187f62db99bdc (pty: Rework the pty layer to
use the normal buffering logic) in 2.6.31-rc3.
js: add more info to the commit log
js: switch to bool
js: lock unconditionally
js: lock only the tty->ops->write call
References: CVE-2014-0196
Reported-and-tested-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[bwh: Backported to 3.2: output_lock is a member of struct tty_struct]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
drivers/tty/n_tty.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 0f8a785..bac83d8 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1997,7 +1997,9 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
tty->ops->flush_chars(tty);
} else {
while (nr > 0) {
+ mutex_lock(&tty->output_lock);
c = tty->ops->write(tty, b, nr);
+ mutex_unlock(&tty->output_lock);
if (c < 0) {
retval = c;
goto break_out;
--
cgit v1.1

View File

@ -1,83 +0,0 @@
From 9aabfc9e7775abbbcf534cdecccc4f12ee423b27 Mon Sep 17 00:00:00 2001
From: Peter Hurley <peter@hurleysoftware.com>
Date: Tue, 13 May 2014 14:36:46 -0700
Subject: n_tty: Fix n_tty_write crash when echoing in raw mode
The tty atomic_write_lock does not provide an exclusion guarantee for
the tty driver if the termios settings are LECHO & !OPOST. And since
it is unexpected and not allowed to call TTY buffer helpers like
tty_insert_flip_string concurrently, this may lead to crashes when
concurrect writers call pty_write. In that case the following two
writers:
* the ECHOing from a workqueue and
* pty_write from the process
race and can overflow the corresponding TTY buffer like follows.
If we look into tty_insert_flip_string_fixed_flag, there is:
int space = __tty_buffer_request_room(port, goal, flags);
struct tty_buffer *tb = port->buf.tail;
...
memcpy(char_buf_ptr(tb, tb->used), chars, space);
...
tb->used += space;
so the race of the two can result in something like this:
A B
__tty_buffer_request_room
__tty_buffer_request_room
memcpy(buf(tb->used), ...)
tb->used += space;
memcpy(buf(tb->used), ...) ->BOOM
B's memcpy is past the tty_buffer due to the previous A's tb->used
increment.
Since the N_TTY line discipline input processing can output
concurrently with a tty write, obtain the N_TTY ldisc output_lock to
serialize echo output with normal tty writes. This ensures the tty
buffer helper tty_insert_flip_string is not called concurrently and
everything is fine.
Note that this is nicely reproducible by an ordinary user using
forkpty and some setup around that (raw termios + ECHO). And it is
present in kernels at least after commit
d945cb9cce20ac7143c2de8d88b187f62db99bdc (pty: Rework the pty layer to
use the normal buffering logic) in 2.6.31-rc3.
js: add more info to the commit log
js: switch to bool
js: lock unconditionally
js: lock only the tty->ops->write call
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Change-Id: I9e235db6ec2bb950f26bd8a23f6145dab5dc0a15
Git-commit: 4291086b1f081b869c6d79e5b7441633dc3ace00
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Signed-off-by: Avijit Kanti Das <avijitnsec@codeaurora.org>
[rsiddoji@codeaurora.org: resolve trivial merge conflicts]
Signed-off-by: Ravi Kumar S <rsiddoji@codeaurora.org>
---
drivers/tty/n_tty.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 8eb5573..54c46c8 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1998,8 +1998,11 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
if (tty->ops->flush_chars)
tty->ops->flush_chars(tty);
} else {
+
while (nr > 0) {
+ mutex_lock(&tty->output_lock);
c = tty->ops->write(tty, b, nr);
+ mutex_unlock(&tty->output_lock);
if (c < 0) {
retval = c;
goto break_out;
--
cgit v1.1

View File

@ -1,80 +0,0 @@
From 4291086b1f081b869c6d79e5b7441633dc3ace00 Mon Sep 17 00:00:00 2001
From: Peter Hurley <peter@hurleysoftware.com>
Date: Sat, 3 May 2014 14:04:59 +0200
Subject: [PATCH] n_tty: Fix n_tty_write crash when echoing in raw mode
The tty atomic_write_lock does not provide an exclusion guarantee for
the tty driver if the termios settings are LECHO & !OPOST. And since
it is unexpected and not allowed to call TTY buffer helpers like
tty_insert_flip_string concurrently, this may lead to crashes when
concurrect writers call pty_write. In that case the following two
writers:
* the ECHOing from a workqueue and
* pty_write from the process
race and can overflow the corresponding TTY buffer like follows.
If we look into tty_insert_flip_string_fixed_flag, there is:
int space = __tty_buffer_request_room(port, goal, flags);
struct tty_buffer *tb = port->buf.tail;
...
memcpy(char_buf_ptr(tb, tb->used), chars, space);
...
tb->used += space;
so the race of the two can result in something like this:
A B
__tty_buffer_request_room
__tty_buffer_request_room
memcpy(buf(tb->used), ...)
tb->used += space;
memcpy(buf(tb->used), ...) ->BOOM
B's memcpy is past the tty_buffer due to the previous A's tb->used
increment.
Since the N_TTY line discipline input processing can output
concurrently with a tty write, obtain the N_TTY ldisc output_lock to
serialize echo output with normal tty writes. This ensures the tty
buffer helper tty_insert_flip_string is not called concurrently and
everything is fine.
Note that this is nicely reproducible by an ordinary user using
forkpty and some setup around that (raw termios + ECHO). And it is
present in kernels at least after commit
d945cb9cce20ac7143c2de8d88b187f62db99bdc (pty: Rework the pty layer to
use the normal buffering logic) in 2.6.31-rc3.
js: add more info to the commit log
js: switch to bool
js: lock unconditionally
js: lock only the tty->ops->write call
References: CVE-2014-0196
Reported-and-tested-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
drivers/tty/n_tty.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 41fe8a047d373..fe9d129c87351 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -2353,8 +2353,12 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
if (tty->ops->flush_chars)
tty->ops->flush_chars(tty);
} else {
+ struct n_tty_data *ldata = tty->disc_data;
+
while (nr > 0) {
+ mutex_lock(&ldata->output_lock);
c = tty->ops->write(tty, b, nr);
+ mutex_unlock(&ldata->output_lock);
if (c < 0) {
retval = c;
goto break_out;

View File

@ -1,45 +0,0 @@
From d36db46c2cba973557eb6138d22210c4e0cf17d6 Mon Sep 17 00:00:00 2001
From: Benjamin LaHaise <bcrl@kvack.org>
Date: Tue, 24 Jun 2014 13:32:51 -0400
Subject: aio: fix kernel memory disclosure in io_getevents() introduced in
v3.10
commit edfbbf388f293d70bf4b7c0bc38774d05e6f711a upstream.
A kernel memory disclosure was introduced in aio_read_events_ring() in v3.10
by commit a31ad380bed817aa25f8830ad23e1a0480fef797. The changes made to
aio_read_events_ring() failed to correctly limit the index into
ctx->ring_pages[], allowing an attacked to cause the subsequent kmap() of
an arbitrary page with a copy_to_user() to copy the contents into userspace.
This vulnerability has been assigned CVE-2014-0206. Thanks to Mateusz and
Petr for disclosing this issue.
This patch applies to v3.12+. A separate backport is needed for 3.10/3.11.
[jmoyer@redhat.com: backported to 3.10]
Signed-off-by: Benjamin LaHaise <bcrl@kvack.org>
Signed-off-by: Jeff Moyer <jmoyer@redhat.com>
Cc: Mateusz Guzik <mguzik@redhat.com>
Cc: Petr Matousek <pmatouse@redhat.com>
Cc: Kent Overstreet <kmo@daterainc.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/aio.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/aio.c b/fs/aio.c
index 8d2c997..ded94c4 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -717,6 +717,8 @@ static long aio_read_events_ring(struct kioctx *ctx,
if (head == ctx->tail)
goto out;
+ head %= ctx->nr_events;
+
while (ret < nr) {
long avail;
struct io_event *ev;
--
cgit v1.1

View File

@ -1,181 +0,0 @@
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

@ -1,31 +0,0 @@
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

@ -1,35 +0,0 @@
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

@ -1,31 +0,0 @@
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,33 +0,0 @@
From e6a623460e5fc960ac3ee9f946d3106233fd28d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Salva=20Peir=C3=B3?= <speiro@ai2.upv.es>
Date: Wed, 30 Apr 2014 19:48:02 +0200
Subject: [media] media-device: fix infoleak in ioctl media_enum_entities()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This fixes CVE-2014-1739.
Signed-off-by: Salva Peiró <speiro@ai2.upv.es>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: stable@vger.kernel.org
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
---
drivers/media/media-device.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index d5a7a13..703560f 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -93,6 +93,7 @@ static long media_device_enum_entities(struct media_device *mdev,
struct media_entity *ent;
struct media_entity_desc u_ent;
+ memset(&u_ent, 0, sizeof(u_ent));
if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id)))
return -EFAULT;
--
cgit v1.1

View File

@ -1,64 +0,0 @@
From 5b866eaa34e4ddc312c927030fde5f6a6184ddc5 Mon Sep 17 00:00:00 2001
From: Daniel Borkmann <dborkman@redhat.com>
Date: Mon, 6 Jan 2014 00:57:54 +0100
Subject: netfilter: nf_conntrack_dccp: fix skb_header_pointer API usages
commit b22f5126a24b3b2f15448c3f2a254fc10cbc2b92 upstream.
Some occurences in the netfilter tree use skb_header_pointer() in
the following way ...
struct dccp_hdr _dh, *dh;
...
skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
... where dh itself is a pointer that is being passed as the copy
buffer. Instead, we need to use &_dh as the forth argument so that
we're copying the data into an actual buffer that sits on the stack.
Currently, we probably could overwrite memory on the stack (e.g.
with a possibly mal-formed DCCP packet), but unintentionally, as
we only want the buffer to be placed into _dh variable.
Fixes: 2bc780499aa3 ("[NETFILTER]: nf_conntrack: add DCCP protocol support")
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
net/netfilter/nf_conntrack_proto_dccp.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index 2e664a6..8aa94ee 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -431,7 +431,7 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
const char *msg;
u_int8_t state;
- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
+ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh);
BUG_ON(dh == NULL);
state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE];
@@ -483,7 +483,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
u_int8_t type, old_state, new_state;
enum ct_dccp_roles role;
- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
+ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh);
BUG_ON(dh == NULL);
type = dh->dccph_type;
@@ -575,7 +575,7 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl,
unsigned int cscov;
const char *msg;
- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
+ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh);
if (dh == NULL) {
msg = "nf_ct_dccp: short packet ";
goto out_invalid;
--
cgit v1.1

View File

@ -1,59 +0,0 @@
From b22f5126a24b3b2f15448c3f2a254fc10cbc2b92 Mon Sep 17 00:00:00 2001
From: Daniel Borkmann <dborkman@redhat.com>
Date: Mon, 6 Jan 2014 00:57:54 +0100
Subject: [PATCH] netfilter: nf_conntrack_dccp: fix skb_header_pointer API
usages
Some occurences in the netfilter tree use skb_header_pointer() in
the following way ...
struct dccp_hdr _dh, *dh;
...
skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
... where dh itself is a pointer that is being passed as the copy
buffer. Instead, we need to use &_dh as the forth argument so that
we're copying the data into an actual buffer that sits on the stack.
Currently, we probably could overwrite memory on the stack (e.g.
with a possibly mal-formed DCCP packet), but unintentionally, as
we only want the buffer to be placed into _dh variable.
Fixes: 2bc780499aa3 ("[NETFILTER]: nf_conntrack: add DCCP protocol support")
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_proto_dccp.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index 38412684a8824..cb372f96f10dc 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -428,7 +428,7 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
const char *msg;
u_int8_t state;
- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
+ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh);
BUG_ON(dh == NULL);
state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE];
@@ -486,7 +486,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
u_int8_t type, old_state, new_state;
enum ct_dccp_roles role;
- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
+ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh);
BUG_ON(dh == NULL);
type = dh->dccph_type;
@@ -577,7 +577,7 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl,
unsigned int cscov;
const char *msg;
- dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
+ dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh);
if (dh == NULL) {
msg = "nf_ct_dccp: short packet ";
goto out_invalid;

View File

@ -1,160 +0,0 @@
From 1d147bfa64293b2723c4fec50922168658e613ba Mon Sep 17 00:00:00 2001
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Date: Thu, 20 Feb 2014 09:22:11 +0200
Subject: mac80211: fix AP powersave TX vs. wakeup race
There is a race between the TX path and the STA wakeup: while
a station is sleeping, mac80211 buffers frames until it wakes
up, then the frames are transmitted. However, the RX and TX
path are concurrent, so the packet indicating wakeup can be
processed while a packet is being transmitted.
This can lead to a situation where the buffered frames list
is emptied on the one side, while a frame is being added on
the other side, as the station is still seen as sleeping in
the TX path.
As a result, the newly added frame will not be send anytime
soon. It might be sent much later (and out of order) when the
station goes to sleep and wakes up the next time.
Additionally, it can lead to the crash below.
Fix all this by synchronising both paths with a new lock.
Both path are not fastpath since they handle PS situations.
In a later patch we'll remove the extra skb queue locks to
reduce locking overhead.
BUG: unable to handle kernel
NULL pointer dereference at 000000b0
IP: [<ff6f1791>] ieee80211_report_used_skb+0x11/0x3e0 [mac80211]
*pde = 00000000
Oops: 0000 [#1] SMP DEBUG_PAGEALLOC
EIP: 0060:[<ff6f1791>] EFLAGS: 00210282 CPU: 1
EIP is at ieee80211_report_used_skb+0x11/0x3e0 [mac80211]
EAX: e5900da0 EBX: 00000000 ECX: 00000001 EDX: 00000000
ESI: e41d00c0 EDI: e5900da0 EBP: ebe458e4 ESP: ebe458b0
DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
CR0: 8005003b CR2: 000000b0 CR3: 25a78000 CR4: 000407d0
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: ffff0ff0 DR7: 00000400
Process iperf (pid: 3934, ti=ebe44000 task=e757c0b0 task.ti=ebe44000)
iwlwifi 0000:02:00.0: I iwl_pcie_enqueue_hcmd Sending command LQ_CMD (#4e), seq: 0x0903, 92 bytes at 3[3]:9
Stack:
e403b32c ebe458c4 00200002 00200286 e403b338 ebe458cc c10960bb e5900da0
ff76a6ec ebe458d8 00000000 e41d00c0 e5900da0 ebe458f0 ff6f1b75 e403b210
ebe4598c ff723dc1 00000000 ff76a6ec e597c978 e403b758 00000002 00000002
Call Trace:
[<ff6f1b75>] ieee80211_free_txskb+0x15/0x20 [mac80211]
[<ff723dc1>] invoke_tx_handlers+0x1661/0x1780 [mac80211]
[<ff7248a5>] ieee80211_tx+0x75/0x100 [mac80211]
[<ff7249bf>] ieee80211_xmit+0x8f/0xc0 [mac80211]
[<ff72550e>] ieee80211_subif_start_xmit+0x4fe/0xe20 [mac80211]
[<c149ef70>] dev_hard_start_xmit+0x450/0x950
[<c14b9aa9>] sch_direct_xmit+0xa9/0x250
[<c14b9c9b>] __qdisc_run+0x4b/0x150
[<c149f732>] dev_queue_xmit+0x2c2/0xca0
Cc: stable@vger.kernel.org
Reported-by: Yaara Rozenblum <yaara.rozenblum@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Reviewed-by: Stanislaw Gruszka <sgruszka@redhat.com>
[reword commit log, use a separate lock]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/sta_info.c | 4 ++++
net/mac80211/sta_info.h | 7 +++----
net/mac80211/tx.c | 15 +++++++++++++++
3 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index decd30c..62a5f08 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -330,6 +330,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
spin_lock_init(&sta->lock);
+ spin_lock_init(&sta->ps_lock);
INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
mutex_init(&sta->ampdu_mlme.mtx);
@@ -1109,6 +1110,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
skb_queue_head_init(&pending);
+ /* sync with ieee80211_tx_h_unicast_ps_buf */
+ spin_lock(&sta->ps_lock);
/* Send all buffered frames to the station */
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
int count = skb_queue_len(&pending), tmp;
@@ -1128,6 +1131,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
}
ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
+ spin_unlock(&sta->ps_lock);
/* This station just woke up and isn't aware of our SMPS state */
if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index d77ff70..d3a6d82 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -267,6 +267,7 @@ struct ieee80211_tx_latency_stat {
* @drv_unblock_wk: used for driver PS unblocking
* @listen_interval: listen interval of this station, when we're acting as AP
* @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
+ * @ps_lock: used for powersave (when mac80211 is the AP) related locking
* @ps_tx_buf: buffers (per AC) of frames to transmit to this station
* when it leaves power saving state or polls
* @tx_filtered: buffers (per AC) of frames we already tried to
@@ -356,10 +357,8 @@ struct sta_info {
/* use the accessors defined below */
unsigned long _flags;
- /*
- * STA powersave frame queues, no more than the internal
- * locking required.
- */
+ /* STA powersave lock and frame queues */
+ spinlock_t ps_lock;
struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
unsigned long driver_buffered_tids;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 97a02d3..4080c61 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -478,6 +478,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta->sta.addr, sta->sta.aid, ac);
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
purge_old_ps_buffers(tx->local);
+
+ /* sync with ieee80211_sta_ps_deliver_wakeup */
+ spin_lock(&sta->ps_lock);
+ /*
+ * STA woke up the meantime and all the frames on ps_tx_buf have
+ * been queued to pending queue. No reordering can happen, go
+ * ahead and Tx the packet.
+ */
+ if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
+ !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
+ spin_unlock(&sta->ps_lock);
+ return TX_CONTINUE;
+ }
+
if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
ps_dbg(tx->sdata,
@@ -492,6 +506,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
+ spin_unlock(&sta->ps_lock);
if (!timer_pending(&local->sta_cleanup))
mod_timer(&local->sta_cleanup,
--
cgit v1.1

View File

@ -1,64 +0,0 @@
From b04c46190219a4f845e46a459e3102137b7f6cac Mon Sep 17 00:00:00 2001
From: "Wang, Xiaoming" <xiaoming.wang@intel.com>
Date: Mon, 14 Apr 2014 12:30:45 -0400
Subject: net: ipv4: current group_info should be put after using.
Plug a group_info refcount leak in ping_init.
group_info is only needed during initialization and
the code failed to release the reference on exit.
While here move grabbing the reference to a place
where it is actually needed.
Signed-off-by: Chuansheng Liu <chuansheng.liu@intel.com>
Signed-off-by: Zhang Dongxing <dongxing.zhang@intel.com>
Signed-off-by: xiaoming wang <xiaoming.wang@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
net/ipv4/ping.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index f4b19e5..8210964 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -252,26 +252,33 @@ int ping_init_sock(struct sock *sk)
{
struct net *net = sock_net(sk);
kgid_t group = current_egid();
- struct group_info *group_info = get_current_groups();
- int i, j, count = group_info->ngroups;
+ struct group_info *group_info;
+ int i, j, count;
kgid_t low, high;
+ int ret = 0;
inet_get_ping_group_range_net(net, &low, &high);
if (gid_lte(low, group) && gid_lte(group, high))
return 0;
+ group_info = get_current_groups();
+ count = group_info->ngroups;
for (i = 0; i < group_info->nblocks; i++) {
int cp_count = min_t(int, NGROUPS_PER_BLOCK, count);
for (j = 0; j < cp_count; j++) {
kgid_t gid = group_info->blocks[i][j];
if (gid_lte(low, gid) && gid_lte(gid, high))
- return 0;
+ goto out_release_group;
}
count -= cp_count;
}
- return -EACCES;
+ ret = -EACCES;
+
+out_release_group:
+ put_group_info(group_info);
+ return ret;
}
EXPORT_SYMBOL_GPL(ping_init_sock);
--
cgit v1.1

View File

@ -1,91 +0,0 @@
From 314760e66c35c8ffa51b4c4ca6948d207e783079 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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
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 52f01229..c6c18d8 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -355,6 +355,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;
@@ -371,11 +373,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

@ -1,90 +0,0 @@
From 05ab8f2647e4221cbdb3856dd7d32bd5407316b3 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
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>
---
net/core/filter.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/net/core/filter.c b/net/core/filter.c
index e08b382..0e0856f 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -600,6 +600,9 @@ static u64 __skb_get_nlattr(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
if (skb_is_nonlinear(skb))
return 0;
+ if (skb->len < sizeof(struct nlattr))
+ return 0;
+
if (A > skb->len - sizeof(struct nlattr))
return 0;
@@ -618,11 +621,14 @@ static u64 __skb_get_nlattr_nest(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
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

@ -1,84 +0,0 @@
From e9c243a5a6de0be8e584c604d353412584b592f8 Mon Sep 17 00:00:00 2001
From: Thomas Gleixner <tglx@linutronix.de>
Date: Tue, 3 Jun 2014 12:27:06 +0000
Subject: futex-prevent-requeue-pi-on-same-futex.patch futex: Forbid uaddr ==
uaddr2 in futex_requeue(..., requeue_pi=1)
If uaddr == uaddr2, then we have broken the rule of only requeueing from
a non-pi futex to a pi futex with this call. If we attempt this, then
dangling pointers may be left for rt_waiter resulting in an exploitable
condition.
This change brings futex_requeue() in line with futex_wait_requeue_pi()
which performs the same check as per commit 6f7b0a2a5c0f ("futex: Forbid
uaddr == uaddr2 in futex_wait_requeue_pi()")
[ tglx: Compare the resulting keys as well, as uaddrs might be
different depending on the mapping ]
Fixes CVE-2014-3153.
Reported-by: Pinkie Pie
Signed-off-by: Will Drewry <wad@chromium.org>
Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Darren Hart <dvhart@linux.intel.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
kernel/futex.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/kernel/futex.c b/kernel/futex.c
index 81dbe77..663ea2b 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1442,6 +1442,13 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
if (requeue_pi) {
/*
+ * Requeue PI only works on two distinct uaddrs. This
+ * check is only valid for private futexes. See below.
+ */
+ if (uaddr1 == uaddr2)
+ return -EINVAL;
+
+ /*
* requeue_pi requires a pi_state, try to allocate it now
* without any locks in case it fails.
*/
@@ -1479,6 +1486,15 @@ retry:
if (unlikely(ret != 0))
goto out_put_key1;
+ /*
+ * The check above which compares uaddrs is not sufficient for
+ * shared futexes. We need to compare the keys:
+ */
+ if (requeue_pi && match_futex(&key1, &key2)) {
+ ret = -EINVAL;
+ goto out_put_keys;
+ }
+
hb1 = hash_futex(&key1);
hb2 = hash_futex(&key2);
@@ -2525,6 +2541,15 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
if (ret)
goto out_key2;
+ /*
+ * The check above which compares uaddrs is not sufficient for
+ * shared futexes. We need to compare the keys:
+ */
+ if (match_futex(&q.key, &key2)) {
+ ret = -EINVAL;
+ goto out_put_keys;
+ }
+
/* Queue the futex_q, drop the hb lock, wait for wakeup. */
futex_wait_queue_me(hb, &q, to);
--
cgit v1.1

View File

@ -1,100 +0,0 @@
From 13fbca4c6ecd96ec1a1cfa2e4f2ce191fe928a5e Mon Sep 17 00:00:00 2001
From: Thomas Gleixner <tglx@linutronix.de>
Date: Tue, 3 Jun 2014 12:27:07 +0000
Subject: futex: Always cleanup owner tid in unlock_pi
If the owner died bit is set at futex_unlock_pi, we currently do not
cleanup the user space futex. So the owner TID of the current owner
(the unlocker) persists. That's observable inconsistant state,
especially when the ownership of the pi state got transferred.
Clean it up unconditionally.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Drewry <wad@chromium.org>
Cc: Darren Hart <dvhart@linux.intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
kernel/futex.c | 40 ++++++++++++++++++----------------------
1 file changed, 18 insertions(+), 22 deletions(-)
diff --git a/kernel/futex.c b/kernel/futex.c
index 520e7b2..e1cb1ba 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1052,6 +1052,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
struct task_struct *new_owner;
struct futex_pi_state *pi_state = this->pi_state;
u32 uninitialized_var(curval), newval;
+ int ret = 0;
if (!pi_state)
return -EINVAL;
@@ -1075,23 +1076,19 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
new_owner = this->task;
/*
- * We pass it to the next owner. (The WAITERS bit is always
- * kept enabled while there is PI state around. We must also
- * preserve the owner died bit.)
+ * We pass it to the next owner. The WAITERS bit is always
+ * kept enabled while there is PI state around. We cleanup the
+ * owner died bit, because we are the owner.
*/
- if (!(uval & FUTEX_OWNER_DIED)) {
- int ret = 0;
-
- newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
+ newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
- if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
- ret = -EFAULT;
- else if (curval != uval)
- ret = -EINVAL;
- if (ret) {
- raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
- return ret;
- }
+ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))
+ ret = -EFAULT;
+ else if (curval != uval)
+ ret = -EINVAL;
+ if (ret) {
+ raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
+ return ret;
}
raw_spin_lock_irq(&pi_state->owner->pi_lock);
@@ -2351,9 +2348,10 @@ retry:
/*
* To avoid races, try to do the TID -> 0 atomic transition
* again. If it succeeds then we can return without waking
- * anyone else up:
+ * anyone else up. We only try this if neither the waiters nor
+ * the owner died bit are set.
*/
- if (!(uval & FUTEX_OWNER_DIED) &&
+ if (!(uval & ~FUTEX_TID_MASK) &&
cmpxchg_futex_value_locked(&uval, uaddr, vpid, 0))
goto pi_faulted;
/*
@@ -2383,11 +2381,9 @@ retry:
/*
* No waiters - kernel unlocks the futex:
*/
- if (!(uval & FUTEX_OWNER_DIED)) {
- ret = unlock_futex_pi(uaddr, uval);
- if (ret == -EFAULT)
- goto pi_faulted;
- }
+ ret = unlock_futex_pi(uaddr, uval);
+ if (ret == -EFAULT)
+ goto pi_faulted;
out_unlock:
spin_unlock(&hb->lock);
--
cgit v1.1

View File

@ -1,279 +0,0 @@
From 54a217887a7b658e2650c3feff22756ab80c7339 Mon Sep 17 00:00:00 2001
From: Thomas Gleixner <tglx@linutronix.de>
Date: Tue, 3 Jun 2014 12:27:08 +0000
Subject: futex: Make lookup_pi_state more robust
The current implementation of lookup_pi_state has ambigous handling of
the TID value 0 in the user space futex. We can get into the kernel
even if the TID value is 0, because either there is a stale waiters bit
or the owner died bit is set or we are called from the requeue_pi path
or from user space just for fun.
The current code avoids an explicit sanity check for pid = 0 in case
that kernel internal state (waiters) are found for the user space
address. This can lead to state leakage and worse under some
circumstances.
Handle the cases explicit:
Waiter | pi_state | pi->owner | uTID | uODIED | ?
[1] NULL | --- | --- | 0 | 0/1 | Valid
[2] NULL | --- | --- | >0 | 0/1 | Valid
[3] Found | NULL | -- | Any | 0/1 | Invalid
[4] Found | Found | NULL | 0 | 1 | Valid
[5] Found | Found | NULL | >0 | 1 | Invalid
[6] Found | Found | task | 0 | 1 | Valid
[7] Found | Found | NULL | Any | 0 | Invalid
[8] Found | Found | task | ==taskTID | 0/1 | Valid
[9] Found | Found | task | 0 | 0 | Invalid
[10] Found | Found | task | !=taskTID | 0/1 | Invalid
[1] Indicates that the kernel can acquire the futex atomically. We
came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit.
[2] Valid, if TID does not belong to a kernel thread. If no matching
thread is found then it indicates that the owner TID has died.
[3] Invalid. The waiter is queued on a non PI futex
[4] Valid state after exit_robust_list(), which sets the user space
value to FUTEX_WAITERS | FUTEX_OWNER_DIED.
[5] The user space value got manipulated between exit_robust_list()
and exit_pi_state_list()
[6] Valid state after exit_pi_state_list() which sets the new owner in
the pi_state but cannot access the user space value.
[7] pi_state->owner can only be NULL when the OWNER_DIED bit is set.
[8] Owner and user space value match
[9] There is no transient state which sets the user space TID to 0
except exit_robust_list(), but this is indicated by the
FUTEX_OWNER_DIED bit. See [4]
[10] There is no transient state which leaves owner and user space
TID out of sync.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Drewry <wad@chromium.org>
Cc: Darren Hart <dvhart@linux.intel.com>
Cc: stable@vger.kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
kernel/futex.c | 134 +++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 106 insertions(+), 28 deletions(-)
diff --git a/kernel/futex.c b/kernel/futex.c
index e1cb1ba..de938d2 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -743,10 +743,58 @@ void exit_pi_state_list(struct task_struct *curr)
raw_spin_unlock_irq(&curr->pi_lock);
}
+/*
+ * We need to check the following states:
+ *
+ * Waiter | pi_state | pi->owner | uTID | uODIED | ?
+ *
+ * [1] NULL | --- | --- | 0 | 0/1 | Valid
+ * [2] NULL | --- | --- | >0 | 0/1 | Valid
+ *
+ * [3] Found | NULL | -- | Any | 0/1 | Invalid
+ *
+ * [4] Found | Found | NULL | 0 | 1 | Valid
+ * [5] Found | Found | NULL | >0 | 1 | Invalid
+ *
+ * [6] Found | Found | task | 0 | 1 | Valid
+ *
+ * [7] Found | Found | NULL | Any | 0 | Invalid
+ *
+ * [8] Found | Found | task | ==taskTID | 0/1 | Valid
+ * [9] Found | Found | task | 0 | 0 | Invalid
+ * [10] Found | Found | task | !=taskTID | 0/1 | Invalid
+ *
+ * [1] Indicates that the kernel can acquire the futex atomically. We
+ * came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit.
+ *
+ * [2] Valid, if TID does not belong to a kernel thread. If no matching
+ * thread is found then it indicates that the owner TID has died.
+ *
+ * [3] Invalid. The waiter is queued on a non PI futex
+ *
+ * [4] Valid state after exit_robust_list(), which sets the user space
+ * value to FUTEX_WAITERS | FUTEX_OWNER_DIED.
+ *
+ * [5] The user space value got manipulated between exit_robust_list()
+ * and exit_pi_state_list()
+ *
+ * [6] Valid state after exit_pi_state_list() which sets the new owner in
+ * the pi_state but cannot access the user space value.
+ *
+ * [7] pi_state->owner can only be NULL when the OWNER_DIED bit is set.
+ *
+ * [8] Owner and user space value match
+ *
+ * [9] There is no transient state which sets the user space TID to 0
+ * except exit_robust_list(), but this is indicated by the
+ * FUTEX_OWNER_DIED bit. See [4]
+ *
+ * [10] There is no transient state which leaves owner and user space
+ * TID out of sync.
+ */
static int
lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
- union futex_key *key, struct futex_pi_state **ps,
- struct task_struct *task)
+ union futex_key *key, struct futex_pi_state **ps)
{
struct futex_pi_state *pi_state = NULL;
struct futex_q *this, *next;
@@ -756,12 +804,13 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
plist_for_each_entry_safe(this, next, &hb->chain, list) {
if (match_futex(&this->key, key)) {
/*
- * Another waiter already exists - bump up
- * the refcount and return its pi_state:
+ * Sanity check the waiter before increasing
+ * the refcount and attaching to it.
*/
pi_state = this->pi_state;
/*
- * Userspace might have messed up non-PI and PI futexes
+ * Userspace might have messed up non-PI and
+ * PI futexes [3]
*/
if (unlikely(!pi_state))
return -EINVAL;
@@ -769,44 +818,70 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
WARN_ON(!atomic_read(&pi_state->refcount));
/*
- * When pi_state->owner is NULL then the owner died
- * and another waiter is on the fly. pi_state->owner
- * is fixed up by the task which acquires
- * pi_state->rt_mutex.
- *
- * We do not check for pid == 0 which can happen when
- * the owner died and robust_list_exit() cleared the
- * TID.
+ * Handle the owner died case:
*/
- if (pid && pi_state->owner) {
+ if (uval & FUTEX_OWNER_DIED) {
/*
- * Bail out if user space manipulated the
- * futex value.
+ * exit_pi_state_list sets owner to NULL and
+ * wakes the topmost waiter. The task which
+ * acquires the pi_state->rt_mutex will fixup
+ * owner.
*/
- if (pid != task_pid_vnr(pi_state->owner))
+ if (!pi_state->owner) {
+ /*
+ * No pi state owner, but the user
+ * space TID is not 0. Inconsistent
+ * state. [5]
+ */
+ if (pid)
+ return -EINVAL;
+ /*
+ * Take a ref on the state and
+ * return. [4]
+ */
+ goto out_state;
+ }
+
+ /*
+ * If TID is 0, then either the dying owner
+ * has not yet executed exit_pi_state_list()
+ * or some waiter acquired the rtmutex in the
+ * pi state, but did not yet fixup the TID in
+ * user space.
+ *
+ * Take a ref on the state and return. [6]
+ */
+ if (!pid)
+ goto out_state;
+ } else {
+ /*
+ * If the owner died bit is not set,
+ * then the pi_state must have an
+ * owner. [7]
+ */
+ if (!pi_state->owner)
return -EINVAL;
}
/*
- * Protect against a corrupted uval. If uval
- * is 0x80000000 then pid is 0 and the waiter
- * bit is set. So the deadlock check in the
- * calling code has failed and we did not fall
- * into the check above due to !pid.
+ * Bail out if user space manipulated the
+ * futex value. If pi state exists then the
+ * owner TID must be the same as the user
+ * space TID. [9/10]
*/
- if (task && pi_state->owner == task)
- return -EDEADLK;
+ if (pid != task_pid_vnr(pi_state->owner))
+ return -EINVAL;
+ out_state:
atomic_inc(&pi_state->refcount);
*ps = pi_state;
-
return 0;
}
}
/*
* We are the first waiter - try to look up the real owner and attach
- * the new pi_state to it, but bail out when TID = 0
+ * the new pi_state to it, but bail out when TID = 0 [1]
*/
if (!pid)
return -ESRCH;
@@ -839,6 +914,9 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
return ret;
}
+ /*
+ * No existing pi state. First waiter. [2]
+ */
pi_state = alloc_pi_state();
/*
@@ -959,7 +1037,7 @@ retry:
* We dont have the lock. Look up the PI state (or create it if
* we are the first waiter):
*/
- ret = lookup_pi_state(uval, hb, key, ps, task);
+ ret = lookup_pi_state(uval, hb, key, ps);
if (unlikely(ret)) {
switch (ret) {
@@ -1565,7 +1643,7 @@ retry_private:
* rereading and handing potential crap to
* lookup_pi_state.
*/
- ret = lookup_pi_state(ret, hb2, &key2, &pi_state, NULL);
+ ret = lookup_pi_state(ret, hb2, &key2, &pi_state);
}
switch (ret) {
--
cgit v1.1

View File

@ -1,56 +0,0 @@
From b3eaa9fc5cd0a4d74b18f6b8dc617aeaf1873270 Mon Sep 17 00:00:00 2001
From: Thomas Gleixner <tglx@linutronix.de>
Date: Tue, 3 Jun 2014 12:27:06 +0000
Subject: futex: Validate atomic acquisition in futex_lock_pi_atomic()
We need to protect the atomic acquisition in the kernel against rogue
user space which sets the user space futex to 0, so the kernel side
acquisition succeeds while there is existing state in the kernel
associated to the real owner.
Verify whether the futex has waiters associated with kernel state. If
it has, return -EINVAL. The state is corrupted already, so no point in
cleaning it up. Subsequent calls will fail as well. Not our problem.
[ tglx: Use futex_top_waiter() and explain why we do not need to try
restoring the already corrupted user space state. ]
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Will Drewry <wad@chromium.org>
Cc: stable@vger.kernel.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
kernel/futex.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/kernel/futex.c b/kernel/futex.c
index 663ea2b..520e7b2 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -910,10 +910,18 @@ retry:
return -EDEADLK;
/*
- * Surprise - we got the lock. Just return to userspace:
+ * Surprise - we got the lock, but we do not trust user space at all.
*/
- if (unlikely(!curval))
- return 1;
+ if (unlikely(!curval)) {
+ /*
+ * We verify whether there is kernel state for this
+ * futex. If not, we can safely assume, that the 0 ->
+ * TID transition is correct. If state exists, we do
+ * not bother to fixup the user space state as it was
+ * corrupted already.
+ */
+ return futex_top_waiter(hb, key) ? -EINVAL : 1;
+ }
uval = curval;
--
cgit v1.1

View File

@ -1,206 +0,0 @@
From 23adbe12ef7d3d4195e80800ab36b37bee28cd03 Mon Sep 17 00:00:00 2001
From: Andy Lutomirski <luto@amacapital.net>
Date: Tue, 10 Jun 2014 12:45:42 -0700
Subject: fs,userns: Change inode_capable to capable_wrt_inode_uidgid
The kernel has no concept of capabilities with respect to inodes; inodes
exist independently of namespaces. For example, inode_capable(inode,
CAP_LINUX_IMMUTABLE) would be nonsense.
This patch changes inode_capable to check for uid and gid mappings and
renames it to capable_wrt_inode_uidgid, which should make it more
obvious what it does.
Fixes CVE-2014-4014.
Cc: Theodore Ts'o <tytso@mit.edu>
Cc: Serge Hallyn <serge.hallyn@ubuntu.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: stable@vger.kernel.org
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
fs/attr.c | 8 ++++----
fs/inode.c | 10 +++++++---
fs/namei.c | 11 ++++++-----
fs/xfs/xfs_ioctl.c | 2 +-
include/linux/capability.h | 2 +-
kernel/capability.c | 20 ++++++++------------
6 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/fs/attr.c b/fs/attr.c
index 5d4e59d..6530ced 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -50,14 +50,14 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
if ((ia_valid & ATTR_UID) &&
(!uid_eq(current_fsuid(), inode->i_uid) ||
!uid_eq(attr->ia_uid, inode->i_uid)) &&
- !inode_capable(inode, CAP_CHOWN))
+ !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
return -EPERM;
/* Make sure caller can chgrp. */
if ((ia_valid & ATTR_GID) &&
(!uid_eq(current_fsuid(), inode->i_uid) ||
(!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) &&
- !inode_capable(inode, CAP_CHOWN))
+ !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
return -EPERM;
/* Make sure a caller can chmod. */
@@ -67,7 +67,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
/* Also check the setgid bit! */
if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
inode->i_gid) &&
- !inode_capable(inode, CAP_FSETID))
+ !capable_wrt_inode_uidgid(inode, CAP_FSETID))
attr->ia_mode &= ~S_ISGID;
}
@@ -160,7 +160,7 @@ void setattr_copy(struct inode *inode, const struct iattr *attr)
umode_t mode = attr->ia_mode;
if (!in_group_p(inode->i_gid) &&
- !inode_capable(inode, CAP_FSETID))
+ !capable_wrt_inode_uidgid(inode, CAP_FSETID))
mode &= ~S_ISGID;
inode->i_mode = mode;
}
diff --git a/fs/inode.c b/fs/inode.c
index 2feb9b6..6eecb7f 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1839,14 +1839,18 @@ EXPORT_SYMBOL(inode_init_owner);
* inode_owner_or_capable - check current task permissions to inode
* @inode: inode being checked
*
- * Return true if current either has CAP_FOWNER to the inode, or
- * owns the file.
+ * Return true if current either has CAP_FOWNER in a namespace with the
+ * inode owner uid mapped, or owns the file.
*/
bool inode_owner_or_capable(const struct inode *inode)
{
+ struct user_namespace *ns;
+
if (uid_eq(current_fsuid(), inode->i_uid))
return true;
- if (inode_capable(inode, CAP_FOWNER))
+
+ ns = current_user_ns();
+ if (ns_capable(ns, CAP_FOWNER) && kuid_has_mapping(ns, inode->i_uid))
return true;
return false;
}
diff --git a/fs/namei.c b/fs/namei.c
index 8016827..985c6f3 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -332,10 +332,11 @@ int generic_permission(struct inode *inode, int mask)
if (S_ISDIR(inode->i_mode)) {
/* DACs are overridable for directories */
- if (inode_capable(inode, CAP_DAC_OVERRIDE))
+ if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE))
return 0;
if (!(mask & MAY_WRITE))
- if (inode_capable(inode, CAP_DAC_READ_SEARCH))
+ if (capable_wrt_inode_uidgid(inode,
+ CAP_DAC_READ_SEARCH))
return 0;
return -EACCES;
}
@@ -345,7 +346,7 @@ int generic_permission(struct inode *inode, int mask)
* at least one exec bit set.
*/
if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO))
- if (inode_capable(inode, CAP_DAC_OVERRIDE))
+ if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE))
return 0;
/*
@@ -353,7 +354,7 @@ int generic_permission(struct inode *inode, int mask)
*/
mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
if (mask == MAY_READ)
- if (inode_capable(inode, CAP_DAC_READ_SEARCH))
+ if (capable_wrt_inode_uidgid(inode, CAP_DAC_READ_SEARCH))
return 0;
return -EACCES;
@@ -2379,7 +2380,7 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
return 0;
if (uid_eq(dir->i_uid, fsuid))
return 0;
- return !inode_capable(inode, CAP_FOWNER);
+ return !capable_wrt_inode_uidgid(inode, CAP_FOWNER);
}
/*
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 0b18776..6152cbe 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1215,7 +1215,7 @@ xfs_ioctl_setattr(
* cleared upon successful return from chown()
*/
if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
- !inode_capable(VFS_I(ip), CAP_FSETID))
+ !capable_wrt_inode_uidgid(VFS_I(ip), CAP_FSETID))
ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);
/*
diff --git a/include/linux/capability.h b/include/linux/capability.h
index a6ee1f9..84b13ad 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -210,7 +210,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t,
struct user_namespace *ns, int cap);
extern bool capable(int cap);
extern bool ns_capable(struct user_namespace *ns, int cap);
-extern bool inode_capable(const struct inode *inode, int cap);
+extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap);
extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
/* audit system wants to get cap info from files as well */
diff --git a/kernel/capability.c b/kernel/capability.c
index 84b2bbf..a5cf13c 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -424,23 +424,19 @@ bool capable(int cap)
EXPORT_SYMBOL(capable);
/**
- * inode_capable - Check superior capability over inode
+ * capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped
* @inode: The inode in question
* @cap: The capability in question
*
- * Return true if the current task has the given superior capability
- * targeted at it's own user namespace and that the given inode is owned
- * by the current user namespace or a child namespace.
- *
- * Currently we check to see if an inode is owned by the current
- * user namespace by seeing if the inode's owner maps into the
- * current user namespace.
- *
+ * Return true if the current task has the given capability targeted at
+ * its own user namespace and that the given inode's uid and gid are
+ * mapped into the current user namespace.
*/
-bool inode_capable(const struct inode *inode, int cap)
+bool capable_wrt_inode_uidgid(const struct inode *inode, int cap)
{
struct user_namespace *ns = current_user_ns();
- return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid);
+ return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid) &&
+ kgid_has_mapping(ns, inode->i_gid);
}
-EXPORT_SYMBOL(inode_capable);
+EXPORT_SYMBOL(capable_wrt_inode_uidgid);
--
cgit v1.1

View File

@ -1,66 +0,0 @@
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

@ -1,94 +0,0 @@
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

@ -1,383 +0,0 @@
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

@ -1,33 +0,0 @@
From 014fa8def84c62893fa016e873c12de1da498603 Mon Sep 17 00:00:00 2001
From: raghavendra ambadas <rambad@codeaurora.org>
Date: Mon, 6 Oct 2014 14:59:57 +0530
Subject: msm: mdp: Validate input arguments from user space
Fully verify the input arguments from user client are safe
to use.
Change-Id: Ie14332443b187951009c63ebfb78456dcd9ba60f
Signed-off-by: Raghavendra Ambadas <rambad@codeaurora.org>
---
drivers/video/msm/mdp.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 4ede0b52..c00bd78 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -485,6 +485,11 @@ static int mdp_lut_hw_update(struct fb_cmap *cmap)
c[1] = cmap->blue;
c[2] = cmap->red;
+ if (cmap->start > MDP_HIST_LUT_SIZE || cmap->len > MDP_HIST_LUT_SIZE ||
+ (cmap->start + cmap->len > MDP_HIST_LUT_SIZE)) {
+ pr_err("mdp_lut_hw_update invalid arguments\n");
+ return -EINVAL;
+ }
for (i = 0; i < cmap->len; i++) {
if (copy_from_user(&r, cmap->red++, sizeof(r)) ||
copy_from_user(&g, cmap->green++, sizeof(g)) ||
--
cgit v1.1

View File

@ -1,308 +0,0 @@
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,88 +0,0 @@
From 82262a46627bebb0febcc26664746c25cef08563 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
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>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
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 00ab034..1f413c2 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1154,8 +1154,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 :
@@ -1164,21 +1162,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,37 +0,0 @@
From 883a1d49f0d77d30012f114b2e19fc141beb3e8e 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
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>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
sound/core/control.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/sound/core/control.c b/sound/core/control.c
index 8d6e4ba..f0b0e14 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -342,6 +342,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 1179c8f1caca90caf4ce0eec54b499de4f1551c4 Mon Sep 17 00:00:00 2001
From: Sasha Levin <sasha.levin@oracle.com>
Date: Mon, 14 Jul 2014 17:02:31 -0700
Subject: net/l2tp: don't fall back on UDP [get|set]sockopt
commit 3cf521f7dc87c031617fd47e4b7aa2593c2f3daf upstream.
The l2tp [get|set]sockopt() code has fallen back to the UDP functions
for socket option levels != SOL_PPPOL2TP since day one, but that has
never actually worked, since the l2tp socket isn't an inet socket.
As David Miller points out:
"If we wanted this to work, it'd have to look up the tunnel and then
use tunnel->sk, but I wonder how useful that would be"
Since this can never have worked so nobody could possibly have depended
on that functionality, just remove the broken code and return -EINVAL.
Reported-by: Sasha Levin <sasha.levin@oracle.com>
Acked-by: James Chapman <jchapman@katalix.com>
Acked-by: David Miller <davem@davemloft.net>
Cc: Phil Turnbull <phil.turnbull@oracle.com>
Cc: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
net/l2tp/l2tp_ppp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index e0f0934..437fb59 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1351,7 +1351,7 @@ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,
int err;
if (level != SOL_PPPOL2TP)
- return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+ return -EINVAL;
if (optlen < sizeof(int))
return -EINVAL;
@@ -1477,7 +1477,7 @@ static int pppol2tp_getsockopt(struct socket *sock, int level,
struct pppol2tp_session *ps;
if (level != SOL_PPPOL2TP)
- return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+ return -EINVAL;
if (get_user(len, (int __user *) optlen))
return -EFAULT;
--
cgit v1.1

View File

@ -1,51 +0,0 @@
From 3cf521f7dc87c031617fd47e4b7aa2593c2f3daf Mon Sep 17 00:00:00 2001
From: Sasha Levin <sasha.levin@oracle.com>
Date: Mon, 14 Jul 2014 17:02:31 -0700
Subject: [PATCH] net/l2tp: don't fall back on UDP [get|set]sockopt
The l2tp [get|set]sockopt() code has fallen back to the UDP functions
for socket option levels != SOL_PPPOL2TP since day one, but that has
never actually worked, since the l2tp socket isn't an inet socket.
As David Miller points out:
"If we wanted this to work, it'd have to look up the tunnel and then
use tunnel->sk, but I wonder how useful that would be"
Since this can never have worked so nobody could possibly have depended
on that functionality, just remove the broken code and return -EINVAL.
Reported-by: Sasha Levin <sasha.levin@oracle.com>
Acked-by: James Chapman <jchapman@katalix.com>
Acked-by: David Miller <davem@davemloft.net>
Cc: Phil Turnbull <phil.turnbull@oracle.com>
Cc: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Willy Tarreau <w@1wt.eu>
Cc: stable@vger.kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
net/l2tp/l2tp_ppp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 950909f04ee6a..13752d96275e8 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -1365,7 +1365,7 @@ static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,
int err;
if (level != SOL_PPPOL2TP)
- return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+ return -EINVAL;
if (optlen < sizeof(int))
return -EINVAL;
@@ -1491,7 +1491,7 @@ static int pppol2tp_getsockopt(struct socket *sock, int level, int optname,
struct pppol2tp_session *ps;
if (level != SOL_PPPOL2TP)
- return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+ return -EINVAL;
if (get_user(len, optlen))
return -EFAULT;

View File

@ -1,52 +0,0 @@
From a6138db815df5ee542d848318e5dae681590fccd Mon Sep 17 00:00:00 2001
From: "Eric W. Biederman" <ebiederm@xmission.com>
Date: Mon, 28 Jul 2014 16:26:53 -0700
Subject: [PATCH] mnt: Only change user settable mount flags in remount
Kenton Varda <kenton@sandstorm.io> discovered that by remounting a
read-only bind mount read-only in a user namespace the
MNT_LOCK_READONLY bit would be cleared, allowing an unprivileged user
to the remount a read-only mount read-write.
Correct this by replacing the mask of mount flags to preserve
with a mask of mount flags that may be changed, and preserve
all others. This ensures that any future bugs with this mask and
remount will fail in an easy to detect way where new mount flags
simply won't change.
Cc: stable@vger.kernel.org
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
---
fs/namespace.c | 2 +-
include/linux/mount.h | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 7187d01329c35..cb40449ea0dfe 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1937,7 +1937,7 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
err = do_remount_sb(sb, flags, data, 0);
if (!err) {
lock_mount_hash();
- mnt_flags |= mnt->mnt.mnt_flags & MNT_PROPAGATION_MASK;
+ mnt_flags |= mnt->mnt.mnt_flags & ~MNT_USER_SETTABLE_MASK;
mnt->mnt.mnt_flags = mnt_flags;
touch_mnt_namespace(mnt->mnt_ns);
unlock_mount_hash();
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 839bac2709048..b637a89e1faeb 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -42,7 +42,9 @@ struct mnt_namespace;
* flag, consider how it interacts with shared mounts.
*/
#define MNT_SHARED_MASK (MNT_UNBINDABLE)
-#define MNT_PROPAGATION_MASK (MNT_SHARED | MNT_UNBINDABLE)
+#define MNT_USER_SETTABLE_MASK (MNT_NOSUID | MNT_NODEV | MNT_NOEXEC \
+ | MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME \
+ | MNT_READONLY)
#define MNT_INTERNAL_FLAGS (MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | \
MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED)

View File

@ -1,72 +0,0 @@
From 894c6350eaad7e613ae267504014a456e00a3e2a Mon Sep 17 00:00:00 2001
From: Ben Hutchings <ben@decadent.org.uk>
Date: Thu, 29 Jan 2015 02:50:33 +0000
Subject: splice: Apply generic position and size checks to each write
We need to check the position and size of file writes against various
limits, using generic_write_check(). This was not being done for
the splice write path. It was fixed upstream by commit 8d0207652cbe
("->splice_write() via ->write_iter()") but we can't apply that.
CVE-2014-7822
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
fs/ocfs2/file.c | 8 ++++++--
fs/splice.c | 8 ++++++--
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index d20d64c..0de24a2 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -2468,9 +2468,7 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
struct address_space *mapping = out->f_mapping;
struct inode *inode = mapping->host;
struct splice_desc sd = {
- .total_len = len,
.flags = flags,
- .pos = *ppos,
.u.file = out,
};
@@ -2480,6 +2478,12 @@ static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe,
out->f_path.dentry->d_name.len,
out->f_path.dentry->d_name.name, len);
+ ret = generic_write_checks(out, ppos, &len, 0);
+ if (ret)
+ return ret;
+ sd.total_len = len;
+ sd.pos = *ppos;
+
if (pipe->inode)
mutex_lock_nested(&pipe->inode->i_mutex, I_MUTEX_PARENT);
diff --git a/fs/splice.c b/fs/splice.c
index 714471d..34c2b2b 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -1013,13 +1013,17 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
struct address_space *mapping = out->f_mapping;
struct inode *inode = mapping->host;
struct splice_desc sd = {
- .total_len = len,
.flags = flags,
- .pos = *ppos,
.u.file = out,
};
ssize_t ret;
+ ret = generic_write_checks(out, ppos, &len, S_ISBLK(inode->i_mode));
+ if (ret)
+ return ret;
+ sd.total_len = len;
+ sd.pos = *ppos;
+
pipe_lock(pipe);
splice_from_pipe_begin(&sd);
--
cgit v1.1

View File

@ -1,50 +0,0 @@
From 6f25b4e75a87fea8087b543f3d1298d301d24ad7 Mon Sep 17 00:00:00 2001
From: Will Deacon <will.deacon@arm.com>
Date: Thu, 16 Aug 2012 18:14:14 +0100
Subject: tracing/syscalls: Fix perf syscall tracing when syscall_nr == -1
commit 60916a9382e88fbf5e54fd36a3e658efd7ab7bed upstream.
syscall_get_nr can return -1 in the case that the task is not executing
a system call.
This patch fixes perf_syscall_{enter,exit} to check that the syscall
number is valid before using it as an index into a bitmap.
Link: http://lkml.kernel.org/r/1345137254-7377-1-git-send-email-will.deacon@arm.com
Cc: Jason Baron <jbaron@redhat.com>
Cc: Wade Farnsworth <wade_farnsworth@mentor.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
kernel/trace/trace_syscalls.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 7c75bbb..22a7c9b 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -519,6 +519,8 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
int size;
syscall_nr = syscall_get_nr(current, regs);
+ if (syscall_nr < 0)
+ return;
if (!test_bit(syscall_nr, enabled_perf_enter_syscalls))
return;
@@ -593,6 +595,8 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
int size;
syscall_nr = syscall_get_nr(current, regs);
+ if (syscall_nr < 0)
+ return;
if (!test_bit(syscall_nr, enabled_perf_exit_syscalls))
return;
--
cgit v1.1

View File

@ -1,91 +0,0 @@
From 8043761416d5ae6d8fe5e95331d26465d52e8c6e Mon Sep 17 00:00:00 2001
From: Rabin Vincent <rabin@rab.in>
Date: Wed, 29 Oct 2014 23:06:58 +0100
Subject: tracing/syscalls: Ignore numbers outside NR_syscalls' range
commit 086ba77a6db00ed858ff07451bedee197df868c9 upstream.
ARM has some private syscalls (for example, set_tls(2)) which lie
outside the range of NR_syscalls. If any of these are called while
syscall tracing is being performed, out-of-bounds array access will
occur in the ftrace and perf sys_{enter,exit} handlers.
# trace-cmd record -e raw_syscalls:* true && trace-cmd report
...
true-653 [000] 384.675777: sys_enter: NR 192 (0, 1000, 3, 4000022, ffffffff, 0)
true-653 [000] 384.675812: sys_exit: NR 192 = 1995915264
true-653 [000] 384.675971: sys_enter: NR 983045 (76f74480, 76f74000, 76f74b28, 76f74480, 76f76f74, 1)
true-653 [000] 384.675988: sys_exit: NR 983045 = 0
...
# trace-cmd record -e syscalls:* true
[ 17.289329] Unable to handle kernel paging request at virtual address aaaaaace
[ 17.289590] pgd = 9e71c000
[ 17.289696] [aaaaaace] *pgd=00000000
[ 17.289985] Internal error: Oops: 5 [#1] PREEMPT SMP ARM
[ 17.290169] Modules linked in:
[ 17.290391] CPU: 0 PID: 704 Comm: true Not tainted 3.18.0-rc2+ #21
[ 17.290585] task: 9f4dab00 ti: 9e710000 task.ti: 9e710000
[ 17.290747] PC is at ftrace_syscall_enter+0x48/0x1f8
[ 17.290866] LR is at syscall_trace_enter+0x124/0x184
Fix this by ignoring out-of-NR_syscalls-bounds syscall numbers.
Commit cd0980fc8add "tracing: Check invalid syscall nr while tracing syscalls"
added the check for less than zero, but it should have also checked
for greater than NR_syscalls.
Link: http://lkml.kernel.org/p/1414620418-29472-1-git-send-email-rabin@rab.in
Fixes: cd0980fc8add "tracing: Check invalid syscall nr while tracing syscalls"
Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
kernel/trace/trace_syscalls.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 22a7c9b..1129062 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -309,7 +309,7 @@ void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
int syscall_nr;
syscall_nr = syscall_get_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
if (!test_bit(syscall_nr, enabled_enter_syscalls))
return;
@@ -349,7 +349,7 @@ void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
int syscall_nr;
syscall_nr = syscall_get_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
if (!test_bit(syscall_nr, enabled_exit_syscalls))
return;
@@ -519,7 +519,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
int size;
syscall_nr = syscall_get_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
if (!test_bit(syscall_nr, enabled_perf_enter_syscalls))
return;
@@ -595,7 +595,7 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
int size;
syscall_nr = syscall_get_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
if (!test_bit(syscall_nr, enabled_perf_exit_syscalls))
return;
--
cgit v1.1

View File

@ -1,85 +0,0 @@
From 086ba77a6db00ed858ff07451bedee197df868c9 Mon Sep 17 00:00:00 2001
From: Rabin Vincent <rabin@rab.in>
Date: Wed, 29 Oct 2014 23:06:58 +0100
Subject: [PATCH] tracing/syscalls: Ignore numbers outside NR_syscalls' range
ARM has some private syscalls (for example, set_tls(2)) which lie
outside the range of NR_syscalls. If any of these are called while
syscall tracing is being performed, out-of-bounds array access will
occur in the ftrace and perf sys_{enter,exit} handlers.
# trace-cmd record -e raw_syscalls:* true && trace-cmd report
...
true-653 [000] 384.675777: sys_enter: NR 192 (0, 1000, 3, 4000022, ffffffff, 0)
true-653 [000] 384.675812: sys_exit: NR 192 = 1995915264
true-653 [000] 384.675971: sys_enter: NR 983045 (76f74480, 76f74000, 76f74b28, 76f74480, 76f76f74, 1)
true-653 [000] 384.675988: sys_exit: NR 983045 = 0
...
# trace-cmd record -e syscalls:* true
[ 17.289329] Unable to handle kernel paging request at virtual address aaaaaace
[ 17.289590] pgd = 9e71c000
[ 17.289696] [aaaaaace] *pgd=00000000
[ 17.289985] Internal error: Oops: 5 [#1] PREEMPT SMP ARM
[ 17.290169] Modules linked in:
[ 17.290391] CPU: 0 PID: 704 Comm: true Not tainted 3.18.0-rc2+ #21
[ 17.290585] task: 9f4dab00 ti: 9e710000 task.ti: 9e710000
[ 17.290747] PC is at ftrace_syscall_enter+0x48/0x1f8
[ 17.290866] LR is at syscall_trace_enter+0x124/0x184
Fix this by ignoring out-of-NR_syscalls-bounds syscall numbers.
Commit cd0980fc8add "tracing: Check invalid syscall nr while tracing syscalls"
added the check for less than zero, but it should have also checked
for greater than NR_syscalls.
Link: http://lkml.kernel.org/p/1414620418-29472-1-git-send-email-rabin@rab.in
Fixes: cd0980fc8add "tracing: Check invalid syscall nr while tracing syscalls"
Cc: stable@vger.kernel.org # 2.6.33+
Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
kernel/trace/trace_syscalls.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 4dc8b79c5f75d..29228c4d56969 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -313,7 +313,7 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id)
int size;
syscall_nr = trace_get_syscall_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
/* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE) */
@@ -360,7 +360,7 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret)
int syscall_nr;
syscall_nr = trace_get_syscall_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
/* Here we're inside tp handler's rcu_read_lock_sched (__DO_TRACE()) */
@@ -567,7 +567,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
int size;
syscall_nr = trace_get_syscall_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
if (!test_bit(syscall_nr, enabled_perf_enter_syscalls))
return;
@@ -641,7 +641,7 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
int size;
syscall_nr = trace_get_syscall_nr(current, regs);
- if (syscall_nr < 0)
+ if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
if (!test_bit(syscall_nr, enabled_perf_exit_syscalls))
return;

View File

@ -1,54 +0,0 @@
From c88f7bbd8026761a615c9969d186ffa2a1a3da3c Mon Sep 17 00:00:00 2001
From: "Eric W. Biederman" <ebiederm@xmission.com>
Date: Thu, 15 Jan 2015 17:49:27 +0000
Subject: [PATCH] mnt: Prevent pivot_root from creating a loop in the mount
tree
Andy Lutomirski recently demonstrated that when chroot is used to set
the root path below the path for the new ``root'' passed to pivot_root
the pivot_root system call succeeds and leaks mounts.
In examining the code I see that starting with a new root that is
below the current root in the mount tree will result in a loop in the
mount tree after the mounts are detached and then reattached to one
another. Resulting in all kinds of ugliness including a leak of that
mounts involved in the leak of the mount loop.
Prevent this problem by ensuring that the new mount is reachable from
the current root of the mount tree.
[Added stable cc. Fixes CVE-2014-7970. --Andy]
Cc: stable@vger.kernel.org
Reported-by: Andy Lutomirski <luto@amacapital.net>
Reviewed-by: Andy Lutomirski <luto@amacapital.net>
Link: http://lkml.kernel.org/r/87bnpmihks.fsf@x220.int.ebiederm.org
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
(backported from commit 0d0826019e529f21c84687521d03f60cd241ca7d)
CVE-2014-7970
BugLink: http://bugs.launchpad.net/bugs/1383356
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Andy Whitcroft <apw@canonical.com>
Signed-off-by: Andy Whitcroft <apw@canonical.com>
Change-Id: I0fe1d090eeb4765cc49401784e44a430f9585498
---
fs/namespace.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/fs/namespace.c b/fs/namespace.c
index 912d273d970..4f47629a4e0 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2618,6 +2618,9 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
goto out4;
} else if (!is_subdir(old.dentry, new.dentry))
goto out4;
+ /* make certain new is below the root */
+ if (!is_path_reachable(new.mnt, new.dentry, &root))
+ goto out4;
br_write_lock(vfsmount_lock);
detach_mnt(new.mnt, &parent_path);
detach_mnt(root.mnt, &root_parent);

View File

@ -1,50 +0,0 @@
From 9f7d53c09a1f87ebe228b55a83c1b8f952d76260 Mon Sep 17 00:00:00 2001
From: "Eric W. Biederman" <ebiederm@xmission.com>
Date: Wed, 8 Oct 2014 10:42:27 -0700
Subject: mnt: Prevent pivot_root from creating a loop in the mount tree
commit 0d0826019e529f21c84687521d03f60cd241ca7d upstream.
Andy Lutomirski recently demonstrated that when chroot is used to set
the root path below the path for the new ``root'' passed to pivot_root
the pivot_root system call succeeds and leaks mounts.
In examining the code I see that starting with a new root that is
below the current root in the mount tree will result in a loop in the
mount tree after the mounts are detached and then reattached to one
another. Resulting in all kinds of ugliness including a leak of that
mounts involved in the leak of the mount loop.
Prevent this problem by ensuring that the new mount is reachable from
the current root of the mount tree.
[Added stable cc. Fixes CVE-2014-7970. --Andy]
Reported-by: Andy Lutomirski <luto@amacapital.net>
Reviewed-by: Andy Lutomirski <luto@amacapital.net>
Link: http://lkml.kernel.org/r/87bnpmihks.fsf@x220.int.ebiederm.org
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
[lizf: Backported to 3.4: adjust context]
Signed-off-by: Zefan Li <lizefan@huawei.com>
---
fs/namespace.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/fs/namespace.c b/fs/namespace.c
index f0f2e06..f7be8d9 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2508,6 +2508,9 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
/* make sure we can reach put_old from new_root */
if (!is_path_reachable(real_mount(old.mnt), old.dentry, &new))
goto out4;
+ /* make certain new is below the root */
+ if (!is_path_reachable(new_mnt, new.dentry, &root))
+ goto out4;
br_write_lock(vfsmount_lock);
detach_mnt(new_mnt, &parent_path);
detach_mnt(root_mnt, &root_parent);
--
cgit v1.1

View File

@ -1,47 +0,0 @@
From 0d0826019e529f21c84687521d03f60cd241ca7d Mon Sep 17 00:00:00 2001
From: "Eric W. Biederman" <ebiederm@xmission.com>
Date: Wed, 8 Oct 2014 10:42:27 -0700
Subject: mnt: Prevent pivot_root from creating a loop in the mount tree
Andy Lutomirski recently demonstrated that when chroot is used to set
the root path below the path for the new ``root'' passed to pivot_root
the pivot_root system call succeeds and leaks mounts.
In examining the code I see that starting with a new root that is
below the current root in the mount tree will result in a loop in the
mount tree after the mounts are detached and then reattached to one
another. Resulting in all kinds of ugliness including a leak of that
mounts involved in the leak of the mount loop.
Prevent this problem by ensuring that the new mount is reachable from
the current root of the mount tree.
[Added stable cc. Fixes CVE-2014-7970. --Andy]
Cc: stable@vger.kernel.org
Reported-by: Andy Lutomirski <luto@amacapital.net>
Reviewed-by: Andy Lutomirski <luto@amacapital.net>
Link: http://lkml.kernel.org/r/87bnpmihks.fsf@x220.int.ebiederm.org
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
---
fs/namespace.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/fs/namespace.c b/fs/namespace.c
index ef42d9b..74647c2 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2820,6 +2820,9 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
/* make sure we can reach put_old from new_root */
if (!is_path_reachable(old_mnt, old.dentry, &new))
goto out4;
+ /* make certain new is below the root */
+ if (!is_path_reachable(new_mnt, new.dentry, &root))
+ goto out4;
root_mp->m_count++; /* pin it so it won't go away */
lock_mount_hash();
detach_mnt(new_mnt, &parent_path);
--
cgit v1.1

View File

@ -1,94 +0,0 @@
From d7cde286daad20dd171247ea47fc5ff4868591f0 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Fri, 26 Sep 2014 11:35:42 +0200
Subject: netfilter: conntrack: disable generic tracking for known protocols
commit db29a9508a9246e77087c5531e45b2c88ec6988b upstream.
Given following iptables ruleset:
-P FORWARD DROP
-A FORWARD -m sctp --dport 9 -j ACCEPT
-A FORWARD -p tcp --dport 80 -j ACCEPT
-A FORWARD -p tcp -m conntrack -m state ESTABLISHED,RELATED -j ACCEPT
One would assume that this allows SCTP on port 9 and TCP on port 80.
Unfortunately, if the SCTP conntrack module is not loaded, this allows
*all* SCTP communication, to pass though, i.e. -p sctp -j ACCEPT,
which we think is a security issue.
This is because on the first SCTP packet on port 9, we create a dummy
"generic l4" conntrack entry without any port information (since
conntrack doesn't know how to extract this information).
All subsequent packets that are unknown will then be in established
state since they will fallback to proto_generic and will match the
'generic' entry.
Our originally proposed version [1] completely disabled generic protocol
tracking, but Jozsef suggests to not track protocols for which a more
suitable helper is available, hence we now mitigate the issue for in
tree known ct protocol helpers only, so that at least NAT and direction
information will still be preserved for others.
[1] http://www.spinics.net/lists/netfilter-devel/msg33430.html
Joint work with Daniel Borkmann.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Acked-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
net/netfilter/nf_conntrack_proto_generic.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index e2091d0..53bf12a 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -14,6 +14,30 @@
static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ;
+static bool nf_generic_should_process(u8 proto)
+{
+ switch (proto) {
+#ifdef CONFIG_NF_CT_PROTO_SCTP_MODULE
+ case IPPROTO_SCTP:
+ return false;
+#endif
+#ifdef CONFIG_NF_CT_PROTO_DCCP_MODULE
+ case IPPROTO_DCCP:
+ return false;
+#endif
+#ifdef CONFIG_NF_CT_PROTO_GRE_MODULE
+ case IPPROTO_GRE:
+ return false;
+#endif
+#ifdef CONFIG_NF_CT_PROTO_UDPLITE_MODULE
+ case IPPROTO_UDPLITE:
+ return false;
+#endif
+ default:
+ return true;
+ }
+}
+
static bool generic_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff,
struct nf_conntrack_tuple *tuple)
@@ -56,7 +80,7 @@ static int packet(struct nf_conn *ct,
static bool new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff)
{
- return true;
+ return nf_generic_should_process(nf_ct_protonum(ct));
}
#ifdef CONFIG_SYSCTL
--
cgit v1.1

View File

@ -1,88 +0,0 @@
From db29a9508a9246e77087c5531e45b2c88ec6988b Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Fri, 26 Sep 2014 11:35:42 +0200
Subject: [PATCH] netfilter: conntrack: disable generic tracking for known
protocols
Given following iptables ruleset:
-P FORWARD DROP
-A FORWARD -m sctp --dport 9 -j ACCEPT
-A FORWARD -p tcp --dport 80 -j ACCEPT
-A FORWARD -p tcp -m conntrack -m state ESTABLISHED,RELATED -j ACCEPT
One would assume that this allows SCTP on port 9 and TCP on port 80.
Unfortunately, if the SCTP conntrack module is not loaded, this allows
*all* SCTP communication, to pass though, i.e. -p sctp -j ACCEPT,
which we think is a security issue.
This is because on the first SCTP packet on port 9, we create a dummy
"generic l4" conntrack entry without any port information (since
conntrack doesn't know how to extract this information).
All subsequent packets that are unknown will then be in established
state since they will fallback to proto_generic and will match the
'generic' entry.
Our originally proposed version [1] completely disabled generic protocol
tracking, but Jozsef suggests to not track protocols for which a more
suitable helper is available, hence we now mitigate the issue for in
tree known ct protocol helpers only, so that at least NAT and direction
information will still be preserved for others.
[1] http://www.spinics.net/lists/netfilter-devel/msg33430.html
Joint work with Daniel Borkmann.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Acked-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_proto_generic.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index d25f293776482..957c1db666525 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -14,6 +14,30 @@
static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ;
+static bool nf_generic_should_process(u8 proto)
+{
+ switch (proto) {
+#ifdef CONFIG_NF_CT_PROTO_SCTP_MODULE
+ case IPPROTO_SCTP:
+ return false;
+#endif
+#ifdef CONFIG_NF_CT_PROTO_DCCP_MODULE
+ case IPPROTO_DCCP:
+ return false;
+#endif
+#ifdef CONFIG_NF_CT_PROTO_GRE_MODULE
+ case IPPROTO_GRE:
+ return false;
+#endif
+#ifdef CONFIG_NF_CT_PROTO_UDPLITE_MODULE
+ case IPPROTO_UDPLITE:
+ return false;
+#endif
+ default:
+ return true;
+ }
+}
+
static inline struct nf_generic_net *generic_pernet(struct net *net)
{
return &net->ct.nf_ct_proto.generic;
@@ -67,7 +91,7 @@ static int generic_packet(struct nf_conn *ct,
static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff, unsigned int *timeouts)
{
- return true;
+ return nf_generic_should_process(nf_ct_protonum(ct));
}
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)

View File

@ -1,51 +0,0 @@
From ee53664bda169f519ce3c6a22d378f0b946c8178 Mon Sep 17 00:00:00 2001
From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Date: Fri, 20 Dec 2013 15:10:03 +0200
Subject: [PATCH] mm: Fix NULL pointer dereference in madvise(MADV_WILLNEED)
support
Sasha Levin found a NULL pointer dereference that is due to a missing
page table lock, which in turn is due to the pmd entry in question being
a transparent huge-table entry.
The code - introduced in commit 1998cc048901 ("mm: make
madvise(MADV_WILLNEED) support swap file prefetch") - correctly checks
for this situation using pmd_none_or_trans_huge_or_clear_bad(), but it
turns out that that function doesn't work correctly.
pmd_none_or_trans_huge_or_clear_bad() expected that pmd_bad() would
trigger if the transparent hugepage bit was set, but it doesn't do that
if pmd_numa() is also set. Note that the NUMA bit only gets set on real
NUMA machines, so people trying to reproduce this on most normal
development systems would never actually trigger this.
Fix it by removing the very subtle (and subtly incorrect) expectation,
and instead just checking pmd_trans_huge() explicitly.
Reported-by: Sasha Levin <sasha.levin@oracle.com>
Acked-by: Andrea Arcangeli <aarcange@redhat.com>
[ Additionally remove the now stale test for pmd_trans_huge() inside the
pmd_bad() case - Linus ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
include/asm-generic/pgtable.h | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index b12079afbd5f2..db09234589409 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -599,11 +599,10 @@ static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
barrier();
#endif
- if (pmd_none(pmdval))
+ if (pmd_none(pmdval) || pmd_trans_huge(pmdval))
return 1;
if (unlikely(pmd_bad(pmdval))) {
- if (!pmd_trans_huge(pmdval))
- pmd_clear_bad(pmd);
+ pmd_clear_bad(pmd);
return 1;
}
return 0;

View File

@ -1,53 +0,0 @@
From 338f977f4eb441e69bb9a46eaa0ac715c931a67f 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
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.
Cc: stable@vger.kernel.org
Fixes: 2de8e0d999b8 ("mac80211: rewrite fragmentation")
Reported-by: Jouni Malinen <j@w1.fi>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
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 27c990b..97a02d3 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -878,7 +878,7 @@ static int ieee80211_fragment(struct ieee80211_tx_data *tx,
}
/* adjust first fragment's length */
- skb->len = hdrlen + per_fragm;
+ skb_trim(skb, hdrlen + per_fragm);
return 0;
}
--
cgit v1.1

View File

@ -1,16 +0,0 @@
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

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

View File

@ -1,519 +0,0 @@
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

@ -1,52 +0,0 @@
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

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

View File

@ -1,10 +0,0 @@
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

@ -1 +0,0 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL2VzcGZpeC5oIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vZXNwZml4LmgKaW5kZXggNzI5MDUxYy4uOTllZmViYiAxMDA2NDQKLS0tIGEvYXJjaC94ODYvaW5jbHVkZS9hc20vZXNwZml4LmgKKysrIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vZXNwZml4LmgKQEAgLTEsNCArMSw0IEBACi0jaWZkZWYgX0FTTV9YODZfRVNQRklYX0gKKyNpZm5kZWYgX0FTTV9YODZfRVNQRklYX0gKICNkZWZpbmUgX0FTTV9YODZfRVNQRklYX0gKIAogI2lmZGVmIENPTkZJR19YODZfNjQK

View File

@ -1,54 +0,0 @@
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

@ -1 +0,0 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L0tjb25maWcgYi9hcmNoL3g4Ni9LY29uZmlnCmluZGV4IDRiMjA4NDYuLjUyMGNkZTggMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L0tjb25maWcKKysrIGIvYXJjaC94ODYvS2NvbmZpZwpAQCAtOTcyLDYgKzk3MiwxMCBAQAogCSAgWEZyZWU4NiB0byBpbml0aWFsaXplIHNvbWUgdmlkZW8gY2FyZHMgdmlhIEJJT1MuIERpc2FibGluZyB0aGlzCiAJICBvcHRpb24gc2F2ZXMgYWJvdXQgNmsuCiAKK2NvbmZpZyBYODZfRVNQRklYNjQKKwlkZWZfYm9vbCB5CisJZGVwZW5kcyBvbiBYODZfNjQKKwogY29uZmlnIFRPU0hJQkEKIAl0cmlzdGF0ZSAiVG9zaGliYSBMYXB0b3Agc3VwcG9ydCIKIAlkZXBlbmRzIG9uIFg4Nl8zMgpkaWZmIC0tZ2l0IGEvYXJjaC94ODYva2VybmVsL01ha2VmaWxlIGIvYXJjaC94ODYva2VybmVsL01ha2VmaWxlCmluZGV4IDBmZGUyOTMuLjExMWViMzUgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC9NYWtlZmlsZQorKysgYi9hcmNoL3g4Ni9rZXJuZWwvTWFrZWZpbGUKQEAgLTI3LDcgKzI3LDcgQEAKIG9iai15CQkJKz0gc3lzY2FsbF8kKEJJVFMpLm8KIG9iai0kKENPTkZJR19YODZfNjQpCSs9IHZzeXNjYWxsXzY0Lm8KIG9iai0kKENPTkZJR19YODZfNjQpCSs9IHZzeXNjYWxsX2VtdV82NC5vCi1vYmotJChDT05GSUdfWDg2XzY0KQkrPSBlc3BmaXhfNjQubworb2JqLSQoQ09ORklHX1g4Nl9FU1BGSVg2NCkJKz0gZXNwZml4XzY0Lm8KIG9iai15CQkJKz0gYm9vdGZsYWcubyBlODIwLm8KIG9iai15CQkJKz0gcGNpLWRtYS5vIHF1aXJrcy5vIHRvcG9sb2d5Lm8ga2RlYnVnZnMubwogb2JqLXkJCQkrPSBhbHRlcm5hdGl2ZS5vIGk4MjUzLm8gcGNpLW5vbW11Lm8gaHdfYnJlYWtwb2ludC5vCmRpZmYgLS1naXQgYS9hcmNoL3g4Ni9rZXJuZWwvc21wYm9vdC5jIGIvYXJjaC94ODYva2VybmVsL3NtcGJvb3QuYwppbmRleCA5ZjAwOWNjLi5mZTg2Mjc1IDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9rZXJuZWwvc21wYm9vdC5jCisrKyBiL2FyY2gveDg2L2tlcm5lbC9zbXBib290LmMKQEAgLTI2Nyw3ICsyNjcsNyBAQAogCS8qCiAJICogRW5hYmxlIHRoZSBlc3BmaXggaGFjayBmb3IgdGhpcyBDUFUKIAkgKi8KLSNpZmRlZiBDT05GSUdfWDg2XzY0CisjaWZkZWYgQ09ORklHX1g4Nl9FU1BGSVg2NAogCWluaXRfZXNwZml4X2FwKCk7CiAjZW5kaWYKIApkaWZmIC0tZ2l0IGEvaW5pdC9tYWluLmMgYi9pbml0L21haW4uYwppbmRleCBhOWU0YTc2Li41NDRjY2NmIDEwMDY0NAotLS0gYS9pbml0L21haW4uYworKysgYi9pbml0L21haW4uYwpAQCAtNjA1LDcgKzYwNSw3IEBACiAJaWYgKGVmaV9lbmFibGVkKEVGSV9SVU5USU1FX1NFUlZJQ0VTKSkKIAkJZWZpX2VudGVyX3ZpcnR1YWxfbW9kZSgpOwogI2VuZGlmCi0jaWZkZWYgQ09ORklHX1g4Nl82NAorI2lmZGVmIENPTkZJR19YODZfRVNQRklYNjQKIAkvKiBTaG91bGQgYmUgcnVuIGJlZm9yZSB0aGUgZmlyc3Qgbm9uLWluaXQgdGhyZWFkIGlzIGNyZWF0ZWQgKi8KIAlpbml0X2VzcGZpeF9ic3AoKTsKICNlbmRpZgo=

View File

@ -1,195 +0,0 @@
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

@ -1,105 +0,0 @@
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

@ -1 +0,0 @@
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL2lycWZsYWdzLmggYi9hcmNoL3g4Ni9pbmNsdWRlL2FzbS9pcnFmbGFncy5oCmluZGV4IGJiYTNjZjguLjBhOGI1MTkgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL2lycWZsYWdzLmgKKysrIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vaXJxZmxhZ3MuaApAQCAtMTI5LDcgKzEyOSw3IEBACiAKICNkZWZpbmUgUEFSQVZJUlRfQURKVVNUX0VYQ0VQVElPTl9GUkFNRQkvKiAgKi8KIAotI2RlZmluZSBJTlRFUlJVUFRfUkVUVVJOCWlyZXRxCisjZGVmaW5lIElOVEVSUlVQVF9SRVRVUk4Jam1wIG5hdGl2ZV9pcmV0CiAjZGVmaW5lIFVTRVJHU19TWVNSRVQ2NAkJCQlcCiAJc3dhcGdzOwkJCQkJXAogCXN5c3JldHE7CmRpZmYgLS1naXQgYS9hcmNoL3g4Ni9rZXJuZWwvZW50cnlfNjQuUyBiL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TCmluZGV4IGY5MzE1ZDkuLmRiMjMwZjggMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TCisrKyBiL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TCkBAIC0xMDU2LDI3ICsxMDU2LDI0IEBACiAJUkVTVE9SRV9BUkdTIDEsOCwxCiAKIGlycV9yZXR1cm46CisJSU5URVJSVVBUX1JFVFVSTgorCitFTlRSWShuYXRpdmVfaXJldCkKIAkvKgogCSAqIEFyZSB3ZSByZXR1cm5pbmcgdG8gYSBzdGFjayBzZWdtZW50IGZyb20gdGhlIExEVD8gIE5vdGU6IGluCiAJICogNjQtYml0IG1vZGUgU1M6UlNQIG9uIHRoZSBleGNlcHRpb24gc3RhY2sgaXMgYWx3YXlzIHZhbGlkLgogCSAqLwogI2lmZGVmIENPTkZJR19YODZfRVNQRklYNjQKIAl0ZXN0YiAkNCwoU1MtUklQKSglcnNwKQotCWpueiBpcnFfcmV0dXJuX2xkdAorCWpueiBuYXRpdmVfaXJxX3JldHVybl9sZHQKICNlbmRpZgogCi1pcnFfcmV0dXJuX2lyZXQ6Ci0JSU5URVJSVVBUX1JFVFVSTgotCV9BU01fRVhUQUJMRShpcnFfcmV0dXJuX2lyZXQsIGJhZF9pcmV0KQotCi0jaWZkZWYgQ09ORklHX1BBUkFWSVJUCi1FTlRSWShuYXRpdmVfaXJldCkKK25hdGl2ZV9pcnFfcmV0dXJuX2lyZXQ6CiAJaXJldHEKLQlfQVNNX0VYVEFCTEUobmF0aXZlX2lyZXQsIGJhZF9pcmV0KQotI2VuZGlmCisJX0FTTV9FWFRBQkxFKG5hdGl2ZV9pcnFfcmV0dXJuX2lyZXQsIGJhZF9pcmV0KQogCiAjaWZkZWYgQ09ORklHX1g4Nl9FU1BGSVg2NAotaXJxX3JldHVybl9sZHQ6CituYXRpdmVfaXJxX3JldHVybl9sZHQ6CiAJcHVzaHFfY2ZpICVyYXgKIAlwdXNocV9jZmkgJXJkaQogCVNXQVBHUwpAQCAtMTA5OCw3ICsxMDk1LDcgQEAKIAlTV0FQR1MKIAltb3ZxICVyYXgsJXJzcAogCXBvcHFfY2ZpICVyYXgKLQlqbXAgaXJxX3JldHVybl9pcmV0CisJam1wIG5hdGl2ZV9pcnFfcmV0dXJuX2lyZXQKICNlbmRpZgogCiAJLnNlY3Rpb24gLmZpeHVwLCJheCIKQEAgLTExODQsMTMgKzExODEsOCBAQAogCWNtcGwgJF9fS0VSTkVMX0NTLENTKCVyZGkpCiAJam5lIGRvX2RvdWJsZV9mYXVsdAogCW1vdnEgUklQKCVyZGkpLCVyYXgKLQljbXBxICRpcnFfcmV0dXJuX2lyZXQsJXJheAotI2lmZGVmIENPTkZJR19QQVJBVklSVAotCWplIDFmCi0JY21wcSAkbmF0aXZlX2lyZXQsJXJheAotI2VuZGlmCisJY21wcSAkbmF0aXZlX2lycV9yZXR1cm5faXJldCwlcmF4CiAJam5lIGRvX2RvdWJsZV9mYXVsdAkJLyogVGhpcyBzaG91bGRuJ3QgaGFwcGVuLi4uICovCi0xOgogCW1vdnEgUEVSX0NQVV9WQVIoa2VybmVsX3N0YWNrKSwlcmF4CiAJc3VicSAkKDYqOC1LRVJORUxfU1RBQ0tfT0ZGU0VUKSwlcmF4CS8qIFJlc2V0IHRvIG9yaWdpbmFsIHN0YWNrICovCiAJbW92cSAlcmF4LFJTUCglcmRpKQpAQCAtMTY1OCw3ICsxNjUwLDcgQEAKICAqLwogZXJyb3Jfa2VybmVsc3BhY2U6CiAJaW5jbCAlZWJ4Ci0JbGVhcSBpcnFfcmV0dXJuX2lyZXQoJXJpcCksJXJjeAorCWxlYXEgbmF0aXZlX2lycV9yZXR1cm5faXJldCglcmlwKSwlcmN4CiAJY21wcSAlcmN4LFJJUCs4KCVyc3ApCiAJamUgZXJyb3Jfc3dhcGdzCiAJbW92bCAlZWN4LCVlYXgJLyogemVybyBleHRlbmQgKi8KZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC9wYXJhdmlydF9wYXRjaF82NC5jIGIvYXJjaC94ODYva2VybmVsL3BhcmF2aXJ0X3BhdGNoXzY0LmMKaW5kZXggM2YwOGYzNC4uYTFkYTY3MyAxMDA2NDQKLS0tIGEvYXJjaC94ODYva2VybmVsL3BhcmF2aXJ0X3BhdGNoXzY0LmMKKysrIGIvYXJjaC94ODYva2VybmVsL3BhcmF2aXJ0X3BhdGNoXzY0LmMKQEAgLTYsNyArNiw2IEBACiBERUZfTkFUSVZFKHB2X2lycV9vcHMsIGlycV9lbmFibGUsICJzdGkiKTsKIERFRl9OQVRJVkUocHZfaXJxX29wcywgcmVzdG9yZV9mbCwgInB1c2hxICVyZGk7IHBvcGZxIik7CiBERUZfTkFUSVZFKHB2X2lycV9vcHMsIHNhdmVfZmwsICJwdXNoZnE7IHBvcHEgJXJheCIpOwotREVGX05BVElWRShwdl9jcHVfb3BzLCBpcmV0LCAiaXJldHEiKTsKIERFRl9OQVRJVkUocHZfbW11X29wcywgcmVhZF9jcjIsICJtb3ZxICVjcjIsICVyYXgiKTsKIERFRl9OQVRJVkUocHZfbW11X29wcywgcmVhZF9jcjMsICJtb3ZxICVjcjMsICVyYXgiKTsKIERFRl9OQVRJVkUocHZfbW11X29wcywgd3JpdGVfY3IzLCAibW92cSAlcmRpLCAlY3IzIik7CkBAIC01MCw3ICs0OSw2IEBACiAJCVBBVENIX1NJVEUocHZfaXJxX29wcywgc2F2ZV9mbCk7CiAJCVBBVENIX1NJVEUocHZfaXJxX29wcywgaXJxX2VuYWJsZSk7CiAJCVBBVENIX1NJVEUocHZfaXJxX29wcywgaXJxX2Rpc2FibGUpOwotCQlQQVRDSF9TSVRFKHB2X2NwdV9vcHMsIGlyZXQpOwogCQlQQVRDSF9TSVRFKHB2X2NwdV9vcHMsIGlycV9lbmFibGVfc3lzZXhpdCk7CiAJCVBBVENIX1NJVEUocHZfY3B1X29wcywgdXNlcmdzX3N5c3JldDMyKTsKIAkJUEFUQ0hfU0lURShwdl9jcHVfb3BzLCB1c2VyZ3Nfc3lzcmV0NjQpOwo=

View File

@ -1,30 +0,0 @@
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

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

View File

@ -1,94 +0,0 @@
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

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

View File

@ -1,101 +0,0 @@
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

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

View File

@ -1,55 +0,0 @@
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

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

View File

@ -1,55 +0,0 @@
From f54e18f1b831c92f6512d2eedb224cd63d607d3d 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
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>
CC: stable@vger.kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
---
fs/isofs/rock.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index f488bba..bb63254 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,47 +0,0 @@
From a3a8784454692dd72e5d5d34dcdab17b4420e74c 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
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>
---
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 9609a7f..c795237 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -148,12 +148,12 @@ static noinline void key_gc_unused_keys(struct list_head *keys)
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,37 +0,0 @@
From f2d130454e46c3989af1b4f882b6a666d24fa2e0 Mon Sep 17 00:00:00 2001
From: Michael Halcrow <mhalcrow@google.com>
Date: Wed, 26 Nov 2014 09:09:16 -0800
Subject: eCryptfs: Remove buggy and unnecessary write in file name decode
routine
commit 942080643bce061c3dd9d5718d3b745dcb39a8bc upstream.
Dmitry Chernenkov used KASAN to discover that eCryptfs writes past the
end of the allocated buffer during encrypted filename decoding. This
fix corrects the issue by getting rid of the unnecessary 0 write when
the current bit offset is 2.
Signed-off-by: Michael Halcrow <mhalcrow@google.com>
Reported-by: Dmitry Chernenkov <dmitryc@google.com>
Suggested-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
fs/ecryptfs/crypto.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 68b19ab..dceedec 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -2038,7 +2038,6 @@ ecryptfs_decode_from_filename(unsigned char *dst, size_t *dst_size,
break;
case 2:
dst[dst_byte_offset++] |= (src_byte);
- dst[dst_byte_offset] = 0;
current_bit_offset = 0;
break;
}
--
cgit v1.1

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