blob: 6cd9f2c718ee891cb666c23e7654226614c1e991 [file] [log] [blame]
Victor Hsieh38c55032018-09-26 12:44:53 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "VerityUtils"
18
19#include <nativehelper/JNIHelp.h>
20#include "jni.h"
21#include <utils/Log.h>
22
Victor Hsiehfcff8dd2018-12-14 15:59:03 -080023#include <errno.h>
24#include <fcntl.h>
Victor Hsieh38c55032018-09-26 12:44:53 -070025#include <string.h>
Victor Hsiehfcff8dd2018-12-14 15:59:03 -080026#include <sys/ioctl.h>
27#include <sys/stat.h>
28#include <sys/types.h>
29
George Burgess IV20d7c962019-02-01 11:52:55 -080030#include <type_traits>
31
Victor Hsiehfcff8dd2018-12-14 15:59:03 -080032#include <android-base/unique_fd.h>
Victor Hsieh38c55032018-09-26 12:44:53 -070033
Victor Hsieh142c0172019-01-25 12:40:46 -080034// TODO(112037636): Always include once fsverity.h is upstreamed.
35#if __has_include(<linux/fsverity.h>)
Victor Hsieh38c55032018-09-26 12:44:53 -070036#include <linux/fsverity.h>
Victor Hsieh16890292019-01-29 11:44:39 -080037#else
38
39// Before fs-verity is upstreamed, use the current snapshot for development.
40// https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/tree/include/uapi/linux/fsverity.h?h=fsverity
41
42#include <linux/limits.h>
43#include <linux/ioctl.h>
44#include <linux/types.h>
45
46struct fsverity_digest {
47 __u16 digest_algorithm;
48 __u16 digest_size; /* input/output */
49 __u8 digest[];
50};
51
52#define FS_IOC_ENABLE_VERITY _IO('f', 133)
53#define FS_IOC_MEASURE_VERITY _IOWR('f', 134, struct fsverity_digest)
54
55#define FS_VERITY_MAGIC "FSVerity"
56
57#define FS_VERITY_ALG_SHA256 1
58
59struct fsverity_descriptor {
60 __u8 magic[8]; /* must be FS_VERITY_MAGIC */
61 __u8 major_version; /* must be 1 */
62 __u8 minor_version; /* must be 0 */
63 __u8 log_data_blocksize;/* log2(data-bytes-per-hash), e.g. 12 for 4KB */
64 __u8 log_tree_blocksize;/* log2(tree-bytes-per-hash), e.g. 12 for 4KB */
65 __le16 data_algorithm; /* hash algorithm for data blocks */
66 __le16 tree_algorithm; /* hash algorithm for tree blocks */
67 __le32 flags; /* flags */
68 __le32 __reserved1; /* must be 0 */
69 __le64 orig_file_size; /* size of the original file data */
70 __le16 auth_ext_count; /* number of authenticated extensions */
71 __u8 __reserved2[30]; /* must be 0 */
72};
73
74#define FS_VERITY_EXT_ROOT_HASH 1
75#define FS_VERITY_EXT_PKCS7_SIGNATURE 3
76
77struct fsverity_extension {
78 __le32 length;
79 __le16 type; /* Type of this extension (see codes above) */
80 __le16 __reserved; /* Reserved, must be 0 */
81};
82
83struct fsverity_digest_disk {
84 __le16 digest_algorithm;
85 __le16 digest_size;
86 __u8 digest[];
87};
88
89struct fsverity_footer {
90 __le32 desc_reverse_offset; /* distance to fsverity_descriptor */
91 __u8 magic[8]; /* FS_VERITY_MAGIC */
92} __packed;
93
Victor Hsieh38c55032018-09-26 12:44:53 -070094#endif
95
Victor Hsieh16890292019-01-29 11:44:39 -080096const int kSha256Bytes = 32;
97
Victor Hsieh38c55032018-09-26 12:44:53 -070098namespace android {
99
100namespace {
101
102class JavaByteArrayHolder {
103 public:
George Burgess IV20d7c962019-02-01 11:52:55 -0800104 JavaByteArrayHolder(const JavaByteArrayHolder &other) = delete;
105 JavaByteArrayHolder(JavaByteArrayHolder &&other)
106 : mEnv(other.mEnv), mBytes(other.mBytes), mElements(other.mElements) {
107 other.mElements = nullptr;
108 }
109
110 static JavaByteArrayHolder newArray(JNIEnv* env, jsize size) {
111 return JavaByteArrayHolder(env, size);
Victor Hsieh38c55032018-09-26 12:44:53 -0700112 }
113
114 jbyte* getRaw() {
115 return mElements;
116 }
117
118 jbyteArray release() {
119 mEnv->ReleaseByteArrayElements(mBytes, mElements, 0);
120 mElements = nullptr;
121 return mBytes;
122 }
123
George Burgess IV20d7c962019-02-01 11:52:55 -0800124 ~JavaByteArrayHolder() {
Victor Hsiehb9d68322019-02-08 09:56:16 -0800125 LOG_ALWAYS_FATAL_IF(mElements != nullptr, "Elements are not released");
George Burgess IV20d7c962019-02-01 11:52:55 -0800126 }
127
Victor Hsieh38c55032018-09-26 12:44:53 -0700128 private:
129 JavaByteArrayHolder(JNIEnv* env, jsize size) {
130 mEnv = env;
131 mBytes = mEnv->NewByteArray(size);
132 mElements = mEnv->GetByteArrayElements(mBytes, nullptr);
133 memset(mElements, 0, size);
134 }
135
Victor Hsieh38c55032018-09-26 12:44:53 -0700136 JNIEnv* mEnv;
137 jbyteArray mBytes;
138 jbyte* mElements;
139};
140
Victor Hsiehaa6cb132018-11-08 11:16:21 -0800141int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
Victor Hsiehaa6cb132018-11-08 11:16:21 -0800142 const char* path = env->GetStringUTFChars(filePath, nullptr);
143 ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
144 if (rfd.get() < 0) {
145 return errno;
146 }
147 if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) {
148 return errno;
149 }
150 return 0;
Victor Hsiehaa6cb132018-11-08 11:16:21 -0800151}
152
Victor Hsiehfcff8dd2018-12-14 15:59:03 -0800153int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
George Burgess IV20d7c962019-02-01 11:52:55 -0800154 using Storage = std::aligned_storage_t<sizeof(fsverity_digest) + kSha256Bytes>;
155
156 Storage bytes;
157 fsverity_digest *data = reinterpret_cast<fsverity_digest *>(&bytes);
Victor Hsiehfcff8dd2018-12-14 15:59:03 -0800158 data->digest_size = kSha256Bytes; // the only input/output parameter
159
160 const char* path = env->GetStringUTFChars(filePath, nullptr);
Victor Hsiehaa6cb132018-11-08 11:16:21 -0800161 ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
162 if (rfd.get() < 0) {
163 return errno;
164 }
Victor Hsiehfcff8dd2018-12-14 15:59:03 -0800165 if (ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data) < 0) {
166 return errno;
167 }
168 return 0;
Victor Hsiehfcff8dd2018-12-14 15:59:03 -0800169}
170
Victor Hsieheef29312018-10-29 16:25:34 -0700171jbyteArray constructFsveritySignedData(JNIEnv* env, jobject /* clazz */, jbyteArray digest) {
Victor Hsieheef29312018-10-29 16:25:34 -0700172 auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest_disk) + kSha256Bytes);
George Burgess IV20d7c962019-02-01 11:52:55 -0800173 fsverity_digest_disk* data = reinterpret_cast<fsverity_digest_disk*>(raii.getRaw());
Victor Hsieheef29312018-10-29 16:25:34 -0700174
175 data->digest_algorithm = FS_VERITY_ALG_SHA256;
176 data->digest_size = kSha256Bytes;
177 if (env->GetArrayLength(digest) != kSha256Bytes) {
178 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid hash size of %d",
179 env->GetArrayLength(digest));
180 return 0;
181 }
182 const jbyte* src = env->GetByteArrayElements(digest, nullptr);
183 memcpy(data->digest, src, kSha256Bytes);
184
George Burgess IV20d7c962019-02-01 11:52:55 -0800185 return raii.release();
Victor Hsieheef29312018-10-29 16:25:34 -0700186}
187
188
Victor Hsieh38c55032018-09-26 12:44:53 -0700189jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) {
Victor Hsieh38c55032018-09-26 12:44:53 -0700190 auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor));
George Burgess IV20d7c962019-02-01 11:52:55 -0800191 fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii.getRaw());
Victor Hsieh38c55032018-09-26 12:44:53 -0700192
193 memcpy(desc->magic, FS_VERITY_MAGIC, sizeof(desc->magic));
194 desc->major_version = 1;
195 desc->minor_version = 0;
196 desc->log_data_blocksize = 12;
197 desc->log_tree_blocksize = 12;
198 desc->data_algorithm = FS_VERITY_ALG_SHA256;
199 desc->tree_algorithm = FS_VERITY_ALG_SHA256;
200 desc->flags = 0;
201 desc->orig_file_size = fileSize;
202 desc->auth_ext_count = 1;
203
George Burgess IV20d7c962019-02-01 11:52:55 -0800204 return raii.release();
Victor Hsieh38c55032018-09-26 12:44:53 -0700205}
206
207jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId,
208 jint extensionDataSize) {
Victor Hsieh38c55032018-09-26 12:44:53 -0700209 auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension));
George Burgess IV20d7c962019-02-01 11:52:55 -0800210 fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii.getRaw());
Victor Hsieh38c55032018-09-26 12:44:53 -0700211
212 ext->length = sizeof(fsverity_extension) + extensionDataSize;
213 ext->type = extensionId;
214
George Burgess IV20d7c962019-02-01 11:52:55 -0800215 return raii.release();
Victor Hsieh38c55032018-09-26 12:44:53 -0700216}
217
218jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */,
219 jint offsetToDescriptorHead) {
Victor Hsieh38c55032018-09-26 12:44:53 -0700220 auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer));
George Burgess IV20d7c962019-02-01 11:52:55 -0800221 fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii.getRaw());
Victor Hsieh38c55032018-09-26 12:44:53 -0700222
223 footer->desc_reverse_offset = offsetToDescriptorHead + sizeof(fsverity_footer);
224 memcpy(footer->magic, FS_VERITY_MAGIC, sizeof(footer->magic));
225
George Burgess IV20d7c962019-02-01 11:52:55 -0800226 return raii.release();
Victor Hsieh38c55032018-09-26 12:44:53 -0700227}
228
229const JNINativeMethod sMethods[] = {
Victor Hsiehaa6cb132018-11-08 11:16:21 -0800230 { "enableFsverityNative", "(Ljava/lang/String;)I", (void *)enableFsverity },
Victor Hsiehfcff8dd2018-12-14 15:59:03 -0800231 { "measureFsverityNative", "(Ljava/lang/String;)I", (void *)measureFsverity },
Victor Hsieheef29312018-10-29 16:25:34 -0700232 { "constructFsveritySignedDataNative", "([B)[B", (void *)constructFsveritySignedData },
Victor Hsieh38c55032018-09-26 12:44:53 -0700233 { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor },
234 { "constructFsverityExtensionNative", "(SI)[B", (void *)constructFsverityExtension },
235 { "constructFsverityFooterNative", "(I)[B", (void *)constructFsverityFooter },
236};
237
238} // namespace
239
240int register_android_server_security_VerityUtils(JNIEnv* env) {
241 return jniRegisterNativeMethods(env,
242 "com/android/server/security/VerityUtils", sMethods, NELEM(sMethods));
243}
244
245} // namespace android