mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-10-01 01:35:54 -04:00
Move Linux patches out of repo
This commit is contained in:
parent
39337477bf
commit
30e0d5e980
@ -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.
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
@ -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;
|
@ -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:
|
@ -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);
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
@ -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)
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
@ -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);
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
@ -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;
|
@ -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
|
||||
|
@ -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
|
@ -1 +0,0 @@
|
||||
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC9lbnRyeV8zMi5TIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzMyLlMKaW5kZXggOGYzZTJkZS4uNDFiYWExZiAxMDA2NDQKLS0tIGEvYXJjaC94ODYva2VybmVsL2VudHJ5XzMyLlMKKysrIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzMyLlMKQEAgLTU1NCwxMSArNTU0LDYgQEAKIAogCUNGSV9SRVNUT1JFX1NUQVRFCiBsZHRfc3M6Ci0JbGFybCBQVF9PTERTUyglZXNwKSwgJWVheAotCWpueiByZXN0b3JlX25vY2hlY2sKLQl0ZXN0bCAkMHgwMDQwMDAwMCwgJWVheAkJIyByZXR1cm5pbmcgdG8gMzJiaXQgc3RhY2s/Ci0Jam56IHJlc3RvcmVfbm9jaGVjawkJIyBhbGxyaWdodCwgbm9ybWFsIHJldHVybgotCiAjaWZkZWYgQ09ORklHX1BBUkFWSVJUCiAJLyoKIAkgKiBUaGUga2VybmVsIGNhbid0IHJ1biBvbiBhIG5vbi1mbGF0IHN0YWNrIGlmIHBhcmF2aXJ0IG1vZGUK
|
@ -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
@ -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
|
@ -1 +0,0 @@
|
||||
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL2VzcGZpeC5oIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vZXNwZml4LmgKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMC4uNzI5MDUxYwotLS0gL2Rldi9udWxsCisrKyBiL2FyY2gveDg2L2luY2x1ZGUvYXNtL2VzcGZpeC5oCkBAIC0wLDAgKzEsMTYgQEAKKyNpZmRlZiBfQVNNX1g4Nl9FU1BGSVhfSAorI2RlZmluZSBfQVNNX1g4Nl9FU1BGSVhfSAorCisjaWZkZWYgQ09ORklHX1g4Nl82NAorCisjaW5jbHVkZSA8YXNtL3BlcmNwdS5oPgorCitERUNMQVJFX1BFUl9DUFVfUkVBRF9NT1NUTFkodW5zaWduZWQgbG9uZywgZXNwZml4X3N0YWNrKTsKK0RFQ0xBUkVfUEVSX0NQVV9SRUFEX01PU1RMWSh1bnNpZ25lZCBsb25nLCBlc3BmaXhfd2FkZHIpOworCitleHRlcm4gdm9pZCBpbml0X2VzcGZpeF9ic3Aodm9pZCk7CitleHRlcm4gdm9pZCBpbml0X2VzcGZpeF9hcCh2b2lkKTsKKworI2VuZGlmIC8qIENPTkZJR19YODZfNjQgKi8KKworI2VuZGlmIC8qIF9BU01fWDg2X0VTUEZJWF9IICovCmRpZmYgLS1naXQgYS9hcmNoL3g4Ni9pbmNsdWRlL2FzbS9zZXR1cC5oIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vc2V0dXAuaAppbmRleCA5Mzc5N2QxLi4yZTMyN2YxIDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9pbmNsdWRlL2FzbS9zZXR1cC5oCisrKyBiL2FyY2gveDg2L2luY2x1ZGUvYXNtL3NldHVwLmgKQEAgLTYwLDExICs2MCwxMCBAQAogc3RhdGljIGlubGluZSB2b2lkIHg4Nl9jZTQxMDBfZWFybHlfc2V0dXAodm9pZCkgeyB9CiAjZW5kaWYKIAotZXh0ZXJuIHZvaWQgaW5pdF9lc3BmaXhfYnNwKHZvaWQpOwotZXh0ZXJuIHZvaWQgaW5pdF9lc3BmaXhfYXAodm9pZCk7Ci0KICNpZm5kZWYgX1NFVFVQCiAKKyNpbmNsdWRlIDxhc20vZXNwZml4Lmg+CisKIC8qCiAgKiBUaGlzIGlzIHNldCB1cCBieSB0aGUgc2V0dXAtcm91dGluZSBhdCBib290LXRpbWUKICAqLwpkaWZmIC0tZ2l0IGEvYXJjaC94ODYva2VybmVsL2VzcGZpeF82NC5jIGIvYXJjaC94ODYva2VybmVsL2VzcGZpeF82NC5jCmluZGV4IDhhNjRkYTMuLjZhZmJiMTYgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC9lc3BmaXhfNjQuYworKysgYi9hcmNoL3g4Ni9rZXJuZWwvZXNwZml4XzY0LmMKQEAgLTQwLDYgKzQwLDcgQEAKICNpbmNsdWRlIDxhc20vcGd0YWJsZS5oPgogI2luY2x1ZGUgPGFzbS9wZ2FsbG9jLmg+CiAjaW5jbHVkZSA8YXNtL3NldHVwLmg+CisjaW5jbHVkZSA8YXNtL2VzcGZpeC5oPgogCiAvKgogICogTm90ZTogd2Ugb25seSBuZWVkIDYqOCA9IDQ4IGJ5dGVzIGZvciB0aGUgZXNwZml4IHN0YWNrLCBidXQgcm91bmQK
|
@ -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
|
@ -1 +0,0 @@
|
||||
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL2VzcGZpeC5oIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vZXNwZml4LmgKaW5kZXggNzI5MDUxYy4uOTllZmViYiAxMDA2NDQKLS0tIGEvYXJjaC94ODYvaW5jbHVkZS9hc20vZXNwZml4LmgKKysrIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vZXNwZml4LmgKQEAgLTEsNCArMSw0IEBACi0jaWZkZWYgX0FTTV9YODZfRVNQRklYX0gKKyNpZm5kZWYgX0FTTV9YODZfRVNQRklYX0gKICNkZWZpbmUgX0FTTV9YODZfRVNQRklYX0gKIAogI2lmZGVmIENPTkZJR19YODZfNjQK
|
@ -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
|
@ -1 +0,0 @@
|
||||
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L0tjb25maWcgYi9hcmNoL3g4Ni9LY29uZmlnCmluZGV4IDRiMjA4NDYuLjUyMGNkZTggMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L0tjb25maWcKKysrIGIvYXJjaC94ODYvS2NvbmZpZwpAQCAtOTcyLDYgKzk3MiwxMCBAQAogCSAgWEZyZWU4NiB0byBpbml0aWFsaXplIHNvbWUgdmlkZW8gY2FyZHMgdmlhIEJJT1MuIERpc2FibGluZyB0aGlzCiAJICBvcHRpb24gc2F2ZXMgYWJvdXQgNmsuCiAKK2NvbmZpZyBYODZfRVNQRklYNjQKKwlkZWZfYm9vbCB5CisJZGVwZW5kcyBvbiBYODZfNjQKKwogY29uZmlnIFRPU0hJQkEKIAl0cmlzdGF0ZSAiVG9zaGliYSBMYXB0b3Agc3VwcG9ydCIKIAlkZXBlbmRzIG9uIFg4Nl8zMgpkaWZmIC0tZ2l0IGEvYXJjaC94ODYva2VybmVsL01ha2VmaWxlIGIvYXJjaC94ODYva2VybmVsL01ha2VmaWxlCmluZGV4IDBmZGUyOTMuLjExMWViMzUgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC9NYWtlZmlsZQorKysgYi9hcmNoL3g4Ni9rZXJuZWwvTWFrZWZpbGUKQEAgLTI3LDcgKzI3LDcgQEAKIG9iai15CQkJKz0gc3lzY2FsbF8kKEJJVFMpLm8KIG9iai0kKENPTkZJR19YODZfNjQpCSs9IHZzeXNjYWxsXzY0Lm8KIG9iai0kKENPTkZJR19YODZfNjQpCSs9IHZzeXNjYWxsX2VtdV82NC5vCi1vYmotJChDT05GSUdfWDg2XzY0KQkrPSBlc3BmaXhfNjQubworb2JqLSQoQ09ORklHX1g4Nl9FU1BGSVg2NCkJKz0gZXNwZml4XzY0Lm8KIG9iai15CQkJKz0gYm9vdGZsYWcubyBlODIwLm8KIG9iai15CQkJKz0gcGNpLWRtYS5vIHF1aXJrcy5vIHRvcG9sb2d5Lm8ga2RlYnVnZnMubwogb2JqLXkJCQkrPSBhbHRlcm5hdGl2ZS5vIGk4MjUzLm8gcGNpLW5vbW11Lm8gaHdfYnJlYWtwb2ludC5vCmRpZmYgLS1naXQgYS9hcmNoL3g4Ni9rZXJuZWwvc21wYm9vdC5jIGIvYXJjaC94ODYva2VybmVsL3NtcGJvb3QuYwppbmRleCA5ZjAwOWNjLi5mZTg2Mjc1IDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9rZXJuZWwvc21wYm9vdC5jCisrKyBiL2FyY2gveDg2L2tlcm5lbC9zbXBib290LmMKQEAgLTI2Nyw3ICsyNjcsNyBAQAogCS8qCiAJICogRW5hYmxlIHRoZSBlc3BmaXggaGFjayBmb3IgdGhpcyBDUFUKIAkgKi8KLSNpZmRlZiBDT05GSUdfWDg2XzY0CisjaWZkZWYgQ09ORklHX1g4Nl9FU1BGSVg2NAogCWluaXRfZXNwZml4X2FwKCk7CiAjZW5kaWYKIApkaWZmIC0tZ2l0IGEvaW5pdC9tYWluLmMgYi9pbml0L21haW4uYwppbmRleCBhOWU0YTc2Li41NDRjY2NmIDEwMDY0NAotLS0gYS9pbml0L21haW4uYworKysgYi9pbml0L21haW4uYwpAQCAtNjA1LDcgKzYwNSw3IEBACiAJaWYgKGVmaV9lbmFibGVkKEVGSV9SVU5USU1FX1NFUlZJQ0VTKSkKIAkJZWZpX2VudGVyX3ZpcnR1YWxfbW9kZSgpOwogI2VuZGlmCi0jaWZkZWYgQ09ORklHX1g4Nl82NAorI2lmZGVmIENPTkZJR19YODZfRVNQRklYNjQKIAkvKiBTaG91bGQgYmUgcnVuIGJlZm9yZSB0aGUgZmlyc3Qgbm9uLWluaXQgdGhyZWFkIGlzIGNyZWF0ZWQgKi8KIAlpbml0X2VzcGZpeF9ic3AoKTsKICNlbmRpZgo=
|
@ -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
@ -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);
|
@ -1 +0,0 @@
|
||||
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL2lycWZsYWdzLmggYi9hcmNoL3g4Ni9pbmNsdWRlL2FzbS9pcnFmbGFncy5oCmluZGV4IGJiYTNjZjguLjBhOGI1MTkgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL2lycWZsYWdzLmgKKysrIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vaXJxZmxhZ3MuaApAQCAtMTI5LDcgKzEyOSw3IEBACiAKICNkZWZpbmUgUEFSQVZJUlRfQURKVVNUX0VYQ0VQVElPTl9GUkFNRQkvKiAgKi8KIAotI2RlZmluZSBJTlRFUlJVUFRfUkVUVVJOCWlyZXRxCisjZGVmaW5lIElOVEVSUlVQVF9SRVRVUk4Jam1wIG5hdGl2ZV9pcmV0CiAjZGVmaW5lIFVTRVJHU19TWVNSRVQ2NAkJCQlcCiAJc3dhcGdzOwkJCQkJXAogCXN5c3JldHE7CmRpZmYgLS1naXQgYS9hcmNoL3g4Ni9rZXJuZWwvZW50cnlfNjQuUyBiL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TCmluZGV4IGY5MzE1ZDkuLmRiMjMwZjggMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TCisrKyBiL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TCkBAIC0xMDU2LDI3ICsxMDU2LDI0IEBACiAJUkVTVE9SRV9BUkdTIDEsOCwxCiAKIGlycV9yZXR1cm46CisJSU5URVJSVVBUX1JFVFVSTgorCitFTlRSWShuYXRpdmVfaXJldCkKIAkvKgogCSAqIEFyZSB3ZSByZXR1cm5pbmcgdG8gYSBzdGFjayBzZWdtZW50IGZyb20gdGhlIExEVD8gIE5vdGU6IGluCiAJICogNjQtYml0IG1vZGUgU1M6UlNQIG9uIHRoZSBleGNlcHRpb24gc3RhY2sgaXMgYWx3YXlzIHZhbGlkLgogCSAqLwogI2lmZGVmIENPTkZJR19YODZfRVNQRklYNjQKIAl0ZXN0YiAkNCwoU1MtUklQKSglcnNwKQotCWpueiBpcnFfcmV0dXJuX2xkdAorCWpueiBuYXRpdmVfaXJxX3JldHVybl9sZHQKICNlbmRpZgogCi1pcnFfcmV0dXJuX2lyZXQ6Ci0JSU5URVJSVVBUX1JFVFVSTgotCV9BU01fRVhUQUJMRShpcnFfcmV0dXJuX2lyZXQsIGJhZF9pcmV0KQotCi0jaWZkZWYgQ09ORklHX1BBUkFWSVJUCi1FTlRSWShuYXRpdmVfaXJldCkKK25hdGl2ZV9pcnFfcmV0dXJuX2lyZXQ6CiAJaXJldHEKLQlfQVNNX0VYVEFCTEUobmF0aXZlX2lyZXQsIGJhZF9pcmV0KQotI2VuZGlmCisJX0FTTV9FWFRBQkxFKG5hdGl2ZV9pcnFfcmV0dXJuX2lyZXQsIGJhZF9pcmV0KQogCiAjaWZkZWYgQ09ORklHX1g4Nl9FU1BGSVg2NAotaXJxX3JldHVybl9sZHQ6CituYXRpdmVfaXJxX3JldHVybl9sZHQ6CiAJcHVzaHFfY2ZpICVyYXgKIAlwdXNocV9jZmkgJXJkaQogCVNXQVBHUwpAQCAtMTA5OCw3ICsxMDk1LDcgQEAKIAlTV0FQR1MKIAltb3ZxICVyYXgsJXJzcAogCXBvcHFfY2ZpICVyYXgKLQlqbXAgaXJxX3JldHVybl9pcmV0CisJam1wIG5hdGl2ZV9pcnFfcmV0dXJuX2lyZXQKICNlbmRpZgogCiAJLnNlY3Rpb24gLmZpeHVwLCJheCIKQEAgLTExODQsMTMgKzExODEsOCBAQAogCWNtcGwgJF9fS0VSTkVMX0NTLENTKCVyZGkpCiAJam5lIGRvX2RvdWJsZV9mYXVsdAogCW1vdnEgUklQKCVyZGkpLCVyYXgKLQljbXBxICRpcnFfcmV0dXJuX2lyZXQsJXJheAotI2lmZGVmIENPTkZJR19QQVJBVklSVAotCWplIDFmCi0JY21wcSAkbmF0aXZlX2lyZXQsJXJheAotI2VuZGlmCisJY21wcSAkbmF0aXZlX2lycV9yZXR1cm5faXJldCwlcmF4CiAJam5lIGRvX2RvdWJsZV9mYXVsdAkJLyogVGhpcyBzaG91bGRuJ3QgaGFwcGVuLi4uICovCi0xOgogCW1vdnEgUEVSX0NQVV9WQVIoa2VybmVsX3N0YWNrKSwlcmF4CiAJc3VicSAkKDYqOC1LRVJORUxfU1RBQ0tfT0ZGU0VUKSwlcmF4CS8qIFJlc2V0IHRvIG9yaWdpbmFsIHN0YWNrICovCiAJbW92cSAlcmF4LFJTUCglcmRpKQpAQCAtMTY1OCw3ICsxNjUwLDcgQEAKICAqLwogZXJyb3Jfa2VybmVsc3BhY2U6CiAJaW5jbCAlZWJ4Ci0JbGVhcSBpcnFfcmV0dXJuX2lyZXQoJXJpcCksJXJjeAorCWxlYXEgbmF0aXZlX2lycV9yZXR1cm5faXJldCglcmlwKSwlcmN4CiAJY21wcSAlcmN4LFJJUCs4KCVyc3ApCiAJamUgZXJyb3Jfc3dhcGdzCiAJbW92bCAlZWN4LCVlYXgJLyogemVybyBleHRlbmQgKi8KZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC9wYXJhdmlydF9wYXRjaF82NC5jIGIvYXJjaC94ODYva2VybmVsL3BhcmF2aXJ0X3BhdGNoXzY0LmMKaW5kZXggM2YwOGYzNC4uYTFkYTY3MyAxMDA2NDQKLS0tIGEvYXJjaC94ODYva2VybmVsL3BhcmF2aXJ0X3BhdGNoXzY0LmMKKysrIGIvYXJjaC94ODYva2VybmVsL3BhcmF2aXJ0X3BhdGNoXzY0LmMKQEAgLTYsNyArNiw2IEBACiBERUZfTkFUSVZFKHB2X2lycV9vcHMsIGlycV9lbmFibGUsICJzdGkiKTsKIERFRl9OQVRJVkUocHZfaXJxX29wcywgcmVzdG9yZV9mbCwgInB1c2hxICVyZGk7IHBvcGZxIik7CiBERUZfTkFUSVZFKHB2X2lycV9vcHMsIHNhdmVfZmwsICJwdXNoZnE7IHBvcHEgJXJheCIpOwotREVGX05BVElWRShwdl9jcHVfb3BzLCBpcmV0LCAiaXJldHEiKTsKIERFRl9OQVRJVkUocHZfbW11X29wcywgcmVhZF9jcjIsICJtb3ZxICVjcjIsICVyYXgiKTsKIERFRl9OQVRJVkUocHZfbW11X29wcywgcmVhZF9jcjMsICJtb3ZxICVjcjMsICVyYXgiKTsKIERFRl9OQVRJVkUocHZfbW11X29wcywgd3JpdGVfY3IzLCAibW92cSAlcmRpLCAlY3IzIik7CkBAIC01MCw3ICs0OSw2IEBACiAJCVBBVENIX1NJVEUocHZfaXJxX29wcywgc2F2ZV9mbCk7CiAJCVBBVENIX1NJVEUocHZfaXJxX29wcywgaXJxX2VuYWJsZSk7CiAJCVBBVENIX1NJVEUocHZfaXJxX29wcywgaXJxX2Rpc2FibGUpOwotCQlQQVRDSF9TSVRFKHB2X2NwdV9vcHMsIGlyZXQpOwogCQlQQVRDSF9TSVRFKHB2X2NwdV9vcHMsIGlycV9lbmFibGVfc3lzZXhpdCk7CiAJCVBBVENIX1NJVEUocHZfY3B1X29wcywgdXNlcmdzX3N5c3JldDMyKTsKIAkJUEFUQ0hfU0lURShwdl9jcHVfb3BzLCB1c2VyZ3Nfc3lzcmV0NjQpOwo=
|
@ -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);
|
||||
|
@ -1 +0,0 @@
|
||||
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC9lc3BmaXhfNjQuYyBiL2FyY2gveDg2L2tlcm5lbC9lc3BmaXhfNjQuYwppbmRleCA2YWZiYjE2Li45NGQ4NTdmIDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9rZXJuZWwvZXNwZml4XzY0LmMKKysrIGIvYXJjaC94ODYva2VybmVsL2VzcGZpeF82NC5jCkBAIC0xNzUsNyArMTc1LDcgQEAKIAlpZiAoIXB1ZF9wcmVzZW50KHB1ZCkpIHsKIAkJcG1kX3AgPSAocG1kX3QgKilfX2dldF9mcmVlX3BhZ2UoUEdBTExPQ19HRlApOwogCQlwdWQgPSBfX3B1ZChfX3BhKHBtZF9wKSB8IChQR1RBQkxFX1BST1QgJiBwdGVtYXNrKSk7Ci0JCXBhcmF2aXJ0X2FsbG9jX3B1ZCgmaW5pdF9tbSwgX19wYShwbWRfcCkgPj4gUEFHRV9TSElGVCk7CisJCXBhcmF2aXJ0X2FsbG9jX3BtZCgmaW5pdF9tbSwgX19wYShwbWRfcCkgPj4gUEFHRV9TSElGVCk7CiAJCWZvciAobiA9IDA7IG4gPCBFU1BGSVhfUFVEX0NMT05FUzsgbisrKQogCQkJc2V0X3B1ZCgmcHVkX3Bbbl0sIHB1ZCk7CiAJfQpAQCAtMTg1LDcgKzE4NSw3IEBACiAJaWYgKCFwbWRfcHJlc2VudChwbWQpKSB7CiAJCXB0ZV9wID0gKHB0ZV90ICopX19nZXRfZnJlZV9wYWdlKFBHQUxMT0NfR0ZQKTsKIAkJcG1kID0gX19wbWQoX19wYShwdGVfcCkgfCAoUEdUQUJMRV9QUk9UICYgcHRlbWFzaykpOwotCQlwYXJhdmlydF9hbGxvY19wbWQoJmluaXRfbW0sIF9fcGEocHRlX3ApID4+IFBBR0VfU0hJRlQpOworCQlwYXJhdmlydF9hbGxvY19wdGUoJmluaXRfbW0sIF9fcGEocHRlX3ApID4+IFBBR0VfU0hJRlQpOwogCQlmb3IgKG4gPSAwOyBuIDwgRVNQRklYX1BNRF9DTE9ORVM7IG4rKykKIAkJCXNldF9wbWQoJnBtZF9wW25dLCBwbWQpOwogCX0KQEAgLTE5Myw3ICsxOTMsNiBAQAogCXB0ZV9wID0gcHRlX29mZnNldF9rZXJuZWwoJnBtZCwgYWRkcik7CiAJc3RhY2tfcGFnZSA9ICh2b2lkICopX19nZXRfZnJlZV9wYWdlKEdGUF9LRVJORUwpOwogCXB0ZSA9IF9fcHRlKF9fcGEoc3RhY2tfcGFnZSkgfCAoX19QQUdFX0tFUk5FTF9STyAmIHB0ZW1hc2spKTsKLQlwYXJhdmlydF9hbGxvY19wdGUoJmluaXRfbW0sIF9fcGEoc3RhY2tfcGFnZSkgPj4gUEFHRV9TSElGVCk7CiAJZm9yIChuID0gMDsgbiA8IEVTUEZJWF9QVEVfQ0xPTkVTOyBuKyspCiAJCXNldF9wdGUoJnB0ZV9wW24qUFRFX1NUUklERV0sIHB0ZSk7CiAK
|
@ -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);
|
@ -1 +0,0 @@
|
||||
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKaW5kZXggZGIyMzBmOC4uMWE0NTRkMCAxMDA2NDQKLS0tIGEvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKKysrIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKQEAgLTEwNjgsNiArMTA2OCw3IEBACiAJam56IG5hdGl2ZV9pcnFfcmV0dXJuX2xkdAogI2VuZGlmCiAKKy5nbG9iYWwgbmF0aXZlX2lycV9yZXR1cm5faXJldAogbmF0aXZlX2lycV9yZXR1cm5faXJldDoKIAlpcmV0cQogCV9BU01fRVhUQUJMRShuYXRpdmVfaXJxX3JldHVybl9pcmV0LCBiYWRfaXJldCkKQEAgLTExNjQsMzcgKzExNjUsNiBAQAogCUNGSV9FTkRQUk9DCiBFTkQoY29tbW9uX2ludGVycnVwdCkKIAotCS8qCi0JICogSWYgSVJFVCB0YWtlcyBhIGZhdWx0IG9uIHRoZSBlc3BmaXggc3RhY2ssIHRoZW4gd2UKLQkgKiBlbmQgdXAgcHJvbW90aW5nIGl0IHRvIGEgZG91YmxlZmF1bHQuICBJbiB0aGF0IGNhc2UsCi0JICogbW9kaWZ5IHRoZSBzdGFjayB0byBtYWtlIGl0IGxvb2sgbGlrZSB3ZSBqdXN0IGVudGVyZWQKLQkgKiB0aGUgI0dQIGhhbmRsZXIgZnJvbSB1c2VyIHNwYWNlLCBzaW1pbGFyIHRvIGJhZF9pcmV0LgotCSAqLwotI2lmZGVmIENPTkZJR19YODZfRVNQRklYNjQKLQlBTElHTgotX19kb19kb3VibGVfZmF1bHQ6Ci0JWENQVF9GUkFNRSAxIFJESSs4Ci0JbW92cSBSU1AoJXJkaSksJXJheAkJLyogVHJhcCBvbiB0aGUgZXNwZml4IHN0YWNrPyAqLwotCXNhcnEgJFBHRElSX1NISUZULCVyYXgKLQljbXBsICRFU1BGSVhfUEdEX0VOVFJZLCVlYXgKLQlqbmUgZG9fZG91YmxlX2ZhdWx0CQkvKiBObywganVzdCBkZWxpdmVyIHRoZSBmYXVsdCAqLwotCWNtcGwgJF9fS0VSTkVMX0NTLENTKCVyZGkpCi0Jam5lIGRvX2RvdWJsZV9mYXVsdAotCW1vdnEgUklQKCVyZGkpLCVyYXgKLQljbXBxICRuYXRpdmVfaXJxX3JldHVybl9pcmV0LCVyYXgKLQlqbmUgZG9fZG91YmxlX2ZhdWx0CQkvKiBUaGlzIHNob3VsZG4ndCBoYXBwZW4uLi4gKi8KLQltb3ZxIFBFUl9DUFVfVkFSKGtlcm5lbF9zdGFjayksJXJheAotCXN1YnEgJCg2KjgtS0VSTkVMX1NUQUNLX09GRlNFVCksJXJheAkvKiBSZXNldCB0byBvcmlnaW5hbCBzdGFjayAqLwotCW1vdnEgJXJheCxSU1AoJXJkaSkKLQltb3ZxICQwLCglcmF4KQkJCS8qIE1pc3NpbmcgKGxvc3QpICNHUCBlcnJvciBjb2RlICovCi0JbW92cSAkZ2VuZXJhbF9wcm90ZWN0aW9uLFJJUCglcmRpKQotCXJldHEKLQlDRklfRU5EUFJPQwotRU5EKF9fZG9fZG91YmxlX2ZhdWx0KQotI2Vsc2UKLSMgZGVmaW5lIF9fZG9fZG91YmxlX2ZhdWx0IGRvX2RvdWJsZV9mYXVsdAotI2VuZGlmCi0KIC8qCiAgKiBFbmQgb2Yga3Byb2JlcyBzZWN0aW9uCiAgKi8KQEAgLTEzNjMsNyArMTMzMyw3IEBACiB6ZXJvZW50cnkgYm91bmRzIGRvX2JvdW5kcwogemVyb2VudHJ5IGludmFsaWRfb3AgZG9faW52YWxpZF9vcAogemVyb2VudHJ5IGRldmljZV9ub3RfYXZhaWxhYmxlIGRvX2RldmljZV9ub3RfYXZhaWxhYmxlCi1wYXJhbm9pZGVycm9yZW50cnkgZG91YmxlX2ZhdWx0IF9fZG9fZG91YmxlX2ZhdWx0CitwYXJhbm9pZGVycm9yZW50cnkgZG91YmxlX2ZhdWx0IGRvX2RvdWJsZV9mYXVsdAogemVyb2VudHJ5IGNvcHJvY2Vzc29yX3NlZ21lbnRfb3ZlcnJ1biBkb19jb3Byb2Nlc3Nvcl9zZWdtZW50X292ZXJydW4KIGVycm9yZW50cnkgaW52YWxpZF9UU1MgZG9faW52YWxpZF9UU1MKIGVycm9yZW50cnkgc2VnbWVudF9ub3RfcHJlc2VudCBkb19zZWdtZW50X25vdF9wcmVzZW50CmRpZmYgLS1naXQgYS9hcmNoL3g4Ni9rZXJuZWwvdHJhcHMuYyBiL2FyY2gveDg2L2tlcm5lbC90cmFwcy5jCmluZGV4IDc3MmUyYTguLjc0ZTA4MDEgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC90cmFwcy5jCisrKyBiL2FyY2gveDg2L2tlcm5lbC90cmFwcy5jCkBAIC0yNDcsNiArMjQ3LDMwIEBACiAJc3RhdGljIGNvbnN0IGNoYXIgc3RyW10gPSAiZG91YmxlIGZhdWx0IjsKIAlzdHJ1Y3QgdGFza19zdHJ1Y3QgKnRzayA9IGN1cnJlbnQ7CiAKKyNpZmRlZiBDT05GSUdfWDg2X0VTUEZJWDY0CisJZXh0ZXJuIHVuc2lnbmVkIGNoYXIgbmF0aXZlX2lycV9yZXR1cm5faXJldFtdOworCisJLyoKKwkgKiBJZiBJUkVUIHRha2VzIGEgbm9uLUlTVCBmYXVsdCBvbiB0aGUgZXNwZml4NjQgc3RhY2ssIHRoZW4gd2UKKwkgKiBlbmQgdXAgcHJvbW90aW5nIGl0IHRvIGEgZG91YmxlZmF1bHQuICBJbiB0aGF0IGNhc2UsIG1vZGlmeQorCSAqIHRoZSBzdGFjayB0byBtYWtlIGl0IGxvb2sgbGlrZSB3ZSBqdXN0IGVudGVyZWQgdGhlICNHUAorCSAqIGhhbmRsZXIgZnJvbSB1c2VyIHNwYWNlLCBzaW1pbGFyIHRvIGJhZF9pcmV0LgorCSAqLworCWlmICgoKGxvbmcpcmVncy0+c3AgPj4gUEdESVJfU0hJRlQpID09IEVTUEZJWF9QR0RfRU5UUlkgJiYKKwkJcmVncy0+Y3MgPT0gX19LRVJORUxfQ1MgJiYKKwkJcmVncy0+aXAgPT0gKHVuc2lnbmVkIGxvbmcpbmF0aXZlX2lycV9yZXR1cm5faXJldCkKKwl7CisJCXN0cnVjdCBwdF9yZWdzICpub3JtYWxfcmVncyA9IHRhc2tfcHRfcmVncyhjdXJyZW50KTsKKworCQkvKiBGYWtlIGEgI0dQKDApIGZyb20gdXNlcnNwYWNlLiAqLworCQltZW1tb3ZlKCZub3JtYWxfcmVncy0+aXAsICh2b2lkICopcmVncy0+c3AsIDUqOCk7CisJCW5vcm1hbF9yZWdzLT5vcmlnX2F4ID0gMDsgIC8qIE1pc3NpbmcgKGxvc3QpICNHUCBlcnJvciBjb2RlICovCisJCXJlZ3MtPmlwID0gKHVuc2lnbmVkIGxvbmcpZ2VuZXJhbF9wcm90ZWN0aW9uOworCQlyZWdzLT5zcCA9ICh1bnNpZ25lZCBsb25nKSZub3JtYWxfcmVncy0+b3JpZ19heDsKKwkJcmV0dXJuOworCX0KKyNlbmRpZgorCiAJZXhjZXB0aW9uX2VudGVyKCk7CiAJLyogUmV0dXJuIG5vdCBjaGVja2VkIGJlY2F1c2UgZG91YmxlIGNoZWNrIGNhbm5vdCBiZSBpZ25vcmVkICovCiAJbm90aWZ5X2RpZShESUVfVFJBUCwgc3RyLCByZWdzLCBlcnJvcl9jb2RlLCBYODZfVFJBUF9ERiwgU0lHU0VHVik7Cg==
|
@ -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);
|
@ -1 +0,0 @@
|
||||
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL3BhZ2VfMzJfdHlwZXMuaCBiL2FyY2gveDg2L2luY2x1ZGUvYXNtL3BhZ2VfMzJfdHlwZXMuaAppbmRleCBlZjE3YWYwLi40Mzc2YjQ1IDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9pbmNsdWRlL2FzbS9wYWdlXzMyX3R5cGVzLmgKKysrIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vcGFnZV8zMl90eXBlcy5oCkBAIC0xOCw3ICsxOCw2IEBACiAjZGVmaW5lIFRIUkVBRF9TSVpFX09SREVSCTEKICNkZWZpbmUgVEhSRUFEX1NJWkUJCShQQUdFX1NJWkUgPDwgVEhSRUFEX1NJWkVfT1JERVIpCiAKLSNkZWZpbmUgU1RBQ0tGQVVMVF9TVEFDSyAwCiAjZGVmaW5lIERPVUJMRUZBVUxUX1NUQUNLIDEKICNkZWZpbmUgTk1JX1NUQUNLIDAKICNkZWZpbmUgREVCVUdfU1RBQ0sgMApkaWZmIC0tZ2l0IGEvYXJjaC94ODYvaW5jbHVkZS9hc20vcGFnZV82NF90eXBlcy5oIGIvYXJjaC94ODYvaW5jbHVkZS9hc20vcGFnZV82NF90eXBlcy5oCmluZGV4IDZjODk2ZmIuLjk3MGYzMDkgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2luY2x1ZGUvYXNtL3BhZ2VfNjRfdHlwZXMuaAorKysgYi9hcmNoL3g4Ni9pbmNsdWRlL2FzbS9wYWdlXzY0X3R5cGVzLmgKQEAgLTE0LDEyICsxNCwxMSBAQAogI2RlZmluZSBJUlFfU1RBQ0tfT1JERVIgMgogI2RlZmluZSBJUlFfU1RBQ0tfU0laRSAoUEFHRV9TSVpFIDw8IElSUV9TVEFDS19PUkRFUikKIAotI2RlZmluZSBTVEFDS0ZBVUxUX1NUQUNLIDEKLSNkZWZpbmUgRE9VQkxFRkFVTFRfU1RBQ0sgMgotI2RlZmluZSBOTUlfU1RBQ0sgMwotI2RlZmluZSBERUJVR19TVEFDSyA0Ci0jZGVmaW5lIE1DRV9TVEFDSyA1Ci0jZGVmaW5lIE5fRVhDRVBUSU9OX1NUQUNLUyA1ICAvKiBodyBsaW1pdDogNyAqLworI2RlZmluZSBET1VCTEVGQVVMVF9TVEFDSyAxCisjZGVmaW5lIE5NSV9TVEFDSyAyCisjZGVmaW5lIERFQlVHX1NUQUNLIDMKKyNkZWZpbmUgTUNFX1NUQUNLIDQKKyNkZWZpbmUgTl9FWENFUFRJT05fU1RBQ0tTIDQgIC8qIGh3IGxpbWl0OiA3ICovCiAKICNkZWZpbmUgUFVEX1BBR0VfU0laRQkJKF9BQygxLCBVTCkgPDwgUFVEX1NISUZUKQogI2RlZmluZSBQVURfUEFHRV9NQVNLCQkofihQVURfUEFHRV9TSVpFLTEpKQpkaWZmIC0tZ2l0IGEvYXJjaC94ODYva2VybmVsL2R1bXBzdGFja182NC5jIGIvYXJjaC94ODYva2VybmVsL2R1bXBzdGFja182NC5jCmluZGV4IGFkZGIyMDcuLjY2ZTI3NGEgMTAwNjQ0Ci0tLSBhL2FyY2gveDg2L2tlcm5lbC9kdW1wc3RhY2tfNjQuYworKysgYi9hcmNoL3g4Ni9rZXJuZWwvZHVtcHN0YWNrXzY0LmMKQEAgLTI0LDcgKzI0LDYgQEAKIAkJWyBERUJVR19TVEFDSy0xCQkJXQk9ICIjREIiLAogCQlbIE5NSV9TVEFDSy0xCQkJXQk9ICJOTUkiLAogCQlbIERPVUJMRUZBVUxUX1NUQUNLLTEJCV0JPSAiI0RGIiwKLQkJWyBTVEFDS0ZBVUxUX1NUQUNLLTEJCV0JPSAiI1NTIiwKIAkJWyBNQ0VfU1RBQ0stMQkJCV0JPSAiI01DIiwKICNpZiBERUJVR19TVEtTWiA+IEVYQ0VQVElPTl9TVEtTWgogCQlbIE5fRVhDRVBUSU9OX1NUQUNLUyAuLi4KZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC9lbnRyeV82NC5TIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKaW5kZXggMWE0NTRkMC4uNTBlNWU1OSAxMDA2NDQKLS0tIGEvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKKysrIGIvYXJjaC94ODYva2VybmVsL2VudHJ5XzY0LlMKQEAgLTE1MDMsNyArMTUwMyw3IEBACiAKIHBhcmFub2lkemVyb2VudHJ5X2lzdCBkZWJ1ZyBkb19kZWJ1ZyBERUJVR19TVEFDSwogcGFyYW5vaWR6ZXJvZW50cnlfaXN0IGludDMgZG9faW50MyBERUJVR19TVEFDSwotcGFyYW5vaWRlcnJvcmVudHJ5IHN0YWNrX3NlZ21lbnQgZG9fc3RhY2tfc2VnbWVudAorZXJyb3JlbnRyeSBzdGFja19zZWdtZW50IGRvX3N0YWNrX3NlZ21lbnQKICNpZmRlZiBDT05GSUdfWEVOCiB6ZXJvZW50cnkgeGVuX2RlYnVnIGRvX2RlYnVnCiB6ZXJvZW50cnkgeGVuX2ludDMgZG9faW50MwpkaWZmIC0tZ2l0IGEvYXJjaC94ODYva2VybmVsL3RyYXBzLmMgYi9hcmNoL3g4Ni9rZXJuZWwvdHJhcHMuYwppbmRleCA3NGUwODAxLi4wMGEyODczIDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9rZXJuZWwvdHJhcHMuYworKysgYi9hcmNoL3g4Ni9rZXJuZWwvdHJhcHMuYwpAQCAtMjIwLDI4ICsyMjAsMTIgQEAKIAkJY29wcm9jZXNzb3Jfc2VnbWVudF9vdmVycnVuKQogRE9fRVJST1IoWDg2X1RSQVBfVFMsIFNJR1NFR1YsICJpbnZhbGlkIFRTUyIsIGludmFsaWRfVFNTKQogRE9fRVJST1IoWDg2X1RSQVBfTlAsIFNJR0JVUywgInNlZ21lbnQgbm90IHByZXNlbnQiLCBzZWdtZW50X25vdF9wcmVzZW50KQotI2lmZGVmIENPTkZJR19YODZfMzIKIERPX0VSUk9SKFg4Nl9UUkFQX1NTLCBTSUdCVVMsICJzdGFjayBzZWdtZW50Iiwgc3RhY2tfc2VnbWVudCkKLSNlbmRpZgogRE9fRVJST1JfSU5GTyhYODZfVFJBUF9BQywgU0lHQlVTLCAiYWxpZ25tZW50IGNoZWNrIiwgYWxpZ25tZW50X2NoZWNrLAogCQlCVVNfQURSQUxOLCAwKQogCiAjaWZkZWYgQ09ORklHX1g4Nl82NAogLyogUnVucyBvbiBJU1Qgc3RhY2sgKi8KLWRvdHJhcGxpbmthZ2Ugdm9pZCBkb19zdGFja19zZWdtZW50KHN0cnVjdCBwdF9yZWdzICpyZWdzLCBsb25nIGVycm9yX2NvZGUpCi17Ci0JZW51bSBjdHhfc3RhdGUgcHJldl9zdGF0ZTsKLQotCXByZXZfc3RhdGUgPSBleGNlcHRpb25fZW50ZXIoKTsKLQlpZiAobm90aWZ5X2RpZShESUVfVFJBUCwgInN0YWNrIHNlZ21lbnQiLCByZWdzLCBlcnJvcl9jb2RlLAotCQkgICAgICAgWDg2X1RSQVBfU1MsIFNJR0JVUykgIT0gTk9USUZZX1NUT1ApIHsKLQkJcHJlZW1wdF9jb25kaXRpb25hbF9zdGkocmVncyk7Ci0JCWRvX3RyYXAoWDg2X1RSQVBfU1MsIFNJR0JVUywgInN0YWNrIHNlZ21lbnQiLCByZWdzLCBlcnJvcl9jb2RlLCBOVUxMKTsKLQkJcHJlZW1wdF9jb25kaXRpb25hbF9jbGkocmVncyk7Ci0JfQotCWV4Y2VwdGlvbl9leGl0KHByZXZfc3RhdGUpOwotfQotCiBkb3RyYXBsaW5rYWdlIHZvaWQgZG9fZG91YmxlX2ZhdWx0KHN0cnVjdCBwdF9yZWdzICpyZWdzLCBsb25nIGVycm9yX2NvZGUpCiB7CiAJc3RhdGljIGNvbnN0IGNoYXIgc3RyW10gPSAiZG91YmxlIGZhdWx0IjsKQEAgLTc2OSw3ICs3NTMsNyBAQAogCXNldF9pbnRyX2dhdGUoWDg2X1RSQVBfT0xEX01GLCAmY29wcm9jZXNzb3Jfc2VnbWVudF9vdmVycnVuKTsKIAlzZXRfaW50cl9nYXRlKFg4Nl9UUkFQX1RTLCAmaW52YWxpZF9UU1MpOwogCXNldF9pbnRyX2dhdGUoWDg2X1RSQVBfTlAsICZzZWdtZW50X25vdF9wcmVzZW50KTsKLQlzZXRfaW50cl9nYXRlX2lzdChYODZfVFJBUF9TUywgJnN0YWNrX3NlZ21lbnQsIFNUQUNLRkFVTFRfU1RBQ0spOworCXNldF9pbnRyX2dhdGUoWDg2X1RSQVBfU1MsIHN0YWNrX3NlZ21lbnQpOwogCXNldF9pbnRyX2dhdGUoWDg2X1RSQVBfR1AsICZnZW5lcmFsX3Byb3RlY3Rpb24pOwogCXNldF9pbnRyX2dhdGUoWDg2X1RSQVBfU1BVUklPVVMsICZzcHVyaW91c19pbnRlcnJ1cHRfYnVnKTsKIAlzZXRfaW50cl9nYXRlKFg4Nl9UUkFQX01GLCAmY29wcm9jZXNzb3JfZXJyb3IpOwo=
|
@ -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));
|
@ -1 +0,0 @@
|
||||
ZGlmZiAtLWdpdCBhL2FyY2gveDg2L2tlcm5lbC90bHMuYyBiL2FyY2gveDg2L2tlcm5lbC90bHMuYwppbmRleCBmN2ZlYzA5Li5lNzY1MGJkIDEwMDY0NAotLS0gYS9hcmNoL3g4Ni9rZXJuZWwvdGxzLmMKKysrIGIvYXJjaC94ODYva2VybmVsL3Rscy5jCkBAIC0yNyw2ICsyNywyMSBAQAogCXJldHVybiAtRVNSQ0g7CiB9CiAKK3N0YXRpYyBib29sIHRsc19kZXNjX29rYXkoY29uc3Qgc3RydWN0IHVzZXJfZGVzYyAqaW5mbykKK3sKKwlpZiAoTERUX2VtcHR5KGluZm8pKQorCQlyZXR1cm4gdHJ1ZTsKKworCS8qCisJICogZXNwZml4IGlzIHJlcXVpcmVkIGZvciAxNi1iaXQgZGF0YSBzZWdtZW50cywgYnV0IGVzcGZpeAorCSAqIG9ubHkgd29ya3MgZm9yIExEVCBzZWdtZW50cy4KKwkgKi8KKwlpZiAoIWluZm8tPnNlZ18zMmJpdCkKKwkJcmV0dXJuIGZhbHNlOworCisJcmV0dXJuIHRydWU7Cit9CisKIHN0YXRpYyB2b2lkIHNldF90bHNfZGVzYyhzdHJ1Y3QgdGFza19zdHJ1Y3QgKnAsIGludCBpZHgsCiAJCQkgY29uc3Qgc3RydWN0IHVzZXJfZGVzYyAqaW5mbywgaW50IG4pCiB7CkBAIC02Niw2ICs4MSw5IEBACiAJaWYgKGNvcHlfZnJvbV91c2VyKCZpbmZvLCB1X2luZm8sIHNpemVvZihpbmZvKSkpCiAJCXJldHVybiAtRUZBVUxUOwogCisJaWYgKCF0bHNfZGVzY19va2F5KCZpbmZvKSkKKwkJcmV0dXJuIC1FSU5WQUw7CisKIAlpZiAoaWR4ID09IC0xKQogCQlpZHggPSBpbmZvLmVudHJ5X251bWJlcjsKIApAQCAtMTkyLDYgKzIxMCw3IEBACiB7CiAJc3RydWN0IHVzZXJfZGVzYyBpbmZvYnVmW0dEVF9FTlRSWV9UTFNfRU5UUklFU107CiAJY29uc3Qgc3RydWN0IHVzZXJfZGVzYyAqaW5mbzsKKwlpbnQgaTsKIAogCWlmIChwb3MgPj0gR0RUX0VOVFJZX1RMU19FTlRSSUVTICogc2l6ZW9mKHN0cnVjdCB1c2VyX2Rlc2MpIHx8CiAJICAgIChwb3MgJSBzaXplb2Yoc3RydWN0IHVzZXJfZGVzYykpICE9IDAgfHwKQEAgLTIwNSw2ICsyMjQsMTAgQEAKIAllbHNlCiAJCWluZm8gPSBpbmZvYnVmOwogCisJZm9yIChpID0gMDsgaSA8IGNvdW50IC8gc2l6ZW9mKHN0cnVjdCB1c2VyX2Rlc2MpOyBpKyspCisJCWlmICghdGxzX2Rlc2Nfb2theShpbmZvICsgaSkpCisJCQlyZXR1cm4gLUVJTlZBTDsKKwogCXNldF90bHNfZGVzYyh0YXJnZXQsCiAJCSAgICAgR0RUX0VOVFJZX1RMU19NSU4gKyAocG9zIC8gc2l6ZW9mKHN0cnVjdCB1c2VyX2Rlc2MpKSwKIAkJICAgICBpbmZvLCBjb3VudCAvIHNpemVvZihzdHJ1Y3QgdXNlcl9kZXNjKSk7Cg==
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user