diff options
76 files changed, 3588 insertions, 1407 deletions
diff --git a/.gitignore b/.gitignore index 4ad4a98b884b..17fa24dd7e46 100644 --- a/.gitignore +++ b/.gitignore | |||
@@ -97,6 +97,7 @@ GTAGS | |||
97 | # Leavings from module signing | 97 | # Leavings from module signing |
98 | # | 98 | # |
99 | extra_certificates | 99 | extra_certificates |
100 | signing_key.pem | ||
100 | signing_key.priv | 101 | signing_key.priv |
101 | signing_key.x509 | 102 | signing_key.x509 |
102 | x509.genkey | 103 | x509.genkey |
diff --git a/Documentation/Changes b/Documentation/Changes index 646cdaa6e9d1..6d8863004858 100644 --- a/Documentation/Changes +++ b/Documentation/Changes | |||
@@ -43,6 +43,7 @@ o udev 081 # udevd --version | |||
43 | o grub 0.93 # grub --version || grub-install --version | 43 | o grub 0.93 # grub --version || grub-install --version |
44 | o mcelog 0.6 # mcelog --version | 44 | o mcelog 0.6 # mcelog --version |
45 | o iptables 1.4.2 # iptables -V | 45 | o iptables 1.4.2 # iptables -V |
46 | o openssl & libcrypto 1.0.1k # openssl version | ||
46 | 47 | ||
47 | 48 | ||
48 | Kernel compilation | 49 | Kernel compilation |
@@ -79,6 +80,17 @@ BC | |||
79 | You will need bc to build kernels 3.10 and higher | 80 | You will need bc to build kernels 3.10 and higher |
80 | 81 | ||
81 | 82 | ||
83 | OpenSSL | ||
84 | ------- | ||
85 | |||
86 | Module signing and external certificate handling use the OpenSSL program and | ||
87 | crypto library to do key creation and signature generation. | ||
88 | |||
89 | You will need openssl to build kernels 3.7 and higher if module signing is | ||
90 | enabled. You will also need openssl development packages to build kernels 4.3 | ||
91 | and higher. | ||
92 | |||
93 | |||
82 | System utilities | 94 | System utilities |
83 | ================ | 95 | ================ |
84 | 96 | ||
@@ -295,6 +307,10 @@ Binutils | |||
295 | -------- | 307 | -------- |
296 | o <ftp://ftp.kernel.org/pub/linux/devel/binutils/> | 308 | o <ftp://ftp.kernel.org/pub/linux/devel/binutils/> |
297 | 309 | ||
310 | OpenSSL | ||
311 | ------- | ||
312 | o <https://www.openssl.org/> | ||
313 | |||
298 | System utilities | 314 | System utilities |
299 | **************** | 315 | **************** |
300 | 316 | ||
@@ -392,4 +408,3 @@ o <http://oprofile.sf.net/download/> | |||
392 | NFS-Utils | 408 | NFS-Utils |
393 | --------- | 409 | --------- |
394 | o <http://nfs.sourceforge.net/> | 410 | o <http://nfs.sourceforge.net/> |
395 | |||
diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt index 6466704d47b5..0ff6a466a05b 100644 --- a/Documentation/kbuild/kbuild.txt +++ b/Documentation/kbuild/kbuild.txt | |||
@@ -174,6 +174,11 @@ The output directory is often set using "O=..." on the commandline. | |||
174 | 174 | ||
175 | The value can be overridden in which case the default value is ignored. | 175 | The value can be overridden in which case the default value is ignored. |
176 | 176 | ||
177 | KBUILD_SIGN_PIN | ||
178 | -------------------------------------------------- | ||
179 | This variable allows a passphrase or PIN to be passed to the sign-file | ||
180 | utility when signing kernel modules, if the private key requires such. | ||
181 | |||
177 | KBUILD_MODPOST_WARN | 182 | KBUILD_MODPOST_WARN |
178 | -------------------------------------------------- | 183 | -------------------------------------------------- |
179 | KBUILD_MODPOST_WARN can be set to avoid errors in case of undefined | 184 | KBUILD_MODPOST_WARN can be set to avoid errors in case of undefined |
diff --git a/Documentation/module-signing.txt b/Documentation/module-signing.txt index c72702ec1ded..a78bf1ffa68c 100644 --- a/Documentation/module-signing.txt +++ b/Documentation/module-signing.txt | |||
@@ -89,6 +89,32 @@ This has a number of options available: | |||
89 | their signatures checked without causing a dependency loop. | 89 | their signatures checked without causing a dependency loop. |
90 | 90 | ||
91 | 91 | ||
92 | (4) "File name or PKCS#11 URI of module signing key" (CONFIG_MODULE_SIG_KEY) | ||
93 | |||
94 | Setting this option to something other than its default of | ||
95 | "certs/signing_key.pem" will disable the autogeneration of signing keys | ||
96 | and allow the kernel modules to be signed with a key of your choosing. | ||
97 | The string provided should identify a file containing both a private key | ||
98 | and its corresponding X.509 certificate in PEM form, or — on systems where | ||
99 | the OpenSSL ENGINE_pkcs11 is functional — a PKCS#11 URI as defined by | ||
100 | RFC7512. In the latter case, the PKCS#11 URI should reference both a | ||
101 | certificate and a private key. | ||
102 | |||
103 | If the PEM file containing the private key is encrypted, or if the | ||
104 | PKCS#11 token requries a PIN, this can be provided at build time by | ||
105 | means of the KBUILD_SIGN_PIN variable. | ||
106 | |||
107 | |||
108 | (5) "Additional X.509 keys for default system keyring" (CONFIG_SYSTEM_TRUSTED_KEYS) | ||
109 | |||
110 | This option can be set to the filename of a PEM-encoded file containing | ||
111 | additional certificates which will be included in the system keyring by | ||
112 | default. | ||
113 | |||
114 | Note that enabling module signing adds a dependency on the OpenSSL devel | ||
115 | packages to the kernel build processes for the tool that does the signing. | ||
116 | |||
117 | |||
92 | ======================= | 118 | ======================= |
93 | GENERATING SIGNING KEYS | 119 | GENERATING SIGNING KEYS |
94 | ======================= | 120 | ======================= |
@@ -100,16 +126,16 @@ it can be deleted or stored securely. The public key gets built into the | |||
100 | kernel so that it can be used to check the signatures as the modules are | 126 | kernel so that it can be used to check the signatures as the modules are |
101 | loaded. | 127 | loaded. |
102 | 128 | ||
103 | Under normal conditions, the kernel build will automatically generate a new | 129 | Under normal conditions, when CONFIG_MODULE_SIG_KEY is unchanged from its |
104 | keypair using openssl if one does not exist in the files: | 130 | default, the kernel build will automatically generate a new keypair using |
131 | openssl if one does not exist in the file: | ||
105 | 132 | ||
106 | signing_key.priv | 133 | certs/signing_key.pem |
107 | signing_key.x509 | ||
108 | 134 | ||
109 | during the building of vmlinux (the public part of the key needs to be built | 135 | during the building of vmlinux (the public part of the key needs to be built |
110 | into vmlinux) using parameters in the: | 136 | into vmlinux) using parameters in the: |
111 | 137 | ||
112 | x509.genkey | 138 | certs/x509.genkey |
113 | 139 | ||
114 | file (which is also generated if it does not already exist). | 140 | file (which is also generated if it does not already exist). |
115 | 141 | ||
@@ -135,8 +161,12 @@ kernel sources tree and the openssl command. The following is an example to | |||
135 | generate the public/private key files: | 161 | generate the public/private key files: |
136 | 162 | ||
137 | openssl req -new -nodes -utf8 -sha256 -days 36500 -batch -x509 \ | 163 | openssl req -new -nodes -utf8 -sha256 -days 36500 -batch -x509 \ |
138 | -config x509.genkey -outform DER -out signing_key.x509 \ | 164 | -config x509.genkey -outform PEM -out kernel_key.pem \ |
139 | -keyout signing_key.priv | 165 | -keyout kernel_key.pem |
166 | |||
167 | The full pathname for the resulting kernel_key.pem file can then be specified | ||
168 | in the CONFIG_MODULE_SIG_KEY option, and the certificate and key therein will | ||
169 | be used instead of an autogenerated keypair. | ||
140 | 170 | ||
141 | 171 | ||
142 | ========================= | 172 | ========================= |
@@ -152,10 +182,9 @@ in a keyring called ".system_keyring" that can be seen by: | |||
152 | 302d2d52 I------ 1 perm 1f010000 0 0 asymmetri Fedora kernel signing key: d69a84e6bce3d216b979e9505b3e3ef9a7118079: X509.RSA a7118079 [] | 182 | 302d2d52 I------ 1 perm 1f010000 0 0 asymmetri Fedora kernel signing key: d69a84e6bce3d216b979e9505b3e3ef9a7118079: X509.RSA a7118079 [] |
153 | ... | 183 | ... |
154 | 184 | ||
155 | Beyond the public key generated specifically for module signing, any file | 185 | Beyond the public key generated specifically for module signing, additional |
156 | placed in the kernel source root directory or the kernel build root directory | 186 | trusted certificates can be provided in a PEM-encoded file referenced by the |
157 | whose name is suffixed with ".x509" will be assumed to be an X.509 public key | 187 | CONFIG_SYSTEM_TRUSTED_KEYS configuration option. |
158 | and will be added to the keyring. | ||
159 | 188 | ||
160 | Further, the architecture code may take public keys from a hardware store and | 189 | Further, the architecture code may take public keys from a hardware store and |
161 | add those in also (e.g. from the UEFI key database). | 190 | add those in also (e.g. from the UEFI key database). |
@@ -181,7 +210,7 @@ To manually sign a module, use the scripts/sign-file tool available in | |||
181 | the Linux kernel source tree. The script requires 4 arguments: | 210 | the Linux kernel source tree. The script requires 4 arguments: |
182 | 211 | ||
183 | 1. The hash algorithm (e.g., sha256) | 212 | 1. The hash algorithm (e.g., sha256) |
184 | 2. The private key filename | 213 | 2. The private key filename or PKCS#11 URI |
185 | 3. The public key filename | 214 | 3. The public key filename |
186 | 4. The kernel module to be signed | 215 | 4. The kernel module to be signed |
187 | 216 | ||
@@ -194,6 +223,9 @@ The hash algorithm used does not have to match the one configured, but if it | |||
194 | doesn't, you should make sure that hash algorithm is either built into the | 223 | doesn't, you should make sure that hash algorithm is either built into the |
195 | kernel or can be loaded without requiring itself. | 224 | kernel or can be loaded without requiring itself. |
196 | 225 | ||
226 | If the private key requires a passphrase or PIN, it can be provided in the | ||
227 | $KBUILD_SIGN_PIN environment variable. | ||
228 | |||
197 | 229 | ||
198 | ============================ | 230 | ============================ |
199 | SIGNED MODULES AND STRIPPING | 231 | SIGNED MODULES AND STRIPPING |
diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt index de5e1aeca7fb..5e6d07fbed07 100644 --- a/Documentation/security/Smack.txt +++ b/Documentation/security/Smack.txt | |||
@@ -28,6 +28,10 @@ Smack kernels use the CIPSO IP option. Some network | |||
28 | configurations are intolerant of IP options and can impede | 28 | configurations are intolerant of IP options and can impede |
29 | access to systems that use them as Smack does. | 29 | access to systems that use them as Smack does. |
30 | 30 | ||
31 | Smack is used in the Tizen operating system. Please | ||
32 | go to http://wiki.tizen.org for information about how | ||
33 | Smack is used in Tizen. | ||
34 | |||
31 | The current git repository for Smack user space is: | 35 | The current git repository for Smack user space is: |
32 | 36 | ||
33 | git://github.com/smack-team/smack.git | 37 | git://github.com/smack-team/smack.git |
@@ -108,6 +112,8 @@ in the smackfs filesystem. This pseudo-filesystem is mounted | |||
108 | on /sys/fs/smackfs. | 112 | on /sys/fs/smackfs. |
109 | 113 | ||
110 | access | 114 | access |
115 | Provided for backward compatibility. The access2 interface | ||
116 | is preferred and should be used instead. | ||
111 | This interface reports whether a subject with the specified | 117 | This interface reports whether a subject with the specified |
112 | Smack label has a particular access to an object with a | 118 | Smack label has a particular access to an object with a |
113 | specified Smack label. Write a fixed format access rule to | 119 | specified Smack label. Write a fixed format access rule to |
@@ -136,6 +142,8 @@ change-rule | |||
136 | those in the fourth string. If there is no such rule it will be | 142 | those in the fourth string. If there is no such rule it will be |
137 | created using the access specified in the third and the fourth strings. | 143 | created using the access specified in the third and the fourth strings. |
138 | cipso | 144 | cipso |
145 | Provided for backward compatibility. The cipso2 interface | ||
146 | is preferred and should be used instead. | ||
139 | This interface allows a specific CIPSO header to be assigned | 147 | This interface allows a specific CIPSO header to be assigned |
140 | to a Smack label. The format accepted on write is: | 148 | to a Smack label. The format accepted on write is: |
141 | "%24s%4d%4d"["%4d"]... | 149 | "%24s%4d%4d"["%4d"]... |
@@ -157,7 +165,19 @@ direct | |||
157 | doi | 165 | doi |
158 | This contains the CIPSO domain of interpretation used in | 166 | This contains the CIPSO domain of interpretation used in |
159 | network packets. | 167 | network packets. |
168 | ipv6host | ||
169 | This interface allows specific IPv6 internet addresses to be | ||
170 | treated as single label hosts. Packets are sent to single | ||
171 | label hosts only from processes that have Smack write access | ||
172 | to the host label. All packets received from single label hosts | ||
173 | are given the specified label. The format accepted on write is: | ||
174 | "%h:%h:%h:%h:%h:%h:%h:%h label" or | ||
175 | "%h:%h:%h:%h:%h:%h:%h:%h/%d label". | ||
176 | The "::" address shortcut is not supported. | ||
177 | If label is "-DELETE" a matched entry will be deleted. | ||
160 | load | 178 | load |
179 | Provided for backward compatibility. The load2 interface | ||
180 | is preferred and should be used instead. | ||
161 | This interface allows access control rules in addition to | 181 | This interface allows access control rules in addition to |
162 | the system defined rules to be specified. The format accepted | 182 | the system defined rules to be specified. The format accepted |
163 | on write is: | 183 | on write is: |
@@ -181,6 +201,8 @@ load2 | |||
181 | permissions that are not allowed. The string "r-x--" would | 201 | permissions that are not allowed. The string "r-x--" would |
182 | specify read and execute access. | 202 | specify read and execute access. |
183 | load-self | 203 | load-self |
204 | Provided for backward compatibility. The load-self2 interface | ||
205 | is preferred and should be used instead. | ||
184 | This interface allows process specific access rules to be | 206 | This interface allows process specific access rules to be |
185 | defined. These rules are only consulted if access would | 207 | defined. These rules are only consulted if access would |
186 | otherwise be permitted, and are intended to provide additional | 208 | otherwise be permitted, and are intended to provide additional |
@@ -205,6 +227,8 @@ netlabel | |||
205 | received from single label hosts are given the specified | 227 | received from single label hosts are given the specified |
206 | label. The format accepted on write is: | 228 | label. The format accepted on write is: |
207 | "%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label". | 229 | "%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label". |
230 | If the label specified is "-CIPSO" the address is treated | ||
231 | as a host that supports CIPSO headers. | ||
208 | onlycap | 232 | onlycap |
209 | This contains labels processes must have for CAP_MAC_ADMIN | 233 | This contains labels processes must have for CAP_MAC_ADMIN |
210 | and CAP_MAC_OVERRIDE to be effective. If this file is empty | 234 | and CAP_MAC_OVERRIDE to be effective. If this file is empty |
@@ -232,7 +256,8 @@ unconfined | |||
232 | is dangerous and can ruin the proper labeling of your system. | 256 | is dangerous and can ruin the proper labeling of your system. |
233 | It should never be used in production. | 257 | It should never be used in production. |
234 | 258 | ||
235 | You can add access rules in /etc/smack/accesses. They take the form: | 259 | If you are using the smackload utility |
260 | you can add access rules in /etc/smack/accesses. They take the form: | ||
236 | 261 | ||
237 | subjectlabel objectlabel access | 262 | subjectlabel objectlabel access |
238 | 263 | ||
diff --git a/Documentation/security/Yama.txt b/Documentation/security/Yama.txt index 227a63f018a2..d9ee7d7a6c7f 100644 --- a/Documentation/security/Yama.txt +++ b/Documentation/security/Yama.txt | |||
@@ -1,9 +1,7 @@ | |||
1 | Yama is a Linux Security Module that collects a number of system-wide DAC | 1 | Yama is a Linux Security Module that collects system-wide DAC security |
2 | security protections that are not handled by the core kernel itself. To | 2 | protections that are not handled by the core kernel itself. This is |
3 | select it at boot time, specify "security=yama" (though this will disable | 3 | selectable at build-time with CONFIG_SECURITY_YAMA, and can be controlled |
4 | any other LSM). | 4 | at run-time through sysctls in /proc/sys/kernel/yama: |
5 | |||
6 | Yama is controlled through sysctl in /proc/sys/kernel/yama: | ||
7 | 5 | ||
8 | - ptrace_scope | 6 | - ptrace_scope |
9 | 7 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 4d8c8e10fb39..6dfc2242715d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -2621,6 +2621,15 @@ S: Supported | |||
2621 | F: Documentation/filesystems/ceph.txt | 2621 | F: Documentation/filesystems/ceph.txt |
2622 | F: fs/ceph/ | 2622 | F: fs/ceph/ |
2623 | 2623 | ||
2624 | CERTIFICATE HANDLING: | ||
2625 | M: David Howells <dhowells@redhat.com> | ||
2626 | M: David Woodhouse <dwmw2@infradead.org> | ||
2627 | L: keyrings@linux-nfs.org | ||
2628 | S: Maintained | ||
2629 | F: Documentation/module-signing.txt | ||
2630 | F: certs/ | ||
2631 | F: scripts/extract-cert.c | ||
2632 | |||
2624 | CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM: | 2633 | CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM: |
2625 | L: linux-usb@vger.kernel.org | 2634 | L: linux-usb@vger.kernel.org |
2626 | S: Orphan | 2635 | S: Orphan |
@@ -5994,7 +6003,7 @@ F: kernel/kexec.c | |||
5994 | 6003 | ||
5995 | KEYS/KEYRINGS: | 6004 | KEYS/KEYRINGS: |
5996 | M: David Howells <dhowells@redhat.com> | 6005 | M: David Howells <dhowells@redhat.com> |
5997 | L: keyrings@linux-nfs.org | 6006 | L: keyrings@vger.kernel.org |
5998 | S: Maintained | 6007 | S: Maintained |
5999 | F: Documentation/security/keys.txt | 6008 | F: Documentation/security/keys.txt |
6000 | F: include/linux/key.h | 6009 | F: include/linux/key.h |
@@ -6006,7 +6015,7 @@ KEYS-TRUSTED | |||
6006 | M: David Safford <safford@us.ibm.com> | 6015 | M: David Safford <safford@us.ibm.com> |
6007 | M: Mimi Zohar <zohar@linux.vnet.ibm.com> | 6016 | M: Mimi Zohar <zohar@linux.vnet.ibm.com> |
6008 | L: linux-security-module@vger.kernel.org | 6017 | L: linux-security-module@vger.kernel.org |
6009 | L: keyrings@linux-nfs.org | 6018 | L: keyrings@vger.kernel.org |
6010 | S: Supported | 6019 | S: Supported |
6011 | F: Documentation/security/keys-trusted-encrypted.txt | 6020 | F: Documentation/security/keys-trusted-encrypted.txt |
6012 | F: include/keys/trusted-type.h | 6021 | F: include/keys/trusted-type.h |
@@ -6017,7 +6026,7 @@ KEYS-ENCRYPTED | |||
6017 | M: Mimi Zohar <zohar@linux.vnet.ibm.com> | 6026 | M: Mimi Zohar <zohar@linux.vnet.ibm.com> |
6018 | M: David Safford <safford@us.ibm.com> | 6027 | M: David Safford <safford@us.ibm.com> |
6019 | L: linux-security-module@vger.kernel.org | 6028 | L: linux-security-module@vger.kernel.org |
6020 | L: keyrings@linux-nfs.org | 6029 | L: keyrings@vger.kernel.org |
6021 | S: Supported | 6030 | S: Supported |
6022 | F: Documentation/security/keys-trusted-encrypted.txt | 6031 | F: Documentation/security/keys-trusted-encrypted.txt |
6023 | F: include/keys/encrypted-type.h | 6032 | F: include/keys/encrypted-type.h |
@@ -9264,6 +9273,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git | |||
9264 | S: Supported | 9273 | S: Supported |
9265 | F: security/apparmor/ | 9274 | F: security/apparmor/ |
9266 | 9275 | ||
9276 | YAMA SECURITY MODULE | ||
9277 | M: Kees Cook <keescook@chromium.org> | ||
9278 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip | ||
9279 | S: Supported | ||
9280 | F: security/yama/ | ||
9281 | |||
9267 | SENSABLE PHANTOM | 9282 | SENSABLE PHANTOM |
9268 | M: Jiri Slaby <jirislaby@gmail.com> | 9283 | M: Jiri Slaby <jirislaby@gmail.com> |
9269 | S: Maintained | 9284 | S: Maintained |
@@ -875,10 +875,9 @@ INITRD_COMPRESS-$(CONFIG_RD_LZ4) := lz4 | |||
875 | # export INITRD_COMPRESS := $(INITRD_COMPRESS-y) | 875 | # export INITRD_COMPRESS := $(INITRD_COMPRESS-y) |
876 | 876 | ||
877 | ifdef CONFIG_MODULE_SIG_ALL | 877 | ifdef CONFIG_MODULE_SIG_ALL |
878 | MODSECKEY = ./signing_key.priv | 878 | $(eval $(call config_filename,MODULE_SIG_KEY)) |
879 | MODPUBKEY = ./signing_key.x509 | 879 | |
880 | export MODPUBKEY | 880 | mod_sign_cmd = scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY) certs/signing_key.x509 |
881 | mod_sign_cmd = perl $(srctree)/scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(MODSECKEY) $(MODPUBKEY) | ||
882 | else | 881 | else |
883 | mod_sign_cmd = true | 882 | mod_sign_cmd = true |
884 | endif | 883 | endif |
@@ -886,7 +885,7 @@ export mod_sign_cmd | |||
886 | 885 | ||
887 | 886 | ||
888 | ifeq ($(KBUILD_EXTMOD),) | 887 | ifeq ($(KBUILD_EXTMOD),) |
889 | core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ | 888 | core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ |
890 | 889 | ||
891 | vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ | 890 | vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ |
892 | $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ | 891 | $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ |
@@ -1178,8 +1177,8 @@ MRPROPER_DIRS += include/config usr/include include/generated \ | |||
1178 | arch/*/include/generated .tmp_objdiff | 1177 | arch/*/include/generated .tmp_objdiff |
1179 | MRPROPER_FILES += .config .config.old .version .old_version \ | 1178 | MRPROPER_FILES += .config .config.old .version .old_version \ |
1180 | Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \ | 1179 | Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \ |
1181 | signing_key.priv signing_key.x509 x509.genkey \ | 1180 | signing_key.pem signing_key.priv signing_key.x509 \ |
1182 | extra_certificates signing_key.x509.keyid \ | 1181 | x509.genkey extra_certificates signing_key.x509.keyid \ |
1183 | signing_key.x509.signer vmlinux-gdb.py | 1182 | signing_key.x509.signer vmlinux-gdb.py |
1184 | 1183 | ||
1185 | # clean - Delete most, but leave enough to build external modules | 1184 | # clean - Delete most, but leave enough to build external modules |
diff --git a/arch/mips/configs/pistachio_defconfig b/arch/mips/configs/pistachio_defconfig index 1646cce032c3..642b50946943 100644 --- a/arch/mips/configs/pistachio_defconfig +++ b/arch/mips/configs/pistachio_defconfig | |||
@@ -320,7 +320,6 @@ CONFIG_KEYS=y | |||
320 | CONFIG_SECURITY=y | 320 | CONFIG_SECURITY=y |
321 | CONFIG_SECURITY_NETWORK=y | 321 | CONFIG_SECURITY_NETWORK=y |
322 | CONFIG_SECURITY_YAMA=y | 322 | CONFIG_SECURITY_YAMA=y |
323 | CONFIG_SECURITY_YAMA_STACKED=y | ||
324 | CONFIG_DEFAULT_SECURITY_DAC=y | 323 | CONFIG_DEFAULT_SECURITY_DAC=y |
325 | CONFIG_CRYPTO_AUTHENC=y | 324 | CONFIG_CRYPTO_AUTHENC=y |
326 | CONFIG_CRYPTO_HMAC=y | 325 | CONFIG_CRYPTO_HMAC=y |
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index 961e51e9c6f6..0f8a6bbaaa44 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c | |||
@@ -533,7 +533,9 @@ static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len) | |||
533 | int ret; | 533 | int ret; |
534 | 534 | ||
535 | ret = verify_pefile_signature(kernel, kernel_len, | 535 | ret = verify_pefile_signature(kernel, kernel_len, |
536 | system_trusted_keyring, &trusted); | 536 | system_trusted_keyring, |
537 | VERIFYING_KEXEC_PE_SIGNATURE, | ||
538 | &trusted); | ||
537 | if (ret < 0) | 539 | if (ret < 0) |
538 | return ret; | 540 | return ret; |
539 | if (!trusted) | 541 | if (!trusted) |
diff --git a/certs/Kconfig b/certs/Kconfig new file mode 100644 index 000000000000..b030b9c7ed34 --- /dev/null +++ b/certs/Kconfig | |||
@@ -0,0 +1,42 @@ | |||
1 | menu "Certificates for signature checking" | ||
2 | |||
3 | config MODULE_SIG_KEY | ||
4 | string "File name or PKCS#11 URI of module signing key" | ||
5 | default "certs/signing_key.pem" | ||
6 | depends on MODULE_SIG | ||
7 | help | ||
8 | Provide the file name of a private key/certificate in PEM format, | ||
9 | or a PKCS#11 URI according to RFC7512. The file should contain, or | ||
10 | the URI should identify, both the certificate and its corresponding | ||
11 | private key. | ||
12 | |||
13 | If this option is unchanged from its default "certs/signing_key.pem", | ||
14 | then the kernel will automatically generate the private key and | ||
15 | certificate as described in Documentation/module-signing.txt | ||
16 | |||
17 | config SYSTEM_TRUSTED_KEYRING | ||
18 | bool "Provide system-wide ring of trusted keys" | ||
19 | depends on KEYS | ||
20 | help | ||
21 | Provide a system keyring to which trusted keys can be added. Keys in | ||
22 | the keyring are considered to be trusted. Keys may be added at will | ||
23 | by the kernel from compiled-in data and from hardware key stores, but | ||
24 | userspace may only add extra keys if those keys can be verified by | ||
25 | keys already in the keyring. | ||
26 | |||
27 | Keys in this keyring are used by module signature checking. | ||
28 | |||
29 | config SYSTEM_TRUSTED_KEYS | ||
30 | string "Additional X.509 keys for default system keyring" | ||
31 | depends on SYSTEM_TRUSTED_KEYRING | ||
32 | help | ||
33 | If set, this option should be the filename of a PEM-formatted file | ||
34 | containing trusted X.509 certificates to be included in the default | ||
35 | system keyring. Any certificate used for module signing is implicitly | ||
36 | also trusted. | ||
37 | |||
38 | NOTE: If you previously provided keys for the system keyring in the | ||
39 | form of DER-encoded *.x509 files in the top-level build directory, | ||
40 | those are no longer used. You will need to set this option instead. | ||
41 | |||
42 | endmenu | ||
diff --git a/certs/Makefile b/certs/Makefile new file mode 100644 index 000000000000..28ac694dd11a --- /dev/null +++ b/certs/Makefile | |||
@@ -0,0 +1,94 @@ | |||
1 | # | ||
2 | # Makefile for the linux kernel signature checking certificates. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o | ||
6 | |||
7 | ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) | ||
8 | |||
9 | $(eval $(call config_filename,SYSTEM_TRUSTED_KEYS)) | ||
10 | |||
11 | # GCC doesn't include .incbin files in -MD generated dependencies (PR#66871) | ||
12 | $(obj)/system_certificates.o: $(obj)/x509_certificate_list | ||
13 | |||
14 | # Cope with signing_key.x509 existing in $(srctree) not $(objtree) | ||
15 | AFLAGS_system_certificates.o := -I$(srctree) | ||
16 | |||
17 | quiet_cmd_extract_certs = EXTRACT_CERTS $(patsubst "%",%,$(2)) | ||
18 | cmd_extract_certs = scripts/extract-cert $(2) $@ || ( rm $@; exit 1) | ||
19 | |||
20 | targets += x509_certificate_list | ||
21 | $(obj)/x509_certificate_list: scripts/extract-cert $(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(SYSTEM_TRUSTED_KEYS_FILENAME) FORCE | ||
22 | $(call if_changed,extract_certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS)) | ||
23 | endif | ||
24 | |||
25 | clean-files := x509_certificate_list .x509.list | ||
26 | |||
27 | ifeq ($(CONFIG_MODULE_SIG),y) | ||
28 | ############################################################################### | ||
29 | # | ||
30 | # If module signing is requested, say by allyesconfig, but a key has not been | ||
31 | # supplied, then one will need to be generated to make sure the build does not | ||
32 | # fail and that the kernel may be used afterwards. | ||
33 | # | ||
34 | ############################################################################### | ||
35 | ifndef CONFIG_MODULE_SIG_HASH | ||
36 | $(error Could not determine digest type to use from kernel config) | ||
37 | endif | ||
38 | |||
39 | # We do it this way rather than having a boolean option for enabling an | ||
40 | # external private key, because 'make randconfig' might enable such a | ||
41 | # boolean option and we unfortunately can't make it depend on !RANDCONFIG. | ||
42 | ifeq ($(CONFIG_MODULE_SIG_KEY),"certs/signing_key.pem") | ||
43 | $(obj)/signing_key.pem: $(obj)/x509.genkey | ||
44 | @echo "###" | ||
45 | @echo "### Now generating an X.509 key pair to be used for signing modules." | ||
46 | @echo "###" | ||
47 | @echo "### If this takes a long time, you might wish to run rngd in the" | ||
48 | @echo "### background to keep the supply of entropy topped up. It" | ||
49 | @echo "### needs to be run as root, and uses a hardware random" | ||
50 | @echo "### number generator if one is available." | ||
51 | @echo "###" | ||
52 | openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \ | ||
53 | -batch -x509 -config $(obj)/x509.genkey \ | ||
54 | -outform PEM -out $(obj)/signing_key.pem \ | ||
55 | -keyout $(obj)/signing_key.pem 2>&1 | ||
56 | @echo "###" | ||
57 | @echo "### Key pair generated." | ||
58 | @echo "###" | ||
59 | |||
60 | $(obj)/x509.genkey: | ||
61 | @echo Generating X.509 key generation config | ||
62 | @echo >$@ "[ req ]" | ||
63 | @echo >>$@ "default_bits = 4096" | ||
64 | @echo >>$@ "distinguished_name = req_distinguished_name" | ||
65 | @echo >>$@ "prompt = no" | ||
66 | @echo >>$@ "string_mask = utf8only" | ||
67 | @echo >>$@ "x509_extensions = myexts" | ||
68 | @echo >>$@ | ||
69 | @echo >>$@ "[ req_distinguished_name ]" | ||
70 | @echo >>$@ "#O = Unspecified company" | ||
71 | @echo >>$@ "CN = Build time autogenerated kernel key" | ||
72 | @echo >>$@ "#emailAddress = unspecified.user@unspecified.company" | ||
73 | @echo >>$@ | ||
74 | @echo >>$@ "[ myexts ]" | ||
75 | @echo >>$@ "basicConstraints=critical,CA:FALSE" | ||
76 | @echo >>$@ "keyUsage=digitalSignature" | ||
77 | @echo >>$@ "subjectKeyIdentifier=hash" | ||
78 | @echo >>$@ "authorityKeyIdentifier=keyid" | ||
79 | endif | ||
80 | |||
81 | $(eval $(call config_filename,MODULE_SIG_KEY)) | ||
82 | |||
83 | # If CONFIG_MODULE_SIG_KEY isn't a PKCS#11 URI, depend on it | ||
84 | ifeq ($(patsubst pkcs11:%,%,$(firstword $(MODULE_SIG_KEY_FILENAME))),$(firstword $(MODULE_SIG_KEY_FILENAME))) | ||
85 | X509_DEP := $(MODULE_SIG_KEY_SRCPREFIX)$(MODULE_SIG_KEY_FILENAME) | ||
86 | endif | ||
87 | |||
88 | # GCC PR#66871 again. | ||
89 | $(obj)/system_certificates.o: $(obj)/signing_key.x509 | ||
90 | |||
91 | targets += signing_key.x509 | ||
92 | $(obj)/signing_key.x509: scripts/extract-cert $(X509_DEP) FORCE | ||
93 | $(call if_changed,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY)) | ||
94 | endif | ||
diff --git a/kernel/system_certificates.S b/certs/system_certificates.S index 3e9868d47535..9216e8c81764 100644 --- a/kernel/system_certificates.S +++ b/certs/system_certificates.S | |||
@@ -7,7 +7,10 @@ | |||
7 | .globl VMLINUX_SYMBOL(system_certificate_list) | 7 | .globl VMLINUX_SYMBOL(system_certificate_list) |
8 | VMLINUX_SYMBOL(system_certificate_list): | 8 | VMLINUX_SYMBOL(system_certificate_list): |
9 | __cert_list_start: | 9 | __cert_list_start: |
10 | .incbin "kernel/x509_certificate_list" | 10 | #ifdef CONFIG_MODULE_SIG |
11 | .incbin "certs/signing_key.x509" | ||
12 | #endif | ||
13 | .incbin "certs/x509_certificate_list" | ||
11 | __cert_list_end: | 14 | __cert_list_end: |
12 | 15 | ||
13 | .align 8 | 16 | .align 8 |
diff --git a/kernel/system_keyring.c b/certs/system_keyring.c index 875f64e8935b..2570598b784d 100644 --- a/kernel/system_keyring.c +++ b/certs/system_keyring.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <keys/asymmetric-type.h> | 17 | #include <keys/asymmetric-type.h> |
18 | #include <keys/system_keyring.h> | 18 | #include <keys/system_keyring.h> |
19 | #include "module-internal.h" | 19 | #include <crypto/pkcs7.h> |
20 | 20 | ||
21 | struct key *system_trusted_keyring; | 21 | struct key *system_trusted_keyring; |
22 | EXPORT_SYMBOL_GPL(system_trusted_keyring); | 22 | EXPORT_SYMBOL_GPL(system_trusted_keyring); |
@@ -104,3 +104,54 @@ dodgy_cert: | |||
104 | return 0; | 104 | return 0; |
105 | } | 105 | } |
106 | late_initcall(load_system_certificate_list); | 106 | late_initcall(load_system_certificate_list); |
107 | |||
108 | #ifdef CONFIG_SYSTEM_DATA_VERIFICATION | ||
109 | |||
110 | /** | ||
111 | * Verify a PKCS#7-based signature on system data. | ||
112 | * @data: The data to be verified. | ||
113 | * @len: Size of @data. | ||
114 | * @raw_pkcs7: The PKCS#7 message that is the signature. | ||
115 | * @pkcs7_len: The size of @raw_pkcs7. | ||
116 | * @usage: The use to which the key is being put. | ||
117 | */ | ||
118 | int system_verify_data(const void *data, unsigned long len, | ||
119 | const void *raw_pkcs7, size_t pkcs7_len, | ||
120 | enum key_being_used_for usage) | ||
121 | { | ||
122 | struct pkcs7_message *pkcs7; | ||
123 | bool trusted; | ||
124 | int ret; | ||
125 | |||
126 | pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len); | ||
127 | if (IS_ERR(pkcs7)) | ||
128 | return PTR_ERR(pkcs7); | ||
129 | |||
130 | /* The data should be detached - so we need to supply it. */ | ||
131 | if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) { | ||
132 | pr_err("PKCS#7 signature with non-detached data\n"); | ||
133 | ret = -EBADMSG; | ||
134 | goto error; | ||
135 | } | ||
136 | |||
137 | ret = pkcs7_verify(pkcs7, usage); | ||
138 | if (ret < 0) | ||
139 | goto error; | ||
140 | |||
141 | ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); | ||
142 | if (ret < 0) | ||
143 | goto error; | ||
144 | |||
145 | if (!trusted) { | ||
146 | pr_err("PKCS#7 signature not signed with a trusted key\n"); | ||
147 | ret = -ENOKEY; | ||
148 | } | ||
149 | |||
150 | error: | ||
151 | pkcs7_free_message(pkcs7); | ||
152 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
153 | return ret; | ||
154 | } | ||
155 | EXPORT_SYMBOL_GPL(system_verify_data); | ||
156 | |||
157 | #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */ | ||
diff --git a/crypto/Kconfig b/crypto/Kconfig index b582ea7f78d3..48ee3e175dac 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig | |||
@@ -1635,5 +1635,6 @@ config CRYPTO_HASH_INFO | |||
1635 | 1635 | ||
1636 | source "drivers/crypto/Kconfig" | 1636 | source "drivers/crypto/Kconfig" |
1637 | source crypto/asymmetric_keys/Kconfig | 1637 | source crypto/asymmetric_keys/Kconfig |
1638 | source certs/Kconfig | ||
1638 | 1639 | ||
1639 | endif # if CRYPTO | 1640 | endif # if CRYPTO |
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile index e47fcd9ac5e8..cd1406f9b14a 100644 --- a/crypto/asymmetric_keys/Makefile +++ b/crypto/asymmetric_keys/Makefile | |||
@@ -15,15 +15,21 @@ obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o | |||
15 | obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o | 15 | obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o |
16 | x509_key_parser-y := \ | 16 | x509_key_parser-y := \ |
17 | x509-asn1.o \ | 17 | x509-asn1.o \ |
18 | x509_akid-asn1.o \ | ||
18 | x509_rsakey-asn1.o \ | 19 | x509_rsakey-asn1.o \ |
19 | x509_cert_parser.o \ | 20 | x509_cert_parser.o \ |
20 | x509_public_key.o | 21 | x509_public_key.o |
21 | 22 | ||
22 | $(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h | 23 | $(obj)/x509_cert_parser.o: \ |
24 | $(obj)/x509-asn1.h \ | ||
25 | $(obj)/x509_akid-asn1.h \ | ||
26 | $(obj)/x509_rsakey-asn1.h | ||
23 | $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h | 27 | $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h |
28 | $(obj)/x509_akid-asn1.o: $(obj)/x509_akid-asn1.c $(obj)/x509_akid-asn1.h | ||
24 | $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h | 29 | $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h |
25 | 30 | ||
26 | clean-files += x509-asn1.c x509-asn1.h | 31 | clean-files += x509-asn1.c x509-asn1.h |
32 | clean-files += x509_akid-asn1.c x509_akid-asn1.h | ||
27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h | 33 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h |
28 | 34 | ||
29 | # | 35 | # |
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index b0e4ed23d668..1916680ad81b 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c | |||
@@ -12,6 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | #include <keys/asymmetric-subtype.h> | 13 | #include <keys/asymmetric-subtype.h> |
14 | #include <keys/asymmetric-parser.h> | 14 | #include <keys/asymmetric-parser.h> |
15 | #include <crypto/public_key.h> | ||
15 | #include <linux/seq_file.h> | 16 | #include <linux/seq_file.h> |
16 | #include <linux/module.h> | 17 | #include <linux/module.h> |
17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
@@ -20,6 +21,16 @@ | |||
20 | 21 | ||
21 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
22 | 23 | ||
24 | const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = { | ||
25 | [VERIFYING_MODULE_SIGNATURE] = "mod sig", | ||
26 | [VERIFYING_FIRMWARE_SIGNATURE] = "firmware sig", | ||
27 | [VERIFYING_KEXEC_PE_SIGNATURE] = "kexec PE sig", | ||
28 | [VERIFYING_KEY_SIGNATURE] = "key sig", | ||
29 | [VERIFYING_KEY_SELF_SIGNATURE] = "key self sig", | ||
30 | [VERIFYING_UNSPECIFIED_SIGNATURE] = "unspec sig", | ||
31 | }; | ||
32 | EXPORT_SYMBOL_GPL(key_being_used_for); | ||
33 | |||
23 | static LIST_HEAD(asymmetric_key_parsers); | 34 | static LIST_HEAD(asymmetric_key_parsers); |
24 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | 35 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); |
25 | 36 | ||
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c index 214a992123cd..adcef59eec0b 100644 --- a/crypto/asymmetric_keys/mscode_parser.c +++ b/crypto/asymmetric_keys/mscode_parser.c | |||
@@ -97,6 +97,15 @@ int mscode_note_digest_algo(void *context, size_t hdrlen, | |||
97 | case OID_sha256: | 97 | case OID_sha256: |
98 | ctx->digest_algo = HASH_ALGO_SHA256; | 98 | ctx->digest_algo = HASH_ALGO_SHA256; |
99 | break; | 99 | break; |
100 | case OID_sha384: | ||
101 | ctx->digest_algo = HASH_ALGO_SHA384; | ||
102 | break; | ||
103 | case OID_sha512: | ||
104 | ctx->digest_algo = HASH_ALGO_SHA512; | ||
105 | break; | ||
106 | case OID_sha224: | ||
107 | ctx->digest_algo = HASH_ALGO_SHA224; | ||
108 | break; | ||
100 | 109 | ||
101 | case OID__NR: | 110 | case OID__NR: |
102 | sprint_oid(value, vlen, buffer, sizeof(buffer)); | 111 | sprint_oid(value, vlen, buffer, sizeof(buffer)); |
diff --git a/crypto/asymmetric_keys/pkcs7.asn1 b/crypto/asymmetric_keys/pkcs7.asn1 index a5a14ef28c86..1eca740b816a 100644 --- a/crypto/asymmetric_keys/pkcs7.asn1 +++ b/crypto/asymmetric_keys/pkcs7.asn1 | |||
@@ -1,14 +1,14 @@ | |||
1 | PKCS7ContentInfo ::= SEQUENCE { | 1 | PKCS7ContentInfo ::= SEQUENCE { |
2 | contentType ContentType, | 2 | contentType ContentType ({ pkcs7_check_content_type }), |
3 | content [0] EXPLICIT SignedData OPTIONAL | 3 | content [0] EXPLICIT SignedData OPTIONAL |
4 | } | 4 | } |
5 | 5 | ||
6 | ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID }) | 6 | ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID }) |
7 | 7 | ||
8 | SignedData ::= SEQUENCE { | 8 | SignedData ::= SEQUENCE { |
9 | version INTEGER, | 9 | version INTEGER ({ pkcs7_note_signeddata_version }), |
10 | digestAlgorithms DigestAlgorithmIdentifiers, | 10 | digestAlgorithms DigestAlgorithmIdentifiers, |
11 | contentInfo ContentInfo, | 11 | contentInfo ContentInfo ({ pkcs7_note_content }), |
12 | certificates CHOICE { | 12 | certificates CHOICE { |
13 | certSet [0] IMPLICIT ExtendedCertificatesAndCertificates, | 13 | certSet [0] IMPLICIT ExtendedCertificatesAndCertificates, |
14 | certSequence [2] IMPLICIT Certificates | 14 | certSequence [2] IMPLICIT Certificates |
@@ -21,7 +21,7 @@ SignedData ::= SEQUENCE { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | ContentInfo ::= SEQUENCE { | 23 | ContentInfo ::= SEQUENCE { |
24 | contentType ContentType, | 24 | contentType ContentType ({ pkcs7_note_OID }), |
25 | content [0] EXPLICIT Data OPTIONAL | 25 | content [0] EXPLICIT Data OPTIONAL |
26 | } | 26 | } |
27 | 27 | ||
@@ -68,8 +68,8 @@ SignerInfos ::= CHOICE { | |||
68 | } | 68 | } |
69 | 69 | ||
70 | SignerInfo ::= SEQUENCE { | 70 | SignerInfo ::= SEQUENCE { |
71 | version INTEGER, | 71 | version INTEGER ({ pkcs7_note_signerinfo_version }), |
72 | issuerAndSerialNumber IssuerAndSerialNumber, | 72 | sid SignerIdentifier, -- CMS variant, not PKCS#7 |
73 | digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }), | 73 | digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }), |
74 | authenticatedAttributes CHOICE { | 74 | authenticatedAttributes CHOICE { |
75 | aaSet [0] IMPLICIT SetOfAuthenticatedAttribute | 75 | aaSet [0] IMPLICIT SetOfAuthenticatedAttribute |
@@ -88,6 +88,12 @@ SignerInfo ::= SEQUENCE { | |||
88 | } OPTIONAL | 88 | } OPTIONAL |
89 | } ({ pkcs7_note_signed_info }) | 89 | } ({ pkcs7_note_signed_info }) |
90 | 90 | ||
91 | SignerIdentifier ::= CHOICE { | ||
92 | -- RFC5652 sec 5.3 | ||
93 | issuerAndSerialNumber IssuerAndSerialNumber, | ||
94 | subjectKeyIdentifier [0] IMPLICIT SubjectKeyIdentifier | ||
95 | } | ||
96 | |||
91 | IssuerAndSerialNumber ::= SEQUENCE { | 97 | IssuerAndSerialNumber ::= SEQUENCE { |
92 | issuer Name ({ pkcs7_sig_note_issuer }), | 98 | issuer Name ({ pkcs7_sig_note_issuer }), |
93 | serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial }) | 99 | serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial }) |
@@ -95,6 +101,8 @@ IssuerAndSerialNumber ::= SEQUENCE { | |||
95 | 101 | ||
96 | CertificateSerialNumber ::= INTEGER | 102 | CertificateSerialNumber ::= INTEGER |
97 | 103 | ||
104 | SubjectKeyIdentifier ::= OCTET STRING ({ pkcs7_sig_note_skid }) | ||
105 | |||
98 | SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute | 106 | SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute |
99 | 107 | ||
100 | AuthenticatedAttribute ::= SEQUENCE { | 108 | AuthenticatedAttribute ::= SEQUENCE { |
@@ -103,7 +111,7 @@ AuthenticatedAttribute ::= SEQUENCE { | |||
103 | } | 111 | } |
104 | 112 | ||
105 | UnauthenticatedAttribute ::= SEQUENCE { | 113 | UnauthenticatedAttribute ::= SEQUENCE { |
106 | type OBJECT IDENTIFIER ({ pkcs7_note_OID }), | 114 | type OBJECT IDENTIFIER, |
107 | values SET OF ANY | 115 | values SET OF ANY |
108 | } | 116 | } |
109 | 117 | ||
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c index 3d13b042da73..e2d0edbbc71a 100644 --- a/crypto/asymmetric_keys/pkcs7_key_type.c +++ b/crypto/asymmetric_keys/pkcs7_key_type.c | |||
@@ -14,16 +14,26 @@ | |||
14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/key-type.h> | 16 | #include <linux/key-type.h> |
17 | #include <keys/asymmetric-type.h> | ||
17 | #include <crypto/pkcs7.h> | 18 | #include <crypto/pkcs7.h> |
18 | #include <keys/user-type.h> | 19 | #include <keys/user-type.h> |
19 | #include <keys/system_keyring.h> | 20 | #include <keys/system_keyring.h> |
20 | #include "pkcs7_parser.h" | 21 | #include "pkcs7_parser.h" |
21 | 22 | ||
23 | MODULE_LICENSE("GPL"); | ||
24 | MODULE_DESCRIPTION("PKCS#7 testing key type"); | ||
25 | |||
26 | static unsigned pkcs7_usage; | ||
27 | module_param_named(usage, pkcs7_usage, uint, S_IWUSR | S_IRUGO); | ||
28 | MODULE_PARM_DESC(pkcs7_usage, | ||
29 | "Usage to specify when verifying the PKCS#7 message"); | ||
30 | |||
22 | /* | 31 | /* |
23 | * Preparse a PKCS#7 wrapped and validated data blob. | 32 | * Preparse a PKCS#7 wrapped and validated data blob. |
24 | */ | 33 | */ |
25 | static int pkcs7_preparse(struct key_preparsed_payload *prep) | 34 | static int pkcs7_preparse(struct key_preparsed_payload *prep) |
26 | { | 35 | { |
36 | enum key_being_used_for usage = pkcs7_usage; | ||
27 | struct pkcs7_message *pkcs7; | 37 | struct pkcs7_message *pkcs7; |
28 | const void *data, *saved_prep_data; | 38 | const void *data, *saved_prep_data; |
29 | size_t datalen, saved_prep_datalen; | 39 | size_t datalen, saved_prep_datalen; |
@@ -32,6 +42,11 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep) | |||
32 | 42 | ||
33 | kenter(""); | 43 | kenter(""); |
34 | 44 | ||
45 | if (usage >= NR__KEY_BEING_USED_FOR) { | ||
46 | pr_err("Invalid usage type %d\n", usage); | ||
47 | return -EINVAL; | ||
48 | } | ||
49 | |||
35 | saved_prep_data = prep->data; | 50 | saved_prep_data = prep->data; |
36 | saved_prep_datalen = prep->datalen; | 51 | saved_prep_datalen = prep->datalen; |
37 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); | 52 | pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); |
@@ -40,7 +55,7 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep) | |||
40 | goto error; | 55 | goto error; |
41 | } | 56 | } |
42 | 57 | ||
43 | ret = pkcs7_verify(pkcs7); | 58 | ret = pkcs7_verify(pkcs7, usage); |
44 | if (ret < 0) | 59 | if (ret < 0) |
45 | goto error_free; | 60 | goto error_free; |
46 | 61 | ||
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index 3bd5a1e4c493..758acabf2d81 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c | |||
@@ -33,6 +33,9 @@ struct pkcs7_parse_context { | |||
33 | unsigned raw_serial_size; | 33 | unsigned raw_serial_size; |
34 | unsigned raw_issuer_size; | 34 | unsigned raw_issuer_size; |
35 | const void *raw_issuer; | 35 | const void *raw_issuer; |
36 | const void *raw_skid; | ||
37 | unsigned raw_skid_size; | ||
38 | bool expect_skid; | ||
36 | }; | 39 | }; |
37 | 40 | ||
38 | /* | 41 | /* |
@@ -78,6 +81,30 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7) | |||
78 | } | 81 | } |
79 | EXPORT_SYMBOL_GPL(pkcs7_free_message); | 82 | EXPORT_SYMBOL_GPL(pkcs7_free_message); |
80 | 83 | ||
84 | /* | ||
85 | * Check authenticatedAttributes are provided or not provided consistently. | ||
86 | */ | ||
87 | static int pkcs7_check_authattrs(struct pkcs7_message *msg) | ||
88 | { | ||
89 | struct pkcs7_signed_info *sinfo; | ||
90 | bool want; | ||
91 | |||
92 | sinfo = msg->signed_infos; | ||
93 | if (sinfo->authattrs) { | ||
94 | want = true; | ||
95 | msg->have_authattrs = true; | ||
96 | } | ||
97 | |||
98 | for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next) | ||
99 | if (!!sinfo->authattrs != want) | ||
100 | goto inconsistent; | ||
101 | return 0; | ||
102 | |||
103 | inconsistent: | ||
104 | pr_warn("Inconsistently supplied authAttrs\n"); | ||
105 | return -EINVAL; | ||
106 | } | ||
107 | |||
81 | /** | 108 | /** |
82 | * pkcs7_parse_message - Parse a PKCS#7 message | 109 | * pkcs7_parse_message - Parse a PKCS#7 message |
83 | * @data: The raw binary ASN.1 encoded message to be parsed | 110 | * @data: The raw binary ASN.1 encoded message to be parsed |
@@ -110,6 +137,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen) | |||
110 | goto out; | 137 | goto out; |
111 | } | 138 | } |
112 | 139 | ||
140 | ret = pkcs7_check_authattrs(ctx->msg); | ||
141 | if (ret < 0) | ||
142 | goto out; | ||
143 | |||
113 | msg = ctx->msg; | 144 | msg = ctx->msg; |
114 | ctx->msg = NULL; | 145 | ctx->msg = NULL; |
115 | 146 | ||
@@ -198,6 +229,14 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, | |||
198 | case OID_sha256: | 229 | case OID_sha256: |
199 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256; | 230 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256; |
200 | break; | 231 | break; |
232 | case OID_sha384: | ||
233 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA384; | ||
234 | break; | ||
235 | case OID_sha512: | ||
236 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA512; | ||
237 | break; | ||
238 | case OID_sha224: | ||
239 | ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA224; | ||
201 | default: | 240 | default: |
202 | printk("Unsupported digest algo: %u\n", ctx->last_oid); | 241 | printk("Unsupported digest algo: %u\n", ctx->last_oid); |
203 | return -ENOPKG; | 242 | return -ENOPKG; |
@@ -226,6 +265,100 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen, | |||
226 | } | 265 | } |
227 | 266 | ||
228 | /* | 267 | /* |
268 | * We only support signed data [RFC2315 sec 9]. | ||
269 | */ | ||
270 | int pkcs7_check_content_type(void *context, size_t hdrlen, | ||
271 | unsigned char tag, | ||
272 | const void *value, size_t vlen) | ||
273 | { | ||
274 | struct pkcs7_parse_context *ctx = context; | ||
275 | |||
276 | if (ctx->last_oid != OID_signed_data) { | ||
277 | pr_warn("Only support pkcs7_signedData type\n"); | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * Note the SignedData version | ||
286 | */ | ||
287 | int pkcs7_note_signeddata_version(void *context, size_t hdrlen, | ||
288 | unsigned char tag, | ||
289 | const void *value, size_t vlen) | ||
290 | { | ||
291 | struct pkcs7_parse_context *ctx = context; | ||
292 | unsigned version; | ||
293 | |||
294 | if (vlen != 1) | ||
295 | goto unsupported; | ||
296 | |||
297 | ctx->msg->version = version = *(const u8 *)value; | ||
298 | switch (version) { | ||
299 | case 1: | ||
300 | /* PKCS#7 SignedData [RFC2315 sec 9.1] | ||
301 | * CMS ver 1 SignedData [RFC5652 sec 5.1] | ||
302 | */ | ||
303 | break; | ||
304 | case 3: | ||
305 | /* CMS ver 3 SignedData [RFC2315 sec 5.1] */ | ||
306 | break; | ||
307 | default: | ||
308 | goto unsupported; | ||
309 | } | ||
310 | |||
311 | return 0; | ||
312 | |||
313 | unsupported: | ||
314 | pr_warn("Unsupported SignedData version\n"); | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Note the SignerInfo version | ||
320 | */ | ||
321 | int pkcs7_note_signerinfo_version(void *context, size_t hdrlen, | ||
322 | unsigned char tag, | ||
323 | const void *value, size_t vlen) | ||
324 | { | ||
325 | struct pkcs7_parse_context *ctx = context; | ||
326 | unsigned version; | ||
327 | |||
328 | if (vlen != 1) | ||
329 | goto unsupported; | ||
330 | |||
331 | version = *(const u8 *)value; | ||
332 | switch (version) { | ||
333 | case 1: | ||
334 | /* PKCS#7 SignerInfo [RFC2315 sec 9.2] | ||
335 | * CMS ver 1 SignerInfo [RFC5652 sec 5.3] | ||
336 | */ | ||
337 | if (ctx->msg->version != 1) | ||
338 | goto version_mismatch; | ||
339 | ctx->expect_skid = false; | ||
340 | break; | ||
341 | case 3: | ||
342 | /* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */ | ||
343 | if (ctx->msg->version == 1) | ||
344 | goto version_mismatch; | ||
345 | ctx->expect_skid = true; | ||
346 | break; | ||
347 | default: | ||
348 | goto unsupported; | ||
349 | } | ||
350 | |||
351 | return 0; | ||
352 | |||
353 | unsupported: | ||
354 | pr_warn("Unsupported SignerInfo version\n"); | ||
355 | return -EINVAL; | ||
356 | version_mismatch: | ||
357 | pr_warn("SignedData-SignerInfo version mismatch\n"); | ||
358 | return -EBADMSG; | ||
359 | } | ||
360 | |||
361 | /* | ||
229 | * Extract a certificate and store it in the context. | 362 | * Extract a certificate and store it in the context. |
230 | */ | 363 | */ |
231 | int pkcs7_extract_cert(void *context, size_t hdrlen, | 364 | int pkcs7_extract_cert(void *context, size_t hdrlen, |
@@ -284,6 +417,25 @@ int pkcs7_note_certificate_list(void *context, size_t hdrlen, | |||
284 | } | 417 | } |
285 | 418 | ||
286 | /* | 419 | /* |
420 | * Note the content type. | ||
421 | */ | ||
422 | int pkcs7_note_content(void *context, size_t hdrlen, | ||
423 | unsigned char tag, | ||
424 | const void *value, size_t vlen) | ||
425 | { | ||
426 | struct pkcs7_parse_context *ctx = context; | ||
427 | |||
428 | if (ctx->last_oid != OID_data && | ||
429 | ctx->last_oid != OID_msIndirectData) { | ||
430 | pr_warn("Unsupported data type %d\n", ctx->last_oid); | ||
431 | return -EINVAL; | ||
432 | } | ||
433 | |||
434 | ctx->msg->data_type = ctx->last_oid; | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | /* | ||
287 | * Extract the data from the message and store that and its content type OID in | 439 | * Extract the data from the message and store that and its content type OID in |
288 | * the context. | 440 | * the context. |
289 | */ | 441 | */ |
@@ -298,45 +450,119 @@ int pkcs7_note_data(void *context, size_t hdrlen, | |||
298 | ctx->msg->data = value; | 450 | ctx->msg->data = value; |
299 | ctx->msg->data_len = vlen; | 451 | ctx->msg->data_len = vlen; |
300 | ctx->msg->data_hdrlen = hdrlen; | 452 | ctx->msg->data_hdrlen = hdrlen; |
301 | ctx->msg->data_type = ctx->last_oid; | ||
302 | return 0; | 453 | return 0; |
303 | } | 454 | } |
304 | 455 | ||
305 | /* | 456 | /* |
306 | * Parse authenticated attributes | 457 | * Parse authenticated attributes. |
307 | */ | 458 | */ |
308 | int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, | 459 | int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen, |
309 | unsigned char tag, | 460 | unsigned char tag, |
310 | const void *value, size_t vlen) | 461 | const void *value, size_t vlen) |
311 | { | 462 | { |
312 | struct pkcs7_parse_context *ctx = context; | 463 | struct pkcs7_parse_context *ctx = context; |
464 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | ||
465 | enum OID content_type; | ||
313 | 466 | ||
314 | pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); | 467 | pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); |
315 | 468 | ||
316 | switch (ctx->last_oid) { | 469 | switch (ctx->last_oid) { |
470 | case OID_contentType: | ||
471 | if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set)) | ||
472 | goto repeated; | ||
473 | content_type = look_up_OID(value, vlen); | ||
474 | if (content_type != ctx->msg->data_type) { | ||
475 | pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n", | ||
476 | ctx->msg->data_type, sinfo->index, | ||
477 | content_type); | ||
478 | return -EBADMSG; | ||
479 | } | ||
480 | return 0; | ||
481 | |||
482 | case OID_signingTime: | ||
483 | if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set)) | ||
484 | goto repeated; | ||
485 | /* Should we check that the signing time is consistent | ||
486 | * with the signer's X.509 cert? | ||
487 | */ | ||
488 | return x509_decode_time(&sinfo->signing_time, | ||
489 | hdrlen, tag, value, vlen); | ||
490 | |||
317 | case OID_messageDigest: | 491 | case OID_messageDigest: |
492 | if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set)) | ||
493 | goto repeated; | ||
318 | if (tag != ASN1_OTS) | 494 | if (tag != ASN1_OTS) |
319 | return -EBADMSG; | 495 | return -EBADMSG; |
320 | ctx->sinfo->msgdigest = value; | 496 | sinfo->msgdigest = value; |
321 | ctx->sinfo->msgdigest_len = vlen; | 497 | sinfo->msgdigest_len = vlen; |
498 | return 0; | ||
499 | |||
500 | case OID_smimeCapabilites: | ||
501 | if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set)) | ||
502 | goto repeated; | ||
503 | if (ctx->msg->data_type != OID_msIndirectData) { | ||
504 | pr_warn("S/MIME Caps only allowed with Authenticode\n"); | ||
505 | return -EKEYREJECTED; | ||
506 | } | ||
507 | return 0; | ||
508 | |||
509 | /* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE | ||
510 | * char URLs and cont[1] 8-bit char URLs. | ||
511 | * | ||
512 | * Microsoft StatementType seems to contain a list of OIDs that | ||
513 | * are also used as extendedKeyUsage types in X.509 certs. | ||
514 | */ | ||
515 | case OID_msSpOpusInfo: | ||
516 | if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) | ||
517 | goto repeated; | ||
518 | goto authenticode_check; | ||
519 | case OID_msStatementType: | ||
520 | if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set)) | ||
521 | goto repeated; | ||
522 | authenticode_check: | ||
523 | if (ctx->msg->data_type != OID_msIndirectData) { | ||
524 | pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n"); | ||
525 | return -EKEYREJECTED; | ||
526 | } | ||
527 | /* I'm not sure how to validate these */ | ||
322 | return 0; | 528 | return 0; |
323 | default: | 529 | default: |
324 | return 0; | 530 | return 0; |
325 | } | 531 | } |
532 | |||
533 | repeated: | ||
534 | /* We permit max one item per AuthenticatedAttribute and no repeats */ | ||
535 | pr_warn("Repeated/multivalue AuthAttrs not permitted\n"); | ||
536 | return -EKEYREJECTED; | ||
326 | } | 537 | } |
327 | 538 | ||
328 | /* | 539 | /* |
329 | * Note the set of auth attributes for digestion purposes [RFC2315 9.3] | 540 | * Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3] |
330 | */ | 541 | */ |
331 | int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, | 542 | int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen, |
332 | unsigned char tag, | 543 | unsigned char tag, |
333 | const void *value, size_t vlen) | 544 | const void *value, size_t vlen) |
334 | { | 545 | { |
335 | struct pkcs7_parse_context *ctx = context; | 546 | struct pkcs7_parse_context *ctx = context; |
547 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | ||
548 | |||
549 | if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) || | ||
550 | !test_bit(sinfo_has_message_digest, &sinfo->aa_set) || | ||
551 | (ctx->msg->data_type == OID_msIndirectData && | ||
552 | !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))) { | ||
553 | pr_warn("Missing required AuthAttr\n"); | ||
554 | return -EBADMSG; | ||
555 | } | ||
556 | |||
557 | if (ctx->msg->data_type != OID_msIndirectData && | ||
558 | test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) { | ||
559 | pr_warn("Unexpected Authenticode AuthAttr\n"); | ||
560 | return -EBADMSG; | ||
561 | } | ||
336 | 562 | ||
337 | /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ | 563 | /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */ |
338 | ctx->sinfo->authattrs = value - (hdrlen - 1); | 564 | sinfo->authattrs = value - (hdrlen - 1); |
339 | ctx->sinfo->authattrs_len = vlen + (hdrlen - 1); | 565 | sinfo->authattrs_len = vlen + (hdrlen - 1); |
340 | return 0; | 566 | return 0; |
341 | } | 567 | } |
342 | 568 | ||
@@ -367,6 +593,22 @@ int pkcs7_sig_note_issuer(void *context, size_t hdrlen, | |||
367 | } | 593 | } |
368 | 594 | ||
369 | /* | 595 | /* |
596 | * Note the issuing cert's subjectKeyIdentifier | ||
597 | */ | ||
598 | int pkcs7_sig_note_skid(void *context, size_t hdrlen, | ||
599 | unsigned char tag, | ||
600 | const void *value, size_t vlen) | ||
601 | { | ||
602 | struct pkcs7_parse_context *ctx = context; | ||
603 | |||
604 | pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value); | ||
605 | |||
606 | ctx->raw_skid = value; | ||
607 | ctx->raw_skid_size = vlen; | ||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | /* | ||
370 | * Note the signature data | 612 | * Note the signature data |
371 | */ | 613 | */ |
372 | int pkcs7_sig_note_signature(void *context, size_t hdrlen, | 614 | int pkcs7_sig_note_signature(void *context, size_t hdrlen, |
@@ -398,14 +640,27 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen, | |||
398 | struct pkcs7_signed_info *sinfo = ctx->sinfo; | 640 | struct pkcs7_signed_info *sinfo = ctx->sinfo; |
399 | struct asymmetric_key_id *kid; | 641 | struct asymmetric_key_id *kid; |
400 | 642 | ||
643 | if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) { | ||
644 | pr_warn("Authenticode requires AuthAttrs\n"); | ||
645 | return -EBADMSG; | ||
646 | } | ||
647 | |||
401 | /* Generate cert issuer + serial number key ID */ | 648 | /* Generate cert issuer + serial number key ID */ |
402 | kid = asymmetric_key_generate_id(ctx->raw_serial, | 649 | if (!ctx->expect_skid) { |
403 | ctx->raw_serial_size, | 650 | kid = asymmetric_key_generate_id(ctx->raw_serial, |
404 | ctx->raw_issuer, | 651 | ctx->raw_serial_size, |
405 | ctx->raw_issuer_size); | 652 | ctx->raw_issuer, |
653 | ctx->raw_issuer_size); | ||
654 | } else { | ||
655 | kid = asymmetric_key_generate_id(ctx->raw_skid, | ||
656 | ctx->raw_skid_size, | ||
657 | "", 0); | ||
658 | } | ||
406 | if (IS_ERR(kid)) | 659 | if (IS_ERR(kid)) |
407 | return PTR_ERR(kid); | 660 | return PTR_ERR(kid); |
408 | 661 | ||
662 | pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data); | ||
663 | |||
409 | sinfo->signing_cert_id = kid; | 664 | sinfo->signing_cert_id = kid; |
410 | sinfo->index = ++ctx->sinfo_index; | 665 | sinfo->index = ++ctx->sinfo_index; |
411 | *ctx->ppsinfo = sinfo; | 666 | *ctx->ppsinfo = sinfo; |
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h index efc7dc9b8f9c..a66b19ebcf47 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.h +++ b/crypto/asymmetric_keys/pkcs7_parser.h | |||
@@ -21,9 +21,9 @@ | |||
21 | struct pkcs7_signed_info { | 21 | struct pkcs7_signed_info { |
22 | struct pkcs7_signed_info *next; | 22 | struct pkcs7_signed_info *next; |
23 | struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ | 23 | struct x509_certificate *signer; /* Signing certificate (in msg->certs) */ |
24 | unsigned index; | 24 | unsigned index; |
25 | bool trusted; | 25 | bool trusted; |
26 | bool unsupported_crypto; /* T if not usable due to missing crypto */ | 26 | bool unsupported_crypto; /* T if not usable due to missing crypto */ |
27 | 27 | ||
28 | /* Message digest - the digest of the Content Data (or NULL) */ | 28 | /* Message digest - the digest of the Content Data (or NULL) */ |
29 | const void *msgdigest; | 29 | const void *msgdigest; |
@@ -32,8 +32,18 @@ struct pkcs7_signed_info { | |||
32 | /* Authenticated Attribute data (or NULL) */ | 32 | /* Authenticated Attribute data (or NULL) */ |
33 | unsigned authattrs_len; | 33 | unsigned authattrs_len; |
34 | const void *authattrs; | 34 | const void *authattrs; |
35 | unsigned long aa_set; | ||
36 | #define sinfo_has_content_type 0 | ||
37 | #define sinfo_has_signing_time 1 | ||
38 | #define sinfo_has_message_digest 2 | ||
39 | #define sinfo_has_smime_caps 3 | ||
40 | #define sinfo_has_ms_opus_info 4 | ||
41 | #define sinfo_has_ms_statement_type 5 | ||
42 | time64_t signing_time; | ||
35 | 43 | ||
36 | /* Issuing cert serial number and issuer's name */ | 44 | /* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1] |
45 | * or issuing cert's SKID [CMS ver 3]. | ||
46 | */ | ||
37 | struct asymmetric_key_id *signing_cert_id; | 47 | struct asymmetric_key_id *signing_cert_id; |
38 | 48 | ||
39 | /* Message signature. | 49 | /* Message signature. |
@@ -50,6 +60,8 @@ struct pkcs7_message { | |||
50 | struct x509_certificate *certs; /* Certificate list */ | 60 | struct x509_certificate *certs; /* Certificate list */ |
51 | struct x509_certificate *crl; /* Revocation list */ | 61 | struct x509_certificate *crl; /* Revocation list */ |
52 | struct pkcs7_signed_info *signed_infos; | 62 | struct pkcs7_signed_info *signed_infos; |
63 | u8 version; /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */ | ||
64 | bool have_authattrs; /* T if have authattrs */ | ||
53 | 65 | ||
54 | /* Content Data (or NULL) */ | 66 | /* Content Data (or NULL) */ |
55 | enum OID data_type; /* Type of Data */ | 67 | enum OID data_type; /* Type of Data */ |
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index 1d29376072da..90d6d47965b0 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c | |||
@@ -54,7 +54,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
54 | /* Look to see if this certificate is present in the trusted | 54 | /* Look to see if this certificate is present in the trusted |
55 | * keys. | 55 | * keys. |
56 | */ | 56 | */ |
57 | key = x509_request_asymmetric_key(trust_keyring, x509->id, | 57 | key = x509_request_asymmetric_key(trust_keyring, |
58 | x509->id, x509->skid, | ||
58 | false); | 59 | false); |
59 | if (!IS_ERR(key)) { | 60 | if (!IS_ERR(key)) { |
60 | /* One of the X.509 certificates in the PKCS#7 message | 61 | /* One of the X.509 certificates in the PKCS#7 message |
@@ -85,8 +86,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
85 | /* No match - see if the root certificate has a signer amongst the | 86 | /* No match - see if the root certificate has a signer amongst the |
86 | * trusted keys. | 87 | * trusted keys. |
87 | */ | 88 | */ |
88 | if (last && last->authority) { | 89 | if (last && (last->akid_id || last->akid_skid)) { |
89 | key = x509_request_asymmetric_key(trust_keyring, last->authority, | 90 | key = x509_request_asymmetric_key(trust_keyring, |
91 | last->akid_id, | ||
92 | last->akid_skid, | ||
90 | false); | 93 | false); |
91 | if (!IS_ERR(key)) { | 94 | if (!IS_ERR(key)) { |
92 | x509 = last; | 95 | x509 = last; |
@@ -103,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
103 | */ | 106 | */ |
104 | key = x509_request_asymmetric_key(trust_keyring, | 107 | key = x509_request_asymmetric_key(trust_keyring, |
105 | sinfo->signing_cert_id, | 108 | sinfo->signing_cert_id, |
109 | NULL, | ||
106 | false); | 110 | false); |
107 | if (!IS_ERR(key)) { | 111 | if (!IS_ERR(key)) { |
108 | pr_devel("sinfo %u: Direct signer is key %x\n", | 112 | pr_devel("sinfo %u: Direct signer is key %x\n", |
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index cd455450b069..d20c0b4b880e 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c | |||
@@ -70,9 +70,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7, | |||
70 | * message digest attribute amongst them which corresponds to the | 70 | * message digest attribute amongst them which corresponds to the |
71 | * digest we just calculated. | 71 | * digest we just calculated. |
72 | */ | 72 | */ |
73 | if (sinfo->msgdigest) { | 73 | if (sinfo->authattrs) { |
74 | u8 tag; | 74 | u8 tag; |
75 | 75 | ||
76 | if (!sinfo->msgdigest) { | ||
77 | pr_warn("Sig %u: No messageDigest\n", sinfo->index); | ||
78 | ret = -EKEYREJECTED; | ||
79 | goto error; | ||
80 | } | ||
81 | |||
76 | if (sinfo->msgdigest_len != sinfo->sig.digest_size) { | 82 | if (sinfo->msgdigest_len != sinfo->sig.digest_size) { |
77 | pr_debug("Sig %u: Invalid digest size (%u)\n", | 83 | pr_debug("Sig %u: Invalid digest size (%u)\n", |
78 | sinfo->index, sinfo->msgdigest_len); | 84 | sinfo->index, sinfo->msgdigest_len); |
@@ -170,6 +176,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
170 | struct pkcs7_signed_info *sinfo) | 176 | struct pkcs7_signed_info *sinfo) |
171 | { | 177 | { |
172 | struct x509_certificate *x509 = sinfo->signer, *p; | 178 | struct x509_certificate *x509 = sinfo->signer, *p; |
179 | struct asymmetric_key_id *auth; | ||
173 | int ret; | 180 | int ret; |
174 | 181 | ||
175 | kenter(""); | 182 | kenter(""); |
@@ -187,11 +194,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
187 | goto maybe_missing_crypto_in_x509; | 194 | goto maybe_missing_crypto_in_x509; |
188 | 195 | ||
189 | pr_debug("- issuer %s\n", x509->issuer); | 196 | pr_debug("- issuer %s\n", x509->issuer); |
190 | if (x509->authority) | 197 | if (x509->akid_id) |
191 | pr_debug("- authkeyid %*phN\n", | 198 | pr_debug("- authkeyid.id %*phN\n", |
192 | x509->authority->len, x509->authority->data); | 199 | x509->akid_id->len, x509->akid_id->data); |
193 | 200 | if (x509->akid_skid) | |
194 | if (!x509->authority || | 201 | pr_debug("- authkeyid.skid %*phN\n", |
202 | x509->akid_skid->len, x509->akid_skid->data); | ||
203 | |||
204 | if ((!x509->akid_id && !x509->akid_skid) || | ||
195 | strcmp(x509->subject, x509->issuer) == 0) { | 205 | strcmp(x509->subject, x509->issuer) == 0) { |
196 | /* If there's no authority certificate specified, then | 206 | /* If there's no authority certificate specified, then |
197 | * the certificate must be self-signed and is the root | 207 | * the certificate must be self-signed and is the root |
@@ -215,21 +225,42 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
215 | /* Look through the X.509 certificates in the PKCS#7 message's | 225 | /* Look through the X.509 certificates in the PKCS#7 message's |
216 | * list to see if the next one is there. | 226 | * list to see if the next one is there. |
217 | */ | 227 | */ |
218 | pr_debug("- want %*phN\n", | 228 | auth = x509->akid_id; |
219 | x509->authority->len, x509->authority->data); | 229 | if (auth) { |
220 | for (p = pkcs7->certs; p; p = p->next) { | 230 | pr_debug("- want %*phN\n", auth->len, auth->data); |
221 | if (!p->skid) | 231 | for (p = pkcs7->certs; p; p = p->next) { |
222 | continue; | 232 | pr_debug("- cmp [%u] %*phN\n", |
223 | pr_debug("- cmp [%u] %*phN\n", | 233 | p->index, p->id->len, p->id->data); |
224 | p->index, p->skid->len, p->skid->data); | 234 | if (asymmetric_key_id_same(p->id, auth)) |
225 | if (asymmetric_key_id_same(p->skid, x509->authority)) | 235 | goto found_issuer_check_skid; |
226 | goto found_issuer; | 236 | } |
237 | } else { | ||
238 | auth = x509->akid_skid; | ||
239 | pr_debug("- want %*phN\n", auth->len, auth->data); | ||
240 | for (p = pkcs7->certs; p; p = p->next) { | ||
241 | if (!p->skid) | ||
242 | continue; | ||
243 | pr_debug("- cmp [%u] %*phN\n", | ||
244 | p->index, p->skid->len, p->skid->data); | ||
245 | if (asymmetric_key_id_same(p->skid, auth)) | ||
246 | goto found_issuer; | ||
247 | } | ||
227 | } | 248 | } |
228 | 249 | ||
229 | /* We didn't find the root of this chain */ | 250 | /* We didn't find the root of this chain */ |
230 | pr_debug("- top\n"); | 251 | pr_debug("- top\n"); |
231 | return 0; | 252 | return 0; |
232 | 253 | ||
254 | found_issuer_check_skid: | ||
255 | /* We matched issuer + serialNumber, but if there's an | ||
256 | * authKeyId.keyId, that must match the CA subjKeyId also. | ||
257 | */ | ||
258 | if (x509->akid_skid && | ||
259 | !asymmetric_key_id_same(p->skid, x509->akid_skid)) { | ||
260 | pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n", | ||
261 | sinfo->index, x509->index, p->index); | ||
262 | return -EKEYREJECTED; | ||
263 | } | ||
233 | found_issuer: | 264 | found_issuer: |
234 | pr_debug("- subject %s\n", p->subject); | 265 | pr_debug("- subject %s\n", p->subject); |
235 | if (p->seen) { | 266 | if (p->seen) { |
@@ -289,6 +320,18 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
289 | pr_devel("Using X.509[%u] for sig %u\n", | 320 | pr_devel("Using X.509[%u] for sig %u\n", |
290 | sinfo->signer->index, sinfo->index); | 321 | sinfo->signer->index, sinfo->index); |
291 | 322 | ||
323 | /* Check that the PKCS#7 signing time is valid according to the X.509 | ||
324 | * certificate. We can't, however, check against the system clock | ||
325 | * since that may not have been set yet and may be wrong. | ||
326 | */ | ||
327 | if (test_bit(sinfo_has_signing_time, &sinfo->aa_set)) { | ||
328 | if (sinfo->signing_time < sinfo->signer->valid_from || | ||
329 | sinfo->signing_time > sinfo->signer->valid_to) { | ||
330 | pr_warn("Message signed outside of X.509 validity window\n"); | ||
331 | return -EKEYREJECTED; | ||
332 | } | ||
333 | } | ||
334 | |||
292 | /* Verify the PKCS#7 binary against the key */ | 335 | /* Verify the PKCS#7 binary against the key */ |
293 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); | 336 | ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); |
294 | if (ret < 0) | 337 | if (ret < 0) |
@@ -303,6 +346,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
303 | /** | 346 | /** |
304 | * pkcs7_verify - Verify a PKCS#7 message | 347 | * pkcs7_verify - Verify a PKCS#7 message |
305 | * @pkcs7: The PKCS#7 message to be verified | 348 | * @pkcs7: The PKCS#7 message to be verified |
349 | * @usage: The use to which the key is being put | ||
306 | * | 350 | * |
307 | * Verify a PKCS#7 message is internally consistent - that is, the data digest | 351 | * Verify a PKCS#7 message is internally consistent - that is, the data digest |
308 | * matches the digest in the AuthAttrs and any signature in the message or one | 352 | * matches the digest in the AuthAttrs and any signature in the message or one |
@@ -314,6 +358,9 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
314 | * | 358 | * |
315 | * Returns, in order of descending priority: | 359 | * Returns, in order of descending priority: |
316 | * | 360 | * |
361 | * (*) -EKEYREJECTED if a key was selected that had a usage restriction at | ||
362 | * odds with the specified usage, or: | ||
363 | * | ||
317 | * (*) -EKEYREJECTED if a signature failed to match for which we found an | 364 | * (*) -EKEYREJECTED if a signature failed to match for which we found an |
318 | * appropriate X.509 certificate, or: | 365 | * appropriate X.509 certificate, or: |
319 | * | 366 | * |
@@ -325,7 +372,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
325 | * (*) 0 if all the signature chains that don't incur -ENOPKG can be verified | 372 | * (*) 0 if all the signature chains that don't incur -ENOPKG can be verified |
326 | * (note that a signature chain may be of zero length), or: | 373 | * (note that a signature chain may be of zero length), or: |
327 | */ | 374 | */ |
328 | int pkcs7_verify(struct pkcs7_message *pkcs7) | 375 | int pkcs7_verify(struct pkcs7_message *pkcs7, |
376 | enum key_being_used_for usage) | ||
329 | { | 377 | { |
330 | struct pkcs7_signed_info *sinfo; | 378 | struct pkcs7_signed_info *sinfo; |
331 | struct x509_certificate *x509; | 379 | struct x509_certificate *x509; |
@@ -334,12 +382,48 @@ int pkcs7_verify(struct pkcs7_message *pkcs7) | |||
334 | 382 | ||
335 | kenter(""); | 383 | kenter(""); |
336 | 384 | ||
385 | switch (usage) { | ||
386 | case VERIFYING_MODULE_SIGNATURE: | ||
387 | if (pkcs7->data_type != OID_data) { | ||
388 | pr_warn("Invalid module sig (not pkcs7-data)\n"); | ||
389 | return -EKEYREJECTED; | ||
390 | } | ||
391 | if (pkcs7->have_authattrs) { | ||
392 | pr_warn("Invalid module sig (has authattrs)\n"); | ||
393 | return -EKEYREJECTED; | ||
394 | } | ||
395 | break; | ||
396 | case VERIFYING_FIRMWARE_SIGNATURE: | ||
397 | if (pkcs7->data_type != OID_data) { | ||
398 | pr_warn("Invalid firmware sig (not pkcs7-data)\n"); | ||
399 | return -EKEYREJECTED; | ||
400 | } | ||
401 | if (!pkcs7->have_authattrs) { | ||
402 | pr_warn("Invalid firmware sig (missing authattrs)\n"); | ||
403 | return -EKEYREJECTED; | ||
404 | } | ||
405 | break; | ||
406 | case VERIFYING_KEXEC_PE_SIGNATURE: | ||
407 | if (pkcs7->data_type != OID_msIndirectData) { | ||
408 | pr_warn("Invalid kexec sig (not Authenticode)\n"); | ||
409 | return -EKEYREJECTED; | ||
410 | } | ||
411 | /* Authattr presence checked in parser */ | ||
412 | break; | ||
413 | case VERIFYING_UNSPECIFIED_SIGNATURE: | ||
414 | if (pkcs7->data_type != OID_data) { | ||
415 | pr_warn("Invalid unspecified sig (not pkcs7-data)\n"); | ||
416 | return -EKEYREJECTED; | ||
417 | } | ||
418 | break; | ||
419 | default: | ||
420 | return -EINVAL; | ||
421 | } | ||
422 | |||
337 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { | 423 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { |
338 | ret = x509_get_sig_params(x509); | 424 | ret = x509_get_sig_params(x509); |
339 | if (ret < 0) | 425 | if (ret < 0) |
340 | return ret; | 426 | return ret; |
341 | pr_debug("X.509[%u] %*phN\n", | ||
342 | n, x509->authority->len, x509->authority->data); | ||
343 | } | 427 | } |
344 | 428 | ||
345 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | 429 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { |
@@ -359,3 +443,28 @@ int pkcs7_verify(struct pkcs7_message *pkcs7) | |||
359 | return enopkg; | 443 | return enopkg; |
360 | } | 444 | } |
361 | EXPORT_SYMBOL_GPL(pkcs7_verify); | 445 | EXPORT_SYMBOL_GPL(pkcs7_verify); |
446 | |||
447 | /** | ||
448 | * pkcs7_supply_detached_data - Supply the data needed to verify a PKCS#7 message | ||
449 | * @pkcs7: The PKCS#7 message | ||
450 | * @data: The data to be verified | ||
451 | * @datalen: The amount of data | ||
452 | * | ||
453 | * Supply the detached data needed to verify a PKCS#7 message. Note that no | ||
454 | * attempt to retain/pin the data is made. That is left to the caller. The | ||
455 | * data will not be modified by pkcs7_verify() and will not be freed when the | ||
456 | * PKCS#7 message is freed. | ||
457 | * | ||
458 | * Returns -EINVAL if data is already supplied in the message, 0 otherwise. | ||
459 | */ | ||
460 | int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7, | ||
461 | const void *data, size_t datalen) | ||
462 | { | ||
463 | if (pkcs7->data) { | ||
464 | pr_debug("Data already supplied\n"); | ||
465 | return -EINVAL; | ||
466 | } | ||
467 | pkcs7->data = data; | ||
468 | pkcs7->data_len = datalen; | ||
469 | return 0; | ||
470 | } | ||
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 2f6e4fb1a1ea..81efccbe22d5 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c | |||
@@ -39,6 +39,7 @@ EXPORT_SYMBOL_GPL(pkey_algo); | |||
39 | const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { | 39 | const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { |
40 | [PKEY_ID_PGP] = "PGP", | 40 | [PKEY_ID_PGP] = "PGP", |
41 | [PKEY_ID_X509] = "X509", | 41 | [PKEY_ID_X509] = "X509", |
42 | [PKEY_ID_PKCS7] = "PKCS#7", | ||
42 | }; | 43 | }; |
43 | EXPORT_SYMBOL_GPL(pkey_id_type_name); | 44 | EXPORT_SYMBOL_GPL(pkey_id_type_name); |
44 | 45 | ||
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c index 2421f46184ce..897b734dabf9 100644 --- a/crypto/asymmetric_keys/verify_pefile.c +++ b/crypto/asymmetric_keys/verify_pefile.c | |||
@@ -393,6 +393,7 @@ error_no_desc: | |||
393 | * @pebuf: Buffer containing the PE binary image | 393 | * @pebuf: Buffer containing the PE binary image |
394 | * @pelen: Length of the binary image | 394 | * @pelen: Length of the binary image |
395 | * @trust_keyring: Signing certificates to use as starting points | 395 | * @trust_keyring: Signing certificates to use as starting points |
396 | * @usage: The use to which the key is being put. | ||
396 | * @_trusted: Set to true if trustworth, false otherwise | 397 | * @_trusted: Set to true if trustworth, false otherwise |
397 | * | 398 | * |
398 | * Validate that the certificate chain inside the PKCS#7 message inside the PE | 399 | * Validate that the certificate chain inside the PKCS#7 message inside the PE |
@@ -417,7 +418,9 @@ error_no_desc: | |||
417 | * May also return -ENOMEM. | 418 | * May also return -ENOMEM. |
418 | */ | 419 | */ |
419 | int verify_pefile_signature(const void *pebuf, unsigned pelen, | 420 | int verify_pefile_signature(const void *pebuf, unsigned pelen, |
420 | struct key *trusted_keyring, bool *_trusted) | 421 | struct key *trusted_keyring, |
422 | enum key_being_used_for usage, | ||
423 | bool *_trusted) | ||
421 | { | 424 | { |
422 | struct pkcs7_message *pkcs7; | 425 | struct pkcs7_message *pkcs7; |
423 | struct pefile_context ctx; | 426 | struct pefile_context ctx; |
@@ -462,7 +465,7 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen, | |||
462 | if (ret < 0) | 465 | if (ret < 0) |
463 | goto error; | 466 | goto error; |
464 | 467 | ||
465 | ret = pkcs7_verify(pkcs7); | 468 | ret = pkcs7_verify(pkcs7, usage); |
466 | if (ret < 0) | 469 | if (ret < 0) |
467 | goto error; | 470 | goto error; |
468 | 471 | ||
diff --git a/crypto/asymmetric_keys/x509_akid.asn1 b/crypto/asymmetric_keys/x509_akid.asn1 new file mode 100644 index 000000000000..1a33231a75a8 --- /dev/null +++ b/crypto/asymmetric_keys/x509_akid.asn1 | |||
@@ -0,0 +1,35 @@ | |||
1 | -- X.509 AuthorityKeyIdentifier | ||
2 | -- rfc5280 section 4.2.1.1 | ||
3 | |||
4 | AuthorityKeyIdentifier ::= SEQUENCE { | ||
5 | keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL, | ||
6 | authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL, | ||
7 | authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL | ||
8 | } | ||
9 | |||
10 | KeyIdentifier ::= OCTET STRING ({ x509_akid_note_kid }) | ||
11 | |||
12 | CertificateSerialNumber ::= INTEGER ({ x509_akid_note_serial }) | ||
13 | |||
14 | GeneralNames ::= SEQUENCE OF GeneralName | ||
15 | |||
16 | GeneralName ::= CHOICE { | ||
17 | otherName [0] ANY, | ||
18 | rfc822Name [1] IA5String, | ||
19 | dNSName [2] IA5String, | ||
20 | x400Address [3] ANY, | ||
21 | directoryName [4] Name ({ x509_akid_note_name }), | ||
22 | ediPartyName [5] ANY, | ||
23 | uniformResourceIdentifier [6] IA5String, | ||
24 | iPAddress [7] OCTET STRING, | ||
25 | registeredID [8] OBJECT IDENTIFIER | ||
26 | } | ||
27 | |||
28 | Name ::= SEQUENCE OF RelativeDistinguishedName | ||
29 | |||
30 | RelativeDistinguishedName ::= SET OF AttributeValueAssertion | ||
31 | |||
32 | AttributeValueAssertion ::= SEQUENCE { | ||
33 | attributeType OBJECT IDENTIFIER ({ x509_note_OID }), | ||
34 | attributeValue ANY ({ x509_extract_name_segment }) | ||
35 | } | ||
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index a668d90302d3..af71878dc15b 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "public_key.h" | 18 | #include "public_key.h" |
19 | #include "x509_parser.h" | 19 | #include "x509_parser.h" |
20 | #include "x509-asn1.h" | 20 | #include "x509-asn1.h" |
21 | #include "x509_akid-asn1.h" | ||
21 | #include "x509_rsakey-asn1.h" | 22 | #include "x509_rsakey-asn1.h" |
22 | 23 | ||
23 | struct x509_parse_context { | 24 | struct x509_parse_context { |
@@ -35,6 +36,10 @@ struct x509_parse_context { | |||
35 | u16 o_offset; /* Offset of organizationName (O) */ | 36 | u16 o_offset; /* Offset of organizationName (O) */ |
36 | u16 cn_offset; /* Offset of commonName (CN) */ | 37 | u16 cn_offset; /* Offset of commonName (CN) */ |
37 | u16 email_offset; /* Offset of emailAddress */ | 38 | u16 email_offset; /* Offset of emailAddress */ |
39 | unsigned raw_akid_size; | ||
40 | const void *raw_akid; /* Raw authorityKeyId in ASN.1 */ | ||
41 | const void *akid_raw_issuer; /* Raw directoryName in authorityKeyId */ | ||
42 | unsigned akid_raw_issuer_size; | ||
38 | }; | 43 | }; |
39 | 44 | ||
40 | /* | 45 | /* |
@@ -48,7 +53,8 @@ void x509_free_certificate(struct x509_certificate *cert) | |||
48 | kfree(cert->subject); | 53 | kfree(cert->subject); |
49 | kfree(cert->id); | 54 | kfree(cert->id); |
50 | kfree(cert->skid); | 55 | kfree(cert->skid); |
51 | kfree(cert->authority); | 56 | kfree(cert->akid_id); |
57 | kfree(cert->akid_skid); | ||
52 | kfree(cert->sig.digest); | 58 | kfree(cert->sig.digest); |
53 | mpi_free(cert->sig.rsa.s); | 59 | mpi_free(cert->sig.rsa.s); |
54 | kfree(cert); | 60 | kfree(cert); |
@@ -85,6 +91,18 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
85 | if (ret < 0) | 91 | if (ret < 0) |
86 | goto error_decode; | 92 | goto error_decode; |
87 | 93 | ||
94 | /* Decode the AuthorityKeyIdentifier */ | ||
95 | if (ctx->raw_akid) { | ||
96 | pr_devel("AKID: %u %*phN\n", | ||
97 | ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid); | ||
98 | ret = asn1_ber_decoder(&x509_akid_decoder, ctx, | ||
99 | ctx->raw_akid, ctx->raw_akid_size); | ||
100 | if (ret < 0) { | ||
101 | pr_warn("Couldn't decode AuthKeyIdentifier\n"); | ||
102 | goto error_decode; | ||
103 | } | ||
104 | } | ||
105 | |||
88 | /* Decode the public key */ | 106 | /* Decode the public key */ |
89 | ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, | 107 | ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, |
90 | ctx->key, ctx->key_size); | 108 | ctx->key, ctx->key_size); |
@@ -422,7 +440,6 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
422 | struct x509_parse_context *ctx = context; | 440 | struct x509_parse_context *ctx = context; |
423 | struct asymmetric_key_id *kid; | 441 | struct asymmetric_key_id *kid; |
424 | const unsigned char *v = value; | 442 | const unsigned char *v = value; |
425 | int i; | ||
426 | 443 | ||
427 | pr_debug("Extension: %u\n", ctx->last_oid); | 444 | pr_debug("Extension: %u\n", ctx->last_oid); |
428 | 445 | ||
@@ -437,9 +454,7 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
437 | 454 | ||
438 | ctx->cert->raw_skid_size = vlen; | 455 | ctx->cert->raw_skid_size = vlen; |
439 | ctx->cert->raw_skid = v; | 456 | ctx->cert->raw_skid = v; |
440 | kid = asymmetric_key_generate_id(ctx->cert->raw_subject, | 457 | kid = asymmetric_key_generate_id(v, vlen, "", 0); |
441 | ctx->cert->raw_subject_size, | ||
442 | v, vlen); | ||
443 | if (IS_ERR(kid)) | 458 | if (IS_ERR(kid)) |
444 | return PTR_ERR(kid); | 459 | return PTR_ERR(kid); |
445 | ctx->cert->skid = kid; | 460 | ctx->cert->skid = kid; |
@@ -449,117 +464,113 @@ int x509_process_extension(void *context, size_t hdrlen, | |||
449 | 464 | ||
450 | if (ctx->last_oid == OID_authorityKeyIdentifier) { | 465 | if (ctx->last_oid == OID_authorityKeyIdentifier) { |
451 | /* Get hold of the CA key fingerprint */ | 466 | /* Get hold of the CA key fingerprint */ |
452 | if (ctx->cert->authority || vlen < 5) | 467 | ctx->raw_akid = v; |
453 | return -EBADMSG; | 468 | ctx->raw_akid_size = vlen; |
454 | |||
455 | /* Authority Key Identifier must be a Constructed SEQUENCE */ | ||
456 | if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5))) | ||
457 | return -EBADMSG; | ||
458 | |||
459 | /* Authority Key Identifier is not indefinite length */ | ||
460 | if (unlikely(vlen == ASN1_INDEFINITE_LENGTH)) | ||
461 | return -EBADMSG; | ||
462 | |||
463 | if (vlen < ASN1_INDEFINITE_LENGTH) { | ||
464 | /* Short Form length */ | ||
465 | if (v[1] != vlen - 2 || | ||
466 | v[2] != SEQ_TAG_KEYID || | ||
467 | v[3] > vlen - 4) | ||
468 | return -EBADMSG; | ||
469 | |||
470 | vlen = v[3]; | ||
471 | v += 4; | ||
472 | } else { | ||
473 | /* Long Form length */ | ||
474 | size_t seq_len = 0; | ||
475 | size_t sub = v[1] - ASN1_INDEFINITE_LENGTH; | ||
476 | |||
477 | if (sub > 2) | ||
478 | return -EBADMSG; | ||
479 | |||
480 | /* calculate the length from subsequent octets */ | ||
481 | v += 2; | ||
482 | for (i = 0; i < sub; i++) { | ||
483 | seq_len <<= 8; | ||
484 | seq_len |= v[i]; | ||
485 | } | ||
486 | |||
487 | if (seq_len != vlen - 2 - sub || | ||
488 | v[sub] != SEQ_TAG_KEYID || | ||
489 | v[sub + 1] > vlen - 4 - sub) | ||
490 | return -EBADMSG; | ||
491 | |||
492 | vlen = v[sub + 1]; | ||
493 | v += (sub + 2); | ||
494 | } | ||
495 | |||
496 | kid = asymmetric_key_generate_id(ctx->cert->raw_issuer, | ||
497 | ctx->cert->raw_issuer_size, | ||
498 | v, vlen); | ||
499 | if (IS_ERR(kid)) | ||
500 | return PTR_ERR(kid); | ||
501 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
502 | ctx->cert->authority = kid; | ||
503 | return 0; | 469 | return 0; |
504 | } | 470 | } |
505 | 471 | ||
506 | return 0; | 472 | return 0; |
507 | } | 473 | } |
508 | 474 | ||
509 | /* | 475 | /** |
510 | * Record a certificate time. | 476 | * x509_decode_time - Decode an X.509 time ASN.1 object |
477 | * @_t: The time to fill in | ||
478 | * @hdrlen: The length of the object header | ||
479 | * @tag: The object tag | ||
480 | * @value: The object value | ||
481 | * @vlen: The size of the object value | ||
482 | * | ||
483 | * Decode an ASN.1 universal time or generalised time field into a struct the | ||
484 | * kernel can handle and check it for validity. The time is decoded thus: | ||
485 | * | ||
486 | * [RFC5280 §4.1.2.5] | ||
487 | * CAs conforming to this profile MUST always encode certificate validity | ||
488 | * dates through the year 2049 as UTCTime; certificate validity dates in | ||
489 | * 2050 or later MUST be encoded as GeneralizedTime. Conforming | ||
490 | * applications MUST be able to process validity dates that are encoded in | ||
491 | * either UTCTime or GeneralizedTime. | ||
511 | */ | 492 | */ |
512 | static int x509_note_time(struct tm *tm, size_t hdrlen, | 493 | int x509_decode_time(time64_t *_t, size_t hdrlen, |
513 | unsigned char tag, | 494 | unsigned char tag, |
514 | const unsigned char *value, size_t vlen) | 495 | const unsigned char *value, size_t vlen) |
515 | { | 496 | { |
497 | static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30, | ||
498 | 31, 31, 30, 31, 30, 31 }; | ||
516 | const unsigned char *p = value; | 499 | const unsigned char *p = value; |
500 | unsigned year, mon, day, hour, min, sec, mon_len; | ||
517 | 501 | ||
518 | #define dec2bin(X) ((X) - '0') | 502 | #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; }) |
519 | #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) | 503 | #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) |
520 | 504 | ||
521 | if (tag == ASN1_UNITIM) { | 505 | if (tag == ASN1_UNITIM) { |
522 | /* UTCTime: YYMMDDHHMMSSZ */ | 506 | /* UTCTime: YYMMDDHHMMSSZ */ |
523 | if (vlen != 13) | 507 | if (vlen != 13) |
524 | goto unsupported_time; | 508 | goto unsupported_time; |
525 | tm->tm_year = DD2bin(p); | 509 | year = DD2bin(p); |
526 | if (tm->tm_year >= 50) | 510 | if (year >= 50) |
527 | tm->tm_year += 1900; | 511 | year += 1900; |
528 | else | 512 | else |
529 | tm->tm_year += 2000; | 513 | year += 2000; |
530 | } else if (tag == ASN1_GENTIM) { | 514 | } else if (tag == ASN1_GENTIM) { |
531 | /* GenTime: YYYYMMDDHHMMSSZ */ | 515 | /* GenTime: YYYYMMDDHHMMSSZ */ |
532 | if (vlen != 15) | 516 | if (vlen != 15) |
533 | goto unsupported_time; | 517 | goto unsupported_time; |
534 | tm->tm_year = DD2bin(p) * 100 + DD2bin(p); | 518 | year = DD2bin(p) * 100 + DD2bin(p); |
519 | if (year >= 1950 && year <= 2049) | ||
520 | goto invalid_time; | ||
535 | } else { | 521 | } else { |
536 | goto unsupported_time; | 522 | goto unsupported_time; |
537 | } | 523 | } |
538 | 524 | ||
539 | tm->tm_year -= 1900; | 525 | mon = DD2bin(p); |
540 | tm->tm_mon = DD2bin(p) - 1; | 526 | day = DD2bin(p); |
541 | tm->tm_mday = DD2bin(p); | 527 | hour = DD2bin(p); |
542 | tm->tm_hour = DD2bin(p); | 528 | min = DD2bin(p); |
543 | tm->tm_min = DD2bin(p); | 529 | sec = DD2bin(p); |
544 | tm->tm_sec = DD2bin(p); | ||
545 | 530 | ||
546 | if (*p != 'Z') | 531 | if (*p != 'Z') |
547 | goto unsupported_time; | 532 | goto unsupported_time; |
548 | 533 | ||
534 | mon_len = month_lengths[mon]; | ||
535 | if (mon == 2) { | ||
536 | if (year % 4 == 0) { | ||
537 | mon_len = 29; | ||
538 | if (year % 100 == 0) { | ||
539 | year /= 100; | ||
540 | if (year % 4 != 0) | ||
541 | mon_len = 28; | ||
542 | } | ||
543 | } | ||
544 | } | ||
545 | |||
546 | if (year < 1970 || | ||
547 | mon < 1 || mon > 12 || | ||
548 | day < 1 || day > mon_len || | ||
549 | hour < 0 || hour > 23 || | ||
550 | min < 0 || min > 59 || | ||
551 | sec < 0 || sec > 59) | ||
552 | goto invalid_time; | ||
553 | |||
554 | *_t = mktime64(year, mon, day, hour, min, sec); | ||
549 | return 0; | 555 | return 0; |
550 | 556 | ||
551 | unsupported_time: | 557 | unsupported_time: |
552 | pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n", | 558 | pr_debug("Got unsupported time [tag %02x]: '%*phN'\n", |
553 | tag, (int)vlen, (int)vlen, value); | 559 | tag, (int)vlen, value); |
560 | return -EBADMSG; | ||
561 | invalid_time: | ||
562 | pr_debug("Got invalid time [tag %02x]: '%*phN'\n", | ||
563 | tag, (int)vlen, value); | ||
554 | return -EBADMSG; | 564 | return -EBADMSG; |
555 | } | 565 | } |
566 | EXPORT_SYMBOL_GPL(x509_decode_time); | ||
556 | 567 | ||
557 | int x509_note_not_before(void *context, size_t hdrlen, | 568 | int x509_note_not_before(void *context, size_t hdrlen, |
558 | unsigned char tag, | 569 | unsigned char tag, |
559 | const void *value, size_t vlen) | 570 | const void *value, size_t vlen) |
560 | { | 571 | { |
561 | struct x509_parse_context *ctx = context; | 572 | struct x509_parse_context *ctx = context; |
562 | return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); | 573 | return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); |
563 | } | 574 | } |
564 | 575 | ||
565 | int x509_note_not_after(void *context, size_t hdrlen, | 576 | int x509_note_not_after(void *context, size_t hdrlen, |
@@ -567,5 +578,71 @@ int x509_note_not_after(void *context, size_t hdrlen, | |||
567 | const void *value, size_t vlen) | 578 | const void *value, size_t vlen) |
568 | { | 579 | { |
569 | struct x509_parse_context *ctx = context; | 580 | struct x509_parse_context *ctx = context; |
570 | return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); | 581 | return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); |
582 | } | ||
583 | |||
584 | /* | ||
585 | * Note a key identifier-based AuthorityKeyIdentifier | ||
586 | */ | ||
587 | int x509_akid_note_kid(void *context, size_t hdrlen, | ||
588 | unsigned char tag, | ||
589 | const void *value, size_t vlen) | ||
590 | { | ||
591 | struct x509_parse_context *ctx = context; | ||
592 | struct asymmetric_key_id *kid; | ||
593 | |||
594 | pr_debug("AKID: keyid: %*phN\n", (int)vlen, value); | ||
595 | |||
596 | if (ctx->cert->akid_skid) | ||
597 | return 0; | ||
598 | |||
599 | kid = asymmetric_key_generate_id(value, vlen, "", 0); | ||
600 | if (IS_ERR(kid)) | ||
601 | return PTR_ERR(kid); | ||
602 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
603 | ctx->cert->akid_skid = kid; | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | /* | ||
608 | * Note a directoryName in an AuthorityKeyIdentifier | ||
609 | */ | ||
610 | int x509_akid_note_name(void *context, size_t hdrlen, | ||
611 | unsigned char tag, | ||
612 | const void *value, size_t vlen) | ||
613 | { | ||
614 | struct x509_parse_context *ctx = context; | ||
615 | |||
616 | pr_debug("AKID: name: %*phN\n", (int)vlen, value); | ||
617 | |||
618 | ctx->akid_raw_issuer = value; | ||
619 | ctx->akid_raw_issuer_size = vlen; | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | /* | ||
624 | * Note a serial number in an AuthorityKeyIdentifier | ||
625 | */ | ||
626 | int x509_akid_note_serial(void *context, size_t hdrlen, | ||
627 | unsigned char tag, | ||
628 | const void *value, size_t vlen) | ||
629 | { | ||
630 | struct x509_parse_context *ctx = context; | ||
631 | struct asymmetric_key_id *kid; | ||
632 | |||
633 | pr_debug("AKID: serial: %*phN\n", (int)vlen, value); | ||
634 | |||
635 | if (!ctx->akid_raw_issuer || ctx->cert->akid_id) | ||
636 | return 0; | ||
637 | |||
638 | kid = asymmetric_key_generate_id(value, | ||
639 | vlen, | ||
640 | ctx->akid_raw_issuer, | ||
641 | ctx->akid_raw_issuer_size); | ||
642 | if (IS_ERR(kid)) | ||
643 | return PTR_ERR(kid); | ||
644 | |||
645 | pr_debug("authkeyid %*phN\n", kid->len, kid->data); | ||
646 | ctx->cert->akid_id = kid; | ||
647 | return 0; | ||
571 | } | 648 | } |
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index 3dfe6b5d6f0b..1de01eaec884 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h | |||
@@ -19,11 +19,12 @@ struct x509_certificate { | |||
19 | struct public_key_signature sig; /* Signature parameters */ | 19 | struct public_key_signature sig; /* Signature parameters */ |
20 | char *issuer; /* Name of certificate issuer */ | 20 | char *issuer; /* Name of certificate issuer */ |
21 | char *subject; /* Name of certificate subject */ | 21 | char *subject; /* Name of certificate subject */ |
22 | struct asymmetric_key_id *id; /* Serial number + issuer */ | 22 | struct asymmetric_key_id *id; /* Issuer + Serial number */ |
23 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ | 23 | struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ |
24 | struct asymmetric_key_id *authority; /* Authority key identifier (optional) */ | 24 | struct asymmetric_key_id *akid_id; /* CA AuthKeyId matching ->id (optional) */ |
25 | struct tm valid_from; | 25 | struct asymmetric_key_id *akid_skid; /* CA AuthKeyId matching ->skid (optional) */ |
26 | struct tm valid_to; | 26 | time64_t valid_from; |
27 | time64_t valid_to; | ||
27 | const void *tbs; /* Signed data */ | 28 | const void *tbs; /* Signed data */ |
28 | unsigned tbs_size; /* Size of signed data */ | 29 | unsigned tbs_size; /* Size of signed data */ |
29 | unsigned raw_sig_size; /* Size of sigature */ | 30 | unsigned raw_sig_size; /* Size of sigature */ |
@@ -48,6 +49,9 @@ struct x509_certificate { | |||
48 | */ | 49 | */ |
49 | extern void x509_free_certificate(struct x509_certificate *cert); | 50 | extern void x509_free_certificate(struct x509_certificate *cert); |
50 | extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); | 51 | extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); |
52 | extern int x509_decode_time(time64_t *_t, size_t hdrlen, | ||
53 | unsigned char tag, | ||
54 | const unsigned char *value, size_t vlen); | ||
51 | 55 | ||
52 | /* | 56 | /* |
53 | * x509_public_key.c | 57 | * x509_public_key.c |
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 24f17e6c5904..6d88dd15c98d 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
@@ -65,23 +65,37 @@ __setup("ca_keys=", ca_keys_setup); | |||
65 | /** | 65 | /** |
66 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. | 66 | * x509_request_asymmetric_key - Request a key by X.509 certificate params. |
67 | * @keyring: The keys to search. | 67 | * @keyring: The keys to search. |
68 | * @kid: The key ID. | 68 | * @id: The issuer & serialNumber to look for or NULL. |
69 | * @skid: The subjectKeyIdentifier to look for or NULL. | ||
69 | * @partial: Use partial match if true, exact if false. | 70 | * @partial: Use partial match if true, exact if false. |
70 | * | 71 | * |
71 | * Find a key in the given keyring by subject name and key ID. These might, | 72 | * Find a key in the given keyring by identifier. The preferred identifier is |
72 | * for instance, be the issuer name and the authority key ID of an X.509 | 73 | * the issuer + serialNumber and the fallback identifier is the |
73 | * certificate that needs to be verified. | 74 | * subjectKeyIdentifier. If both are given, the lookup is by the former, but |
75 | * the latter must also match. | ||
74 | */ | 76 | */ |
75 | struct key *x509_request_asymmetric_key(struct key *keyring, | 77 | struct key *x509_request_asymmetric_key(struct key *keyring, |
76 | const struct asymmetric_key_id *kid, | 78 | const struct asymmetric_key_id *id, |
79 | const struct asymmetric_key_id *skid, | ||
77 | bool partial) | 80 | bool partial) |
78 | { | 81 | { |
79 | key_ref_t key; | 82 | struct key *key; |
80 | char *id, *p; | 83 | key_ref_t ref; |
81 | 84 | const char *lookup; | |
85 | char *req, *p; | ||
86 | int len; | ||
87 | |||
88 | if (id) { | ||
89 | lookup = id->data; | ||
90 | len = id->len; | ||
91 | } else { | ||
92 | lookup = skid->data; | ||
93 | len = skid->len; | ||
94 | } | ||
95 | |||
82 | /* Construct an identifier "id:<keyid>". */ | 96 | /* Construct an identifier "id:<keyid>". */ |
83 | p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL); | 97 | p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); |
84 | if (!id) | 98 | if (!req) |
85 | return ERR_PTR(-ENOMEM); | 99 | return ERR_PTR(-ENOMEM); |
86 | 100 | ||
87 | if (partial) { | 101 | if (partial) { |
@@ -92,32 +106,48 @@ struct key *x509_request_asymmetric_key(struct key *keyring, | |||
92 | *p++ = 'x'; | 106 | *p++ = 'x'; |
93 | } | 107 | } |
94 | *p++ = ':'; | 108 | *p++ = ':'; |
95 | p = bin2hex(p, kid->data, kid->len); | 109 | p = bin2hex(p, lookup, len); |
96 | *p = 0; | 110 | *p = 0; |
97 | 111 | ||
98 | pr_debug("Look up: \"%s\"\n", id); | 112 | pr_debug("Look up: \"%s\"\n", req); |
99 | 113 | ||
100 | key = keyring_search(make_key_ref(keyring, 1), | 114 | ref = keyring_search(make_key_ref(keyring, 1), |
101 | &key_type_asymmetric, id); | 115 | &key_type_asymmetric, req); |
102 | if (IS_ERR(key)) | 116 | if (IS_ERR(ref)) |
103 | pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key)); | 117 | pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); |
104 | kfree(id); | 118 | kfree(req); |
105 | 119 | ||
106 | if (IS_ERR(key)) { | 120 | if (IS_ERR(ref)) { |
107 | switch (PTR_ERR(key)) { | 121 | switch (PTR_ERR(ref)) { |
108 | /* Hide some search errors */ | 122 | /* Hide some search errors */ |
109 | case -EACCES: | 123 | case -EACCES: |
110 | case -ENOTDIR: | 124 | case -ENOTDIR: |
111 | case -EAGAIN: | 125 | case -EAGAIN: |
112 | return ERR_PTR(-ENOKEY); | 126 | return ERR_PTR(-ENOKEY); |
113 | default: | 127 | default: |
114 | return ERR_CAST(key); | 128 | return ERR_CAST(ref); |
129 | } | ||
130 | } | ||
131 | |||
132 | key = key_ref_to_ptr(ref); | ||
133 | if (id && skid) { | ||
134 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); | ||
135 | if (!kids->id[1]) { | ||
136 | pr_debug("issuer+serial match, but expected SKID missing\n"); | ||
137 | goto reject; | ||
138 | } | ||
139 | if (!asymmetric_key_id_same(skid, kids->id[1])) { | ||
140 | pr_debug("issuer+serial match, but SKID does not\n"); | ||
141 | goto reject; | ||
115 | } | 142 | } |
116 | } | 143 | } |
144 | |||
145 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); | ||
146 | return key; | ||
117 | 147 | ||
118 | pr_devel("<==%s() = 0 [%x]\n", __func__, | 148 | reject: |
119 | key_serial(key_ref_to_ptr(key))); | 149 | key_put(key); |
120 | return key_ref_to_ptr(key); | 150 | return ERR_PTR(-EKEYREJECTED); |
121 | } | 151 | } |
122 | EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); | 152 | EXPORT_SYMBOL_GPL(x509_request_asymmetric_key); |
123 | 153 | ||
@@ -227,10 +257,11 @@ static int x509_validate_trust(struct x509_certificate *cert, | |||
227 | if (!trust_keyring) | 257 | if (!trust_keyring) |
228 | return -EOPNOTSUPP; | 258 | return -EOPNOTSUPP; |
229 | 259 | ||
230 | if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid)) | 260 | if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid)) |
231 | return -EPERM; | 261 | return -EPERM; |
232 | 262 | ||
233 | key = x509_request_asymmetric_key(trust_keyring, cert->authority, | 263 | key = x509_request_asymmetric_key(trust_keyring, |
264 | cert->akid_id, cert->akid_skid, | ||
234 | false); | 265 | false); |
235 | if (!IS_ERR(key)) { | 266 | if (!IS_ERR(key)) { |
236 | if (!use_builtin_keys | 267 | if (!use_builtin_keys |
@@ -271,14 +302,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
271 | } | 302 | } |
272 | 303 | ||
273 | pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); | 304 | pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); |
274 | pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", | 305 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); |
275 | cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, | ||
276 | cert->valid_from.tm_mday, cert->valid_from.tm_hour, | ||
277 | cert->valid_from.tm_min, cert->valid_from.tm_sec); | ||
278 | pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", | ||
279 | cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, | ||
280 | cert->valid_to.tm_mday, cert->valid_to.tm_hour, | ||
281 | cert->valid_to.tm_min, cert->valid_to.tm_sec); | ||
282 | pr_devel("Cert Signature: %s + %s\n", | 306 | pr_devel("Cert Signature: %s + %s\n", |
283 | pkey_algo_name[cert->sig.pkey_algo], | 307 | pkey_algo_name[cert->sig.pkey_algo], |
284 | hash_algo_name[cert->sig.pkey_hash_algo]); | 308 | hash_algo_name[cert->sig.pkey_hash_algo]); |
@@ -287,8 +311,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
287 | cert->pub->id_type = PKEY_ID_X509; | 311 | cert->pub->id_type = PKEY_ID_X509; |
288 | 312 | ||
289 | /* Check the signature on the key if it appears to be self-signed */ | 313 | /* Check the signature on the key if it appears to be self-signed */ |
290 | if (!cert->authority || | 314 | if ((!cert->akid_skid && !cert->akid_id) || |
291 | asymmetric_key_id_same(cert->skid, cert->authority)) { | 315 | asymmetric_key_id_same(cert->skid, cert->akid_skid) || |
316 | asymmetric_key_id_same(cert->id, cert->akid_id)) { | ||
292 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ | 317 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ |
293 | if (ret < 0) | 318 | if (ret < 0) |
294 | goto error_free_cert; | 319 | goto error_free_cert; |
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h index 691c79172a26..441aff9b5aa7 100644 --- a/include/crypto/pkcs7.h +++ b/include/crypto/pkcs7.h | |||
@@ -9,6 +9,11 @@ | |||
9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #ifndef _CRYPTO_PKCS7_H | ||
13 | #define _CRYPTO_PKCS7_H | ||
14 | |||
15 | #include <crypto/public_key.h> | ||
16 | |||
12 | struct key; | 17 | struct key; |
13 | struct pkcs7_message; | 18 | struct pkcs7_message; |
14 | 19 | ||
@@ -33,4 +38,10 @@ extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7, | |||
33 | /* | 38 | /* |
34 | * pkcs7_verify.c | 39 | * pkcs7_verify.c |
35 | */ | 40 | */ |
36 | extern int pkcs7_verify(struct pkcs7_message *pkcs7); | 41 | extern int pkcs7_verify(struct pkcs7_message *pkcs7, |
42 | enum key_being_used_for usage); | ||
43 | |||
44 | extern int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7, | ||
45 | const void *data, size_t datalen); | ||
46 | |||
47 | #endif /* _CRYPTO_PKCS7_H */ | ||
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index 54add2069901..067c242b1e15 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h | |||
@@ -33,12 +33,27 @@ extern const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST]; | |||
33 | enum pkey_id_type { | 33 | enum pkey_id_type { |
34 | PKEY_ID_PGP, /* OpenPGP generated key ID */ | 34 | PKEY_ID_PGP, /* OpenPGP generated key ID */ |
35 | PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ | 35 | PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ |
36 | PKEY_ID_PKCS7, /* Signature in PKCS#7 message */ | ||
36 | PKEY_ID_TYPE__LAST | 37 | PKEY_ID_TYPE__LAST |
37 | }; | 38 | }; |
38 | 39 | ||
39 | extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST]; | 40 | extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST]; |
40 | 41 | ||
41 | /* | 42 | /* |
43 | * The use to which an asymmetric key is being put. | ||
44 | */ | ||
45 | enum key_being_used_for { | ||
46 | VERIFYING_MODULE_SIGNATURE, | ||
47 | VERIFYING_FIRMWARE_SIGNATURE, | ||
48 | VERIFYING_KEXEC_PE_SIGNATURE, | ||
49 | VERIFYING_KEY_SIGNATURE, | ||
50 | VERIFYING_KEY_SELF_SIGNATURE, | ||
51 | VERIFYING_UNSPECIFIED_SIGNATURE, | ||
52 | NR__KEY_BEING_USED_FOR | ||
53 | }; | ||
54 | extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; | ||
55 | |||
56 | /* | ||
42 | * Cryptographic data for the public-key subtype of the asymmetric key type. | 57 | * Cryptographic data for the public-key subtype of the asymmetric key type. |
43 | * | 58 | * |
44 | * Note that this may include private part of the key as well as the public | 59 | * Note that this may include private part of the key as well as the public |
@@ -101,7 +116,8 @@ extern int verify_signature(const struct key *key, | |||
101 | 116 | ||
102 | struct asymmetric_key_id; | 117 | struct asymmetric_key_id; |
103 | extern struct key *x509_request_asymmetric_key(struct key *keyring, | 118 | extern struct key *x509_request_asymmetric_key(struct key *keyring, |
104 | const struct asymmetric_key_id *kid, | 119 | const struct asymmetric_key_id *id, |
120 | const struct asymmetric_key_id *skid, | ||
105 | bool partial); | 121 | bool partial); |
106 | 122 | ||
107 | #endif /* _LINUX_PUBLIC_KEY_H */ | 123 | #endif /* _LINUX_PUBLIC_KEY_H */ |
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h index 72665eb80692..b20cd885c1fd 100644 --- a/include/keys/system_keyring.h +++ b/include/keys/system_keyring.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING | 15 | #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING |
16 | 16 | ||
17 | #include <linux/key.h> | 17 | #include <linux/key.h> |
18 | #include <crypto/public_key.h> | ||
18 | 19 | ||
19 | extern struct key *system_trusted_keyring; | 20 | extern struct key *system_trusted_keyring; |
20 | static inline struct key *get_system_trusted_keyring(void) | 21 | static inline struct key *get_system_trusted_keyring(void) |
@@ -28,4 +29,10 @@ static inline struct key *get_system_trusted_keyring(void) | |||
28 | } | 29 | } |
29 | #endif | 30 | #endif |
30 | 31 | ||
32 | #ifdef CONFIG_SYSTEM_DATA_VERIFICATION | ||
33 | extern int system_verify_data(const void *data, unsigned long len, | ||
34 | const void *raw_pkcs7, size_t pkcs7_len, | ||
35 | enum key_being_used_for usage); | ||
36 | #endif | ||
37 | |||
31 | #endif /* _KEYS_SYSTEM_KEYRING_H */ | 38 | #endif /* _KEYS_SYSTEM_KEYRING_H */ |
diff --git a/include/linux/asn1_ber_bytecode.h b/include/linux/asn1_ber_bytecode.h index 945d44ae529c..ab3a6c002f7b 100644 --- a/include/linux/asn1_ber_bytecode.h +++ b/include/linux/asn1_ber_bytecode.h | |||
@@ -45,23 +45,27 @@ enum asn1_opcode { | |||
45 | ASN1_OP_MATCH_JUMP = 0x04, | 45 | ASN1_OP_MATCH_JUMP = 0x04, |
46 | ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05, | 46 | ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05, |
47 | ASN1_OP_MATCH_ANY = 0x08, | 47 | ASN1_OP_MATCH_ANY = 0x08, |
48 | ASN1_OP_MATCH_ANY_OR_SKIP = 0x09, | ||
48 | ASN1_OP_MATCH_ANY_ACT = 0x0a, | 49 | ASN1_OP_MATCH_ANY_ACT = 0x0a, |
50 | ASN1_OP_MATCH_ANY_ACT_OR_SKIP = 0x0b, | ||
49 | /* Everything before here matches unconditionally */ | 51 | /* Everything before here matches unconditionally */ |
50 | 52 | ||
51 | ASN1_OP_COND_MATCH_OR_SKIP = 0x11, | 53 | ASN1_OP_COND_MATCH_OR_SKIP = 0x11, |
52 | ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13, | 54 | ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13, |
53 | ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15, | 55 | ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15, |
54 | ASN1_OP_COND_MATCH_ANY = 0x18, | 56 | ASN1_OP_COND_MATCH_ANY = 0x18, |
57 | ASN1_OP_COND_MATCH_ANY_OR_SKIP = 0x19, | ||
55 | ASN1_OP_COND_MATCH_ANY_ACT = 0x1a, | 58 | ASN1_OP_COND_MATCH_ANY_ACT = 0x1a, |
59 | ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP = 0x1b, | ||
56 | 60 | ||
57 | /* Everything before here will want a tag from the data */ | 61 | /* Everything before here will want a tag from the data */ |
58 | #define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT | 62 | #define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP |
59 | 63 | ||
60 | /* These are here to help fill up space */ | 64 | /* These are here to help fill up space */ |
61 | ASN1_OP_COND_FAIL = 0x1b, | 65 | ASN1_OP_COND_FAIL = 0x1c, |
62 | ASN1_OP_COMPLETE = 0x1c, | 66 | ASN1_OP_COMPLETE = 0x1d, |
63 | ASN1_OP_ACT = 0x1d, | 67 | ASN1_OP_ACT = 0x1e, |
64 | ASN1_OP_RETURN = 0x1e, | 68 | ASN1_OP_MAYBE_ACT = 0x1f, |
65 | 69 | ||
66 | /* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */ | 70 | /* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */ |
67 | ASN1_OP_END_SEQ = 0x20, | 71 | ASN1_OP_END_SEQ = 0x20, |
@@ -76,6 +80,8 @@ enum asn1_opcode { | |||
76 | #define ASN1_OP_END__OF 0x02 | 80 | #define ASN1_OP_END__OF 0x02 |
77 | #define ASN1_OP_END__ACT 0x04 | 81 | #define ASN1_OP_END__ACT 0x04 |
78 | 82 | ||
83 | ASN1_OP_RETURN = 0x28, | ||
84 | |||
79 | ASN1_OP__NR | 85 | ASN1_OP__NR |
80 | }; | 86 | }; |
81 | 87 | ||
diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index 1cc89e9df480..ffb9c9da4f39 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h | |||
@@ -40,6 +40,11 @@ struct lsm_network_audit { | |||
40 | } fam; | 40 | } fam; |
41 | }; | 41 | }; |
42 | 42 | ||
43 | struct lsm_ioctlop_audit { | ||
44 | struct path path; | ||
45 | u16 cmd; | ||
46 | }; | ||
47 | |||
43 | /* Auxiliary data to use in generating the audit record. */ | 48 | /* Auxiliary data to use in generating the audit record. */ |
44 | struct common_audit_data { | 49 | struct common_audit_data { |
45 | char type; | 50 | char type; |
@@ -53,6 +58,7 @@ struct common_audit_data { | |||
53 | #define LSM_AUDIT_DATA_KMOD 8 | 58 | #define LSM_AUDIT_DATA_KMOD 8 |
54 | #define LSM_AUDIT_DATA_INODE 9 | 59 | #define LSM_AUDIT_DATA_INODE 9 |
55 | #define LSM_AUDIT_DATA_DENTRY 10 | 60 | #define LSM_AUDIT_DATA_DENTRY 10 |
61 | #define LSM_AUDIT_DATA_IOCTL_OP 11 | ||
56 | union { | 62 | union { |
57 | struct path path; | 63 | struct path path; |
58 | struct dentry *dentry; | 64 | struct dentry *dentry; |
@@ -68,6 +74,7 @@ struct common_audit_data { | |||
68 | } key_struct; | 74 | } key_struct; |
69 | #endif | 75 | #endif |
70 | char *kmod_name; | 76 | char *kmod_name; |
77 | struct lsm_ioctlop_audit *op; | ||
71 | } u; | 78 | } u; |
72 | /* this union contains LSM specific data */ | 79 | /* this union contains LSM specific data */ |
73 | union { | 80 | union { |
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 9429f054c323..ec3a6bab29de 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h | |||
@@ -1881,8 +1881,10 @@ static inline void security_delete_hooks(struct security_hook_list *hooks, | |||
1881 | 1881 | ||
1882 | extern int __init security_module_enable(const char *module); | 1882 | extern int __init security_module_enable(const char *module); |
1883 | extern void __init capability_add_hooks(void); | 1883 | extern void __init capability_add_hooks(void); |
1884 | #ifdef CONFIG_SECURITY_YAMA_STACKED | 1884 | #ifdef CONFIG_SECURITY_YAMA |
1885 | void __init yama_add_hooks(void); | 1885 | extern void __init yama_add_hooks(void); |
1886 | #else | ||
1887 | static inline void __init yama_add_hooks(void) { } | ||
1886 | #endif | 1888 | #endif |
1887 | 1889 | ||
1888 | #endif /* ! __LINUX_LSM_HOOKS_H */ | 1890 | #endif /* ! __LINUX_LSM_HOOKS_H */ |
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index c2bbf672b84e..d2fa9ca42e9a 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h | |||
@@ -41,7 +41,7 @@ enum OID { | |||
41 | OID_signed_data, /* 1.2.840.113549.1.7.2 */ | 41 | OID_signed_data, /* 1.2.840.113549.1.7.2 */ |
42 | /* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */ | 42 | /* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */ |
43 | OID_email_address, /* 1.2.840.113549.1.9.1 */ | 43 | OID_email_address, /* 1.2.840.113549.1.9.1 */ |
44 | OID_content_type, /* 1.2.840.113549.1.9.3 */ | 44 | OID_contentType, /* 1.2.840.113549.1.9.3 */ |
45 | OID_messageDigest, /* 1.2.840.113549.1.9.4 */ | 45 | OID_messageDigest, /* 1.2.840.113549.1.9.4 */ |
46 | OID_signingTime, /* 1.2.840.113549.1.9.5 */ | 46 | OID_signingTime, /* 1.2.840.113549.1.9.5 */ |
47 | OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */ | 47 | OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */ |
@@ -54,6 +54,8 @@ enum OID { | |||
54 | 54 | ||
55 | /* Microsoft Authenticode & Software Publishing */ | 55 | /* Microsoft Authenticode & Software Publishing */ |
56 | OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */ | 56 | OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */ |
57 | OID_msStatementType, /* 1.3.6.1.4.1.311.2.1.11 */ | ||
58 | OID_msSpOpusInfo, /* 1.3.6.1.4.1.311.2.1.12 */ | ||
57 | OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */ | 59 | OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */ |
58 | OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */ | 60 | OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */ |
59 | OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ | 61 | OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */ |
@@ -61,6 +63,9 @@ enum OID { | |||
61 | OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ | 63 | OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ |
62 | OID_sha1, /* 1.3.14.3.2.26 */ | 64 | OID_sha1, /* 1.3.14.3.2.26 */ |
63 | OID_sha256, /* 2.16.840.1.101.3.4.2.1 */ | 65 | OID_sha256, /* 2.16.840.1.101.3.4.2.1 */ |
66 | OID_sha384, /* 2.16.840.1.101.3.4.2.2 */ | ||
67 | OID_sha512, /* 2.16.840.1.101.3.4.2.3 */ | ||
68 | OID_sha224, /* 2.16.840.1.101.3.4.2.4 */ | ||
64 | 69 | ||
65 | /* Distinguished Name attribute IDs [RFC 2256] */ | 70 | /* Distinguished Name attribute IDs [RFC 2256] */ |
66 | OID_commonName, /* 2.5.4.3 */ | 71 | OID_commonName, /* 2.5.4.3 */ |
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 987a73a40ef8..061265f92876 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h | |||
@@ -34,6 +34,7 @@ | |||
34 | #define PT_TRACE_SECCOMP PT_EVENT_FLAG(PTRACE_EVENT_SECCOMP) | 34 | #define PT_TRACE_SECCOMP PT_EVENT_FLAG(PTRACE_EVENT_SECCOMP) |
35 | 35 | ||
36 | #define PT_EXITKILL (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT) | 36 | #define PT_EXITKILL (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT) |
37 | #define PT_SUSPEND_SECCOMP (PTRACE_O_SUSPEND_SECCOMP << PT_OPT_FLAG_SHIFT) | ||
37 | 38 | ||
38 | /* single stepping state bits (used on ARM and PA-RISC) */ | 39 | /* single stepping state bits (used on ARM and PA-RISC) */ |
39 | #define PT_SINGLESTEP_BIT 31 | 40 | #define PT_SINGLESTEP_BIT 31 |
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index a19ddacdac30..f4265039a94c 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h | |||
@@ -78,7 +78,7 @@ static inline long prctl_set_seccomp(unsigned long arg2, char __user *arg3) | |||
78 | 78 | ||
79 | static inline int seccomp_mode(struct seccomp *s) | 79 | static inline int seccomp_mode(struct seccomp *s) |
80 | { | 80 | { |
81 | return 0; | 81 | return SECCOMP_MODE_DISABLED; |
82 | } | 82 | } |
83 | #endif /* CONFIG_SECCOMP */ | 83 | #endif /* CONFIG_SECCOMP */ |
84 | 84 | ||
diff --git a/include/linux/verify_pefile.h b/include/linux/verify_pefile.h index ac34819214f9..da2049b5161c 100644 --- a/include/linux/verify_pefile.h +++ b/include/linux/verify_pefile.h | |||
@@ -12,7 +12,11 @@ | |||
12 | #ifndef _LINUX_VERIFY_PEFILE_H | 12 | #ifndef _LINUX_VERIFY_PEFILE_H |
13 | #define _LINUX_VERIFY_PEFILE_H | 13 | #define _LINUX_VERIFY_PEFILE_H |
14 | 14 | ||
15 | #include <crypto/public_key.h> | ||
16 | |||
15 | extern int verify_pefile_signature(const void *pebuf, unsigned pelen, | 17 | extern int verify_pefile_signature(const void *pebuf, unsigned pelen, |
16 | struct key *trusted_keyring, bool *_trusted); | 18 | struct key *trusted_keyring, |
19 | enum key_being_used_for usage, | ||
20 | bool *_trusted); | ||
17 | 21 | ||
18 | #endif /* _LINUX_VERIFY_PEFILE_H */ | 22 | #endif /* _LINUX_VERIFY_PEFILE_H */ |
diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h index cf1019e15f5b..a7a697986614 100644 --- a/include/uapi/linux/ptrace.h +++ b/include/uapi/linux/ptrace.h | |||
@@ -89,9 +89,11 @@ struct ptrace_peeksiginfo_args { | |||
89 | #define PTRACE_O_TRACESECCOMP (1 << PTRACE_EVENT_SECCOMP) | 89 | #define PTRACE_O_TRACESECCOMP (1 << PTRACE_EVENT_SECCOMP) |
90 | 90 | ||
91 | /* eventless options */ | 91 | /* eventless options */ |
92 | #define PTRACE_O_EXITKILL (1 << 20) | 92 | #define PTRACE_O_EXITKILL (1 << 20) |
93 | #define PTRACE_O_SUSPEND_SECCOMP (1 << 21) | ||
93 | 94 | ||
94 | #define PTRACE_O_MASK (0x000000ff | PTRACE_O_EXITKILL) | 95 | #define PTRACE_O_MASK (\ |
96 | 0x000000ff | PTRACE_O_EXITKILL | PTRACE_O_SUSPEND_SECCOMP) | ||
95 | 97 | ||
96 | #include <asm/ptrace.h> | 98 | #include <asm/ptrace.h> |
97 | 99 | ||
diff --git a/init/Kconfig b/init/Kconfig index 9cabd866b34b..02da9f1fd9df 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -1765,17 +1765,23 @@ config MMAP_ALLOW_UNINITIALIZED | |||
1765 | 1765 | ||
1766 | See Documentation/nommu-mmap.txt for more information. | 1766 | See Documentation/nommu-mmap.txt for more information. |
1767 | 1767 | ||
1768 | config SYSTEM_TRUSTED_KEYRING | 1768 | config SYSTEM_DATA_VERIFICATION |
1769 | bool "Provide system-wide ring of trusted keys" | 1769 | def_bool n |
1770 | depends on KEYS | 1770 | select SYSTEM_TRUSTED_KEYRING |
1771 | select KEYS | ||
1772 | select CRYPTO | ||
1773 | select ASYMMETRIC_KEY_TYPE | ||
1774 | select ASYMMETRIC_PUBLIC_KEY_SUBTYPE | ||
1775 | select PUBLIC_KEY_ALGO_RSA | ||
1776 | select ASN1 | ||
1777 | select OID_REGISTRY | ||
1778 | select X509_CERTIFICATE_PARSER | ||
1779 | select PKCS7_MESSAGE_PARSER | ||
1771 | help | 1780 | help |
1772 | Provide a system keyring to which trusted keys can be added. Keys in | 1781 | Provide PKCS#7 message verification using the contents of the system |
1773 | the keyring are considered to be trusted. Keys may be added at will | 1782 | trusted keyring to provide public keys. This then can be used for |
1774 | by the kernel from compiled-in data and from hardware key stores, but | 1783 | module verification, kexec image verification and firmware blob |
1775 | userspace may only add extra keys if those keys can be verified by | 1784 | verification. |
1776 | keys already in the keyring. | ||
1777 | |||
1778 | Keys in this keyring are used by module signature checking. | ||
1779 | 1785 | ||
1780 | config PROFILING | 1786 | config PROFILING |
1781 | bool "Profiling support" | 1787 | bool "Profiling support" |
@@ -1885,20 +1891,16 @@ config MODULE_SRCVERSION_ALL | |||
1885 | config MODULE_SIG | 1891 | config MODULE_SIG |
1886 | bool "Module signature verification" | 1892 | bool "Module signature verification" |
1887 | depends on MODULES | 1893 | depends on MODULES |
1888 | select SYSTEM_TRUSTED_KEYRING | 1894 | select SYSTEM_DATA_VERIFICATION |
1889 | select KEYS | ||
1890 | select CRYPTO | ||
1891 | select ASYMMETRIC_KEY_TYPE | ||
1892 | select ASYMMETRIC_PUBLIC_KEY_SUBTYPE | ||
1893 | select PUBLIC_KEY_ALGO_RSA | ||
1894 | select ASN1 | ||
1895 | select OID_REGISTRY | ||
1896 | select X509_CERTIFICATE_PARSER | ||
1897 | help | 1895 | help |
1898 | Check modules for valid signatures upon load: the signature | 1896 | Check modules for valid signatures upon load: the signature |
1899 | is simply appended to the module. For more information see | 1897 | is simply appended to the module. For more information see |
1900 | Documentation/module-signing.txt. | 1898 | Documentation/module-signing.txt. |
1901 | 1899 | ||
1900 | Note that this option adds the OpenSSL development packages as a | ||
1901 | kernel build dependency so that the signing tool can use its crypto | ||
1902 | library. | ||
1903 | |||
1902 | !!!WARNING!!! If you enable this option, you MUST make sure that the | 1904 | !!!WARNING!!! If you enable this option, you MUST make sure that the |
1903 | module DOES NOT get stripped after being signed. This includes the | 1905 | module DOES NOT get stripped after being signed. This includes the |
1904 | debuginfo strip done by some packagers (such as rpmbuild) and | 1906 | debuginfo strip done by some packagers (such as rpmbuild) and |
diff --git a/kernel/Makefile b/kernel/Makefile index 718fb8afab7a..330387cfb730 100644 --- a/kernel/Makefile +++ b/kernel/Makefile | |||
@@ -45,7 +45,6 @@ ifneq ($(CONFIG_SMP),y) | |||
45 | obj-y += up.o | 45 | obj-y += up.o |
46 | endif | 46 | endif |
47 | obj-$(CONFIG_UID16) += uid16.o | 47 | obj-$(CONFIG_UID16) += uid16.o |
48 | obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o | ||
49 | obj-$(CONFIG_MODULES) += module.o | 48 | obj-$(CONFIG_MODULES) += module.o |
50 | obj-$(CONFIG_MODULE_SIG) += module_signing.o | 49 | obj-$(CONFIG_MODULE_SIG) += module_signing.o |
51 | obj-$(CONFIG_KALLSYMS) += kallsyms.o | 50 | obj-$(CONFIG_KALLSYMS) += kallsyms.o |
@@ -112,99 +111,3 @@ $(obj)/config_data.gz: $(KCONFIG_CONFIG) FORCE | |||
112 | targets += config_data.h | 111 | targets += config_data.h |
113 | $(obj)/config_data.h: $(obj)/config_data.gz FORCE | 112 | $(obj)/config_data.h: $(obj)/config_data.gz FORCE |
114 | $(call filechk,ikconfiggz) | 113 | $(call filechk,ikconfiggz) |
115 | |||
116 | ############################################################################### | ||
117 | # | ||
118 | # Roll all the X.509 certificates that we can find together and pull them into | ||
119 | # the kernel so that they get loaded into the system trusted keyring during | ||
120 | # boot. | ||
121 | # | ||
122 | # We look in the source root and the build root for all files whose name ends | ||
123 | # in ".x509". Unfortunately, this will generate duplicate filenames, so we | ||
124 | # have make canonicalise the pathnames and then sort them to discard the | ||
125 | # duplicates. | ||
126 | # | ||
127 | ############################################################################### | ||
128 | ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) | ||
129 | X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509) | ||
130 | X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += $(objtree)/signing_key.x509 | ||
131 | X509_CERTIFICATES-raw := $(sort $(foreach CERT,$(X509_CERTIFICATES-y), \ | ||
132 | $(or $(realpath $(CERT)),$(CERT)))) | ||
133 | X509_CERTIFICATES := $(subst $(realpath $(objtree))/,,$(X509_CERTIFICATES-raw)) | ||
134 | |||
135 | ifeq ($(X509_CERTIFICATES),) | ||
136 | $(warning *** No X.509 certificates found ***) | ||
137 | endif | ||
138 | |||
139 | ifneq ($(wildcard $(obj)/.x509.list),) | ||
140 | ifneq ($(shell cat $(obj)/.x509.list),$(X509_CERTIFICATES)) | ||
141 | $(warning X.509 certificate list changed to "$(X509_CERTIFICATES)" from "$(shell cat $(obj)/.x509.list)") | ||
142 | $(shell rm $(obj)/.x509.list) | ||
143 | endif | ||
144 | endif | ||
145 | |||
146 | kernel/system_certificates.o: $(obj)/x509_certificate_list | ||
147 | |||
148 | quiet_cmd_x509certs = CERTS $@ | ||
149 | cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; $(kecho) " - Including cert $(X509)") | ||
150 | |||
151 | targets += $(obj)/x509_certificate_list | ||
152 | $(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list | ||
153 | $(call if_changed,x509certs) | ||
154 | |||
155 | targets += $(obj)/.x509.list | ||
156 | $(obj)/.x509.list: | ||
157 | @echo $(X509_CERTIFICATES) >$@ | ||
158 | endif | ||
159 | |||
160 | clean-files := x509_certificate_list .x509.list | ||
161 | |||
162 | ifeq ($(CONFIG_MODULE_SIG),y) | ||
163 | ############################################################################### | ||
164 | # | ||
165 | # If module signing is requested, say by allyesconfig, but a key has not been | ||
166 | # supplied, then one will need to be generated to make sure the build does not | ||
167 | # fail and that the kernel may be used afterwards. | ||
168 | # | ||
169 | ############################################################################### | ||
170 | ifndef CONFIG_MODULE_SIG_HASH | ||
171 | $(error Could not determine digest type to use from kernel config) | ||
172 | endif | ||
173 | |||
174 | signing_key.priv signing_key.x509: x509.genkey | ||
175 | @echo "###" | ||
176 | @echo "### Now generating an X.509 key pair to be used for signing modules." | ||
177 | @echo "###" | ||
178 | @echo "### If this takes a long time, you might wish to run rngd in the" | ||
179 | @echo "### background to keep the supply of entropy topped up. It" | ||
180 | @echo "### needs to be run as root, and uses a hardware random" | ||
181 | @echo "### number generator if one is available." | ||
182 | @echo "###" | ||
183 | openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \ | ||
184 | -batch -x509 -config x509.genkey \ | ||
185 | -outform DER -out signing_key.x509 \ | ||
186 | -keyout signing_key.priv 2>&1 | ||
187 | @echo "###" | ||
188 | @echo "### Key pair generated." | ||
189 | @echo "###" | ||
190 | |||
191 | x509.genkey: | ||
192 | @echo Generating X.509 key generation config | ||
193 | @echo >x509.genkey "[ req ]" | ||
194 | @echo >>x509.genkey "default_bits = 4096" | ||
195 | @echo >>x509.genkey "distinguished_name = req_distinguished_name" | ||
196 | @echo >>x509.genkey "prompt = no" | ||
197 | @echo >>x509.genkey "string_mask = utf8only" | ||
198 | @echo >>x509.genkey "x509_extensions = myexts" | ||
199 | @echo >>x509.genkey | ||
200 | @echo >>x509.genkey "[ req_distinguished_name ]" | ||
201 | @echo >>x509.genkey "#O = Unspecified company" | ||
202 | @echo >>x509.genkey "CN = Build time autogenerated kernel key" | ||
203 | @echo >>x509.genkey "#emailAddress = unspecified.user@unspecified.company" | ||
204 | @echo >>x509.genkey | ||
205 | @echo >>x509.genkey "[ myexts ]" | ||
206 | @echo >>x509.genkey "basicConstraints=critical,CA:FALSE" | ||
207 | @echo >>x509.genkey "keyUsage=digitalSignature" | ||
208 | @echo >>x509.genkey "subjectKeyIdentifier=hash" | ||
209 | @echo >>x509.genkey "authorityKeyIdentifier=keyid" | ||
210 | endif | ||
diff --git a/kernel/module_signing.c b/kernel/module_signing.c index be5b8fac4bd0..bd62f5cda746 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c | |||
@@ -10,11 +10,8 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/err.h> | ||
14 | #include <crypto/public_key.h> | ||
15 | #include <crypto/hash.h> | ||
16 | #include <keys/asymmetric-type.h> | ||
17 | #include <keys/system_keyring.h> | 13 | #include <keys/system_keyring.h> |
14 | #include <crypto/public_key.h> | ||
18 | #include "module-internal.h" | 15 | #include "module-internal.h" |
19 | 16 | ||
20 | /* | 17 | /* |
@@ -28,170 +25,22 @@ | |||
28 | * - Information block | 25 | * - Information block |
29 | */ | 26 | */ |
30 | struct module_signature { | 27 | struct module_signature { |
31 | u8 algo; /* Public-key crypto algorithm [enum pkey_algo] */ | 28 | u8 algo; /* Public-key crypto algorithm [0] */ |
32 | u8 hash; /* Digest algorithm [enum hash_algo] */ | 29 | u8 hash; /* Digest algorithm [0] */ |
33 | u8 id_type; /* Key identifier type [enum pkey_id_type] */ | 30 | u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */ |
34 | u8 signer_len; /* Length of signer's name */ | 31 | u8 signer_len; /* Length of signer's name [0] */ |
35 | u8 key_id_len; /* Length of key identifier */ | 32 | u8 key_id_len; /* Length of key identifier [0] */ |
36 | u8 __pad[3]; | 33 | u8 __pad[3]; |
37 | __be32 sig_len; /* Length of signature data */ | 34 | __be32 sig_len; /* Length of signature data */ |
38 | }; | 35 | }; |
39 | 36 | ||
40 | /* | 37 | /* |
41 | * Digest the module contents. | ||
42 | */ | ||
43 | static struct public_key_signature *mod_make_digest(enum hash_algo hash, | ||
44 | const void *mod, | ||
45 | unsigned long modlen) | ||
46 | { | ||
47 | struct public_key_signature *pks; | ||
48 | struct crypto_shash *tfm; | ||
49 | struct shash_desc *desc; | ||
50 | size_t digest_size, desc_size; | ||
51 | int ret; | ||
52 | |||
53 | pr_devel("==>%s()\n", __func__); | ||
54 | |||
55 | /* Allocate the hashing algorithm we're going to need and find out how | ||
56 | * big the hash operational data will be. | ||
57 | */ | ||
58 | tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0); | ||
59 | if (IS_ERR(tfm)) | ||
60 | return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm); | ||
61 | |||
62 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | ||
63 | digest_size = crypto_shash_digestsize(tfm); | ||
64 | |||
65 | /* We allocate the hash operational data storage on the end of our | ||
66 | * context data and the digest output buffer on the end of that. | ||
67 | */ | ||
68 | ret = -ENOMEM; | ||
69 | pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL); | ||
70 | if (!pks) | ||
71 | goto error_no_pks; | ||
72 | |||
73 | pks->pkey_hash_algo = hash; | ||
74 | pks->digest = (u8 *)pks + sizeof(*pks) + desc_size; | ||
75 | pks->digest_size = digest_size; | ||
76 | |||
77 | desc = (void *)pks + sizeof(*pks); | ||
78 | desc->tfm = tfm; | ||
79 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
80 | |||
81 | ret = crypto_shash_init(desc); | ||
82 | if (ret < 0) | ||
83 | goto error; | ||
84 | |||
85 | ret = crypto_shash_finup(desc, mod, modlen, pks->digest); | ||
86 | if (ret < 0) | ||
87 | goto error; | ||
88 | |||
89 | crypto_free_shash(tfm); | ||
90 | pr_devel("<==%s() = ok\n", __func__); | ||
91 | return pks; | ||
92 | |||
93 | error: | ||
94 | kfree(pks); | ||
95 | error_no_pks: | ||
96 | crypto_free_shash(tfm); | ||
97 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
98 | return ERR_PTR(ret); | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * Extract an MPI array from the signature data. This represents the actual | ||
103 | * signature. Each raw MPI is prefaced by a BE 2-byte value indicating the | ||
104 | * size of the MPI in bytes. | ||
105 | * | ||
106 | * RSA signatures only have one MPI, so currently we only read one. | ||
107 | */ | ||
108 | static int mod_extract_mpi_array(struct public_key_signature *pks, | ||
109 | const void *data, size_t len) | ||
110 | { | ||
111 | size_t nbytes; | ||
112 | MPI mpi; | ||
113 | |||
114 | if (len < 3) | ||
115 | return -EBADMSG; | ||
116 | nbytes = ((const u8 *)data)[0] << 8 | ((const u8 *)data)[1]; | ||
117 | data += 2; | ||
118 | len -= 2; | ||
119 | if (len != nbytes) | ||
120 | return -EBADMSG; | ||
121 | |||
122 | mpi = mpi_read_raw_data(data, nbytes); | ||
123 | if (!mpi) | ||
124 | return -ENOMEM; | ||
125 | pks->mpi[0] = mpi; | ||
126 | pks->nr_mpi = 1; | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * Request an asymmetric key. | ||
132 | */ | ||
133 | static struct key *request_asymmetric_key(const char *signer, size_t signer_len, | ||
134 | const u8 *key_id, size_t key_id_len) | ||
135 | { | ||
136 | key_ref_t key; | ||
137 | size_t i; | ||
138 | char *id, *q; | ||
139 | |||
140 | pr_devel("==>%s(,%zu,,%zu)\n", __func__, signer_len, key_id_len); | ||
141 | |||
142 | /* Construct an identifier. */ | ||
143 | id = kmalloc(signer_len + 2 + key_id_len * 2 + 1, GFP_KERNEL); | ||
144 | if (!id) | ||
145 | return ERR_PTR(-ENOKEY); | ||
146 | |||
147 | memcpy(id, signer, signer_len); | ||
148 | |||
149 | q = id + signer_len; | ||
150 | *q++ = ':'; | ||
151 | *q++ = ' '; | ||
152 | for (i = 0; i < key_id_len; i++) { | ||
153 | *q++ = hex_asc[*key_id >> 4]; | ||
154 | *q++ = hex_asc[*key_id++ & 0x0f]; | ||
155 | } | ||
156 | |||
157 | *q = 0; | ||
158 | |||
159 | pr_debug("Look up: \"%s\"\n", id); | ||
160 | |||
161 | key = keyring_search(make_key_ref(system_trusted_keyring, 1), | ||
162 | &key_type_asymmetric, id); | ||
163 | if (IS_ERR(key)) | ||
164 | pr_warn("Request for unknown module key '%s' err %ld\n", | ||
165 | id, PTR_ERR(key)); | ||
166 | kfree(id); | ||
167 | |||
168 | if (IS_ERR(key)) { | ||
169 | switch (PTR_ERR(key)) { | ||
170 | /* Hide some search errors */ | ||
171 | case -EACCES: | ||
172 | case -ENOTDIR: | ||
173 | case -EAGAIN: | ||
174 | return ERR_PTR(-ENOKEY); | ||
175 | default: | ||
176 | return ERR_CAST(key); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key))); | ||
181 | return key_ref_to_ptr(key); | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * Verify the signature on a module. | 38 | * Verify the signature on a module. |
186 | */ | 39 | */ |
187 | int mod_verify_sig(const void *mod, unsigned long *_modlen) | 40 | int mod_verify_sig(const void *mod, unsigned long *_modlen) |
188 | { | 41 | { |
189 | struct public_key_signature *pks; | ||
190 | struct module_signature ms; | 42 | struct module_signature ms; |
191 | struct key *key; | ||
192 | const void *sig; | ||
193 | size_t modlen = *_modlen, sig_len; | 43 | size_t modlen = *_modlen, sig_len; |
194 | int ret; | ||
195 | 44 | ||
196 | pr_devel("==>%s(,%zu)\n", __func__, modlen); | 45 | pr_devel("==>%s(,%zu)\n", __func__, modlen); |
197 | 46 | ||
@@ -205,46 +54,24 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen) | |||
205 | if (sig_len >= modlen) | 54 | if (sig_len >= modlen) |
206 | return -EBADMSG; | 55 | return -EBADMSG; |
207 | modlen -= sig_len; | 56 | modlen -= sig_len; |
208 | if ((size_t)ms.signer_len + ms.key_id_len >= modlen) | ||
209 | return -EBADMSG; | ||
210 | modlen -= (size_t)ms.signer_len + ms.key_id_len; | ||
211 | |||
212 | *_modlen = modlen; | 57 | *_modlen = modlen; |
213 | sig = mod + modlen; | ||
214 | |||
215 | /* For the moment, only support RSA and X.509 identifiers */ | ||
216 | if (ms.algo != PKEY_ALGO_RSA || | ||
217 | ms.id_type != PKEY_ID_X509) | ||
218 | return -ENOPKG; | ||
219 | 58 | ||
220 | if (ms.hash >= PKEY_HASH__LAST || | 59 | if (ms.id_type != PKEY_ID_PKCS7) { |
221 | !hash_algo_name[ms.hash]) | 60 | pr_err("Module is not signed with expected PKCS#7 message\n"); |
222 | return -ENOPKG; | 61 | return -ENOPKG; |
223 | |||
224 | key = request_asymmetric_key(sig, ms.signer_len, | ||
225 | sig + ms.signer_len, ms.key_id_len); | ||
226 | if (IS_ERR(key)) | ||
227 | return PTR_ERR(key); | ||
228 | |||
229 | pks = mod_make_digest(ms.hash, mod, modlen); | ||
230 | if (IS_ERR(pks)) { | ||
231 | ret = PTR_ERR(pks); | ||
232 | goto error_put_key; | ||
233 | } | 62 | } |
234 | 63 | ||
235 | ret = mod_extract_mpi_array(pks, sig + ms.signer_len + ms.key_id_len, | 64 | if (ms.algo != 0 || |
236 | sig_len); | 65 | ms.hash != 0 || |
237 | if (ret < 0) | 66 | ms.signer_len != 0 || |
238 | goto error_free_pks; | 67 | ms.key_id_len != 0 || |
239 | 68 | ms.__pad[0] != 0 || | |
240 | ret = verify_signature(key, pks); | 69 | ms.__pad[1] != 0 || |
241 | pr_devel("verify_signature() = %d\n", ret); | 70 | ms.__pad[2] != 0) { |
71 | pr_err("PKCS#7 signature info has unexpected non-zero params\n"); | ||
72 | return -EBADMSG; | ||
73 | } | ||
242 | 74 | ||
243 | error_free_pks: | 75 | return system_verify_data(mod, modlen, mod + modlen, sig_len, |
244 | mpi_free(pks->rsa.s); | 76 | VERIFYING_MODULE_SIGNATURE); |
245 | kfree(pks); | ||
246 | error_put_key: | ||
247 | key_put(key); | ||
248 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
249 | return ret; | ||
250 | } | 77 | } |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index c8e0e050a36a..787320de68e0 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -556,6 +556,19 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data) | |||
556 | if (data & ~(unsigned long)PTRACE_O_MASK) | 556 | if (data & ~(unsigned long)PTRACE_O_MASK) |
557 | return -EINVAL; | 557 | return -EINVAL; |
558 | 558 | ||
559 | if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { | ||
560 | if (!config_enabled(CONFIG_CHECKPOINT_RESTORE) || | ||
561 | !config_enabled(CONFIG_SECCOMP)) | ||
562 | return -EINVAL; | ||
563 | |||
564 | if (!capable(CAP_SYS_ADMIN)) | ||
565 | return -EPERM; | ||
566 | |||
567 | if (seccomp_mode(¤t->seccomp) != SECCOMP_MODE_DISABLED || | ||
568 | current->ptrace & PT_SUSPEND_SECCOMP) | ||
569 | return -EPERM; | ||
570 | } | ||
571 | |||
559 | /* Avoid intermediate state when all opts are cleared */ | 572 | /* Avoid intermediate state when all opts are cleared */ |
560 | flags = child->ptrace; | 573 | flags = child->ptrace; |
561 | flags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT); | 574 | flags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT); |
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 245df6b32b81..5bd4779282df 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -175,17 +175,16 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen) | |||
175 | */ | 175 | */ |
176 | static u32 seccomp_run_filters(struct seccomp_data *sd) | 176 | static u32 seccomp_run_filters(struct seccomp_data *sd) |
177 | { | 177 | { |
178 | struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter); | ||
179 | struct seccomp_data sd_local; | 178 | struct seccomp_data sd_local; |
180 | u32 ret = SECCOMP_RET_ALLOW; | 179 | u32 ret = SECCOMP_RET_ALLOW; |
180 | /* Make sure cross-thread synced filter points somewhere sane. */ | ||
181 | struct seccomp_filter *f = | ||
182 | lockless_dereference(current->seccomp.filter); | ||
181 | 183 | ||
182 | /* Ensure unexpected behavior doesn't result in failing open. */ | 184 | /* Ensure unexpected behavior doesn't result in failing open. */ |
183 | if (unlikely(WARN_ON(f == NULL))) | 185 | if (unlikely(WARN_ON(f == NULL))) |
184 | return SECCOMP_RET_KILL; | 186 | return SECCOMP_RET_KILL; |
185 | 187 | ||
186 | /* Make sure cross-thread synced filter points somewhere sane. */ | ||
187 | smp_read_barrier_depends(); | ||
188 | |||
189 | if (!sd) { | 188 | if (!sd) { |
190 | populate_seccomp_data(&sd_local); | 189 | populate_seccomp_data(&sd_local); |
191 | sd = &sd_local; | 190 | sd = &sd_local; |
@@ -549,7 +548,11 @@ void secure_computing_strict(int this_syscall) | |||
549 | { | 548 | { |
550 | int mode = current->seccomp.mode; | 549 | int mode = current->seccomp.mode; |
551 | 550 | ||
552 | if (mode == 0) | 551 | if (config_enabled(CONFIG_CHECKPOINT_RESTORE) && |
552 | unlikely(current->ptrace & PT_SUSPEND_SECCOMP)) | ||
553 | return; | ||
554 | |||
555 | if (mode == SECCOMP_MODE_DISABLED) | ||
553 | return; | 556 | return; |
554 | else if (mode == SECCOMP_MODE_STRICT) | 557 | else if (mode == SECCOMP_MODE_STRICT) |
555 | __secure_computing_strict(this_syscall); | 558 | __secure_computing_strict(this_syscall); |
@@ -650,6 +653,10 @@ u32 seccomp_phase1(struct seccomp_data *sd) | |||
650 | int this_syscall = sd ? sd->nr : | 653 | int this_syscall = sd ? sd->nr : |
651 | syscall_get_nr(current, task_pt_regs(current)); | 654 | syscall_get_nr(current, task_pt_regs(current)); |
652 | 655 | ||
656 | if (config_enabled(CONFIG_CHECKPOINT_RESTORE) && | ||
657 | unlikely(current->ptrace & PT_SUSPEND_SECCOMP)) | ||
658 | return SECCOMP_PHASE1_OK; | ||
659 | |||
653 | switch (mode) { | 660 | switch (mode) { |
654 | case SECCOMP_MODE_STRICT: | 661 | case SECCOMP_MODE_STRICT: |
655 | __secure_computing_strict(this_syscall); /* may call do_exit */ | 662 | __secure_computing_strict(this_syscall); /* may call do_exit */ |
diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c index 1a000bb050f9..2b3f46c049d4 100644 --- a/lib/asn1_decoder.c +++ b/lib/asn1_decoder.c | |||
@@ -24,15 +24,20 @@ static const unsigned char asn1_op_lengths[ASN1_OP__NR] = { | |||
24 | [ASN1_OP_MATCH_JUMP] = 1 + 1 + 1, | 24 | [ASN1_OP_MATCH_JUMP] = 1 + 1 + 1, |
25 | [ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, | 25 | [ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, |
26 | [ASN1_OP_MATCH_ANY] = 1, | 26 | [ASN1_OP_MATCH_ANY] = 1, |
27 | [ASN1_OP_MATCH_ANY_OR_SKIP] = 1, | ||
27 | [ASN1_OP_MATCH_ANY_ACT] = 1 + 1, | 28 | [ASN1_OP_MATCH_ANY_ACT] = 1 + 1, |
29 | [ASN1_OP_MATCH_ANY_ACT_OR_SKIP] = 1 + 1, | ||
28 | [ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1, | 30 | [ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1, |
29 | [ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, | 31 | [ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1, |
30 | [ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, | 32 | [ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1, |
31 | [ASN1_OP_COND_MATCH_ANY] = 1, | 33 | [ASN1_OP_COND_MATCH_ANY] = 1, |
34 | [ASN1_OP_COND_MATCH_ANY_OR_SKIP] = 1, | ||
32 | [ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1, | 35 | [ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1, |
36 | [ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP] = 1 + 1, | ||
33 | [ASN1_OP_COND_FAIL] = 1, | 37 | [ASN1_OP_COND_FAIL] = 1, |
34 | [ASN1_OP_COMPLETE] = 1, | 38 | [ASN1_OP_COMPLETE] = 1, |
35 | [ASN1_OP_ACT] = 1 + 1, | 39 | [ASN1_OP_ACT] = 1 + 1, |
40 | [ASN1_OP_MAYBE_ACT] = 1 + 1, | ||
36 | [ASN1_OP_RETURN] = 1, | 41 | [ASN1_OP_RETURN] = 1, |
37 | [ASN1_OP_END_SEQ] = 1, | 42 | [ASN1_OP_END_SEQ] = 1, |
38 | [ASN1_OP_END_SEQ_OF] = 1 + 1, | 43 | [ASN1_OP_END_SEQ_OF] = 1 + 1, |
@@ -177,6 +182,7 @@ int asn1_ber_decoder(const struct asn1_decoder *decoder, | |||
177 | unsigned char flags = 0; | 182 | unsigned char flags = 0; |
178 | #define FLAG_INDEFINITE_LENGTH 0x01 | 183 | #define FLAG_INDEFINITE_LENGTH 0x01 |
179 | #define FLAG_MATCHED 0x02 | 184 | #define FLAG_MATCHED 0x02 |
185 | #define FLAG_LAST_MATCHED 0x04 /* Last tag matched */ | ||
180 | #define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag | 186 | #define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag |
181 | * - ie. whether or not we are going to parse | 187 | * - ie. whether or not we are going to parse |
182 | * a compound type. | 188 | * a compound type. |
@@ -208,9 +214,9 @@ next_op: | |||
208 | unsigned char tmp; | 214 | unsigned char tmp; |
209 | 215 | ||
210 | /* Skip conditional matches if possible */ | 216 | /* Skip conditional matches if possible */ |
211 | if ((op & ASN1_OP_MATCH__COND && | 217 | if ((op & ASN1_OP_MATCH__COND && flags & FLAG_MATCHED) || |
212 | flags & FLAG_MATCHED) || | 218 | (op & ASN1_OP_MATCH__SKIP && dp == datalen)) { |
213 | dp == datalen) { | 219 | flags &= ~FLAG_LAST_MATCHED; |
214 | pc += asn1_op_lengths[op]; | 220 | pc += asn1_op_lengths[op]; |
215 | goto next_op; | 221 | goto next_op; |
216 | } | 222 | } |
@@ -302,7 +308,9 @@ next_op: | |||
302 | /* Decide how to handle the operation */ | 308 | /* Decide how to handle the operation */ |
303 | switch (op) { | 309 | switch (op) { |
304 | case ASN1_OP_MATCH_ANY_ACT: | 310 | case ASN1_OP_MATCH_ANY_ACT: |
311 | case ASN1_OP_MATCH_ANY_ACT_OR_SKIP: | ||
305 | case ASN1_OP_COND_MATCH_ANY_ACT: | 312 | case ASN1_OP_COND_MATCH_ANY_ACT: |
313 | case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP: | ||
306 | ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len); | 314 | ret = actions[machine[pc + 1]](context, hdr, tag, data + dp, len); |
307 | if (ret < 0) | 315 | if (ret < 0) |
308 | return ret; | 316 | return ret; |
@@ -319,8 +327,10 @@ next_op: | |||
319 | case ASN1_OP_MATCH: | 327 | case ASN1_OP_MATCH: |
320 | case ASN1_OP_MATCH_OR_SKIP: | 328 | case ASN1_OP_MATCH_OR_SKIP: |
321 | case ASN1_OP_MATCH_ANY: | 329 | case ASN1_OP_MATCH_ANY: |
330 | case ASN1_OP_MATCH_ANY_OR_SKIP: | ||
322 | case ASN1_OP_COND_MATCH_OR_SKIP: | 331 | case ASN1_OP_COND_MATCH_OR_SKIP: |
323 | case ASN1_OP_COND_MATCH_ANY: | 332 | case ASN1_OP_COND_MATCH_ANY: |
333 | case ASN1_OP_COND_MATCH_ANY_OR_SKIP: | ||
324 | skip_data: | 334 | skip_data: |
325 | if (!(flags & FLAG_CONS)) { | 335 | if (!(flags & FLAG_CONS)) { |
326 | if (flags & FLAG_INDEFINITE_LENGTH) { | 336 | if (flags & FLAG_INDEFINITE_LENGTH) { |
@@ -422,8 +432,15 @@ next_op: | |||
422 | pc += asn1_op_lengths[op]; | 432 | pc += asn1_op_lengths[op]; |
423 | goto next_op; | 433 | goto next_op; |
424 | 434 | ||
435 | case ASN1_OP_MAYBE_ACT: | ||
436 | if (!(flags & FLAG_LAST_MATCHED)) { | ||
437 | pc += asn1_op_lengths[op]; | ||
438 | goto next_op; | ||
439 | } | ||
425 | case ASN1_OP_ACT: | 440 | case ASN1_OP_ACT: |
426 | ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len); | 441 | ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len); |
442 | if (ret < 0) | ||
443 | return ret; | ||
427 | pc += asn1_op_lengths[op]; | 444 | pc += asn1_op_lengths[op]; |
428 | goto next_op; | 445 | goto next_op; |
429 | 446 | ||
@@ -431,6 +448,7 @@ next_op: | |||
431 | if (unlikely(jsp <= 0)) | 448 | if (unlikely(jsp <= 0)) |
432 | goto jump_stack_underflow; | 449 | goto jump_stack_underflow; |
433 | pc = jump_stack[--jsp]; | 450 | pc = jump_stack[--jsp]; |
451 | flags |= FLAG_MATCHED | FLAG_LAST_MATCHED; | ||
434 | goto next_op; | 452 | goto next_op; |
435 | 453 | ||
436 | default: | 454 | default: |
@@ -438,7 +456,8 @@ next_op: | |||
438 | } | 456 | } |
439 | 457 | ||
440 | /* Shouldn't reach here */ | 458 | /* Shouldn't reach here */ |
441 | pr_err("ASN.1 decoder error: Found reserved opcode (%u)\n", op); | 459 | pr_err("ASN.1 decoder error: Found reserved opcode (%u) pc=%zu\n", |
460 | op, pc); | ||
442 | return -EBADMSG; | 461 | return -EBADMSG; |
443 | 462 | ||
444 | data_overrun_error: | 463 | data_overrun_error: |
diff --git a/scripts/.gitignore b/scripts/.gitignore index 5ecfe93f2028..12efbbefd4d7 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore | |||
@@ -10,3 +10,5 @@ recordmcount | |||
10 | docproc | 10 | docproc |
11 | sortextable | 11 | sortextable |
12 | asn1_compiler | 12 | asn1_compiler |
13 | extract-cert | ||
14 | sign-file | ||
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index d3437b82ac25..608ac65c61e3 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include | |||
@@ -303,3 +303,54 @@ why = \ | |||
303 | 303 | ||
304 | echo-why = $(call escsq, $(strip $(why))) | 304 | echo-why = $(call escsq, $(strip $(why))) |
305 | endif | 305 | endif |
306 | |||
307 | ############################################################################### | ||
308 | # | ||
309 | # When a Kconfig string contains a filename, it is suitable for | ||
310 | # passing to shell commands. It is surrounded by double-quotes, and | ||
311 | # any double-quotes or backslashes within it are escaped by | ||
312 | # backslashes. | ||
313 | # | ||
314 | # This is no use for dependencies or $(wildcard). We need to strip the | ||
315 | # surrounding quotes and the escaping from quotes and backslashes, and | ||
316 | # we *do* need to escape any spaces in the string. So, for example: | ||
317 | # | ||
318 | # Usage: $(eval $(call config_filename,FOO)) | ||
319 | # | ||
320 | # Defines FOO_FILENAME based on the contents of the CONFIG_FOO option, | ||
321 | # transformed as described above to be suitable for use within the | ||
322 | # makefile. | ||
323 | # | ||
324 | # Also, if the filename is a relative filename and exists in the source | ||
325 | # tree but not the build tree, define FOO_SRCPREFIX as $(srctree)/ to | ||
326 | # be prefixed to *both* command invocation and dependencies. | ||
327 | # | ||
328 | # Note: We also print the filenames in the quiet_cmd_foo text, and | ||
329 | # perhaps ought to have a version specially escaped for that purpose. | ||
330 | # But it's only cosmetic, and $(patsubst "%",%,$(CONFIG_FOO)) is good | ||
331 | # enough. It'll strip the quotes in the common case where there's no | ||
332 | # space and it's a simple filename, and it'll retain the quotes when | ||
333 | # there's a space. There are some esoteric cases in which it'll print | ||
334 | # the wrong thing, but we don't really care. The actual dependencies | ||
335 | # and commands *do* get it right, with various combinations of single | ||
336 | # and double quotes, backslashes and spaces in the filenames. | ||
337 | # | ||
338 | ############################################################################### | ||
339 | # | ||
340 | space_escape := %%%SPACE%%% | ||
341 | # | ||
342 | define config_filename | ||
343 | ifneq ($$(CONFIG_$(1)),"") | ||
344 | $(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1))))))) | ||
345 | ifneq ($$(patsubst /%,%,$$(firstword $$($(1)_FILENAME))),$$(firstword $$($(1)_FILENAME))) | ||
346 | else | ||
347 | ifeq ($$(wildcard $$($(1)_FILENAME)),) | ||
348 | ifneq ($$(wildcard $$(srctree)/$$($(1)_FILENAME)),) | ||
349 | $(1)_SRCPREFIX := $(srctree)/ | ||
350 | endif | ||
351 | endif | ||
352 | endif | ||
353 | endif | ||
354 | endef | ||
355 | # | ||
356 | ############################################################################### | ||
diff --git a/scripts/Makefile b/scripts/Makefile index 2016a64497ab..1b2661712d44 100644 --- a/scripts/Makefile +++ b/scripts/Makefile | |||
@@ -16,9 +16,13 @@ hostprogs-$(CONFIG_VT) += conmakehash | |||
16 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount | 16 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount |
17 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable | 17 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable |
18 | hostprogs-$(CONFIG_ASN1) += asn1_compiler | 18 | hostprogs-$(CONFIG_ASN1) += asn1_compiler |
19 | hostprogs-$(CONFIG_MODULE_SIG) += sign-file | ||
20 | hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert | ||
19 | 21 | ||
20 | HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include | 22 | HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include |
21 | HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include | 23 | HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include |
24 | HOSTLOADLIBES_sign-file = -lcrypto | ||
25 | HOSTLOADLIBES_extract-cert = -lcrypto | ||
22 | 26 | ||
23 | always := $(hostprogs-y) $(hostprogs-m) | 27 | always := $(hostprogs-y) $(hostprogs-m) |
24 | 28 | ||
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst index e48a4e9d8868..07650eeaaf06 100644 --- a/scripts/Makefile.modinst +++ b/scripts/Makefile.modinst | |||
@@ -22,7 +22,7 @@ quiet_cmd_modules_install = INSTALL $@ | |||
22 | mkdir -p $(2) ; \ | 22 | mkdir -p $(2) ; \ |
23 | cp $@ $(2) ; \ | 23 | cp $@ $(2) ; \ |
24 | $(mod_strip_cmd) $(2)/$(notdir $@) ; \ | 24 | $(mod_strip_cmd) $(2)/$(notdir $@) ; \ |
25 | $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) ; \ | 25 | $(mod_sign_cmd) $(2)/$(notdir $@) $(patsubst %,|| true,$(KBUILD_EXTMOD)) && \ |
26 | $(mod_compress_cmd) $(2)/$(notdir $@) | 26 | $(mod_compress_cmd) $(2)/$(notdir $@) |
27 | 27 | ||
28 | # Modules built outside the kernel source tree go into extra by default | 28 | # Modules built outside the kernel source tree go into extra by default |
diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c index 7750e9c31483..e000f44e37b8 100644 --- a/scripts/asn1_compiler.c +++ b/scripts/asn1_compiler.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <stdio.h> | 13 | #include <stdio.h> |
14 | #include <stdlib.h> | 14 | #include <stdlib.h> |
15 | #include <stdint.h> | 15 | #include <stdint.h> |
16 | #include <stdbool.h> | ||
16 | #include <string.h> | 17 | #include <string.h> |
17 | #include <ctype.h> | 18 | #include <ctype.h> |
18 | #include <unistd.h> | 19 | #include <unistd.h> |
@@ -293,8 +294,8 @@ static const char *const directives[NR__DIRECTIVES] = { | |||
293 | 294 | ||
294 | struct action { | 295 | struct action { |
295 | struct action *next; | 296 | struct action *next; |
297 | char *name; | ||
296 | unsigned char index; | 298 | unsigned char index; |
297 | char name[]; | ||
298 | }; | 299 | }; |
299 | 300 | ||
300 | static struct action *action_list; | 301 | static struct action *action_list; |
@@ -305,15 +306,17 @@ struct token { | |||
305 | enum token_type token_type : 8; | 306 | enum token_type token_type : 8; |
306 | unsigned char size; | 307 | unsigned char size; |
307 | struct action *action; | 308 | struct action *action; |
308 | const char *value; | 309 | char *content; |
309 | struct type *type; | 310 | struct type *type; |
310 | }; | 311 | }; |
311 | 312 | ||
312 | static struct token *token_list; | 313 | static struct token *token_list; |
313 | static unsigned nr_tokens; | 314 | static unsigned nr_tokens; |
314 | static _Bool verbose; | 315 | static bool verbose_opt; |
316 | static bool debug_opt; | ||
315 | 317 | ||
316 | #define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0) | 318 | #define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0) |
319 | #define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0) | ||
317 | 320 | ||
318 | static int directive_compare(const void *_key, const void *_pdir) | 321 | static int directive_compare(const void *_key, const void *_pdir) |
319 | { | 322 | { |
@@ -325,11 +328,9 @@ static int directive_compare(const void *_key, const void *_pdir) | |||
325 | dlen = strlen(dir); | 328 | dlen = strlen(dir); |
326 | clen = (dlen < token->size) ? dlen : token->size; | 329 | clen = (dlen < token->size) ? dlen : token->size; |
327 | 330 | ||
328 | //debug("cmp(%*.*s,%s) = ", | 331 | //debug("cmp(%s,%s) = ", token->content, dir); |
329 | // (int)token->size, (int)token->size, token->value, | ||
330 | // dir); | ||
331 | 332 | ||
332 | val = memcmp(token->value, dir, clen); | 333 | val = memcmp(token->content, dir, clen); |
333 | if (val != 0) { | 334 | if (val != 0) { |
334 | //debug("%d [cmp]\n", val); | 335 | //debug("%d [cmp]\n", val); |
335 | return val; | 336 | return val; |
@@ -349,7 +350,7 @@ static int directive_compare(const void *_key, const void *_pdir) | |||
349 | static void tokenise(char *buffer, char *end) | 350 | static void tokenise(char *buffer, char *end) |
350 | { | 351 | { |
351 | struct token *tokens; | 352 | struct token *tokens; |
352 | char *line, *nl, *p, *q; | 353 | char *line, *nl, *start, *p, *q; |
353 | unsigned tix, lineno; | 354 | unsigned tix, lineno; |
354 | 355 | ||
355 | /* Assume we're going to have half as many tokens as we have | 356 | /* Assume we're going to have half as many tokens as we have |
@@ -408,11 +409,11 @@ static void tokenise(char *buffer, char *end) | |||
408 | break; | 409 | break; |
409 | 410 | ||
410 | tokens[tix].line = lineno; | 411 | tokens[tix].line = lineno; |
411 | tokens[tix].value = p; | 412 | start = p; |
412 | 413 | ||
413 | /* Handle string tokens */ | 414 | /* Handle string tokens */ |
414 | if (isalpha(*p)) { | 415 | if (isalpha(*p)) { |
415 | const char **dir; | 416 | const char **dir, *start = p; |
416 | 417 | ||
417 | /* Can be a directive, type name or element | 418 | /* Can be a directive, type name or element |
418 | * name. Find the end of the name. | 419 | * name. Find the end of the name. |
@@ -423,10 +424,18 @@ static void tokenise(char *buffer, char *end) | |||
423 | tokens[tix].size = q - p; | 424 | tokens[tix].size = q - p; |
424 | p = q; | 425 | p = q; |
425 | 426 | ||
427 | tokens[tix].content = malloc(tokens[tix].size + 1); | ||
428 | if (!tokens[tix].content) { | ||
429 | perror(NULL); | ||
430 | exit(1); | ||
431 | } | ||
432 | memcpy(tokens[tix].content, start, tokens[tix].size); | ||
433 | tokens[tix].content[tokens[tix].size] = 0; | ||
434 | |||
426 | /* If it begins with a lowercase letter then | 435 | /* If it begins with a lowercase letter then |
427 | * it's an element name | 436 | * it's an element name |
428 | */ | 437 | */ |
429 | if (islower(tokens[tix].value[0])) { | 438 | if (islower(tokens[tix].content[0])) { |
430 | tokens[tix++].token_type = TOKEN_ELEMENT_NAME; | 439 | tokens[tix++].token_type = TOKEN_ELEMENT_NAME; |
431 | continue; | 440 | continue; |
432 | } | 441 | } |
@@ -455,6 +464,13 @@ static void tokenise(char *buffer, char *end) | |||
455 | q++; | 464 | q++; |
456 | tokens[tix].size = q - p; | 465 | tokens[tix].size = q - p; |
457 | p = q; | 466 | p = q; |
467 | tokens[tix].content = malloc(tokens[tix].size + 1); | ||
468 | if (!tokens[tix].content) { | ||
469 | perror(NULL); | ||
470 | exit(1); | ||
471 | } | ||
472 | memcpy(tokens[tix].content, start, tokens[tix].size); | ||
473 | tokens[tix].content[tokens[tix].size] = 0; | ||
458 | tokens[tix++].token_type = TOKEN_NUMBER; | 474 | tokens[tix++].token_type = TOKEN_NUMBER; |
459 | continue; | 475 | continue; |
460 | } | 476 | } |
@@ -463,6 +479,7 @@ static void tokenise(char *buffer, char *end) | |||
463 | if (memcmp(p, "::=", 3) == 0) { | 479 | if (memcmp(p, "::=", 3) == 0) { |
464 | p += 3; | 480 | p += 3; |
465 | tokens[tix].size = 3; | 481 | tokens[tix].size = 3; |
482 | tokens[tix].content = "::="; | ||
466 | tokens[tix++].token_type = TOKEN_ASSIGNMENT; | 483 | tokens[tix++].token_type = TOKEN_ASSIGNMENT; |
467 | continue; | 484 | continue; |
468 | } | 485 | } |
@@ -472,12 +489,14 @@ static void tokenise(char *buffer, char *end) | |||
472 | if (memcmp(p, "({", 2) == 0) { | 489 | if (memcmp(p, "({", 2) == 0) { |
473 | p += 2; | 490 | p += 2; |
474 | tokens[tix].size = 2; | 491 | tokens[tix].size = 2; |
492 | tokens[tix].content = "({"; | ||
475 | tokens[tix++].token_type = TOKEN_OPEN_ACTION; | 493 | tokens[tix++].token_type = TOKEN_OPEN_ACTION; |
476 | continue; | 494 | continue; |
477 | } | 495 | } |
478 | if (memcmp(p, "})", 2) == 0) { | 496 | if (memcmp(p, "})", 2) == 0) { |
479 | p += 2; | 497 | p += 2; |
480 | tokens[tix].size = 2; | 498 | tokens[tix].size = 2; |
499 | tokens[tix].content = "})"; | ||
481 | tokens[tix++].token_type = TOKEN_CLOSE_ACTION; | 500 | tokens[tix++].token_type = TOKEN_CLOSE_ACTION; |
482 | continue; | 501 | continue; |
483 | } | 502 | } |
@@ -488,22 +507,27 @@ static void tokenise(char *buffer, char *end) | |||
488 | switch (*p) { | 507 | switch (*p) { |
489 | case '{': | 508 | case '{': |
490 | p += 1; | 509 | p += 1; |
510 | tokens[tix].content = "{"; | ||
491 | tokens[tix++].token_type = TOKEN_OPEN_CURLY; | 511 | tokens[tix++].token_type = TOKEN_OPEN_CURLY; |
492 | continue; | 512 | continue; |
493 | case '}': | 513 | case '}': |
494 | p += 1; | 514 | p += 1; |
515 | tokens[tix].content = "}"; | ||
495 | tokens[tix++].token_type = TOKEN_CLOSE_CURLY; | 516 | tokens[tix++].token_type = TOKEN_CLOSE_CURLY; |
496 | continue; | 517 | continue; |
497 | case '[': | 518 | case '[': |
498 | p += 1; | 519 | p += 1; |
520 | tokens[tix].content = "["; | ||
499 | tokens[tix++].token_type = TOKEN_OPEN_SQUARE; | 521 | tokens[tix++].token_type = TOKEN_OPEN_SQUARE; |
500 | continue; | 522 | continue; |
501 | case ']': | 523 | case ']': |
502 | p += 1; | 524 | p += 1; |
525 | tokens[tix].content = "]"; | ||
503 | tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; | 526 | tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; |
504 | continue; | 527 | continue; |
505 | case ',': | 528 | case ',': |
506 | p += 1; | 529 | p += 1; |
530 | tokens[tix].content = ","; | ||
507 | tokens[tix++].token_type = TOKEN_COMMA; | 531 | tokens[tix++].token_type = TOKEN_COMMA; |
508 | continue; | 532 | continue; |
509 | default: | 533 | default: |
@@ -518,22 +542,20 @@ static void tokenise(char *buffer, char *end) | |||
518 | } | 542 | } |
519 | 543 | ||
520 | nr_tokens = tix; | 544 | nr_tokens = tix; |
521 | debug("Extracted %u tokens\n", nr_tokens); | 545 | verbose("Extracted %u tokens\n", nr_tokens); |
522 | 546 | ||
523 | #if 0 | 547 | #if 0 |
524 | { | 548 | { |
525 | int n; | 549 | int n; |
526 | for (n = 0; n < nr_tokens; n++) | 550 | for (n = 0; n < nr_tokens; n++) |
527 | debug("Token %3u: '%*.*s'\n", | 551 | debug("Token %3u: '%s'\n", n, token_list[n].content); |
528 | n, | ||
529 | (int)token_list[n].size, (int)token_list[n].size, | ||
530 | token_list[n].value); | ||
531 | } | 552 | } |
532 | #endif | 553 | #endif |
533 | } | 554 | } |
534 | 555 | ||
535 | static void build_type_list(void); | 556 | static void build_type_list(void); |
536 | static void parse(void); | 557 | static void parse(void); |
558 | static void dump_elements(void); | ||
537 | static void render(FILE *out, FILE *hdr); | 559 | static void render(FILE *out, FILE *hdr); |
538 | 560 | ||
539 | /* | 561 | /* |
@@ -548,16 +570,27 @@ int main(int argc, char **argv) | |||
548 | char *kbuild_verbose; | 570 | char *kbuild_verbose; |
549 | int fd; | 571 | int fd; |
550 | 572 | ||
573 | kbuild_verbose = getenv("KBUILD_VERBOSE"); | ||
574 | if (kbuild_verbose) | ||
575 | verbose_opt = atoi(kbuild_verbose); | ||
576 | |||
577 | while (argc > 4) { | ||
578 | if (strcmp(argv[1], "-v") == 0) | ||
579 | verbose_opt = true; | ||
580 | else if (strcmp(argv[1], "-d") == 0) | ||
581 | debug_opt = true; | ||
582 | else | ||
583 | break; | ||
584 | memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *)); | ||
585 | argc--; | ||
586 | } | ||
587 | |||
551 | if (argc != 4) { | 588 | if (argc != 4) { |
552 | fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n", | 589 | fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n", |
553 | argv[0]); | 590 | argv[0]); |
554 | exit(2); | 591 | exit(2); |
555 | } | 592 | } |
556 | 593 | ||
557 | kbuild_verbose = getenv("KBUILD_VERBOSE"); | ||
558 | if (kbuild_verbose) | ||
559 | verbose = atoi(kbuild_verbose); | ||
560 | |||
561 | filename = argv[1]; | 594 | filename = argv[1]; |
562 | outputname = argv[2]; | 595 | outputname = argv[2]; |
563 | headername = argv[3]; | 596 | headername = argv[3]; |
@@ -608,6 +641,7 @@ int main(int argc, char **argv) | |||
608 | tokenise(buffer, buffer + readlen); | 641 | tokenise(buffer, buffer + readlen); |
609 | build_type_list(); | 642 | build_type_list(); |
610 | parse(); | 643 | parse(); |
644 | dump_elements(); | ||
611 | 645 | ||
612 | out = fopen(outputname, "w"); | 646 | out = fopen(outputname, "w"); |
613 | if (!out) { | 647 | if (!out) { |
@@ -666,7 +700,7 @@ struct element { | |||
666 | unsigned flags; | 700 | unsigned flags; |
667 | #define ELEMENT_IMPLICIT 0x0001 | 701 | #define ELEMENT_IMPLICIT 0x0001 |
668 | #define ELEMENT_EXPLICIT 0x0002 | 702 | #define ELEMENT_EXPLICIT 0x0002 |
669 | #define ELEMENT_MARKED 0x0004 | 703 | #define ELEMENT_TAG_SPECIFIED 0x0004 |
670 | #define ELEMENT_RENDERED 0x0008 | 704 | #define ELEMENT_RENDERED 0x0008 |
671 | #define ELEMENT_SKIPPABLE 0x0010 | 705 | #define ELEMENT_SKIPPABLE 0x0010 |
672 | #define ELEMENT_CONDITIONAL 0x0020 | 706 | #define ELEMENT_CONDITIONAL 0x0020 |
@@ -693,7 +727,7 @@ static int type_index_compare(const void *_a, const void *_b) | |||
693 | if ((*a)->name->size != (*b)->name->size) | 727 | if ((*a)->name->size != (*b)->name->size) |
694 | return (*a)->name->size - (*b)->name->size; | 728 | return (*a)->name->size - (*b)->name->size; |
695 | else | 729 | else |
696 | return memcmp((*a)->name->value, (*b)->name->value, | 730 | return memcmp((*a)->name->content, (*b)->name->content, |
697 | (*a)->name->size); | 731 | (*a)->name->size); |
698 | } | 732 | } |
699 | 733 | ||
@@ -706,7 +740,7 @@ static int type_finder(const void *_key, const void *_ti) | |||
706 | if (token->size != type->name->size) | 740 | if (token->size != type->name->size) |
707 | return token->size - type->name->size; | 741 | return token->size - type->name->size; |
708 | else | 742 | else |
709 | return memcmp(token->value, type->name->value, | 743 | return memcmp(token->content, type->name->content, |
710 | token->size); | 744 | token->size); |
711 | } | 745 | } |
712 | 746 | ||
@@ -756,14 +790,11 @@ static void build_type_list(void) | |||
756 | 790 | ||
757 | qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); | 791 | qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); |
758 | 792 | ||
759 | debug("Extracted %u types\n", nr_types); | 793 | verbose("Extracted %u types\n", nr_types); |
760 | #if 0 | 794 | #if 0 |
761 | for (n = 0; n < nr_types; n++) { | 795 | for (n = 0; n < nr_types; n++) { |
762 | struct type *type = type_index[n]; | 796 | struct type *type = type_index[n]; |
763 | debug("- %*.*s\n", | 797 | debug("- %*.*s\n", type->name->content); |
764 | (int)type->name->size, | ||
765 | (int)type->name->size, | ||
766 | type->name->value); | ||
767 | } | 798 | } |
768 | #endif | 799 | #endif |
769 | } | 800 | } |
@@ -793,15 +824,14 @@ static void parse(void) | |||
793 | type->element->type_def = type; | 824 | type->element->type_def = type; |
794 | 825 | ||
795 | if (cursor != type[1].name) { | 826 | if (cursor != type[1].name) { |
796 | fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n", | 827 | fprintf(stderr, "%s:%d: Parse error at token '%s'\n", |
797 | filename, cursor->line, | 828 | filename, cursor->line, cursor->content); |
798 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
799 | exit(1); | 829 | exit(1); |
800 | } | 830 | } |
801 | 831 | ||
802 | } while (type++, !(type->flags & TYPE_STOP_MARKER)); | 832 | } while (type++, !(type->flags & TYPE_STOP_MARKER)); |
803 | 833 | ||
804 | debug("Extracted %u actions\n", nr_actions); | 834 | verbose("Extracted %u actions\n", nr_actions); |
805 | } | 835 | } |
806 | 836 | ||
807 | static struct element *element_list; | 837 | static struct element *element_list; |
@@ -862,33 +892,31 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
862 | cursor++; | 892 | cursor++; |
863 | break; | 893 | break; |
864 | default: | 894 | default: |
865 | fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n", | 895 | fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n", |
866 | filename, cursor->line, | 896 | filename, cursor->line, cursor->content); |
867 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
868 | exit(1); | 897 | exit(1); |
869 | } | 898 | } |
870 | 899 | ||
871 | if (cursor >= end) | 900 | if (cursor >= end) |
872 | goto overrun_error; | 901 | goto overrun_error; |
873 | if (cursor->token_type != TOKEN_NUMBER) { | 902 | if (cursor->token_type != TOKEN_NUMBER) { |
874 | fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n", | 903 | fprintf(stderr, "%s:%d: Missing tag number '%s'\n", |
875 | filename, cursor->line, | 904 | filename, cursor->line, cursor->content); |
876 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
877 | exit(1); | 905 | exit(1); |
878 | } | 906 | } |
879 | 907 | ||
880 | element->tag &= ~0x1f; | 908 | element->tag &= ~0x1f; |
881 | element->tag |= strtoul(cursor->value, &p, 10); | 909 | element->tag |= strtoul(cursor->content, &p, 10); |
882 | if (p - cursor->value != cursor->size) | 910 | element->flags |= ELEMENT_TAG_SPECIFIED; |
911 | if (p - cursor->content != cursor->size) | ||
883 | abort(); | 912 | abort(); |
884 | cursor++; | 913 | cursor++; |
885 | 914 | ||
886 | if (cursor >= end) | 915 | if (cursor >= end) |
887 | goto overrun_error; | 916 | goto overrun_error; |
888 | if (cursor->token_type != TOKEN_CLOSE_SQUARE) { | 917 | if (cursor->token_type != TOKEN_CLOSE_SQUARE) { |
889 | fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n", | 918 | fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n", |
890 | filename, cursor->line, | 919 | filename, cursor->line, cursor->content); |
891 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
892 | exit(1); | 920 | exit(1); |
893 | } | 921 | } |
894 | cursor++; | 922 | cursor++; |
@@ -988,9 +1016,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
988 | ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), | 1016 | ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), |
989 | type_finder); | 1017 | type_finder); |
990 | if (!ref) { | 1018 | if (!ref) { |
991 | fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n", | 1019 | fprintf(stderr, "%s:%d: Type '%s' undefined\n", |
992 | filename, cursor->line, | 1020 | filename, cursor->line, cursor->content); |
993 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
994 | exit(1); | 1021 | exit(1); |
995 | } | 1022 | } |
996 | cursor->type = *ref; | 1023 | cursor->type = *ref; |
@@ -1039,9 +1066,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
1039 | break; | 1066 | break; |
1040 | 1067 | ||
1041 | default: | 1068 | default: |
1042 | fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n", | 1069 | fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n", |
1043 | filename, cursor->line, | 1070 | filename, cursor->line, cursor->content); |
1044 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
1045 | exit(1); | 1071 | exit(1); |
1046 | } | 1072 | } |
1047 | 1073 | ||
@@ -1058,20 +1084,18 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
1058 | if (cursor >= end) | 1084 | if (cursor >= end) |
1059 | goto overrun_error; | 1085 | goto overrun_error; |
1060 | if (cursor->token_type != TOKEN_ELEMENT_NAME) { | 1086 | if (cursor->token_type != TOKEN_ELEMENT_NAME) { |
1061 | fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n", | 1087 | fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n", |
1062 | filename, cursor->line, | 1088 | filename, cursor->line, cursor->content); |
1063 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
1064 | exit(1); | 1089 | exit(1); |
1065 | } | 1090 | } |
1066 | 1091 | ||
1067 | action = malloc(sizeof(struct action) + cursor->size + 1); | 1092 | action = malloc(sizeof(struct action)); |
1068 | if (!action) { | 1093 | if (!action) { |
1069 | perror(NULL); | 1094 | perror(NULL); |
1070 | exit(1); | 1095 | exit(1); |
1071 | } | 1096 | } |
1072 | action->index = 0; | 1097 | action->index = 0; |
1073 | memcpy(action->name, cursor->value, cursor->size); | 1098 | action->name = cursor->content; |
1074 | action->name[cursor->size] = 0; | ||
1075 | 1099 | ||
1076 | for (ppaction = &action_list; | 1100 | for (ppaction = &action_list; |
1077 | *ppaction; | 1101 | *ppaction; |
@@ -1101,9 +1125,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
1101 | if (cursor >= end) | 1125 | if (cursor >= end) |
1102 | goto overrun_error; | 1126 | goto overrun_error; |
1103 | if (cursor->token_type != TOKEN_CLOSE_ACTION) { | 1127 | if (cursor->token_type != TOKEN_CLOSE_ACTION) { |
1104 | fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n", | 1128 | fprintf(stderr, "%s:%d: Missing close action, got '%s'\n", |
1105 | filename, cursor->line, | 1129 | filename, cursor->line, cursor->content); |
1106 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
1107 | exit(1); | 1130 | exit(1); |
1108 | } | 1131 | } |
1109 | cursor++; | 1132 | cursor++; |
@@ -1113,9 +1136,8 @@ static struct element *parse_type(struct token **_cursor, struct token *end, | |||
1113 | return top; | 1136 | return top; |
1114 | 1137 | ||
1115 | parse_error: | 1138 | parse_error: |
1116 | fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n", | 1139 | fprintf(stderr, "%s:%d: Unexpected token '%s'\n", |
1117 | filename, cursor->line, | 1140 | filename, cursor->line, cursor->content); |
1118 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
1119 | exit(1); | 1141 | exit(1); |
1120 | 1142 | ||
1121 | overrun_error: | 1143 | overrun_error: |
@@ -1133,9 +1155,8 @@ static struct element *parse_compound(struct token **_cursor, struct token *end, | |||
1133 | struct token *cursor = *_cursor, *name; | 1155 | struct token *cursor = *_cursor, *name; |
1134 | 1156 | ||
1135 | if (cursor->token_type != TOKEN_OPEN_CURLY) { | 1157 | if (cursor->token_type != TOKEN_OPEN_CURLY) { |
1136 | fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n", | 1158 | fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n", |
1137 | filename, cursor->line, | 1159 | filename, cursor->line, cursor->content); |
1138 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
1139 | exit(1); | 1160 | exit(1); |
1140 | } | 1161 | } |
1141 | cursor++; | 1162 | cursor++; |
@@ -1176,9 +1197,8 @@ static struct element *parse_compound(struct token **_cursor, struct token *end, | |||
1176 | children->flags &= ~ELEMENT_CONDITIONAL; | 1197 | children->flags &= ~ELEMENT_CONDITIONAL; |
1177 | 1198 | ||
1178 | if (cursor->token_type != TOKEN_CLOSE_CURLY) { | 1199 | if (cursor->token_type != TOKEN_CLOSE_CURLY) { |
1179 | fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n", | 1200 | fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n", |
1180 | filename, cursor->line, | 1201 | filename, cursor->line, cursor->content); |
1181 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
1182 | exit(1); | 1202 | exit(1); |
1183 | } | 1203 | } |
1184 | cursor++; | 1204 | cursor++; |
@@ -1191,6 +1211,52 @@ overrun_error: | |||
1191 | exit(1); | 1211 | exit(1); |
1192 | } | 1212 | } |
1193 | 1213 | ||
1214 | static void dump_element(const struct element *e, int level) | ||
1215 | { | ||
1216 | const struct element *c; | ||
1217 | const struct type *t = e->type_def; | ||
1218 | const char *name = e->name ? e->name->content : "."; | ||
1219 | const char *tname = t && t->name ? t->name->content : "."; | ||
1220 | char tag[32]; | ||
1221 | |||
1222 | if (e->class == 0 && e->method == 0 && e->tag == 0) | ||
1223 | strcpy(tag, "<...>"); | ||
1224 | else if (e->class == ASN1_UNIV) | ||
1225 | sprintf(tag, "%s %s %s", | ||
1226 | asn1_classes[e->class], | ||
1227 | asn1_methods[e->method], | ||
1228 | asn1_universal_tags[e->tag]); | ||
1229 | else | ||
1230 | sprintf(tag, "%s %s %u", | ||
1231 | asn1_classes[e->class], | ||
1232 | asn1_methods[e->method], | ||
1233 | e->tag); | ||
1234 | |||
1235 | printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n", | ||
1236 | e->flags & ELEMENT_IMPLICIT ? 'I' : '-', | ||
1237 | e->flags & ELEMENT_EXPLICIT ? 'E' : '-', | ||
1238 | e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-', | ||
1239 | e->flags & ELEMENT_SKIPPABLE ? 'S' : '-', | ||
1240 | e->flags & ELEMENT_CONDITIONAL ? 'C' : '-', | ||
1241 | "-tTqQcaro"[e->compound], | ||
1242 | level, "", | ||
1243 | tag, | ||
1244 | tname, | ||
1245 | name, | ||
1246 | e->action ? e->action->name : ""); | ||
1247 | if (e->compound == TYPE_REF) | ||
1248 | dump_element(e->type->type->element, level + 3); | ||
1249 | else | ||
1250 | for (c = e->children; c; c = c->next) | ||
1251 | dump_element(c, level + 3); | ||
1252 | } | ||
1253 | |||
1254 | static void dump_elements(void) | ||
1255 | { | ||
1256 | if (debug_opt) | ||
1257 | dump_element(type_list[0].element, 0); | ||
1258 | } | ||
1259 | |||
1194 | static void render_element(FILE *out, struct element *e, struct element *tag); | 1260 | static void render_element(FILE *out, struct element *e, struct element *tag); |
1195 | static void render_out_of_line_list(FILE *out); | 1261 | static void render_out_of_line_list(FILE *out); |
1196 | 1262 | ||
@@ -1292,7 +1358,7 @@ static void render(FILE *out, FILE *hdr) | |||
1292 | } | 1358 | } |
1293 | 1359 | ||
1294 | /* We do two passes - the first one calculates all the offsets */ | 1360 | /* We do two passes - the first one calculates all the offsets */ |
1295 | debug("Pass 1\n"); | 1361 | verbose("Pass 1\n"); |
1296 | nr_entries = 0; | 1362 | nr_entries = 0; |
1297 | root = &type_list[0]; | 1363 | root = &type_list[0]; |
1298 | render_element(NULL, root->element, NULL); | 1364 | render_element(NULL, root->element, NULL); |
@@ -1303,7 +1369,7 @@ static void render(FILE *out, FILE *hdr) | |||
1303 | e->flags &= ~ELEMENT_RENDERED; | 1369 | e->flags &= ~ELEMENT_RENDERED; |
1304 | 1370 | ||
1305 | /* And then we actually render */ | 1371 | /* And then we actually render */ |
1306 | debug("Pass 2\n"); | 1372 | verbose("Pass 2\n"); |
1307 | fprintf(out, "\n"); | 1373 | fprintf(out, "\n"); |
1308 | fprintf(out, "static const unsigned char %s_machine[] = {\n", | 1374 | fprintf(out, "static const unsigned char %s_machine[] = {\n", |
1309 | grammar_name); | 1375 | grammar_name); |
@@ -1376,7 +1442,7 @@ static void render_out_of_line_list(FILE *out) | |||
1376 | */ | 1442 | */ |
1377 | static void render_element(FILE *out, struct element *e, struct element *tag) | 1443 | static void render_element(FILE *out, struct element *e, struct element *tag) |
1378 | { | 1444 | { |
1379 | struct element *ec; | 1445 | struct element *ec, *x; |
1380 | const char *cond, *act; | 1446 | const char *cond, *act; |
1381 | int entry, skippable = 0, outofline = 0; | 1447 | int entry, skippable = 0, outofline = 0; |
1382 | 1448 | ||
@@ -1389,9 +1455,7 @@ static void render_element(FILE *out, struct element *e, struct element *tag) | |||
1389 | outofline = 1; | 1455 | outofline = 1; |
1390 | 1456 | ||
1391 | if (e->type_def && out) { | 1457 | if (e->type_def && out) { |
1392 | render_more(out, "\t// %*.*s\n", | 1458 | render_more(out, "\t// %s\n", e->type_def->name->content); |
1393 | (int)e->type_def->name->size, (int)e->type_def->name->size, | ||
1394 | e->type_def->name->value); | ||
1395 | } | 1459 | } |
1396 | 1460 | ||
1397 | /* Render the operation */ | 1461 | /* Render the operation */ |
@@ -1400,11 +1464,10 @@ static void render_element(FILE *out, struct element *e, struct element *tag) | |||
1400 | act = e->action ? "_ACT" : ""; | 1464 | act = e->action ? "_ACT" : ""; |
1401 | switch (e->compound) { | 1465 | switch (e->compound) { |
1402 | case ANY: | 1466 | case ANY: |
1403 | render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act); | 1467 | render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,", |
1468 | cond, act, skippable ? "_OR_SKIP" : ""); | ||
1404 | if (e->name) | 1469 | if (e->name) |
1405 | render_more(out, "\t\t// %*.*s", | 1470 | render_more(out, "\t\t// %s", e->name->content); |
1406 | (int)e->name->size, (int)e->name->size, | ||
1407 | e->name->value); | ||
1408 | render_more(out, "\n"); | 1471 | render_more(out, "\n"); |
1409 | goto dont_render_tag; | 1472 | goto dont_render_tag; |
1410 | 1473 | ||
@@ -1435,15 +1498,15 @@ static void render_element(FILE *out, struct element *e, struct element *tag) | |||
1435 | break; | 1498 | break; |
1436 | } | 1499 | } |
1437 | 1500 | ||
1438 | if (e->name) | 1501 | x = tag ?: e; |
1439 | render_more(out, "\t\t// %*.*s", | 1502 | if (x->name) |
1440 | (int)e->name->size, (int)e->name->size, | 1503 | render_more(out, "\t\t// %s", x->name->content); |
1441 | e->name->value); | ||
1442 | render_more(out, "\n"); | 1504 | render_more(out, "\n"); |
1443 | 1505 | ||
1444 | /* Render the tag */ | 1506 | /* Render the tag */ |
1445 | if (!tag) | 1507 | if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED)) |
1446 | tag = e; | 1508 | tag = e; |
1509 | |||
1447 | if (tag->class == ASN1_UNIV && | 1510 | if (tag->class == ASN1_UNIV && |
1448 | tag->tag != 14 && | 1511 | tag->tag != 14 && |
1449 | tag->tag != 15 && | 1512 | tag->tag != 15 && |
@@ -1465,7 +1528,8 @@ dont_render_tag: | |||
1465 | case TYPE_REF: | 1528 | case TYPE_REF: |
1466 | render_element(out, e->type->type->element, tag); | 1529 | render_element(out, e->type->type->element, tag); |
1467 | if (e->action) | 1530 | if (e->action) |
1468 | render_opcode(out, "ASN1_OP_ACT,\n"); | 1531 | render_opcode(out, "ASN1_OP_%sACT,\n", |
1532 | skippable ? "MAYBE_" : ""); | ||
1469 | break; | 1533 | break; |
1470 | 1534 | ||
1471 | case SEQUENCE: | 1535 | case SEQUENCE: |
@@ -1474,10 +1538,8 @@ dont_render_tag: | |||
1474 | * skipability */ | 1538 | * skipability */ |
1475 | render_opcode(out, "_jump_target(%u),", e->entry_index); | 1539 | render_opcode(out, "_jump_target(%u),", e->entry_index); |
1476 | if (e->type_def && e->type_def->name) | 1540 | if (e->type_def && e->type_def->name) |
1477 | render_more(out, "\t\t// --> %*.*s", | 1541 | render_more(out, "\t\t// --> %s", |
1478 | (int)e->type_def->name->size, | 1542 | e->type_def->name->content); |
1479 | (int)e->type_def->name->size, | ||
1480 | e->type_def->name->value); | ||
1481 | render_more(out, "\n"); | 1543 | render_more(out, "\n"); |
1482 | if (!(e->flags & ELEMENT_RENDERED)) { | 1544 | if (!(e->flags & ELEMENT_RENDERED)) { |
1483 | e->flags |= ELEMENT_RENDERED; | 1545 | e->flags |= ELEMENT_RENDERED; |
@@ -1502,10 +1564,8 @@ dont_render_tag: | |||
1502 | * skipability */ | 1564 | * skipability */ |
1503 | render_opcode(out, "_jump_target(%u),", e->entry_index); | 1565 | render_opcode(out, "_jump_target(%u),", e->entry_index); |
1504 | if (e->type_def && e->type_def->name) | 1566 | if (e->type_def && e->type_def->name) |
1505 | render_more(out, "\t\t// --> %*.*s", | 1567 | render_more(out, "\t\t// --> %s", |
1506 | (int)e->type_def->name->size, | 1568 | e->type_def->name->content); |
1507 | (int)e->type_def->name->size, | ||
1508 | e->type_def->name->value); | ||
1509 | render_more(out, "\n"); | 1569 | render_more(out, "\n"); |
1510 | if (!(e->flags & ELEMENT_RENDERED)) { | 1570 | if (!(e->flags & ELEMENT_RENDERED)) { |
1511 | e->flags |= ELEMENT_RENDERED; | 1571 | e->flags |= ELEMENT_RENDERED; |
@@ -1539,7 +1599,7 @@ dont_render_tag: | |||
1539 | 1599 | ||
1540 | case CHOICE: | 1600 | case CHOICE: |
1541 | for (ec = e->children; ec; ec = ec->next) | 1601 | for (ec = e->children; ec; ec = ec->next) |
1542 | render_element(out, ec, NULL); | 1602 | render_element(out, ec, ec); |
1543 | if (!skippable) | 1603 | if (!skippable) |
1544 | render_opcode(out, "ASN1_OP_COND_FAIL,\n"); | 1604 | render_opcode(out, "ASN1_OP_COND_FAIL,\n"); |
1545 | if (e->action) | 1605 | if (e->action) |
diff --git a/scripts/extract-cert.c b/scripts/extract-cert.c new file mode 100644 index 000000000000..fd0db015c65c --- /dev/null +++ b/scripts/extract-cert.c | |||
@@ -0,0 +1,166 @@ | |||
1 | /* Extract X.509 certificate in DER form from PKCS#11 or PEM. | ||
2 | * | ||
3 | * Copyright © 2014 Red Hat, Inc. All Rights Reserved. | ||
4 | * Copyright © 2015 Intel Corporation. | ||
5 | * | ||
6 | * Authors: David Howells <dhowells@redhat.com> | ||
7 | * David Woodhouse <dwmw2@infradead.org> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public Licence | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the Licence, or (at your option) any later version. | ||
13 | */ | ||
14 | #define _GNU_SOURCE | ||
15 | #include <stdio.h> | ||
16 | #include <stdlib.h> | ||
17 | #include <stdint.h> | ||
18 | #include <stdbool.h> | ||
19 | #include <string.h> | ||
20 | #include <getopt.h> | ||
21 | #include <err.h> | ||
22 | #include <arpa/inet.h> | ||
23 | #include <openssl/bio.h> | ||
24 | #include <openssl/evp.h> | ||
25 | #include <openssl/pem.h> | ||
26 | #include <openssl/pkcs7.h> | ||
27 | #include <openssl/err.h> | ||
28 | #include <openssl/engine.h> | ||
29 | |||
30 | #define PKEY_ID_PKCS7 2 | ||
31 | |||
32 | static __attribute__((noreturn)) | ||
33 | void format(void) | ||
34 | { | ||
35 | fprintf(stderr, | ||
36 | "Usage: scripts/extract-cert <source> <dest>\n"); | ||
37 | exit(2); | ||
38 | } | ||
39 | |||
40 | static void display_openssl_errors(int l) | ||
41 | { | ||
42 | const char *file; | ||
43 | char buf[120]; | ||
44 | int e, line; | ||
45 | |||
46 | if (ERR_peek_error() == 0) | ||
47 | return; | ||
48 | fprintf(stderr, "At main.c:%d:\n", l); | ||
49 | |||
50 | while ((e = ERR_get_error_line(&file, &line))) { | ||
51 | ERR_error_string(e, buf); | ||
52 | fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | static void drain_openssl_errors(void) | ||
57 | { | ||
58 | const char *file; | ||
59 | int line; | ||
60 | |||
61 | if (ERR_peek_error() == 0) | ||
62 | return; | ||
63 | while (ERR_get_error_line(&file, &line)) {} | ||
64 | } | ||
65 | |||
66 | #define ERR(cond, fmt, ...) \ | ||
67 | do { \ | ||
68 | bool __cond = (cond); \ | ||
69 | display_openssl_errors(__LINE__); \ | ||
70 | if (__cond) { \ | ||
71 | err(1, fmt, ## __VA_ARGS__); \ | ||
72 | } \ | ||
73 | } while(0) | ||
74 | |||
75 | static const char *key_pass; | ||
76 | static BIO *wb; | ||
77 | static char *cert_dst; | ||
78 | int kbuild_verbose; | ||
79 | |||
80 | static void write_cert(X509 *x509) | ||
81 | { | ||
82 | char buf[200]; | ||
83 | |||
84 | if (!wb) { | ||
85 | wb = BIO_new_file(cert_dst, "wb"); | ||
86 | ERR(!wb, "%s", cert_dst); | ||
87 | } | ||
88 | X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); | ||
89 | ERR(!i2d_X509_bio(wb, x509), cert_dst); | ||
90 | if (kbuild_verbose) | ||
91 | fprintf(stderr, "Extracted cert: %s\n", buf); | ||
92 | } | ||
93 | |||
94 | int main(int argc, char **argv) | ||
95 | { | ||
96 | char *cert_src; | ||
97 | |||
98 | OpenSSL_add_all_algorithms(); | ||
99 | ERR_load_crypto_strings(); | ||
100 | ERR_clear_error(); | ||
101 | |||
102 | kbuild_verbose = atoi(getenv("KBUILD_VERBOSE")?:"0"); | ||
103 | |||
104 | key_pass = getenv("KBUILD_SIGN_PIN"); | ||
105 | |||
106 | if (argc != 3) | ||
107 | format(); | ||
108 | |||
109 | cert_src = argv[1]; | ||
110 | cert_dst = argv[2]; | ||
111 | |||
112 | if (!cert_src[0]) { | ||
113 | /* Invoked with no input; create empty file */ | ||
114 | FILE *f = fopen(cert_dst, "wb"); | ||
115 | ERR(!f, "%s", cert_dst); | ||
116 | fclose(f); | ||
117 | exit(0); | ||
118 | } else if (!strncmp(cert_src, "pkcs11:", 7)) { | ||
119 | ENGINE *e; | ||
120 | struct { | ||
121 | const char *cert_id; | ||
122 | X509 *cert; | ||
123 | } parms; | ||
124 | |||
125 | parms.cert_id = cert_src; | ||
126 | parms.cert = NULL; | ||
127 | |||
128 | ENGINE_load_builtin_engines(); | ||
129 | drain_openssl_errors(); | ||
130 | e = ENGINE_by_id("pkcs11"); | ||
131 | ERR(!e, "Load PKCS#11 ENGINE"); | ||
132 | if (ENGINE_init(e)) | ||
133 | drain_openssl_errors(); | ||
134 | else | ||
135 | ERR(1, "ENGINE_init"); | ||
136 | if (key_pass) | ||
137 | ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); | ||
138 | ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 1); | ||
139 | ERR(!parms.cert, "Get X.509 from PKCS#11"); | ||
140 | write_cert(parms.cert); | ||
141 | } else { | ||
142 | BIO *b; | ||
143 | X509 *x509; | ||
144 | |||
145 | b = BIO_new_file(cert_src, "rb"); | ||
146 | ERR(!b, "%s", cert_src); | ||
147 | |||
148 | while (1) { | ||
149 | x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); | ||
150 | if (wb && !x509) { | ||
151 | unsigned long err = ERR_peek_last_error(); | ||
152 | if (ERR_GET_LIB(err) == ERR_LIB_PEM && | ||
153 | ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { | ||
154 | ERR_clear_error(); | ||
155 | break; | ||
156 | } | ||
157 | } | ||
158 | ERR(!x509, "%s", cert_src); | ||
159 | write_cert(x509); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | BIO_free(wb); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c index 62b34ce1f50d..e10beb11b696 100644 --- a/scripts/selinux/mdp/mdp.c +++ b/scripts/selinux/mdp/mdp.c | |||
@@ -98,6 +98,7 @@ int main(int argc, char *argv[]) | |||
98 | 98 | ||
99 | /* types, roles, and allows */ | 99 | /* types, roles, and allows */ |
100 | fprintf(fout, "type base_t;\n"); | 100 | fprintf(fout, "type base_t;\n"); |
101 | fprintf(fout, "role base_r;\n"); | ||
101 | fprintf(fout, "role base_r types { base_t };\n"); | 102 | fprintf(fout, "role base_r types { base_t };\n"); |
102 | for (i = 0; secclass_map[i].name; i++) | 103 | for (i = 0; secclass_map[i].name; i++) |
103 | fprintf(fout, "allow base_t base_t:%s *;\n", | 104 | fprintf(fout, "allow base_t base_t:%s *;\n", |
diff --git a/scripts/sign-file b/scripts/sign-file deleted file mode 100755 index 3906ee1e2f76..000000000000 --- a/scripts/sign-file +++ /dev/null | |||
@@ -1,421 +0,0 @@ | |||
1 | #!/usr/bin/perl -w | ||
2 | # | ||
3 | # Sign a module file using the given key. | ||
4 | # | ||
5 | |||
6 | my $USAGE = | ||
7 | "Usage: scripts/sign-file [-v] <hash algo> <key> <x509> <module> [<dest>]\n" . | ||
8 | " scripts/sign-file [-v] -s <raw sig> <hash algo> <x509> <module> [<dest>]\n"; | ||
9 | |||
10 | use strict; | ||
11 | use FileHandle; | ||
12 | use IPC::Open2; | ||
13 | use Getopt::Std; | ||
14 | |||
15 | my %opts; | ||
16 | getopts('vs:', \%opts) or die $USAGE; | ||
17 | my $verbose = $opts{'v'}; | ||
18 | my $signature_file = $opts{'s'}; | ||
19 | |||
20 | die $USAGE if ($#ARGV > 4); | ||
21 | die $USAGE if (!$signature_file && $#ARGV < 3 || $signature_file && $#ARGV < 2); | ||
22 | |||
23 | my $dgst = shift @ARGV; | ||
24 | my $private_key; | ||
25 | if (!$signature_file) { | ||
26 | $private_key = shift @ARGV; | ||
27 | } | ||
28 | my $x509 = shift @ARGV; | ||
29 | my $module = shift @ARGV; | ||
30 | my ($dest, $keep_orig); | ||
31 | if (@ARGV) { | ||
32 | $dest = $ARGV[0]; | ||
33 | $keep_orig = 1; | ||
34 | } else { | ||
35 | $dest = $module . "~"; | ||
36 | } | ||
37 | |||
38 | die "Can't read private key\n" if (!$signature_file && !-r $private_key); | ||
39 | die "Can't read signature file\n" if ($signature_file && !-r $signature_file); | ||
40 | die "Can't read X.509 certificate\n" unless (-r $x509); | ||
41 | die "Can't read module\n" unless (-r $module); | ||
42 | |||
43 | # | ||
44 | # Function to read the contents of a file into a variable. | ||
45 | # | ||
46 | sub read_file($) | ||
47 | { | ||
48 | my ($file) = @_; | ||
49 | my $contents; | ||
50 | my $len; | ||
51 | |||
52 | open(FD, "<$file") || die $file; | ||
53 | binmode FD; | ||
54 | my @st = stat(FD); | ||
55 | die $file if (!@st); | ||
56 | $len = read(FD, $contents, $st[7]) || die $file; | ||
57 | close(FD) || die $file; | ||
58 | die "$file: Wanted length ", $st[7], ", got ", $len, "\n" | ||
59 | if ($len != $st[7]); | ||
60 | return $contents; | ||
61 | } | ||
62 | |||
63 | ############################################################################### | ||
64 | # | ||
65 | # First of all, we have to parse the X.509 certificate to find certain details | ||
66 | # about it. | ||
67 | # | ||
68 | # We read the DER-encoded X509 certificate and parse it to extract the Subject | ||
69 | # name and Subject Key Identifier. Theis provides the data we need to build | ||
70 | # the certificate identifier. | ||
71 | # | ||
72 | # The signer's name part of the identifier is fabricated from the commonName, | ||
73 | # the organizationName or the emailAddress components of the X.509 subject | ||
74 | # name. | ||
75 | # | ||
76 | # The subject key ID is used to select which of that signer's certificates | ||
77 | # we're intending to use to sign the module. | ||
78 | # | ||
79 | ############################################################################### | ||
80 | my $x509_certificate = read_file($x509); | ||
81 | |||
82 | my $UNIV = 0 << 6; | ||
83 | my $APPL = 1 << 6; | ||
84 | my $CONT = 2 << 6; | ||
85 | my $PRIV = 3 << 6; | ||
86 | |||
87 | my $CONS = 0x20; | ||
88 | |||
89 | my $BOOLEAN = 0x01; | ||
90 | my $INTEGER = 0x02; | ||
91 | my $BIT_STRING = 0x03; | ||
92 | my $OCTET_STRING = 0x04; | ||
93 | my $NULL = 0x05; | ||
94 | my $OBJ_ID = 0x06; | ||
95 | my $UTF8String = 0x0c; | ||
96 | my $SEQUENCE = 0x10; | ||
97 | my $SET = 0x11; | ||
98 | my $UTCTime = 0x17; | ||
99 | my $GeneralizedTime = 0x18; | ||
100 | |||
101 | my %OIDs = ( | ||
102 | pack("CCC", 85, 4, 3) => "commonName", | ||
103 | pack("CCC", 85, 4, 6) => "countryName", | ||
104 | pack("CCC", 85, 4, 10) => "organizationName", | ||
105 | pack("CCC", 85, 4, 11) => "organizationUnitName", | ||
106 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption", | ||
107 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption", | ||
108 | pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress", | ||
109 | pack("CCC", 85, 29, 35) => "authorityKeyIdentifier", | ||
110 | pack("CCC", 85, 29, 14) => "subjectKeyIdentifier", | ||
111 | pack("CCC", 85, 29, 19) => "basicConstraints" | ||
112 | ); | ||
113 | |||
114 | ############################################################################### | ||
115 | # | ||
116 | # Extract an ASN.1 element from a string and return information about it. | ||
117 | # | ||
118 | ############################################################################### | ||
119 | sub asn1_extract($$@) | ||
120 | { | ||
121 | my ($cursor, $expected_tag, $optional) = @_; | ||
122 | |||
123 | return [ -1 ] | ||
124 | if ($cursor->[1] == 0 && $optional); | ||
125 | |||
126 | die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n" | ||
127 | if ($cursor->[1] < 2); | ||
128 | |||
129 | my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2)); | ||
130 | |||
131 | if ($expected_tag != -1 && $tag != $expected_tag) { | ||
132 | return [ -1 ] | ||
133 | if ($optional); | ||
134 | die $x509, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag, | ||
135 | " not ", $expected_tag, ")\n"; | ||
136 | } | ||
137 | |||
138 | $cursor->[0] += 2; | ||
139 | $cursor->[1] -= 2; | ||
140 | |||
141 | die $x509, ": ", $cursor->[0], ": ASN.1 long tag\n" | ||
142 | if (($tag & 0x1f) == 0x1f); | ||
143 | die $x509, ": ", $cursor->[0], ": ASN.1 indefinite length\n" | ||
144 | if ($len == 0x80); | ||
145 | |||
146 | if ($len > 0x80) { | ||
147 | my $l = $len - 0x80; | ||
148 | die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n" | ||
149 | if ($cursor->[1] < $l); | ||
150 | |||
151 | if ($l == 0x1) { | ||
152 | $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)); | ||
153 | } elsif ($l == 0x2) { | ||
154 | $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2)); | ||
155 | } elsif ($l == 0x3) { | ||
156 | $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16; | ||
157 | $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2)); | ||
158 | } elsif ($l == 0x4) { | ||
159 | $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4)); | ||
160 | } else { | ||
161 | die $x509, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n"; | ||
162 | } | ||
163 | |||
164 | $cursor->[0] += $l; | ||
165 | $cursor->[1] -= $l; | ||
166 | } | ||
167 | |||
168 | die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n" | ||
169 | if ($cursor->[1] < $len); | ||
170 | |||
171 | my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ]; | ||
172 | $cursor->[0] += $len; | ||
173 | $cursor->[1] -= $len; | ||
174 | |||
175 | return $ret; | ||
176 | } | ||
177 | |||
178 | ############################################################################### | ||
179 | # | ||
180 | # Retrieve the data referred to by a cursor | ||
181 | # | ||
182 | ############################################################################### | ||
183 | sub asn1_retrieve($) | ||
184 | { | ||
185 | my ($cursor) = @_; | ||
186 | my ($offset, $len, $data) = @$cursor; | ||
187 | return substr($$data, $offset, $len); | ||
188 | } | ||
189 | |||
190 | ############################################################################### | ||
191 | # | ||
192 | # Roughly parse the X.509 certificate | ||
193 | # | ||
194 | ############################################################################### | ||
195 | my $cursor = [ 0, length($x509_certificate), \$x509_certificate ]; | ||
196 | |||
197 | my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE); | ||
198 | my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE); | ||
199 | my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1); | ||
200 | my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER); | ||
201 | my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
202 | my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
203 | my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
204 | my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
205 | my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE); | ||
206 | my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1); | ||
207 | my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1); | ||
208 | my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1); | ||
209 | |||
210 | my $subject_key_id = (); | ||
211 | my $authority_key_id = (); | ||
212 | |||
213 | # | ||
214 | # Parse the extension list | ||
215 | # | ||
216 | if ($extension_list->[0] != -1) { | ||
217 | my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE); | ||
218 | |||
219 | while ($extensions->[1]->[1] > 0) { | ||
220 | my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE); | ||
221 | my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID); | ||
222 | my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1); | ||
223 | my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING); | ||
224 | |||
225 | my $raw_oid = asn1_retrieve($x_oid->[1]); | ||
226 | next if (!exists($OIDs{$raw_oid})); | ||
227 | my $x_type = $OIDs{$raw_oid}; | ||
228 | |||
229 | my $raw_value = asn1_retrieve($x_val->[1]); | ||
230 | |||
231 | if ($x_type eq "subjectKeyIdentifier") { | ||
232 | my $vcursor = [ 0, length($raw_value), \$raw_value ]; | ||
233 | |||
234 | $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING); | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | |||
239 | ############################################################################### | ||
240 | # | ||
241 | # Determine what we're going to use as the signer's name. In order of | ||
242 | # preference, take one of: commonName, organizationName or emailAddress. | ||
243 | # | ||
244 | ############################################################################### | ||
245 | my $org = ""; | ||
246 | my $cn = ""; | ||
247 | my $email = ""; | ||
248 | |||
249 | while ($subject->[1]->[1] > 0) { | ||
250 | my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET); | ||
251 | my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE); | ||
252 | my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID); | ||
253 | my $n_val = asn1_extract($attr->[1], -1); | ||
254 | |||
255 | my $raw_oid = asn1_retrieve($n_oid->[1]); | ||
256 | next if (!exists($OIDs{$raw_oid})); | ||
257 | my $n_type = $OIDs{$raw_oid}; | ||
258 | |||
259 | my $raw_value = asn1_retrieve($n_val->[1]); | ||
260 | |||
261 | if ($n_type eq "organizationName") { | ||
262 | $org = $raw_value; | ||
263 | } elsif ($n_type eq "commonName") { | ||
264 | $cn = $raw_value; | ||
265 | } elsif ($n_type eq "emailAddress") { | ||
266 | $email = $raw_value; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | my $signers_name = $email; | ||
271 | |||
272 | if ($org && $cn) { | ||
273 | # Don't use the organizationName if the commonName repeats it | ||
274 | if (length($org) <= length($cn) && | ||
275 | substr($cn, 0, length($org)) eq $org) { | ||
276 | $signers_name = $cn; | ||
277 | goto got_id_name; | ||
278 | } | ||
279 | |||
280 | # Or a signifcant chunk of it | ||
281 | if (length($org) >= 7 && | ||
282 | length($cn) >= 7 && | ||
283 | substr($cn, 0, 7) eq substr($org, 0, 7)) { | ||
284 | $signers_name = $cn; | ||
285 | goto got_id_name; | ||
286 | } | ||
287 | |||
288 | $signers_name = $org . ": " . $cn; | ||
289 | } elsif ($org) { | ||
290 | $signers_name = $org; | ||
291 | } elsif ($cn) { | ||
292 | $signers_name = $cn; | ||
293 | } | ||
294 | |||
295 | got_id_name: | ||
296 | |||
297 | die $x509, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n" | ||
298 | if (!$subject_key_id); | ||
299 | |||
300 | my $key_identifier = asn1_retrieve($subject_key_id->[1]); | ||
301 | |||
302 | ############################################################################### | ||
303 | # | ||
304 | # Create and attach the module signature | ||
305 | # | ||
306 | ############################################################################### | ||
307 | |||
308 | # | ||
309 | # Signature parameters | ||
310 | # | ||
311 | my $algo = 1; # Public-key crypto algorithm: RSA | ||
312 | my $hash = 0; # Digest algorithm | ||
313 | my $id_type = 1; # Identifier type: X.509 | ||
314 | |||
315 | # | ||
316 | # Digest the data | ||
317 | # | ||
318 | my $prologue; | ||
319 | if ($dgst eq "sha1") { | ||
320 | $prologue = pack("C*", | ||
321 | 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, | ||
322 | 0x2B, 0x0E, 0x03, 0x02, 0x1A, | ||
323 | 0x05, 0x00, 0x04, 0x14); | ||
324 | $hash = 2; | ||
325 | } elsif ($dgst eq "sha224") { | ||
326 | $prologue = pack("C*", | ||
327 | 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, | ||
328 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, | ||
329 | 0x05, 0x00, 0x04, 0x1C); | ||
330 | $hash = 7; | ||
331 | } elsif ($dgst eq "sha256") { | ||
332 | $prologue = pack("C*", | ||
333 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, | ||
334 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, | ||
335 | 0x05, 0x00, 0x04, 0x20); | ||
336 | $hash = 4; | ||
337 | } elsif ($dgst eq "sha384") { | ||
338 | $prologue = pack("C*", | ||
339 | 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, | ||
340 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, | ||
341 | 0x05, 0x00, 0x04, 0x30); | ||
342 | $hash = 5; | ||
343 | } elsif ($dgst eq "sha512") { | ||
344 | $prologue = pack("C*", | ||
345 | 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, | ||
346 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, | ||
347 | 0x05, 0x00, 0x04, 0x40); | ||
348 | $hash = 6; | ||
349 | } else { | ||
350 | die "Unknown hash algorithm: $dgst\n"; | ||
351 | } | ||
352 | |||
353 | my $signature; | ||
354 | if ($signature_file) { | ||
355 | $signature = read_file($signature_file); | ||
356 | } else { | ||
357 | # | ||
358 | # Generate the digest and read from openssl's stdout | ||
359 | # | ||
360 | my $digest; | ||
361 | $digest = readpipe("openssl dgst -$dgst -binary $module") || die "openssl dgst"; | ||
362 | |||
363 | # | ||
364 | # Generate the binary signature, which will be just the integer that | ||
365 | # comprises the signature with no metadata attached. | ||
366 | # | ||
367 | my $pid; | ||
368 | $pid = open2(*read_from, *write_to, | ||
369 | "openssl rsautl -sign -inkey $private_key -keyform PEM") || | ||
370 | die "openssl rsautl"; | ||
371 | binmode write_to; | ||
372 | print write_to $prologue . $digest || die "pipe to openssl rsautl"; | ||
373 | close(write_to) || die "pipe to openssl rsautl"; | ||
374 | |||
375 | binmode read_from; | ||
376 | read(read_from, $signature, 4096) || die "pipe from openssl rsautl"; | ||
377 | close(read_from) || die "pipe from openssl rsautl"; | ||
378 | waitpid($pid, 0) || die; | ||
379 | die "openssl rsautl died: $?" if ($? >> 8); | ||
380 | } | ||
381 | $signature = pack("n", length($signature)) . $signature, | ||
382 | |||
383 | # | ||
384 | # Build the signed binary | ||
385 | # | ||
386 | my $unsigned_module = read_file($module); | ||
387 | |||
388 | my $magic_number = "~Module signature appended~\n"; | ||
389 | |||
390 | my $info = pack("CCCCCxxxN", | ||
391 | $algo, $hash, $id_type, | ||
392 | length($signers_name), | ||
393 | length($key_identifier), | ||
394 | length($signature)); | ||
395 | |||
396 | if ($verbose) { | ||
397 | print "Size of unsigned module: ", length($unsigned_module), "\n"; | ||
398 | print "Size of signer's name : ", length($signers_name), "\n"; | ||
399 | print "Size of key identifier : ", length($key_identifier), "\n"; | ||
400 | print "Size of signature : ", length($signature), "\n"; | ||
401 | print "Size of information : ", length($info), "\n"; | ||
402 | print "Size of magic number : ", length($magic_number), "\n"; | ||
403 | print "Signer's name : '", $signers_name, "'\n"; | ||
404 | print "Digest : $dgst\n"; | ||
405 | } | ||
406 | |||
407 | open(FD, ">$dest") || die $dest; | ||
408 | binmode FD; | ||
409 | print FD | ||
410 | $unsigned_module, | ||
411 | $signers_name, | ||
412 | $key_identifier, | ||
413 | $signature, | ||
414 | $info, | ||
415 | $magic_number | ||
416 | ; | ||
417 | close FD || die $dest; | ||
418 | |||
419 | if (!$keep_orig) { | ||
420 | rename($dest, $module) || die $module; | ||
421 | } | ||
diff --git a/scripts/sign-file.c b/scripts/sign-file.c new file mode 100755 index 000000000000..058bba3103e2 --- /dev/null +++ b/scripts/sign-file.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* Sign a module file using the given key. | ||
2 | * | ||
3 | * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | #define _GNU_SOURCE | ||
12 | #include <stdio.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <stdint.h> | ||
15 | #include <stdbool.h> | ||
16 | #include <string.h> | ||
17 | #include <getopt.h> | ||
18 | #include <err.h> | ||
19 | #include <arpa/inet.h> | ||
20 | #include <openssl/bio.h> | ||
21 | #include <openssl/evp.h> | ||
22 | #include <openssl/pem.h> | ||
23 | #include <openssl/cms.h> | ||
24 | #include <openssl/err.h> | ||
25 | #include <openssl/engine.h> | ||
26 | |||
27 | struct module_signature { | ||
28 | uint8_t algo; /* Public-key crypto algorithm [0] */ | ||
29 | uint8_t hash; /* Digest algorithm [0] */ | ||
30 | uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */ | ||
31 | uint8_t signer_len; /* Length of signer's name [0] */ | ||
32 | uint8_t key_id_len; /* Length of key identifier [0] */ | ||
33 | uint8_t __pad[3]; | ||
34 | uint32_t sig_len; /* Length of signature data */ | ||
35 | }; | ||
36 | |||
37 | #define PKEY_ID_PKCS7 2 | ||
38 | |||
39 | static char magic_number[] = "~Module signature appended~\n"; | ||
40 | |||
41 | static __attribute__((noreturn)) | ||
42 | void format(void) | ||
43 | { | ||
44 | fprintf(stderr, | ||
45 | "Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n"); | ||
46 | exit(2); | ||
47 | } | ||
48 | |||
49 | static void display_openssl_errors(int l) | ||
50 | { | ||
51 | const char *file; | ||
52 | char buf[120]; | ||
53 | int e, line; | ||
54 | |||
55 | if (ERR_peek_error() == 0) | ||
56 | return; | ||
57 | fprintf(stderr, "At main.c:%d:\n", l); | ||
58 | |||
59 | while ((e = ERR_get_error_line(&file, &line))) { | ||
60 | ERR_error_string(e, buf); | ||
61 | fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); | ||
62 | } | ||
63 | } | ||
64 | |||
65 | static void drain_openssl_errors(void) | ||
66 | { | ||
67 | const char *file; | ||
68 | int line; | ||
69 | |||
70 | if (ERR_peek_error() == 0) | ||
71 | return; | ||
72 | while (ERR_get_error_line(&file, &line)) {} | ||
73 | } | ||
74 | |||
75 | #define ERR(cond, fmt, ...) \ | ||
76 | do { \ | ||
77 | bool __cond = (cond); \ | ||
78 | display_openssl_errors(__LINE__); \ | ||
79 | if (__cond) { \ | ||
80 | err(1, fmt, ## __VA_ARGS__); \ | ||
81 | } \ | ||
82 | } while(0) | ||
83 | |||
84 | static const char *key_pass; | ||
85 | |||
86 | static int pem_pw_cb(char *buf, int len, int w, void *v) | ||
87 | { | ||
88 | int pwlen; | ||
89 | |||
90 | if (!key_pass) | ||
91 | return -1; | ||
92 | |||
93 | pwlen = strlen(key_pass); | ||
94 | if (pwlen >= len) | ||
95 | return -1; | ||
96 | |||
97 | strcpy(buf, key_pass); | ||
98 | |||
99 | /* If it's wrong, don't keep trying it. */ | ||
100 | key_pass = NULL; | ||
101 | |||
102 | return pwlen; | ||
103 | } | ||
104 | |||
105 | int main(int argc, char **argv) | ||
106 | { | ||
107 | struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 }; | ||
108 | char *hash_algo = NULL; | ||
109 | char *private_key_name, *x509_name, *module_name, *dest_name; | ||
110 | bool save_cms = false, replace_orig; | ||
111 | bool sign_only = false; | ||
112 | unsigned char buf[4096]; | ||
113 | unsigned long module_size, cms_size; | ||
114 | unsigned int use_keyid = 0, use_signed_attrs = CMS_NOATTR; | ||
115 | const EVP_MD *digest_algo; | ||
116 | EVP_PKEY *private_key; | ||
117 | CMS_ContentInfo *cms; | ||
118 | X509 *x509; | ||
119 | BIO *b, *bd = NULL, *bm; | ||
120 | int opt, n; | ||
121 | |||
122 | OpenSSL_add_all_algorithms(); | ||
123 | ERR_load_crypto_strings(); | ||
124 | ERR_clear_error(); | ||
125 | |||
126 | key_pass = getenv("KBUILD_SIGN_PIN"); | ||
127 | |||
128 | do { | ||
129 | opt = getopt(argc, argv, "dpk"); | ||
130 | switch (opt) { | ||
131 | case 'p': save_cms = true; break; | ||
132 | case 'd': sign_only = true; save_cms = true; break; | ||
133 | case 'k': use_keyid = CMS_USE_KEYID; break; | ||
134 | case -1: break; | ||
135 | default: format(); | ||
136 | } | ||
137 | } while (opt != -1); | ||
138 | |||
139 | argc -= optind; | ||
140 | argv += optind; | ||
141 | if (argc < 4 || argc > 5) | ||
142 | format(); | ||
143 | |||
144 | hash_algo = argv[0]; | ||
145 | private_key_name = argv[1]; | ||
146 | x509_name = argv[2]; | ||
147 | module_name = argv[3]; | ||
148 | if (argc == 5) { | ||
149 | dest_name = argv[4]; | ||
150 | replace_orig = false; | ||
151 | } else { | ||
152 | ERR(asprintf(&dest_name, "%s.~signed~", module_name) < 0, | ||
153 | "asprintf"); | ||
154 | replace_orig = true; | ||
155 | } | ||
156 | |||
157 | /* Read the private key and the X.509 cert the PKCS#7 message | ||
158 | * will point to. | ||
159 | */ | ||
160 | if (!strncmp(private_key_name, "pkcs11:", 7)) { | ||
161 | ENGINE *e; | ||
162 | |||
163 | ENGINE_load_builtin_engines(); | ||
164 | drain_openssl_errors(); | ||
165 | e = ENGINE_by_id("pkcs11"); | ||
166 | ERR(!e, "Load PKCS#11 ENGINE"); | ||
167 | if (ENGINE_init(e)) | ||
168 | drain_openssl_errors(); | ||
169 | else | ||
170 | ERR(1, "ENGINE_init"); | ||
171 | if (key_pass) | ||
172 | ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN"); | ||
173 | private_key = ENGINE_load_private_key(e, private_key_name, NULL, | ||
174 | NULL); | ||
175 | ERR(!private_key, "%s", private_key_name); | ||
176 | } else { | ||
177 | b = BIO_new_file(private_key_name, "rb"); | ||
178 | ERR(!b, "%s", private_key_name); | ||
179 | private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, NULL); | ||
180 | ERR(!private_key, "%s", private_key_name); | ||
181 | BIO_free(b); | ||
182 | } | ||
183 | |||
184 | b = BIO_new_file(x509_name, "rb"); | ||
185 | ERR(!b, "%s", x509_name); | ||
186 | x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */ | ||
187 | if (!x509) { | ||
188 | ERR(BIO_reset(b) != 1, "%s", x509_name); | ||
189 | x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); /* PEM encoded X.509 */ | ||
190 | if (x509) | ||
191 | drain_openssl_errors(); | ||
192 | } | ||
193 | BIO_free(b); | ||
194 | ERR(!x509, "%s", x509_name); | ||
195 | |||
196 | /* Open the destination file now so that we can shovel the module data | ||
197 | * across as we read it. | ||
198 | */ | ||
199 | if (!sign_only) { | ||
200 | bd = BIO_new_file(dest_name, "wb"); | ||
201 | ERR(!bd, "%s", dest_name); | ||
202 | } | ||
203 | |||
204 | /* Digest the module data. */ | ||
205 | OpenSSL_add_all_digests(); | ||
206 | display_openssl_errors(__LINE__); | ||
207 | digest_algo = EVP_get_digestbyname(hash_algo); | ||
208 | ERR(!digest_algo, "EVP_get_digestbyname"); | ||
209 | |||
210 | bm = BIO_new_file(module_name, "rb"); | ||
211 | ERR(!bm, "%s", module_name); | ||
212 | |||
213 | /* Load the CMS message from the digest buffer. */ | ||
214 | cms = CMS_sign(NULL, NULL, NULL, NULL, | ||
215 | CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED | CMS_STREAM); | ||
216 | ERR(!cms, "CMS_sign"); | ||
217 | |||
218 | ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, | ||
219 | CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP | | ||
220 | use_keyid | use_signed_attrs), | ||
221 | "CMS_sign_add_signer"); | ||
222 | ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0, | ||
223 | "CMS_final"); | ||
224 | |||
225 | if (save_cms) { | ||
226 | char *cms_name; | ||
227 | |||
228 | ERR(asprintf(&cms_name, "%s.p7s", module_name) < 0, "asprintf"); | ||
229 | b = BIO_new_file(cms_name, "wb"); | ||
230 | ERR(!b, "%s", cms_name); | ||
231 | ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0, "%s", cms_name); | ||
232 | BIO_free(b); | ||
233 | } | ||
234 | |||
235 | if (sign_only) | ||
236 | return 0; | ||
237 | |||
238 | /* Append the marker and the PKCS#7 message to the destination file */ | ||
239 | ERR(BIO_reset(bm) < 0, "%s", module_name); | ||
240 | while ((n = BIO_read(bm, buf, sizeof(buf))), | ||
241 | n > 0) { | ||
242 | ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name); | ||
243 | } | ||
244 | ERR(n < 0, "%s", module_name); | ||
245 | module_size = BIO_number_written(bd); | ||
246 | |||
247 | ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name); | ||
248 | cms_size = BIO_number_written(bd) - module_size; | ||
249 | sig_info.sig_len = htonl(cms_size); | ||
250 | ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name); | ||
251 | ERR(BIO_write(bd, magic_number, sizeof(magic_number) - 1) < 0, "%s", dest_name); | ||
252 | |||
253 | ERR(BIO_free(bd) < 0, "%s", dest_name); | ||
254 | |||
255 | /* Finally, if we're signing in place, replace the original. */ | ||
256 | if (replace_orig) | ||
257 | ERR(rename(dest_name, module_name) < 0, "%s", dest_name); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
diff --git a/security/Kconfig b/security/Kconfig index bf4ec46474b6..e45237897b43 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -132,7 +132,6 @@ choice | |||
132 | default DEFAULT_SECURITY_SMACK if SECURITY_SMACK | 132 | default DEFAULT_SECURITY_SMACK if SECURITY_SMACK |
133 | default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO | 133 | default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO |
134 | default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR | 134 | default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR |
135 | default DEFAULT_SECURITY_YAMA if SECURITY_YAMA | ||
136 | default DEFAULT_SECURITY_DAC | 135 | default DEFAULT_SECURITY_DAC |
137 | 136 | ||
138 | help | 137 | help |
@@ -151,9 +150,6 @@ choice | |||
151 | config DEFAULT_SECURITY_APPARMOR | 150 | config DEFAULT_SECURITY_APPARMOR |
152 | bool "AppArmor" if SECURITY_APPARMOR=y | 151 | bool "AppArmor" if SECURITY_APPARMOR=y |
153 | 152 | ||
154 | config DEFAULT_SECURITY_YAMA | ||
155 | bool "Yama" if SECURITY_YAMA=y | ||
156 | |||
157 | config DEFAULT_SECURITY_DAC | 153 | config DEFAULT_SECURITY_DAC |
158 | bool "Unix Discretionary Access Controls" | 154 | bool "Unix Discretionary Access Controls" |
159 | 155 | ||
@@ -165,7 +161,6 @@ config DEFAULT_SECURITY | |||
165 | default "smack" if DEFAULT_SECURITY_SMACK | 161 | default "smack" if DEFAULT_SECURITY_SMACK |
166 | default "tomoyo" if DEFAULT_SECURITY_TOMOYO | 162 | default "tomoyo" if DEFAULT_SECURITY_TOMOYO |
167 | default "apparmor" if DEFAULT_SECURITY_APPARMOR | 163 | default "apparmor" if DEFAULT_SECURITY_APPARMOR |
168 | default "yama" if DEFAULT_SECURITY_YAMA | ||
169 | default "" if DEFAULT_SECURITY_DAC | 164 | default "" if DEFAULT_SECURITY_DAC |
170 | 165 | ||
171 | endmenu | 166 | endmenu |
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 4ed98107ace3..cccbf3068cdc 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c | |||
@@ -245,6 +245,21 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
245 | } | 245 | } |
246 | break; | 246 | break; |
247 | } | 247 | } |
248 | case LSM_AUDIT_DATA_IOCTL_OP: { | ||
249 | struct inode *inode; | ||
250 | |||
251 | audit_log_d_path(ab, " path=", &a->u.op->path); | ||
252 | |||
253 | inode = a->u.op->path.dentry->d_inode; | ||
254 | if (inode) { | ||
255 | audit_log_format(ab, " dev="); | ||
256 | audit_log_untrustedstring(ab, inode->i_sb->s_id); | ||
257 | audit_log_format(ab, " ino=%lu", inode->i_ino); | ||
258 | } | ||
259 | |||
260 | audit_log_format(ab, " ioctlcmd=%hx", a->u.op->cmd); | ||
261 | break; | ||
262 | } | ||
248 | case LSM_AUDIT_DATA_DENTRY: { | 263 | case LSM_AUDIT_DATA_DENTRY: { |
249 | struct inode *inode; | 264 | struct inode *inode; |
250 | 265 | ||
diff --git a/security/security.c b/security/security.c index 75b85fdc4e97..46f405ce6b0f 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -56,18 +56,13 @@ int __init security_init(void) | |||
56 | pr_info("Security Framework initialized\n"); | 56 | pr_info("Security Framework initialized\n"); |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Always load the capability module. | 59 | * Load minor LSMs, with the capability module always first. |
60 | */ | 60 | */ |
61 | capability_add_hooks(); | 61 | capability_add_hooks(); |
62 | #ifdef CONFIG_SECURITY_YAMA_STACKED | ||
63 | /* | ||
64 | * If Yama is configured for stacking load it next. | ||
65 | */ | ||
66 | yama_add_hooks(); | 62 | yama_add_hooks(); |
67 | #endif | 63 | |
68 | /* | 64 | /* |
69 | * Load the chosen module if there is one. | 65 | * Load all the remaining security modules. |
70 | * This will also find yama if it is stacking | ||
71 | */ | 66 | */ |
72 | do_security_initcalls(); | 67 | do_security_initcalls(); |
73 | 68 | ||
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 0b122b1421a9..e60c79de13e1 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/skbuff.h> | 23 | #include <linux/skbuff.h> |
24 | #include <linux/percpu.h> | 24 | #include <linux/percpu.h> |
25 | #include <linux/list.h> | ||
25 | #include <net/sock.h> | 26 | #include <net/sock.h> |
26 | #include <linux/un.h> | 27 | #include <linux/un.h> |
27 | #include <net/af_unix.h> | 28 | #include <net/af_unix.h> |
@@ -48,6 +49,7 @@ struct avc_entry { | |||
48 | u32 tsid; | 49 | u32 tsid; |
49 | u16 tclass; | 50 | u16 tclass; |
50 | struct av_decision avd; | 51 | struct av_decision avd; |
52 | struct avc_xperms_node *xp_node; | ||
51 | }; | 53 | }; |
52 | 54 | ||
53 | struct avc_node { | 55 | struct avc_node { |
@@ -56,6 +58,16 @@ struct avc_node { | |||
56 | struct rcu_head rhead; | 58 | struct rcu_head rhead; |
57 | }; | 59 | }; |
58 | 60 | ||
61 | struct avc_xperms_decision_node { | ||
62 | struct extended_perms_decision xpd; | ||
63 | struct list_head xpd_list; /* list of extended_perms_decision */ | ||
64 | }; | ||
65 | |||
66 | struct avc_xperms_node { | ||
67 | struct extended_perms xp; | ||
68 | struct list_head xpd_head; /* list head of extended_perms_decision */ | ||
69 | }; | ||
70 | |||
59 | struct avc_cache { | 71 | struct avc_cache { |
60 | struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ | 72 | struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ |
61 | spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ | 73 | spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ |
@@ -80,6 +92,9 @@ DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; | |||
80 | static struct avc_cache avc_cache; | 92 | static struct avc_cache avc_cache; |
81 | static struct avc_callback_node *avc_callbacks; | 93 | static struct avc_callback_node *avc_callbacks; |
82 | static struct kmem_cache *avc_node_cachep; | 94 | static struct kmem_cache *avc_node_cachep; |
95 | static struct kmem_cache *avc_xperms_data_cachep; | ||
96 | static struct kmem_cache *avc_xperms_decision_cachep; | ||
97 | static struct kmem_cache *avc_xperms_cachep; | ||
83 | 98 | ||
84 | static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) | 99 | static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) |
85 | { | 100 | { |
@@ -101,6 +116,7 @@ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) | |||
101 | return; | 116 | return; |
102 | } | 117 | } |
103 | 118 | ||
119 | BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); | ||
104 | perms = secclass_map[tclass-1].perms; | 120 | perms = secclass_map[tclass-1].perms; |
105 | 121 | ||
106 | audit_log_format(ab, " {"); | 122 | audit_log_format(ab, " {"); |
@@ -149,7 +165,7 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla | |||
149 | kfree(scontext); | 165 | kfree(scontext); |
150 | } | 166 | } |
151 | 167 | ||
152 | BUG_ON(tclass >= ARRAY_SIZE(secclass_map)); | 168 | BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); |
153 | audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name); | 169 | audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name); |
154 | } | 170 | } |
155 | 171 | ||
@@ -170,7 +186,17 @@ void __init avc_init(void) | |||
170 | atomic_set(&avc_cache.lru_hint, 0); | 186 | atomic_set(&avc_cache.lru_hint, 0); |
171 | 187 | ||
172 | avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), | 188 | avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), |
173 | 0, SLAB_PANIC, NULL); | 189 | 0, SLAB_PANIC, NULL); |
190 | avc_xperms_cachep = kmem_cache_create("avc_xperms_node", | ||
191 | sizeof(struct avc_xperms_node), | ||
192 | 0, SLAB_PANIC, NULL); | ||
193 | avc_xperms_decision_cachep = kmem_cache_create( | ||
194 | "avc_xperms_decision_node", | ||
195 | sizeof(struct avc_xperms_decision_node), | ||
196 | 0, SLAB_PANIC, NULL); | ||
197 | avc_xperms_data_cachep = kmem_cache_create("avc_xperms_data", | ||
198 | sizeof(struct extended_perms_data), | ||
199 | 0, SLAB_PANIC, NULL); | ||
174 | 200 | ||
175 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); | 201 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); |
176 | } | 202 | } |
@@ -205,9 +231,261 @@ int avc_get_hash_stats(char *page) | |||
205 | slots_used, AVC_CACHE_SLOTS, max_chain_len); | 231 | slots_used, AVC_CACHE_SLOTS, max_chain_len); |
206 | } | 232 | } |
207 | 233 | ||
234 | /* | ||
235 | * using a linked list for extended_perms_decision lookup because the list is | ||
236 | * always small. i.e. less than 5, typically 1 | ||
237 | */ | ||
238 | static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver, | ||
239 | struct avc_xperms_node *xp_node) | ||
240 | { | ||
241 | struct avc_xperms_decision_node *xpd_node; | ||
242 | |||
243 | list_for_each_entry(xpd_node, &xp_node->xpd_head, xpd_list) { | ||
244 | if (xpd_node->xpd.driver == driver) | ||
245 | return &xpd_node->xpd; | ||
246 | } | ||
247 | return NULL; | ||
248 | } | ||
249 | |||
250 | static inline unsigned int | ||
251 | avc_xperms_has_perm(struct extended_perms_decision *xpd, | ||
252 | u8 perm, u8 which) | ||
253 | { | ||
254 | unsigned int rc = 0; | ||
255 | |||
256 | if ((which == XPERMS_ALLOWED) && | ||
257 | (xpd->used & XPERMS_ALLOWED)) | ||
258 | rc = security_xperm_test(xpd->allowed->p, perm); | ||
259 | else if ((which == XPERMS_AUDITALLOW) && | ||
260 | (xpd->used & XPERMS_AUDITALLOW)) | ||
261 | rc = security_xperm_test(xpd->auditallow->p, perm); | ||
262 | else if ((which == XPERMS_DONTAUDIT) && | ||
263 | (xpd->used & XPERMS_DONTAUDIT)) | ||
264 | rc = security_xperm_test(xpd->dontaudit->p, perm); | ||
265 | return rc; | ||
266 | } | ||
267 | |||
268 | static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node, | ||
269 | u8 driver, u8 perm) | ||
270 | { | ||
271 | struct extended_perms_decision *xpd; | ||
272 | security_xperm_set(xp_node->xp.drivers.p, driver); | ||
273 | xpd = avc_xperms_decision_lookup(driver, xp_node); | ||
274 | if (xpd && xpd->allowed) | ||
275 | security_xperm_set(xpd->allowed->p, perm); | ||
276 | } | ||
277 | |||
278 | static void avc_xperms_decision_free(struct avc_xperms_decision_node *xpd_node) | ||
279 | { | ||
280 | struct extended_perms_decision *xpd; | ||
281 | |||
282 | xpd = &xpd_node->xpd; | ||
283 | if (xpd->allowed) | ||
284 | kmem_cache_free(avc_xperms_data_cachep, xpd->allowed); | ||
285 | if (xpd->auditallow) | ||
286 | kmem_cache_free(avc_xperms_data_cachep, xpd->auditallow); | ||
287 | if (xpd->dontaudit) | ||
288 | kmem_cache_free(avc_xperms_data_cachep, xpd->dontaudit); | ||
289 | kmem_cache_free(avc_xperms_decision_cachep, xpd_node); | ||
290 | } | ||
291 | |||
292 | static void avc_xperms_free(struct avc_xperms_node *xp_node) | ||
293 | { | ||
294 | struct avc_xperms_decision_node *xpd_node, *tmp; | ||
295 | |||
296 | if (!xp_node) | ||
297 | return; | ||
298 | |||
299 | list_for_each_entry_safe(xpd_node, tmp, &xp_node->xpd_head, xpd_list) { | ||
300 | list_del(&xpd_node->xpd_list); | ||
301 | avc_xperms_decision_free(xpd_node); | ||
302 | } | ||
303 | kmem_cache_free(avc_xperms_cachep, xp_node); | ||
304 | } | ||
305 | |||
306 | static void avc_copy_xperms_decision(struct extended_perms_decision *dest, | ||
307 | struct extended_perms_decision *src) | ||
308 | { | ||
309 | dest->driver = src->driver; | ||
310 | dest->used = src->used; | ||
311 | if (dest->used & XPERMS_ALLOWED) | ||
312 | memcpy(dest->allowed->p, src->allowed->p, | ||
313 | sizeof(src->allowed->p)); | ||
314 | if (dest->used & XPERMS_AUDITALLOW) | ||
315 | memcpy(dest->auditallow->p, src->auditallow->p, | ||
316 | sizeof(src->auditallow->p)); | ||
317 | if (dest->used & XPERMS_DONTAUDIT) | ||
318 | memcpy(dest->dontaudit->p, src->dontaudit->p, | ||
319 | sizeof(src->dontaudit->p)); | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * similar to avc_copy_xperms_decision, but only copy decision | ||
324 | * information relevant to this perm | ||
325 | */ | ||
326 | static inline void avc_quick_copy_xperms_decision(u8 perm, | ||
327 | struct extended_perms_decision *dest, | ||
328 | struct extended_perms_decision *src) | ||
329 | { | ||
330 | /* | ||
331 | * compute index of the u32 of the 256 bits (8 u32s) that contain this | ||
332 | * command permission | ||
333 | */ | ||
334 | u8 i = perm >> 5; | ||
335 | |||
336 | dest->used = src->used; | ||
337 | if (dest->used & XPERMS_ALLOWED) | ||
338 | dest->allowed->p[i] = src->allowed->p[i]; | ||
339 | if (dest->used & XPERMS_AUDITALLOW) | ||
340 | dest->auditallow->p[i] = src->auditallow->p[i]; | ||
341 | if (dest->used & XPERMS_DONTAUDIT) | ||
342 | dest->dontaudit->p[i] = src->dontaudit->p[i]; | ||
343 | } | ||
344 | |||
345 | static struct avc_xperms_decision_node | ||
346 | *avc_xperms_decision_alloc(u8 which) | ||
347 | { | ||
348 | struct avc_xperms_decision_node *xpd_node; | ||
349 | struct extended_perms_decision *xpd; | ||
350 | |||
351 | xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, | ||
352 | GFP_ATOMIC | __GFP_NOMEMALLOC); | ||
353 | if (!xpd_node) | ||
354 | return NULL; | ||
355 | |||
356 | xpd = &xpd_node->xpd; | ||
357 | if (which & XPERMS_ALLOWED) { | ||
358 | xpd->allowed = kmem_cache_zalloc(avc_xperms_data_cachep, | ||
359 | GFP_ATOMIC | __GFP_NOMEMALLOC); | ||
360 | if (!xpd->allowed) | ||
361 | goto error; | ||
362 | } | ||
363 | if (which & XPERMS_AUDITALLOW) { | ||
364 | xpd->auditallow = kmem_cache_zalloc(avc_xperms_data_cachep, | ||
365 | GFP_ATOMIC | __GFP_NOMEMALLOC); | ||
366 | if (!xpd->auditallow) | ||
367 | goto error; | ||
368 | } | ||
369 | if (which & XPERMS_DONTAUDIT) { | ||
370 | xpd->dontaudit = kmem_cache_zalloc(avc_xperms_data_cachep, | ||
371 | GFP_ATOMIC | __GFP_NOMEMALLOC); | ||
372 | if (!xpd->dontaudit) | ||
373 | goto error; | ||
374 | } | ||
375 | return xpd_node; | ||
376 | error: | ||
377 | avc_xperms_decision_free(xpd_node); | ||
378 | return NULL; | ||
379 | } | ||
380 | |||
381 | static int avc_add_xperms_decision(struct avc_node *node, | ||
382 | struct extended_perms_decision *src) | ||
383 | { | ||
384 | struct avc_xperms_decision_node *dest_xpd; | ||
385 | |||
386 | node->ae.xp_node->xp.len++; | ||
387 | dest_xpd = avc_xperms_decision_alloc(src->used); | ||
388 | if (!dest_xpd) | ||
389 | return -ENOMEM; | ||
390 | avc_copy_xperms_decision(&dest_xpd->xpd, src); | ||
391 | list_add(&dest_xpd->xpd_list, &node->ae.xp_node->xpd_head); | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static struct avc_xperms_node *avc_xperms_alloc(void) | ||
396 | { | ||
397 | struct avc_xperms_node *xp_node; | ||
398 | |||
399 | xp_node = kmem_cache_zalloc(avc_xperms_cachep, | ||
400 | GFP_ATOMIC|__GFP_NOMEMALLOC); | ||
401 | if (!xp_node) | ||
402 | return xp_node; | ||
403 | INIT_LIST_HEAD(&xp_node->xpd_head); | ||
404 | return xp_node; | ||
405 | } | ||
406 | |||
407 | static int avc_xperms_populate(struct avc_node *node, | ||
408 | struct avc_xperms_node *src) | ||
409 | { | ||
410 | struct avc_xperms_node *dest; | ||
411 | struct avc_xperms_decision_node *dest_xpd; | ||
412 | struct avc_xperms_decision_node *src_xpd; | ||
413 | |||
414 | if (src->xp.len == 0) | ||
415 | return 0; | ||
416 | dest = avc_xperms_alloc(); | ||
417 | if (!dest) | ||
418 | return -ENOMEM; | ||
419 | |||
420 | memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p)); | ||
421 | dest->xp.len = src->xp.len; | ||
422 | |||
423 | /* for each source xpd allocate a destination xpd and copy */ | ||
424 | list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) { | ||
425 | dest_xpd = avc_xperms_decision_alloc(src_xpd->xpd.used); | ||
426 | if (!dest_xpd) | ||
427 | goto error; | ||
428 | avc_copy_xperms_decision(&dest_xpd->xpd, &src_xpd->xpd); | ||
429 | list_add(&dest_xpd->xpd_list, &dest->xpd_head); | ||
430 | } | ||
431 | node->ae.xp_node = dest; | ||
432 | return 0; | ||
433 | error: | ||
434 | avc_xperms_free(dest); | ||
435 | return -ENOMEM; | ||
436 | |||
437 | } | ||
438 | |||
439 | static inline u32 avc_xperms_audit_required(u32 requested, | ||
440 | struct av_decision *avd, | ||
441 | struct extended_perms_decision *xpd, | ||
442 | u8 perm, | ||
443 | int result, | ||
444 | u32 *deniedp) | ||
445 | { | ||
446 | u32 denied, audited; | ||
447 | |||
448 | denied = requested & ~avd->allowed; | ||
449 | if (unlikely(denied)) { | ||
450 | audited = denied & avd->auditdeny; | ||
451 | if (audited && xpd) { | ||
452 | if (avc_xperms_has_perm(xpd, perm, XPERMS_DONTAUDIT)) | ||
453 | audited &= ~requested; | ||
454 | } | ||
455 | } else if (result) { | ||
456 | audited = denied = requested; | ||
457 | } else { | ||
458 | audited = requested & avd->auditallow; | ||
459 | if (audited && xpd) { | ||
460 | if (!avc_xperms_has_perm(xpd, perm, XPERMS_AUDITALLOW)) | ||
461 | audited &= ~requested; | ||
462 | } | ||
463 | } | ||
464 | |||
465 | *deniedp = denied; | ||
466 | return audited; | ||
467 | } | ||
468 | |||
469 | static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass, | ||
470 | u32 requested, struct av_decision *avd, | ||
471 | struct extended_perms_decision *xpd, | ||
472 | u8 perm, int result, | ||
473 | struct common_audit_data *ad) | ||
474 | { | ||
475 | u32 audited, denied; | ||
476 | |||
477 | audited = avc_xperms_audit_required( | ||
478 | requested, avd, xpd, perm, result, &denied); | ||
479 | if (likely(!audited)) | ||
480 | return 0; | ||
481 | return slow_avc_audit(ssid, tsid, tclass, requested, | ||
482 | audited, denied, result, ad, 0); | ||
483 | } | ||
484 | |||
208 | static void avc_node_free(struct rcu_head *rhead) | 485 | static void avc_node_free(struct rcu_head *rhead) |
209 | { | 486 | { |
210 | struct avc_node *node = container_of(rhead, struct avc_node, rhead); | 487 | struct avc_node *node = container_of(rhead, struct avc_node, rhead); |
488 | avc_xperms_free(node->ae.xp_node); | ||
211 | kmem_cache_free(avc_node_cachep, node); | 489 | kmem_cache_free(avc_node_cachep, node); |
212 | avc_cache_stats_incr(frees); | 490 | avc_cache_stats_incr(frees); |
213 | } | 491 | } |
@@ -221,6 +499,7 @@ static void avc_node_delete(struct avc_node *node) | |||
221 | 499 | ||
222 | static void avc_node_kill(struct avc_node *node) | 500 | static void avc_node_kill(struct avc_node *node) |
223 | { | 501 | { |
502 | avc_xperms_free(node->ae.xp_node); | ||
224 | kmem_cache_free(avc_node_cachep, node); | 503 | kmem_cache_free(avc_node_cachep, node); |
225 | avc_cache_stats_incr(frees); | 504 | avc_cache_stats_incr(frees); |
226 | atomic_dec(&avc_cache.active_nodes); | 505 | atomic_dec(&avc_cache.active_nodes); |
@@ -367,6 +646,7 @@ static int avc_latest_notif_update(int seqno, int is_insert) | |||
367 | * @tsid: target security identifier | 646 | * @tsid: target security identifier |
368 | * @tclass: target security class | 647 | * @tclass: target security class |
369 | * @avd: resulting av decision | 648 | * @avd: resulting av decision |
649 | * @xp_node: resulting extended permissions | ||
370 | * | 650 | * |
371 | * Insert an AVC entry for the SID pair | 651 | * Insert an AVC entry for the SID pair |
372 | * (@ssid, @tsid) and class @tclass. | 652 | * (@ssid, @tsid) and class @tclass. |
@@ -378,7 +658,9 @@ static int avc_latest_notif_update(int seqno, int is_insert) | |||
378 | * the access vectors into a cache entry, returns | 658 | * the access vectors into a cache entry, returns |
379 | * avc_node inserted. Otherwise, this function returns NULL. | 659 | * avc_node inserted. Otherwise, this function returns NULL. |
380 | */ | 660 | */ |
381 | static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) | 661 | static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, |
662 | struct av_decision *avd, | ||
663 | struct avc_xperms_node *xp_node) | ||
382 | { | 664 | { |
383 | struct avc_node *pos, *node = NULL; | 665 | struct avc_node *pos, *node = NULL; |
384 | int hvalue; | 666 | int hvalue; |
@@ -391,10 +673,15 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_dec | |||
391 | if (node) { | 673 | if (node) { |
392 | struct hlist_head *head; | 674 | struct hlist_head *head; |
393 | spinlock_t *lock; | 675 | spinlock_t *lock; |
676 | int rc = 0; | ||
394 | 677 | ||
395 | hvalue = avc_hash(ssid, tsid, tclass); | 678 | hvalue = avc_hash(ssid, tsid, tclass); |
396 | avc_node_populate(node, ssid, tsid, tclass, avd); | 679 | avc_node_populate(node, ssid, tsid, tclass, avd); |
397 | 680 | rc = avc_xperms_populate(node, xp_node); | |
681 | if (rc) { | ||
682 | kmem_cache_free(avc_node_cachep, node); | ||
683 | return NULL; | ||
684 | } | ||
398 | head = &avc_cache.slots[hvalue]; | 685 | head = &avc_cache.slots[hvalue]; |
399 | lock = &avc_cache.slots_lock[hvalue]; | 686 | lock = &avc_cache.slots_lock[hvalue]; |
400 | 687 | ||
@@ -523,14 +810,17 @@ out: | |||
523 | * @perms : Permission mask bits | 810 | * @perms : Permission mask bits |
524 | * @ssid,@tsid,@tclass : identifier of an AVC entry | 811 | * @ssid,@tsid,@tclass : identifier of an AVC entry |
525 | * @seqno : sequence number when decision was made | 812 | * @seqno : sequence number when decision was made |
813 | * @xpd: extended_perms_decision to be added to the node | ||
526 | * | 814 | * |
527 | * if a valid AVC entry doesn't exist,this function returns -ENOENT. | 815 | * if a valid AVC entry doesn't exist,this function returns -ENOENT. |
528 | * if kmalloc() called internal returns NULL, this function returns -ENOMEM. | 816 | * if kmalloc() called internal returns NULL, this function returns -ENOMEM. |
529 | * otherwise, this function updates the AVC entry. The original AVC-entry object | 817 | * otherwise, this function updates the AVC entry. The original AVC-entry object |
530 | * will release later by RCU. | 818 | * will release later by RCU. |
531 | */ | 819 | */ |
532 | static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, | 820 | static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, |
533 | u32 seqno) | 821 | u32 tsid, u16 tclass, u32 seqno, |
822 | struct extended_perms_decision *xpd, | ||
823 | u32 flags) | ||
534 | { | 824 | { |
535 | int hvalue, rc = 0; | 825 | int hvalue, rc = 0; |
536 | unsigned long flag; | 826 | unsigned long flag; |
@@ -574,9 +864,19 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, | |||
574 | 864 | ||
575 | avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd); | 865 | avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd); |
576 | 866 | ||
867 | if (orig->ae.xp_node) { | ||
868 | rc = avc_xperms_populate(node, orig->ae.xp_node); | ||
869 | if (rc) { | ||
870 | kmem_cache_free(avc_node_cachep, node); | ||
871 | goto out_unlock; | ||
872 | } | ||
873 | } | ||
874 | |||
577 | switch (event) { | 875 | switch (event) { |
578 | case AVC_CALLBACK_GRANT: | 876 | case AVC_CALLBACK_GRANT: |
579 | node->ae.avd.allowed |= perms; | 877 | node->ae.avd.allowed |= perms; |
878 | if (node->ae.xp_node && (flags & AVC_EXTENDED_PERMS)) | ||
879 | avc_xperms_allow_perm(node->ae.xp_node, driver, xperm); | ||
580 | break; | 880 | break; |
581 | case AVC_CALLBACK_TRY_REVOKE: | 881 | case AVC_CALLBACK_TRY_REVOKE: |
582 | case AVC_CALLBACK_REVOKE: | 882 | case AVC_CALLBACK_REVOKE: |
@@ -594,6 +894,9 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, | |||
594 | case AVC_CALLBACK_AUDITDENY_DISABLE: | 894 | case AVC_CALLBACK_AUDITDENY_DISABLE: |
595 | node->ae.avd.auditdeny &= ~perms; | 895 | node->ae.avd.auditdeny &= ~perms; |
596 | break; | 896 | break; |
897 | case AVC_CALLBACK_ADD_XPERMS: | ||
898 | avc_add_xperms_decision(node, xpd); | ||
899 | break; | ||
597 | } | 900 | } |
598 | avc_node_replace(node, orig); | 901 | avc_node_replace(node, orig); |
599 | out_unlock: | 902 | out_unlock: |
@@ -665,18 +968,20 @@ int avc_ss_reset(u32 seqno) | |||
665 | * results in a bigger stack frame. | 968 | * results in a bigger stack frame. |
666 | */ | 969 | */ |
667 | static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, | 970 | static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, |
668 | u16 tclass, struct av_decision *avd) | 971 | u16 tclass, struct av_decision *avd, |
972 | struct avc_xperms_node *xp_node) | ||
669 | { | 973 | { |
670 | rcu_read_unlock(); | 974 | rcu_read_unlock(); |
671 | security_compute_av(ssid, tsid, tclass, avd); | 975 | INIT_LIST_HEAD(&xp_node->xpd_head); |
976 | security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp); | ||
672 | rcu_read_lock(); | 977 | rcu_read_lock(); |
673 | return avc_insert(ssid, tsid, tclass, avd); | 978 | return avc_insert(ssid, tsid, tclass, avd, xp_node); |
674 | } | 979 | } |
675 | 980 | ||
676 | static noinline int avc_denied(u32 ssid, u32 tsid, | 981 | static noinline int avc_denied(u32 ssid, u32 tsid, |
677 | u16 tclass, u32 requested, | 982 | u16 tclass, u32 requested, |
678 | unsigned flags, | 983 | u8 driver, u8 xperm, unsigned flags, |
679 | struct av_decision *avd) | 984 | struct av_decision *avd) |
680 | { | 985 | { |
681 | if (flags & AVC_STRICT) | 986 | if (flags & AVC_STRICT) |
682 | return -EACCES; | 987 | return -EACCES; |
@@ -684,11 +989,91 @@ static noinline int avc_denied(u32 ssid, u32 tsid, | |||
684 | if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) | 989 | if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) |
685 | return -EACCES; | 990 | return -EACCES; |
686 | 991 | ||
687 | avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, | 992 | avc_update_node(AVC_CALLBACK_GRANT, requested, driver, xperm, ssid, |
688 | tsid, tclass, avd->seqno); | 993 | tsid, tclass, avd->seqno, NULL, flags); |
689 | return 0; | 994 | return 0; |
690 | } | 995 | } |
691 | 996 | ||
997 | /* | ||
998 | * The avc extended permissions logic adds an additional 256 bits of | ||
999 | * permissions to an avc node when extended permissions for that node are | ||
1000 | * specified in the avtab. If the additional 256 permissions is not adequate, | ||
1001 | * as-is the case with ioctls, then multiple may be chained together and the | ||
1002 | * driver field is used to specify which set contains the permission. | ||
1003 | */ | ||
1004 | int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, | ||
1005 | u8 driver, u8 xperm, struct common_audit_data *ad) | ||
1006 | { | ||
1007 | struct avc_node *node; | ||
1008 | struct av_decision avd; | ||
1009 | u32 denied; | ||
1010 | struct extended_perms_decision local_xpd; | ||
1011 | struct extended_perms_decision *xpd = NULL; | ||
1012 | struct extended_perms_data allowed; | ||
1013 | struct extended_perms_data auditallow; | ||
1014 | struct extended_perms_data dontaudit; | ||
1015 | struct avc_xperms_node local_xp_node; | ||
1016 | struct avc_xperms_node *xp_node; | ||
1017 | int rc = 0, rc2; | ||
1018 | |||
1019 | xp_node = &local_xp_node; | ||
1020 | BUG_ON(!requested); | ||
1021 | |||
1022 | rcu_read_lock(); | ||
1023 | |||
1024 | node = avc_lookup(ssid, tsid, tclass); | ||
1025 | if (unlikely(!node)) { | ||
1026 | node = avc_compute_av(ssid, tsid, tclass, &avd, xp_node); | ||
1027 | } else { | ||
1028 | memcpy(&avd, &node->ae.avd, sizeof(avd)); | ||
1029 | xp_node = node->ae.xp_node; | ||
1030 | } | ||
1031 | /* if extended permissions are not defined, only consider av_decision */ | ||
1032 | if (!xp_node || !xp_node->xp.len) | ||
1033 | goto decision; | ||
1034 | |||
1035 | local_xpd.allowed = &allowed; | ||
1036 | local_xpd.auditallow = &auditallow; | ||
1037 | local_xpd.dontaudit = &dontaudit; | ||
1038 | |||
1039 | xpd = avc_xperms_decision_lookup(driver, xp_node); | ||
1040 | if (unlikely(!xpd)) { | ||
1041 | /* | ||
1042 | * Compute the extended_perms_decision only if the driver | ||
1043 | * is flagged | ||
1044 | */ | ||
1045 | if (!security_xperm_test(xp_node->xp.drivers.p, driver)) { | ||
1046 | avd.allowed &= ~requested; | ||
1047 | goto decision; | ||
1048 | } | ||
1049 | rcu_read_unlock(); | ||
1050 | security_compute_xperms_decision(ssid, tsid, tclass, driver, | ||
1051 | &local_xpd); | ||
1052 | rcu_read_lock(); | ||
1053 | avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver, xperm, | ||
1054 | ssid, tsid, tclass, avd.seqno, &local_xpd, 0); | ||
1055 | } else { | ||
1056 | avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd); | ||
1057 | } | ||
1058 | xpd = &local_xpd; | ||
1059 | |||
1060 | if (!avc_xperms_has_perm(xpd, xperm, XPERMS_ALLOWED)) | ||
1061 | avd.allowed &= ~requested; | ||
1062 | |||
1063 | decision: | ||
1064 | denied = requested & ~(avd.allowed); | ||
1065 | if (unlikely(denied)) | ||
1066 | rc = avc_denied(ssid, tsid, tclass, requested, driver, xperm, | ||
1067 | AVC_EXTENDED_PERMS, &avd); | ||
1068 | |||
1069 | rcu_read_unlock(); | ||
1070 | |||
1071 | rc2 = avc_xperms_audit(ssid, tsid, tclass, requested, | ||
1072 | &avd, xpd, xperm, rc, ad); | ||
1073 | if (rc2) | ||
1074 | return rc2; | ||
1075 | return rc; | ||
1076 | } | ||
692 | 1077 | ||
693 | /** | 1078 | /** |
694 | * avc_has_perm_noaudit - Check permissions but perform no auditing. | 1079 | * avc_has_perm_noaudit - Check permissions but perform no auditing. |
@@ -716,6 +1101,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
716 | struct av_decision *avd) | 1101 | struct av_decision *avd) |
717 | { | 1102 | { |
718 | struct avc_node *node; | 1103 | struct avc_node *node; |
1104 | struct avc_xperms_node xp_node; | ||
719 | int rc = 0; | 1105 | int rc = 0; |
720 | u32 denied; | 1106 | u32 denied; |
721 | 1107 | ||
@@ -725,13 +1111,13 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
725 | 1111 | ||
726 | node = avc_lookup(ssid, tsid, tclass); | 1112 | node = avc_lookup(ssid, tsid, tclass); |
727 | if (unlikely(!node)) | 1113 | if (unlikely(!node)) |
728 | node = avc_compute_av(ssid, tsid, tclass, avd); | 1114 | node = avc_compute_av(ssid, tsid, tclass, avd, &xp_node); |
729 | else | 1115 | else |
730 | memcpy(avd, &node->ae.avd, sizeof(*avd)); | 1116 | memcpy(avd, &node->ae.avd, sizeof(*avd)); |
731 | 1117 | ||
732 | denied = requested & ~(avd->allowed); | 1118 | denied = requested & ~(avd->allowed); |
733 | if (unlikely(denied)) | 1119 | if (unlikely(denied)) |
734 | rc = avc_denied(ssid, tsid, tclass, requested, flags, avd); | 1120 | rc = avc_denied(ssid, tsid, tclass, requested, 0, 0, flags, avd); |
735 | 1121 | ||
736 | rcu_read_unlock(); | 1122 | rcu_read_unlock(); |
737 | return rc; | 1123 | return rc; |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index cdf4c589a391..e4369d86e588 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -254,10 +254,21 @@ static void inode_free_security(struct inode *inode) | |||
254 | struct inode_security_struct *isec = inode->i_security; | 254 | struct inode_security_struct *isec = inode->i_security; |
255 | struct superblock_security_struct *sbsec = inode->i_sb->s_security; | 255 | struct superblock_security_struct *sbsec = inode->i_sb->s_security; |
256 | 256 | ||
257 | spin_lock(&sbsec->isec_lock); | 257 | /* |
258 | if (!list_empty(&isec->list)) | 258 | * As not all inode security structures are in a list, we check for |
259 | * empty list outside of the lock to make sure that we won't waste | ||
260 | * time taking a lock doing nothing. | ||
261 | * | ||
262 | * The list_del_init() function can be safely called more than once. | ||
263 | * It should not be possible for this function to be called with | ||
264 | * concurrent list_add(), but for better safety against future changes | ||
265 | * in the code, we use list_empty_careful() here. | ||
266 | */ | ||
267 | if (!list_empty_careful(&isec->list)) { | ||
268 | spin_lock(&sbsec->isec_lock); | ||
259 | list_del_init(&isec->list); | 269 | list_del_init(&isec->list); |
260 | spin_unlock(&sbsec->isec_lock); | 270 | spin_unlock(&sbsec->isec_lock); |
271 | } | ||
261 | 272 | ||
262 | /* | 273 | /* |
263 | * The inode may still be referenced in a path walk and | 274 | * The inode may still be referenced in a path walk and |
@@ -1698,6 +1709,32 @@ out: | |||
1698 | return rc; | 1709 | return rc; |
1699 | } | 1710 | } |
1700 | 1711 | ||
1712 | /* | ||
1713 | * Determine the label for an inode that might be unioned. | ||
1714 | */ | ||
1715 | static int selinux_determine_inode_label(const struct inode *dir, | ||
1716 | const struct qstr *name, | ||
1717 | u16 tclass, | ||
1718 | u32 *_new_isid) | ||
1719 | { | ||
1720 | const struct superblock_security_struct *sbsec = dir->i_sb->s_security; | ||
1721 | const struct inode_security_struct *dsec = dir->i_security; | ||
1722 | const struct task_security_struct *tsec = current_security(); | ||
1723 | |||
1724 | if ((sbsec->flags & SE_SBINITIALIZED) && | ||
1725 | (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) { | ||
1726 | *_new_isid = sbsec->mntpoint_sid; | ||
1727 | } else if ((sbsec->flags & SBLABEL_MNT) && | ||
1728 | tsec->create_sid) { | ||
1729 | *_new_isid = tsec->create_sid; | ||
1730 | } else { | ||
1731 | return security_transition_sid(tsec->sid, dsec->sid, tclass, | ||
1732 | name, _new_isid); | ||
1733 | } | ||
1734 | |||
1735 | return 0; | ||
1736 | } | ||
1737 | |||
1701 | /* Check whether a task can create a file. */ | 1738 | /* Check whether a task can create a file. */ |
1702 | static int may_create(struct inode *dir, | 1739 | static int may_create(struct inode *dir, |
1703 | struct dentry *dentry, | 1740 | struct dentry *dentry, |
@@ -1714,7 +1751,6 @@ static int may_create(struct inode *dir, | |||
1714 | sbsec = dir->i_sb->s_security; | 1751 | sbsec = dir->i_sb->s_security; |
1715 | 1752 | ||
1716 | sid = tsec->sid; | 1753 | sid = tsec->sid; |
1717 | newsid = tsec->create_sid; | ||
1718 | 1754 | ||
1719 | ad.type = LSM_AUDIT_DATA_DENTRY; | 1755 | ad.type = LSM_AUDIT_DATA_DENTRY; |
1720 | ad.u.dentry = dentry; | 1756 | ad.u.dentry = dentry; |
@@ -1725,12 +1761,10 @@ static int may_create(struct inode *dir, | |||
1725 | if (rc) | 1761 | if (rc) |
1726 | return rc; | 1762 | return rc; |
1727 | 1763 | ||
1728 | if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { | 1764 | rc = selinux_determine_inode_label(dir, &dentry->d_name, tclass, |
1729 | rc = security_transition_sid(sid, dsec->sid, tclass, | 1765 | &newsid); |
1730 | &dentry->d_name, &newsid); | 1766 | if (rc) |
1731 | if (rc) | 1767 | return rc; |
1732 | return rc; | ||
1733 | } | ||
1734 | 1768 | ||
1735 | rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad); | 1769 | rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad); |
1736 | if (rc) | 1770 | if (rc) |
@@ -2704,32 +2738,14 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode, | |||
2704 | struct qstr *name, void **ctx, | 2738 | struct qstr *name, void **ctx, |
2705 | u32 *ctxlen) | 2739 | u32 *ctxlen) |
2706 | { | 2740 | { |
2707 | const struct cred *cred = current_cred(); | ||
2708 | struct task_security_struct *tsec; | ||
2709 | struct inode_security_struct *dsec; | ||
2710 | struct superblock_security_struct *sbsec; | ||
2711 | struct inode *dir = d_backing_inode(dentry->d_parent); | ||
2712 | u32 newsid; | 2741 | u32 newsid; |
2713 | int rc; | 2742 | int rc; |
2714 | 2743 | ||
2715 | tsec = cred->security; | 2744 | rc = selinux_determine_inode_label(d_inode(dentry->d_parent), name, |
2716 | dsec = dir->i_security; | 2745 | inode_mode_to_security_class(mode), |
2717 | sbsec = dir->i_sb->s_security; | 2746 | &newsid); |
2718 | 2747 | if (rc) | |
2719 | if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { | 2748 | return rc; |
2720 | newsid = tsec->create_sid; | ||
2721 | } else { | ||
2722 | rc = security_transition_sid(tsec->sid, dsec->sid, | ||
2723 | inode_mode_to_security_class(mode), | ||
2724 | name, | ||
2725 | &newsid); | ||
2726 | if (rc) { | ||
2727 | printk(KERN_WARNING | ||
2728 | "%s: security_transition_sid failed, rc=%d\n", | ||
2729 | __func__, -rc); | ||
2730 | return rc; | ||
2731 | } | ||
2732 | } | ||
2733 | 2749 | ||
2734 | return security_sid_to_context(newsid, (char **)ctx, ctxlen); | 2750 | return security_sid_to_context(newsid, (char **)ctx, ctxlen); |
2735 | } | 2751 | } |
@@ -2752,22 +2768,12 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2752 | sid = tsec->sid; | 2768 | sid = tsec->sid; |
2753 | newsid = tsec->create_sid; | 2769 | newsid = tsec->create_sid; |
2754 | 2770 | ||
2755 | if ((sbsec->flags & SE_SBINITIALIZED) && | 2771 | rc = selinux_determine_inode_label( |
2756 | (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) | 2772 | dir, qstr, |
2757 | newsid = sbsec->mntpoint_sid; | 2773 | inode_mode_to_security_class(inode->i_mode), |
2758 | else if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { | 2774 | &newsid); |
2759 | rc = security_transition_sid(sid, dsec->sid, | 2775 | if (rc) |
2760 | inode_mode_to_security_class(inode->i_mode), | 2776 | return rc; |
2761 | qstr, &newsid); | ||
2762 | if (rc) { | ||
2763 | printk(KERN_WARNING "%s: " | ||
2764 | "security_transition_sid failed, rc=%d (dev=%s " | ||
2765 | "ino=%ld)\n", | ||
2766 | __func__, | ||
2767 | -rc, inode->i_sb->s_id, inode->i_ino); | ||
2768 | return rc; | ||
2769 | } | ||
2770 | } | ||
2771 | 2777 | ||
2772 | /* Possibly defer initialization to selinux_complete_init. */ | 2778 | /* Possibly defer initialization to selinux_complete_init. */ |
2773 | if (sbsec->flags & SE_SBINITIALIZED) { | 2779 | if (sbsec->flags & SE_SBINITIALIZED) { |
@@ -3228,6 +3234,46 @@ static void selinux_file_free_security(struct file *file) | |||
3228 | file_free_security(file); | 3234 | file_free_security(file); |
3229 | } | 3235 | } |
3230 | 3236 | ||
3237 | /* | ||
3238 | * Check whether a task has the ioctl permission and cmd | ||
3239 | * operation to an inode. | ||
3240 | */ | ||
3241 | int ioctl_has_perm(const struct cred *cred, struct file *file, | ||
3242 | u32 requested, u16 cmd) | ||
3243 | { | ||
3244 | struct common_audit_data ad; | ||
3245 | struct file_security_struct *fsec = file->f_security; | ||
3246 | struct inode *inode = file_inode(file); | ||
3247 | struct inode_security_struct *isec = inode->i_security; | ||
3248 | struct lsm_ioctlop_audit ioctl; | ||
3249 | u32 ssid = cred_sid(cred); | ||
3250 | int rc; | ||
3251 | u8 driver = cmd >> 8; | ||
3252 | u8 xperm = cmd & 0xff; | ||
3253 | |||
3254 | ad.type = LSM_AUDIT_DATA_IOCTL_OP; | ||
3255 | ad.u.op = &ioctl; | ||
3256 | ad.u.op->cmd = cmd; | ||
3257 | ad.u.op->path = file->f_path; | ||
3258 | |||
3259 | if (ssid != fsec->sid) { | ||
3260 | rc = avc_has_perm(ssid, fsec->sid, | ||
3261 | SECCLASS_FD, | ||
3262 | FD__USE, | ||
3263 | &ad); | ||
3264 | if (rc) | ||
3265 | goto out; | ||
3266 | } | ||
3267 | |||
3268 | if (unlikely(IS_PRIVATE(inode))) | ||
3269 | return 0; | ||
3270 | |||
3271 | rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, | ||
3272 | requested, driver, xperm, &ad); | ||
3273 | out: | ||
3274 | return rc; | ||
3275 | } | ||
3276 | |||
3231 | static int selinux_file_ioctl(struct file *file, unsigned int cmd, | 3277 | static int selinux_file_ioctl(struct file *file, unsigned int cmd, |
3232 | unsigned long arg) | 3278 | unsigned long arg) |
3233 | { | 3279 | { |
@@ -3270,7 +3316,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, | |||
3270 | * to the file's ioctl() function. | 3316 | * to the file's ioctl() function. |
3271 | */ | 3317 | */ |
3272 | default: | 3318 | default: |
3273 | error = file_has_perm(cred, file, FILE__IOCTL); | 3319 | error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); |
3274 | } | 3320 | } |
3275 | return error; | 3321 | return error; |
3276 | } | 3322 | } |
@@ -4520,6 +4566,7 @@ static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority | |||
4520 | 4566 | ||
4521 | sksec->peer_sid = SECINITSID_UNLABELED; | 4567 | sksec->peer_sid = SECINITSID_UNLABELED; |
4522 | sksec->sid = SECINITSID_UNLABELED; | 4568 | sksec->sid = SECINITSID_UNLABELED; |
4569 | sksec->sclass = SECCLASS_SOCKET; | ||
4523 | selinux_netlbl_sk_security_reset(sksec); | 4570 | selinux_netlbl_sk_security_reset(sksec); |
4524 | sk->sk_security = sksec; | 4571 | sk->sk_security = sksec; |
4525 | 4572 | ||
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 5973c327c54e..0999df03af8b 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
@@ -143,6 +143,7 @@ static inline int avc_audit(u32 ssid, u32 tsid, | |||
143 | } | 143 | } |
144 | 144 | ||
145 | #define AVC_STRICT 1 /* Ignore permissive mode. */ | 145 | #define AVC_STRICT 1 /* Ignore permissive mode. */ |
146 | #define AVC_EXTENDED_PERMS 2 /* update extended permissions */ | ||
146 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 147 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
147 | u16 tclass, u32 requested, | 148 | u16 tclass, u32 requested, |
148 | unsigned flags, | 149 | unsigned flags, |
@@ -156,6 +157,10 @@ int avc_has_perm_flags(u32 ssid, u32 tsid, | |||
156 | struct common_audit_data *auditdata, | 157 | struct common_audit_data *auditdata, |
157 | int flags); | 158 | int flags); |
158 | 159 | ||
160 | int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, | ||
161 | u8 driver, u8 perm, struct common_audit_data *ad); | ||
162 | |||
163 | |||
159 | u32 avc_policy_seqno(void); | 164 | u32 avc_policy_seqno(void); |
160 | 165 | ||
161 | #define AVC_CALLBACK_GRANT 1 | 166 | #define AVC_CALLBACK_GRANT 1 |
@@ -166,6 +171,7 @@ u32 avc_policy_seqno(void); | |||
166 | #define AVC_CALLBACK_AUDITALLOW_DISABLE 32 | 171 | #define AVC_CALLBACK_AUDITALLOW_DISABLE 32 |
167 | #define AVC_CALLBACK_AUDITDENY_ENABLE 64 | 172 | #define AVC_CALLBACK_AUDITDENY_ENABLE 64 |
168 | #define AVC_CALLBACK_AUDITDENY_DISABLE 128 | 173 | #define AVC_CALLBACK_AUDITDENY_DISABLE 128 |
174 | #define AVC_CALLBACK_ADD_XPERMS 256 | ||
169 | 175 | ||
170 | int avc_add_callback(int (*callback)(u32 event), u32 events); | 176 | int avc_add_callback(int (*callback)(u32 event), u32 events); |
171 | 177 | ||
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 36993ad1c067..6a681d26bf20 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -35,13 +35,14 @@ | |||
35 | #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 | 35 | #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 |
36 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 | 36 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 |
37 | #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 | 37 | #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 |
38 | #define POLICYDB_VERSION_XPERMS_IOCTL 30 | ||
38 | 39 | ||
39 | /* Range of policy versions we understand*/ | 40 | /* Range of policy versions we understand*/ |
40 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 41 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
41 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX | 42 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX |
42 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE | 43 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE |
43 | #else | 44 | #else |
44 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES | 45 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_XPERMS_IOCTL |
45 | #endif | 46 | #endif |
46 | 47 | ||
47 | /* Mask for just the mount related flags */ | 48 | /* Mask for just the mount related flags */ |
@@ -109,11 +110,38 @@ struct av_decision { | |||
109 | u32 flags; | 110 | u32 flags; |
110 | }; | 111 | }; |
111 | 112 | ||
113 | #define XPERMS_ALLOWED 1 | ||
114 | #define XPERMS_AUDITALLOW 2 | ||
115 | #define XPERMS_DONTAUDIT 4 | ||
116 | |||
117 | #define security_xperm_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f)) | ||
118 | #define security_xperm_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f))) | ||
119 | struct extended_perms_data { | ||
120 | u32 p[8]; | ||
121 | }; | ||
122 | |||
123 | struct extended_perms_decision { | ||
124 | u8 used; | ||
125 | u8 driver; | ||
126 | struct extended_perms_data *allowed; | ||
127 | struct extended_perms_data *auditallow; | ||
128 | struct extended_perms_data *dontaudit; | ||
129 | }; | ||
130 | |||
131 | struct extended_perms { | ||
132 | u16 len; /* length associated decision chain */ | ||
133 | struct extended_perms_data drivers; /* flag drivers that are used */ | ||
134 | }; | ||
135 | |||
112 | /* definitions of av_decision.flags */ | 136 | /* definitions of av_decision.flags */ |
113 | #define AVD_FLAGS_PERMISSIVE 0x0001 | 137 | #define AVD_FLAGS_PERMISSIVE 0x0001 |
114 | 138 | ||
115 | void security_compute_av(u32 ssid, u32 tsid, | 139 | void security_compute_av(u32 ssid, u32 tsid, |
116 | u16 tclass, struct av_decision *avd); | 140 | u16 tclass, struct av_decision *avd, |
141 | struct extended_perms *xperms); | ||
142 | |||
143 | void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, | ||
144 | u8 driver, struct extended_perms_decision *xpermd); | ||
117 | 145 | ||
118 | void security_compute_av_user(u32 ssid, u32 tsid, | 146 | void security_compute_av_user(u32 ssid, u32 tsid, |
119 | u16 tclass, struct av_decision *avd); | 147 | u16 tclass, struct av_decision *avd); |
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index b64f2772b030..3628d3a868b6 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "policydb.h" | 24 | #include "policydb.h" |
25 | 25 | ||
26 | static struct kmem_cache *avtab_node_cachep; | 26 | static struct kmem_cache *avtab_node_cachep; |
27 | static struct kmem_cache *avtab_xperms_cachep; | ||
27 | 28 | ||
28 | /* Based on MurmurHash3, written by Austin Appleby and placed in the | 29 | /* Based on MurmurHash3, written by Austin Appleby and placed in the |
29 | * public domain. | 30 | * public domain. |
@@ -70,11 +71,24 @@ avtab_insert_node(struct avtab *h, int hvalue, | |||
70 | struct avtab_key *key, struct avtab_datum *datum) | 71 | struct avtab_key *key, struct avtab_datum *datum) |
71 | { | 72 | { |
72 | struct avtab_node *newnode; | 73 | struct avtab_node *newnode; |
74 | struct avtab_extended_perms *xperms; | ||
73 | newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); | 75 | newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); |
74 | if (newnode == NULL) | 76 | if (newnode == NULL) |
75 | return NULL; | 77 | return NULL; |
76 | newnode->key = *key; | 78 | newnode->key = *key; |
77 | newnode->datum = *datum; | 79 | |
80 | if (key->specified & AVTAB_XPERMS) { | ||
81 | xperms = kmem_cache_zalloc(avtab_xperms_cachep, GFP_KERNEL); | ||
82 | if (xperms == NULL) { | ||
83 | kmem_cache_free(avtab_node_cachep, newnode); | ||
84 | return NULL; | ||
85 | } | ||
86 | *xperms = *(datum->u.xperms); | ||
87 | newnode->datum.u.xperms = xperms; | ||
88 | } else { | ||
89 | newnode->datum.u.data = datum->u.data; | ||
90 | } | ||
91 | |||
78 | if (prev) { | 92 | if (prev) { |
79 | newnode->next = prev->next; | 93 | newnode->next = prev->next; |
80 | prev->next = newnode; | 94 | prev->next = newnode; |
@@ -107,8 +121,12 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat | |||
107 | if (key->source_type == cur->key.source_type && | 121 | if (key->source_type == cur->key.source_type && |
108 | key->target_type == cur->key.target_type && | 122 | key->target_type == cur->key.target_type && |
109 | key->target_class == cur->key.target_class && | 123 | key->target_class == cur->key.target_class && |
110 | (specified & cur->key.specified)) | 124 | (specified & cur->key.specified)) { |
125 | /* extended perms may not be unique */ | ||
126 | if (specified & AVTAB_XPERMS) | ||
127 | break; | ||
111 | return -EEXIST; | 128 | return -EEXIST; |
129 | } | ||
112 | if (key->source_type < cur->key.source_type) | 130 | if (key->source_type < cur->key.source_type) |
113 | break; | 131 | break; |
114 | if (key->source_type == cur->key.source_type && | 132 | if (key->source_type == cur->key.source_type && |
@@ -271,6 +289,9 @@ void avtab_destroy(struct avtab *h) | |||
271 | while (cur) { | 289 | while (cur) { |
272 | temp = cur; | 290 | temp = cur; |
273 | cur = cur->next; | 291 | cur = cur->next; |
292 | if (temp->key.specified & AVTAB_XPERMS) | ||
293 | kmem_cache_free(avtab_xperms_cachep, | ||
294 | temp->datum.u.xperms); | ||
274 | kmem_cache_free(avtab_node_cachep, temp); | 295 | kmem_cache_free(avtab_node_cachep, temp); |
275 | } | 296 | } |
276 | } | 297 | } |
@@ -359,7 +380,10 @@ static uint16_t spec_order[] = { | |||
359 | AVTAB_AUDITALLOW, | 380 | AVTAB_AUDITALLOW, |
360 | AVTAB_TRANSITION, | 381 | AVTAB_TRANSITION, |
361 | AVTAB_CHANGE, | 382 | AVTAB_CHANGE, |
362 | AVTAB_MEMBER | 383 | AVTAB_MEMBER, |
384 | AVTAB_XPERMS_ALLOWED, | ||
385 | AVTAB_XPERMS_AUDITALLOW, | ||
386 | AVTAB_XPERMS_DONTAUDIT | ||
363 | }; | 387 | }; |
364 | 388 | ||
365 | int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | 389 | int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, |
@@ -369,10 +393,11 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | |||
369 | { | 393 | { |
370 | __le16 buf16[4]; | 394 | __le16 buf16[4]; |
371 | u16 enabled; | 395 | u16 enabled; |
372 | __le32 buf32[7]; | ||
373 | u32 items, items2, val, vers = pol->policyvers; | 396 | u32 items, items2, val, vers = pol->policyvers; |
374 | struct avtab_key key; | 397 | struct avtab_key key; |
375 | struct avtab_datum datum; | 398 | struct avtab_datum datum; |
399 | struct avtab_extended_perms xperms; | ||
400 | __le32 buf32[ARRAY_SIZE(xperms.perms.p)]; | ||
376 | int i, rc; | 401 | int i, rc; |
377 | unsigned set; | 402 | unsigned set; |
378 | 403 | ||
@@ -429,11 +454,15 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | |||
429 | printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); | 454 | printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); |
430 | return -EINVAL; | 455 | return -EINVAL; |
431 | } | 456 | } |
457 | if (val & AVTAB_XPERMS) { | ||
458 | printk(KERN_ERR "SELinux: avtab: entry has extended permissions\n"); | ||
459 | return -EINVAL; | ||
460 | } | ||
432 | 461 | ||
433 | for (i = 0; i < ARRAY_SIZE(spec_order); i++) { | 462 | for (i = 0; i < ARRAY_SIZE(spec_order); i++) { |
434 | if (val & spec_order[i]) { | 463 | if (val & spec_order[i]) { |
435 | key.specified = spec_order[i] | enabled; | 464 | key.specified = spec_order[i] | enabled; |
436 | datum.data = le32_to_cpu(buf32[items++]); | 465 | datum.u.data = le32_to_cpu(buf32[items++]); |
437 | rc = insertf(a, &key, &datum, p); | 466 | rc = insertf(a, &key, &datum, p); |
438 | if (rc) | 467 | if (rc) |
439 | return rc; | 468 | return rc; |
@@ -476,14 +505,42 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, | |||
476 | return -EINVAL; | 505 | return -EINVAL; |
477 | } | 506 | } |
478 | 507 | ||
479 | rc = next_entry(buf32, fp, sizeof(u32)); | 508 | if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) && |
480 | if (rc) { | 509 | (key.specified & AVTAB_XPERMS)) { |
481 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | 510 | printk(KERN_ERR "SELinux: avtab: policy version %u does not " |
482 | return rc; | 511 | "support extended permissions rules and one " |
512 | "was specified\n", vers); | ||
513 | return -EINVAL; | ||
514 | } else if (key.specified & AVTAB_XPERMS) { | ||
515 | memset(&xperms, 0, sizeof(struct avtab_extended_perms)); | ||
516 | rc = next_entry(&xperms.specified, fp, sizeof(u8)); | ||
517 | if (rc) { | ||
518 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
519 | return rc; | ||
520 | } | ||
521 | rc = next_entry(&xperms.driver, fp, sizeof(u8)); | ||
522 | if (rc) { | ||
523 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
524 | return rc; | ||
525 | } | ||
526 | rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p)); | ||
527 | if (rc) { | ||
528 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
529 | return rc; | ||
530 | } | ||
531 | for (i = 0; i < ARRAY_SIZE(xperms.perms.p); i++) | ||
532 | xperms.perms.p[i] = le32_to_cpu(buf32[i]); | ||
533 | datum.u.xperms = &xperms; | ||
534 | } else { | ||
535 | rc = next_entry(buf32, fp, sizeof(u32)); | ||
536 | if (rc) { | ||
537 | printk(KERN_ERR "SELinux: avtab: truncated entry\n"); | ||
538 | return rc; | ||
539 | } | ||
540 | datum.u.data = le32_to_cpu(*buf32); | ||
483 | } | 541 | } |
484 | datum.data = le32_to_cpu(*buf32); | ||
485 | if ((key.specified & AVTAB_TYPE) && | 542 | if ((key.specified & AVTAB_TYPE) && |
486 | !policydb_type_isvalid(pol, datum.data)) { | 543 | !policydb_type_isvalid(pol, datum.u.data)) { |
487 | printk(KERN_ERR "SELinux: avtab: invalid type\n"); | 544 | printk(KERN_ERR "SELinux: avtab: invalid type\n"); |
488 | return -EINVAL; | 545 | return -EINVAL; |
489 | } | 546 | } |
@@ -543,8 +600,9 @@ bad: | |||
543 | int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) | 600 | int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) |
544 | { | 601 | { |
545 | __le16 buf16[4]; | 602 | __le16 buf16[4]; |
546 | __le32 buf32[1]; | 603 | __le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)]; |
547 | int rc; | 604 | int rc; |
605 | unsigned int i; | ||
548 | 606 | ||
549 | buf16[0] = cpu_to_le16(cur->key.source_type); | 607 | buf16[0] = cpu_to_le16(cur->key.source_type); |
550 | buf16[1] = cpu_to_le16(cur->key.target_type); | 608 | buf16[1] = cpu_to_le16(cur->key.target_type); |
@@ -553,8 +611,22 @@ int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) | |||
553 | rc = put_entry(buf16, sizeof(u16), 4, fp); | 611 | rc = put_entry(buf16, sizeof(u16), 4, fp); |
554 | if (rc) | 612 | if (rc) |
555 | return rc; | 613 | return rc; |
556 | buf32[0] = cpu_to_le32(cur->datum.data); | 614 | |
557 | rc = put_entry(buf32, sizeof(u32), 1, fp); | 615 | if (cur->key.specified & AVTAB_XPERMS) { |
616 | rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, fp); | ||
617 | if (rc) | ||
618 | return rc; | ||
619 | rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp); | ||
620 | if (rc) | ||
621 | return rc; | ||
622 | for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++) | ||
623 | buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]); | ||
624 | rc = put_entry(buf32, sizeof(u32), | ||
625 | ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp); | ||
626 | } else { | ||
627 | buf32[0] = cpu_to_le32(cur->datum.u.data); | ||
628 | rc = put_entry(buf32, sizeof(u32), 1, fp); | ||
629 | } | ||
558 | if (rc) | 630 | if (rc) |
559 | return rc; | 631 | return rc; |
560 | return 0; | 632 | return 0; |
@@ -588,9 +660,13 @@ void avtab_cache_init(void) | |||
588 | avtab_node_cachep = kmem_cache_create("avtab_node", | 660 | avtab_node_cachep = kmem_cache_create("avtab_node", |
589 | sizeof(struct avtab_node), | 661 | sizeof(struct avtab_node), |
590 | 0, SLAB_PANIC, NULL); | 662 | 0, SLAB_PANIC, NULL); |
663 | avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms", | ||
664 | sizeof(struct avtab_extended_perms), | ||
665 | 0, SLAB_PANIC, NULL); | ||
591 | } | 666 | } |
592 | 667 | ||
593 | void avtab_cache_destroy(void) | 668 | void avtab_cache_destroy(void) |
594 | { | 669 | { |
595 | kmem_cache_destroy(avtab_node_cachep); | 670 | kmem_cache_destroy(avtab_node_cachep); |
671 | kmem_cache_destroy(avtab_xperms_cachep); | ||
596 | } | 672 | } |
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index adb451cd44f9..d946c9dc3c9c 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #ifndef _SS_AVTAB_H_ | 23 | #ifndef _SS_AVTAB_H_ |
24 | #define _SS_AVTAB_H_ | 24 | #define _SS_AVTAB_H_ |
25 | 25 | ||
26 | #include "security.h" | ||
26 | #include <linux/flex_array.h> | 27 | #include <linux/flex_array.h> |
27 | 28 | ||
28 | struct avtab_key { | 29 | struct avtab_key { |
@@ -37,13 +38,43 @@ struct avtab_key { | |||
37 | #define AVTAB_MEMBER 0x0020 | 38 | #define AVTAB_MEMBER 0x0020 |
38 | #define AVTAB_CHANGE 0x0040 | 39 | #define AVTAB_CHANGE 0x0040 |
39 | #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) | 40 | #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) |
41 | /* extended permissions */ | ||
42 | #define AVTAB_XPERMS_ALLOWED 0x0100 | ||
43 | #define AVTAB_XPERMS_AUDITALLOW 0x0200 | ||
44 | #define AVTAB_XPERMS_DONTAUDIT 0x0400 | ||
45 | #define AVTAB_XPERMS (AVTAB_XPERMS_ALLOWED | \ | ||
46 | AVTAB_XPERMS_AUDITALLOW | \ | ||
47 | AVTAB_XPERMS_DONTAUDIT) | ||
40 | #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ | 48 | #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ |
41 | #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ | 49 | #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ |
42 | u16 specified; /* what field is specified */ | 50 | u16 specified; /* what field is specified */ |
43 | }; | 51 | }; |
44 | 52 | ||
53 | /* | ||
54 | * For operations that require more than the 32 permissions provided by the avc | ||
55 | * extended permissions may be used to provide 256 bits of permissions. | ||
56 | */ | ||
57 | struct avtab_extended_perms { | ||
58 | /* These are not flags. All 256 values may be used */ | ||
59 | #define AVTAB_XPERMS_IOCTLFUNCTION 0x01 | ||
60 | #define AVTAB_XPERMS_IOCTLDRIVER 0x02 | ||
61 | /* extension of the avtab_key specified */ | ||
62 | u8 specified; /* ioctl, netfilter, ... */ | ||
63 | /* | ||
64 | * if 256 bits is not adequate as is often the case with ioctls, then | ||
65 | * multiple extended perms may be used and the driver field | ||
66 | * specifies which permissions are included. | ||
67 | */ | ||
68 | u8 driver; | ||
69 | /* 256 bits of permissions */ | ||
70 | struct extended_perms_data perms; | ||
71 | }; | ||
72 | |||
45 | struct avtab_datum { | 73 | struct avtab_datum { |
46 | u32 data; /* access vector or type value */ | 74 | union { |
75 | u32 data; /* access vector or type value */ | ||
76 | struct avtab_extended_perms *xperms; | ||
77 | } u; | ||
47 | }; | 78 | }; |
48 | 79 | ||
49 | struct avtab_node { | 80 | struct avtab_node { |
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 62c6773be0b7..18643bf9894d 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include "security.h" | 16 | #include "security.h" |
17 | #include "conditional.h" | 17 | #include "conditional.h" |
18 | #include "services.h" | ||
18 | 19 | ||
19 | /* | 20 | /* |
20 | * cond_evaluate_expr evaluates a conditional expr | 21 | * cond_evaluate_expr evaluates a conditional expr |
@@ -612,21 +613,39 @@ int cond_write_list(struct policydb *p, struct cond_node *list, void *fp) | |||
612 | 613 | ||
613 | return 0; | 614 | return 0; |
614 | } | 615 | } |
616 | |||
617 | void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, | ||
618 | struct extended_perms_decision *xpermd) | ||
619 | { | ||
620 | struct avtab_node *node; | ||
621 | |||
622 | if (!ctab || !key || !xpermd) | ||
623 | return; | ||
624 | |||
625 | for (node = avtab_search_node(ctab, key); node; | ||
626 | node = avtab_search_node_next(node, key->specified)) { | ||
627 | if (node->key.specified & AVTAB_ENABLED) | ||
628 | services_compute_xperms_decision(xpermd, node); | ||
629 | } | ||
630 | return; | ||
631 | |||
632 | } | ||
615 | /* Determine whether additional permissions are granted by the conditional | 633 | /* Determine whether additional permissions are granted by the conditional |
616 | * av table, and if so, add them to the result | 634 | * av table, and if so, add them to the result |
617 | */ | 635 | */ |
618 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd) | 636 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, |
637 | struct av_decision *avd, struct extended_perms *xperms) | ||
619 | { | 638 | { |
620 | struct avtab_node *node; | 639 | struct avtab_node *node; |
621 | 640 | ||
622 | if (!ctab || !key || !avd) | 641 | if (!ctab || !key || !avd || !xperms) |
623 | return; | 642 | return; |
624 | 643 | ||
625 | for (node = avtab_search_node(ctab, key); node; | 644 | for (node = avtab_search_node(ctab, key); node; |
626 | node = avtab_search_node_next(node, key->specified)) { | 645 | node = avtab_search_node_next(node, key->specified)) { |
627 | if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == | 646 | if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == |
628 | (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) | 647 | (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) |
629 | avd->allowed |= node->datum.data; | 648 | avd->allowed |= node->datum.u.data; |
630 | if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == | 649 | if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == |
631 | (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) | 650 | (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) |
632 | /* Since a '0' in an auditdeny mask represents a | 651 | /* Since a '0' in an auditdeny mask represents a |
@@ -634,10 +653,13 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi | |||
634 | * the '&' operand to ensure that all '0's in the mask | 653 | * the '&' operand to ensure that all '0's in the mask |
635 | * are retained (much unlike the allow and auditallow cases). | 654 | * are retained (much unlike the allow and auditallow cases). |
636 | */ | 655 | */ |
637 | avd->auditdeny &= node->datum.data; | 656 | avd->auditdeny &= node->datum.u.data; |
638 | if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == | 657 | if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == |
639 | (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) | 658 | (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) |
640 | avd->auditallow |= node->datum.data; | 659 | avd->auditallow |= node->datum.u.data; |
660 | if ((node->key.specified & AVTAB_ENABLED) && | ||
661 | (node->key.specified & AVTAB_XPERMS)) | ||
662 | services_compute_xperms_drivers(xperms, node); | ||
641 | } | 663 | } |
642 | return; | 664 | return; |
643 | } | 665 | } |
diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 4d1f87466508..ddb43e7e1c75 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h | |||
@@ -73,8 +73,10 @@ int cond_read_list(struct policydb *p, void *fp); | |||
73 | int cond_write_bool(void *key, void *datum, void *ptr); | 73 | int cond_write_bool(void *key, void *datum, void *ptr); |
74 | int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); | 74 | int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); |
75 | 75 | ||
76 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); | 76 | void cond_compute_av(struct avtab *ctab, struct avtab_key *key, |
77 | 77 | struct av_decision *avd, struct extended_perms *xperms); | |
78 | void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, | ||
79 | struct extended_perms_decision *xpermd); | ||
78 | int evaluate_cond_node(struct policydb *p, struct cond_node *node); | 80 | int evaluate_cond_node(struct policydb *p, struct cond_node *node); |
79 | 81 | ||
80 | #endif /* _CONDITIONAL_H_ */ | 82 | #endif /* _CONDITIONAL_H_ */ |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 74aa224267c1..992a31530825 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -148,6 +148,11 @@ static struct policydb_compat_info policydb_compat[] = { | |||
148 | .sym_num = SYM_NUM, | 148 | .sym_num = SYM_NUM, |
149 | .ocon_num = OCON_NUM, | 149 | .ocon_num = OCON_NUM, |
150 | }, | 150 | }, |
151 | { | ||
152 | .version = POLICYDB_VERSION_XPERMS_IOCTL, | ||
153 | .sym_num = SYM_NUM, | ||
154 | .ocon_num = OCON_NUM, | ||
155 | }, | ||
151 | }; | 156 | }; |
152 | 157 | ||
153 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 158 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 9e2d82070915..b7df12ba61d8 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -93,9 +93,10 @@ static int context_struct_to_string(struct context *context, char **scontext, | |||
93 | u32 *scontext_len); | 93 | u32 *scontext_len); |
94 | 94 | ||
95 | static void context_struct_compute_av(struct context *scontext, | 95 | static void context_struct_compute_av(struct context *scontext, |
96 | struct context *tcontext, | 96 | struct context *tcontext, |
97 | u16 tclass, | 97 | u16 tclass, |
98 | struct av_decision *avd); | 98 | struct av_decision *avd, |
99 | struct extended_perms *xperms); | ||
99 | 100 | ||
100 | struct selinux_mapping { | 101 | struct selinux_mapping { |
101 | u16 value; /* policy value */ | 102 | u16 value; /* policy value */ |
@@ -565,7 +566,8 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
565 | context_struct_compute_av(&lo_scontext, | 566 | context_struct_compute_av(&lo_scontext, |
566 | tcontext, | 567 | tcontext, |
567 | tclass, | 568 | tclass, |
568 | &lo_avd); | 569 | &lo_avd, |
570 | NULL); | ||
569 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 571 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
570 | return; /* no masked permission */ | 572 | return; /* no masked permission */ |
571 | masked = ~lo_avd.allowed & avd->allowed; | 573 | masked = ~lo_avd.allowed & avd->allowed; |
@@ -580,7 +582,8 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
580 | context_struct_compute_av(scontext, | 582 | context_struct_compute_av(scontext, |
581 | &lo_tcontext, | 583 | &lo_tcontext, |
582 | tclass, | 584 | tclass, |
583 | &lo_avd); | 585 | &lo_avd, |
586 | NULL); | ||
584 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 587 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
585 | return; /* no masked permission */ | 588 | return; /* no masked permission */ |
586 | masked = ~lo_avd.allowed & avd->allowed; | 589 | masked = ~lo_avd.allowed & avd->allowed; |
@@ -596,7 +599,8 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
596 | context_struct_compute_av(&lo_scontext, | 599 | context_struct_compute_av(&lo_scontext, |
597 | &lo_tcontext, | 600 | &lo_tcontext, |
598 | tclass, | 601 | tclass, |
599 | &lo_avd); | 602 | &lo_avd, |
603 | NULL); | ||
600 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 604 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
601 | return; /* no masked permission */ | 605 | return; /* no masked permission */ |
602 | masked = ~lo_avd.allowed & avd->allowed; | 606 | masked = ~lo_avd.allowed & avd->allowed; |
@@ -613,13 +617,39 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
613 | } | 617 | } |
614 | 618 | ||
615 | /* | 619 | /* |
616 | * Compute access vectors based on a context structure pair for | 620 | * flag which drivers have permissions |
617 | * the permissions in a particular class. | 621 | * only looking for ioctl based extended permssions |
622 | */ | ||
623 | void services_compute_xperms_drivers( | ||
624 | struct extended_perms *xperms, | ||
625 | struct avtab_node *node) | ||
626 | { | ||
627 | unsigned int i; | ||
628 | |||
629 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
630 | /* if one or more driver has all permissions allowed */ | ||
631 | for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++) | ||
632 | xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; | ||
633 | } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
634 | /* if allowing permissions within a driver */ | ||
635 | security_xperm_set(xperms->drivers.p, | ||
636 | node->datum.u.xperms->driver); | ||
637 | } | ||
638 | |||
639 | /* If no ioctl commands are allowed, ignore auditallow and auditdeny */ | ||
640 | if (node->key.specified & AVTAB_XPERMS_ALLOWED) | ||
641 | xperms->len = 1; | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * Compute access vectors and extended permissions based on a context | ||
646 | * structure pair for the permissions in a particular class. | ||
618 | */ | 647 | */ |
619 | static void context_struct_compute_av(struct context *scontext, | 648 | static void context_struct_compute_av(struct context *scontext, |
620 | struct context *tcontext, | 649 | struct context *tcontext, |
621 | u16 tclass, | 650 | u16 tclass, |
622 | struct av_decision *avd) | 651 | struct av_decision *avd, |
652 | struct extended_perms *xperms) | ||
623 | { | 653 | { |
624 | struct constraint_node *constraint; | 654 | struct constraint_node *constraint; |
625 | struct role_allow *ra; | 655 | struct role_allow *ra; |
@@ -633,6 +663,10 @@ static void context_struct_compute_av(struct context *scontext, | |||
633 | avd->allowed = 0; | 663 | avd->allowed = 0; |
634 | avd->auditallow = 0; | 664 | avd->auditallow = 0; |
635 | avd->auditdeny = 0xffffffff; | 665 | avd->auditdeny = 0xffffffff; |
666 | if (xperms) { | ||
667 | memset(&xperms->drivers, 0, sizeof(xperms->drivers)); | ||
668 | xperms->len = 0; | ||
669 | } | ||
636 | 670 | ||
637 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { | 671 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { |
638 | if (printk_ratelimit()) | 672 | if (printk_ratelimit()) |
@@ -647,7 +681,7 @@ static void context_struct_compute_av(struct context *scontext, | |||
647 | * this permission check, then use it. | 681 | * this permission check, then use it. |
648 | */ | 682 | */ |
649 | avkey.target_class = tclass; | 683 | avkey.target_class = tclass; |
650 | avkey.specified = AVTAB_AV; | 684 | avkey.specified = AVTAB_AV | AVTAB_XPERMS; |
651 | sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); | 685 | sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); |
652 | BUG_ON(!sattr); | 686 | BUG_ON(!sattr); |
653 | tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); | 687 | tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); |
@@ -660,15 +694,18 @@ static void context_struct_compute_av(struct context *scontext, | |||
660 | node; | 694 | node; |
661 | node = avtab_search_node_next(node, avkey.specified)) { | 695 | node = avtab_search_node_next(node, avkey.specified)) { |
662 | if (node->key.specified == AVTAB_ALLOWED) | 696 | if (node->key.specified == AVTAB_ALLOWED) |
663 | avd->allowed |= node->datum.data; | 697 | avd->allowed |= node->datum.u.data; |
664 | else if (node->key.specified == AVTAB_AUDITALLOW) | 698 | else if (node->key.specified == AVTAB_AUDITALLOW) |
665 | avd->auditallow |= node->datum.data; | 699 | avd->auditallow |= node->datum.u.data; |
666 | else if (node->key.specified == AVTAB_AUDITDENY) | 700 | else if (node->key.specified == AVTAB_AUDITDENY) |
667 | avd->auditdeny &= node->datum.data; | 701 | avd->auditdeny &= node->datum.u.data; |
702 | else if (xperms && (node->key.specified & AVTAB_XPERMS)) | ||
703 | services_compute_xperms_drivers(xperms, node); | ||
668 | } | 704 | } |
669 | 705 | ||
670 | /* Check conditional av table for additional permissions */ | 706 | /* Check conditional av table for additional permissions */ |
671 | cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); | 707 | cond_compute_av(&policydb.te_cond_avtab, &avkey, |
708 | avd, xperms); | ||
672 | 709 | ||
673 | } | 710 | } |
674 | } | 711 | } |
@@ -899,6 +936,139 @@ static void avd_init(struct av_decision *avd) | |||
899 | avd->flags = 0; | 936 | avd->flags = 0; |
900 | } | 937 | } |
901 | 938 | ||
939 | void services_compute_xperms_decision(struct extended_perms_decision *xpermd, | ||
940 | struct avtab_node *node) | ||
941 | { | ||
942 | unsigned int i; | ||
943 | |||
944 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
945 | if (xpermd->driver != node->datum.u.xperms->driver) | ||
946 | return; | ||
947 | } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
948 | if (!security_xperm_test(node->datum.u.xperms->perms.p, | ||
949 | xpermd->driver)) | ||
950 | return; | ||
951 | } else { | ||
952 | BUG(); | ||
953 | } | ||
954 | |||
955 | if (node->key.specified == AVTAB_XPERMS_ALLOWED) { | ||
956 | xpermd->used |= XPERMS_ALLOWED; | ||
957 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
958 | memset(xpermd->allowed->p, 0xff, | ||
959 | sizeof(xpermd->allowed->p)); | ||
960 | } | ||
961 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
962 | for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++) | ||
963 | xpermd->allowed->p[i] |= | ||
964 | node->datum.u.xperms->perms.p[i]; | ||
965 | } | ||
966 | } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { | ||
967 | xpermd->used |= XPERMS_AUDITALLOW; | ||
968 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
969 | memset(xpermd->auditallow->p, 0xff, | ||
970 | sizeof(xpermd->auditallow->p)); | ||
971 | } | ||
972 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
973 | for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++) | ||
974 | xpermd->auditallow->p[i] |= | ||
975 | node->datum.u.xperms->perms.p[i]; | ||
976 | } | ||
977 | } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { | ||
978 | xpermd->used |= XPERMS_DONTAUDIT; | ||
979 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { | ||
980 | memset(xpermd->dontaudit->p, 0xff, | ||
981 | sizeof(xpermd->dontaudit->p)); | ||
982 | } | ||
983 | if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { | ||
984 | for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++) | ||
985 | xpermd->dontaudit->p[i] |= | ||
986 | node->datum.u.xperms->perms.p[i]; | ||
987 | } | ||
988 | } else { | ||
989 | BUG(); | ||
990 | } | ||
991 | } | ||
992 | |||
993 | void security_compute_xperms_decision(u32 ssid, | ||
994 | u32 tsid, | ||
995 | u16 orig_tclass, | ||
996 | u8 driver, | ||
997 | struct extended_perms_decision *xpermd) | ||
998 | { | ||
999 | u16 tclass; | ||
1000 | struct context *scontext, *tcontext; | ||
1001 | struct avtab_key avkey; | ||
1002 | struct avtab_node *node; | ||
1003 | struct ebitmap *sattr, *tattr; | ||
1004 | struct ebitmap_node *snode, *tnode; | ||
1005 | unsigned int i, j; | ||
1006 | |||
1007 | xpermd->driver = driver; | ||
1008 | xpermd->used = 0; | ||
1009 | memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p)); | ||
1010 | memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); | ||
1011 | memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); | ||
1012 | |||
1013 | read_lock(&policy_rwlock); | ||
1014 | if (!ss_initialized) | ||
1015 | goto allow; | ||
1016 | |||
1017 | scontext = sidtab_search(&sidtab, ssid); | ||
1018 | if (!scontext) { | ||
1019 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
1020 | __func__, ssid); | ||
1021 | goto out; | ||
1022 | } | ||
1023 | |||
1024 | tcontext = sidtab_search(&sidtab, tsid); | ||
1025 | if (!tcontext) { | ||
1026 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
1027 | __func__, tsid); | ||
1028 | goto out; | ||
1029 | } | ||
1030 | |||
1031 | tclass = unmap_class(orig_tclass); | ||
1032 | if (unlikely(orig_tclass && !tclass)) { | ||
1033 | if (policydb.allow_unknown) | ||
1034 | goto allow; | ||
1035 | goto out; | ||
1036 | } | ||
1037 | |||
1038 | |||
1039 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { | ||
1040 | pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass); | ||
1041 | goto out; | ||
1042 | } | ||
1043 | |||
1044 | avkey.target_class = tclass; | ||
1045 | avkey.specified = AVTAB_XPERMS; | ||
1046 | sattr = flex_array_get(policydb.type_attr_map_array, | ||
1047 | scontext->type - 1); | ||
1048 | BUG_ON(!sattr); | ||
1049 | tattr = flex_array_get(policydb.type_attr_map_array, | ||
1050 | tcontext->type - 1); | ||
1051 | BUG_ON(!tattr); | ||
1052 | ebitmap_for_each_positive_bit(sattr, snode, i) { | ||
1053 | ebitmap_for_each_positive_bit(tattr, tnode, j) { | ||
1054 | avkey.source_type = i + 1; | ||
1055 | avkey.target_type = j + 1; | ||
1056 | for (node = avtab_search_node(&policydb.te_avtab, &avkey); | ||
1057 | node; | ||
1058 | node = avtab_search_node_next(node, avkey.specified)) | ||
1059 | services_compute_xperms_decision(xpermd, node); | ||
1060 | |||
1061 | cond_compute_xperms(&policydb.te_cond_avtab, | ||
1062 | &avkey, xpermd); | ||
1063 | } | ||
1064 | } | ||
1065 | out: | ||
1066 | read_unlock(&policy_rwlock); | ||
1067 | return; | ||
1068 | allow: | ||
1069 | memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); | ||
1070 | goto out; | ||
1071 | } | ||
902 | 1072 | ||
903 | /** | 1073 | /** |
904 | * security_compute_av - Compute access vector decisions. | 1074 | * security_compute_av - Compute access vector decisions. |
@@ -906,6 +1076,7 @@ static void avd_init(struct av_decision *avd) | |||
906 | * @tsid: target security identifier | 1076 | * @tsid: target security identifier |
907 | * @tclass: target security class | 1077 | * @tclass: target security class |
908 | * @avd: access vector decisions | 1078 | * @avd: access vector decisions |
1079 | * @xperms: extended permissions | ||
909 | * | 1080 | * |
910 | * Compute a set of access vector decisions based on the | 1081 | * Compute a set of access vector decisions based on the |
911 | * SID pair (@ssid, @tsid) for the permissions in @tclass. | 1082 | * SID pair (@ssid, @tsid) for the permissions in @tclass. |
@@ -913,13 +1084,15 @@ static void avd_init(struct av_decision *avd) | |||
913 | void security_compute_av(u32 ssid, | 1084 | void security_compute_av(u32 ssid, |
914 | u32 tsid, | 1085 | u32 tsid, |
915 | u16 orig_tclass, | 1086 | u16 orig_tclass, |
916 | struct av_decision *avd) | 1087 | struct av_decision *avd, |
1088 | struct extended_perms *xperms) | ||
917 | { | 1089 | { |
918 | u16 tclass; | 1090 | u16 tclass; |
919 | struct context *scontext = NULL, *tcontext = NULL; | 1091 | struct context *scontext = NULL, *tcontext = NULL; |
920 | 1092 | ||
921 | read_lock(&policy_rwlock); | 1093 | read_lock(&policy_rwlock); |
922 | avd_init(avd); | 1094 | avd_init(avd); |
1095 | xperms->len = 0; | ||
923 | if (!ss_initialized) | 1096 | if (!ss_initialized) |
924 | goto allow; | 1097 | goto allow; |
925 | 1098 | ||
@@ -947,7 +1120,7 @@ void security_compute_av(u32 ssid, | |||
947 | goto allow; | 1120 | goto allow; |
948 | goto out; | 1121 | goto out; |
949 | } | 1122 | } |
950 | context_struct_compute_av(scontext, tcontext, tclass, avd); | 1123 | context_struct_compute_av(scontext, tcontext, tclass, avd, xperms); |
951 | map_decision(orig_tclass, avd, policydb.allow_unknown); | 1124 | map_decision(orig_tclass, avd, policydb.allow_unknown); |
952 | out: | 1125 | out: |
953 | read_unlock(&policy_rwlock); | 1126 | read_unlock(&policy_rwlock); |
@@ -993,7 +1166,7 @@ void security_compute_av_user(u32 ssid, | |||
993 | goto out; | 1166 | goto out; |
994 | } | 1167 | } |
995 | 1168 | ||
996 | context_struct_compute_av(scontext, tcontext, tclass, avd); | 1169 | context_struct_compute_av(scontext, tcontext, tclass, avd, NULL); |
997 | out: | 1170 | out: |
998 | read_unlock(&policy_rwlock); | 1171 | read_unlock(&policy_rwlock); |
999 | return; | 1172 | return; |
@@ -1515,7 +1688,7 @@ static int security_compute_sid(u32 ssid, | |||
1515 | 1688 | ||
1516 | if (avdatum) { | 1689 | if (avdatum) { |
1517 | /* Use the type from the type transition/member/change rule. */ | 1690 | /* Use the type from the type transition/member/change rule. */ |
1518 | newcontext.type = avdatum->data; | 1691 | newcontext.type = avdatum->u.data; |
1519 | } | 1692 | } |
1520 | 1693 | ||
1521 | /* if we have a objname this is a file trans check so check those rules */ | 1694 | /* if we have a objname this is a file trans check so check those rules */ |
diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h index e8d907e903cd..6abcd8729ec3 100644 --- a/security/selinux/ss/services.h +++ b/security/selinux/ss/services.h | |||
@@ -11,5 +11,11 @@ | |||
11 | 11 | ||
12 | extern struct policydb policydb; | 12 | extern struct policydb policydb; |
13 | 13 | ||
14 | void services_compute_xperms_drivers(struct extended_perms *xperms, | ||
15 | struct avtab_node *node); | ||
16 | |||
17 | void services_compute_xperms_decision(struct extended_perms_decision *xpermd, | ||
18 | struct avtab_node *node); | ||
19 | |||
14 | #endif /* _SS_SERVICES_H_ */ | 20 | #endif /* _SS_SERVICES_H_ */ |
15 | 21 | ||
diff --git a/security/smack/smack.h b/security/smack/smack.h index 244e035e5a99..fff0c612bbb7 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -17,12 +17,27 @@ | |||
17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
18 | #include <linux/lsm_hooks.h> | 18 | #include <linux/lsm_hooks.h> |
19 | #include <linux/in.h> | 19 | #include <linux/in.h> |
20 | #if IS_ENABLED(CONFIG_IPV6) | ||
21 | #include <linux/in6.h> | ||
22 | #endif /* CONFIG_IPV6 */ | ||
20 | #include <net/netlabel.h> | 23 | #include <net/netlabel.h> |
21 | #include <linux/list.h> | 24 | #include <linux/list.h> |
22 | #include <linux/rculist.h> | 25 | #include <linux/rculist.h> |
23 | #include <linux/lsm_audit.h> | 26 | #include <linux/lsm_audit.h> |
24 | 27 | ||
25 | /* | 28 | /* |
29 | * Use IPv6 port labeling if IPv6 is enabled and secmarks | ||
30 | * are not being used. | ||
31 | */ | ||
32 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | ||
33 | #define SMACK_IPV6_PORT_LABELING 1 | ||
34 | #endif | ||
35 | |||
36 | #if IS_ENABLED(CONFIG_IPV6) && defined(CONFIG_SECURITY_SMACK_NETFILTER) | ||
37 | #define SMACK_IPV6_SECMARK_LABELING 1 | ||
38 | #endif | ||
39 | |||
40 | /* | ||
26 | * Smack labels were limited to 23 characters for a long time. | 41 | * Smack labels were limited to 23 characters for a long time. |
27 | */ | 42 | */ |
28 | #define SMK_LABELLEN 24 | 43 | #define SMK_LABELLEN 24 |
@@ -118,15 +133,30 @@ struct smack_rule { | |||
118 | }; | 133 | }; |
119 | 134 | ||
120 | /* | 135 | /* |
121 | * An entry in the table identifying hosts. | 136 | * An entry in the table identifying IPv4 hosts. |
122 | */ | 137 | */ |
123 | struct smk_netlbladdr { | 138 | struct smk_net4addr { |
124 | struct list_head list; | 139 | struct list_head list; |
125 | struct sockaddr_in smk_host; /* network address */ | 140 | struct in_addr smk_host; /* network address */ |
126 | struct in_addr smk_mask; /* network mask */ | 141 | struct in_addr smk_mask; /* network mask */ |
142 | int smk_masks; /* mask size */ | ||
143 | struct smack_known *smk_label; /* label */ | ||
144 | }; | ||
145 | |||
146 | #if IS_ENABLED(CONFIG_IPV6) | ||
147 | /* | ||
148 | * An entry in the table identifying IPv6 hosts. | ||
149 | */ | ||
150 | struct smk_net6addr { | ||
151 | struct list_head list; | ||
152 | struct in6_addr smk_host; /* network address */ | ||
153 | struct in6_addr smk_mask; /* network mask */ | ||
154 | int smk_masks; /* mask size */ | ||
127 | struct smack_known *smk_label; /* label */ | 155 | struct smack_known *smk_label; /* label */ |
128 | }; | 156 | }; |
157 | #endif /* CONFIG_IPV6 */ | ||
129 | 158 | ||
159 | #ifdef SMACK_IPV6_PORT_LABELING | ||
130 | /* | 160 | /* |
131 | * An entry in the table identifying ports. | 161 | * An entry in the table identifying ports. |
132 | */ | 162 | */ |
@@ -137,12 +167,31 @@ struct smk_port_label { | |||
137 | struct smack_known *smk_in; /* inbound label */ | 167 | struct smack_known *smk_in; /* inbound label */ |
138 | struct smack_known *smk_out; /* outgoing label */ | 168 | struct smack_known *smk_out; /* outgoing label */ |
139 | }; | 169 | }; |
170 | #endif /* SMACK_IPV6_PORT_LABELING */ | ||
140 | 171 | ||
141 | struct smack_onlycap { | 172 | struct smack_onlycap { |
142 | struct list_head list; | 173 | struct list_head list; |
143 | struct smack_known *smk_label; | 174 | struct smack_known *smk_label; |
144 | }; | 175 | }; |
145 | 176 | ||
177 | /* Super block security struct flags for mount options */ | ||
178 | #define FSDEFAULT_MNT 0x01 | ||
179 | #define FSFLOOR_MNT 0x02 | ||
180 | #define FSHAT_MNT 0x04 | ||
181 | #define FSROOT_MNT 0x08 | ||
182 | #define FSTRANS_MNT 0x10 | ||
183 | |||
184 | #define NUM_SMK_MNT_OPTS 5 | ||
185 | |||
186 | enum { | ||
187 | Opt_error = -1, | ||
188 | Opt_fsdefault = 1, | ||
189 | Opt_fsfloor = 2, | ||
190 | Opt_fshat = 3, | ||
191 | Opt_fsroot = 4, | ||
192 | Opt_fstransmute = 5, | ||
193 | }; | ||
194 | |||
146 | /* | 195 | /* |
147 | * Mount options | 196 | * Mount options |
148 | */ | 197 | */ |
@@ -152,6 +201,7 @@ struct smack_onlycap { | |||
152 | #define SMK_FSROOT "smackfsroot=" | 201 | #define SMK_FSROOT "smackfsroot=" |
153 | #define SMK_FSTRANS "smackfstransmute=" | 202 | #define SMK_FSTRANS "smackfstransmute=" |
154 | 203 | ||
204 | #define SMACK_DELETE_OPTION "-DELETE" | ||
155 | #define SMACK_CIPSO_OPTION "-CIPSO" | 205 | #define SMACK_CIPSO_OPTION "-CIPSO" |
156 | 206 | ||
157 | /* | 207 | /* |
@@ -234,10 +284,6 @@ struct smk_audit_info { | |||
234 | struct smack_audit_data sad; | 284 | struct smack_audit_data sad; |
235 | #endif | 285 | #endif |
236 | }; | 286 | }; |
237 | /* | ||
238 | * These functions are in smack_lsm.c | ||
239 | */ | ||
240 | struct inode_smack *new_inode_smack(struct smack_known *); | ||
241 | 287 | ||
242 | /* | 288 | /* |
243 | * These functions are in smack_access.c | 289 | * These functions are in smack_access.c |
@@ -267,7 +313,6 @@ extern struct smack_known *smack_syslog_label; | |||
267 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 313 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
268 | extern struct smack_known *smack_unconfined; | 314 | extern struct smack_known *smack_unconfined; |
269 | #endif | 315 | #endif |
270 | extern struct smack_known smack_cipso_option; | ||
271 | extern int smack_ptrace_rule; | 316 | extern int smack_ptrace_rule; |
272 | 317 | ||
273 | extern struct smack_known smack_known_floor; | 318 | extern struct smack_known smack_known_floor; |
@@ -279,7 +324,10 @@ extern struct smack_known smack_known_web; | |||
279 | 324 | ||
280 | extern struct mutex smack_known_lock; | 325 | extern struct mutex smack_known_lock; |
281 | extern struct list_head smack_known_list; | 326 | extern struct list_head smack_known_list; |
282 | extern struct list_head smk_netlbladdr_list; | 327 | extern struct list_head smk_net4addr_list; |
328 | #if IS_ENABLED(CONFIG_IPV6) | ||
329 | extern struct list_head smk_net6addr_list; | ||
330 | #endif /* CONFIG_IPV6 */ | ||
283 | 331 | ||
284 | extern struct mutex smack_onlycap_lock; | 332 | extern struct mutex smack_onlycap_lock; |
285 | extern struct list_head smack_onlycap_list; | 333 | extern struct list_head smack_onlycap_list; |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 00f6b38bffbd..bc1053fb5d1d 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -639,6 +639,12 @@ int smack_privileged(int cap) | |||
639 | struct smack_known *skp = smk_of_current(); | 639 | struct smack_known *skp = smk_of_current(); |
640 | struct smack_onlycap *sop; | 640 | struct smack_onlycap *sop; |
641 | 641 | ||
642 | /* | ||
643 | * All kernel tasks are privileged | ||
644 | */ | ||
645 | if (unlikely(current->flags & PF_KTHREAD)) | ||
646 | return 1; | ||
647 | |||
642 | if (!capable(cap)) | 648 | if (!capable(cap)) |
643 | return 0; | 649 | return 0; |
644 | 650 | ||
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index a143328f75eb..996c88956438 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/msg.h> | 41 | #include <linux/msg.h> |
42 | #include <linux/shm.h> | 42 | #include <linux/shm.h> |
43 | #include <linux/binfmts.h> | 43 | #include <linux/binfmts.h> |
44 | #include <linux/parser.h> | ||
44 | #include "smack.h" | 45 | #include "smack.h" |
45 | 46 | ||
46 | #define TRANS_TRUE "TRUE" | 47 | #define TRANS_TRUE "TRUE" |
@@ -50,12 +51,21 @@ | |||
50 | #define SMK_RECEIVING 1 | 51 | #define SMK_RECEIVING 1 |
51 | #define SMK_SENDING 2 | 52 | #define SMK_SENDING 2 |
52 | 53 | ||
53 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 54 | #ifdef SMACK_IPV6_PORT_LABELING |
54 | LIST_HEAD(smk_ipv6_port_list); | 55 | LIST_HEAD(smk_ipv6_port_list); |
55 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 56 | #endif |
56 | static struct kmem_cache *smack_inode_cache; | 57 | static struct kmem_cache *smack_inode_cache; |
57 | int smack_enabled; | 58 | int smack_enabled; |
58 | 59 | ||
60 | static const match_table_t smk_mount_tokens = { | ||
61 | {Opt_fsdefault, SMK_FSDEFAULT "%s"}, | ||
62 | {Opt_fsfloor, SMK_FSFLOOR "%s"}, | ||
63 | {Opt_fshat, SMK_FSHAT "%s"}, | ||
64 | {Opt_fsroot, SMK_FSROOT "%s"}, | ||
65 | {Opt_fstransmute, SMK_FSTRANS "%s"}, | ||
66 | {Opt_error, NULL}, | ||
67 | }; | ||
68 | |||
59 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 69 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
60 | static char *smk_bu_mess[] = { | 70 | static char *smk_bu_mess[] = { |
61 | "Bringup Error", /* Unused */ | 71 | "Bringup Error", /* Unused */ |
@@ -281,7 +291,7 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip, | |||
281 | * | 291 | * |
282 | * Returns the new blob or NULL if there's no memory available | 292 | * Returns the new blob or NULL if there's no memory available |
283 | */ | 293 | */ |
284 | struct inode_smack *new_inode_smack(struct smack_known *skp) | 294 | static struct inode_smack *new_inode_smack(struct smack_known *skp) |
285 | { | 295 | { |
286 | struct inode_smack *isp; | 296 | struct inode_smack *isp; |
287 | 297 | ||
@@ -577,76 +587,197 @@ static int smack_sb_copy_data(char *orig, char *smackopts) | |||
577 | } | 587 | } |
578 | 588 | ||
579 | /** | 589 | /** |
580 | * smack_sb_kern_mount - Smack specific mount processing | 590 | * smack_parse_opts_str - parse Smack specific mount options |
591 | * @options: mount options string | ||
592 | * @opts: where to store converted mount opts | ||
593 | * | ||
594 | * Returns 0 on success or -ENOMEM on error. | ||
595 | * | ||
596 | * converts Smack specific mount options to generic security option format | ||
597 | */ | ||
598 | static int smack_parse_opts_str(char *options, | ||
599 | struct security_mnt_opts *opts) | ||
600 | { | ||
601 | char *p; | ||
602 | char *fsdefault = NULL; | ||
603 | char *fsfloor = NULL; | ||
604 | char *fshat = NULL; | ||
605 | char *fsroot = NULL; | ||
606 | char *fstransmute = NULL; | ||
607 | int rc = -ENOMEM; | ||
608 | int num_mnt_opts = 0; | ||
609 | int token; | ||
610 | |||
611 | opts->num_mnt_opts = 0; | ||
612 | |||
613 | if (!options) | ||
614 | return 0; | ||
615 | |||
616 | while ((p = strsep(&options, ",")) != NULL) { | ||
617 | substring_t args[MAX_OPT_ARGS]; | ||
618 | |||
619 | if (!*p) | ||
620 | continue; | ||
621 | |||
622 | token = match_token(p, smk_mount_tokens, args); | ||
623 | |||
624 | switch (token) { | ||
625 | case Opt_fsdefault: | ||
626 | if (fsdefault) | ||
627 | goto out_opt_err; | ||
628 | fsdefault = match_strdup(&args[0]); | ||
629 | if (!fsdefault) | ||
630 | goto out_err; | ||
631 | break; | ||
632 | case Opt_fsfloor: | ||
633 | if (fsfloor) | ||
634 | goto out_opt_err; | ||
635 | fsfloor = match_strdup(&args[0]); | ||
636 | if (!fsfloor) | ||
637 | goto out_err; | ||
638 | break; | ||
639 | case Opt_fshat: | ||
640 | if (fshat) | ||
641 | goto out_opt_err; | ||
642 | fshat = match_strdup(&args[0]); | ||
643 | if (!fshat) | ||
644 | goto out_err; | ||
645 | break; | ||
646 | case Opt_fsroot: | ||
647 | if (fsroot) | ||
648 | goto out_opt_err; | ||
649 | fsroot = match_strdup(&args[0]); | ||
650 | if (!fsroot) | ||
651 | goto out_err; | ||
652 | break; | ||
653 | case Opt_fstransmute: | ||
654 | if (fstransmute) | ||
655 | goto out_opt_err; | ||
656 | fstransmute = match_strdup(&args[0]); | ||
657 | if (!fstransmute) | ||
658 | goto out_err; | ||
659 | break; | ||
660 | default: | ||
661 | rc = -EINVAL; | ||
662 | pr_warn("Smack: unknown mount option\n"); | ||
663 | goto out_err; | ||
664 | } | ||
665 | } | ||
666 | |||
667 | opts->mnt_opts = kcalloc(NUM_SMK_MNT_OPTS, sizeof(char *), GFP_ATOMIC); | ||
668 | if (!opts->mnt_opts) | ||
669 | goto out_err; | ||
670 | |||
671 | opts->mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS, sizeof(int), | ||
672 | GFP_ATOMIC); | ||
673 | if (!opts->mnt_opts_flags) { | ||
674 | kfree(opts->mnt_opts); | ||
675 | goto out_err; | ||
676 | } | ||
677 | |||
678 | if (fsdefault) { | ||
679 | opts->mnt_opts[num_mnt_opts] = fsdefault; | ||
680 | opts->mnt_opts_flags[num_mnt_opts++] = FSDEFAULT_MNT; | ||
681 | } | ||
682 | if (fsfloor) { | ||
683 | opts->mnt_opts[num_mnt_opts] = fsfloor; | ||
684 | opts->mnt_opts_flags[num_mnt_opts++] = FSFLOOR_MNT; | ||
685 | } | ||
686 | if (fshat) { | ||
687 | opts->mnt_opts[num_mnt_opts] = fshat; | ||
688 | opts->mnt_opts_flags[num_mnt_opts++] = FSHAT_MNT; | ||
689 | } | ||
690 | if (fsroot) { | ||
691 | opts->mnt_opts[num_mnt_opts] = fsroot; | ||
692 | opts->mnt_opts_flags[num_mnt_opts++] = FSROOT_MNT; | ||
693 | } | ||
694 | if (fstransmute) { | ||
695 | opts->mnt_opts[num_mnt_opts] = fstransmute; | ||
696 | opts->mnt_opts_flags[num_mnt_opts++] = FSTRANS_MNT; | ||
697 | } | ||
698 | |||
699 | opts->num_mnt_opts = num_mnt_opts; | ||
700 | return 0; | ||
701 | |||
702 | out_opt_err: | ||
703 | rc = -EINVAL; | ||
704 | pr_warn("Smack: duplicate mount options\n"); | ||
705 | |||
706 | out_err: | ||
707 | kfree(fsdefault); | ||
708 | kfree(fsfloor); | ||
709 | kfree(fshat); | ||
710 | kfree(fsroot); | ||
711 | kfree(fstransmute); | ||
712 | return rc; | ||
713 | } | ||
714 | |||
715 | /** | ||
716 | * smack_set_mnt_opts - set Smack specific mount options | ||
581 | * @sb: the file system superblock | 717 | * @sb: the file system superblock |
582 | * @flags: the mount flags | 718 | * @opts: Smack mount options |
583 | * @data: the smack mount options | 719 | * @kern_flags: mount option from kernel space or user space |
720 | * @set_kern_flags: where to store converted mount opts | ||
584 | * | 721 | * |
585 | * Returns 0 on success, an error code on failure | 722 | * Returns 0 on success, an error code on failure |
723 | * | ||
724 | * Allow filesystems with binary mount data to explicitly set Smack mount | ||
725 | * labels. | ||
586 | */ | 726 | */ |
587 | static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | 727 | static int smack_set_mnt_opts(struct super_block *sb, |
728 | struct security_mnt_opts *opts, | ||
729 | unsigned long kern_flags, | ||
730 | unsigned long *set_kern_flags) | ||
588 | { | 731 | { |
589 | struct dentry *root = sb->s_root; | 732 | struct dentry *root = sb->s_root; |
590 | struct inode *inode = d_backing_inode(root); | 733 | struct inode *inode = d_backing_inode(root); |
591 | struct superblock_smack *sp = sb->s_security; | 734 | struct superblock_smack *sp = sb->s_security; |
592 | struct inode_smack *isp; | 735 | struct inode_smack *isp; |
593 | struct smack_known *skp; | 736 | struct smack_known *skp; |
594 | char *op; | 737 | int i; |
595 | char *commap; | 738 | int num_opts = opts->num_mnt_opts; |
596 | int transmute = 0; | 739 | int transmute = 0; |
597 | int specified = 0; | ||
598 | 740 | ||
599 | if (sp->smk_initialized) | 741 | if (sp->smk_initialized) |
600 | return 0; | 742 | return 0; |
601 | 743 | ||
602 | sp->smk_initialized = 1; | 744 | sp->smk_initialized = 1; |
603 | 745 | ||
604 | for (op = data; op != NULL; op = commap) { | 746 | for (i = 0; i < num_opts; i++) { |
605 | commap = strchr(op, ','); | 747 | switch (opts->mnt_opts_flags[i]) { |
606 | if (commap != NULL) | 748 | case FSDEFAULT_MNT: |
607 | *commap++ = '\0'; | 749 | skp = smk_import_entry(opts->mnt_opts[i], 0); |
608 | |||
609 | if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) { | ||
610 | op += strlen(SMK_FSHAT); | ||
611 | skp = smk_import_entry(op, 0); | ||
612 | if (IS_ERR(skp)) | 750 | if (IS_ERR(skp)) |
613 | return PTR_ERR(skp); | 751 | return PTR_ERR(skp); |
614 | sp->smk_hat = skp; | 752 | sp->smk_default = skp; |
615 | specified = 1; | 753 | break; |
616 | 754 | case FSFLOOR_MNT: | |
617 | } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) { | 755 | skp = smk_import_entry(opts->mnt_opts[i], 0); |
618 | op += strlen(SMK_FSFLOOR); | ||
619 | skp = smk_import_entry(op, 0); | ||
620 | if (IS_ERR(skp)) | 756 | if (IS_ERR(skp)) |
621 | return PTR_ERR(skp); | 757 | return PTR_ERR(skp); |
622 | sp->smk_floor = skp; | 758 | sp->smk_floor = skp; |
623 | specified = 1; | 759 | break; |
624 | 760 | case FSHAT_MNT: | |
625 | } else if (strncmp(op, SMK_FSDEFAULT, | 761 | skp = smk_import_entry(opts->mnt_opts[i], 0); |
626 | strlen(SMK_FSDEFAULT)) == 0) { | ||
627 | op += strlen(SMK_FSDEFAULT); | ||
628 | skp = smk_import_entry(op, 0); | ||
629 | if (IS_ERR(skp)) | 762 | if (IS_ERR(skp)) |
630 | return PTR_ERR(skp); | 763 | return PTR_ERR(skp); |
631 | sp->smk_default = skp; | 764 | sp->smk_hat = skp; |
632 | specified = 1; | 765 | break; |
633 | 766 | case FSROOT_MNT: | |
634 | } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) { | 767 | skp = smk_import_entry(opts->mnt_opts[i], 0); |
635 | op += strlen(SMK_FSROOT); | ||
636 | skp = smk_import_entry(op, 0); | ||
637 | if (IS_ERR(skp)) | 768 | if (IS_ERR(skp)) |
638 | return PTR_ERR(skp); | 769 | return PTR_ERR(skp); |
639 | sp->smk_root = skp; | 770 | sp->smk_root = skp; |
640 | specified = 1; | 771 | break; |
641 | 772 | case FSTRANS_MNT: | |
642 | } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { | 773 | skp = smk_import_entry(opts->mnt_opts[i], 0); |
643 | op += strlen(SMK_FSTRANS); | ||
644 | skp = smk_import_entry(op, 0); | ||
645 | if (IS_ERR(skp)) | 774 | if (IS_ERR(skp)) |
646 | return PTR_ERR(skp); | 775 | return PTR_ERR(skp); |
647 | sp->smk_root = skp; | 776 | sp->smk_root = skp; |
648 | transmute = 1; | 777 | transmute = 1; |
649 | specified = 1; | 778 | break; |
779 | default: | ||
780 | break; | ||
650 | } | 781 | } |
651 | } | 782 | } |
652 | 783 | ||
@@ -654,7 +785,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
654 | /* | 785 | /* |
655 | * Unprivileged mounts don't get to specify Smack values. | 786 | * Unprivileged mounts don't get to specify Smack values. |
656 | */ | 787 | */ |
657 | if (specified) | 788 | if (num_opts) |
658 | return -EPERM; | 789 | return -EPERM; |
659 | /* | 790 | /* |
660 | * Unprivileged mounts get root and default from the caller. | 791 | * Unprivileged mounts get root and default from the caller. |
@@ -663,6 +794,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
663 | sp->smk_root = skp; | 794 | sp->smk_root = skp; |
664 | sp->smk_default = skp; | 795 | sp->smk_default = skp; |
665 | } | 796 | } |
797 | |||
666 | /* | 798 | /* |
667 | * Initialize the root inode. | 799 | * Initialize the root inode. |
668 | */ | 800 | */ |
@@ -682,6 +814,37 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
682 | } | 814 | } |
683 | 815 | ||
684 | /** | 816 | /** |
817 | * smack_sb_kern_mount - Smack specific mount processing | ||
818 | * @sb: the file system superblock | ||
819 | * @flags: the mount flags | ||
820 | * @data: the smack mount options | ||
821 | * | ||
822 | * Returns 0 on success, an error code on failure | ||
823 | */ | ||
824 | static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | ||
825 | { | ||
826 | int rc = 0; | ||
827 | char *options = data; | ||
828 | struct security_mnt_opts opts; | ||
829 | |||
830 | security_init_mnt_opts(&opts); | ||
831 | |||
832 | if (!options) | ||
833 | goto out; | ||
834 | |||
835 | rc = smack_parse_opts_str(options, &opts); | ||
836 | if (rc) | ||
837 | goto out_err; | ||
838 | |||
839 | out: | ||
840 | rc = smack_set_mnt_opts(sb, &opts, 0, NULL); | ||
841 | |||
842 | out_err: | ||
843 | security_free_mnt_opts(&opts); | ||
844 | return rc; | ||
845 | } | ||
846 | |||
847 | /** | ||
685 | * smack_sb_statfs - Smack check on statfs | 848 | * smack_sb_statfs - Smack check on statfs |
686 | * @dentry: identifies the file system in question | 849 | * @dentry: identifies the file system in question |
687 | * | 850 | * |
@@ -2113,7 +2276,7 @@ static void smack_sk_free_security(struct sock *sk) | |||
2113 | } | 2276 | } |
2114 | 2277 | ||
2115 | /** | 2278 | /** |
2116 | * smack_host_label - check host based restrictions | 2279 | * smack_ipv4host_label - check host based restrictions |
2117 | * @sip: the object end | 2280 | * @sip: the object end |
2118 | * | 2281 | * |
2119 | * looks for host based access restrictions | 2282 | * looks for host based access restrictions |
@@ -2124,30 +2287,96 @@ static void smack_sk_free_security(struct sock *sk) | |||
2124 | * | 2287 | * |
2125 | * Returns the label of the far end or NULL if it's not special. | 2288 | * Returns the label of the far end or NULL if it's not special. |
2126 | */ | 2289 | */ |
2127 | static struct smack_known *smack_host_label(struct sockaddr_in *sip) | 2290 | static struct smack_known *smack_ipv4host_label(struct sockaddr_in *sip) |
2128 | { | 2291 | { |
2129 | struct smk_netlbladdr *snp; | 2292 | struct smk_net4addr *snp; |
2130 | struct in_addr *siap = &sip->sin_addr; | 2293 | struct in_addr *siap = &sip->sin_addr; |
2131 | 2294 | ||
2132 | if (siap->s_addr == 0) | 2295 | if (siap->s_addr == 0) |
2133 | return NULL; | 2296 | return NULL; |
2134 | 2297 | ||
2135 | list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) | 2298 | list_for_each_entry_rcu(snp, &smk_net4addr_list, list) |
2299 | /* | ||
2300 | * we break after finding the first match because | ||
2301 | * the list is sorted from longest to shortest mask | ||
2302 | * so we have found the most specific match | ||
2303 | */ | ||
2304 | if (snp->smk_host.s_addr == | ||
2305 | (siap->s_addr & snp->smk_mask.s_addr)) | ||
2306 | return snp->smk_label; | ||
2307 | |||
2308 | return NULL; | ||
2309 | } | ||
2310 | |||
2311 | #if IS_ENABLED(CONFIG_IPV6) | ||
2312 | /* | ||
2313 | * smk_ipv6_localhost - Check for local ipv6 host address | ||
2314 | * @sip: the address | ||
2315 | * | ||
2316 | * Returns boolean true if this is the localhost address | ||
2317 | */ | ||
2318 | static bool smk_ipv6_localhost(struct sockaddr_in6 *sip) | ||
2319 | { | ||
2320 | __be16 *be16p = (__be16 *)&sip->sin6_addr; | ||
2321 | __be32 *be32p = (__be32 *)&sip->sin6_addr; | ||
2322 | |||
2323 | if (be32p[0] == 0 && be32p[1] == 0 && be32p[2] == 0 && be16p[6] == 0 && | ||
2324 | ntohs(be16p[7]) == 1) | ||
2325 | return true; | ||
2326 | return false; | ||
2327 | } | ||
2328 | |||
2329 | /** | ||
2330 | * smack_ipv6host_label - check host based restrictions | ||
2331 | * @sip: the object end | ||
2332 | * | ||
2333 | * looks for host based access restrictions | ||
2334 | * | ||
2335 | * This version will only be appropriate for really small sets of single label | ||
2336 | * hosts. The caller is responsible for ensuring that the RCU read lock is | ||
2337 | * taken before calling this function. | ||
2338 | * | ||
2339 | * Returns the label of the far end or NULL if it's not special. | ||
2340 | */ | ||
2341 | static struct smack_known *smack_ipv6host_label(struct sockaddr_in6 *sip) | ||
2342 | { | ||
2343 | struct smk_net6addr *snp; | ||
2344 | struct in6_addr *sap = &sip->sin6_addr; | ||
2345 | int i; | ||
2346 | int found = 0; | ||
2347 | |||
2348 | /* | ||
2349 | * It's local. Don't look for a host label. | ||
2350 | */ | ||
2351 | if (smk_ipv6_localhost(sip)) | ||
2352 | return NULL; | ||
2353 | |||
2354 | list_for_each_entry_rcu(snp, &smk_net6addr_list, list) { | ||
2136 | /* | 2355 | /* |
2137 | * we break after finding the first match because | 2356 | * we break after finding the first match because |
2138 | * the list is sorted from longest to shortest mask | 2357 | * the list is sorted from longest to shortest mask |
2139 | * so we have found the most specific match | 2358 | * so we have found the most specific match |
2140 | */ | 2359 | */ |
2141 | if ((&snp->smk_host.sin_addr)->s_addr == | 2360 | for (found = 1, i = 0; i < 8; i++) { |
2142 | (siap->s_addr & (&snp->smk_mask)->s_addr)) { | 2361 | /* |
2143 | /* we have found the special CIPSO option */ | 2362 | * If the label is NULL the entry has |
2144 | if (snp->smk_label == &smack_cipso_option) | 2363 | * been renounced. Ignore it. |
2145 | return NULL; | 2364 | */ |
2146 | return snp->smk_label; | 2365 | if (snp->smk_label == NULL) |
2366 | continue; | ||
2367 | if ((sap->s6_addr16[i] & snp->smk_mask.s6_addr16[i]) != | ||
2368 | snp->smk_host.s6_addr16[i]) { | ||
2369 | found = 0; | ||
2370 | break; | ||
2371 | } | ||
2147 | } | 2372 | } |
2373 | if (found) | ||
2374 | return snp->smk_label; | ||
2375 | } | ||
2148 | 2376 | ||
2149 | return NULL; | 2377 | return NULL; |
2150 | } | 2378 | } |
2379 | #endif /* CONFIG_IPV6 */ | ||
2151 | 2380 | ||
2152 | /** | 2381 | /** |
2153 | * smack_netlabel - Set the secattr on a socket | 2382 | * smack_netlabel - Set the secattr on a socket |
@@ -2211,7 +2440,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) | |||
2211 | struct smk_audit_info ad; | 2440 | struct smk_audit_info ad; |
2212 | 2441 | ||
2213 | rcu_read_lock(); | 2442 | rcu_read_lock(); |
2214 | hkp = smack_host_label(sap); | 2443 | hkp = smack_ipv4host_label(sap); |
2215 | if (hkp != NULL) { | 2444 | if (hkp != NULL) { |
2216 | #ifdef CONFIG_AUDIT | 2445 | #ifdef CONFIG_AUDIT |
2217 | struct lsm_network_audit net; | 2446 | struct lsm_network_audit net; |
@@ -2236,7 +2465,42 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) | |||
2236 | return smack_netlabel(sk, sk_lbl); | 2465 | return smack_netlabel(sk, sk_lbl); |
2237 | } | 2466 | } |
2238 | 2467 | ||
2239 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 2468 | #if IS_ENABLED(CONFIG_IPV6) |
2469 | /** | ||
2470 | * smk_ipv6_check - check Smack access | ||
2471 | * @subject: subject Smack label | ||
2472 | * @object: object Smack label | ||
2473 | * @address: address | ||
2474 | * @act: the action being taken | ||
2475 | * | ||
2476 | * Check an IPv6 access | ||
2477 | */ | ||
2478 | static int smk_ipv6_check(struct smack_known *subject, | ||
2479 | struct smack_known *object, | ||
2480 | struct sockaddr_in6 *address, int act) | ||
2481 | { | ||
2482 | #ifdef CONFIG_AUDIT | ||
2483 | struct lsm_network_audit net; | ||
2484 | #endif | ||
2485 | struct smk_audit_info ad; | ||
2486 | int rc; | ||
2487 | |||
2488 | #ifdef CONFIG_AUDIT | ||
2489 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); | ||
2490 | ad.a.u.net->family = PF_INET6; | ||
2491 | ad.a.u.net->dport = ntohs(address->sin6_port); | ||
2492 | if (act == SMK_RECEIVING) | ||
2493 | ad.a.u.net->v6info.saddr = address->sin6_addr; | ||
2494 | else | ||
2495 | ad.a.u.net->v6info.daddr = address->sin6_addr; | ||
2496 | #endif | ||
2497 | rc = smk_access(subject, object, MAY_WRITE, &ad); | ||
2498 | rc = smk_bu_note("IPv6 check", subject, object, MAY_WRITE, rc); | ||
2499 | return rc; | ||
2500 | } | ||
2501 | #endif /* CONFIG_IPV6 */ | ||
2502 | |||
2503 | #ifdef SMACK_IPV6_PORT_LABELING | ||
2240 | /** | 2504 | /** |
2241 | * smk_ipv6_port_label - Smack port access table management | 2505 | * smk_ipv6_port_label - Smack port access table management |
2242 | * @sock: socket | 2506 | * @sock: socket |
@@ -2320,48 +2584,43 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) | |||
2320 | static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, | 2584 | static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, |
2321 | int act) | 2585 | int act) |
2322 | { | 2586 | { |
2323 | __be16 *bep; | ||
2324 | __be32 *be32p; | ||
2325 | struct smk_port_label *spp; | 2587 | struct smk_port_label *spp; |
2326 | struct socket_smack *ssp = sk->sk_security; | 2588 | struct socket_smack *ssp = sk->sk_security; |
2327 | struct smack_known *skp; | 2589 | struct smack_known *skp = NULL; |
2328 | unsigned short port = 0; | 2590 | unsigned short port; |
2329 | struct smack_known *object; | 2591 | struct smack_known *object; |
2330 | struct smk_audit_info ad; | ||
2331 | int rc; | ||
2332 | #ifdef CONFIG_AUDIT | ||
2333 | struct lsm_network_audit net; | ||
2334 | #endif | ||
2335 | 2592 | ||
2336 | if (act == SMK_RECEIVING) { | 2593 | if (act == SMK_RECEIVING) { |
2337 | skp = smack_net_ambient; | 2594 | skp = smack_ipv6host_label(address); |
2338 | object = ssp->smk_in; | 2595 | object = ssp->smk_in; |
2339 | } else { | 2596 | } else { |
2340 | skp = ssp->smk_out; | 2597 | skp = ssp->smk_out; |
2341 | object = smack_net_ambient; | 2598 | object = smack_ipv6host_label(address); |
2342 | } | 2599 | } |
2343 | 2600 | ||
2344 | /* | 2601 | /* |
2345 | * Get the IP address and port from the address. | 2602 | * The other end is a single label host. |
2346 | */ | 2603 | */ |
2347 | port = ntohs(address->sin6_port); | 2604 | if (skp != NULL && object != NULL) |
2348 | bep = (__be16 *)(&address->sin6_addr); | 2605 | return smk_ipv6_check(skp, object, address, act); |
2349 | be32p = (__be32 *)(&address->sin6_addr); | 2606 | if (skp == NULL) |
2607 | skp = smack_net_ambient; | ||
2608 | if (object == NULL) | ||
2609 | object = smack_net_ambient; | ||
2350 | 2610 | ||
2351 | /* | 2611 | /* |
2352 | * It's remote, so port lookup does no good. | 2612 | * It's remote, so port lookup does no good. |
2353 | */ | 2613 | */ |
2354 | if (be32p[0] || be32p[1] || be32p[2] || bep[6] || ntohs(bep[7]) != 1) | 2614 | if (!smk_ipv6_localhost(address)) |
2355 | goto auditout; | 2615 | return smk_ipv6_check(skp, object, address, act); |
2356 | 2616 | ||
2357 | /* | 2617 | /* |
2358 | * It's local so the send check has to have passed. | 2618 | * It's local so the send check has to have passed. |
2359 | */ | 2619 | */ |
2360 | if (act == SMK_RECEIVING) { | 2620 | if (act == SMK_RECEIVING) |
2361 | skp = &smack_known_web; | 2621 | return 0; |
2362 | goto auditout; | ||
2363 | } | ||
2364 | 2622 | ||
2623 | port = ntohs(address->sin6_port); | ||
2365 | list_for_each_entry(spp, &smk_ipv6_port_list, list) { | 2624 | list_for_each_entry(spp, &smk_ipv6_port_list, list) { |
2366 | if (spp->smk_port != port) | 2625 | if (spp->smk_port != port) |
2367 | continue; | 2626 | continue; |
@@ -2371,22 +2630,9 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, | |||
2371 | break; | 2630 | break; |
2372 | } | 2631 | } |
2373 | 2632 | ||
2374 | auditout: | 2633 | return smk_ipv6_check(skp, object, address, act); |
2375 | |||
2376 | #ifdef CONFIG_AUDIT | ||
2377 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); | ||
2378 | ad.a.u.net->family = sk->sk_family; | ||
2379 | ad.a.u.net->dport = port; | ||
2380 | if (act == SMK_RECEIVING) | ||
2381 | ad.a.u.net->v6info.saddr = address->sin6_addr; | ||
2382 | else | ||
2383 | ad.a.u.net->v6info.daddr = address->sin6_addr; | ||
2384 | #endif | ||
2385 | rc = smk_access(skp, object, MAY_WRITE, &ad); | ||
2386 | rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc); | ||
2387 | return rc; | ||
2388 | } | 2634 | } |
2389 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 2635 | #endif /* SMACK_IPV6_PORT_LABELING */ |
2390 | 2636 | ||
2391 | /** | 2637 | /** |
2392 | * smack_inode_setsecurity - set smack xattrs | 2638 | * smack_inode_setsecurity - set smack xattrs |
@@ -2447,10 +2693,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
2447 | } else | 2693 | } else |
2448 | return -EOPNOTSUPP; | 2694 | return -EOPNOTSUPP; |
2449 | 2695 | ||
2450 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 2696 | #ifdef SMACK_IPV6_PORT_LABELING |
2451 | if (sock->sk->sk_family == PF_INET6) | 2697 | if (sock->sk->sk_family == PF_INET6) |
2452 | smk_ipv6_port_label(sock, NULL); | 2698 | smk_ipv6_port_label(sock, NULL); |
2453 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 2699 | #endif |
2454 | 2700 | ||
2455 | return 0; | 2701 | return 0; |
2456 | } | 2702 | } |
@@ -2492,7 +2738,7 @@ static int smack_socket_post_create(struct socket *sock, int family, | |||
2492 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); | 2738 | return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); |
2493 | } | 2739 | } |
2494 | 2740 | ||
2495 | #ifndef CONFIG_SECURITY_SMACK_NETFILTER | 2741 | #ifdef SMACK_IPV6_PORT_LABELING |
2496 | /** | 2742 | /** |
2497 | * smack_socket_bind - record port binding information. | 2743 | * smack_socket_bind - record port binding information. |
2498 | * @sock: the socket | 2744 | * @sock: the socket |
@@ -2506,14 +2752,11 @@ static int smack_socket_post_create(struct socket *sock, int family, | |||
2506 | static int smack_socket_bind(struct socket *sock, struct sockaddr *address, | 2752 | static int smack_socket_bind(struct socket *sock, struct sockaddr *address, |
2507 | int addrlen) | 2753 | int addrlen) |
2508 | { | 2754 | { |
2509 | #if IS_ENABLED(CONFIG_IPV6) | ||
2510 | if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) | 2755 | if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) |
2511 | smk_ipv6_port_label(sock, address); | 2756 | smk_ipv6_port_label(sock, address); |
2512 | #endif | ||
2513 | |||
2514 | return 0; | 2757 | return 0; |
2515 | } | 2758 | } |
2516 | #endif /* !CONFIG_SECURITY_SMACK_NETFILTER */ | 2759 | #endif /* SMACK_IPV6_PORT_LABELING */ |
2517 | 2760 | ||
2518 | /** | 2761 | /** |
2519 | * smack_socket_connect - connect access check | 2762 | * smack_socket_connect - connect access check |
@@ -2529,6 +2772,13 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, | |||
2529 | int addrlen) | 2772 | int addrlen) |
2530 | { | 2773 | { |
2531 | int rc = 0; | 2774 | int rc = 0; |
2775 | #if IS_ENABLED(CONFIG_IPV6) | ||
2776 | struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap; | ||
2777 | #endif | ||
2778 | #ifdef SMACK_IPV6_SECMARK_LABELING | ||
2779 | struct smack_known *rsp; | ||
2780 | struct socket_smack *ssp = sock->sk->sk_security; | ||
2781 | #endif | ||
2532 | 2782 | ||
2533 | if (sock->sk == NULL) | 2783 | if (sock->sk == NULL) |
2534 | return 0; | 2784 | return 0; |
@@ -2542,10 +2792,15 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, | |||
2542 | case PF_INET6: | 2792 | case PF_INET6: |
2543 | if (addrlen < sizeof(struct sockaddr_in6)) | 2793 | if (addrlen < sizeof(struct sockaddr_in6)) |
2544 | return -EINVAL; | 2794 | return -EINVAL; |
2545 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 2795 | #ifdef SMACK_IPV6_SECMARK_LABELING |
2546 | rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap, | 2796 | rsp = smack_ipv6host_label(sip); |
2797 | if (rsp != NULL) | ||
2798 | rc = smk_ipv6_check(ssp->smk_out, rsp, sip, | ||
2547 | SMK_CONNECTING); | 2799 | SMK_CONNECTING); |
2548 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 2800 | #endif |
2801 | #ifdef SMACK_IPV6_PORT_LABELING | ||
2802 | rc = smk_ipv6_port_check(sock->sk, sip, SMK_CONNECTING); | ||
2803 | #endif | ||
2549 | break; | 2804 | break; |
2550 | } | 2805 | } |
2551 | return rc; | 2806 | return rc; |
@@ -3431,9 +3686,13 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
3431 | int size) | 3686 | int size) |
3432 | { | 3687 | { |
3433 | struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; | 3688 | struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; |
3434 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 3689 | #if IS_ENABLED(CONFIG_IPV6) |
3435 | struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; | 3690 | struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; |
3436 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 3691 | #endif |
3692 | #ifdef SMACK_IPV6_SECMARK_LABELING | ||
3693 | struct socket_smack *ssp = sock->sk->sk_security; | ||
3694 | struct smack_known *rsp; | ||
3695 | #endif | ||
3437 | int rc = 0; | 3696 | int rc = 0; |
3438 | 3697 | ||
3439 | /* | 3698 | /* |
@@ -3447,9 +3706,15 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
3447 | rc = smack_netlabel_send(sock->sk, sip); | 3706 | rc = smack_netlabel_send(sock->sk, sip); |
3448 | break; | 3707 | break; |
3449 | case AF_INET6: | 3708 | case AF_INET6: |
3450 | #if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) | 3709 | #ifdef SMACK_IPV6_SECMARK_LABELING |
3710 | rsp = smack_ipv6host_label(sap); | ||
3711 | if (rsp != NULL) | ||
3712 | rc = smk_ipv6_check(ssp->smk_out, rsp, sap, | ||
3713 | SMK_CONNECTING); | ||
3714 | #endif | ||
3715 | #ifdef SMACK_IPV6_PORT_LABELING | ||
3451 | rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); | 3716 | rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); |
3452 | #endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ | 3717 | #endif |
3453 | break; | 3718 | break; |
3454 | } | 3719 | } |
3455 | return rc; | 3720 | return rc; |
@@ -3663,10 +3928,12 @@ access_check: | |||
3663 | proto = smk_skb_to_addr_ipv6(skb, &sadd); | 3928 | proto = smk_skb_to_addr_ipv6(skb, &sadd); |
3664 | if (proto != IPPROTO_UDP && proto != IPPROTO_TCP) | 3929 | if (proto != IPPROTO_UDP && proto != IPPROTO_TCP) |
3665 | break; | 3930 | break; |
3666 | #ifdef CONFIG_SECURITY_SMACK_NETFILTER | 3931 | #ifdef SMACK_IPV6_SECMARK_LABELING |
3667 | if (skb && skb->secmark != 0) | 3932 | if (skb && skb->secmark != 0) |
3668 | skp = smack_from_secid(skb->secmark); | 3933 | skp = smack_from_secid(skb->secmark); |
3669 | else | 3934 | else |
3935 | skp = smack_ipv6host_label(&sadd); | ||
3936 | if (skp == NULL) | ||
3670 | skp = smack_net_ambient; | 3937 | skp = smack_net_ambient; |
3671 | #ifdef CONFIG_AUDIT | 3938 | #ifdef CONFIG_AUDIT |
3672 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); | 3939 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); |
@@ -3677,9 +3944,10 @@ access_check: | |||
3677 | rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); | 3944 | rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); |
3678 | rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in, | 3945 | rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in, |
3679 | MAY_WRITE, rc); | 3946 | MAY_WRITE, rc); |
3680 | #else /* CONFIG_SECURITY_SMACK_NETFILTER */ | 3947 | #endif /* SMACK_IPV6_SECMARK_LABELING */ |
3948 | #ifdef SMACK_IPV6_PORT_LABELING | ||
3681 | rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); | 3949 | rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); |
3682 | #endif /* CONFIG_SECURITY_SMACK_NETFILTER */ | 3950 | #endif /* SMACK_IPV6_PORT_LABELING */ |
3683 | break; | 3951 | break; |
3684 | #endif /* CONFIG_IPV6 */ | 3952 | #endif /* CONFIG_IPV6 */ |
3685 | } | 3953 | } |
@@ -3777,13 +4045,11 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, | |||
3777 | } | 4045 | } |
3778 | netlbl_secattr_destroy(&secattr); | 4046 | netlbl_secattr_destroy(&secattr); |
3779 | break; | 4047 | break; |
3780 | #if IS_ENABLED(CONFIG_IPV6) | ||
3781 | case PF_INET6: | 4048 | case PF_INET6: |
3782 | #ifdef CONFIG_SECURITY_SMACK_NETFILTER | 4049 | #ifdef SMACK_IPV6_SECMARK_LABELING |
3783 | s = skb->secmark; | 4050 | s = skb->secmark; |
3784 | #endif /* CONFIG_SECURITY_SMACK_NETFILTER */ | 4051 | #endif |
3785 | break; | 4052 | break; |
3786 | #endif /* CONFIG_IPV6 */ | ||
3787 | } | 4053 | } |
3788 | *secid = s; | 4054 | *secid = s; |
3789 | if (s == 0) | 4055 | if (s == 0) |
@@ -3906,7 +4172,7 @@ access_check: | |||
3906 | hdr = ip_hdr(skb); | 4172 | hdr = ip_hdr(skb); |
3907 | addr.sin_addr.s_addr = hdr->saddr; | 4173 | addr.sin_addr.s_addr = hdr->saddr; |
3908 | rcu_read_lock(); | 4174 | rcu_read_lock(); |
3909 | hskp = smack_host_label(&addr); | 4175 | hskp = smack_ipv4host_label(&addr); |
3910 | rcu_read_unlock(); | 4176 | rcu_read_unlock(); |
3911 | 4177 | ||
3912 | if (hskp == NULL) | 4178 | if (hskp == NULL) |
@@ -4254,7 +4520,7 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | |||
4254 | return 0; | 4520 | return 0; |
4255 | } | 4521 | } |
4256 | 4522 | ||
4257 | struct security_hook_list smack_hooks[] = { | 4523 | static struct security_hook_list smack_hooks[] = { |
4258 | LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), | 4524 | LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), |
4259 | LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), | 4525 | LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), |
4260 | LSM_HOOK_INIT(syslog, smack_syslog), | 4526 | LSM_HOOK_INIT(syslog, smack_syslog), |
@@ -4264,6 +4530,8 @@ struct security_hook_list smack_hooks[] = { | |||
4264 | LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data), | 4530 | LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data), |
4265 | LSM_HOOK_INIT(sb_kern_mount, smack_sb_kern_mount), | 4531 | LSM_HOOK_INIT(sb_kern_mount, smack_sb_kern_mount), |
4266 | LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), | 4532 | LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), |
4533 | LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts), | ||
4534 | LSM_HOOK_INIT(sb_parse_opts_str, smack_parse_opts_str), | ||
4267 | 4535 | ||
4268 | LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), | 4536 | LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), |
4269 | LSM_HOOK_INIT(bprm_committing_creds, smack_bprm_committing_creds), | 4537 | LSM_HOOK_INIT(bprm_committing_creds, smack_bprm_committing_creds), |
@@ -4356,9 +4624,9 @@ struct security_hook_list smack_hooks[] = { | |||
4356 | LSM_HOOK_INIT(unix_may_send, smack_unix_may_send), | 4624 | LSM_HOOK_INIT(unix_may_send, smack_unix_may_send), |
4357 | 4625 | ||
4358 | LSM_HOOK_INIT(socket_post_create, smack_socket_post_create), | 4626 | LSM_HOOK_INIT(socket_post_create, smack_socket_post_create), |
4359 | #ifndef CONFIG_SECURITY_SMACK_NETFILTER | 4627 | #ifdef SMACK_IPV6_PORT_LABELING |
4360 | LSM_HOOK_INIT(socket_bind, smack_socket_bind), | 4628 | LSM_HOOK_INIT(socket_bind, smack_socket_bind), |
4361 | #endif /* CONFIG_SECURITY_SMACK_NETFILTER */ | 4629 | #endif |
4362 | LSM_HOOK_INIT(socket_connect, smack_socket_connect), | 4630 | LSM_HOOK_INIT(socket_connect, smack_socket_connect), |
4363 | LSM_HOOK_INIT(socket_sendmsg, smack_socket_sendmsg), | 4631 | LSM_HOOK_INIT(socket_sendmsg, smack_socket_sendmsg), |
4364 | LSM_HOOK_INIT(socket_sock_rcv_skb, smack_socket_sock_rcv_skb), | 4632 | LSM_HOOK_INIT(socket_sock_rcv_skb, smack_socket_sock_rcv_skb), |
@@ -4453,7 +4721,16 @@ static __init int smack_init(void) | |||
4453 | return -ENOMEM; | 4721 | return -ENOMEM; |
4454 | } | 4722 | } |
4455 | 4723 | ||
4456 | printk(KERN_INFO "Smack: Initializing.\n"); | 4724 | pr_info("Smack: Initializing.\n"); |
4725 | #ifdef CONFIG_SECURITY_SMACK_NETFILTER | ||
4726 | pr_info("Smack: Netfilter enabled.\n"); | ||
4727 | #endif | ||
4728 | #ifdef SMACK_IPV6_PORT_LABELING | ||
4729 | pr_info("Smack: IPv6 port labeling enabled.\n"); | ||
4730 | #endif | ||
4731 | #ifdef SMACK_IPV6_SECMARK_LABELING | ||
4732 | pr_info("Smack: IPv6 Netfilter enabled.\n"); | ||
4733 | #endif | ||
4457 | 4734 | ||
4458 | /* | 4735 | /* |
4459 | * Set the security state for the initial task. | 4736 | * Set the security state for the initial task. |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 2716d02119f3..c20b154a33f2 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/magic.h> | 29 | #include <linux/magic.h> |
30 | #include "smack.h" | 30 | #include "smack.h" |
31 | 31 | ||
32 | #define BEBITS (sizeof(__be32) * 8) | ||
32 | /* | 33 | /* |
33 | * smackfs pseudo filesystem. | 34 | * smackfs pseudo filesystem. |
34 | */ | 35 | */ |
@@ -40,7 +41,7 @@ enum smk_inos { | |||
40 | SMK_DOI = 5, /* CIPSO DOI */ | 41 | SMK_DOI = 5, /* CIPSO DOI */ |
41 | SMK_DIRECT = 6, /* CIPSO level indicating direct label */ | 42 | SMK_DIRECT = 6, /* CIPSO level indicating direct label */ |
42 | SMK_AMBIENT = 7, /* internet ambient label */ | 43 | SMK_AMBIENT = 7, /* internet ambient label */ |
43 | SMK_NETLBLADDR = 8, /* single label hosts */ | 44 | SMK_NET4ADDR = 8, /* single label hosts */ |
44 | SMK_ONLYCAP = 9, /* the only "capable" label */ | 45 | SMK_ONLYCAP = 9, /* the only "capable" label */ |
45 | SMK_LOGGING = 10, /* logging */ | 46 | SMK_LOGGING = 10, /* logging */ |
46 | SMK_LOAD_SELF = 11, /* task specific rules */ | 47 | SMK_LOAD_SELF = 11, /* task specific rules */ |
@@ -57,6 +58,9 @@ enum smk_inos { | |||
57 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP | 58 | #ifdef CONFIG_SECURITY_SMACK_BRINGUP |
58 | SMK_UNCONFINED = 22, /* define an unconfined label */ | 59 | SMK_UNCONFINED = 22, /* define an unconfined label */ |
59 | #endif | 60 | #endif |
61 | #if IS_ENABLED(CONFIG_IPV6) | ||
62 | SMK_NET6ADDR = 23, /* single label IPv6 hosts */ | ||
63 | #endif /* CONFIG_IPV6 */ | ||
60 | }; | 64 | }; |
61 | 65 | ||
62 | /* | 66 | /* |
@@ -64,7 +68,10 @@ enum smk_inos { | |||
64 | */ | 68 | */ |
65 | static DEFINE_MUTEX(smack_cipso_lock); | 69 | static DEFINE_MUTEX(smack_cipso_lock); |
66 | static DEFINE_MUTEX(smack_ambient_lock); | 70 | static DEFINE_MUTEX(smack_ambient_lock); |
67 | static DEFINE_MUTEX(smk_netlbladdr_lock); | 71 | static DEFINE_MUTEX(smk_net4addr_lock); |
72 | #if IS_ENABLED(CONFIG_IPV6) | ||
73 | static DEFINE_MUTEX(smk_net6addr_lock); | ||
74 | #endif /* CONFIG_IPV6 */ | ||
68 | 75 | ||
69 | /* | 76 | /* |
70 | * This is the "ambient" label for network traffic. | 77 | * This is the "ambient" label for network traffic. |
@@ -118,7 +125,10 @@ int smack_ptrace_rule = SMACK_PTRACE_DEFAULT; | |||
118 | * can write to the specified label. | 125 | * can write to the specified label. |
119 | */ | 126 | */ |
120 | 127 | ||
121 | LIST_HEAD(smk_netlbladdr_list); | 128 | LIST_HEAD(smk_net4addr_list); |
129 | #if IS_ENABLED(CONFIG_IPV6) | ||
130 | LIST_HEAD(smk_net6addr_list); | ||
131 | #endif /* CONFIG_IPV6 */ | ||
122 | 132 | ||
123 | /* | 133 | /* |
124 | * Rule lists are maintained for each label. | 134 | * Rule lists are maintained for each label. |
@@ -129,7 +139,7 @@ struct smack_master_list { | |||
129 | struct smack_rule *smk_rule; | 139 | struct smack_rule *smk_rule; |
130 | }; | 140 | }; |
131 | 141 | ||
132 | LIST_HEAD(smack_rule_list); | 142 | static LIST_HEAD(smack_rule_list); |
133 | 143 | ||
134 | struct smack_parsed_rule { | 144 | struct smack_parsed_rule { |
135 | struct smack_known *smk_subject; | 145 | struct smack_known *smk_subject; |
@@ -140,11 +150,6 @@ struct smack_parsed_rule { | |||
140 | 150 | ||
141 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; | 151 | static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; |
142 | 152 | ||
143 | struct smack_known smack_cipso_option = { | ||
144 | .smk_known = SMACK_CIPSO_OPTION, | ||
145 | .smk_secid = 0, | ||
146 | }; | ||
147 | |||
148 | /* | 153 | /* |
149 | * Values for parsing cipso rules | 154 | * Values for parsing cipso rules |
150 | * SMK_DIGITLEN: Length of a digit field in a rule. | 155 | * SMK_DIGITLEN: Length of a digit field in a rule. |
@@ -1047,92 +1052,90 @@ static const struct file_operations smk_cipso2_ops = { | |||
1047 | * Seq_file read operations for /smack/netlabel | 1052 | * Seq_file read operations for /smack/netlabel |
1048 | */ | 1053 | */ |
1049 | 1054 | ||
1050 | static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos) | 1055 | static void *net4addr_seq_start(struct seq_file *s, loff_t *pos) |
1051 | { | 1056 | { |
1052 | return smk_seq_start(s, pos, &smk_netlbladdr_list); | 1057 | return smk_seq_start(s, pos, &smk_net4addr_list); |
1053 | } | 1058 | } |
1054 | 1059 | ||
1055 | static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) | 1060 | static void *net4addr_seq_next(struct seq_file *s, void *v, loff_t *pos) |
1056 | { | 1061 | { |
1057 | return smk_seq_next(s, v, pos, &smk_netlbladdr_list); | 1062 | return smk_seq_next(s, v, pos, &smk_net4addr_list); |
1058 | } | 1063 | } |
1059 | #define BEBITS (sizeof(__be32) * 8) | ||
1060 | 1064 | ||
1061 | /* | 1065 | /* |
1062 | * Print host/label pairs | 1066 | * Print host/label pairs |
1063 | */ | 1067 | */ |
1064 | static int netlbladdr_seq_show(struct seq_file *s, void *v) | 1068 | static int net4addr_seq_show(struct seq_file *s, void *v) |
1065 | { | 1069 | { |
1066 | struct list_head *list = v; | 1070 | struct list_head *list = v; |
1067 | struct smk_netlbladdr *skp = | 1071 | struct smk_net4addr *skp = |
1068 | list_entry_rcu(list, struct smk_netlbladdr, list); | 1072 | list_entry_rcu(list, struct smk_net4addr, list); |
1069 | unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; | 1073 | char *kp = SMACK_CIPSO_OPTION; |
1070 | int maskn; | ||
1071 | u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); | ||
1072 | |||
1073 | for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++); | ||
1074 | 1074 | ||
1075 | seq_printf(s, "%u.%u.%u.%u/%d %s\n", | 1075 | if (skp->smk_label != NULL) |
1076 | hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label->smk_known); | 1076 | kp = skp->smk_label->smk_known; |
1077 | seq_printf(s, "%pI4/%d %s\n", &skp->smk_host.s_addr, | ||
1078 | skp->smk_masks, kp); | ||
1077 | 1079 | ||
1078 | return 0; | 1080 | return 0; |
1079 | } | 1081 | } |
1080 | 1082 | ||
1081 | static const struct seq_operations netlbladdr_seq_ops = { | 1083 | static const struct seq_operations net4addr_seq_ops = { |
1082 | .start = netlbladdr_seq_start, | 1084 | .start = net4addr_seq_start, |
1083 | .next = netlbladdr_seq_next, | 1085 | .next = net4addr_seq_next, |
1084 | .show = netlbladdr_seq_show, | 1086 | .show = net4addr_seq_show, |
1085 | .stop = smk_seq_stop, | 1087 | .stop = smk_seq_stop, |
1086 | }; | 1088 | }; |
1087 | 1089 | ||
1088 | /** | 1090 | /** |
1089 | * smk_open_netlbladdr - open() for /smack/netlabel | 1091 | * smk_open_net4addr - open() for /smack/netlabel |
1090 | * @inode: inode structure representing file | 1092 | * @inode: inode structure representing file |
1091 | * @file: "netlabel" file pointer | 1093 | * @file: "netlabel" file pointer |
1092 | * | 1094 | * |
1093 | * Connect our netlbladdr_seq_* operations with /smack/netlabel | 1095 | * Connect our net4addr_seq_* operations with /smack/netlabel |
1094 | * file_operations | 1096 | * file_operations |
1095 | */ | 1097 | */ |
1096 | static int smk_open_netlbladdr(struct inode *inode, struct file *file) | 1098 | static int smk_open_net4addr(struct inode *inode, struct file *file) |
1097 | { | 1099 | { |
1098 | return seq_open(file, &netlbladdr_seq_ops); | 1100 | return seq_open(file, &net4addr_seq_ops); |
1099 | } | 1101 | } |
1100 | 1102 | ||
1101 | /** | 1103 | /** |
1102 | * smk_netlbladdr_insert | 1104 | * smk_net4addr_insert |
1103 | * @new : netlabel to insert | 1105 | * @new : netlabel to insert |
1104 | * | 1106 | * |
1105 | * This helper insert netlabel in the smack_netlbladdrs list | 1107 | * This helper insert netlabel in the smack_net4addrs list |
1106 | * sorted by netmask length (longest to smallest) | 1108 | * sorted by netmask length (longest to smallest) |
1107 | * locked by &smk_netlbladdr_lock in smk_write_netlbladdr | 1109 | * locked by &smk_net4addr_lock in smk_write_net4addr |
1108 | * | 1110 | * |
1109 | */ | 1111 | */ |
1110 | static void smk_netlbladdr_insert(struct smk_netlbladdr *new) | 1112 | static void smk_net4addr_insert(struct smk_net4addr *new) |
1111 | { | 1113 | { |
1112 | struct smk_netlbladdr *m, *m_next; | 1114 | struct smk_net4addr *m; |
1115 | struct smk_net4addr *m_next; | ||
1113 | 1116 | ||
1114 | if (list_empty(&smk_netlbladdr_list)) { | 1117 | if (list_empty(&smk_net4addr_list)) { |
1115 | list_add_rcu(&new->list, &smk_netlbladdr_list); | 1118 | list_add_rcu(&new->list, &smk_net4addr_list); |
1116 | return; | 1119 | return; |
1117 | } | 1120 | } |
1118 | 1121 | ||
1119 | m = list_entry_rcu(smk_netlbladdr_list.next, | 1122 | m = list_entry_rcu(smk_net4addr_list.next, |
1120 | struct smk_netlbladdr, list); | 1123 | struct smk_net4addr, list); |
1121 | 1124 | ||
1122 | /* the comparison '>' is a bit hacky, but works */ | 1125 | /* the comparison '>' is a bit hacky, but works */ |
1123 | if (new->smk_mask.s_addr > m->smk_mask.s_addr) { | 1126 | if (new->smk_masks > m->smk_masks) { |
1124 | list_add_rcu(&new->list, &smk_netlbladdr_list); | 1127 | list_add_rcu(&new->list, &smk_net4addr_list); |
1125 | return; | 1128 | return; |
1126 | } | 1129 | } |
1127 | 1130 | ||
1128 | list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) { | 1131 | list_for_each_entry_rcu(m, &smk_net4addr_list, list) { |
1129 | if (list_is_last(&m->list, &smk_netlbladdr_list)) { | 1132 | if (list_is_last(&m->list, &smk_net4addr_list)) { |
1130 | list_add_rcu(&new->list, &m->list); | 1133 | list_add_rcu(&new->list, &m->list); |
1131 | return; | 1134 | return; |
1132 | } | 1135 | } |
1133 | m_next = list_entry_rcu(m->list.next, | 1136 | m_next = list_entry_rcu(m->list.next, |
1134 | struct smk_netlbladdr, list); | 1137 | struct smk_net4addr, list); |
1135 | if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) { | 1138 | if (new->smk_masks > m_next->smk_masks) { |
1136 | list_add_rcu(&new->list, &m->list); | 1139 | list_add_rcu(&new->list, &m->list); |
1137 | return; | 1140 | return; |
1138 | } | 1141 | } |
@@ -1141,28 +1144,29 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new) | |||
1141 | 1144 | ||
1142 | 1145 | ||
1143 | /** | 1146 | /** |
1144 | * smk_write_netlbladdr - write() for /smack/netlabel | 1147 | * smk_write_net4addr - write() for /smack/netlabel |
1145 | * @file: file pointer, not actually used | 1148 | * @file: file pointer, not actually used |
1146 | * @buf: where to get the data from | 1149 | * @buf: where to get the data from |
1147 | * @count: bytes sent | 1150 | * @count: bytes sent |
1148 | * @ppos: where to start | 1151 | * @ppos: where to start |
1149 | * | 1152 | * |
1150 | * Accepts only one netlbladdr per write call. | 1153 | * Accepts only one net4addr per write call. |
1151 | * Returns number of bytes written or error code, as appropriate | 1154 | * Returns number of bytes written or error code, as appropriate |
1152 | */ | 1155 | */ |
1153 | static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | 1156 | static ssize_t smk_write_net4addr(struct file *file, const char __user *buf, |
1154 | size_t count, loff_t *ppos) | 1157 | size_t count, loff_t *ppos) |
1155 | { | 1158 | { |
1156 | struct smk_netlbladdr *snp; | 1159 | struct smk_net4addr *snp; |
1157 | struct sockaddr_in newname; | 1160 | struct sockaddr_in newname; |
1158 | char *smack; | 1161 | char *smack; |
1159 | struct smack_known *skp; | 1162 | struct smack_known *skp = NULL; |
1160 | char *data; | 1163 | char *data; |
1161 | char *host = (char *)&newname.sin_addr.s_addr; | 1164 | char *host = (char *)&newname.sin_addr.s_addr; |
1162 | int rc; | 1165 | int rc; |
1163 | struct netlbl_audit audit_info; | 1166 | struct netlbl_audit audit_info; |
1164 | struct in_addr mask; | 1167 | struct in_addr mask; |
1165 | unsigned int m; | 1168 | unsigned int m; |
1169 | unsigned int masks; | ||
1166 | int found; | 1170 | int found; |
1167 | u32 mask_bits = (1<<31); | 1171 | u32 mask_bits = (1<<31); |
1168 | __be32 nsa; | 1172 | __be32 nsa; |
@@ -1200,7 +1204,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1200 | data[count] = '\0'; | 1204 | data[count] = '\0'; |
1201 | 1205 | ||
1202 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%u %s", | 1206 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%u %s", |
1203 | &host[0], &host[1], &host[2], &host[3], &m, smack); | 1207 | &host[0], &host[1], &host[2], &host[3], &masks, smack); |
1204 | if (rc != 6) { | 1208 | if (rc != 6) { |
1205 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", | 1209 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", |
1206 | &host[0], &host[1], &host[2], &host[3], smack); | 1210 | &host[0], &host[1], &host[2], &host[3], smack); |
@@ -1209,8 +1213,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1209 | goto free_out; | 1213 | goto free_out; |
1210 | } | 1214 | } |
1211 | m = BEBITS; | 1215 | m = BEBITS; |
1216 | masks = 32; | ||
1212 | } | 1217 | } |
1213 | if (m > BEBITS) { | 1218 | if (masks > BEBITS) { |
1214 | rc = -EINVAL; | 1219 | rc = -EINVAL; |
1215 | goto free_out; | 1220 | goto free_out; |
1216 | } | 1221 | } |
@@ -1225,16 +1230,16 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1225 | goto free_out; | 1230 | goto free_out; |
1226 | } | 1231 | } |
1227 | } else { | 1232 | } else { |
1228 | /* check known options */ | 1233 | /* |
1229 | if (strcmp(smack, smack_cipso_option.smk_known) == 0) | 1234 | * Only the -CIPSO option is supported for IPv4 |
1230 | skp = &smack_cipso_option; | 1235 | */ |
1231 | else { | 1236 | if (strcmp(smack, SMACK_CIPSO_OPTION) != 0) { |
1232 | rc = -EINVAL; | 1237 | rc = -EINVAL; |
1233 | goto free_out; | 1238 | goto free_out; |
1234 | } | 1239 | } |
1235 | } | 1240 | } |
1236 | 1241 | ||
1237 | for (temp_mask = 0; m > 0; m--) { | 1242 | for (m = masks, temp_mask = 0; m > 0; m--) { |
1238 | temp_mask |= mask_bits; | 1243 | temp_mask |= mask_bits; |
1239 | mask_bits >>= 1; | 1244 | mask_bits >>= 1; |
1240 | } | 1245 | } |
@@ -1245,14 +1250,13 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1245 | * Only allow one writer at a time. Writes should be | 1250 | * Only allow one writer at a time. Writes should be |
1246 | * quite rare and small in any case. | 1251 | * quite rare and small in any case. |
1247 | */ | 1252 | */ |
1248 | mutex_lock(&smk_netlbladdr_lock); | 1253 | mutex_lock(&smk_net4addr_lock); |
1249 | 1254 | ||
1250 | nsa = newname.sin_addr.s_addr; | 1255 | nsa = newname.sin_addr.s_addr; |
1251 | /* try to find if the prefix is already in the list */ | 1256 | /* try to find if the prefix is already in the list */ |
1252 | found = 0; | 1257 | found = 0; |
1253 | list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) { | 1258 | list_for_each_entry_rcu(snp, &smk_net4addr_list, list) { |
1254 | if (snp->smk_host.sin_addr.s_addr == nsa && | 1259 | if (snp->smk_host.s_addr == nsa && snp->smk_masks == masks) { |
1255 | snp->smk_mask.s_addr == mask.s_addr) { | ||
1256 | found = 1; | 1260 | found = 1; |
1257 | break; | 1261 | break; |
1258 | } | 1262 | } |
@@ -1265,17 +1269,20 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1265 | rc = -ENOMEM; | 1269 | rc = -ENOMEM; |
1266 | else { | 1270 | else { |
1267 | rc = 0; | 1271 | rc = 0; |
1268 | snp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; | 1272 | snp->smk_host.s_addr = newname.sin_addr.s_addr; |
1269 | snp->smk_mask.s_addr = mask.s_addr; | 1273 | snp->smk_mask.s_addr = mask.s_addr; |
1270 | snp->smk_label = skp; | 1274 | snp->smk_label = skp; |
1271 | smk_netlbladdr_insert(snp); | 1275 | snp->smk_masks = masks; |
1276 | smk_net4addr_insert(snp); | ||
1272 | } | 1277 | } |
1273 | } else { | 1278 | } else { |
1274 | /* we delete the unlabeled entry, only if the previous label | 1279 | /* |
1275 | * wasn't the special CIPSO option */ | 1280 | * Delete the unlabeled entry, only if the previous label |
1276 | if (snp->smk_label != &smack_cipso_option) | 1281 | * wasn't the special CIPSO option |
1282 | */ | ||
1283 | if (snp->smk_label != NULL) | ||
1277 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, | 1284 | rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, |
1278 | &snp->smk_host.sin_addr, &snp->smk_mask, | 1285 | &snp->smk_host, &snp->smk_mask, |
1279 | PF_INET, &audit_info); | 1286 | PF_INET, &audit_info); |
1280 | else | 1287 | else |
1281 | rc = 0; | 1288 | rc = 0; |
@@ -1287,15 +1294,15 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1287 | * this host so that incoming packets get labeled. | 1294 | * this host so that incoming packets get labeled. |
1288 | * but only if we didn't get the special CIPSO option | 1295 | * but only if we didn't get the special CIPSO option |
1289 | */ | 1296 | */ |
1290 | if (rc == 0 && skp != &smack_cipso_option) | 1297 | if (rc == 0 && skp != NULL) |
1291 | rc = netlbl_cfg_unlbl_static_add(&init_net, NULL, | 1298 | rc = netlbl_cfg_unlbl_static_add(&init_net, NULL, |
1292 | &snp->smk_host.sin_addr, &snp->smk_mask, PF_INET, | 1299 | &snp->smk_host, &snp->smk_mask, PF_INET, |
1293 | snp->smk_label->smk_secid, &audit_info); | 1300 | snp->smk_label->smk_secid, &audit_info); |
1294 | 1301 | ||
1295 | if (rc == 0) | 1302 | if (rc == 0) |
1296 | rc = count; | 1303 | rc = count; |
1297 | 1304 | ||
1298 | mutex_unlock(&smk_netlbladdr_lock); | 1305 | mutex_unlock(&smk_net4addr_lock); |
1299 | 1306 | ||
1300 | free_out: | 1307 | free_out: |
1301 | kfree(smack); | 1308 | kfree(smack); |
@@ -1305,14 +1312,279 @@ free_data_out: | |||
1305 | return rc; | 1312 | return rc; |
1306 | } | 1313 | } |
1307 | 1314 | ||
1308 | static const struct file_operations smk_netlbladdr_ops = { | 1315 | static const struct file_operations smk_net4addr_ops = { |
1309 | .open = smk_open_netlbladdr, | 1316 | .open = smk_open_net4addr, |
1310 | .read = seq_read, | 1317 | .read = seq_read, |
1311 | .llseek = seq_lseek, | 1318 | .llseek = seq_lseek, |
1312 | .write = smk_write_netlbladdr, | 1319 | .write = smk_write_net4addr, |
1313 | .release = seq_release, | 1320 | .release = seq_release, |
1314 | }; | 1321 | }; |
1315 | 1322 | ||
1323 | #if IS_ENABLED(CONFIG_IPV6) | ||
1324 | /* | ||
1325 | * Seq_file read operations for /smack/netlabel6 | ||
1326 | */ | ||
1327 | |||
1328 | static void *net6addr_seq_start(struct seq_file *s, loff_t *pos) | ||
1329 | { | ||
1330 | return smk_seq_start(s, pos, &smk_net6addr_list); | ||
1331 | } | ||
1332 | |||
1333 | static void *net6addr_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
1334 | { | ||
1335 | return smk_seq_next(s, v, pos, &smk_net6addr_list); | ||
1336 | } | ||
1337 | |||
1338 | /* | ||
1339 | * Print host/label pairs | ||
1340 | */ | ||
1341 | static int net6addr_seq_show(struct seq_file *s, void *v) | ||
1342 | { | ||
1343 | struct list_head *list = v; | ||
1344 | struct smk_net6addr *skp = | ||
1345 | list_entry(list, struct smk_net6addr, list); | ||
1346 | |||
1347 | if (skp->smk_label != NULL) | ||
1348 | seq_printf(s, "%pI6/%d %s\n", &skp->smk_host, skp->smk_masks, | ||
1349 | skp->smk_label->smk_known); | ||
1350 | |||
1351 | return 0; | ||
1352 | } | ||
1353 | |||
1354 | static const struct seq_operations net6addr_seq_ops = { | ||
1355 | .start = net6addr_seq_start, | ||
1356 | .next = net6addr_seq_next, | ||
1357 | .show = net6addr_seq_show, | ||
1358 | .stop = smk_seq_stop, | ||
1359 | }; | ||
1360 | |||
1361 | /** | ||
1362 | * smk_open_net6addr - open() for /smack/netlabel | ||
1363 | * @inode: inode structure representing file | ||
1364 | * @file: "netlabel" file pointer | ||
1365 | * | ||
1366 | * Connect our net6addr_seq_* operations with /smack/netlabel | ||
1367 | * file_operations | ||
1368 | */ | ||
1369 | static int smk_open_net6addr(struct inode *inode, struct file *file) | ||
1370 | { | ||
1371 | return seq_open(file, &net6addr_seq_ops); | ||
1372 | } | ||
1373 | |||
1374 | /** | ||
1375 | * smk_net6addr_insert | ||
1376 | * @new : entry to insert | ||
1377 | * | ||
1378 | * This inserts an entry in the smack_net6addrs list | ||
1379 | * sorted by netmask length (longest to smallest) | ||
1380 | * locked by &smk_net6addr_lock in smk_write_net6addr | ||
1381 | * | ||
1382 | */ | ||
1383 | static void smk_net6addr_insert(struct smk_net6addr *new) | ||
1384 | { | ||
1385 | struct smk_net6addr *m_next; | ||
1386 | struct smk_net6addr *m; | ||
1387 | |||
1388 | if (list_empty(&smk_net6addr_list)) { | ||
1389 | list_add_rcu(&new->list, &smk_net6addr_list); | ||
1390 | return; | ||
1391 | } | ||
1392 | |||
1393 | m = list_entry_rcu(smk_net6addr_list.next, | ||
1394 | struct smk_net6addr, list); | ||
1395 | |||
1396 | if (new->smk_masks > m->smk_masks) { | ||
1397 | list_add_rcu(&new->list, &smk_net6addr_list); | ||
1398 | return; | ||
1399 | } | ||
1400 | |||
1401 | list_for_each_entry_rcu(m, &smk_net6addr_list, list) { | ||
1402 | if (list_is_last(&m->list, &smk_net6addr_list)) { | ||
1403 | list_add_rcu(&new->list, &m->list); | ||
1404 | return; | ||
1405 | } | ||
1406 | m_next = list_entry_rcu(m->list.next, | ||
1407 | struct smk_net6addr, list); | ||
1408 | if (new->smk_masks > m_next->smk_masks) { | ||
1409 | list_add_rcu(&new->list, &m->list); | ||
1410 | return; | ||
1411 | } | ||
1412 | } | ||
1413 | } | ||
1414 | |||
1415 | |||
1416 | /** | ||
1417 | * smk_write_net6addr - write() for /smack/netlabel | ||
1418 | * @file: file pointer, not actually used | ||
1419 | * @buf: where to get the data from | ||
1420 | * @count: bytes sent | ||
1421 | * @ppos: where to start | ||
1422 | * | ||
1423 | * Accepts only one net6addr per write call. | ||
1424 | * Returns number of bytes written or error code, as appropriate | ||
1425 | */ | ||
1426 | static ssize_t smk_write_net6addr(struct file *file, const char __user *buf, | ||
1427 | size_t count, loff_t *ppos) | ||
1428 | { | ||
1429 | struct smk_net6addr *snp; | ||
1430 | struct in6_addr newname; | ||
1431 | struct in6_addr fullmask; | ||
1432 | struct smack_known *skp = NULL; | ||
1433 | char *smack; | ||
1434 | char *data; | ||
1435 | int rc = 0; | ||
1436 | int found = 0; | ||
1437 | int i; | ||
1438 | unsigned int scanned[8]; | ||
1439 | unsigned int m; | ||
1440 | unsigned int mask = 128; | ||
1441 | |||
1442 | /* | ||
1443 | * Must have privilege. | ||
1444 | * No partial writes. | ||
1445 | * Enough data must be present. | ||
1446 | * "<addr/mask, as a:b:c:d:e:f:g:h/e><space><label>" | ||
1447 | * "<addr, as a:b:c:d:e:f:g:h><space><label>" | ||
1448 | */ | ||
1449 | if (!smack_privileged(CAP_MAC_ADMIN)) | ||
1450 | return -EPERM; | ||
1451 | if (*ppos != 0) | ||
1452 | return -EINVAL; | ||
1453 | if (count < SMK_NETLBLADDRMIN) | ||
1454 | return -EINVAL; | ||
1455 | |||
1456 | data = kzalloc(count + 1, GFP_KERNEL); | ||
1457 | if (data == NULL) | ||
1458 | return -ENOMEM; | ||
1459 | |||
1460 | if (copy_from_user(data, buf, count) != 0) { | ||
1461 | rc = -EFAULT; | ||
1462 | goto free_data_out; | ||
1463 | } | ||
1464 | |||
1465 | smack = kzalloc(count + 1, GFP_KERNEL); | ||
1466 | if (smack == NULL) { | ||
1467 | rc = -ENOMEM; | ||
1468 | goto free_data_out; | ||
1469 | } | ||
1470 | |||
1471 | data[count] = '\0'; | ||
1472 | |||
1473 | i = sscanf(data, "%x:%x:%x:%x:%x:%x:%x:%x/%u %s", | ||
1474 | &scanned[0], &scanned[1], &scanned[2], &scanned[3], | ||
1475 | &scanned[4], &scanned[5], &scanned[6], &scanned[7], | ||
1476 | &mask, smack); | ||
1477 | if (i != 10) { | ||
1478 | i = sscanf(data, "%x:%x:%x:%x:%x:%x:%x:%x %s", | ||
1479 | &scanned[0], &scanned[1], &scanned[2], | ||
1480 | &scanned[3], &scanned[4], &scanned[5], | ||
1481 | &scanned[6], &scanned[7], smack); | ||
1482 | if (i != 9) { | ||
1483 | rc = -EINVAL; | ||
1484 | goto free_out; | ||
1485 | } | ||
1486 | } | ||
1487 | if (mask > 128) { | ||
1488 | rc = -EINVAL; | ||
1489 | goto free_out; | ||
1490 | } | ||
1491 | for (i = 0; i < 8; i++) { | ||
1492 | if (scanned[i] > 0xffff) { | ||
1493 | rc = -EINVAL; | ||
1494 | goto free_out; | ||
1495 | } | ||
1496 | newname.s6_addr16[i] = htons(scanned[i]); | ||
1497 | } | ||
1498 | |||
1499 | /* | ||
1500 | * If smack begins with '-', it is an option, don't import it | ||
1501 | */ | ||
1502 | if (smack[0] != '-') { | ||
1503 | skp = smk_import_entry(smack, 0); | ||
1504 | if (skp == NULL) { | ||
1505 | rc = -EINVAL; | ||
1506 | goto free_out; | ||
1507 | } | ||
1508 | } else { | ||
1509 | /* | ||
1510 | * Only -DELETE is supported for IPv6 | ||
1511 | */ | ||
1512 | if (strcmp(smack, SMACK_DELETE_OPTION) != 0) { | ||
1513 | rc = -EINVAL; | ||
1514 | goto free_out; | ||
1515 | } | ||
1516 | } | ||
1517 | |||
1518 | for (i = 0, m = mask; i < 8; i++) { | ||
1519 | if (m >= 16) { | ||
1520 | fullmask.s6_addr16[i] = 0xffff; | ||
1521 | m -= 16; | ||
1522 | } else if (m > 0) { | ||
1523 | fullmask.s6_addr16[i] = (1 << m) - 1; | ||
1524 | m = 0; | ||
1525 | } else | ||
1526 | fullmask.s6_addr16[i] = 0; | ||
1527 | newname.s6_addr16[i] &= fullmask.s6_addr16[i]; | ||
1528 | } | ||
1529 | |||
1530 | /* | ||
1531 | * Only allow one writer at a time. Writes should be | ||
1532 | * quite rare and small in any case. | ||
1533 | */ | ||
1534 | mutex_lock(&smk_net6addr_lock); | ||
1535 | /* | ||
1536 | * Try to find the prefix in the list | ||
1537 | */ | ||
1538 | list_for_each_entry_rcu(snp, &smk_net6addr_list, list) { | ||
1539 | if (mask != snp->smk_masks) | ||
1540 | continue; | ||
1541 | for (found = 1, i = 0; i < 8; i++) { | ||
1542 | if (newname.s6_addr16[i] != | ||
1543 | snp->smk_host.s6_addr16[i]) { | ||
1544 | found = 0; | ||
1545 | break; | ||
1546 | } | ||
1547 | } | ||
1548 | if (found == 1) | ||
1549 | break; | ||
1550 | } | ||
1551 | if (found == 0) { | ||
1552 | snp = kzalloc(sizeof(*snp), GFP_KERNEL); | ||
1553 | if (snp == NULL) | ||
1554 | rc = -ENOMEM; | ||
1555 | else { | ||
1556 | snp->smk_host = newname; | ||
1557 | snp->smk_mask = fullmask; | ||
1558 | snp->smk_masks = mask; | ||
1559 | snp->smk_label = skp; | ||
1560 | smk_net6addr_insert(snp); | ||
1561 | } | ||
1562 | } else { | ||
1563 | snp->smk_label = skp; | ||
1564 | } | ||
1565 | |||
1566 | if (rc == 0) | ||
1567 | rc = count; | ||
1568 | |||
1569 | mutex_unlock(&smk_net6addr_lock); | ||
1570 | |||
1571 | free_out: | ||
1572 | kfree(smack); | ||
1573 | free_data_out: | ||
1574 | kfree(data); | ||
1575 | |||
1576 | return rc; | ||
1577 | } | ||
1578 | |||
1579 | static const struct file_operations smk_net6addr_ops = { | ||
1580 | .open = smk_open_net6addr, | ||
1581 | .read = seq_read, | ||
1582 | .llseek = seq_lseek, | ||
1583 | .write = smk_write_net6addr, | ||
1584 | .release = seq_release, | ||
1585 | }; | ||
1586 | #endif /* CONFIG_IPV6 */ | ||
1587 | |||
1316 | /** | 1588 | /** |
1317 | * smk_read_doi - read() for /smack/doi | 1589 | * smk_read_doi - read() for /smack/doi |
1318 | * @filp: file pointer, not actually used | 1590 | * @filp: file pointer, not actually used |
@@ -2320,11 +2592,7 @@ static const struct file_operations smk_revoke_subj_ops = { | |||
2320 | */ | 2592 | */ |
2321 | static int smk_init_sysfs(void) | 2593 | static int smk_init_sysfs(void) |
2322 | { | 2594 | { |
2323 | int err; | 2595 | return sysfs_create_mount_point(fs_kobj, "smackfs"); |
2324 | err = sysfs_create_mount_point(fs_kobj, "smackfs"); | ||
2325 | if (err) | ||
2326 | return err; | ||
2327 | return 0; | ||
2328 | } | 2596 | } |
2329 | 2597 | ||
2330 | /** | 2598 | /** |
@@ -2519,8 +2787,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
2519 | "direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, | 2787 | "direct", &smk_direct_ops, S_IRUGO|S_IWUSR}, |
2520 | [SMK_AMBIENT] = { | 2788 | [SMK_AMBIENT] = { |
2521 | "ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, | 2789 | "ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR}, |
2522 | [SMK_NETLBLADDR] = { | 2790 | [SMK_NET4ADDR] = { |
2523 | "netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR}, | 2791 | "netlabel", &smk_net4addr_ops, S_IRUGO|S_IWUSR}, |
2524 | [SMK_ONLYCAP] = { | 2792 | [SMK_ONLYCAP] = { |
2525 | "onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, | 2793 | "onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR}, |
2526 | [SMK_LOGGING] = { | 2794 | [SMK_LOGGING] = { |
@@ -2552,6 +2820,10 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
2552 | [SMK_UNCONFINED] = { | 2820 | [SMK_UNCONFINED] = { |
2553 | "unconfined", &smk_unconfined_ops, S_IRUGO|S_IWUSR}, | 2821 | "unconfined", &smk_unconfined_ops, S_IRUGO|S_IWUSR}, |
2554 | #endif | 2822 | #endif |
2823 | #if IS_ENABLED(CONFIG_IPV6) | ||
2824 | [SMK_NET6ADDR] = { | ||
2825 | "ipv6host", &smk_net6addr_ops, S_IRUGO|S_IWUSR}, | ||
2826 | #endif /* CONFIG_IPV6 */ | ||
2555 | /* last one */ | 2827 | /* last one */ |
2556 | {""} | 2828 | {""} |
2557 | }; | 2829 | }; |
diff --git a/security/yama/Kconfig b/security/yama/Kconfig index 3123e1da2fed..90c605eea892 100644 --- a/security/yama/Kconfig +++ b/security/yama/Kconfig | |||
@@ -6,14 +6,7 @@ config SECURITY_YAMA | |||
6 | This selects Yama, which extends DAC support with additional | 6 | This selects Yama, which extends DAC support with additional |
7 | system-wide security settings beyond regular Linux discretionary | 7 | system-wide security settings beyond regular Linux discretionary |
8 | access controls. Currently available is ptrace scope restriction. | 8 | access controls. Currently available is ptrace scope restriction. |
9 | Like capabilities, this security module stacks with other LSMs. | ||
9 | Further information can be found in Documentation/security/Yama.txt. | 10 | Further information can be found in Documentation/security/Yama.txt. |
10 | 11 | ||
11 | If you are unsure how to answer this question, answer N. | 12 | If you are unsure how to answer this question, answer N. |
12 | |||
13 | config SECURITY_YAMA_STACKED | ||
14 | bool "Yama stacked with other LSMs" | ||
15 | depends on SECURITY_YAMA | ||
16 | default n | ||
17 | help | ||
18 | When Yama is built into the kernel, force it to stack with the | ||
19 | selected primary LSM. | ||
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 5ebb89687936..d3c19c970a06 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c | |||
@@ -353,11 +353,6 @@ static struct security_hook_list yama_hooks[] = { | |||
353 | LSM_HOOK_INIT(task_free, yama_task_free), | 353 | LSM_HOOK_INIT(task_free, yama_task_free), |
354 | }; | 354 | }; |
355 | 355 | ||
356 | void __init yama_add_hooks(void) | ||
357 | { | ||
358 | security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks)); | ||
359 | } | ||
360 | |||
361 | #ifdef CONFIG_SYSCTL | 356 | #ifdef CONFIG_SYSCTL |
362 | static int yama_dointvec_minmax(struct ctl_table *table, int write, | 357 | static int yama_dointvec_minmax(struct ctl_table *table, int write, |
363 | void __user *buffer, size_t *lenp, loff_t *ppos) | 358 | void __user *buffer, size_t *lenp, loff_t *ppos) |
@@ -396,26 +391,18 @@ static struct ctl_table yama_sysctl_table[] = { | |||
396 | }, | 391 | }, |
397 | { } | 392 | { } |
398 | }; | 393 | }; |
399 | #endif /* CONFIG_SYSCTL */ | 394 | static void __init yama_init_sysctl(void) |
400 | |||
401 | static __init int yama_init(void) | ||
402 | { | 395 | { |
403 | #ifndef CONFIG_SECURITY_YAMA_STACKED | ||
404 | /* | ||
405 | * If yama is being stacked this is already taken care of. | ||
406 | */ | ||
407 | if (!security_module_enable("yama")) | ||
408 | return 0; | ||
409 | yama_add_hooks(); | ||
410 | #endif | ||
411 | pr_info("Yama: becoming mindful.\n"); | ||
412 | |||
413 | #ifdef CONFIG_SYSCTL | ||
414 | if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) | 396 | if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) |
415 | panic("Yama: sysctl registration failed.\n"); | 397 | panic("Yama: sysctl registration failed.\n"); |
416 | #endif | ||
417 | |||
418 | return 0; | ||
419 | } | 398 | } |
399 | #else | ||
400 | static inline void yama_init_sysctl(void) { } | ||
401 | #endif /* CONFIG_SYSCTL */ | ||
420 | 402 | ||
421 | security_initcall(yama_init); | 403 | void __init yama_add_hooks(void) |
404 | { | ||
405 | pr_info("Yama: becoming mindful.\n"); | ||
406 | security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks)); | ||
407 | yama_init_sysctl(); | ||
408 | } | ||