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