1 /* 2 * Copyright (C) 2011 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 package libcore.io; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.system.ErrnoException; 21 import android.system.GaiException; 22 import android.system.Int64Ref; 23 import android.system.OsConstants; 24 import android.system.StructAddrinfo; 25 import android.system.StructLinger; 26 import android.system.StructPollfd; 27 import android.system.StructStat; 28 import android.system.StructStatVfs; 29 30 import java.io.FileDescriptor; 31 import java.io.InterruptedIOException; 32 import java.net.InetAddress; 33 import java.net.InetSocketAddress; 34 import java.net.SocketAddress; 35 import java.net.SocketException; 36 import java.nio.ByteBuffer; 37 38 import dalvik.system.BlockGuard; 39 import dalvik.system.SocketTagger; 40 41 import static android.system.OsConstants.*; 42 43 /** 44 * Informs BlockGuard of any activity it should be aware of. 45 */ 46 public class BlockGuardOs extends ForwardingOs { 47 @UnsupportedAppUsage BlockGuardOs(Os os)48 public BlockGuardOs(Os os) { 49 super(os); 50 } 51 tagSocket(FileDescriptor fd)52 private FileDescriptor tagSocket(FileDescriptor fd) throws ErrnoException { 53 try { 54 SocketTagger.get().tag(fd); 55 return fd; 56 } catch (SocketException e) { 57 throw new ErrnoException("socket", EINVAL, e); 58 } 59 } 60 accept(FileDescriptor fd, SocketAddress peerAddress)61 @Override public FileDescriptor accept(FileDescriptor fd, SocketAddress peerAddress) throws ErrnoException, SocketException { 62 BlockGuard.getThreadPolicy().onNetwork(); 63 final FileDescriptor acceptFd = super.accept(fd, peerAddress); 64 if (isInetSocket(acceptFd)) { 65 tagSocket(acceptFd); 66 } 67 return acceptFd; 68 } 69 access(String path, int mode)70 @Override public boolean access(String path, int mode) throws ErrnoException { 71 BlockGuard.getThreadPolicy().onReadFromDisk(); 72 BlockGuard.getVmPolicy().onPathAccess(path); 73 return super.access(path, mode); 74 } 75 76 @UnsupportedAppUsage chmod(String path, int mode)77 @Override public void chmod(String path, int mode) throws ErrnoException { 78 BlockGuard.getThreadPolicy().onWriteToDisk(); 79 BlockGuard.getVmPolicy().onPathAccess(path); 80 super.chmod(path, mode); 81 } 82 83 @UnsupportedAppUsage chown(String path, int uid, int gid)84 @Override public void chown(String path, int uid, int gid) throws ErrnoException { 85 BlockGuard.getThreadPolicy().onWriteToDisk(); 86 BlockGuard.getVmPolicy().onPathAccess(path); 87 super.chown(path, uid, gid); 88 } 89 90 @UnsupportedAppUsage close(FileDescriptor fd)91 @Override public void close(FileDescriptor fd) throws ErrnoException { 92 try { 93 // The usual case is that this _isn't_ a socket, so the getsockopt(2) call in 94 // isLingerSocket will throw, and that's really expensive. Try to avoid asking 95 // if we don't care. 96 if (fd.isSocket$()) { 97 if (isLingerSocket(fd)) { 98 // If the fd is a socket with SO_LINGER set, we might block indefinitely. 99 // We allow non-linger sockets so that apps can close their network 100 // connections in methods like onDestroy which will run on the UI thread. 101 BlockGuard.getThreadPolicy().onNetwork(); 102 } 103 } 104 } catch (ErrnoException ignored) { 105 // We're called via Socket.close (which doesn't ask for us to be called), so we 106 // must not throw here, because Socket.close must not throw if asked to close an 107 // already-closed socket. Also, the passed-in FileDescriptor isn't necessarily 108 // a socket at all. 109 } 110 super.close(fd); 111 } 112 isInetSocket(FileDescriptor fd)113 private static boolean isInetSocket(FileDescriptor fd) throws ErrnoException{ 114 return isInetDomain(Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_DOMAIN)); 115 } 116 isInetDomain(int domain)117 private static boolean isInetDomain(int domain) { 118 return (domain == AF_INET) || (domain == AF_INET6); 119 } 120 isLingerSocket(FileDescriptor fd)121 private static boolean isLingerSocket(FileDescriptor fd) throws ErrnoException { 122 StructLinger linger = Libcore.os.getsockoptLinger(fd, SOL_SOCKET, SO_LINGER); 123 return linger.isOn() && linger.l_linger > 0; 124 } 125 isUdpSocket(FileDescriptor fd)126 private static boolean isUdpSocket(FileDescriptor fd) throws ErrnoException { 127 return Libcore.os.getsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL) == IPPROTO_UDP; 128 } 129 connect(FileDescriptor fd, InetAddress address, int port)130 @Override public void connect(FileDescriptor fd, InetAddress address, int port) 131 throws ErrnoException, SocketException { 132 boolean skipGuard = false; 133 try { 134 skipGuard = isUdpSocket(fd); 135 } catch (ErrnoException ignored) { 136 } 137 if (!skipGuard) BlockGuard.getThreadPolicy().onNetwork(); 138 super.connect(fd, address, port); 139 } 140 connect(FileDescriptor fd, SocketAddress address)141 @Override public void connect(FileDescriptor fd, SocketAddress address) throws ErrnoException, 142 SocketException { 143 boolean skipGuard = false; 144 try { 145 skipGuard = isUdpSocket(fd); 146 } catch (ErrnoException ignored) { 147 } 148 if (!skipGuard) BlockGuard.getThreadPolicy().onNetwork(); 149 super.connect(fd, address); 150 } 151 152 @UnsupportedAppUsage fchmod(FileDescriptor fd, int mode)153 @Override public void fchmod(FileDescriptor fd, int mode) throws ErrnoException { 154 BlockGuard.getThreadPolicy().onWriteToDisk(); 155 super.fchmod(fd, mode); 156 } 157 158 @UnsupportedAppUsage fchown(FileDescriptor fd, int uid, int gid)159 @Override public void fchown(FileDescriptor fd, int uid, int gid) throws ErrnoException { 160 BlockGuard.getThreadPolicy().onWriteToDisk(); 161 super.fchown(fd, uid, gid); 162 } 163 164 // TODO: Untag newFd when needed for dup2(FileDescriptor oldFd, int newFd) 165 166 @UnsupportedAppUsage fdatasync(FileDescriptor fd)167 @Override public void fdatasync(FileDescriptor fd) throws ErrnoException { 168 BlockGuard.getThreadPolicy().onWriteToDisk(); 169 super.fdatasync(fd); 170 } 171 172 @UnsupportedAppUsage fstat(FileDescriptor fd)173 @Override public StructStat fstat(FileDescriptor fd) throws ErrnoException { 174 BlockGuard.getThreadPolicy().onReadFromDisk(); 175 return super.fstat(fd); 176 } 177 178 @UnsupportedAppUsage fstatvfs(FileDescriptor fd)179 @Override public StructStatVfs fstatvfs(FileDescriptor fd) throws ErrnoException { 180 BlockGuard.getThreadPolicy().onReadFromDisk(); 181 return super.fstatvfs(fd); 182 } 183 fsync(FileDescriptor fd)184 @Override public void fsync(FileDescriptor fd) throws ErrnoException { 185 BlockGuard.getThreadPolicy().onWriteToDisk(); 186 super.fsync(fd); 187 } 188 ftruncate(FileDescriptor fd, long length)189 @Override public void ftruncate(FileDescriptor fd, long length) throws ErrnoException { 190 BlockGuard.getThreadPolicy().onWriteToDisk(); 191 super.ftruncate(fd, length); 192 } 193 android_getaddrinfo(String node, StructAddrinfo hints, int netId)194 @Override public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException { 195 // With AI_NUMERICHOST flag set, the node must a numerical network address, therefore no 196 // host address lookups will be performed. In this case, it is fine to perform on main 197 // thread. 198 boolean isNumericHost = (hints.ai_flags & AI_NUMERICHOST) != 0; 199 if (!isNumericHost) { 200 BlockGuard.getThreadPolicy().onNetwork(); 201 } 202 return super.android_getaddrinfo(node, hints, netId); 203 } 204 205 @UnsupportedAppUsage lchown(String path, int uid, int gid)206 @Override public void lchown(String path, int uid, int gid) throws ErrnoException { 207 BlockGuard.getThreadPolicy().onWriteToDisk(); 208 BlockGuard.getVmPolicy().onPathAccess(path); 209 super.lchown(path, uid, gid); 210 } 211 212 @UnsupportedAppUsage link(String oldPath, String newPath)213 @Override public void link(String oldPath, String newPath) throws ErrnoException { 214 BlockGuard.getThreadPolicy().onWriteToDisk(); 215 BlockGuard.getVmPolicy().onPathAccess(oldPath); 216 BlockGuard.getVmPolicy().onPathAccess(newPath); 217 super.link(oldPath, newPath); 218 } 219 220 @UnsupportedAppUsage lseek(FileDescriptor fd, long offset, int whence)221 @Override public long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException { 222 BlockGuard.getThreadPolicy().onReadFromDisk(); 223 return super.lseek(fd, offset, whence); 224 } 225 226 @UnsupportedAppUsage lstat(String path)227 @Override public StructStat lstat(String path) throws ErrnoException { 228 BlockGuard.getThreadPolicy().onReadFromDisk(); 229 BlockGuard.getVmPolicy().onPathAccess(path); 230 return super.lstat(path); 231 } 232 233 @UnsupportedAppUsage mkdir(String path, int mode)234 @Override public void mkdir(String path, int mode) throws ErrnoException { 235 BlockGuard.getThreadPolicy().onWriteToDisk(); 236 BlockGuard.getVmPolicy().onPathAccess(path); 237 super.mkdir(path, mode); 238 } 239 240 @UnsupportedAppUsage mkfifo(String path, int mode)241 @Override public void mkfifo(String path, int mode) throws ErrnoException { 242 BlockGuard.getThreadPolicy().onWriteToDisk(); 243 BlockGuard.getVmPolicy().onPathAccess(path); 244 super.mkfifo(path, mode); 245 } 246 247 @UnsupportedAppUsage open(String path, int flags, int mode)248 @Override public FileDescriptor open(String path, int flags, int mode) throws ErrnoException { 249 BlockGuard.getThreadPolicy().onReadFromDisk(); 250 BlockGuard.getVmPolicy().onPathAccess(path); 251 if ((flags & O_ACCMODE) != O_RDONLY) { 252 BlockGuard.getThreadPolicy().onWriteToDisk(); 253 } 254 return super.open(path, flags, mode); 255 } 256 poll(StructPollfd[] fds, int timeoutMs)257 @Override public int poll(StructPollfd[] fds, int timeoutMs) throws ErrnoException { 258 // Greater than 0 is a timeout in milliseconds and -1 means "block forever", 259 // but 0 means "poll and return immediately", which shouldn't be subject to BlockGuard. 260 if (timeoutMs != 0) { 261 BlockGuard.getThreadPolicy().onNetwork(); 262 } 263 return super.poll(fds, timeoutMs); 264 } 265 266 @UnsupportedAppUsage posix_fallocate(FileDescriptor fd, long offset, long length)267 @Override public void posix_fallocate(FileDescriptor fd, long offset, long length) throws ErrnoException { 268 BlockGuard.getThreadPolicy().onWriteToDisk(); 269 super.posix_fallocate(fd, offset, length); 270 } 271 272 @UnsupportedAppUsage pread(FileDescriptor fd, ByteBuffer buffer, long offset)273 @Override public int pread(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException, InterruptedIOException { 274 BlockGuard.getThreadPolicy().onReadFromDisk(); 275 return super.pread(fd, buffer, offset); 276 } 277 278 @UnsupportedAppUsage pread(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset)279 @Override public int pread(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException { 280 BlockGuard.getThreadPolicy().onReadFromDisk(); 281 return super.pread(fd, bytes, byteOffset, byteCount, offset); 282 } 283 284 @UnsupportedAppUsage pwrite(FileDescriptor fd, ByteBuffer buffer, long offset)285 @Override public int pwrite(FileDescriptor fd, ByteBuffer buffer, long offset) throws ErrnoException, InterruptedIOException { 286 BlockGuard.getThreadPolicy().onWriteToDisk(); 287 return super.pwrite(fd, buffer, offset); 288 } 289 290 @UnsupportedAppUsage pwrite(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset)291 @Override public int pwrite(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, long offset) throws ErrnoException, InterruptedIOException { 292 BlockGuard.getThreadPolicy().onWriteToDisk(); 293 return super.pwrite(fd, bytes, byteOffset, byteCount, offset); 294 } 295 296 @UnsupportedAppUsage read(FileDescriptor fd, ByteBuffer buffer)297 @Override public int read(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException, InterruptedIOException { 298 BlockGuard.getThreadPolicy().onReadFromDisk(); 299 return super.read(fd, buffer); 300 } 301 302 @UnsupportedAppUsage read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount)303 @Override public int read(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException, InterruptedIOException { 304 BlockGuard.getThreadPolicy().onReadFromDisk(); 305 return super.read(fd, bytes, byteOffset, byteCount); 306 } 307 308 @UnsupportedAppUsage readlink(String path)309 @Override public String readlink(String path) throws ErrnoException { 310 BlockGuard.getThreadPolicy().onReadFromDisk(); 311 BlockGuard.getVmPolicy().onPathAccess(path); 312 return super.readlink(path); 313 } 314 315 @UnsupportedAppUsage realpath(String path)316 @Override public String realpath(String path) throws ErrnoException { 317 BlockGuard.getThreadPolicy().onReadFromDisk(); 318 BlockGuard.getVmPolicy().onPathAccess(path); 319 return super.realpath(path); 320 } 321 322 @UnsupportedAppUsage readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts)323 @Override public int readv(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException, InterruptedIOException { 324 BlockGuard.getThreadPolicy().onReadFromDisk(); 325 return super.readv(fd, buffers, offsets, byteCounts); 326 } 327 recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress)328 @Override public int recvfrom(FileDescriptor fd, ByteBuffer buffer, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { 329 BlockGuard.getThreadPolicy().onNetwork(); 330 return super.recvfrom(fd, buffer, flags, srcAddress); 331 } 332 recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress)333 @Override public int recvfrom(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetSocketAddress srcAddress) throws ErrnoException, SocketException { 334 BlockGuard.getThreadPolicy().onNetwork(); 335 return super.recvfrom(fd, bytes, byteOffset, byteCount, flags, srcAddress); 336 } 337 338 @UnsupportedAppUsage remove(String path)339 @Override public void remove(String path) throws ErrnoException { 340 BlockGuard.getThreadPolicy().onWriteToDisk(); 341 BlockGuard.getVmPolicy().onPathAccess(path); 342 super.remove(path); 343 } 344 345 @UnsupportedAppUsage rename(String oldPath, String newPath)346 @Override public void rename(String oldPath, String newPath) throws ErrnoException { 347 BlockGuard.getThreadPolicy().onWriteToDisk(); 348 BlockGuard.getVmPolicy().onPathAccess(oldPath); 349 BlockGuard.getVmPolicy().onPathAccess(newPath); 350 super.rename(oldPath, newPath); 351 } 352 sendfile(FileDescriptor outFd, FileDescriptor inFd, Int64Ref offset, long byteCount)353 @Override public long sendfile(FileDescriptor outFd, FileDescriptor inFd, Int64Ref offset, long byteCount) throws ErrnoException { 354 BlockGuard.getThreadPolicy().onWriteToDisk(); 355 return super.sendfile(outFd, inFd, offset, byteCount); 356 } 357 sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port)358 @Override public int sendto(FileDescriptor fd, ByteBuffer buffer, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { 359 BlockGuard.getThreadPolicy().onNetwork(); 360 return super.sendto(fd, buffer, flags, inetAddress, port); 361 } 362 sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port)363 @Override public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, InetAddress inetAddress, int port) throws ErrnoException, SocketException { 364 // We permit datagrams without hostname lookups. 365 if (inetAddress != null) { 366 BlockGuard.getThreadPolicy().onNetwork(); 367 } 368 return super.sendto(fd, bytes, byteOffset, byteCount, flags, inetAddress, port); 369 } 370 socket(int domain, int type, int protocol)371 @Override public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException { 372 final FileDescriptor fd = super.socket(domain, type, protocol); 373 if (isInetDomain(domain)) { 374 tagSocket(fd); 375 } 376 return fd; 377 } 378 socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2)379 @Override public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException { 380 super.socketpair(domain, type, protocol, fd1, fd2); 381 if (isInetDomain(domain)) { 382 tagSocket(fd1); 383 tagSocket(fd2); 384 } 385 } 386 387 @UnsupportedAppUsage stat(String path)388 @Override public StructStat stat(String path) throws ErrnoException { 389 BlockGuard.getThreadPolicy().onReadFromDisk(); 390 BlockGuard.getVmPolicy().onPathAccess(path); 391 return super.stat(path); 392 } 393 394 @UnsupportedAppUsage statvfs(String path)395 @Override public StructStatVfs statvfs(String path) throws ErrnoException { 396 BlockGuard.getThreadPolicy().onReadFromDisk(); 397 BlockGuard.getVmPolicy().onPathAccess(path); 398 return super.statvfs(path); 399 } 400 401 @UnsupportedAppUsage symlink(String oldPath, String newPath)402 @Override public void symlink(String oldPath, String newPath) throws ErrnoException { 403 BlockGuard.getThreadPolicy().onWriteToDisk(); 404 BlockGuard.getVmPolicy().onPathAccess(oldPath); 405 BlockGuard.getVmPolicy().onPathAccess(newPath); 406 super.symlink(oldPath, newPath); 407 } 408 409 @UnsupportedAppUsage write(FileDescriptor fd, ByteBuffer buffer)410 @Override public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException, InterruptedIOException { 411 BlockGuard.getThreadPolicy().onWriteToDisk(); 412 return super.write(fd, buffer); 413 } 414 415 @UnsupportedAppUsage write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount)416 @Override public int write(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount) throws ErrnoException, InterruptedIOException { 417 BlockGuard.getThreadPolicy().onWriteToDisk(); 418 return super.write(fd, bytes, byteOffset, byteCount); 419 } 420 421 @UnsupportedAppUsage writev(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts)422 @Override public int writev(FileDescriptor fd, Object[] buffers, int[] offsets, int[] byteCounts) throws ErrnoException, InterruptedIOException { 423 BlockGuard.getThreadPolicy().onWriteToDisk(); 424 return super.writev(fd, buffers, offsets, byteCounts); 425 } 426 execv(String filename, String[] argv)427 @Override public void execv(String filename, String[] argv) throws ErrnoException { 428 BlockGuard.getThreadPolicy().onReadFromDisk(); 429 BlockGuard.getVmPolicy().onPathAccess(filename); 430 super.execv(filename, argv); 431 } 432 execve(String filename, String[] argv, String[] envp)433 @Override public void execve(String filename, String[] argv, String[] envp) 434 throws ErrnoException { 435 BlockGuard.getThreadPolicy().onReadFromDisk(); 436 BlockGuard.getVmPolicy().onPathAccess(filename); 437 super.execve(filename, argv, envp); 438 } 439 getxattr(String path, String name)440 @Override public byte[] getxattr(String path, String name) throws ErrnoException { 441 BlockGuard.getThreadPolicy().onReadFromDisk(); 442 BlockGuard.getVmPolicy().onPathAccess(path); 443 return super.getxattr(path, name); 444 } 445 msync(long address, long byteCount, int flags)446 @Override public void msync(long address, long byteCount, int flags) throws ErrnoException { 447 if ((flags & OsConstants.MS_SYNC) != 0) { 448 BlockGuard.getThreadPolicy().onWriteToDisk(); 449 } 450 super.msync(address, byteCount, flags); 451 } 452 removexattr(String path, String name)453 @Override public void removexattr(String path, String name) throws ErrnoException { 454 BlockGuard.getThreadPolicy().onWriteToDisk(); 455 BlockGuard.getVmPolicy().onPathAccess(path); 456 super.removexattr(path, name); 457 } 458 setxattr(String path, String name, byte[] value, int flags)459 @Override public void setxattr(String path, String name, byte[] value, int flags) 460 throws ErrnoException { 461 BlockGuard.getThreadPolicy().onWriteToDisk(); 462 BlockGuard.getVmPolicy().onPathAccess(path); 463 super.setxattr(path, name, value, flags); 464 } 465 sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, int flags, SocketAddress address)466 @Override public int sendto(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, 467 int flags, SocketAddress address) throws ErrnoException, SocketException { 468 BlockGuard.getThreadPolicy().onNetwork(); 469 return super.sendto(fd, bytes, byteOffset, byteCount, flags, address); 470 } 471 unlink(String pathname)472 @Override public void unlink(String pathname) throws ErrnoException { 473 BlockGuard.getThreadPolicy().onWriteToDisk(); 474 BlockGuard.getVmPolicy().onPathAccess(pathname); 475 super.unlink(pathname); 476 } 477 splice(FileDescriptor fdIn, Int64Ref offIn, FileDescriptor fdOut, Int64Ref offOut, long len, int flags)478 @Override public long splice(FileDescriptor fdIn, Int64Ref offIn, FileDescriptor fdOut, Int64Ref offOut, long len, int flags) throws ErrnoException { 479 // It's infeasible to figure out if splice will result in read or write (would require fstat to figure out which fd is pipe). 480 // So, signal both read and write. 481 BlockGuard.getThreadPolicy().onWriteToDisk(); 482 BlockGuard.getThreadPolicy().onReadFromDisk(); 483 return super.splice(fdIn, offIn, fdOut, offOut, len, flags); 484 } 485 } 486