1 /*
2  * Copyright (C) 2010 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 #include <errno.h>
18 #include <fcntl.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 
24 #define LOG_TAG "ObbFile"
25 
26 #include <androidfw/ObbFile.h>
27 #include <utils/Compat.h>
28 #include <utils/Log.h>
29 
30 //#define DEBUG 1
31 
32 #define kFooterTagSize 8  /* last two 32-bit integers */
33 
34 #define kFooterMinSize 33 /* 32-bit signature version (4 bytes)
35                            * 32-bit package version (4 bytes)
36                            * 32-bit flags (4 bytes)
37                            * 64-bit salt (8 bytes)
38                            * 32-bit package name size (4 bytes)
39                            * >=1-character package name (1 byte)
40                            * 32-bit footer size (4 bytes)
41                            * 32-bit footer marker (4 bytes)
42                            */
43 
44 #define kMaxBufSize    32768 /* Maximum file read buffer */
45 
46 #define kSignature     0x01059983U /* ObbFile signature */
47 
48 #define kSigVersion    1 /* We only know about signature version 1 */
49 
50 /* offsets in version 1 of the header */
51 #define kPackageVersionOffset 4
52 #define kFlagsOffset          8
53 #define kSaltOffset           12
54 #define kPackageNameLenOffset 20
55 #define kPackageNameOffset    24
56 
57 /*
58  * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
59  * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
60  * not already defined, then define it here.
61  */
62 #ifndef TEMP_FAILURE_RETRY
63 /* Used to retry syscalls that can return EINTR. */
64 #define TEMP_FAILURE_RETRY(exp) ({         \
65     typeof (exp) _rc;                      \
66     do {                                   \
67         _rc = (exp);                       \
68     } while (_rc == -1 && errno == EINTR); \
69     _rc; })
70 #endif
71 
72 
73 namespace android {
74 
ObbFile()75 ObbFile::ObbFile()
76         : mPackageName("")
77         , mVersion(-1)
78         , mFlags(0)
79 {
80     memset(mSalt, 0, sizeof(mSalt));
81 }
82 
~ObbFile()83 ObbFile::~ObbFile() {
84 }
85 
readFrom(const char * filename)86 bool ObbFile::readFrom(const char* filename)
87 {
88     int fd;
89     bool success = false;
90 
91     fd = ::open(filename, O_RDONLY);
92     if (fd < 0) {
93         ALOGW("couldn't open file %s: %s", filename, strerror(errno));
94         goto out;
95     }
96     success = readFrom(fd);
97     close(fd);
98 
99     if (!success) {
100         ALOGW("failed to read from %s (fd=%d)\n", filename, fd);
101     }
102 
103 out:
104     return success;
105 }
106 
readFrom(int fd)107 bool ObbFile::readFrom(int fd)
108 {
109     if (fd < 0) {
110         ALOGW("attempt to read from invalid fd\n");
111         return false;
112     }
113 
114     return parseObbFile(fd);
115 }
116 
parseObbFile(int fd)117 bool ObbFile::parseObbFile(int fd)
118 {
119     off64_t fileLength = lseek64(fd, 0, SEEK_END);
120 
121     if (fileLength < kFooterMinSize) {
122         if (fileLength < 0) {
123             ALOGW("error seeking in ObbFile: %s\n", strerror(errno));
124         } else {
125             ALOGW("file is only %lld (less than %d minimum)\n", (long long int)fileLength, kFooterMinSize);
126         }
127         return false;
128     }
129 
130     ssize_t actual;
131     size_t footerSize;
132 
133     {
134         lseek64(fd, fileLength - kFooterTagSize, SEEK_SET);
135 
136         char footer[kFooterTagSize];
137         actual = TEMP_FAILURE_RETRY(read(fd, footer, kFooterTagSize));
138         if (actual != kFooterTagSize) {
139             ALOGW("couldn't read footer signature: %s\n", strerror(errno));
140             return false;
141         }
142 
143         unsigned int fileSig = get4LE((unsigned char*)footer + sizeof(int32_t));
144         if (fileSig != kSignature) {
145             ALOGW("footer didn't match magic string (expected 0x%08x; got 0x%08x)\n",
146                     kSignature, fileSig);
147             return false;
148         }
149 
150         footerSize = get4LE((unsigned char*)footer);
151         if (footerSize > (size_t)fileLength - kFooterTagSize
152                 || footerSize > kMaxBufSize) {
153             ALOGW("claimed footer size is too large (0x%08zx; file size is 0x%08lld)\n",
154                     footerSize, (long long int)fileLength);
155             return false;
156         }
157 
158         if (footerSize < (kFooterMinSize - kFooterTagSize)) {
159             ALOGW("claimed footer size is too small (0x%zx; minimum size is 0x%x)\n",
160                     footerSize, kFooterMinSize - kFooterTagSize);
161             return false;
162         }
163     }
164 
165     off64_t fileOffset = fileLength - footerSize - kFooterTagSize;
166     if (lseek64(fd, fileOffset, SEEK_SET) != fileOffset) {
167         ALOGW("seek %lld failed: %s\n", (long long int)fileOffset, strerror(errno));
168         return false;
169     }
170 
171     mFooterStart = fileOffset;
172 
173     char* scanBuf = (char*)malloc(footerSize);
174     if (scanBuf == NULL) {
175         ALOGW("couldn't allocate scanBuf: %s\n", strerror(errno));
176         return false;
177     }
178 
179     actual = TEMP_FAILURE_RETRY(read(fd, scanBuf, footerSize));
180     // readAmount is guaranteed to be less than kMaxBufSize
181     if (actual != (ssize_t)footerSize) {
182         ALOGI("couldn't read ObbFile footer: %s\n", strerror(errno));
183         free(scanBuf);
184         return false;
185     }
186 
187 #ifdef DEBUG
188     for (int i = 0; i < footerSize; ++i) {
189         ALOGI("char: 0x%02x\n", scanBuf[i]);
190     }
191 #endif
192 
193     uint32_t sigVersion = get4LE((unsigned char*)scanBuf);
194     if (sigVersion != kSigVersion) {
195         ALOGW("Unsupported ObbFile version %d\n", sigVersion);
196         free(scanBuf);
197         return false;
198     }
199 
200     mVersion = (int32_t) get4LE((unsigned char*)scanBuf + kPackageVersionOffset);
201     mFlags = (int32_t) get4LE((unsigned char*)scanBuf + kFlagsOffset);
202 
203     memcpy(&mSalt, (unsigned char*)scanBuf + kSaltOffset, sizeof(mSalt));
204 
205     size_t packageNameLen = get4LE((unsigned char*)scanBuf + kPackageNameLenOffset);
206     if (packageNameLen == 0
207             || packageNameLen > (footerSize - kPackageNameOffset)) {
208         ALOGW("bad ObbFile package name length (0x%04zx; 0x%04zx possible)\n",
209                 packageNameLen, footerSize - kPackageNameOffset);
210         free(scanBuf);
211         return false;
212     }
213 
214     char* packageName = reinterpret_cast<char*>(scanBuf + kPackageNameOffset);
215     mPackageName = String8(const_cast<char*>(packageName), packageNameLen);
216 
217     free(scanBuf);
218 
219 #ifdef DEBUG
220     ALOGI("Obb scan succeeded: packageName=%s, version=%d\n", mPackageName.string(), mVersion);
221 #endif
222 
223     return true;
224 }
225 
writeTo(const char * filename)226 bool ObbFile::writeTo(const char* filename)
227 {
228     int fd;
229     bool success = false;
230 
231     fd = ::open(filename, O_WRONLY);
232     if (fd < 0) {
233         goto out;
234     }
235     success = writeTo(fd);
236     close(fd);
237 
238 out:
239     if (!success) {
240         ALOGW("failed to write to %s: %s\n", filename, strerror(errno));
241     }
242     return success;
243 }
244 
writeTo(int fd)245 bool ObbFile::writeTo(int fd)
246 {
247     if (fd < 0) {
248         return false;
249     }
250 
251     lseek64(fd, 0, SEEK_END);
252 
253     if (mPackageName.size() == 0 || mVersion == -1) {
254         ALOGW("tried to write uninitialized ObbFile data\n");
255         return false;
256     }
257 
258     unsigned char intBuf[sizeof(uint32_t)+1];
259     memset(&intBuf, 0, sizeof(intBuf));
260 
261     put4LE(intBuf, kSigVersion);
262     if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
263         ALOGW("couldn't write signature version: %s\n", strerror(errno));
264         return false;
265     }
266 
267     put4LE(intBuf, mVersion);
268     if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
269         ALOGW("couldn't write package version\n");
270         return false;
271     }
272 
273     put4LE(intBuf, mFlags);
274     if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
275         ALOGW("couldn't write package version\n");
276         return false;
277     }
278 
279     if (write(fd, mSalt, sizeof(mSalt)) != (ssize_t)sizeof(mSalt)) {
280         ALOGW("couldn't write salt: %s\n", strerror(errno));
281         return false;
282     }
283 
284     size_t packageNameLen = mPackageName.size();
285     put4LE(intBuf, packageNameLen);
286     if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
287         ALOGW("couldn't write package name length: %s\n", strerror(errno));
288         return false;
289     }
290 
291     if (write(fd, mPackageName.string(), packageNameLen) != (ssize_t)packageNameLen) {
292         ALOGW("couldn't write package name: %s\n", strerror(errno));
293         return false;
294     }
295 
296     put4LE(intBuf, kPackageNameOffset + packageNameLen);
297     if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
298         ALOGW("couldn't write footer size: %s\n", strerror(errno));
299         return false;
300     }
301 
302     put4LE(intBuf, kSignature);
303     if (write(fd, &intBuf, sizeof(uint32_t)) != (ssize_t)sizeof(uint32_t)) {
304         ALOGW("couldn't write footer magic signature: %s\n", strerror(errno));
305         return false;
306     }
307 
308     return true;
309 }
310 
removeFrom(const char * filename)311 bool ObbFile::removeFrom(const char* filename)
312 {
313     int fd;
314     bool success = false;
315 
316     fd = ::open(filename, O_RDWR);
317     if (fd < 0) {
318         goto out;
319     }
320     success = removeFrom(fd);
321     close(fd);
322 
323 out:
324     if (!success) {
325         ALOGW("failed to remove signature from %s: %s\n", filename, strerror(errno));
326     }
327     return success;
328 }
329 
removeFrom(int fd)330 bool ObbFile::removeFrom(int fd)
331 {
332     if (fd < 0) {
333         return false;
334     }
335 
336     if (!readFrom(fd)) {
337         return false;
338     }
339 
340     if (ftruncate(fd, mFooterStart) == -1) {
341         return false;
342     }
343 
344     return true;
345 }
346 
347 }
348