1 /*
2  * Copyright (C) 2021 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 TLOG_TAG "apploader-app-version"
18 
19 #include <apploader/package.h>
20 #include <assert.h>
21 #include <inttypes.h>
22 #include <lib/app_manifest/app_manifest.h>
23 #include <lib/storage/storage.h>
24 #include <lib/system_state/system_state.h>
25 #include <stdarg.h>
26 #include <trusty_log.h>
27 #include <uapi/err.h>
28 #include <algorithm>
29 #include <array>
30 
31 #include "app_manifest_parser.h"
32 
33 constexpr const char kStorageFilePrefix[] = "app_version.";
34 
35 /*
36  * Size of storage file name:
37  * length of the prefix + UUID (32 bytes) + null terminator
38  */
39 constexpr size_t kStorageFileNameSize =
40         (countof(kStorageFilePrefix) - 1) + 32 + 1;
41 using StorageFileName = std::array<char, kStorageFileNameSize>;
42 
get_storage_file_name(const uuid_t * app_uuid)43 static StorageFileName get_storage_file_name(const uuid_t* app_uuid) {
44     StorageFileName result;
45 
46     __UNUSED int written = snprintf(
47             result.data(), result.size(),
48             "%s%08" PRIx32 "%04" PRIx16 "%04" PRIx16 "%02" PRIx8 "%02" PRIx8
49             "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8
50             "%02" PRIx8,
51             kStorageFilePrefix, app_uuid->time_low, app_uuid->time_mid,
52             app_uuid->time_hi_and_version, app_uuid->clock_seq_and_node[0],
53             app_uuid->clock_seq_and_node[1], app_uuid->clock_seq_and_node[2],
54             app_uuid->clock_seq_and_node[3], app_uuid->clock_seq_and_node[4],
55             app_uuid->clock_seq_and_node[5], app_uuid->clock_seq_and_node[6],
56             app_uuid->clock_seq_and_node[7]);
57 
58     assert(static_cast<size_t>(written) == result.size() - 1);
59 
60     return result;
61 }
62 
63 /*
64  * Retrieves the version of an application from storage.
65  */
get_app_storage_version(const uuid_t * app_uuid,uint32_t * app_version)66 static int get_app_storage_version(const uuid_t* app_uuid,
67                                    uint32_t* app_version) {
68     assert(app_version);
69 
70     auto file_name = get_storage_file_name(app_uuid);
71 
72     int rc;
73     storage_session_t session;
74     rc = storage_open_session(&session, STORAGE_CLIENT_TP_PORT);
75     if (rc < 0) {
76         TLOGE("Error opening storage session (%d)\n", rc);
77         goto err_open_session;
78     }
79 
80     file_handle_t file;
81     rc = storage_open_file(session, &file, file_name.data(), 0, 0);
82     if (rc < 0) {
83         if (rc == ERR_NOT_FOUND) {
84             /* File does not exist, treat this case as version 0 */
85             *app_version = 0;
86             rc = 0;
87         } else {
88             TLOGE("Error opening storage file (%d)\n", rc);
89         }
90         goto err_open_file;
91     }
92 
93     uint32_t file_version;
94     rc = storage_read(file, 0, &file_version, sizeof(file_version));
95     if (rc != sizeof(file_version)) {
96         TLOGE("Error reading file (%d)\n", rc);
97         goto err_read_file;
98     }
99 
100     *app_version = file_version;
101     rc = NO_ERROR;
102 
103 err_read_file:
104     storage_close_file(file);
105 err_open_file:
106 err_get_file:
107     storage_close_session(session);
108 err_open_session:
109     return rc;
110 }
111 
update_app_version(const uuid_t * app_uuid,uint32_t new_version)112 static int update_app_version(const uuid_t* app_uuid, uint32_t new_version) {
113     int rc;
114     auto file_name = get_storage_file_name(app_uuid);
115     storage_session_t session;
116     rc = storage_open_session(&session, STORAGE_CLIENT_TP_PORT);
117     if (rc < 0) {
118         TLOGE("Error opening storage session (%d)\n", rc);
119         goto err_open_session;
120     }
121 
122     file_handle_t file;
123     rc = storage_open_file(session, &file, file_name.data(),
124                            STORAGE_FILE_OPEN_CREATE, 0);
125     if (rc < 0) {
126         TLOGE("Error opening storage file (%d)\n", rc);
127         goto err_open_file;
128     }
129 
130     rc = storage_write(file, 0, &new_version, sizeof(new_version),
131                        STORAGE_OP_COMPLETE);
132     if (rc != sizeof(new_version)) {
133         TLOGE("Error writing to file (%d)\n", rc);
134     }
135 
136     rc = NO_ERROR;
137 
138 err_write_file:
139     storage_close_file(file);
140 err_open_file:
141     storage_close_session(session);
142 err_open_session:
143     return rc;
144 }
145 
apploader_read_app_version(const uuid_t * uuid,uint32_t * version)146 extern "C" bool apploader_read_app_version(const uuid_t* uuid,
147                                            uint32_t* version) {
148     assert(uuid);
149     assert(version);
150 
151     int rc = get_app_storage_version(uuid, version);
152     if (rc < 0) {
153         TLOGE("Error retrieving application version from storage (%d)\n", rc);
154         return false;
155     }
156 
157     return true;
158 }
159 
apploader_write_app_version(const uuid_t * uuid,uint32_t version)160 extern "C" bool apploader_write_app_version(const uuid_t* uuid,
161                                             uint32_t version) {
162     assert(uuid);
163 
164     int rc = update_app_version(uuid, version);
165     if (rc < 0) {
166         TLOGE("Error updating application version in storage (%d)\n", rc);
167         return false;
168     }
169 
170     return true;
171 }
172