blob: 988d75cfb98413d86372e49e358aca9aa021cfbf [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
30#include <android-base/unique_fd.h>
Victor Hsieh38c55032018-09-26 12:44:53 -070031
Victor Hsieh142c0172019-01-25 12:40:46 -080032// TODO(112037636): Always include once fsverity.h is upstreamed.
33#if __has_include(<linux/fsverity.h>)
Victor Hsieh38c55032018-09-26 12:44:53 -070034#include <linux/fsverity.h>
Victor Hsieh16890292019-01-29 11:44:39 -080035#else
36
37// Before fs-verity is upstreamed, use the current snapshot for development.
38// https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/tree/include/uapi/linux/fsverity.h?h=fsverity
39
40#include <linux/limits.h>
41#include <linux/ioctl.h>
42#include <linux/types.h>
43
44struct fsverity_digest {
45 __u16 digest_algorithm;
46 __u16 digest_size; /* input/output */
47 __u8 digest[];
48};
49
50#define FS_IOC_ENABLE_VERITY _IO('f', 133)
51#define FS_IOC_MEASURE_VERITY _IOWR('f', 134, struct fsverity_digest)
52
53#define FS_VERITY_MAGIC "FSVerity"
54
55#define FS_VERITY_ALG_SHA256 1
56
57struct fsverity_descriptor {
58 __u8 magic[8]; /* must be FS_VERITY_MAGIC */
59 __u8 major_version; /* must be 1 */
60 __u8 minor_version; /* must be 0 */
61 __u8 log_data_blocksize;/* log2(data-bytes-per-hash), e.g. 12 for 4KB */
62 __u8 log_tree_blocksize;/* log2(tree-bytes-per-hash), e.g. 12 for 4KB */
63 __le16 data_algorithm; /* hash algorithm for data blocks */
64 __le16 tree_algorithm; /* hash algorithm for tree blocks */
65 __le32 flags; /* flags */
66 __le32 __reserved1; /* must be 0 */
67 __le64 orig_file_size; /* size of the original file data */
68 __le16 auth_ext_count; /* number of authenticated extensions */
69 __u8 __reserved2[30]; /* must be 0 */
70};
71
72#define FS_VERITY_EXT_ROOT_HASH 1
73#define FS_VERITY_EXT_PKCS7_SIGNATURE 3
74
75struct fsverity_extension {
76 __le32 length;
77 __le16 type; /* Type of this extension (see codes above) */
78 __le16 __reserved; /* Reserved, must be 0 */
79};
80
81struct fsverity_digest_disk {
82 __le16 digest_algorithm;
83 __le16 digest_size;
84 __u8 digest[];
85};
86
87struct fsverity_footer {
88 __le32 desc_reverse_offset; /* distance to fsverity_descriptor */
89 __u8 magic[8]; /* FS_VERITY_MAGIC */
90} __packed;
91
Victor Hsieh38c55032018-09-26 12:44:53 -070092#endif
93
Victor Hsieh16890292019-01-29 11:44:39 -080094const int kSha256Bytes = 32;
95
Victor Hsieh38c55032018-09-26 12:44:53 -070096namespace android {
97
98namespace {
99
100class JavaByteArrayHolder {
101 public:
102 static JavaByteArrayHolder* newArray(JNIEnv* env, jsize size) {
103 return new JavaByteArrayHolder(env, size);
104 }
105
106 jbyte* getRaw() {
107 return mElements;
108 }
109
110 jbyteArray release() {
111 mEnv->ReleaseByteArrayElements(mBytes, mElements, 0);
112 mElements = nullptr;
113 return mBytes;
114 }
115
116 private:
117 JavaByteArrayHolder(JNIEnv* env, jsize size) {
118 mEnv = env;
119 mBytes = mEnv->NewByteArray(size);
120 mElements = mEnv->GetByteArrayElements(mBytes, nullptr);
121 memset(mElements, 0, size);
122 }
123
124 virtual ~JavaByteArrayHolder() {
125 LOG_ALWAYS_FATAL_IF(mElements == nullptr, "Elements are not released");
126 }
127
128 JNIEnv* mEnv;
129 jbyteArray mBytes;
130 jbyte* mElements;
131};
132
Victor Hsiehaa6cb132018-11-08 11:16:21 -0800133int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
Victor Hsiehaa6cb132018-11-08 11:16:21 -0800134 const char* path = env->GetStringUTFChars(filePath, nullptr);
135 ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
136 if (rfd.get() < 0) {
137 return errno;
138 }
139 if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) {
140 return errno;
141 }
142 return 0;
Victor Hsiehaa6cb132018-11-08 11:16:21 -0800143}
144
Victor Hsiehfcff8dd2018-12-14 15:59:03 -0800145int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
Victor Hsiehfcff8dd2018-12-14 15:59:03 -0800146 auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest) + kSha256Bytes);
147 fsverity_digest* data = reinterpret_cast<fsverity_digest*>(raii->getRaw());
148 data->digest_size = kSha256Bytes; // the only input/output parameter
149
150 const char* path = env->GetStringUTFChars(filePath, nullptr);
Victor Hsiehaa6cb132018-11-08 11:16:21 -0800151 ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC));
152 if (rfd.get() < 0) {
153 return errno;
154 }
Victor Hsiehfcff8dd2018-12-14 15:59:03 -0800155 if (ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data) < 0) {
156 return errno;
157 }
158 return 0;
Victor Hsiehfcff8dd2018-12-14 15:59:03 -0800159}
160
Victor Hsieheef29312018-10-29 16:25:34 -0700161jbyteArray constructFsveritySignedData(JNIEnv* env, jobject /* clazz */, jbyteArray digest) {
Victor Hsieheef29312018-10-29 16:25:34 -0700162 auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest_disk) + kSha256Bytes);
163 fsverity_digest_disk* data = reinterpret_cast<fsverity_digest_disk*>(raii->getRaw());
164
165 data->digest_algorithm = FS_VERITY_ALG_SHA256;
166 data->digest_size = kSha256Bytes;
167 if (env->GetArrayLength(digest) != kSha256Bytes) {
168 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid hash size of %d",
169 env->GetArrayLength(digest));
170 return 0;
171 }
172 const jbyte* src = env->GetByteArrayElements(digest, nullptr);
173 memcpy(data->digest, src, kSha256Bytes);
174
175 return raii->release();
Victor Hsieheef29312018-10-29 16:25:34 -0700176}
177
178
Victor Hsieh38c55032018-09-26 12:44:53 -0700179jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) {
Victor Hsieh38c55032018-09-26 12:44:53 -0700180 auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor));
181 fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii->getRaw());
182
183 memcpy(desc->magic, FS_VERITY_MAGIC, sizeof(desc->magic));
184 desc->major_version = 1;
185 desc->minor_version = 0;
186 desc->log_data_blocksize = 12;
187 desc->log_tree_blocksize = 12;
188 desc->data_algorithm = FS_VERITY_ALG_SHA256;
189 desc->tree_algorithm = FS_VERITY_ALG_SHA256;
190 desc->flags = 0;
191 desc->orig_file_size = fileSize;
192 desc->auth_ext_count = 1;
193
194 return raii->release();
Victor Hsieh38c55032018-09-26 12:44:53 -0700195}
196
197jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId,
198 jint extensionDataSize) {
Victor Hsieh38c55032018-09-26 12:44:53 -0700199 auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension));
200 fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii->getRaw());
201
202 ext->length = sizeof(fsverity_extension) + extensionDataSize;
203 ext->type = extensionId;
204
205 return raii->release();
Victor Hsieh38c55032018-09-26 12:44:53 -0700206}
207
208jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */,
209 jint offsetToDescriptorHead) {
Victor Hsieh38c55032018-09-26 12:44:53 -0700210 auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer));
211 fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii->getRaw());
212
213 footer->desc_reverse_offset = offsetToDescriptorHead + sizeof(fsverity_footer);
214 memcpy(footer->magic, FS_VERITY_MAGIC, sizeof(footer->magic));
215
216 return raii->release();
Victor Hsieh38c55032018-09-26 12:44:53 -0700217}
218
219const JNINativeMethod sMethods[] = {
Victor Hsiehaa6cb132018-11-08 11:16:21 -0800220 { "enableFsverityNative", "(Ljava/lang/String;)I", (void *)enableFsverity },
Victor Hsiehfcff8dd2018-12-14 15:59:03 -0800221 { "measureFsverityNative", "(Ljava/lang/String;)I", (void *)measureFsverity },
Victor Hsieheef29312018-10-29 16:25:34 -0700222 { "constructFsveritySignedDataNative", "([B)[B", (void *)constructFsveritySignedData },
Victor Hsieh38c55032018-09-26 12:44:53 -0700223 { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor },
224 { "constructFsverityExtensionNative", "(SI)[B", (void *)constructFsverityExtension },
225 { "constructFsverityFooterNative", "(I)[B", (void *)constructFsverityFooter },
226};
227
228} // namespace
229
230int register_android_server_security_VerityUtils(JNIEnv* env) {
231 return jniRegisterNativeMethods(env,
232 "com/android/server/security/VerityUtils", sMethods, NELEM(sMethods));
233}
234
235} // namespace android