Skip to content

Commit ebc061f

Browse files
Khoa HongOhMyVenyx
authored andcommitted
Add protections against queueing a UsbRequest when the underlying UsbDeviceConnection is closed.
Bug: 204584366 Test: CTS Verifier: USB Accessory Test & USB Device Test Test: No HWASan use-after-free reports with a test app Change-Id: Ia3a9b10349efc0236b1539c81465f479cb32e02b (cherry picked from commit 1691b54) Merged-In: Ia3a9b10349efc0236b1539c81465f479cb32e02b
1 parent 097ee0b commit ebc061f

2 files changed

Lines changed: 86 additions & 10 deletions

File tree

core/java/android/hardware/usb/UsbDeviceConnection.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,34 @@ boolean isOpen() {
107107
}
108108
}
109109

110+
/**
111+
* This is meant to be called by UsbRequest's queue() in order to synchronize on
112+
* UsbDeviceConnection's mLock to prevent the connection being closed while queueing.
113+
*/
114+
/* package */ boolean queueRequest(UsbRequest request, ByteBuffer buffer, int length) {
115+
synchronized (mLock) {
116+
if (!isOpen()) {
117+
return false;
118+
}
119+
120+
return request.queueIfConnectionOpen(buffer, length);
121+
}
122+
}
123+
124+
/**
125+
* This is meant to be called by UsbRequest's queue() in order to synchronize on
126+
* UsbDeviceConnection's mLock to prevent the connection being closed while queueing.
127+
*/
128+
/* package */ boolean queueRequest(UsbRequest request, @Nullable ByteBuffer buffer) {
129+
synchronized (mLock) {
130+
if (!isOpen()) {
131+
return false;
132+
}
133+
134+
return request.queueIfConnectionOpen(buffer);
135+
}
136+
}
137+
110138
/**
111139
* Releases all system resources related to the device.
112140
* Once the object is closed it cannot be used again.

core/java/android/hardware/usb/UsbRequest.java

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,13 @@ public boolean initialize(UsbDeviceConnection connection, UsbEndpoint endpoint)
113113
* Releases all resources related to this request.
114114
*/
115115
public void close() {
116-
if (mNativeContext != 0) {
117-
mEndpoint = null;
118-
mConnection = null;
119-
native_close();
120-
mCloseGuard.close();
116+
synchronized (mLock) {
117+
if (mNativeContext != 0) {
118+
mEndpoint = null;
119+
mConnection = null;
120+
native_close();
121+
mCloseGuard.close();
122+
}
121123
}
122124
}
123125

@@ -191,10 +193,32 @@ public void setClientData(Object data) {
191193
*/
192194
@Deprecated
193195
public boolean queue(ByteBuffer buffer, int length) {
196+
UsbDeviceConnection connection = mConnection;
197+
if (connection == null) {
198+
// The expected exception by CTS Verifier - USB Device test
199+
throw new NullPointerException("invalid connection");
200+
}
201+
202+
// Calling into the underlying UsbDeviceConnection to synchronize on its lock, to prevent
203+
// the connection being closed while queueing.
204+
return connection.queueRequest(this, buffer, length);
205+
}
206+
207+
/**
208+
* This is meant to be called from UsbDeviceConnection after synchronizing using the lock over
209+
* there, to prevent the connection being closed while queueing.
210+
*/
211+
/* package */ boolean queueIfConnectionOpen(ByteBuffer buffer, int length) {
212+
UsbDeviceConnection connection = mConnection;
213+
if (connection == null || !connection.isOpen()) {
214+
// The expected exception by CTS Verifier - USB Device test
215+
throw new NullPointerException("invalid connection");
216+
}
217+
194218
boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
195219
boolean result;
196220

197-
if (mConnection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
221+
if (connection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
198222
&& length > MAX_USBFS_BUFFER_SIZE) {
199223
length = MAX_USBFS_BUFFER_SIZE;
200224
}
@@ -243,6 +267,28 @@ public boolean queue(ByteBuffer buffer, int length) {
243267
* @return true if the queueing operation succeeded
244268
*/
245269
public boolean queue(@Nullable ByteBuffer buffer) {
270+
UsbDeviceConnection connection = mConnection;
271+
if (connection == null) {
272+
// The expected exception by CTS Verifier - USB Device test
273+
throw new IllegalStateException("invalid connection");
274+
}
275+
276+
// Calling into the underlying UsbDeviceConnection to synchronize on its lock, to prevent
277+
// the connection being closed while queueing.
278+
return connection.queueRequest(this, buffer);
279+
}
280+
281+
/**
282+
* This is meant to be called from UsbDeviceConnection after synchronizing using the lock over
283+
* there, to prevent the connection being closed while queueing.
284+
*/
285+
/* package */ boolean queueIfConnectionOpen(@Nullable ByteBuffer buffer) {
286+
UsbDeviceConnection connection = mConnection;
287+
if (connection == null || !connection.isOpen()) {
288+
// The expected exception by CTS Verifier - USB Device test
289+
throw new IllegalStateException("invalid connection");
290+
}
291+
246292
// Request need to be initialized
247293
Preconditions.checkState(mNativeContext != 0, "request is not initialized");
248294

@@ -260,7 +306,7 @@ public boolean queue(@Nullable ByteBuffer buffer) {
260306
mIsUsingNewQueue = true;
261307
wasQueued = native_queue(null, 0, 0);
262308
} else {
263-
if (mConnection.getContext().getApplicationInfo().targetSdkVersion
309+
if (connection.getContext().getApplicationInfo().targetSdkVersion
264310
< Build.VERSION_CODES.P) {
265311
// Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
266312
Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
@@ -363,11 +409,12 @@ public boolean queue(@Nullable ByteBuffer buffer) {
363409
* @return true if cancelling succeeded
364410
*/
365411
public boolean cancel() {
366-
if (mConnection == null) {
412+
UsbDeviceConnection connection = mConnection;
413+
if (connection == null) {
367414
return false;
368415
}
369416

370-
return mConnection.cancelRequest(this);
417+
return connection.cancelRequest(this);
371418
}
372419

373420
/**
@@ -382,7 +429,8 @@ public boolean cancel() {
382429
* @return true if cancelling succeeded.
383430
*/
384431
/* package */ boolean cancelIfOpen() {
385-
if (mNativeContext == 0 || (mConnection != null && !mConnection.isOpen())) {
432+
UsbDeviceConnection connection = mConnection;
433+
if (mNativeContext == 0 || (connection != null && !connection.isOpen())) {
386434
Log.w(TAG,
387435
"Detected attempt to cancel a request on a connection which isn't open");
388436
return false;

0 commit comments

Comments
 (0)