* [PATCH v2 02/16] ABI: Fix KernelVersion tags
From: Mauro Carvalho Chehab @ 2019-06-14 17:52 UTC (permalink / raw)
To: Linux Doc Mailing List, Greg Kroah-Hartman
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
Jonathan Corbet, Kees Cook, Anton Vorontsov, Colin Cross,
Tony Luck, Andrew Donnellan, Rafael J. Wysocki, Rajat Jain,
Bjorn Helgaas
In-Reply-To: <3b8d7c64f887ddea01df3c4eeabc745c8ec45406.1560534648.git.mchehab+samsung@kernel.org>
It is "KernelVersion:" and not "Kernel Version:".
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
Documentation/ABI/testing/pstore | 2 +-
.../sysfs-bus-event_source-devices-format | 2 +-
.../ABI/testing/sysfs-bus-i2c-devices-hm6352 | 6 ++---
.../testing/sysfs-bus-pci-devices-aer_stats | 12 +++++-----
.../ABI/testing/sysfs-bus-pci-devices-cciss | 22 +++++++++----------
.../testing/sysfs-bus-usb-devices-usbsevseg | 10 ++++-----
.../ABI/testing/sysfs-driver-altera-cvp | 2 +-
Documentation/ABI/testing/sysfs-driver-ppi | 2 +-
Documentation/ABI/testing/sysfs-driver-st | 2 +-
Documentation/ABI/testing/sysfs-driver-wacom | 2 +-
10 files changed, 31 insertions(+), 31 deletions(-)
diff --git a/Documentation/ABI/testing/pstore b/Documentation/ABI/testing/pstore
index 8d6e48f4e8ef..d45209abdb1b 100644
--- a/Documentation/ABI/testing/pstore
+++ b/Documentation/ABI/testing/pstore
@@ -1,6 +1,6 @@
What: /sys/fs/pstore/... (or /dev/pstore/...)
Date: March 2011
-Kernel Version: 2.6.39
+KernelVersion: 2.6.39
Contact: tony.luck@intel.com
Description: Generic interface to platform dependent persistent storage.
diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-format b/Documentation/ABI/testing/sysfs-bus-event_source-devices-format
index b6f8748e0200..5bb793ec926c 100644
--- a/Documentation/ABI/testing/sysfs-bus-event_source-devices-format
+++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-format
@@ -1,6 +1,6 @@
What: /sys/bus/event_source/devices/<dev>/format
Date: January 2012
-Kernel Version: 3.3
+KernelVersion: 3.3
Contact: Jiri Olsa <jolsa@redhat.com>
Description:
Attribute group to describe the magic bits that go into
diff --git a/Documentation/ABI/testing/sysfs-bus-i2c-devices-hm6352 b/Documentation/ABI/testing/sysfs-bus-i2c-devices-hm6352
index 29bd447e50a0..4a251b7f11e4 100644
--- a/Documentation/ABI/testing/sysfs-bus-i2c-devices-hm6352
+++ b/Documentation/ABI/testing/sysfs-bus-i2c-devices-hm6352
@@ -1,20 +1,20 @@
What: /sys/bus/i2c/devices/.../heading0_input
Date: April 2010
-Kernel Version: 2.6.36?
+KernelVersion: 2.6.36?
Contact: alan.cox@intel.com
Description: Reports the current heading from the compass as a floating
point value in degrees.
What: /sys/bus/i2c/devices/.../power_state
Date: April 2010
-Kernel Version: 2.6.36?
+KernelVersion: 2.6.36?
Contact: alan.cox@intel.com
Description: Sets the power state of the device. 0 sets the device into
sleep mode, 1 wakes it up.
What: /sys/bus/i2c/devices/.../calibration
Date: April 2010
-Kernel Version: 2.6.36?
+KernelVersion: 2.6.36?
Contact: alan.cox@intel.com
Description: Sets the calibration on or off (1 = on, 0 = off). See the
chip data sheet.
diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats b/Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats
index ff229d71961c..3c9a8c4a25eb 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats
+++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats
@@ -11,7 +11,7 @@ saw any problems).
What: /sys/bus/pci/devices/<dev>/aer_dev_correctable
Date: July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: List of correctable errors seen and reported by this
PCI device using ERR_COR. Note that since multiple errors may
@@ -33,7 +33,7 @@ TOTAL_ERR_COR 2
What: /sys/bus/pci/devices/<dev>/aer_dev_fatal
Date: July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: List of uncorrectable fatal errors seen and reported by this
PCI device using ERR_FATAL. Note that since multiple errors may
@@ -64,7 +64,7 @@ TOTAL_ERR_FATAL 0
What: /sys/bus/pci/devices/<dev>/aer_dev_nonfatal
Date: July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: List of uncorrectable nonfatal errors seen and reported by this
PCI device using ERR_NONFATAL. Note that since multiple errors
@@ -105,18 +105,18 @@ messages on the PCI hierarchy originating at that root port.
What: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_cor
Date: July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: Total number of ERR_COR messages reported to rootport.
What: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_fatal
Date: July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: Total number of ERR_FATAL messages reported to rootport.
What: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_nonfatal
Date: July 2018
-Kernel Version: 4.19.0
+KernelVersion: 4.19.0
Contact: linux-pci@vger.kernel.org, rajatja@google.com
Description: Total number of ERR_NONFATAL messages reported to rootport.
diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss
index eb449169c30b..92a94e1068c2 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss
+++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss
@@ -1,68 +1,68 @@
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/model
Date: March 2009
-Kernel Version: 2.6.30
+KernelVersion: 2.6.30
Contact: iss_storagedev@hp.com
Description: Displays the SCSI INQUIRY page 0 model for logical drive
Y of controller X.
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/rev
Date: March 2009
-Kernel Version: 2.6.30
+KernelVersion: 2.6.30
Contact: iss_storagedev@hp.com
Description: Displays the SCSI INQUIRY page 0 revision for logical
drive Y of controller X.
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/unique_id
Date: March 2009
-Kernel Version: 2.6.30
+KernelVersion: 2.6.30
Contact: iss_storagedev@hp.com
Description: Displays the SCSI INQUIRY page 83 serial number for logical
drive Y of controller X.
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/vendor
Date: March 2009
-Kernel Version: 2.6.30
+KernelVersion: 2.6.30
Contact: iss_storagedev@hp.com
Description: Displays the SCSI INQUIRY page 0 vendor for logical drive
Y of controller X.
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/block:cciss!cXdY
Date: March 2009
-Kernel Version: 2.6.30
+KernelVersion: 2.6.30
Contact: iss_storagedev@hp.com
Description: A symbolic link to /sys/block/cciss!cXdY
What: /sys/bus/pci/devices/<dev>/ccissX/rescan
Date: August 2009
-Kernel Version: 2.6.31
+KernelVersion: 2.6.31
Contact: iss_storagedev@hp.com
Description: Kicks of a rescan of the controller to discover logical
drive topology changes.
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/lunid
Date: August 2009
-Kernel Version: 2.6.31
+KernelVersion: 2.6.31
Contact: iss_storagedev@hp.com
Description: Displays the 8-byte LUN ID used to address logical
drive Y of controller X.
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/raid_level
Date: August 2009
-Kernel Version: 2.6.31
+KernelVersion: 2.6.31
Contact: iss_storagedev@hp.com
Description: Displays the RAID level of logical drive Y of
controller X.
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/usage_count
Date: August 2009
-Kernel Version: 2.6.31
+KernelVersion: 2.6.31
Contact: iss_storagedev@hp.com
Description: Displays the usage count (number of opens) of logical drive Y
of controller X.
What: /sys/bus/pci/devices/<dev>/ccissX/resettable
Date: February 2011
-Kernel Version: 2.6.38
+KernelVersion: 2.6.38
Contact: iss_storagedev@hp.com
Description: Value of 1 indicates the controller can honor the reset_devices
kernel parameter. Value of 0 indicates reset_devices cannot be
@@ -73,7 +73,7 @@ Description: Value of 1 indicates the controller can honor the reset_devices
What: /sys/bus/pci/devices/<dev>/ccissX/transport_mode
Date: July 2011
-Kernel Version: 3.0
+KernelVersion: 3.0
Contact: iss_storagedev@hp.com
Description: Value of "simple" indicates that the controller has been placed
in "simple mode". Value of "performant" indicates that the
diff --git a/Documentation/ABI/testing/sysfs-bus-usb-devices-usbsevseg b/Documentation/ABI/testing/sysfs-bus-usb-devices-usbsevseg
index f6199b314196..9ade80f81f96 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb-devices-usbsevseg
+++ b/Documentation/ABI/testing/sysfs-bus-usb-devices-usbsevseg
@@ -1,6 +1,6 @@
What: /sys/bus/usb/.../powered
Date: August 2008
-Kernel Version: 2.6.26
+KernelVersion: 2.6.26
Contact: Harrison Metzger <harrisonmetz@gmail.com>
Description: Controls whether the device's display will powered.
A value of 0 is off and a non-zero value is on.
@@ -8,7 +8,7 @@ Description: Controls whether the device's display will powered.
What: /sys/bus/usb/.../mode_msb
What: /sys/bus/usb/.../mode_lsb
Date: August 2008
-Kernel Version: 2.6.26
+KernelVersion: 2.6.26
Contact: Harrison Metzger <harrisonmetz@gmail.com>
Description: Controls the devices display mode.
For a 6 character display the values are
@@ -18,7 +18,7 @@ Description: Controls the devices display mode.
What: /sys/bus/usb/.../textmode
Date: August 2008
-Kernel Version: 2.6.26
+KernelVersion: 2.6.26
Contact: Harrison Metzger <harrisonmetz@gmail.com>
Description: Controls the way the device interprets its text buffer.
raw: each character controls its segment manually
@@ -27,13 +27,13 @@ Description: Controls the way the device interprets its text buffer.
What: /sys/bus/usb/.../text
Date: August 2008
-Kernel Version: 2.6.26
+KernelVersion: 2.6.26
Contact: Harrison Metzger <harrisonmetz@gmail.com>
Description: The text (or data) for the device to display
What: /sys/bus/usb/.../decimals
Date: August 2008
-Kernel Version: 2.6.26
+KernelVersion: 2.6.26
Contact: Harrison Metzger <harrisonmetz@gmail.com>
Description: Controls the decimal places on the device.
To set the nth decimal place, give this field
diff --git a/Documentation/ABI/testing/sysfs-driver-altera-cvp b/Documentation/ABI/testing/sysfs-driver-altera-cvp
index 8cde64a71edb..fbd8078fd7ad 100644
--- a/Documentation/ABI/testing/sysfs-driver-altera-cvp
+++ b/Documentation/ABI/testing/sysfs-driver-altera-cvp
@@ -1,6 +1,6 @@
What: /sys/bus/pci/drivers/altera-cvp/chkcfg
Date: May 2017
-Kernel Version: 4.13
+KernelVersion: 4.13
Contact: Anatolij Gustschin <agust@denx.de>
Description:
Contains either 1 or 0 and controls if configuration
diff --git a/Documentation/ABI/testing/sysfs-driver-ppi b/Documentation/ABI/testing/sysfs-driver-ppi
index 9921ef285899..1a56fc507689 100644
--- a/Documentation/ABI/testing/sysfs-driver-ppi
+++ b/Documentation/ABI/testing/sysfs-driver-ppi
@@ -1,6 +1,6 @@
What: /sys/class/tpm/tpmX/ppi/
Date: August 2012
-Kernel Version: 3.6
+KernelVersion: 3.6
Contact: xiaoyan.zhang@intel.com
Description:
This folder includes the attributes related with PPI (Physical
diff --git a/Documentation/ABI/testing/sysfs-driver-st b/Documentation/ABI/testing/sysfs-driver-st
index ba5d77008a85..88cab66fd77f 100644
--- a/Documentation/ABI/testing/sysfs-driver-st
+++ b/Documentation/ABI/testing/sysfs-driver-st
@@ -1,6 +1,6 @@
What: /sys/bus/scsi/drivers/st/debug_flag
Date: October 2015
-Kernel Version: ?.?
+KernelVersion: ?.?
Contact: shane.seymour@hpe.com
Description:
This file allows you to turn debug output from the st driver
diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom
index 2aa5503ee200..afc48fc163b5 100644
--- a/Documentation/ABI/testing/sysfs-driver-wacom
+++ b/Documentation/ABI/testing/sysfs-driver-wacom
@@ -1,6 +1,6 @@
What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/speed
Date: April 2010
-Kernel Version: 2.6.35
+KernelVersion: 2.6.35
Contact: linux-bluetooth@vger.kernel.org
Description:
The /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/speed file
--
2.21.0
^ permalink raw reply related
* [PATCH v2 07/16] scripts/get_abi.pl: add support for searching for ABI symbols
From: Mauro Carvalho Chehab @ 2019-06-14 17:52 UTC (permalink / raw)
To: Linux Doc Mailing List, Greg Kroah-Hartman
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
Jonathan Corbet
In-Reply-To: <3b8d7c64f887ddea01df3c4eeabc745c8ec45406.1560534648.git.mchehab+samsung@kernel.org>
Change its syntax to allow switching between ReST output mode
and a new search mode, with allows to seek for ABI symbols
using regex.
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
scripts/get_abi.pl | 112 +++++++++++++++++++++++++++++++++++++++++----
1 file changed, 103 insertions(+), 9 deletions(-)
diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl
index f84d321a72bb..ecf6b91df7c4 100755
--- a/scripts/get_abi.pl
+++ b/scripts/get_abi.pl
@@ -9,9 +9,11 @@ use Fcntl ':mode';
my $help;
my $man;
my $debug;
+my $prefix="Documentation/ABI";
GetOptions(
"debug|d+" => \$debug,
+ "dir=s" => \$prefix,
'help|?' => \$help,
man => \$man
) or pod2usage(2);
@@ -19,9 +21,12 @@ GetOptions(
pod2usage(1) if $help;
pod2usage(-exitstatus => 0, -verbose => 2) if $man;
-pod2usage(2) if (scalar @ARGV != 1);
+pod2usage(2) if (scalar @ARGV < 1 || @ARGV > 2);
-my ($prefix) = @ARGV;
+my ($cmd, $arg) = @ARGV;
+
+pod2usage(2) if ($cmd ne "search" && $cmd ne "rest");
+pod2usage(2) if ($cmd eq "search" && !$arg);
require Data::Dumper if ($debug);
@@ -53,6 +58,7 @@ sub parse_abi {
$data{$nametag}->{what} = "File $name";
$data{$nametag}->{type} = "File";
$data{$nametag}->{file} = $name;
+ $data{$nametag}->{filepath} = $file;
$data{$nametag}->{is_file} = 1;
my $type = $file;
@@ -115,6 +121,7 @@ sub parse_abi {
$data{$what}->{type} = $type;
$data{$what}->{file} = $name;
+ $data{$what}->{filepath} = $file;
print STDERR "\twhat: $what\n" if ($debug > 1);
}
@@ -183,7 +190,9 @@ sub parse_abi {
close IN;
}
-# Outputs the output on ReST format
+#
+# Outputs the book on ReST format
+#
sub output_rest {
foreach my $what (sort keys %data) {
my $type = $data{$what}->{type};
@@ -262,6 +271,45 @@ sub output_rest {
}
}
+#
+# Searches for ABI symbols
+#
+sub search_symbols {
+ foreach my $what (sort keys %data) {
+ next if (!($what =~ m/($arg)/));
+
+ my $type = $data{$what}->{type};
+ next if ($type eq "File");
+
+ my $file = $data{$what}->{filepath};
+
+ my $bar = $what;
+ $bar =~ s/./-/g;
+
+ print "\n$what\n$bar\n\n";
+
+ my $kernelversion = $data{$what}->{kernelversion};
+ my $contact = $data{$what}->{contact};
+ my $users = $data{$what}->{users};
+ my $date = $data{$what}->{date};
+ my $desc = $data{$what}->{description};
+ $kernelversion =~ s/^\s+//;
+ $contact =~ s/^\s+//;
+ $users =~ s/^\s+//;
+ $users =~ s/\n//g;
+ $date =~ s/^\s+//;
+ $desc =~ s/^\s+//;
+
+ printf "Kernel version:\t\t%s\n", $kernelversion if ($kernelversion);
+ printf "Date:\t\t\t%s\n", $date if ($date);
+ printf "Contact:\t\t%s\n", $contact if ($contact);
+ printf "Users:\t\t\t%s\n", $users if ($users);
+ print "Defined on file:\t$file\n\n";
+ print "Description:\n\n$desc";
+ }
+}
+
+
#
# Parses all ABI files located at $prefix dir
#
@@ -270,9 +318,13 @@ find({wanted =>\&parse_abi, no_chdir => 1}, $prefix);
print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug);
#
-# Outputs an ReST file with the ABI contents
+# Handles the command
#
-output_rest
+if ($cmd eq "rest") {
+ output_rest;
+} else {
+ search_symbols;
+}
__END__
@@ -283,12 +335,27 @@ abi_book.pl - parse the Linux ABI files and produce a ReST book.
=head1 SYNOPSIS
-B<abi_book.pl> [--debug] <ABI_DIR>]
+B<abi_book.pl> [--debug] <COMAND> [<ARGUMENT>]
+
+Where <COMMAND> can be:
+
+=over 8
+
+B<search> [SEARCH_REGEX] - search for [SEARCH_REGEX] inside ABI
+
+B<rest> - output the ABI in ReST markup language
+
+=back
=head1 OPTIONS
=over 8
+=item B<--dir>
+
+Changes the location of the ABI search. By default, it uses
+the Documentation/ABI directory.
+
=item B<--debug>
Put the script in verbose mode, useful for debugging. Can be called multiple
@@ -306,8 +373,35 @@ Prints the manual page and exits.
=head1 DESCRIPTION
-Parse the Linux ABI files from ABI DIR (usually located at Documentation/ABI)
-and produce a ReST book containing the Linux ABI.
+Parse the Linux ABI files from ABI DIR (usually located at Documentation/ABI),
+allowing to search for ABI symbols or to produce a ReST book containing
+the Linux ABI documentation.
+
+=head1 EXAMPLES
+
+Search for all stable symbols with the word "usb":
+
+=over 8
+
+$ scripts/get_abi.pl search usb --dir Documentation/ABI/stable
+
+=back
+
+Search for all symbols that match the regex expression "usb.*cap":
+
+=over 8
+
+$ scripts/get_abi.pl search usb.*cap
+
+=back
+
+Output all obsoleted symbols in ReST format
+
+=over 8
+
+$ scripts/get_abi.pl rest --dir Documentation/ABI/obsolete
+
+=back
=head1 BUGS
@@ -315,7 +409,7 @@ Report bugs to Mauro Carvalho Chehab <mchehab@s-opensource.com>
=head1 COPYRIGHT
-Copyright (c) 2016 by Mauro Carvalho Chehab <mchehab@s-opensource.com>.
+Copyright (c) 2016-2017 by Mauro Carvalho Chehab <mchehab@s-opensource.com>.
License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.
--
2.21.0
^ permalink raw reply related
* [PATCH v2 13/16] doc-rst: add ABI documentation to the admin-guide book
From: Mauro Carvalho Chehab @ 2019-06-14 17:52 UTC (permalink / raw)
To: Linux Doc Mailing List, Greg Kroah-Hartman
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
Jonathan Corbet, Thomas Gleixner, Theodore Ts'o,
Alexey Budankov, Changbin Du, Darrick J. Wong
In-Reply-To: <3b8d7c64f887ddea01df3c4eeabc745c8ec45406.1560534648.git.mchehab+samsung@kernel.org>
As we don't want a generic Sphinx extension to execute commands,
change the one proposed to Markus to call the abi_book.pl
script.
Use a script to parse the Documentation/ABI directory and output
it at the admin-guide.
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
Documentation/admin-guide/abi-obsolete.rst | 10 ++
Documentation/admin-guide/abi-removed.rst | 4 +
Documentation/admin-guide/abi-stable.rst | 13 ++
Documentation/admin-guide/abi-testing.rst | 19 +++
Documentation/admin-guide/abi.rst | 11 ++
Documentation/admin-guide/index.rst | 1 +
Documentation/conf.py | 2 +-
Documentation/sphinx/kernel_abi.py | 155 +++++++++++++++++++++
8 files changed, 214 insertions(+), 1 deletion(-)
create mode 100644 Documentation/admin-guide/abi-obsolete.rst
create mode 100644 Documentation/admin-guide/abi-removed.rst
create mode 100644 Documentation/admin-guide/abi-stable.rst
create mode 100644 Documentation/admin-guide/abi-testing.rst
create mode 100644 Documentation/admin-guide/abi.rst
create mode 100644 Documentation/sphinx/kernel_abi.py
diff --git a/Documentation/admin-guide/abi-obsolete.rst b/Documentation/admin-guide/abi-obsolete.rst
new file mode 100644
index 000000000000..cda9168445a5
--- /dev/null
+++ b/Documentation/admin-guide/abi-obsolete.rst
@@ -0,0 +1,10 @@
+ABI obsolete symbols
+====================
+
+Documents interfaces that are still remaining in the kernel, but are
+marked to be removed at some later point in time.
+
+The description of the interface will document the reason why it is
+obsolete and when it can be expected to be removed.
+
+.. kernel-abi:: $srctree/Documentation/ABI/obsolete
diff --git a/Documentation/admin-guide/abi-removed.rst b/Documentation/admin-guide/abi-removed.rst
new file mode 100644
index 000000000000..497978fc9632
--- /dev/null
+++ b/Documentation/admin-guide/abi-removed.rst
@@ -0,0 +1,4 @@
+ABI removed symbols
+===================
+
+.. kernel-abi:: $srctree/Documentation/ABI/removed
diff --git a/Documentation/admin-guide/abi-stable.rst b/Documentation/admin-guide/abi-stable.rst
new file mode 100644
index 000000000000..7495d7a35048
--- /dev/null
+++ b/Documentation/admin-guide/abi-stable.rst
@@ -0,0 +1,13 @@
+ABI stable symbols
+==================
+
+Documents the interfaces that the developer has defined to be stable.
+
+Userspace programs are free to use these interfaces with no
+restrictions, and backward compatibility for them will be guaranteed
+for at least 2 years.
+
+Most interfaces (like syscalls) are expected to never change and always
+be available.
+
+.. kernel-abi:: $srctree/Documentation/ABI/stable
diff --git a/Documentation/admin-guide/abi-testing.rst b/Documentation/admin-guide/abi-testing.rst
new file mode 100644
index 000000000000..5c886fc50b9e
--- /dev/null
+++ b/Documentation/admin-guide/abi-testing.rst
@@ -0,0 +1,19 @@
+ABI testing symbols
+===================
+
+Documents interfaces that are felt to be stable,
+as the main development of this interface has been completed.
+
+The interface can be changed to add new features, but the
+current interface will not break by doing this, unless grave
+errors or security problems are found in them.
+
+Userspace programs can start to rely on these interfaces, but they must
+be aware of changes that can occur before these interfaces move to
+be marked stable.
+
+Programs that use these interfaces are strongly encouraged to add their
+name to the description of these interfaces, so that the kernel
+developers can easily notify them if any changes occur.
+
+.. kernel-abi:: $srctree/Documentation/ABI/testing
diff --git a/Documentation/admin-guide/abi.rst b/Documentation/admin-guide/abi.rst
new file mode 100644
index 000000000000..3b9645c77469
--- /dev/null
+++ b/Documentation/admin-guide/abi.rst
@@ -0,0 +1,11 @@
+=====================
+Linux ABI description
+=====================
+
+.. toctree::
+ :maxdepth: 1
+
+ abi-stable
+ abi-testing
+ abi-obsolete
+ abi-removed
diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst
index 8001917ee012..20c3020fd73c 100644
--- a/Documentation/admin-guide/index.rst
+++ b/Documentation/admin-guide/index.rst
@@ -16,6 +16,7 @@ etc.
README
kernel-parameters
devices
+ abi
This section describes CPU vulnerabilities and their mitigations.
diff --git a/Documentation/conf.py b/Documentation/conf.py
index 7ace3f8852bd..598256fb5c98 100644
--- a/Documentation/conf.py
+++ b/Documentation/conf.py
@@ -34,7 +34,7 @@ needs_sphinx = '1.3'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
-extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain', 'kfigure', 'sphinx.ext.ifconfig']
+extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain', 'kfigure', 'sphinx.ext.ifconfig', 'kernel_abi']
# The name of the math extension changed on Sphinx 1.4
if (major == 1 and minor > 3) or (major > 1):
diff --git a/Documentation/sphinx/kernel_abi.py b/Documentation/sphinx/kernel_abi.py
new file mode 100644
index 000000000000..32ce90775d96
--- /dev/null
+++ b/Documentation/sphinx/kernel_abi.py
@@ -0,0 +1,155 @@
+# -*- coding: utf-8; mode: python -*-
+u"""
+ kernel-abi
+ ~~~~~~~~~~
+
+ Implementation of the ``kernel-abi`` reST-directive.
+
+ :copyright: Copyright (C) 2016 Markus Heiser
+ :copyright: Copyright (C) 2016 Mauro Carvalho Chehab
+ :license: GPL Version 2, June 1991 see Linux/COPYING for details.
+
+ The ``kernel-abi`` (:py:class:`KernelCmd`) directive calls the
+ scripts/get_abi.pl script to parse the Kernel ABI files.
+
+ Overview of directive's argument and options.
+
+ .. code-block:: rst
+
+ .. kernel-abi:: <ABI directory location>
+ :debug:
+
+ The argument ``<ABI directory location>`` is required. It contains the
+ location of the ABI files to be parsed.
+
+ ``debug``
+ Inserts a code-block with the *raw* reST. Sometimes it is helpful to see
+ what reST is generated.
+
+"""
+
+import sys
+import os
+from os import path
+import subprocess
+
+from sphinx.ext.autodoc import AutodocReporter
+
+from docutils import nodes
+from docutils.parsers.rst import Directive, directives
+from docutils.statemachine import ViewList
+from docutils.utils.error_reporting import ErrorString
+
+
+__version__ = '1.0'
+
+# We can't assume that six is installed
+PY3 = sys.version_info[0] == 3
+PY2 = sys.version_info[0] == 2
+if PY3:
+ # pylint: disable=C0103, W0622
+ unicode = str
+ basestring = str
+
+def setup(app):
+
+ app.add_directive("kernel-abi", KernelCmd)
+ return dict(
+ version = __version__
+ , parallel_read_safe = True
+ , parallel_write_safe = True
+ )
+
+class KernelCmd(Directive):
+
+ u"""KernelABI (``kernel-abi``) directive"""
+
+ required_arguments = 1
+ optional_arguments = 0
+ has_content = False
+ final_argument_whitespace = True
+
+ option_spec = {
+ "debug" : directives.flag
+ }
+
+ def warn(self, message, **replace):
+ replace["fname"] = self.state.document.current_source
+ replace["line_no"] = replace.get("line_no", self.lineno)
+ message = ("%(fname)s:%(line_no)s: [kernel-abi WARN] : " + message) % replace
+ self.state.document.settings.env.app.warn(message, prefix="")
+
+ def run(self):
+
+ doc = self.state.document
+ if not doc.settings.file_insertion_enabled:
+ raise self.warning("docutils: file insertion disabled")
+
+ env = doc.settings.env
+ cwd = path.dirname(doc.current_source)
+ cmd = "get_abi.pl rest --dir "
+ cmd += self.arguments[0]
+
+ srctree = path.abspath(os.environ["srctree"])
+
+ fname = cmd
+
+ # extend PATH with $(srctree)/scripts
+ path_env = os.pathsep.join([
+ srctree + os.sep + "scripts",
+ os.environ["PATH"]
+ ])
+ shell_env = os.environ.copy()
+ shell_env["PATH"] = path_env
+ shell_env["srctree"] = srctree
+
+ lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env)
+ nodeList = self.nestedParse(lines, fname)
+ return nodeList
+
+ def runCmd(self, cmd, **kwargs):
+ u"""Run command ``cmd`` and return it's stdout as unicode."""
+
+ try:
+ proc = subprocess.Popen(
+ cmd
+ , stdout = subprocess.PIPE
+ , stderr = subprocess.PIPE
+ , universal_newlines = True
+ , **kwargs
+ )
+ out, err = proc.communicate()
+ if err:
+ self.warn(err)
+ if proc.returncode != 0:
+ raise self.severe(
+ u"command '%s' failed with return code %d"
+ % (cmd, proc.returncode)
+ )
+ except OSError as exc:
+ raise self.severe(u"problems with '%s' directive: %s."
+ % (self.name, ErrorString(exc)))
+ return unicode(out)
+
+ def nestedParse(self, lines, fname):
+ content = ViewList()
+ node = nodes.section()
+
+ if "debug" in self.options:
+ code_block = "\n\n.. code-block:: rst\n :linenos:\n"
+ for l in lines.split("\n"):
+ code_block += "\n " + l
+ lines = code_block + "\n\n"
+
+ for c, l in enumerate(lines.split("\n")):
+ content.append(l, fname, c)
+
+ buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
+ self.state.memo.title_styles = []
+ self.state.memo.section_level = 0
+ self.state.memo.reporter = AutodocReporter(content, self.state.memo.reporter)
+ try:
+ self.state.nested_parse(content, 0, node, match_titles=1)
+ finally:
+ self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf
+ return node.children
--
2.21.0
^ permalink raw reply related
* [PATCH v2 11/16] scripts/get_abi.pl: add a handler for invalid "where" tag
From: Mauro Carvalho Chehab @ 2019-06-14 17:52 UTC (permalink / raw)
To: Linux Doc Mailing List, Greg Kroah-Hartman
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
Jonathan Corbet
In-Reply-To: <3b8d7c64f887ddea01df3c4eeabc745c8ec45406.1560534648.git.mchehab+samsung@kernel.org>
The ABI README file doesn't provide any meaning for a Where:
tag. Yet, a few ABI symbols use it. So, make the parser
handle it, emitting a warning.
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
scripts/get_abi.pl | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl
index 329ace635ac2..c5038a0a7313 100755
--- a/scripts/get_abi.pl
+++ b/scripts/get_abi.pl
@@ -92,6 +92,12 @@ sub parse_abi {
}
}
+ # Invalid, but it is a common mistake
+ if ($new_tag eq "where") {
+ parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", $_);
+ $new_tag = "what";
+ }
+
if ($new_tag =~ m/what/) {
$space = "";
if ($tag =~ m/what/) {
--
2.21.0
^ permalink raw reply related
* [PATCH v2 03/16] scripts: add an script to parse the ABI files
From: Mauro Carvalho Chehab @ 2019-06-14 17:52 UTC (permalink / raw)
To: Linux Doc Mailing List, Greg Kroah-Hartman
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
Jonathan Corbet
In-Reply-To: <3b8d7c64f887ddea01df3c4eeabc745c8ec45406.1560534648.git.mchehab+samsung@kernel.org>
Add a script to parse the Documentation/ABI files and produce
an output with all entries inside an ABI (sub)directory.
Right now, it outputs its contents on ReST format. It shouldn't
be hard to make it produce other kind of outputs, since the ABI
file parser is implemented in separate than the output generator.
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
scripts/get_abi.pl | 212 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 212 insertions(+)
create mode 100755 scripts/get_abi.pl
diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl
new file mode 100755
index 000000000000..f7c9944a833c
--- /dev/null
+++ b/scripts/get_abi.pl
@@ -0,0 +1,212 @@
+#!/usr/bin/perl
+
+use strict;
+use Pod::Usage;
+use Getopt::Long;
+use File::Find;
+use Fcntl ':mode';
+
+my $help;
+my $man;
+my $debug;
+
+GetOptions(
+ "debug|d+" => \$debug,
+ 'help|?' => \$help,
+ man => \$man
+) or pod2usage(2);
+
+pod2usage(1) if $help;
+pod2usage(-exitstatus => 0, -verbose => 2) if $man;
+
+pod2usage(2) if (scalar @ARGV != 1);
+
+my ($prefix) = @ARGV;
+
+require Data::Dumper if ($debug);
+
+my %data;
+
+#
+# Displays an error message, printing file name and line
+#
+sub parse_error($$$$) {
+ my ($file, $ln, $msg, $data) = @_;
+
+ print STDERR "file $file#$ln: $msg at\n\t$data";
+}
+
+#
+# Parse an ABI file, storing its contents at %data
+#
+sub parse_abi {
+ my $file = $File::Find::name;
+
+ my $mode = (stat($file))[2];
+ return if ($mode & S_IFDIR);
+ return if ($file =~ m,/README,);
+
+ my $name = $file;
+ $name =~ s,.*/,,;
+
+ my $type = $file;
+ $type =~ s,.*/(.*)/.*,$1,;
+
+ my $what;
+ my $new_what;
+ my $tag;
+ my $ln;
+
+ print STDERR "Opening $file\n" if ($debug > 1);
+ open IN, $file;
+ while(<IN>) {
+ $ln++;
+ if (m/^(\S+):\s*(.*)/i) {
+ my $new_tag = lc($1);
+ my $content = $2;
+
+ if (!($new_tag =~ m/(what|date|kernelversion|contact|description|users)/)) {
+ if ($tag eq "description") {
+ $data{$what}->{$tag} .= "\n$content";;
+ $data{$what}->{$tag} =~ s/\n+$//;
+ next;
+ } else {
+ parse_error($file, $ln, "tag '$tag' is invalid", $_);
+ }
+ }
+
+ if ($new_tag =~ m/what/) {
+ if ($tag =~ m/what/) {
+ $what .= ", " . $content;
+ } else {
+ $what = $content;
+ $new_what = 1;
+ }
+ $tag = $new_tag;
+ next;
+ }
+
+ $tag = $new_tag;
+
+ if ($new_what) {
+ $new_what = 0;
+
+ $data{$what}->{type} = $type;
+ $data{$what}->{file} = $name;
+ print STDERR "\twhat: $what\n" if ($debug > 1);
+ }
+
+ if (!$what) {
+ parse_error($file, $ln, "'What:' should come first:", $_);
+ next;
+ }
+ $data{$what}->{$tag} = $content;
+ next;
+ }
+
+ # Silently ignore any headers before the database
+ next if (!$tag);
+
+ if (m/^\s*(.*)/) {
+ $data{$what}->{$tag} .= "\n$1";
+ $data{$what}->{$tag} =~ s/\n+$//;
+ next;
+ }
+
+ # Everything else is error
+ parse_error($file, $ln, "Unexpected line:", $_);
+ }
+ close IN;
+}
+
+# Outputs the output on ReST format
+sub output_rest {
+ foreach my $what (sort keys %data) {
+ my $type = $data{$what}->{type};
+ my $file = $data{$what}->{file};
+
+ my $w = $what;
+ $w =~ s/([\(\)\_\-\*\=\^\~\\])/\\$1/g;
+
+ print "$w\n\n";
+ print "- defined on file $file (type: $type)\n\n::\n\n";
+
+ my $desc = $data{$what}->{description};
+ $desc =~ s/^\s+//;
+
+ # Remove title markups from the description, as they won't work
+ $desc =~ s/\n[\-\*\=\^\~]+\n/\n/g;
+
+ # put everything inside a code block
+ $desc =~ s/\n/\n /g;
+
+
+ if (!($desc =~ /^\s*$/)) {
+ print " $desc\n\n";
+ } else {
+ print " DESCRIPTION MISSING\n\n";
+ }
+ }
+}
+
+#
+# Parses all ABI files located at $prefix dir
+#
+find({wanted =>\&parse_abi, no_chdir => 1}, $prefix);
+
+print STDERR Data::Dumper->Dump([\%data], [qw(*data)]) if ($debug);
+
+#
+# Outputs an ReST file with the ABI contents
+#
+output_rest
+
+
+__END__
+
+=head1 NAME
+
+abi_book.pl - parse the Linux ABI files and produce a ReST book.
+
+=head1 SYNOPSIS
+
+B<abi_book.pl> [--debug] <ABI_DIR>]
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<--debug>
+
+Put the script in verbose mode, useful for debugging. Can be called multiple
+times, to increase verbosity.
+
+=item B<--help>
+
+Prints a brief help message and exits.
+
+=item B<--man>
+
+Prints the manual page and exits.
+
+=back
+
+=head1 DESCRIPTION
+
+Parse the Linux ABI files from ABI DIR (usually located at Documentation/ABI)
+and produce a ReST book containing the Linux ABI.
+
+=head1 BUGS
+
+Report bugs to Mauro Carvalho Chehab <mchehab@s-opensource.com>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2016 by Mauro Carvalho Chehab <mchehab@s-opensource.com>.
+
+License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html>.
+
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+
+=cut
--
2.21.0
^ permalink raw reply related
* [PATCH v2 04/16] scripts/get_abi.pl: parse files with text at beginning
From: Mauro Carvalho Chehab @ 2019-06-14 17:52 UTC (permalink / raw)
To: Linux Doc Mailing List, Greg Kroah-Hartman
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
Jonathan Corbet
In-Reply-To: <3b8d7c64f887ddea01df3c4eeabc745c8ec45406.1560534648.git.mchehab+samsung@kernel.org>
It sounds usefult o parse files with has some text at the
beginning. Add support for it.
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
scripts/get_abi.pl | 59 ++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 54 insertions(+), 5 deletions(-)
diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl
index f7c9944a833c..ef9b6e108973 100755
--- a/scripts/get_abi.pl
+++ b/scripts/get_abi.pl
@@ -55,7 +55,10 @@ sub parse_abi {
my $what;
my $new_what;
my $tag;
+ my $label;
my $ln;
+ my $has_file;
+ my $xrefs;
print STDERR "Opening $file\n" if ($debug > 1);
open IN, $file;
@@ -67,7 +70,7 @@ sub parse_abi {
if (!($new_tag =~ m/(what|date|kernelversion|contact|description|users)/)) {
if ($tag eq "description") {
- $data{$what}->{$tag} .= "\n$content";;
+ $data{$what}->{$tag} .= "\n$content";
$data{$what}->{$tag} =~ s/\n+$//;
next;
} else {
@@ -83,6 +86,25 @@ sub parse_abi {
$new_what = 1;
}
$tag = $new_tag;
+
+ if ($has_file) {
+ $label = "abi_" . $content . " ";
+ $label =~ tr/A-Z/a-z/;
+
+ # Convert special chars to "_"
+ $label =~s/[\x00-\x2f]+/_/g;
+ $label =~s/[\x3a-\x40]+/_/g;
+ $label =~s/[\x7b-\xff]+/_/g;
+ $label =~ s,_+,_,g;
+ $label =~ s,_$,,;
+
+ $data{$what}->{label} .= $label;
+
+ # Escape special chars from content
+ $content =~s/([\x00-\x1f\x21-\x2f\x3a-\x40\x7b-\xff])/\\$1/g;
+
+ $xrefs .= "- :ref:`$content <$label>`\n\n";
+ }
next;
}
@@ -104,8 +126,18 @@ sub parse_abi {
next;
}
- # Silently ignore any headers before the database
- next if (!$tag);
+ # Store any contents before the database
+ if (!$tag) {
+ next if (/^\n/);
+
+ my $my_what = "File $name";
+ $data{$my_what}->{what} = "File $name";
+ $data{$my_what}->{type} = "File";
+ $data{$my_what}->{file} = $name;
+ $data{$my_what}->{description} .= $_;
+ $has_file = 1;
+ next;
+ }
if (m/^\s*(.*)/) {
$data{$what}->{$tag} .= "\n$1";
@@ -117,6 +149,11 @@ sub parse_abi {
parse_error($file, $ln, "Unexpected line:", $_);
}
close IN;
+
+ if ($has_file) {
+ my $my_what = "File $name";
+ $data{$my_what}->{xrefs} = $xrefs;
+ }
}
# Outputs the output on ReST format
@@ -128,8 +165,17 @@ sub output_rest {
my $w = $what;
$w =~ s/([\(\)\_\-\*\=\^\~\\])/\\$1/g;
+ if ($data{$what}->{label}) {
+ my @labels = split(/\s/, $data{$what}->{label});
+ foreach my $label (@labels) {
+ printf ".. _%s:\n\n", $label;
+ }
+ }
+
print "$w\n\n";
- print "- defined on file $file (type: $type)\n\n::\n\n";
+
+ print "- defined on file $file (type: $type)\n\n" if ($type ne "File");
+ print "::\n\n";
my $desc = $data{$what}->{description};
$desc =~ s/^\s+//;
@@ -144,8 +190,11 @@ sub output_rest {
if (!($desc =~ /^\s*$/)) {
print " $desc\n\n";
} else {
- print " DESCRIPTION MISSING\n\n";
+ print " DESCRIPTION MISSING for $what\n\n";
}
+
+ printf "Has the following ABI:\n\n%s", $data{$what}->{xrefs} if ($data{$what}->{xrefs});
+
}
}
--
2.21.0
^ permalink raw reply related
* [PATCH v2 09/16] scripts/get_abi.pl: fix parse issues with some files
From: Mauro Carvalho Chehab @ 2019-06-14 17:52 UTC (permalink / raw)
To: Linux Doc Mailing List, Greg Kroah-Hartman
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
Jonathan Corbet
In-Reply-To: <3b8d7c64f887ddea01df3c4eeabc745c8ec45406.1560534648.git.mchehab+samsung@kernel.org>
A few files are failing to parse:
Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats
Documentation/ABI/testing/sysfs-class-pktcdvd
Documentation/ABI/testing/sysfs-bus-nfit
On all three files, the problem is that there is a ":" character
at the initial file description.
Improve the parse in order to handle those special cases.
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
scripts/get_abi.pl | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl
index 7d454e359d25..116f0c33c16d 100755
--- a/scripts/get_abi.pl
+++ b/scripts/get_abi.pl
@@ -87,7 +87,7 @@ sub parse_abi {
# New "tag" is actually part of
# description. Don't consider it a tag
$new_tag = "";
- } else {
+ } elsif ($tag ne "") {
parse_error($file, $ln, "tag '$tag' is invalid", $_);
}
}
@@ -110,7 +110,7 @@ sub parse_abi {
next;
}
- if ($new_tag) {
+ if ($tag ne "" && $new_tag) {
$tag = $new_tag;
if ($new_what) {
--
2.21.0
^ permalink raw reply related
* [PATCH v2 16/16] docs: Kconfig/Makefile: add a check for broken ABI files
From: Mauro Carvalho Chehab @ 2019-06-14 17:52 UTC (permalink / raw)
To: Linux Doc Mailing List, Greg Kroah-Hartman
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
Jonathan Corbet, Andrew Morton, Masahiro Yamada, Kees Cook,
Petr Mladek, Andy Shevchenko, Matthew Wilcox, Joe Lawrence,
Mikulas Patocka, Tetsuo Handa, Sri Krishna chowdary, Changbin Du
In-Reply-To: <3b8d7c64f887ddea01df3c4eeabc745c8ec45406.1560534648.git.mchehab+samsung@kernel.org>
The files under Documentation/ABI should follow the syntax
as defined at Documentation/ABI/README.
Allow checking if they're following the syntax by running
the ABI parser script on COMPILE_TEST.
With that, when there's a problem with a file under
Documentation/ABI, it would produce a warning like:
Warning: file ./Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats#14:
What '/sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_cor' doesn't have a description
Warning: file ./Documentation/ABI/testing/sysfs-bus-pci-devices-aer_stats#21:
What '/sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_fatal' doesn't have a description
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
Documentation/Kconfig | 11 +++++++++++
Documentation/Makefile | 5 +++++
lib/Kconfig.debug | 2 ++
scripts/get_abi.pl | 14 +++++++++++---
4 files changed, 29 insertions(+), 3 deletions(-)
create mode 100644 Documentation/Kconfig
diff --git a/Documentation/Kconfig b/Documentation/Kconfig
new file mode 100644
index 000000000000..a8b0701c1422
--- /dev/null
+++ b/Documentation/Kconfig
@@ -0,0 +1,11 @@
+config WARN_ABI_ERRORS
+ bool "Warn if there are errors at ABI files"
+ depends on COMPILE_TEST
+ help
+ The files under Documentation/ABI should follow what's
+ described at Documentation/ABI/README. Yet, as they're manually
+ written, it would be possible that some of those files would
+ have errors that would break them for being parsed by
+ scripts/get_abi.pl. Add a check to verify them.
+
+ If unsure, select 'N'.
diff --git a/Documentation/Makefile b/Documentation/Makefile
index e889e7cb8511..c6480ed22884 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -4,6 +4,11 @@
subdir-y := devicetree/bindings/
+# Check for broken ABI files
+ifeq ($(CONFIG_WARN_ABI_ERRORS),y)
+$(shell $(srctree)/scripts/get_abi.pl validate --dir $(srctree)/Documentation/ABI)
+endif
+
# You can set these variables from the command line.
SPHINXBUILD = sphinx-build
SPHINXOPTS =
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index cbdfae379896..b1b7e141ca99 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2110,4 +2110,6 @@ config IO_STRICT_DEVMEM
source "arch/$(SRCARCH)/Kconfig.debug"
+source "Documentation/Kconfig"
+
endmenu # Kernel hacking
diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl
index 774e9b809ead..25248c012eb3 100755
--- a/scripts/get_abi.pl
+++ b/scripts/get_abi.pl
@@ -38,7 +38,15 @@ my %data;
sub parse_error($$$$) {
my ($file, $ln, $msg, $data) = @_;
- print STDERR "file $file#$ln: $msg at\n\t$data";
+ $data =~ s/\s+$/\n/;
+
+ print STDERR "Warning: file $file#$ln:\n\t$msg";
+
+ if ($data ne "") {
+ print STDERR ". Line\n\t\t$data";
+ } else {
+ print STDERR "\n";
+ }
}
#
@@ -94,7 +102,7 @@ sub parse_abi {
# Invalid, but it is a common mistake
if ($new_tag eq "where") {
- parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", $_);
+ parse_error($file, $ln, "tag 'Where' is invalid. Should be 'What:' instead", "");
$new_tag = "what";
}
@@ -190,7 +198,7 @@ sub parse_abi {
}
# Everything else is error
- parse_error($file, $ln, "Unexpected line:", $_);
+ parse_error($file, $ln, "Unexpected content", $_);
}
$data{$nametag}->{description} =~ s/^\n+//;
close IN;
--
2.21.0
^ permalink raw reply related
* [PATCH v2 10/16] scripts/get_abi.pl: avoid creating duplicate names
From: Mauro Carvalho Chehab @ 2019-06-14 17:52 UTC (permalink / raw)
To: Linux Doc Mailing List, Greg Kroah-Hartman
Cc: Mauro Carvalho Chehab, Mauro Carvalho Chehab, linux-kernel,
Jonathan Corbet
In-Reply-To: <3b8d7c64f887ddea01df3c4eeabc745c8ec45406.1560534648.git.mchehab+samsung@kernel.org>
The file the Documentation/ABI/testing/sysfs-class-power has
voltage_min, voltage_max and voltage_now symbols duplicated.
They are defined first for "General Properties" and then for
"USB Properties".
This cause those warnings:
get_abi.pl rest --dir $srctree/Documentation/ABI/testing:26933: WARNING: Duplicate explicit target name: "abi_sys_class_power_supply_supply_name_voltage_max".
get_abi.pl rest --dir $srctree/Documentation/ABI/testing:26968: WARNING: Duplicate explicit target name: "abi_sys_class_power_supply_supply_name_voltage_min".
get_abi.pl rest --dir $srctree/Documentation/ABI/testing:27008: WARNING: Duplicate explicit target name: "abi_sys_class_power_supply_supply_name_voltage_now".
And, as the references are not valid, it will also generate
warnings about links to undefined references.
Fix it by storing labels into a hash table and, when a duplicated
one is found, appending random characters at the end.
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
scripts/get_abi.pl | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/scripts/get_abi.pl b/scripts/get_abi.pl
index 116f0c33c16d..329ace635ac2 100755
--- a/scripts/get_abi.pl
+++ b/scripts/get_abi.pl
@@ -194,6 +194,8 @@ sub parse_abi {
# Outputs the book on ReST format
#
+my %labels;
+
sub output_rest {
foreach my $what (sort {
($data{$a}->{type} eq "File") cmp ($data{$b}->{type} eq "File") ||
@@ -217,6 +219,13 @@ sub output_rest {
$label =~ s,_+,_,g;
$label =~ s,_$,,;
+ # Avoid duplicated labels
+ while (defined($labels{$label})) {
+ my @chars = ("A".."Z", "a".."z");
+ $label .= $chars[rand @chars];
+ }
+ $labels{$label} = 1;
+
$data{$what}->{label} .= $label;
printf ".. _%s:\n\n", $label;
--
2.21.0
^ permalink raw reply related
* [PATCH v4 00/14] ima: introduce IMA Digest Lists extension
From: Roberto Sassu @ 2019-06-14 17:54 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
This patch set introduces a new IMA extension called IMA Digest Lists.
At early boot, the extension preloads in kernel memory reference digest
values, that can be compared with actual file digests when files are
accessed in the system.
The extension will open for new possibilities: PCR with predictable value,
that can be used for sealing policies associated to data or TPM keys;
appraisal based on reference digests already provided by Linux distribution
vendors in the software packages.
The first objective can be achieved because the PCR values does not depend
on which and when files are measured: the extension measures digest lists
sequentially and files whose digest is not in the digest list.
The second objective can be reached because the extension is able to
extract reference measurements from packages (with a user space tool) and
use it as a source for appraisal verification as the reference came from
the security.ima xattr. This approach will also reduce the overhead as only
one signature is verified for many files (as opposed to one signature for
each file with the current implementation).
This version of the patch set provides a clear separation between current
and new functionality. First, the new functionality must be explicitly
enabled from the kernel command line. Second, results of operations
performed by the extension can be distinguished from those obtained from
the existing code: measurement entries created by the extension have a
different PCR; mutable files appraised with the extension have a different
security.ima type.
The review of this patch set should start from patch 11 and 12, which
modify the IMA-Measure and IMA-Appraise submodules to use digest lists.
Patch 1 to 5 are prerequisites. Patch 6 to 10 adds support for digest
lists. Finally, patch 13 introduces two new policies to measure/appraise
rootfs and patch 14 adds the documentation (including a flow chart to
show how IMA has been modified).
The user space tools to configure digest lists are available at:
https://github.com/euleros/digest-list-tools/releases/tag/v0.3
The patch set applies on top of linux-integrity/next-queued-testing
(73589972b987).
It is necessary to apply also:
https://patchwork.kernel.org/cover/10957495/
To use appraisal, it is necessary to use a modified cpio and a modified
dracut:
https://github.com/euleros/cpio/tree/xattr-v1
https://github.com/euleros/dracut/tree/digest-lists
For now, please use it only in a testing environment.
Changelog
v3:
- move ima_lookup_loaded_digest() and ima_add_digest_data_entry() from
ima_queue.c to ima_digest_list.c
- remove patch that introduces security.ima_algo
- add version number and type modifiers to the compact list header
- remove digest list metadata, all digest lists in the directory are
accessed
- move loading of signing keys to user space
- add violation for both PCRs if they are selected
- introduce two new appraisal modes
v2:
- add support for multiple hash algorithms
- remove RPM parser from the kernel
- add support for parsing digest lists in user space
v1:
- add support for immutable/mutable files
- add support for appraisal with digest lists
Roberto Sassu (14):
ima: read hash algorithm from security.ima even if appraisal is not
enabled
ima: generalize ima_read_policy()
ima: generalize ima_write_policy() and raise uploaded data size limit
ima: generalize policy file operations
ima: use ima_show_htable_value to show violations and hash table data
ima: add parser of compact digest list
ima: restrict upload of converted digest lists
ima: prevent usage of digest lists that are not measured/appraised
ima: introduce new securityfs files
ima: load parser digests and execute the parser at boot time
ima: add support for measurement with digest lists
ima: add support for appraisal with digest lists
ima: introduce new policies initrd and appraise_initrd
ima: add Documentation/security/IMA-digest-lists.txt
.../admin-guide/kernel-parameters.txt | 16 +-
Documentation/security/IMA-digest-lists.txt | 226 +++++++++++++
include/linux/evm.h | 6 +
include/linux/fs.h | 1 +
security/integrity/evm/evm_main.c | 2 +-
security/integrity/iint.c | 1 +
security/integrity/ima/Kconfig | 25 ++
security/integrity/ima/Makefile | 1 +
security/integrity/ima/ima.h | 32 +-
security/integrity/ima/ima_api.c | 43 ++-
security/integrity/ima/ima_appraise.c | 92 +++---
security/integrity/ima/ima_digest_list.c | 309 ++++++++++++++++++
security/integrity/ima/ima_digest_list.h | 69 ++++
security/integrity/ima/ima_fs.c | 224 ++++++++-----
security/integrity/ima/ima_init.c | 2 +-
security/integrity/ima/ima_main.c | 81 ++++-
security/integrity/ima/ima_policy.c | 29 +-
security/integrity/integrity.h | 22 ++
18 files changed, 1018 insertions(+), 163 deletions(-)
create mode 100644 Documentation/security/IMA-digest-lists.txt
create mode 100644 security/integrity/ima/ima_digest_list.c
create mode 100644 security/integrity/ima/ima_digest_list.h
--
2.17.1
^ permalink raw reply
* [PATCH v4 01/14] ima: read hash algorithm from security.ima even if appraisal is not enabled
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
IMA reads the hash algorithm from security.ima, if exists, so that a
signature can be verified even if the algorithm used for the signature
differs from IMA algorithm.
This patch moves ima_read_xattr() and ima_get_hash_algo() to ima_main.c, to
retrieve the algorithm even if appraisal is not enabled. Knowing the
algorithm in advance would be useful also for measurement. The new Digest
Lists extension does not add a new entry to the measurement list if the
actual file digest is found in a loaded list. It might be possible that the
algorithm used for the digest lists differs from IMA algorithm.
This patch also changes the requirement that security.ima must contain a
signature, if the type is EVM_IMA_XATTR_DIGSIG. A signature with length
zero is accepted.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/ima/ima.h | 16 --------
security/integrity/ima/ima_appraise.c | 55 ++-------------------------
security/integrity/ima/ima_main.c | 51 +++++++++++++++++++++++++
3 files changed, 55 insertions(+), 67 deletions(-)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index ee509c68fe14..b4a0d2a02ff2 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -248,10 +248,6 @@ int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
enum ima_hooks func);
-enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
- int xattr_len);
-int ima_read_xattr(struct dentry *dentry,
- struct evm_ima_xattr_data **xattr_value);
#else
static inline int ima_appraise_measurement(enum ima_hooks func,
@@ -282,18 +278,6 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c
return INTEGRITY_UNKNOWN;
}
-static inline enum hash_algo
-ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len)
-{
- return ima_hash_algo;
-}
-
-static inline int ima_read_xattr(struct dentry *dentry,
- struct evm_ima_xattr_data **xattr_value)
-{
- return 0;
-}
-
#endif /* CONFIG_IMA_APPRAISE */
/* LSM based policy rules require audit */
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 9b3b172f9748..2566dbfd2464 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -151,57 +151,6 @@ static void ima_cache_flags(struct integrity_iint_cache *iint,
}
}
-enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
- int xattr_len)
-{
- struct signature_v2_hdr *sig;
- enum hash_algo ret;
-
- if (!xattr_value || xattr_len < 2)
- /* return default hash algo */
- return ima_hash_algo;
-
- switch (xattr_value->type) {
- case EVM_IMA_XATTR_DIGSIG:
- sig = (typeof(sig))xattr_value;
- if (sig->version != 2 || xattr_len <= sizeof(*sig))
- return ima_hash_algo;
- return sig->hash_algo;
- break;
- case IMA_XATTR_DIGEST_NG:
- ret = xattr_value->digest[0];
- if (ret < HASH_ALGO__LAST)
- return ret;
- break;
- case IMA_XATTR_DIGEST:
- /* this is for backward compatibility */
- if (xattr_len == 21) {
- unsigned int zero = 0;
- if (!memcmp(&xattr_value->digest[16], &zero, 4))
- return HASH_ALGO_MD5;
- else
- return HASH_ALGO_SHA1;
- } else if (xattr_len == 17)
- return HASH_ALGO_MD5;
- break;
- }
-
- /* return default hash algo */
- return ima_hash_algo;
-}
-
-int ima_read_xattr(struct dentry *dentry,
- struct evm_ima_xattr_data **xattr_value)
-{
- ssize_t ret;
-
- ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
- 0, GFP_NOFS);
- if (ret == -EOPNOTSUPP)
- ret = 0;
- return ret;
-}
-
/*
* ima_appraise_measurement - appraise file measurement
*
@@ -226,6 +175,10 @@ int ima_appraise_measurement(enum ima_hooks func,
if (!(inode->i_opflags & IOP_XATTR))
return INTEGRITY_UNKNOWN;
+ if (xattr_len == sizeof(struct signature_v2_hdr) &&
+ xattr_value->type == EVM_IMA_XATTR_DIGSIG)
+ rc = -ENODATA;
+
if (rc <= 0) {
if (rc && rc != -ENODATA)
goto out;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 0c49cf6470a4..dc53ed8b0dd0 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -143,6 +143,57 @@ static void ima_rdwr_violation_check(struct file *file,
"invalid_pcr", "open_writers");
}
+static enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
+ int xattr_len)
+{
+ struct signature_v2_hdr *sig;
+ enum hash_algo ret;
+
+ if (!xattr_value || xattr_len < 2)
+ /* return default hash algo */
+ return ima_hash_algo;
+
+ switch (xattr_value->type) {
+ case EVM_IMA_XATTR_DIGSIG:
+ sig = (typeof(sig))xattr_value;
+ if (sig->version != 2 || xattr_len < sizeof(*sig))
+ return ima_hash_algo;
+ return sig->hash_algo;
+ case IMA_XATTR_DIGEST_NG:
+ ret = xattr_value->digest[0];
+ if (ret < HASH_ALGO__LAST)
+ return ret;
+ break;
+ case IMA_XATTR_DIGEST:
+ /* this is for backward compatibility */
+ if (xattr_len == 21) {
+ unsigned int zero = 0;
+
+ if (!memcmp(&xattr_value->digest[16], &zero, 4))
+ return HASH_ALGO_MD5;
+ else
+ return HASH_ALGO_SHA1;
+ } else if (xattr_len == 17)
+ return HASH_ALGO_MD5;
+ break;
+ }
+
+ /* return default hash algo */
+ return ima_hash_algo;
+}
+
+static int ima_read_xattr(struct dentry *dentry,
+ struct evm_ima_xattr_data **xattr_value)
+{
+ ssize_t ret;
+
+ ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
+ 0, GFP_NOFS);
+ if (ret == -EOPNOTSUPP)
+ ret = 0;
+ return ret;
+}
+
static void ima_check_last_writer(struct integrity_iint_cache *iint,
struct inode *inode, struct file *file)
{
--
2.17.1
^ permalink raw reply related
* [PATCH v4 02/14] ima: generalize ima_read_policy()
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
Rename ima_read_policy() to ima_read_file(), and add file_id as a new
parameter. If file_id is equal to READING_POLICY, ima_read_file() behavior
remains unchanged. If file_id will be READING_DIGEST_LIST (not yet
defined), ima_read_file() will read and parse a digest list from a file
whose path is written to securityfs.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/ima/ima_fs.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 2000e8df0301..02980b55a3f1 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -272,7 +272,7 @@ static const struct file_operations ima_ascii_measurements_ops = {
.release = seq_release,
};
-static ssize_t ima_read_policy(char *path)
+static ssize_t ima_read_file(char *path, enum kernel_read_file_id file_id)
{
void *data;
char *datap;
@@ -285,16 +285,26 @@ static ssize_t ima_read_policy(char *path)
datap = path;
strsep(&datap, "\n");
- rc = kernel_read_file_from_path(path, &data, &size, 0, READING_POLICY);
+ rc = kernel_read_file_from_path(path, &data, &size, 0, file_id);
if (rc < 0) {
pr_err("Unable to open file: %s (%d)", path, rc);
return rc;
}
datap = data;
- while (size > 0 && (p = strsep(&datap, "\n"))) {
- pr_debug("rule: %s\n", p);
- rc = ima_parse_add_rule(p);
+ while (size > 0) {
+ switch (file_id) {
+ case READING_POLICY:
+ p = strsep(&datap, "\n");
+ if (p == NULL)
+ break;
+
+ pr_debug("rule: %s\n", p);
+ rc = ima_parse_add_rule(p);
+ break;
+ default:
+ break;
+ }
if (rc < 0)
break;
size -= rc;
@@ -334,7 +344,7 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
goto out_free;
if (data[0] == '/') {
- result = ima_read_policy(data);
+ result = ima_read_file(data, READING_POLICY);
} else if (ima_appraise & IMA_APPRAISE_POLICY) {
pr_err("signed policy file (specified as an absolute pathname) required\n");
integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
--
2.17.1
^ permalink raw reply related
* [PATCH v4 03/14] ima: generalize ima_write_policy() and raise uploaded data size limit
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
ima_write_policy() is being used to load a new policy from user space. This
function can be reused to load different types of data.
This patch renames ima_write_policy() to ima_write_data() and executes the
appropriate actions depending on the opened file in the securityfs
filesystem.
Also, this patch raises the uploaded data size limit to 64M, to accept
files (e.g. digest lists) larger than a policy. The same limit is used
for the SELinux policy.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/ima/ima_fs.c | 68 +++++++++++++++++++--------------
1 file changed, 40 insertions(+), 28 deletions(-)
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 02980b55a3f1..9a10b62e380f 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -27,6 +27,14 @@
static DEFINE_MUTEX(ima_write_mutex);
+static struct dentry *ima_dir;
+static struct dentry *ima_symlink;
+static struct dentry *binary_runtime_measurements;
+static struct dentry *ascii_runtime_measurements;
+static struct dentry *runtime_measurements_count;
+static struct dentry *violations;
+static struct dentry *ima_policy;
+
bool ima_canonical_fmt;
static int __init default_canonical_fmt_setup(char *str)
{
@@ -319,25 +327,32 @@ static ssize_t ima_read_file(char *path, enum kernel_read_file_id file_id)
return pathlen;
}
-static ssize_t ima_write_policy(struct file *file, const char __user *buf,
- size_t datalen, loff_t *ppos)
+static ssize_t ima_write_data(struct file *file, const char __user *buf,
+ size_t datalen, loff_t *ppos)
{
char *data;
ssize_t result;
-
- if (datalen >= PAGE_SIZE)
- datalen = PAGE_SIZE - 1;
+ struct dentry *dentry = file_dentry(file);
/* No partial writes. */
result = -EINVAL;
if (*ppos != 0)
goto out;
- data = memdup_user_nul(buf, datalen);
- if (IS_ERR(data)) {
- result = PTR_ERR(data);
+ result = -EFBIG;
+ if (datalen + 1 > 64 * 1024 * 1024)
goto out;
- }
+
+ result = -ENOMEM;
+ data = vmalloc(datalen + 1);
+ if (!data)
+ goto out;
+
+ result = -EFAULT;
+ if (copy_from_user(data, buf, datalen) != 0)
+ goto out_free;
+
+ data[datalen] = '\0';
result = mutex_lock_interruptible(&ima_write_mutex);
if (result < 0)
@@ -345,34 +360,31 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
if (data[0] == '/') {
result = ima_read_file(data, READING_POLICY);
- } else if (ima_appraise & IMA_APPRAISE_POLICY) {
- pr_err("signed policy file (specified as an absolute pathname) required\n");
- integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
- "policy_update", "signed policy required",
- 1, 0);
- if (ima_appraise & IMA_APPRAISE_ENFORCE)
- result = -EACCES;
+ } else if (dentry == ima_policy) {
+ if (ima_appraise & IMA_APPRAISE_POLICY) {
+ pr_err("signed policy file (specified as an absolute pathname) required\n");
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
+ "policy_update",
+ "signed policy required", 1, 0);
+ if (ima_appraise & IMA_APPRAISE_ENFORCE)
+ result = -EACCES;
+ } else {
+ result = ima_parse_add_rule(data);
+ }
} else {
- result = ima_parse_add_rule(data);
+ pr_err("Unknown data type\n");
+ result = -EINVAL;
}
mutex_unlock(&ima_write_mutex);
out_free:
- kfree(data);
+ vfree(data);
out:
- if (result < 0)
+ if (dentry == ima_policy && result < 0)
valid_policy = 0;
return result;
}
-static struct dentry *ima_dir;
-static struct dentry *ima_symlink;
-static struct dentry *binary_runtime_measurements;
-static struct dentry *ascii_runtime_measurements;
-static struct dentry *runtime_measurements_count;
-static struct dentry *violations;
-static struct dentry *ima_policy;
-
enum ima_fs_flags {
IMA_FS_BUSY,
};
@@ -453,7 +465,7 @@ static int ima_release_policy(struct inode *inode, struct file *file)
static const struct file_operations ima_measure_policy_ops = {
.open = ima_open_policy,
- .write = ima_write_policy,
+ .write = ima_write_data,
.read = seq_read,
.release = ima_release_policy,
.llseek = generic_file_llseek,
--
2.17.1
^ permalink raw reply related
* [PATCH v4 04/14] ima: generalize policy file operations
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
This patch renames ima_open_policy() and ima_release_policy() respectively
to ima_open_data_upload() and ima_release_data_upload(). They will be used
to implement file operations for interfaces allowing to load data from user
space.
A new flag (IMA_POLICY_BUSY) has been defined to prevent concurrent policy
upload.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/ima/ima_fs.c | 58 ++++++++++++++++++++++++---------
1 file changed, 43 insertions(+), 15 deletions(-)
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 9a10b62e380f..c8bbc56f735e 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -386,9 +386,20 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf,
}
enum ima_fs_flags {
+ IMA_POLICY_BUSY,
IMA_FS_BUSY,
};
+static enum ima_fs_flags ima_get_dentry_flag(struct dentry *dentry)
+{
+ enum ima_fs_flags flag = IMA_FS_BUSY;
+
+ if (dentry == ima_policy)
+ flag = IMA_POLICY_BUSY;
+
+ return flag;
+}
+
static unsigned long ima_fs_flags;
#ifdef CONFIG_IMA_READ_POLICY
@@ -401,22 +412,32 @@ static const struct seq_operations ima_policy_seqops = {
#endif
/*
- * ima_open_policy: sequentialize access to the policy file
+ * ima_open_data_upload: sequentialize access to the data upload interface
*/
-static int ima_open_policy(struct inode *inode, struct file *filp)
+static int ima_open_data_upload(struct inode *inode, struct file *filp)
{
+ struct dentry *dentry = file_dentry(filp);
+ const struct seq_operations *seq_ops = NULL;
+ enum ima_fs_flags flag = ima_get_dentry_flag(dentry);
+ bool read_allowed = false;
+
+ if (dentry == ima_policy) {
+#ifdef CONFIG_IMA_READ_POLICY
+ read_allowed = true;
+ seq_ops = &ima_policy_seqops;
+#endif
+ }
+
if (!(filp->f_flags & O_WRONLY)) {
-#ifndef CONFIG_IMA_READ_POLICY
- return -EACCES;
-#else
+ if (!read_allowed)
+ return -EACCES;
if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
return -EACCES;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- return seq_open(filp, &ima_policy_seqops);
-#endif
+ return seq_open(filp, seq_ops);
}
- if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
+ if (test_and_set_bit(flag, &ima_fs_flags))
return -EBUSY;
return 0;
}
@@ -428,13 +449,20 @@ static int ima_open_policy(struct inode *inode, struct file *filp)
* point to the new policy rules, and remove the securityfs policy file,
* assuming a valid policy.
*/
-static int ima_release_policy(struct inode *inode, struct file *file)
+static int ima_release_data_upload(struct inode *inode, struct file *file)
{
+ struct dentry *dentry = file_dentry(file);
const char *cause = valid_policy ? "completed" : "failed";
+ enum ima_fs_flags flag = ima_get_dentry_flag(dentry);
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return seq_release(inode, file);
+ if (dentry != ima_policy) {
+ clear_bit(flag, &ima_fs_flags);
+ return 0;
+ }
+
if (valid_policy && ima_check_policy() < 0) {
cause = "failed";
valid_policy = 0;
@@ -447,7 +475,7 @@ static int ima_release_policy(struct inode *inode, struct file *file)
if (!valid_policy) {
ima_delete_rules();
valid_policy = 1;
- clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+ clear_bit(flag, &ima_fs_flags);
return 0;
}
@@ -456,18 +484,18 @@ static int ima_release_policy(struct inode *inode, struct file *file)
securityfs_remove(ima_policy);
ima_policy = NULL;
#elif defined(CONFIG_IMA_WRITE_POLICY)
- clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+ clear_bit(flag, &ima_fs_flags);
#elif defined(CONFIG_IMA_READ_POLICY)
inode->i_mode &= ~S_IWUSR;
#endif
return 0;
}
-static const struct file_operations ima_measure_policy_ops = {
- .open = ima_open_policy,
+static const struct file_operations ima_data_upload_ops = {
+ .open = ima_open_data_upload,
.write = ima_write_data,
.read = seq_read,
- .release = ima_release_policy,
+ .release = ima_release_data_upload,
.llseek = generic_file_llseek,
};
@@ -511,7 +539,7 @@ int __init ima_fs_init(void)
ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
ima_dir, NULL,
- &ima_measure_policy_ops);
+ &ima_data_upload_ops);
if (IS_ERR(ima_policy))
goto out;
--
2.17.1
^ permalink raw reply related
* [PATCH v4 05/14] ima: use ima_show_htable_value to show violations and hash table data
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
ima_show_htable_violations() and ima_show_measurements_count() both call
ima_show_htable_value() to copy the value of an atomic_long_t variable to
a buffer.
This patch modifies the definition of ima_show_htable_value(), so that this
function can be used in any file_operations structure. The atomic_long_t
variable used as source is chosen depending on the opened file in the
securityfs filesystem.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/ima/ima_fs.c | 38 +++++++++++----------------------
1 file changed, 12 insertions(+), 26 deletions(-)
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index c8bbc56f735e..0f503b7cd396 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -47,38 +47,24 @@ __setup("ima_canonical_fmt", default_canonical_fmt_setup);
static int valid_policy = 1;
-static ssize_t ima_show_htable_value(char __user *buf, size_t count,
- loff_t *ppos, atomic_long_t *val)
+static ssize_t ima_show_htable_value(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
{
+ atomic_long_t *val = NULL;
char tmpbuf[32]; /* greater than largest 'long' string value */
ssize_t len;
+ if (filp->f_path.dentry == violations)
+ val = &ima_htable.violations;
+ else if (filp->f_path.dentry == runtime_measurements_count)
+ val = &ima_htable.len;
+
len = scnprintf(tmpbuf, sizeof(tmpbuf), "%li\n", atomic_long_read(val));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
}
-static ssize_t ima_show_htable_violations(struct file *filp,
- char __user *buf,
- size_t count, loff_t *ppos)
-{
- return ima_show_htable_value(buf, count, ppos, &ima_htable.violations);
-}
-
-static const struct file_operations ima_htable_violations_ops = {
- .read = ima_show_htable_violations,
- .llseek = generic_file_llseek,
-};
-
-static ssize_t ima_show_measurements_count(struct file *filp,
- char __user *buf,
- size_t count, loff_t *ppos)
-{
- return ima_show_htable_value(buf, count, ppos, &ima_htable.len);
-
-}
-
-static const struct file_operations ima_measurements_count_ops = {
- .read = ima_show_measurements_count,
+static const struct file_operations ima_htable_value_ops = {
+ .read = ima_show_htable_value,
.llseek = generic_file_llseek,
};
@@ -527,13 +513,13 @@ int __init ima_fs_init(void)
runtime_measurements_count =
securityfs_create_file("runtime_measurements_count",
S_IRUSR | S_IRGRP, ima_dir, NULL,
- &ima_measurements_count_ops);
+ &ima_htable_value_ops);
if (IS_ERR(runtime_measurements_count))
goto out;
violations =
securityfs_create_file("violations", S_IRUSR | S_IRGRP,
- ima_dir, NULL, &ima_htable_violations_ops);
+ ima_dir, NULL, &ima_htable_value_ops);
if (IS_ERR(violations))
goto out;
--
2.17.1
^ permalink raw reply related
* [PATCH v4 06/14] ima: add parser of compact digest list
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
This patch introduces the parser of the compact digest list. The format is
optimized to store a large quantity of data with the same type. It is the
only format supported by the kernel.
Digest lists can be parsed directly by the kernel like the policy or, if
they are in a different format, they can be parsed by a user space parser,
and uploaded to IMA after they have been converted to the compact list
format.
A compact list is a set of consecutive data blocks, each consisting of a
header and a payload. The header indicates the type of data, how many
elements and the length of the payload.
The COMPACT_KEY data type indicates that the payload contains keys for
verifying digest list signatures. COMPACT_PARSER is used for digests of the
parser binary and shared libraries. COMPACT_FILE is used for digests of
regular files.
The header contains also a type modifier to indicate attributes of the
elements included in the payload. The COMPACT_MOD_IMMUTABLE modifier
indicates that a file can be opened only for read, if appraisal is in
enforcing mode.
This patch also introduces ima_lookup_loaded_digest() and
ima_add_digest_data_entry() to search and add digests in the new hash table
(ima_digests_htable).
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/ima/Kconfig | 10 ++
security/integrity/ima/Makefile | 1 +
security/integrity/ima/ima_digest_list.c | 152 +++++++++++++++++++++++
security/integrity/ima/ima_digest_list.h | 40 ++++++
security/integrity/integrity.h | 12 ++
5 files changed, 215 insertions(+)
create mode 100644 security/integrity/ima/ima_digest_list.c
create mode 100644 security/integrity/ima/ima_digest_list.h
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 2ced99dde694..b3a7b46d21cf 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -297,3 +297,13 @@ config IMA_APPRAISE_SIGNED_INIT
default n
help
This option requires user-space init to be signed.
+
+config IMA_DIGEST_LIST
+ bool "Measure and appraise files with digest lists"
+ depends on IMA
+ default n
+ help
+ This option allows users to load digest lists. If calculated digests
+ of accessed files are found in one of those lists, no new entries are
+ added to the measurement list, and access to the file is granted if
+ appraisal is in enforcing mode.
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index d921dc4f9eb0..29b49c7aacd0 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -10,4 +10,5 @@ ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
ima_policy.o ima_template.o ima_template_lib.o
ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
ima-$(CONFIG_HAVE_IMA_KEXEC) += ima_kexec.o
+ima-$(CONFIG_IMA_DIGEST_LIST) += ima_digest_list.o
obj-$(CONFIG_IMA_BLACKLIST_KEYRING) += ima_mok.o
diff --git a/security/integrity/ima/ima_digest_list.c b/security/integrity/ima/ima_digest_list.c
new file mode 100644
index 000000000000..6c7dd2cfbb68
--- /dev/null
+++ b/security/integrity/ima/ima_digest_list.c
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017-2019 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * File: ima_digest_list.c
+ * Functions to manage digest lists.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+
+#include "ima.h"
+#include "ima_digest_list.h"
+
+struct ima_h_table ima_digests_htable = {
+ .len = ATOMIC_LONG_INIT(0),
+ .queue[0 ... IMA_MEASURE_HTABLE_SIZE - 1] = HLIST_HEAD_INIT
+};
+
+/*********************
+ * Get/add functions *
+ *********************/
+struct ima_digest *ima_lookup_digest(u8 *digest, enum hash_algo algo)
+{
+ struct ima_digest *d = NULL;
+ int digest_len = hash_digest_size[algo];
+ unsigned int key = ima_hash_key(digest);
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(d, &ima_digests_htable.queue[key], hnext)
+ if (d->algo == algo && !memcmp(d->digest, digest, digest_len))
+ break;
+
+ rcu_read_unlock();
+ return d;
+}
+
+static int ima_add_digest_data_entry(u8 *digest, enum hash_algo algo,
+ enum compact_types type, u16 modifiers)
+{
+ struct ima_digest *d;
+ int digest_len = hash_digest_size[algo];
+ unsigned int key = ima_hash_key(digest);
+
+ d = ima_lookup_digest(digest, algo);
+ if (d) {
+ d->modifiers |= modifiers;
+ return -EEXIST;
+ }
+
+ d = kmalloc(sizeof(*d) + digest_len, GFP_KERNEL);
+ if (d == NULL)
+ return -ENOMEM;
+
+ d->algo = algo;
+ d->type = type;
+ d->modifiers = modifiers;
+
+ memcpy(d->digest, digest, digest_len);
+ hlist_add_head_rcu(&d->hnext, &ima_digests_htable.queue[key]);
+ atomic_long_inc(&ima_digests_htable.len);
+ return 0;
+}
+
+/***********************
+ * Compact list parser *
+ ***********************/
+struct compact_list_hdr {
+ u8 version;
+ u8 _reserved;
+ u16 type;
+ u16 modifiers;
+ u16 algo;
+ u32 count;
+ u32 datalen;
+} __packed;
+
+int ima_parse_compact_list(loff_t size, void *buf)
+{
+ u8 *digest;
+ void *bufp = buf, *bufendp = buf + size;
+ struct compact_list_hdr *hdr;
+ size_t digest_len;
+ int ret, i;
+
+ while (bufp < bufendp) {
+ if (bufp + sizeof(*hdr) > bufendp) {
+ pr_err("compact list, invalid data\n");
+ return -EINVAL;
+ }
+
+ hdr = bufp;
+
+ if (hdr->version != 1) {
+ pr_err("compact list, unsupported version\n");
+ return -EINVAL;
+ }
+
+ if (ima_canonical_fmt) {
+ hdr->type = le16_to_cpu(hdr->type);
+ hdr->modifiers = le16_to_cpu(hdr->modifiers);
+ hdr->algo = le16_to_cpu(hdr->algo);
+ hdr->count = le32_to_cpu(hdr->count);
+ hdr->datalen = le32_to_cpu(hdr->datalen);
+ }
+
+ if (hdr->algo >= HASH_ALGO__LAST)
+ return -EINVAL;
+
+ digest_len = hash_digest_size[hdr->algo];
+
+ if (hdr->type >= COMPACT__LAST) {
+ pr_err("compact list, invalid type %d\n", hdr->type);
+ return -EINVAL;
+ }
+
+ bufp += sizeof(*hdr);
+
+ for (i = 0; i < hdr->count; i++) {
+ if (bufp + digest_len > bufendp) {
+ pr_err("compact list, invalid data\n");
+ return -EINVAL;
+ }
+
+ digest = bufp;
+ bufp += digest_len;
+
+ ret = ima_add_digest_data_entry(digest, hdr->algo,
+ hdr->type,
+ hdr->modifiers);
+ if (ret < 0 && ret != -EEXIST)
+ return ret;
+ }
+
+ if (i != hdr->count ||
+ bufp != (void *)hdr + sizeof(*hdr) + hdr->datalen) {
+ pr_err("compact list, invalid data\n");
+ return -EINVAL;
+ }
+ }
+
+ return bufp - buf;
+}
diff --git a/security/integrity/ima/ima_digest_list.h b/security/integrity/ima/ima_digest_list.h
new file mode 100644
index 000000000000..13cdc3d954bd
--- /dev/null
+++ b/security/integrity/ima/ima_digest_list.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017-2019 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ * File: ima_digest_list.h
+ * Header of ima_digest_list.c
+ */
+
+#ifndef __LINUX_IMA_DIGEST_LIST_H
+#define __LINUX_IMA_DIGEST_LIST_H
+
+static inline bool ima_digest_is_immutable(struct ima_digest *digest)
+{
+ return (digest->modifiers & (1 << COMPACT_MOD_IMMUTABLE));
+}
+
+#ifdef CONFIG_IMA_DIGEST_LIST
+extern struct ima_h_table ima_digests_htable;
+
+struct ima_digest *ima_lookup_digest(u8 *digest, enum hash_algo algo);
+int ima_parse_compact_list(loff_t size, void *buf);
+#else
+static inline struct ima_digest *ima_lookup_digest(u8 *digest,
+ enum hash_algo algo)
+{
+ return NULL;
+}
+static inline int ima_parse_compact_list(loff_t size, void *buf)
+{
+ return -ENOTSUPP;
+}
+#endif /*CONFIG_IMA_DIGEST_LIST*/
+#endif /*LINUX_IMA_DIGEST_LIST_H*/
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 54a7ad4f6cc0..1a9bff2e01ec 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -11,6 +11,7 @@
#include <crypto/sha.h>
#include <linux/key.h>
#include <linux/audit.h>
+#include <linux/hash_info.h>
/* iint action cache flags */
#define IMA_MEASURE 0x00000001
@@ -127,6 +128,17 @@ struct integrity_iint_cache {
struct ima_digest_data *ima_hash;
};
+enum compact_types { COMPACT_KEY, COMPACT_PARSER, COMPACT_FILE, COMPACT__LAST };
+enum compact_modifiers { COMPACT_MOD_IMMUTABLE, COMPACT_MOD__LAST };
+
+struct ima_digest {
+ struct hlist_node hnext;
+ enum hash_algo algo;
+ enum compact_types type;
+ u16 modifiers;
+ u8 digest[0];
+};
+
/* rbtree tree calls to lookup, insert, delete
* integrity data associated with an inode.
*/
--
2.17.1
^ permalink raw reply related
* [PATCH v4 07/14] ima: restrict upload of converted digest lists
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
If digest lists cannot be directly parsed by the kernel, access to the
securityfs file must be exclusively granted to the parser, to avoid that an
arbitrary process makes undesired modifications before uploading converted
lists to IMA. Digest lists are measured before they are converted and no
new measurement is taken after conversion.
This patch introduces ima_check_set_parser(), to verify whether the process
opening the interface to upload digest lists is the user space parser. It
checks whether the digest of the executable is found in a digest list and
if the type of found digest is COMPACT_PARSER.
It also introduces ima_set_parser() and ima_get_parser() to return the
task_struct of the process that opened digest_list_data. This will be used
to determine whether digest lists have been measured/appraised and, if not,
to prevent their usage.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/ima/ima_digest_list.c | 54 ++++++++++++++++++++++++
security/integrity/ima/ima_digest_list.h | 14 ++++++
2 files changed, 68 insertions(+)
diff --git a/security/integrity/ima/ima_digest_list.c b/security/integrity/ima/ima_digest_list.c
index 6c7dd2cfbb68..3c77a6cec29a 100644
--- a/security/integrity/ima/ima_digest_list.c
+++ b/security/integrity/ima/ima_digest_list.c
@@ -17,6 +17,8 @@
#include <linux/vmalloc.h>
#include <linux/module.h>
+#include <linux/file.h>
+#include <linux/sched/mm.h>
#include "ima.h"
#include "ima_digest_list.h"
@@ -150,3 +152,55 @@ int ima_parse_compact_list(loff_t size, void *buf)
return bufp - buf;
}
+
+/****************
+ * Parser check *
+ ****************/
+bool ima_check_current_is_parser(void)
+{
+ struct integrity_iint_cache *parser_iint;
+ struct ima_digest *parser_digest = NULL;
+ struct file *parser_file;
+ struct mm_struct *mm;
+
+ mm = get_task_mm(current);
+ if (!mm)
+ return false;
+
+ parser_file = get_mm_exe_file(mm);
+ mmput(mm);
+
+ if (!parser_file)
+ return false;
+
+ parser_iint = integrity_iint_find(file_inode(parser_file));
+ fput(parser_file);
+
+ if (!parser_iint)
+ return false;
+
+ /* flag cannot be cleared due to write protection of executables */
+ if (!(parser_iint->flags & IMA_COLLECTED))
+ return false;
+
+ parser_digest = ima_lookup_digest(parser_iint->ima_hash->digest,
+ parser_iint->ima_hash->algo);
+
+ return (parser_digest && parser_digest->type == COMPACT_PARSER);
+}
+
+/*
+ * Current parser set and reset respectively during open() and close() of
+ * /sys/kernel/security/ima/digest_list_data.
+ */
+static struct task_struct *current_parser;
+
+void ima_set_parser(struct task_struct *parser)
+{
+ current_parser = parser;
+}
+
+struct task_struct *ima_get_parser(void)
+{
+ return current_parser;
+}
diff --git a/security/integrity/ima/ima_digest_list.h b/security/integrity/ima/ima_digest_list.h
index 13cdc3d954bd..be07a4afd7b6 100644
--- a/security/integrity/ima/ima_digest_list.h
+++ b/security/integrity/ima/ima_digest_list.h
@@ -26,6 +26,9 @@ extern struct ima_h_table ima_digests_htable;
struct ima_digest *ima_lookup_digest(u8 *digest, enum hash_algo algo);
int ima_parse_compact_list(loff_t size, void *buf);
+bool ima_check_current_is_parser(void);
+void ima_set_parser(struct task_struct *parser);
+struct task_struct *ima_get_parser(void);
#else
static inline struct ima_digest *ima_lookup_digest(u8 *digest,
enum hash_algo algo)
@@ -36,5 +39,16 @@ static inline int ima_parse_compact_list(loff_t size, void *buf)
{
return -ENOTSUPP;
}
+static inline bool ima_check_current_is_parser(void)
+{
+ return false;
+}
+static inline void ima_set_parser(struct task_struct *parser)
+{
+}
+static inline struct task_struct *ima_get_parser(void)
+{
+ return NULL;
+}
#endif /*CONFIG_IMA_DIGEST_LIST*/
#endif /*LINUX_IMA_DIGEST_LIST_H*/
--
2.17.1
^ permalink raw reply related
* [PATCH v4 08/14] ima: prevent usage of digest lists that are not measured/appraised
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
The Digest Lists extension creates a new measurement only when a file is
unknown (i.e. its digest is not found in the uploaded digest lists).
However, if digest lists are not measured, a remote verifier cannot
determine which files could have possibly been accessed. If they are not
appraised, a user would be able to access files that are not signed or
protected with a HMAC.
This patch prevents this issue by monitoring the process that opened
digest_list_data and that can upload digests. If the process opens a file
that is not measured, digest list queries by IMA-Measure will be always
negative (ima_digest_allow() will always return a NULL pointer). The same
happens for IMA-Appraise.
This patch also ensures that the parser can only execute shared libraries
with type COMPACT_PARSER (i.e. libraries adding support for custom digest
list formats).
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/ima/ima.h | 2 ++
security/integrity/ima/ima_digest_list.c | 36 ++++++++++++++++++++++++
security/integrity/ima/ima_digest_list.h | 15 ++++++++++
security/integrity/ima/ima_main.c | 17 ++++++++++-
4 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index b4a0d2a02ff2..1729ecc4e3e7 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -53,6 +53,8 @@ extern int ima_hash_algo;
extern int ima_appraise;
extern struct tpm_chip *ima_tpm_chip;
+extern int ima_digest_list_actions;
+
/* IMA event related data */
struct ima_event_data {
struct integrity_iint_cache *iint;
diff --git a/security/integrity/ima/ima_digest_list.c b/security/integrity/ima/ima_digest_list.c
index 3c77a6cec29a..3aaa26d6e8e3 100644
--- a/security/integrity/ima/ima_digest_list.c
+++ b/security/integrity/ima/ima_digest_list.c
@@ -163,6 +163,9 @@ bool ima_check_current_is_parser(void)
struct file *parser_file;
struct mm_struct *mm;
+ if (!(ima_digest_list_actions & ima_policy_flag))
+ return false;
+
mm = get_task_mm(current);
if (!mm)
return false;
@@ -204,3 +207,36 @@ struct task_struct *ima_get_parser(void)
{
return current_parser;
}
+
+/**********************
+ * Digest usage check *
+ **********************/
+void ima_check_parser_action(struct inode *inode, enum ima_hooks hook,
+ int mask, int action, bool check_digest,
+ struct ima_digest *digest)
+{
+ int action_mask = (IMA_DO_MASK & ~IMA_APPRAISE_SUBMASK);
+
+ if (current != current_parser)
+ return;
+
+ if (!(mask & (MAY_READ | MAY_EXEC)))
+ return;
+
+ if (hook == MMAP_CHECK && mask == MAY_EXEC && check_digest &&
+ (!digest || digest->type != COMPACT_PARSER))
+ action_mask = 0;
+
+ if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
+ action_mask = 0;
+
+ ima_digest_list_actions &= (action & action_mask);
+}
+
+struct ima_digest *ima_digest_allow(struct ima_digest *digest, int action)
+{
+ if (!(ima_digest_list_actions & action))
+ return NULL;
+
+ return digest;
+}
diff --git a/security/integrity/ima/ima_digest_list.h b/security/integrity/ima/ima_digest_list.h
index be07a4afd7b6..49798688f9c8 100644
--- a/security/integrity/ima/ima_digest_list.h
+++ b/security/integrity/ima/ima_digest_list.h
@@ -29,6 +29,10 @@ int ima_parse_compact_list(loff_t size, void *buf);
bool ima_check_current_is_parser(void);
void ima_set_parser(struct task_struct *parser);
struct task_struct *ima_get_parser(void);
+void ima_check_parser_action(struct inode *inode, enum ima_hooks hook,
+ int mask, int action, bool check_digest,
+ struct ima_digest *digest);
+struct ima_digest *ima_digest_allow(struct ima_digest *digest, int action);
#else
static inline struct ima_digest *ima_lookup_digest(u8 *digest,
enum hash_algo algo)
@@ -50,5 +54,16 @@ static inline struct task_struct *ima_get_parser(void)
{
return NULL;
}
+static inline void ima_check_parser_action(struct inode *inode,
+ enum ima_hooks hook, int mask,
+ int action, bool check_digest,
+ struct ima_digest *digest)
+{
+}
+static inline struct ima_digest *ima_digest_allow(struct ima_digest *digest,
+ int action)
+{
+ return NULL;
+}
#endif /*CONFIG_IMA_DIGEST_LIST*/
#endif /*LINUX_IMA_DIGEST_LIST_H*/
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index dc53ed8b0dd0..15eb00fb6b6d 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -29,6 +29,7 @@
#include <linux/fs.h>
#include "ima.h"
+#include "ima_digest_list.h"
#ifdef CONFIG_IMA_APPRAISE
int ima_appraise = IMA_APPRAISE_ENFORCE;
@@ -36,6 +37,9 @@ int ima_appraise = IMA_APPRAISE_ENFORCE;
int ima_appraise;
#endif
+/* Actions (measure/appraisal) for which digest lists can be used */
+int ima_digest_list_actions;
+
int ima_hash_algo = HASH_ALGO_SHA1;
static int hash_setup_done;
@@ -252,11 +256,15 @@ static int process_measurement(struct file *file, const struct cred *cred,
const char *pathname = NULL;
int rc = 0, action, must_appraise = 0;
int pcr = CONFIG_IMA_MEASURE_PCR_IDX;
+ struct ima_digest *found_digest = NULL;
struct evm_ima_xattr_data *xattr_value = NULL;
int xattr_len = 0;
bool violation_check;
enum hash_algo hash_algo;
+ ima_check_parser_action(inode, func, mask, ima_policy_flag, false,
+ NULL);
+
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
return 0;
@@ -268,6 +276,9 @@ static int process_measurement(struct file *file, const struct cred *cred,
&template_desc);
violation_check = ((func == FILE_CHECK || func == MMAP_CHECK) &&
(ima_policy_flag & IMA_MEASURE));
+
+ ima_check_parser_action(inode, func, mask, action, false, NULL);
+
if (!action && !violation_check)
return 0;
@@ -312,7 +323,8 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags) ||
((inode->i_sb->s_iflags & SB_I_IMA_UNVERIFIABLE_SIGNATURE) &&
!(inode->i_sb->s_iflags & SB_I_UNTRUSTED_MOUNTER) &&
- !(action & IMA_FAIL_UNVERIFIABLE_SIGS))) {
+ !(action & IMA_FAIL_UNVERIFIABLE_SIGS)) ||
+ ima_get_parser() == current) {
iint->flags &= ~IMA_DONE_MASK;
iint->measured_pcrs = 0;
}
@@ -366,6 +378,9 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */
pathname = ima_d_path(&file->f_path, &pathbuf, filename);
+ found_digest = ima_lookup_digest(iint->ima_hash->digest, hash_algo);
+ ima_check_parser_action(inode, func, mask, action, true, found_digest);
+
if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len, pcr,
--
2.17.1
^ permalink raw reply related
* [PATCH v4 09/14] ima: introduce new securityfs files
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
This patch introduces two new files in the securityfs filesystem:
digest_list_data, loads a digest list from the specified path, if it is in
the compact format, or loads a digest list converted by the user space
parser; digests_count: shows the number of digests stored in the
ima_digests_htable hash table.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
include/linux/fs.h | 1 +
security/integrity/ima/ima_fs.c | 44 ++++++++++++++++++++++++++++++++-
2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f7fdfe93e25d..0591a3c3cc2f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2921,6 +2921,7 @@ extern int do_pipe_flags(int *, int);
id(KEXEC_INITRAMFS, kexec-initramfs) \
id(POLICY, security-policy) \
id(X509_CERTIFICATE, x509-certificate) \
+ id(DIGEST_LIST, digest-list) \
id(MAX_ID, )
#define __fid_enumify(ENUM, dummy) READING_ ## ENUM,
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 0f503b7cd396..b02b9a447d56 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -24,6 +24,7 @@
#include <linux/vmalloc.h>
#include "ima.h"
+#include "ima_digest_list.h"
static DEFINE_MUTEX(ima_write_mutex);
@@ -34,6 +35,8 @@ static struct dentry *ascii_runtime_measurements;
static struct dentry *runtime_measurements_count;
static struct dentry *violations;
static struct dentry *ima_policy;
+static struct dentry *digests_count;
+static struct dentry *digest_list_data;
bool ima_canonical_fmt;
static int __init default_canonical_fmt_setup(char *str)
@@ -58,6 +61,10 @@ static ssize_t ima_show_htable_value(struct file *filp, char __user *buf,
val = &ima_htable.violations;
else if (filp->f_path.dentry == runtime_measurements_count)
val = &ima_htable.len;
+#ifdef CONFIG_IMA_DIGEST_LIST
+ else if (filp->f_path.dentry == digests_count)
+ val = &ima_digests_htable.len;
+#endif
len = scnprintf(tmpbuf, sizeof(tmpbuf), "%li\n", atomic_long_read(val));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
@@ -296,6 +303,9 @@ static ssize_t ima_read_file(char *path, enum kernel_read_file_id file_id)
pr_debug("rule: %s\n", p);
rc = ima_parse_add_rule(p);
break;
+ case READING_DIGEST_LIST:
+ rc = ima_parse_compact_list(size, data);
+ break;
default:
break;
}
@@ -319,6 +329,10 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf,
char *data;
ssize_t result;
struct dentry *dentry = file_dentry(file);
+ enum kernel_read_file_id id = READING_POLICY;
+
+ if (dentry == digest_list_data)
+ id = READING_DIGEST_LIST;
/* No partial writes. */
result = -EINVAL;
@@ -345,7 +359,7 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf,
goto out_free;
if (data[0] == '/') {
- result = ima_read_file(data, READING_POLICY);
+ result = ima_read_file(data, id);
} else if (dentry == ima_policy) {
if (ima_appraise & IMA_APPRAISE_POLICY) {
pr_err("signed policy file (specified as an absolute pathname) required\n");
@@ -357,6 +371,11 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf,
} else {
result = ima_parse_add_rule(data);
}
+ } else if (dentry == digest_list_data) {
+ if (ima_check_current_is_parser())
+ result = ima_parse_compact_list(datalen, data);
+ else
+ result = -EACCES;
} else {
pr_err("Unknown data type\n");
result = -EINVAL;
@@ -373,6 +392,7 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf,
enum ima_fs_flags {
IMA_POLICY_BUSY,
+ IMA_DIGEST_LIST_DATA_BUSY,
IMA_FS_BUSY,
};
@@ -382,6 +402,8 @@ static enum ima_fs_flags ima_get_dentry_flag(struct dentry *dentry)
if (dentry == ima_policy)
flag = IMA_POLICY_BUSY;
+ else if (dentry == digest_list_data)
+ flag = IMA_DIGEST_LIST_DATA_BUSY;
return flag;
}
@@ -412,6 +434,8 @@ static int ima_open_data_upload(struct inode *inode, struct file *filp)
read_allowed = true;
seq_ops = &ima_policy_seqops;
#endif
+ } else if (dentry == digest_list_data) {
+ ima_set_parser(current);
}
if (!(filp->f_flags & O_WRONLY)) {
@@ -444,6 +468,9 @@ static int ima_release_data_upload(struct inode *inode, struct file *file)
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return seq_release(inode, file);
+ if (dentry == digest_list_data)
+ ima_set_parser(NULL);
+
if (dentry != ima_policy) {
clear_bit(flag, &ima_fs_flags);
return 0;
@@ -529,8 +556,23 @@ int __init ima_fs_init(void)
if (IS_ERR(ima_policy))
goto out;
+#ifdef CONFIG_IMA_DIGEST_LIST
+ digests_count = securityfs_create_file("digests_count",
+ S_IRUSR | S_IRGRP, ima_dir,
+ NULL, &ima_htable_value_ops);
+ if (IS_ERR(digests_count))
+ goto out;
+
+ digest_list_data = securityfs_create_file("digest_list_data", S_IWUSR,
+ ima_dir, NULL,
+ &ima_data_upload_ops);
+ if (IS_ERR(digest_list_data))
+ goto out;
+#endif
return 0;
out:
+ securityfs_remove(digest_list_data);
+ securityfs_remove(digests_count);
securityfs_remove(violations);
securityfs_remove(runtime_measurements_count);
securityfs_remove(ascii_runtime_measurements);
--
2.17.1
^ permalink raw reply related
* [PATCH v4 10/14] ima: load parser digests and execute the parser at boot time
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
Digest lists should be uploaded to IMA as soon as possible, otherwise file
digests would appear in the measurement list or access would be denied if
appraisal is in enforcing mode.
This patch adds a call to ima_load_parser_digest_list() in
integrity_load_keys(), so that the function is executed when rootfs becomes
available, before the init process is executed.
ima_load_parser_digest_list() loads a compact list containing the digests
of the parser and the shared libraries. This list is measured and
appraised depending on the current IMA policy. Then, the function executes
the parser executable with the User-Mode-Helper (UMH).
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
security/integrity/iint.c | 1 +
security/integrity/ima/Kconfig | 15 +++++++++
security/integrity/ima/ima_digest_list.c | 42 ++++++++++++++++++++++++
security/integrity/integrity.h | 8 +++++
4 files changed, 66 insertions(+)
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index e12c4900510f..de73baccc847 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -213,6 +213,7 @@ void __init integrity_load_keys(void)
{
ima_load_x509();
evm_load_x509();
+ ima_load_parser_digest_list();
}
static int __init integrity_fs_init(void)
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index b3a7b46d21cf..c1bb9fedeccc 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -307,3 +307,18 @@ config IMA_DIGEST_LIST
of accessed files are found in one of those lists, no new entries are
added to the measurement list, and access to the file is granted if
appraisal is in enforcing mode.
+
+config IMA_PARSER_DIGEST_LIST_PATH
+ string "Path of the parser digest list"
+ depends on IMA_DIGEST_LIST
+ default "/etc/ima/digest_lists/compact-upload_digest_lists"
+ help
+ This option defines the path of the digest list containing the
+ digest of the parser.
+
+config IMA_PARSER_BINARY_PATH
+ string "Path of the parser binary"
+ depends on IMA_DIGEST_LIST
+ default "/usr/bin/upload_digest_lists"
+ help
+ This option defines the path of the parser binary.
diff --git a/security/integrity/ima/ima_digest_list.c b/security/integrity/ima/ima_digest_list.c
index 3aaa26d6e8e3..532aaf5145ae 100644
--- a/security/integrity/ima/ima_digest_list.c
+++ b/security/integrity/ima/ima_digest_list.c
@@ -240,3 +240,45 @@ struct ima_digest *ima_digest_allow(struct ima_digest *digest, int action)
return digest;
}
+
+/********************
+ * Parser execution *
+ ********************/
+static void ima_exec_parser(void)
+{
+ char *argv[2] = {NULL}, *envp[1] = {NULL};
+
+ argv[0] = (char *)CONFIG_IMA_PARSER_BINARY_PATH;
+ call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+}
+
+void __init ima_load_parser_digest_list(void)
+{
+ void *datap;
+ loff_t size;
+ int ret;
+
+ if (!(ima_digest_list_actions & ima_policy_flag))
+ return;
+
+ ima_set_parser(current);
+ ret = kernel_read_file_from_path(CONFIG_IMA_PARSER_DIGEST_LIST_PATH,
+ &datap, &size, 0, READING_DIGEST_LIST);
+ ima_set_parser(NULL);
+
+ if (ret < 0) {
+ if (ret != -ENOENT)
+ pr_err("Unable to open file: %s (%d)",
+ CONFIG_IMA_PARSER_DIGEST_LIST_PATH, ret);
+ return;
+ }
+
+ ret = ima_parse_compact_list(size, datap);
+
+ vfree(datap);
+
+ if (ret < 0)
+ return;
+
+ ima_exec_parser();
+}
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 1a9bff2e01ec..8c4cf5127a8b 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -213,6 +213,14 @@ static inline void evm_load_x509(void)
}
#endif
+#ifdef CONFIG_IMA_DIGEST_LIST
+void __init ima_load_parser_digest_list(void);
+#else
+static inline void ima_load_parser_digest_list(void)
+{
+}
+#endif
+
#ifdef CONFIG_INTEGRITY_AUDIT
/* declarations */
void integrity_audit_msg(int audit_msgno, struct inode *inode,
--
2.17.1
^ permalink raw reply related
* [PATCH v4 11/14] ima: add support for measurement with digest lists
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
IMA-Measure creates a new measurement entry every time a file is measured,
unless the same entry is already in the measurement list.
This patch introduces a new type of measurement list, recognizable by the
PCR number specified with the new ima_digest_list_pcr= kernel option. This
type of measurement list includes measurements of digest lists and files
not found in those lists.
The benefit of this patch is the availability of a predictable PCR that
can be used to seal data or TPM keys to the OS software. Unlike standard
measurements, digest lists measurements only indicate that files with a
digest in those lists could have been accessed, but not if and when. With
standard measurements, however, the chosen PCR is unlikely predictable.
Both standard and digest list measurements can be generated at the same
time by adding '+' as a prefix to the value of ima_digest_list_pcr=
(example: with ima_digest_list_pcr=+11, IMA generates standard measurements
with PCR 10 and digest list measurements with PCR 11).
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
.../admin-guide/kernel-parameters.txt | 8 ++++
security/integrity/ima/ima.h | 9 ++--
security/integrity/ima/ima_api.c | 43 ++++++++++++++++---
security/integrity/ima/ima_digest_list.c | 25 +++++++++++
security/integrity/ima/ima_init.c | 2 +-
security/integrity/ima/ima_main.c | 9 +++-
security/integrity/ima/ima_policy.c | 3 +-
7 files changed, 86 insertions(+), 13 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 0585194ca736..05862a0c402d 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1599,6 +1599,14 @@
Use the canonical format for the binary runtime
measurements, instead of host native format.
+ ima_digest_list_pcr=
+ [IMA]
+ Specify which PCR is extended with digests not found
+ in loaded digest lists. Measurement entries for known
+ files are not created unless the '+' is added before
+ the chosen PCR.
+ Format: { [+]<unsigned int> }
+
ima_hash= [IMA]
Format: { md5 | sha1 | rmd160 | sha256 | sha384
| sha512 | ... }
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 1729ecc4e3e7..42e4f2b64cd1 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -52,6 +52,8 @@ extern int ima_policy_flag;
extern int ima_hash_algo;
extern int ima_appraise;
extern struct tpm_chip *ima_tpm_chip;
+extern int ima_digest_list_pcr;
+extern bool ima_plus_standard_pcr;
extern int ima_digest_list_actions;
@@ -204,15 +206,16 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, int pcr,
- struct ima_template_desc *template_desc);
+ struct ima_template_desc *template_desc,
+ struct ima_digest *digest);
void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename);
int ima_alloc_init_template(struct ima_event_data *event_data,
struct ima_template_entry **entry,
struct ima_template_desc *template_desc);
int ima_store_template(struct ima_template_entry *entry, int violation,
- struct inode *inode,
- const unsigned char *filename, int pcr);
+ struct inode *inode, const unsigned char *filename,
+ int pcr, struct ima_digest *digest);
void ima_free_template_entry(struct ima_template_entry *entry);
const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 3233cd69a91b..a3e23b8e2ec7 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -90,11 +90,13 @@ int ima_alloc_init_template(struct ima_event_data *event_data,
*/
int ima_store_template(struct ima_template_entry *entry,
int violation, struct inode *inode,
- const unsigned char *filename, int pcr)
+ const unsigned char *filename, int pcr,
+ struct ima_digest *digest)
{
static const char op[] = "add_template_measure";
static const char audit_cause[] = "hashing_error";
char *template_name = entry->template_desc->name;
+ struct ima_template_entry *duplicated_entry = NULL;
int result;
struct {
struct ima_digest_data hdr;
@@ -117,8 +119,27 @@ int ima_store_template(struct ima_template_entry *entry,
}
memcpy(entry->digest, hash.hdr.digest, hash.hdr.length);
}
+
+ if (ima_plus_standard_pcr && !digest) {
+ duplicated_entry = kmemdup(entry,
+ sizeof(*entry) + entry->template_desc->num_fields *
+ sizeof(struct ima_field_data), GFP_KERNEL);
+ if (duplicated_entry)
+ duplicated_entry->pcr = ima_digest_list_pcr;
+ } else if (!ima_plus_standard_pcr && ima_digest_list_pcr >= 0) {
+ pcr = ima_digest_list_pcr;
+ }
+
entry->pcr = pcr;
+
result = ima_add_template_entry(entry, violation, op, inode, filename);
+ if (!result && duplicated_entry) {
+ result = ima_add_template_entry(duplicated_entry, violation, op,
+ inode, filename);
+ if (result < 0)
+ kfree(duplicated_entry);
+ }
+
return result;
}
@@ -150,8 +171,8 @@ void ima_add_violation(struct file *file, const unsigned char *filename,
result = -ENOMEM;
goto err_out;
}
- result = ima_store_template(entry, violation, inode,
- filename, CONFIG_IMA_MEASURE_PCR_IDX);
+ result = ima_store_template(entry, violation, inode, filename,
+ CONFIG_IMA_MEASURE_PCR_IDX, NULL);
if (result < 0)
ima_free_template_entry(entry);
err_out:
@@ -285,13 +306,14 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int xattr_len, int pcr,
- struct ima_template_desc *template_desc)
+ struct ima_template_desc *template_desc,
+ struct ima_digest *digest)
{
static const char op[] = "add_template_measure";
static const char audit_cause[] = "ENOMEM";
int result = -ENOMEM;
struct inode *inode = file_inode(file);
- struct ima_template_entry *entry;
+ struct ima_template_entry *entry = NULL;
struct ima_event_data event_data = { .iint = iint,
.file = file,
.filename = filename,
@@ -302,6 +324,11 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
if (iint->measured_pcrs & (0x1 << pcr))
return;
+ if (digest && !ima_plus_standard_pcr && ima_digest_list_pcr >= 0) {
+ result = -EEXIST;
+ goto out;
+ }
+
result = ima_alloc_init_template(&event_data, &entry, template_desc);
if (result < 0) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
@@ -309,12 +336,14 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
return;
}
- result = ima_store_template(entry, violation, inode, filename, pcr);
+ result = ima_store_template(entry, violation, inode, filename, pcr,
+ digest);
+out:
if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) {
iint->flags |= IMA_MEASURED;
iint->measured_pcrs |= (0x1 << pcr);
}
- if (result < 0)
+ if (result < 0 && entry)
ima_free_template_entry(entry);
}
diff --git a/security/integrity/ima/ima_digest_list.c b/security/integrity/ima/ima_digest_list.c
index 532aaf5145ae..c9c079ae82c7 100644
--- a/security/integrity/ima/ima_digest_list.c
+++ b/security/integrity/ima/ima_digest_list.c
@@ -28,6 +28,31 @@ struct ima_h_table ima_digests_htable = {
.queue[0 ... IMA_MEASURE_HTABLE_SIZE - 1] = HLIST_HEAD_INIT
};
+static int __init digest_list_pcr_setup(char *str)
+{
+ int pcr, ret;
+
+ ret = kstrtouint(str, 10, &pcr);
+ if (ret) {
+ pr_err("Invalid PCR number %s\n", str);
+ return 1;
+ }
+
+ if (pcr == CONFIG_IMA_MEASURE_PCR_IDX) {
+ pr_err("Default PCR cannot be used for digest lists\n");
+ return 1;
+ }
+
+ ima_digest_list_pcr = pcr;
+ ima_digest_list_actions |= IMA_MEASURE;
+
+ if (*str == '+')
+ ima_plus_standard_pcr = true;
+
+ return 1;
+}
+__setup("ima_digest_list_pcr=", digest_list_pcr_setup);
+
/*********************
* Get/add functions *
*********************/
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 5d55ade5f3b9..5ca9250b913a 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -76,7 +76,7 @@ static int __init ima_add_boot_aggregate(void)
result = ima_store_template(entry, violation, NULL,
boot_aggregate_name,
- CONFIG_IMA_MEASURE_PCR_IDX);
+ CONFIG_IMA_MEASURE_PCR_IDX, NULL);
if (result < 0) {
ima_free_template_entry(entry);
audit_cause = "store_entry";
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 15eb00fb6b6d..eca55e788c28 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -39,6 +39,10 @@ int ima_appraise;
/* Actions (measure/appraisal) for which digest lists can be used */
int ima_digest_list_actions;
+/* PCR used for digest list measurements */
+int ima_digest_list_pcr = -1;
+/* Flag to include standard measurement if digest list PCR is specified */
+bool ima_plus_standard_pcr;
int ima_hash_algo = HASH_ALGO_SHA1;
static int hash_setup_done;
@@ -384,7 +388,10 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (action & IMA_MEASURE)
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len, pcr,
- template_desc);
+ template_desc,
+ ima_digest_allow(found_digest,
+ IMA_MEASURE));
+
if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
inode_lock(inode);
rc = ima_appraise_measurement(func, iint, file, pathname,
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 0e1c81a29ac1..5537b91272f0 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -1135,7 +1135,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
ima_log_string(ab, "pcr", args[0].from);
result = kstrtoint(args[0].from, 10, &entry->pcr);
- if (result || INVALID_PCR(entry->pcr))
+ if (result || INVALID_PCR(entry->pcr) ||
+ entry->pcr == ima_digest_list_pcr)
result = -EINVAL;
else
entry->flags |= IMA_PCR;
--
2.17.1
^ permalink raw reply related
* [PATCH v4 12/14] ima: add support for appraisal with digest lists
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
IMA-Appraise grants access to files with a valid signature or with actual
file digest equal to the digest included in security.ima.
This patch adds support for appraisal based on digest lists. Instead of
using the reference value from security.ima, this patch checks if the
calculated file digest is included in the uploaded digest lists.
This functionality must be explicitly enabled by providing one of the
following values for the ima_appraise= kernel option:
- digest: this mode enables appraisal verification with digest lists until
EVM is initialized; after that, access to files without signature/HMAC
will be denied; this mode would be used for systems that perform HMAC
verification and rely on digest lists for the system initialization until
the HMAC key is unsealed;
- digest-nometadata: this mode enables appraisal verification with digest
lists even after EVM has been initialized; access will be granted if
a file does not have IMA/EVM xattrs but its digest is found in the digest
lists; after update, mutable files will have a new security.ima type, so
that they can be made inaccessible unless this mode is specified; this
mode would be used for systems that perform appraisal verification
exclusively based on digest lists.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
.../admin-guide/kernel-parameters.txt | 3 +-
include/linux/evm.h | 6 +++
security/integrity/evm/evm_main.c | 2 +-
security/integrity/ima/ima.h | 5 ++-
security/integrity/ima/ima_appraise.c | 37 ++++++++++++++++++-
security/integrity/ima/ima_main.c | 4 +-
security/integrity/integrity.h | 2 +
7 files changed, 53 insertions(+), 6 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 05862a0c402d..765682b4187d 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1588,7 +1588,8 @@
ima_appraise= [IMA] appraise integrity measurements
Format: { "off" | "enforce" | "fix" | "log" |
- "enforce-evm" | "log-evm" }
+ "enforce-evm" | "log-evm" | "digest" |
+ "digest-nometadata" }
default: "enforce"
ima_appraise_tcb [IMA] Deprecated. Use ima_policy= instead.
diff --git a/include/linux/evm.h b/include/linux/evm.h
index 8302bc29bb35..6e89d046b716 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -15,6 +15,7 @@
struct integrity_iint_cache;
#ifdef CONFIG_EVM
+extern bool evm_key_loaded(void);
extern int evm_set_key(void *key, size_t keylen);
extern enum integrity_status evm_verifyxattr(struct dentry *dentry,
const char *xattr_name,
@@ -45,6 +46,11 @@ static inline int posix_xattr_acl(const char *xattrname)
#endif
#else
+static inline bool evm_key_loaded(void)
+{
+ return false;
+}
+
static inline int evm_set_key(void *key, size_t keylen)
{
return -EOPNOTSUPP;
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index abb5ce3fd942..fbe0bb5cd7c4 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -86,7 +86,7 @@ static void __init evm_init_config(void)
pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs);
}
-static bool evm_key_loaded(void)
+bool evm_key_loaded(void)
{
return (bool)(evm_initialized & EVM_KEY_MASK);
}
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 42e4f2b64cd1..16952df04cb6 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -248,7 +248,7 @@ int ima_appraise_measurement(enum ima_hooks func,
struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
- int xattr_len);
+ int xattr_len, struct ima_digest *found_digest);
int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func);
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file);
enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint,
@@ -260,7 +260,8 @@ static inline int ima_appraise_measurement(enum ima_hooks func,
struct file *file,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
- int xattr_len)
+ int xattr_len,
+ struct ima_digest *found_digest)
{
return INTEGRITY_UNKNOWN;
}
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 2566dbfd2464..01210a265f1f 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -14,8 +14,10 @@
#include <linux/evm.h>
#include "ima.h"
+#include "ima_digest_list.h"
static bool ima_appraise_req_evm __ro_after_init;
+static bool ima_appraise_no_metadata __ro_after_init;
static int __init default_appraise_setup(char *str)
{
#ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
@@ -29,6 +31,14 @@ static int __init default_appraise_setup(char *str)
if (strcmp(str, "enforce-evm") == 0 ||
strcmp(str, "log-evm") == 0)
ima_appraise_req_evm = true;
+#ifdef CONFIG_IMA_DIGEST_LIST
+ if (!strncmp(str, "digest", 6)) {
+ ima_digest_list_actions |= IMA_APPRAISE;
+
+ if (!strcmp(str + 6, "-nometadata"))
+ ima_appraise_no_metadata = true;
+ }
+#endif
return 1;
}
@@ -73,6 +83,8 @@ static int ima_fix_xattr(struct dentry *dentry,
} else {
offset = 0;
iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG;
+ if (iint->flags & IMA_DIGEST_LISTS)
+ iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_LIST;
iint->ima_hash->xattr.ng.algo = algo;
}
rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
@@ -163,7 +175,7 @@ int ima_appraise_measurement(enum ima_hooks func,
struct integrity_iint_cache *iint,
struct file *file, const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
- int xattr_len)
+ int xattr_len, struct ima_digest *found_digest)
{
static const char op[] = "appraise_data";
const char *cause = "unknown";
@@ -192,6 +204,22 @@ int ima_appraise_measurement(enum ima_hooks func,
(!(iint->flags & IMA_DIGSIG_REQUIRED) ||
(inode->i_size == 0)))
status = INTEGRITY_PASS;
+ if (found_digest) {
+ if (!evm_key_loaded() || ima_appraise_no_metadata)
+ status = INTEGRITY_PASS;
+
+ if (!ima_digest_is_immutable(found_digest)) {
+ if ((iint->flags & IMA_DIGSIG_REQUIRED)) {
+ cause = "IMA-signature-required";
+ status = INTEGRITY_FAIL;
+ goto out;
+ }
+ clear_bit(IMA_DIGSIG, &iint->atomic_flags);
+ iint->flags |= IMA_DIGEST_LISTS;
+ } else {
+ set_bit(IMA_DIGSIG, &iint->atomic_flags);
+ }
+ }
goto out;
}
@@ -217,6 +245,13 @@ int ima_appraise_measurement(enum ima_hooks func,
}
switch (xattr_value->type) {
+ case IMA_XATTR_DIGEST_LIST:
+ if (!ima_appraise_no_metadata) {
+ cause = "IMA-xattr-untrusted";
+ status = INTEGRITY_FAIL;
+ break;
+ }
+ iint->flags |= IMA_DIGEST_LISTS;
case IMA_XATTR_DIGEST_NG:
/* first byte contains algorithm id */
hash_start = 1;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index eca55e788c28..53c6b2eeaec0 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -395,7 +395,9 @@ static int process_measurement(struct file *file, const struct cred *cred,
if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
inode_lock(inode);
rc = ima_appraise_measurement(func, iint, file, pathname,
- xattr_value, xattr_len);
+ xattr_value, xattr_len,
+ ima_digest_allow(found_digest,
+ IMA_APPRAISE));
inode_unlock(inode);
if (!rc)
rc = mmap_violation_check(func, file, &pathbuf,
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 8c4cf5127a8b..f695b70feb1a 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -32,6 +32,7 @@
#define IMA_NEW_FILE 0x04000000
#define EVM_IMMUTABLE_DIGSIG 0x08000000
#define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000
+#define IMA_DIGEST_LISTS 0x20000000
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \
IMA_HASH | IMA_APPRAISE_SUBMASK)
@@ -71,6 +72,7 @@ enum evm_ima_xattr_type {
IMA_XATTR_DIGEST_NG,
EVM_XATTR_PORTABLE_DIGSIG,
EVM_XATTR_HMAC_RND_KEY,
+ IMA_XATTR_DIGEST_LIST,
IMA_XATTR_LAST
};
--
2.17.1
^ permalink raw reply related
* [PATCH v4 13/14] ima: introduce new policies initrd and appraise_initrd
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
This patch introduces the new policies 'initrd' and 'appraise_initrd' to
measure/appraise files in the initial ram disk.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
.../admin-guide/kernel-parameters.txt | 5 +++-
security/integrity/ima/ima_policy.c | 26 +++++++++++++++++--
2 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 765682b4187d..47311cdf63d9 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1619,7 +1619,7 @@
ima_policy= [IMA]
The builtin policies to load during IMA setup.
Format: "tcb | appraise_tcb | secure_boot |
- fail_securely"
+ fail_securely | initrd | appraise_initrd"
The "tcb" policy measures all programs exec'd, files
mmap'd for exec, and all files opened with the read
@@ -1638,6 +1638,9 @@
filesystems with the SB_I_UNVERIFIABLE_SIGNATURE
flag.
+ The "initrd" and "appraise_initrd" policies include
+ rootfs among the filesystems to be measured/appraised.
+
ima_tcb [IMA] Deprecated. Use ima_policy= instead.
Load a policy which meets the needs of the Trusted
Computing Base. This means IMA will measure all
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 5537b91272f0..70412df07718 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -165,6 +165,14 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
#endif
};
+static struct ima_rule_entry initrd_measure_rule __ro_after_init = {
+ .action = MEASURE, .fsname = "rootfs", .flags = IMA_FSNAME
+};
+
+static struct ima_rule_entry initrd_appraise_rule __ro_after_init = {
+ .action = APPRAISE, .fsname = "rootfs", .flags = IMA_FSNAME
+};
+
static struct ima_rule_entry build_appraise_rules[] __ro_after_init = {
#ifdef CONFIG_IMA_APPRAISE_REQUIRE_MODULE_SIGS
{.action = APPRAISE, .func = MODULE_CHECK,
@@ -218,6 +226,8 @@ __setup("ima_tcb", default_measure_policy_setup);
static bool ima_use_appraise_tcb __initdata;
static bool ima_use_secure_boot __initdata;
static bool ima_fail_unverifiable_sigs __ro_after_init;
+static bool ima_measure_initrd __initdata;
+static bool ima_appraise_initrd __initdata;
static int __init policy_setup(char *str)
{
char *p;
@@ -233,6 +243,10 @@ static int __init policy_setup(char *str)
ima_use_secure_boot = true;
else if (strcmp(p, "fail_securely") == 0)
ima_fail_unverifiable_sigs = true;
+ else if (strcmp(p, "initrd") == 0)
+ ima_measure_initrd = true;
+ else if (strcmp(p, "appraise_initrd") == 0)
+ ima_appraise_initrd = true;
}
return 1;
@@ -640,9 +654,13 @@ void __init ima_init_policy(void)
int build_appraise_entries, arch_entries;
/* if !ima_policy, we load NO default rules */
- if (ima_policy)
+ if (ima_policy) {
+ if (ima_measure_initrd)
+ add_rules(&initrd_measure_rule, 1, IMA_DEFAULT_POLICY);
+
add_rules(dont_measure_rules, ARRAY_SIZE(dont_measure_rules),
IMA_DEFAULT_POLICY);
+ }
switch (ima_policy) {
case ORIGINAL_TCB:
@@ -695,10 +713,14 @@ void __init ima_init_policy(void)
IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY);
}
- if (ima_use_appraise_tcb)
+ if (ima_use_appraise_tcb) {
+ if (ima_appraise_initrd)
+ add_rules(&initrd_appraise_rule, 1, IMA_DEFAULT_POLICY);
+
add_rules(default_appraise_rules,
ARRAY_SIZE(default_appraise_rules),
IMA_DEFAULT_POLICY);
+ }
ima_rules = &ima_default_rules;
ima_update_policy_flag();
--
2.17.1
^ permalink raw reply related
* [PATCH v4 14/14] ima: add Documentation/security/IMA-digest-lists.txt
From: Roberto Sassu @ 2019-06-14 17:55 UTC (permalink / raw)
To: zohar, dmitry.kasatkin, mjg59
Cc: linux-integrity, linux-security-module, linux-fsdevel, linux-doc,
linux-kernel, silviu.vlasceanu, Roberto Sassu
In-Reply-To: <20190614175513.27097-1-roberto.sassu@huawei.com>
This patch adds the documentation of the IMA Digest Lists extension.
Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
Documentation/security/IMA-digest-lists.txt | 226 ++++++++++++++++++++
1 file changed, 226 insertions(+)
create mode 100644 Documentation/security/IMA-digest-lists.txt
diff --git a/Documentation/security/IMA-digest-lists.txt b/Documentation/security/IMA-digest-lists.txt
new file mode 100644
index 000000000000..dd9633e21304
--- /dev/null
+++ b/Documentation/security/IMA-digest-lists.txt
@@ -0,0 +1,226 @@
+==========================
+IMA Digest Lists Extension
+==========================
+
+INTRODUCTION
+============
+
+Integrity Measurement Architecture (IMA) is a security module that performs
+measurement of files accessed with the execve(), mmap() and open() system
+calls. File measurements can be used for different purposes. They can be
+added in a measurement list and sent to a remote verifier for an integrity
+evaluation. They can be compared to reference values provided by the
+software vendor and access can be denied if there is a mismatch. File
+measurements can also be included in system logs for auditing purposes.
+
+IMA Digest Lists is an extension providing additional functionality for
+the IMA submodules. Its main task is to load reference file digests in the
+kernel memory, and to communicate to IMA submodules (measurement and
+appraisal) whether the digest of a file being accessed is found in the
+uploaded digest lists.
+
+The IMA-Measure submodule uses the IMA Digest Lists extension to create
+a new measurement list (with a different PCR, for example 11) which
+contains the measurement of uploaded digest lists and unknown files. Since
+the loading of digest lists is sequential, the chosen PCR will have a
+predictable value for the whole boot cycle and can be used for sealing
+policies based on the OS software integrity.
+
+Both the standard and the new measurement list can be generated at the same
+time, allowing for implicit attestation based on the usage of a TPM key
+sealed to the OS, and for explicit attestation when a more precise
+integrity evaluation is necessary.
+
+The IMA-Appraise submodule uses the IMA Digest Lists extension to
+grant/deny access to the files depending on whether the file digest is
+found in the uploaded digest lists, instead of checking security.ima.
+
+The main advantage of the extension is that reference measurements used for
+the digest comparison can be extracted from already existing sources (for
+example RPM headers). Another benefit is that the overhead compared to file
+signatures is lower as only one signature is verified for all files
+included in the digest list. A disadvantage is that file metadata are not
+verified.
+
+
+
+WORKFLOW
+========
+
+The IMA workflow is modified as follows. The added steps are marked as
+[NEW].
+
+ +------------+
+ | IMA hook |
+ +------------+
+ |
+ +---------+
+ | collect |
+ +---------+
+ | +---------------------+
++---------------+ ------------| don't measure [NEW] |
+| digest lookup | | yes +---------------------+
+| [NEW] | -------------- no +---------------------+
++---------------+ -----/ digest \---| add to measurement |
+ | | \ found? [NEW] / | list (PCR 11) [NEW] |
+ | | -------------- +---------------------+
+ +----------+ +-------------+ +--------------------+
+ | switch |-------| IMA-Measure |----------------| add to measurement |
+ | (action) | +-------------+ | list (PCR 10) |
+ +----------+ +--------------------+
+ |
+ |
+ | no xattr
++--------------+ --------------- yes
+| IMA-Appraise |----/ filec created \-------------------------------
++--------------+ \ created [NEW] / |
+ xattr | --------------- |
+ | | no |
+ | ------------------ no -------------- yes +--------+
+ | / EVM initialized? \----/ digest \------| grant |
+ | \ [NEW] / \ found? [NEW] / | access |
+ | ------------------ -------------- +--------+
+ | | yes | no
+ | | | +--------+
+ | ------------------- no ---------------| deny |
+ | / digest-nometadata \-------------------------| access |
+ | \ mode? [NEW] / +--------+
+ | -------------------
+ | ^ | yes +--------+
+ | | -------------------------------------| grant |
+ | | | access |
+ | | +--------+
+ | | yes
+ | ------------------------- no +--------+
+ |----------/ security.ima (new type) \-------------------| deny |
+ | \ present and valid? / | access |
+ | ------------------------- +--------+
+ | |
+ | -------------------------- no |
+ -----------/ security.ima (cur types) \-----------------------
+ \ present and valid? /
+ --------------------------
+ | yes +--------+
+ ------------------------------------| grant |
+ | access |
+ +--------+
+
+After the file digest is calculated, it is searched in the hash table
+containing all digests extracted from the uploaded digest lists. Then, if
+the digest is found, a structure is returned to IMA with information
+associated to that digest. The structure is returned only to the IMA
+submodules that processed the digest lists (i.e. the action returned by
+ima_get_action() was 'measure' or 'appraise').
+
+IMA-Measure behavior depends on whether the digest list PCR has been
+specified in the kernel command line. If the PCR was not specified, the
+submodule behaves as before. If the PCR was specified, IMA-Measure creates
+a new measurement with that PCR, only if the file digest is not found in
+the digest lists. It additionally creates a measurement with the default
+PCR if '+' is added as a prefix to the PCR.
+
+IMA-Appraise behavior depends on whether either the 'digest' or
+'digest-nometadata' appraisal modes have been specified in the kernel
+command line. If they were not specified, IMA-Appraise relies solely on the
+security.ima xattr for verification. If the 'digest' mode was specified,
+verification succeeds if the file digest is found in the digest lists and
+EVM is not initialized, as there is no other way to verify file metadata.
+
+If the 'digest-nometadata' mode was specified, verification succeeds
+regardless of the fact that EVM is initialized or not. However, after a
+write, files for which access was granted without verifying metadata will
+have a new security.ima type, so that they can be identified also after
+reboot. Specifying 'digest-nometadata' is required also to access files
+with the new security.ima type.
+
+
+
+ARCHITECTURE
+============
+
++--------------+ 8) digest lookup
+| IMA-Appraise |--------------------------------------
++--------------+ |
+ |
++-------------+ 7) digest lookup |
+| IMA-Measure | -------------------------------------|
++-------------+ ||
+ |||
++-------------+ 2a/5b) parse compact list +-------------------+
+| IMA (secfs) | ------------------------> | IMA Digests Lists |
++-------------+ +-------------------+
+ ^ ^ | | 3a/6b add digests
+ | | | +------------+
+ | | | | hash table |
+ | | | +------------+
+ | | 4b) upload compact list |
+ | | | kernel space
+---|--------|---------------------------------|-------------------------------
+ | | 1b) open digest_list_data | user space
+ | +-------------+ |
+ | | Parser |<--------------------------
+ | +-------------+ 2b) check parser binary, shared libraries
+ | ^ ^ ^ and actions (measure/appraise)
+ | RPM | ... 3b) read and convert digest list
+ | manifest
+ |
+1a) upload compact list
+
+The main addition to IMA is a new hash table (similar to that used to check
+for duplicate measurement entries), which contains file digests extracted
+from the digest lists.
+
+File digests can be uploaded to IMA through a new securityfs file named
+'digest_list_data' and must be sent in a format called compact list. Digest
+lists can be uploaded directly to the kernel, by specifying their path, or
+by executing a user space parser.
+
+The parser, called upload_digest_lists, converts digest lists from the
+original format defined by the software vendor (e.g. RPM package header) to
+the compact list format. It is executed by the kernel even before init,
+so that the hash table is populated before any file is accessed.
+
+Converted digest lists can be uploaded exclusively by the parser. The
+reason is that digest lists are measured only when they are accessed. If
+they were uploaded by any process there wouldn't be any guarantee that the
+converted lists contain the same digests as the original list. IMA checks
+that the digest of the executable that opened 'digest_list_data' as well as
+shared libraries supporting new digest list formats have type
+COMPACT_PARSER.
+
+As mentioned above, digest lists cannot be used unconditionally but must
+have been processed by the IMA submodule willing to use them. This is
+achieved by keeping track of the process that opens and closes
+digest_list_data, and checking the actions done by that process. If a file
+opened by the parser is not being measured, IMA-Measure will not be able
+to use digest lists until reboot. The same happens for IMA-Appraise.
+
+
+
+CONFIGURATION
+=============
+
+The first step consists in generating digest lists with the
+gen_digest_lists tool included in the digest-list-tools package.
+digest-list-tools can be retrieved at the URL:
+
+https://github.com/euleros/digest-list-tools
+
+gen_digest_lists can generate digest lists from different sources (for
+example: RPM package DB and IMA measurement list). By default, it saves
+generated digest lists in the /etc/ima/digest_lists directory.
+digest-list-tools includes also two bash scripts setup_ima_digest_lists and
+setup_digest_lists_demo to simplify the digest list generation for the
+users.
+
+To use the parser at boot, it is also necessary to generate a digest list
+for it. It is automatically generated by the setup_ima_digest_lists script,
+or it must be manually generated otherwise. If digest lists are used for
+appraisal, they must be signed with a key saved to /etc/keys/x509_ima.der
+and the key must be signed with a key in the primary or secondary kernel
+keyring.
+
+To use digest lists during early boot, it is necessary to regenerate the
+initial ram disk. Digest lists and the parser will be included in the ram
+disk by the new dracut/initramfs-tools modules, included in the
+digest-list-tools package.
--
2.17.1
^ permalink raw reply related
* [PATCH v2 00/16] Add support to generate ABI documentation at admin-guide
From: Mauro Carvalho Chehab @ 2019-06-14 18:07 UTC (permalink / raw)
To: Linux Doc Mailing List, Greg Kroah-Hartman
Cc: Mauro Carvalho Chehab, linux-kernel, Jonathan Corbet, Rajat Jain,
Bjorn Helgaas
In-Reply-To: <3b8d7c64f887ddea01df3c4eeabc745c8ec45406.1560534648.git.mchehab+samsung@kernel.org>
Greg,
In time: forgot to add a 00/16 patch... someone come to my desk while I was
sending this... sorry for that.
That's the second version of the doc ABI updated logic.
Changes from version 1:
- I updated my e-mail on older patches;
- Two new ABI fix patches;
- Improved the parser to detect a few more issues I discovered on
some ABI files.
- There's now a "validate" command at get_abi.pl. It simply runs
the parser without any output, except for warnings;
- It now runs "get_abi.pl validate" during the build (if enabled).
Please notice that the last patch will conflict with another patch
merged via docs-next tree, with creates a Documentation/Kconfig and
adds a check at Documentation/Makefile for broken documentation
links. The conflict is trivial to solve, through: just add the contents
on both tress.
This series is based on your driver-core git tree.
-
On this series:
- The first two patches contain two extra ABI fixes;
- The next 10 patches contain the ABI parsing script. I don't
mind if you prefer folding them on a single patch, but IMO,
preserving the history may help tracking bugs, if any;
- The 13th patch adds the new script to the documentation build
system, together with a new python Sphinx extension with calls it;
- The 14th patch fixes the python script when running with newer
Sphinx versions (1.7 and upper);
- The 15th patch fixes an UTF-8 troubles;
- The final patch adds a Kconfig var that will check for ABI
file problems, if COMPILE_TEST and WARN_ABI_ERRORS are
enabled.
Mauro Carvalho Chehab (16):
ABI: sysfs-bus-pci-devices-aer_stats uses an invalid tag
ABI: Fix KernelVersion tags
scripts: add an script to parse the ABI files
scripts/get_abi.pl: parse files with text at beginning
scripts/get_abi.pl: avoid use literal blocks when not needed
scripts/get_abi.pl: split label naming from xref logic
scripts/get_abi.pl: add support for searching for ABI symbols
scripts/get_abi.pl: represent what in tables
scripts/get_abi.pl: fix parse issues with some files
scripts/get_abi.pl: avoid creating duplicate names
scripts/get_abi.pl: add a handler for invalid "where" tag
scripts/get_abi.pl: add a validate command
doc-rst: add ABI documentation to the admin-guide book
docs: sphinx/kernel_abi.py: fix UTF-8 support
sphinx/kernel_abi.py: make it compatible with Sphinx 1.7+
docs: Kconfig/Makefile: add a check for broken ABI files
Documentation/ABI/testing/pstore | 2 +-
.../sysfs-bus-event_source-devices-format | 2 +-
.../ABI/testing/sysfs-bus-i2c-devices-hm6352 | 6 +-
.../testing/sysfs-bus-pci-devices-aer_stats | 24 +-
.../ABI/testing/sysfs-bus-pci-devices-cciss | 22 +-
.../testing/sysfs-bus-usb-devices-usbsevseg | 10 +-
.../ABI/testing/sysfs-driver-altera-cvp | 2 +-
Documentation/ABI/testing/sysfs-driver-ppi | 2 +-
Documentation/ABI/testing/sysfs-driver-st | 2 +-
Documentation/ABI/testing/sysfs-driver-wacom | 2 +-
Documentation/Kconfig | 11 +
Documentation/Makefile | 5 +
Documentation/admin-guide/abi-obsolete.rst | 10 +
Documentation/admin-guide/abi-removed.rst | 4 +
Documentation/admin-guide/abi-stable.rst | 13 +
Documentation/admin-guide/abi-testing.rst | 19 +
Documentation/admin-guide/abi.rst | 11 +
Documentation/admin-guide/index.rst | 1 +
Documentation/conf.py | 2 +-
Documentation/sphinx/kernel_abi.py | 164 ++++++
lib/Kconfig.debug | 2 +
scripts/get_abi.pl | 475 ++++++++++++++++++
22 files changed, 753 insertions(+), 38 deletions(-)
create mode 100644 Documentation/Kconfig
create mode 100644 Documentation/admin-guide/abi-obsolete.rst
create mode 100644 Documentation/admin-guide/abi-removed.rst
create mode 100644 Documentation/admin-guide/abi-stable.rst
create mode 100644 Documentation/admin-guide/abi-testing.rst
create mode 100644 Documentation/admin-guide/abi.rst
create mode 100644 Documentation/sphinx/kernel_abi.py
create mode 100755 scripts/get_abi.pl
--
2.21.0
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox