diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-23 18:04:24 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-23 18:04:24 -0500 |
commit | 2eb02aa94f99ae2b94ab3c42d5d605128fd5c0c5 (patch) | |
tree | 6cdea2843d46cbac680a02ad6d4cc5441847dbaa | |
parent | 65738c6b461a8bb0b056e024299738f7cc9a28b7 (diff) | |
parent | 120f3b11ef88fc38ce1d0ff9c9a4b37860ad3140 (diff) |
Merge branch 'fixes-v4.16-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem fixes from James Morris:
- keys fixes via David Howells:
"A collection of fixes for Linux keyrings, mostly thanks to Eric
Biggers:
- Fix some PKCS#7 verification issues.
- Fix handling of unsupported crypto in X.509.
- Fix too-large allocation in big_key"
- Seccomp updates via Kees Cook:
"These are fixes for the get_metadata interface that landed during
-rc1. While the new selftest is strictly not a bug fix, I think
it's in the same spirit of avoiding bugs"
- an IMA build fix from Randy Dunlap
* 'fixes-v4.16-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
integrity/security: fix digsig.c build error with header file
KEYS: Use individual pages in big_key for crypto buffers
X.509: fix NULL dereference when restricting key with unsupported_sig
X.509: fix BUG_ON() when hash algorithm is unsupported
PKCS#7: fix direct verification of SignerInfo signature
PKCS#7: fix certificate blacklisting
PKCS#7: fix certificate chain verification
seccomp: add a selftest for get_metadata
ptrace, seccomp: tweak get_metadata behavior slightly
seccomp, ptrace: switch get_metadata types to arch independent
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_trust.c | 1 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_verify.c | 12 | ||||
-rw-r--r-- | crypto/asymmetric_keys/public_key.c | 4 | ||||
-rw-r--r-- | crypto/asymmetric_keys/restrict.c | 21 | ||||
-rw-r--r-- | include/uapi/linux/ptrace.h | 4 | ||||
-rw-r--r-- | kernel/seccomp.c | 6 | ||||
-rw-r--r-- | security/integrity/digsig.c | 1 | ||||
-rw-r--r-- | security/keys/big_key.c | 110 | ||||
-rw-r--r-- | tools/testing/selftests/seccomp/seccomp_bpf.c | 61 |
9 files changed, 179 insertions, 41 deletions
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index 1f4e25f10049..598906b1e28d 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c | |||
@@ -106,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, | |||
106 | pr_devel("sinfo %u: Direct signer is key %x\n", | 106 | pr_devel("sinfo %u: Direct signer is key %x\n", |
107 | sinfo->index, key_serial(key)); | 107 | sinfo->index, key_serial(key)); |
108 | x509 = NULL; | 108 | x509 = NULL; |
109 | sig = sinfo->sig; | ||
109 | goto matched; | 110 | goto matched; |
110 | } | 111 | } |
111 | if (PTR_ERR(key) != -ENOKEY) | 112 | if (PTR_ERR(key) != -ENOKEY) |
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 39e6de0c2761..97c77f66b20d 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c | |||
@@ -270,7 +270,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
270 | sinfo->index); | 270 | sinfo->index); |
271 | return 0; | 271 | return 0; |
272 | } | 272 | } |
273 | ret = public_key_verify_signature(p->pub, p->sig); | 273 | ret = public_key_verify_signature(p->pub, x509->sig); |
274 | if (ret < 0) | 274 | if (ret < 0) |
275 | return ret; | 275 | return ret; |
276 | x509->signer = p; | 276 | x509->signer = p; |
@@ -366,8 +366,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, | |||
366 | * | 366 | * |
367 | * (*) -EBADMSG if some part of the message was invalid, or: | 367 | * (*) -EBADMSG if some part of the message was invalid, or: |
368 | * | 368 | * |
369 | * (*) 0 if no signature chains were found to be blacklisted or to contain | 369 | * (*) 0 if a signature chain passed verification, or: |
370 | * unsupported crypto, or: | ||
371 | * | 370 | * |
372 | * (*) -EKEYREJECTED if a blacklisted key was encountered, or: | 371 | * (*) -EKEYREJECTED if a blacklisted key was encountered, or: |
373 | * | 372 | * |
@@ -423,8 +422,11 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, | |||
423 | 422 | ||
424 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | 423 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { |
425 | ret = pkcs7_verify_one(pkcs7, sinfo); | 424 | ret = pkcs7_verify_one(pkcs7, sinfo); |
426 | if (sinfo->blacklisted && actual_ret == -ENOPKG) | 425 | if (sinfo->blacklisted) { |
427 | actual_ret = -EKEYREJECTED; | 426 | if (actual_ret == -ENOPKG) |
427 | actual_ret = -EKEYREJECTED; | ||
428 | continue; | ||
429 | } | ||
428 | if (ret < 0) { | 430 | if (ret < 0) { |
429 | if (ret == -ENOPKG) { | 431 | if (ret == -ENOPKG) { |
430 | sinfo->unsupported_crypto = true; | 432 | sinfo->unsupported_crypto = true; |
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index de996586762a..e929fe1e4106 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c | |||
@@ -79,9 +79,11 @@ int public_key_verify_signature(const struct public_key *pkey, | |||
79 | 79 | ||
80 | BUG_ON(!pkey); | 80 | BUG_ON(!pkey); |
81 | BUG_ON(!sig); | 81 | BUG_ON(!sig); |
82 | BUG_ON(!sig->digest); | ||
83 | BUG_ON(!sig->s); | 82 | BUG_ON(!sig->s); |
84 | 83 | ||
84 | if (!sig->digest) | ||
85 | return -ENOPKG; | ||
86 | |||
85 | alg_name = sig->pkey_algo; | 87 | alg_name = sig->pkey_algo; |
86 | if (strcmp(sig->pkey_algo, "rsa") == 0) { | 88 | if (strcmp(sig->pkey_algo, "rsa") == 0) { |
87 | /* The data wangled by the RSA algorithm is typically padded | 89 | /* The data wangled by the RSA algorithm is typically padded |
diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c index 86fb68508952..7c93c7728454 100644 --- a/crypto/asymmetric_keys/restrict.c +++ b/crypto/asymmetric_keys/restrict.c | |||
@@ -67,8 +67,9 @@ __setup("ca_keys=", ca_keys_setup); | |||
67 | * | 67 | * |
68 | * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a | 68 | * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a |
69 | * matching parent certificate in the trusted list, -EKEYREJECTED if the | 69 | * matching parent certificate in the trusted list, -EKEYREJECTED if the |
70 | * signature check fails or the key is blacklisted and some other error if | 70 | * signature check fails or the key is blacklisted, -ENOPKG if the signature |
71 | * there is a matching certificate but the signature check cannot be performed. | 71 | * uses unsupported crypto, or some other error if there is a matching |
72 | * certificate but the signature check cannot be performed. | ||
72 | */ | 73 | */ |
73 | int restrict_link_by_signature(struct key *dest_keyring, | 74 | int restrict_link_by_signature(struct key *dest_keyring, |
74 | const struct key_type *type, | 75 | const struct key_type *type, |
@@ -88,6 +89,8 @@ int restrict_link_by_signature(struct key *dest_keyring, | |||
88 | return -EOPNOTSUPP; | 89 | return -EOPNOTSUPP; |
89 | 90 | ||
90 | sig = payload->data[asym_auth]; | 91 | sig = payload->data[asym_auth]; |
92 | if (!sig) | ||
93 | return -ENOPKG; | ||
91 | if (!sig->auth_ids[0] && !sig->auth_ids[1]) | 94 | if (!sig->auth_ids[0] && !sig->auth_ids[1]) |
92 | return -ENOKEY; | 95 | return -ENOKEY; |
93 | 96 | ||
@@ -139,6 +142,8 @@ static int key_or_keyring_common(struct key *dest_keyring, | |||
139 | return -EOPNOTSUPP; | 142 | return -EOPNOTSUPP; |
140 | 143 | ||
141 | sig = payload->data[asym_auth]; | 144 | sig = payload->data[asym_auth]; |
145 | if (!sig) | ||
146 | return -ENOPKG; | ||
142 | if (!sig->auth_ids[0] && !sig->auth_ids[1]) | 147 | if (!sig->auth_ids[0] && !sig->auth_ids[1]) |
143 | return -ENOKEY; | 148 | return -ENOKEY; |
144 | 149 | ||
@@ -222,9 +227,9 @@ static int key_or_keyring_common(struct key *dest_keyring, | |||
222 | * | 227 | * |
223 | * Returns 0 if the new certificate was accepted, -ENOKEY if we | 228 | * Returns 0 if the new certificate was accepted, -ENOKEY if we |
224 | * couldn't find a matching parent certificate in the trusted list, | 229 | * couldn't find a matching parent certificate in the trusted list, |
225 | * -EKEYREJECTED if the signature check fails, and some other error if | 230 | * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses |
226 | * there is a matching certificate but the signature check cannot be | 231 | * unsupported crypto, or some other error if there is a matching certificate |
227 | * performed. | 232 | * but the signature check cannot be performed. |
228 | */ | 233 | */ |
229 | int restrict_link_by_key_or_keyring(struct key *dest_keyring, | 234 | int restrict_link_by_key_or_keyring(struct key *dest_keyring, |
230 | const struct key_type *type, | 235 | const struct key_type *type, |
@@ -249,9 +254,9 @@ int restrict_link_by_key_or_keyring(struct key *dest_keyring, | |||
249 | * | 254 | * |
250 | * Returns 0 if the new certificate was accepted, -ENOKEY if we | 255 | * Returns 0 if the new certificate was accepted, -ENOKEY if we |
251 | * couldn't find a matching parent certificate in the trusted list, | 256 | * couldn't find a matching parent certificate in the trusted list, |
252 | * -EKEYREJECTED if the signature check fails, and some other error if | 257 | * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses |
253 | * there is a matching certificate but the signature check cannot be | 258 | * unsupported crypto, or some other error if there is a matching certificate |
254 | * performed. | 259 | * but the signature check cannot be performed. |
255 | */ | 260 | */ |
256 | int restrict_link_by_key_or_keyring_chain(struct key *dest_keyring, | 261 | int restrict_link_by_key_or_keyring_chain(struct key *dest_keyring, |
257 | const struct key_type *type, | 262 | const struct key_type *type, |
diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h index e46d82b91166..d5a1b8a492b9 100644 --- a/include/uapi/linux/ptrace.h +++ b/include/uapi/linux/ptrace.h | |||
@@ -69,8 +69,8 @@ struct ptrace_peeksiginfo_args { | |||
69 | #define PTRACE_SECCOMP_GET_METADATA 0x420d | 69 | #define PTRACE_SECCOMP_GET_METADATA 0x420d |
70 | 70 | ||
71 | struct seccomp_metadata { | 71 | struct seccomp_metadata { |
72 | unsigned long filter_off; /* Input: which filter */ | 72 | __u64 filter_off; /* Input: which filter */ |
73 | unsigned int flags; /* Output: filter's flags */ | 73 | __u64 flags; /* Output: filter's flags */ |
74 | }; | 74 | }; |
75 | 75 | ||
76 | /* Read signals from a shared (process wide) queue */ | 76 | /* Read signals from a shared (process wide) queue */ |
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 940fa408a288..dc77548167ef 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -1076,14 +1076,16 @@ long seccomp_get_metadata(struct task_struct *task, | |||
1076 | 1076 | ||
1077 | size = min_t(unsigned long, size, sizeof(kmd)); | 1077 | size = min_t(unsigned long, size, sizeof(kmd)); |
1078 | 1078 | ||
1079 | if (copy_from_user(&kmd, data, size)) | 1079 | if (size < sizeof(kmd.filter_off)) |
1080 | return -EINVAL; | ||
1081 | |||
1082 | if (copy_from_user(&kmd.filter_off, data, sizeof(kmd.filter_off))) | ||
1080 | return -EFAULT; | 1083 | return -EFAULT; |
1081 | 1084 | ||
1082 | filter = get_nth_filter(task, kmd.filter_off); | 1085 | filter = get_nth_filter(task, kmd.filter_off); |
1083 | if (IS_ERR(filter)) | 1086 | if (IS_ERR(filter)) |
1084 | return PTR_ERR(filter); | 1087 | return PTR_ERR(filter); |
1085 | 1088 | ||
1086 | memset(&kmd, 0, sizeof(kmd)); | ||
1087 | if (filter->log) | 1089 | if (filter->log) |
1088 | kmd.flags |= SECCOMP_FILTER_FLAG_LOG; | 1090 | kmd.flags |= SECCOMP_FILTER_FLAG_LOG; |
1089 | 1091 | ||
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 6f9e4ce568cd..9bb0a7f2863e 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/cred.h> | 18 | #include <linux/cred.h> |
19 | #include <linux/key-type.h> | 19 | #include <linux/key-type.h> |
20 | #include <linux/digsig.h> | 20 | #include <linux/digsig.h> |
21 | #include <linux/vmalloc.h> | ||
21 | #include <crypto/public_key.h> | 22 | #include <crypto/public_key.h> |
22 | #include <keys/system_keyring.h> | 23 | #include <keys/system_keyring.h> |
23 | 24 | ||
diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 929e14978c42..fa728f662a6f 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c | |||
@@ -22,6 +22,13 @@ | |||
22 | #include <keys/big_key-type.h> | 22 | #include <keys/big_key-type.h> |
23 | #include <crypto/aead.h> | 23 | #include <crypto/aead.h> |
24 | 24 | ||
25 | struct big_key_buf { | ||
26 | unsigned int nr_pages; | ||
27 | void *virt; | ||
28 | struct scatterlist *sg; | ||
29 | struct page *pages[]; | ||
30 | }; | ||
31 | |||
25 | /* | 32 | /* |
26 | * Layout of key payload words. | 33 | * Layout of key payload words. |
27 | */ | 34 | */ |
@@ -91,10 +98,9 @@ static DEFINE_MUTEX(big_key_aead_lock); | |||
91 | /* | 98 | /* |
92 | * Encrypt/decrypt big_key data | 99 | * Encrypt/decrypt big_key data |
93 | */ | 100 | */ |
94 | static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) | 101 | static int big_key_crypt(enum big_key_op op, struct big_key_buf *buf, size_t datalen, u8 *key) |
95 | { | 102 | { |
96 | int ret; | 103 | int ret; |
97 | struct scatterlist sgio; | ||
98 | struct aead_request *aead_req; | 104 | struct aead_request *aead_req; |
99 | /* We always use a zero nonce. The reason we can get away with this is | 105 | /* We always use a zero nonce. The reason we can get away with this is |
100 | * because we're using a different randomly generated key for every | 106 | * because we're using a different randomly generated key for every |
@@ -109,8 +115,7 @@ static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) | |||
109 | return -ENOMEM; | 115 | return -ENOMEM; |
110 | 116 | ||
111 | memset(zero_nonce, 0, sizeof(zero_nonce)); | 117 | memset(zero_nonce, 0, sizeof(zero_nonce)); |
112 | sg_init_one(&sgio, data, datalen + (op == BIG_KEY_ENC ? ENC_AUTHTAG_SIZE : 0)); | 118 | aead_request_set_crypt(aead_req, buf->sg, buf->sg, datalen, zero_nonce); |
113 | aead_request_set_crypt(aead_req, &sgio, &sgio, datalen, zero_nonce); | ||
114 | aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); | 119 | aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); |
115 | aead_request_set_ad(aead_req, 0); | 120 | aead_request_set_ad(aead_req, 0); |
116 | 121 | ||
@@ -130,21 +135,81 @@ error: | |||
130 | } | 135 | } |
131 | 136 | ||
132 | /* | 137 | /* |
138 | * Free up the buffer. | ||
139 | */ | ||
140 | static void big_key_free_buffer(struct big_key_buf *buf) | ||
141 | { | ||
142 | unsigned int i; | ||
143 | |||
144 | if (buf->virt) { | ||
145 | memset(buf->virt, 0, buf->nr_pages * PAGE_SIZE); | ||
146 | vunmap(buf->virt); | ||
147 | } | ||
148 | |||
149 | for (i = 0; i < buf->nr_pages; i++) | ||
150 | if (buf->pages[i]) | ||
151 | __free_page(buf->pages[i]); | ||
152 | |||
153 | kfree(buf); | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * Allocate a buffer consisting of a set of pages with a virtual mapping | ||
158 | * applied over them. | ||
159 | */ | ||
160 | static void *big_key_alloc_buffer(size_t len) | ||
161 | { | ||
162 | struct big_key_buf *buf; | ||
163 | unsigned int npg = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
164 | unsigned int i, l; | ||
165 | |||
166 | buf = kzalloc(sizeof(struct big_key_buf) + | ||
167 | sizeof(struct page) * npg + | ||
168 | sizeof(struct scatterlist) * npg, | ||
169 | GFP_KERNEL); | ||
170 | if (!buf) | ||
171 | return NULL; | ||
172 | |||
173 | buf->nr_pages = npg; | ||
174 | buf->sg = (void *)(buf->pages + npg); | ||
175 | sg_init_table(buf->sg, npg); | ||
176 | |||
177 | for (i = 0; i < buf->nr_pages; i++) { | ||
178 | buf->pages[i] = alloc_page(GFP_KERNEL); | ||
179 | if (!buf->pages[i]) | ||
180 | goto nomem; | ||
181 | |||
182 | l = min_t(size_t, len, PAGE_SIZE); | ||
183 | sg_set_page(&buf->sg[i], buf->pages[i], l, 0); | ||
184 | len -= l; | ||
185 | } | ||
186 | |||
187 | buf->virt = vmap(buf->pages, buf->nr_pages, VM_MAP, PAGE_KERNEL); | ||
188 | if (!buf->virt) | ||
189 | goto nomem; | ||
190 | |||
191 | return buf; | ||
192 | |||
193 | nomem: | ||
194 | big_key_free_buffer(buf); | ||
195 | return NULL; | ||
196 | } | ||
197 | |||
198 | /* | ||
133 | * Preparse a big key | 199 | * Preparse a big key |
134 | */ | 200 | */ |
135 | int big_key_preparse(struct key_preparsed_payload *prep) | 201 | int big_key_preparse(struct key_preparsed_payload *prep) |
136 | { | 202 | { |
203 | struct big_key_buf *buf; | ||
137 | struct path *path = (struct path *)&prep->payload.data[big_key_path]; | 204 | struct path *path = (struct path *)&prep->payload.data[big_key_path]; |
138 | struct file *file; | 205 | struct file *file; |
139 | u8 *enckey; | 206 | u8 *enckey; |
140 | u8 *data = NULL; | ||
141 | ssize_t written; | 207 | ssize_t written; |
142 | size_t datalen = prep->datalen; | 208 | size_t datalen = prep->datalen, enclen = datalen + ENC_AUTHTAG_SIZE; |
143 | int ret; | 209 | int ret; |
144 | 210 | ||
145 | ret = -EINVAL; | ||
146 | if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data) | 211 | if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data) |
147 | goto error; | 212 | return -EINVAL; |
148 | 213 | ||
149 | /* Set an arbitrary quota */ | 214 | /* Set an arbitrary quota */ |
150 | prep->quotalen = 16; | 215 | prep->quotalen = 16; |
@@ -157,13 +222,12 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
157 | * | 222 | * |
158 | * File content is stored encrypted with randomly generated key. | 223 | * File content is stored encrypted with randomly generated key. |
159 | */ | 224 | */ |
160 | size_t enclen = datalen + ENC_AUTHTAG_SIZE; | ||
161 | loff_t pos = 0; | 225 | loff_t pos = 0; |
162 | 226 | ||
163 | data = kmalloc(enclen, GFP_KERNEL); | 227 | buf = big_key_alloc_buffer(enclen); |
164 | if (!data) | 228 | if (!buf) |
165 | return -ENOMEM; | 229 | return -ENOMEM; |
166 | memcpy(data, prep->data, datalen); | 230 | memcpy(buf->virt, prep->data, datalen); |
167 | 231 | ||
168 | /* generate random key */ | 232 | /* generate random key */ |
169 | enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); | 233 | enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); |
@@ -176,7 +240,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
176 | goto err_enckey; | 240 | goto err_enckey; |
177 | 241 | ||
178 | /* encrypt aligned data */ | 242 | /* encrypt aligned data */ |
179 | ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey); | 243 | ret = big_key_crypt(BIG_KEY_ENC, buf, datalen, enckey); |
180 | if (ret) | 244 | if (ret) |
181 | goto err_enckey; | 245 | goto err_enckey; |
182 | 246 | ||
@@ -187,7 +251,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
187 | goto err_enckey; | 251 | goto err_enckey; |
188 | } | 252 | } |
189 | 253 | ||
190 | written = kernel_write(file, data, enclen, &pos); | 254 | written = kernel_write(file, buf->virt, enclen, &pos); |
191 | if (written != enclen) { | 255 | if (written != enclen) { |
192 | ret = written; | 256 | ret = written; |
193 | if (written >= 0) | 257 | if (written >= 0) |
@@ -202,7 +266,7 @@ int big_key_preparse(struct key_preparsed_payload *prep) | |||
202 | *path = file->f_path; | 266 | *path = file->f_path; |
203 | path_get(path); | 267 | path_get(path); |
204 | fput(file); | 268 | fput(file); |
205 | kzfree(data); | 269 | big_key_free_buffer(buf); |
206 | } else { | 270 | } else { |
207 | /* Just store the data in a buffer */ | 271 | /* Just store the data in a buffer */ |
208 | void *data = kmalloc(datalen, GFP_KERNEL); | 272 | void *data = kmalloc(datalen, GFP_KERNEL); |
@@ -220,7 +284,7 @@ err_fput: | |||
220 | err_enckey: | 284 | err_enckey: |
221 | kzfree(enckey); | 285 | kzfree(enckey); |
222 | error: | 286 | error: |
223 | kzfree(data); | 287 | big_key_free_buffer(buf); |
224 | return ret; | 288 | return ret; |
225 | } | 289 | } |
226 | 290 | ||
@@ -298,15 +362,15 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) | |||
298 | return datalen; | 362 | return datalen; |
299 | 363 | ||
300 | if (datalen > BIG_KEY_FILE_THRESHOLD) { | 364 | if (datalen > BIG_KEY_FILE_THRESHOLD) { |
365 | struct big_key_buf *buf; | ||
301 | struct path *path = (struct path *)&key->payload.data[big_key_path]; | 366 | struct path *path = (struct path *)&key->payload.data[big_key_path]; |
302 | struct file *file; | 367 | struct file *file; |
303 | u8 *data; | ||
304 | u8 *enckey = (u8 *)key->payload.data[big_key_data]; | 368 | u8 *enckey = (u8 *)key->payload.data[big_key_data]; |
305 | size_t enclen = datalen + ENC_AUTHTAG_SIZE; | 369 | size_t enclen = datalen + ENC_AUTHTAG_SIZE; |
306 | loff_t pos = 0; | 370 | loff_t pos = 0; |
307 | 371 | ||
308 | data = kmalloc(enclen, GFP_KERNEL); | 372 | buf = big_key_alloc_buffer(enclen); |
309 | if (!data) | 373 | if (!buf) |
310 | return -ENOMEM; | 374 | return -ENOMEM; |
311 | 375 | ||
312 | file = dentry_open(path, O_RDONLY, current_cred()); | 376 | file = dentry_open(path, O_RDONLY, current_cred()); |
@@ -316,26 +380,26 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen) | |||
316 | } | 380 | } |
317 | 381 | ||
318 | /* read file to kernel and decrypt */ | 382 | /* read file to kernel and decrypt */ |
319 | ret = kernel_read(file, data, enclen, &pos); | 383 | ret = kernel_read(file, buf->virt, enclen, &pos); |
320 | if (ret >= 0 && ret != enclen) { | 384 | if (ret >= 0 && ret != enclen) { |
321 | ret = -EIO; | 385 | ret = -EIO; |
322 | goto err_fput; | 386 | goto err_fput; |
323 | } | 387 | } |
324 | 388 | ||
325 | ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey); | 389 | ret = big_key_crypt(BIG_KEY_DEC, buf, enclen, enckey); |
326 | if (ret) | 390 | if (ret) |
327 | goto err_fput; | 391 | goto err_fput; |
328 | 392 | ||
329 | ret = datalen; | 393 | ret = datalen; |
330 | 394 | ||
331 | /* copy decrypted data to user */ | 395 | /* copy decrypted data to user */ |
332 | if (copy_to_user(buffer, data, datalen) != 0) | 396 | if (copy_to_user(buffer, buf->virt, datalen) != 0) |
333 | ret = -EFAULT; | 397 | ret = -EFAULT; |
334 | 398 | ||
335 | err_fput: | 399 | err_fput: |
336 | fput(file); | 400 | fput(file); |
337 | error: | 401 | error: |
338 | kzfree(data); | 402 | big_key_free_buffer(buf); |
339 | } else { | 403 | } else { |
340 | ret = datalen; | 404 | ret = datalen; |
341 | if (copy_to_user(buffer, key->payload.data[big_key_data], | 405 | if (copy_to_user(buffer, key->payload.data[big_key_data], |
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 0b457e8e0f0c..5df609950a66 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c | |||
@@ -141,6 +141,15 @@ struct seccomp_data { | |||
141 | #define SECCOMP_FILTER_FLAG_LOG 2 | 141 | #define SECCOMP_FILTER_FLAG_LOG 2 |
142 | #endif | 142 | #endif |
143 | 143 | ||
144 | #ifndef PTRACE_SECCOMP_GET_METADATA | ||
145 | #define PTRACE_SECCOMP_GET_METADATA 0x420d | ||
146 | |||
147 | struct seccomp_metadata { | ||
148 | __u64 filter_off; /* Input: which filter */ | ||
149 | __u64 flags; /* Output: filter's flags */ | ||
150 | }; | ||
151 | #endif | ||
152 | |||
144 | #ifndef seccomp | 153 | #ifndef seccomp |
145 | int seccomp(unsigned int op, unsigned int flags, void *args) | 154 | int seccomp(unsigned int op, unsigned int flags, void *args) |
146 | { | 155 | { |
@@ -2845,6 +2854,58 @@ TEST(get_action_avail) | |||
2845 | EXPECT_EQ(errno, EOPNOTSUPP); | 2854 | EXPECT_EQ(errno, EOPNOTSUPP); |
2846 | } | 2855 | } |
2847 | 2856 | ||
2857 | TEST(get_metadata) | ||
2858 | { | ||
2859 | pid_t pid; | ||
2860 | int pipefd[2]; | ||
2861 | char buf; | ||
2862 | struct seccomp_metadata md; | ||
2863 | |||
2864 | ASSERT_EQ(0, pipe(pipefd)); | ||
2865 | |||
2866 | pid = fork(); | ||
2867 | ASSERT_GE(pid, 0); | ||
2868 | if (pid == 0) { | ||
2869 | struct sock_filter filter[] = { | ||
2870 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), | ||
2871 | }; | ||
2872 | struct sock_fprog prog = { | ||
2873 | .len = (unsigned short)ARRAY_SIZE(filter), | ||
2874 | .filter = filter, | ||
2875 | }; | ||
2876 | |||
2877 | /* one with log, one without */ | ||
2878 | ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, | ||
2879 | SECCOMP_FILTER_FLAG_LOG, &prog)); | ||
2880 | ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog)); | ||
2881 | |||
2882 | ASSERT_EQ(0, close(pipefd[0])); | ||
2883 | ASSERT_EQ(1, write(pipefd[1], "1", 1)); | ||
2884 | ASSERT_EQ(0, close(pipefd[1])); | ||
2885 | |||
2886 | while (1) | ||
2887 | sleep(100); | ||
2888 | } | ||
2889 | |||
2890 | ASSERT_EQ(0, close(pipefd[1])); | ||
2891 | ASSERT_EQ(1, read(pipefd[0], &buf, 1)); | ||
2892 | |||
2893 | ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid)); | ||
2894 | ASSERT_EQ(pid, waitpid(pid, NULL, 0)); | ||
2895 | |||
2896 | md.filter_off = 0; | ||
2897 | ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md)); | ||
2898 | EXPECT_EQ(md.flags, SECCOMP_FILTER_FLAG_LOG); | ||
2899 | EXPECT_EQ(md.filter_off, 0); | ||
2900 | |||
2901 | md.filter_off = 1; | ||
2902 | ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md)); | ||
2903 | EXPECT_EQ(md.flags, 0); | ||
2904 | EXPECT_EQ(md.filter_off, 1); | ||
2905 | |||
2906 | ASSERT_EQ(0, kill(pid, SIGKILL)); | ||
2907 | } | ||
2908 | |||
2848 | /* | 2909 | /* |
2849 | * TODO: | 2910 | * TODO: |
2850 | * - add microbenchmarks | 2911 | * - add microbenchmarks |