Loading core/java/android/companion/AssociationRequest.java +1 −1 Original line number Diff line number Diff line Loading @@ -148,7 +148,7 @@ public final class AssociationRequest implements Parcelable { /** @hide */ public void setSkipPrompt(boolean value) { mSkipPrompt = true; mSkipPrompt = value; } /** @hide */ Loading core/java/com/android/internal/os/ZygoteConnection.java +3 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,9 @@ class ZygoteConnection { throw ex; } if (peer.getUid() != Process.SYSTEM_UID) { throw new ZygoteSecurityException("Only system UID is allowed to connect to Zygote."); } isEof = false; } Loading core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp +53 −28 Original line number Diff line number Diff line Loading @@ -341,6 +341,18 @@ jstring com_android_internal_os_ZygoteCommandBuffer_nativeNextArg(JNIEnv* env, j return result; } static uid_t getSocketPeerUid(int socket, const std::function<void(const std::string&)>& fail_fn) { struct ucred credentials; socklen_t cred_size = sizeof credentials; if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1 || cred_size != sizeof credentials) { fail_fn(CREATE_ERROR("Failed to get socket credentials, %s", strerror(errno))); } return credentials.uid; } // Read all lines from the current command into the buffer, and then reset the buffer, so // we will start reading again at the beginning of the command, starting with the argument // count. And we don't need access to the fd to do so. Loading Loading @@ -398,18 +410,12 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly( fail_fn_z("Failed to retrieve session socket timeout"); } struct ucred credentials; socklen_t cred_size = sizeof credentials; if (getsockopt(n_buffer->getFd(), SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1 || cred_size != sizeof credentials) { fail_fn_1(CREATE_ERROR("ForkMany failed to get initial credentials, %s", strerror(errno))); uid_t peerUid = getSocketPeerUid(session_socket, fail_fn_1); if (peerUid != static_cast<uid_t>(expected_uid)) { return JNI_FALSE; } bool first_time = true; do { if (credentials.uid != expected_uid) { return JNI_FALSE; } n_buffer->readAllLines(first_time ? fail_fn_1 : fail_fn_n); n_buffer->reset(); int pid = zygote::forkApp(env, /* no pipe FDs */ -1, -1, session_socket_fds, Loading Loading @@ -439,22 +445,48 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly( // Clear buffer and get count from next command. n_buffer->clear(); for (;;) { bool valid_session_socket = true; // Poll isn't strictly necessary for now. But without it, disconnect is hard to detect. int poll_res = TEMP_FAILURE_RETRY(poll(fd_structs, 2, -1 /* infinite timeout */)); if ((fd_structs[SESSION_IDX].revents & POLLIN) != 0) { if (n_buffer->getCount(fail_fn_z) != 0) { break; } // else disconnected; } else { // Session socket was disconnected valid_session_socket = false; close(session_socket); } } else if (poll_res == 0 || (fd_structs[ZYGOTE_IDX].revents & POLLIN) == 0) { fail_fn_z( CREATE_ERROR("Poll returned with no descriptors ready! Poll returned %d", poll_res)); } int new_fd = -1; do { // We've now seen either a disconnect or connect request. close(session_socket); int new_fd = TEMP_FAILURE_RETRY(accept(zygote_socket_fd, nullptr, nullptr)); new_fd = TEMP_FAILURE_RETRY(accept(zygote_socket_fd, nullptr, nullptr)); if (new_fd == -1) { fail_fn_z(CREATE_ERROR("Accept(%d) failed: %s", zygote_socket_fd, strerror(errno))); } uid_t newPeerUid = getSocketPeerUid(new_fd, fail_fn_1); if (newPeerUid != static_cast<uid_t>(expected_uid)) { ALOGW("Dropping new connection with a mismatched uid %d\n", newPeerUid); close(new_fd); new_fd = -1; } else { // If we still have a valid session socket, close it now if (valid_session_socket) { close(session_socket); } valid_session_socket = true; } } while (!valid_session_socket); // At this point we either have a valid new connection (new_fd > 0), or // an existing session socket we can poll on if (new_fd == -1) { // The new connection wasn't valid, and we still have an old one; retry polling continue; } if (new_fd != session_socket) { // Move new_fd back to the old value, so that we don't have to change Java-level data // structures to reflect a change. This implicitly closes the old one. Loading @@ -474,13 +506,6 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly( fail_fn_z(CREATE_ERROR("Failed to set send timeout for socket %d: %s", session_socket, strerror(errno))); } if (getsockopt(session_socket, SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1) { fail_fn_z(CREATE_ERROR("ForkMany failed to get credentials: %s", strerror(errno))); } if (cred_size != sizeof credentials) { fail_fn_z(CREATE_ERROR("ForkMany credential size = %d, should be %d", cred_size, static_cast<int>(sizeof credentials))); } } first_time = false; } while (n_buffer->isSimpleForkCommand(minUid, fail_fn_n)); Loading media/java/android/media/session/ParcelableListBinder.java +11 −2 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ public class ParcelableListBinder<T extends Parcelable> extends Binder { private static final int END_OF_PARCEL = 0; private static final int ITEM_CONTINUED = 1; private final Class<T> mListElementsClass; private final Consumer<List<T>> mConsumer; private final Object mLock = new Object(); Loading @@ -61,9 +62,11 @@ public class ParcelableListBinder<T extends Parcelable> extends Binder { /** * Creates an instance. * * @param listElementsClass the class of the list elements. * @param consumer a consumer that consumes the list received */ public ParcelableListBinder(@NonNull Consumer<List<T>> consumer) { public ParcelableListBinder(Class<T> listElementsClass, @NonNull Consumer<List<T>> consumer) { mListElementsClass = listElementsClass; mConsumer = consumer; } Loading @@ -83,7 +86,13 @@ public class ParcelableListBinder<T extends Parcelable> extends Binder { mCount = data.readInt(); } while (i < mCount && data.readInt() != END_OF_PARCEL) { mList.add(data.readParcelable(null)); Object object = data.readParcelable(null); if (mListElementsClass.isAssignableFrom(object.getClass())) { // Checking list items are of compaitible types to validate against malicious // apps calling it directly via reflection with non compilable items. // See b/317048338 for more details mList.add((T) object); } i++; } if (i >= mCount) { Loading services/core/java/com/android/server/media/MediaSessionRecord.java +8 −6 Original line number Diff line number Diff line Loading @@ -1095,7 +1095,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR @Override public IBinder getBinderForSetQueue() throws RemoteException { return new ParcelableListBinder<QueueItem>((list) -> { return new ParcelableListBinder<QueueItem>( QueueItem.class, (list) -> { synchronized (mLock) { mQueue = list; } Loading Loading
core/java/android/companion/AssociationRequest.java +1 −1 Original line number Diff line number Diff line Loading @@ -148,7 +148,7 @@ public final class AssociationRequest implements Parcelable { /** @hide */ public void setSkipPrompt(boolean value) { mSkipPrompt = true; mSkipPrompt = value; } /** @hide */ Loading
core/java/com/android/internal/os/ZygoteConnection.java +3 −0 Original line number Diff line number Diff line Loading @@ -93,6 +93,9 @@ class ZygoteConnection { throw ex; } if (peer.getUid() != Process.SYSTEM_UID) { throw new ZygoteSecurityException("Only system UID is allowed to connect to Zygote."); } isEof = false; } Loading
core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp +53 −28 Original line number Diff line number Diff line Loading @@ -341,6 +341,18 @@ jstring com_android_internal_os_ZygoteCommandBuffer_nativeNextArg(JNIEnv* env, j return result; } static uid_t getSocketPeerUid(int socket, const std::function<void(const std::string&)>& fail_fn) { struct ucred credentials; socklen_t cred_size = sizeof credentials; if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1 || cred_size != sizeof credentials) { fail_fn(CREATE_ERROR("Failed to get socket credentials, %s", strerror(errno))); } return credentials.uid; } // Read all lines from the current command into the buffer, and then reset the buffer, so // we will start reading again at the beginning of the command, starting with the argument // count. And we don't need access to the fd to do so. Loading Loading @@ -398,18 +410,12 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly( fail_fn_z("Failed to retrieve session socket timeout"); } struct ucred credentials; socklen_t cred_size = sizeof credentials; if (getsockopt(n_buffer->getFd(), SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1 || cred_size != sizeof credentials) { fail_fn_1(CREATE_ERROR("ForkMany failed to get initial credentials, %s", strerror(errno))); uid_t peerUid = getSocketPeerUid(session_socket, fail_fn_1); if (peerUid != static_cast<uid_t>(expected_uid)) { return JNI_FALSE; } bool first_time = true; do { if (credentials.uid != expected_uid) { return JNI_FALSE; } n_buffer->readAllLines(first_time ? fail_fn_1 : fail_fn_n); n_buffer->reset(); int pid = zygote::forkApp(env, /* no pipe FDs */ -1, -1, session_socket_fds, Loading Loading @@ -439,22 +445,48 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly( // Clear buffer and get count from next command. n_buffer->clear(); for (;;) { bool valid_session_socket = true; // Poll isn't strictly necessary for now. But without it, disconnect is hard to detect. int poll_res = TEMP_FAILURE_RETRY(poll(fd_structs, 2, -1 /* infinite timeout */)); if ((fd_structs[SESSION_IDX].revents & POLLIN) != 0) { if (n_buffer->getCount(fail_fn_z) != 0) { break; } // else disconnected; } else { // Session socket was disconnected valid_session_socket = false; close(session_socket); } } else if (poll_res == 0 || (fd_structs[ZYGOTE_IDX].revents & POLLIN) == 0) { fail_fn_z( CREATE_ERROR("Poll returned with no descriptors ready! Poll returned %d", poll_res)); } int new_fd = -1; do { // We've now seen either a disconnect or connect request. close(session_socket); int new_fd = TEMP_FAILURE_RETRY(accept(zygote_socket_fd, nullptr, nullptr)); new_fd = TEMP_FAILURE_RETRY(accept(zygote_socket_fd, nullptr, nullptr)); if (new_fd == -1) { fail_fn_z(CREATE_ERROR("Accept(%d) failed: %s", zygote_socket_fd, strerror(errno))); } uid_t newPeerUid = getSocketPeerUid(new_fd, fail_fn_1); if (newPeerUid != static_cast<uid_t>(expected_uid)) { ALOGW("Dropping new connection with a mismatched uid %d\n", newPeerUid); close(new_fd); new_fd = -1; } else { // If we still have a valid session socket, close it now if (valid_session_socket) { close(session_socket); } valid_session_socket = true; } } while (!valid_session_socket); // At this point we either have a valid new connection (new_fd > 0), or // an existing session socket we can poll on if (new_fd == -1) { // The new connection wasn't valid, and we still have an old one; retry polling continue; } if (new_fd != session_socket) { // Move new_fd back to the old value, so that we don't have to change Java-level data // structures to reflect a change. This implicitly closes the old one. Loading @@ -474,13 +506,6 @@ jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly( fail_fn_z(CREATE_ERROR("Failed to set send timeout for socket %d: %s", session_socket, strerror(errno))); } if (getsockopt(session_socket, SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1) { fail_fn_z(CREATE_ERROR("ForkMany failed to get credentials: %s", strerror(errno))); } if (cred_size != sizeof credentials) { fail_fn_z(CREATE_ERROR("ForkMany credential size = %d, should be %d", cred_size, static_cast<int>(sizeof credentials))); } } first_time = false; } while (n_buffer->isSimpleForkCommand(minUid, fail_fn_n)); Loading
media/java/android/media/session/ParcelableListBinder.java +11 −2 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ public class ParcelableListBinder<T extends Parcelable> extends Binder { private static final int END_OF_PARCEL = 0; private static final int ITEM_CONTINUED = 1; private final Class<T> mListElementsClass; private final Consumer<List<T>> mConsumer; private final Object mLock = new Object(); Loading @@ -61,9 +62,11 @@ public class ParcelableListBinder<T extends Parcelable> extends Binder { /** * Creates an instance. * * @param listElementsClass the class of the list elements. * @param consumer a consumer that consumes the list received */ public ParcelableListBinder(@NonNull Consumer<List<T>> consumer) { public ParcelableListBinder(Class<T> listElementsClass, @NonNull Consumer<List<T>> consumer) { mListElementsClass = listElementsClass; mConsumer = consumer; } Loading @@ -83,7 +86,13 @@ public class ParcelableListBinder<T extends Parcelable> extends Binder { mCount = data.readInt(); } while (i < mCount && data.readInt() != END_OF_PARCEL) { mList.add(data.readParcelable(null)); Object object = data.readParcelable(null); if (mListElementsClass.isAssignableFrom(object.getClass())) { // Checking list items are of compaitible types to validate against malicious // apps calling it directly via reflection with non compilable items. // See b/317048338 for more details mList.add((T) object); } i++; } if (i >= mCount) { Loading
services/core/java/com/android/server/media/MediaSessionRecord.java +8 −6 Original line number Diff line number Diff line Loading @@ -1095,7 +1095,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR @Override public IBinder getBinderForSetQueue() throws RemoteException { return new ParcelableListBinder<QueueItem>((list) -> { return new ParcelableListBinder<QueueItem>( QueueItem.class, (list) -> { synchronized (mLock) { mQueue = list; } Loading