• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 <android-base/unique_fd.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <linux/fs.h>
23 #include <linux/fsverity.h>
24 #include <linux/stat.h>
25 #include <nativehelper/JNIHelp.h>
26 #include <nativehelper/ScopedUtfChars.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <utils/Log.h>
32 
33 #include <type_traits>
34 
35 #include "jni.h"
36 
37 namespace android {
38 
39 namespace {
40 
enableFsverityForFd(JNIEnv * env,jobject clazz,jint fd)41 int enableFsverityForFd(JNIEnv *env, jobject clazz, jint fd) {
42     if (fd < 0) {
43         return errno;
44     }
45 
46     fsverity_enable_arg arg = {};
47     arg.version = 1;
48     arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; // hardcoded in measureFsverity below
49     arg.block_size = 4096;
50     arg.salt_size = 0;
51     arg.salt_ptr = reinterpret_cast<uintptr_t>(nullptr);
52 
53     if (ioctl(fd, FS_IOC_ENABLE_VERITY, &arg) < 0) {
54         return errno;
55     }
56     return 0;
57 }
58 
enableFsverity(JNIEnv * env,jobject clazz,jstring filePath)59 int enableFsverity(JNIEnv *env, jobject clazz, jstring filePath) {
60     ScopedUtfChars path(env, filePath);
61     if (path.c_str() == nullptr) {
62         return EINVAL;
63     }
64     ::android::base::unique_fd rfd(open(path.c_str(), O_RDONLY | O_CLOEXEC));
65     return enableFsverityForFd(env, clazz, rfd.get());
66 }
67 
68 // Returns whether the file has fs-verity enabled.
69 // 0 if it is not present, 1 if is present, and -errno if there was an error.
statxForFsverity(JNIEnv * env,jobject,jstring filePath)70 int statxForFsverity(JNIEnv *env, jobject /* clazz */, jstring filePath) {
71     ScopedUtfChars path(env, filePath);
72 
73     // There are two ways to check whether a file has fs-verity enabled: statx() and FS_IOC_GETFLAGS
74     // (See https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#statx and
75     // https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#fs-ioc-getflags.)
76     // We try statx() first, since it doesn't require opening the file.
77 
78     struct statx out = {};
79     if (statx(AT_FDCWD, path.c_str(), 0 /* flags */, STATX_ALL, &out) != 0) {
80         return -errno;
81     }
82 
83     if (out.stx_attributes_mask & STATX_ATTR_VERITY) {
84         return (out.stx_attributes & STATX_ATTR_VERITY) != 0;
85     }
86 
87     // The filesystem doesn't support STATX_ATTR_VERITY.  This normally means that it doesn't
88     // support fs-verity, in which case we should simply return 0.  Unfortunately, virtio-fs is an
89     // exception, since it doesn't support STATX_ATTR_VERITY but does support querying FS_VERITY_FL
90     // via FS_IOC_GETFLAGS.  So we have to fall back to FS_IOC_GETFLAGS.  Note: despite being an
91     // ioctl, FS_IOC_GETFLAGS doesn't require the "ioctl" SELinux permission but rather "getattr".
92 
93     ::android::base::unique_fd rfd(open(path.c_str(), O_RDONLY | O_CLOEXEC));
94     if (rfd.get() < 0) {
95         ALOGE("open failed at %s", path.c_str());
96         return -errno;
97     }
98 
99     unsigned int flags;
100     if (ioctl(rfd.get(), FS_IOC_GETFLAGS, &flags) < 0) {
101         if (errno == ENOTTY) {
102             // If the filesystem supports neither STATX_ATTR_VERITY nor FS_IOC_GETFLAGS, then assume
103             // that it doesn't support fs-verity.
104             return 0;
105         }
106         ALOGE("ioctl(FS_IOC_GETFLAGS) failed at %s", path.c_str());
107         return -errno;
108     }
109 
110     return (flags & FS_VERITY_FL) != 0;
111 }
112 
measureFsverity(JNIEnv * env,jobject,jstring filePath,jbyteArray digest)113 int measureFsverity(JNIEnv *env, jobject /* clazz */, jstring filePath, jbyteArray digest) {
114     static constexpr auto kDigestSha256 = 32;
115     using Storage = std::aligned_storage_t<sizeof(fsverity_digest) + kDigestSha256>;
116 
117     Storage bytes;
118     fsverity_digest *data = reinterpret_cast<fsverity_digest *>(&bytes);
119     data->digest_size = kDigestSha256; // the only input/output parameter
120 
121     ScopedUtfChars path(env, filePath);
122     ::android::base::unique_fd rfd(open(path.c_str(), O_RDONLY | O_CLOEXEC));
123     if (rfd.get() < 0) {
124         return -errno;
125     }
126     if (::ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data) < 0) {
127         return -errno;
128     }
129 
130     if (data->digest_algorithm != FS_VERITY_HASH_ALG_SHA256) {
131         return -EINVAL;
132     }
133 
134     if (digest != nullptr && data->digest_size > 0) {
135         auto digestSize = env->GetArrayLength(digest);
136         if (data->digest_size > digestSize) {
137             return -E2BIG;
138         }
139         env->SetByteArrayRegion(digest, 0, data->digest_size, (const jbyte *)data->digest);
140     }
141 
142     return 0;
143 }
144 const JNINativeMethod sMethods[] = {
145         {"enableFsverityNative", "(Ljava/lang/String;)I", (void *)enableFsverity},
146         {"enableFsverityForFdNative", "(I)I", (void *)enableFsverityForFd},
147         {"statxForFsverityNative", "(Ljava/lang/String;)I", (void *)statxForFsverity},
148         {"measureFsverityNative", "(Ljava/lang/String;[B)I", (void *)measureFsverity},
149 };
150 
151 } // namespace
152 
register_com_android_internal_security_VerityUtils(JNIEnv * env)153 int register_com_android_internal_security_VerityUtils(JNIEnv *env) {
154     return jniRegisterNativeMethods(env, "com/android/internal/security/VerityUtils", sMethods,
155                                     NELEM(sMethods));
156 }
157 
158 } // namespace android
159