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 75 ObbFile::ObbFile() 76 : mPackageName("") 77 , mVersion(-1) 78 , mFlags(0) 79 { 80 memset(mSalt, 0, sizeof(mSalt)); 81 } 82 83 ObbFile::~ObbFile() { 84 } 85 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 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 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", 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 = new char[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%08llx)\n", 154 footerSize, 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", 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 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 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 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 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 ftruncate(fd, mFooterStart); 341 342 return true; 343 } 344 345 } 346