ANDROID: fix ashmem_rust return EINVAL bug in ashmem_rust.rs

The application read the length of file and triggered a crash in android16-6.12. We found through analysis that FIONREAD should return ENOTTY, but EINVAL was returned in ashmem_rust.rs, which caused this issue. The default return is ENOTTY in ashmem.c.

The failed stacks is as follows:
07-03 10:47:51.830 13963 13963 D AndroidRuntime: Shutting down VM
07-03 10:47:51.834 13963 13963 E AndroidRuntime: FATAL EXCEPTION: main
07-03 10:47:51.834 13963 13963 E AndroidRuntime: Process: com.example.parceldemo:service, PID: 13963
07-03 10:47:51.834 13963 13963 E AndroidRuntime: java.lang.RuntimeException: Unable to start service com.example.parceldemo.services.ProcessService@b11ac4f with Intent { xflg=0x4 cmp=com.example.parceldemo/.services.ProcessService (has extras) }: java.io.IOException: Invalid argument
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:6099)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(Unknown Source:0)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:3067)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:110)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:266)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at android.os.Looper.loop(Looper.java:361)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:10155)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:638)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1002)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: Caused by: java.io.IOException: Invalid argument
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at java.io.FileInputStream.available0(Native Method)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at java.io.FileInputStream.available(FileInputStream.java:523)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at kotlin.io.ByteStreamsKt.readBytes(IOStreams.kt:135)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at com.example.parceldemo.model.Book$Companion.from(Book.kt:25)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at com.example.parceldemo.services.ProcessService.onStartCommand(ProcessService.kt:37)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:6081)
07-03 10:47:51.834 13963 13963 E AndroidRuntime: ... 9 more

The analysis process is as follows:
InputStream.readBytes(): ByteArray --> available() --> ioctl(fd, FIONREAD, &n)
--> ashmem_rust.rs fn ioctl(me: Pin<&Ashmem>, _file: &File, cmd: u32, arg: usize) -> Result<isize>
--> return Err(EINVAL)

/**
 * Reads this stream completely into a byte array.
 *
 * **Note**: It is the caller's responsibility to close this stream.
 */
@SinceKotlin("1.3")
public fun InputStream.readBytes(): ByteArray {
    val buffer = ByteArrayOutputStream(maxOf(DEFAULT_BUFFER_SIZE, this.available()))
    copyTo(buffer)
    return buffer.toByteArray()
}

libcore/ojluni/src/main/native/FileInputStream.c
128 static int available(int fd, jlong *bytes) {
129 // BEGIN Android-added: Fuchsia does not support FIONREAD. http://b/120566512
130 #if defined(__Fuchsia__)
131 *bytes = 0;
132 return 1;
133 #else
134 // END Android-added: Fuchsia does not support FIONREAD. http://b/120566512
135 int n;
136 // Unlike the original OpenJdk implementation, we use FIONREAD for all file
137 // types. For regular files, this is specified to return the difference
138 // between the current position and the file size. Note that this can be
139 // negative if we're positioned past the end of the file. We must return 0
140 // in that case.
141 if (ioctl(fd, FIONREAD, &n) != -1) {
142 if (n < 0) {
143 n = 0;
144 }
145 *bytes = n;
146 return 1;
147 }
148
149 // FIONREAD is specified to return ENOTTY when fd refers to a file
150 // type for which this ioctl isn't implemented.
151 if (errno == ENOTTY) {
152 *bytes = 0;
153 return 1;
154 }
155
156 // Raise an exception for all other error types.
157 return 0;
158 // Android-added: Fuchsia does not support the FIONREAD code. http://b/120566512
159 #endif
160 }
161
162 JNIEXPORT jint JNICALL
163 Java_java_io_FileInputStream_available0(JNIEnv *env, jobject this) {
164 jlong ret;
165 FD fd = getFD(env, this, fis_fd);
166 if (fd == -1) {
167 JNU_ThrowIOException (env, "Stream Closed");
168 return 0;
169 }
170 if (available(fd, &ret)) {
171 if (ret > INT_MAX) {
172 ret = (jlong) INT_MAX;
173 } else if (ret < 0) {
174 ret = 0;
175 }
176 return jlong_to_jint(ret);
177 }
178 JNU_ThrowIOExceptionWithLastError(env, NULL);
179 return 0;
180 }

common/drivers/staging/android/ashmem_rust.rs
245 fn ioctl(me: Pin<&Ashmem>, _file: &File, cmd: u32, arg: usize) -> Result<isize> {
246 let size = _IOC_SIZE(cmd);
247 match cmd {
248 bindings::ASHMEM_SET_NAME => me.set_name(UserSlice::new(arg, size).reader()),
249 bindings::ASHMEM_GET_NAME => me.get_name(UserSlice::new(arg, size).writer()),
250 bindings::ASHMEM_SET_SIZE => me.set_size(arg),
251 bindings::ASHMEM_GET_SIZE => me.get_size(),
252 bindings::ASHMEM_SET_PROT_MASK => me.set_prot_mask(arg),
253 bindings::ASHMEM_GET_PROT_MASK => me.get_prot_mask(),
254 bindings::ASHMEM_GET_FILE_ID => me.get_file_id(UserSlice::new(arg, size).writer()),
255 ASHMEM_PIN | ASHMEM_UNPIN | ASHMEM_GET_PIN_STATUS => {
256 me.pin_unpin(cmd, UserSlice::new(arg, size).reader())
257 }
258 bindings::ASHMEM_PURGE_ALL_CACHES => me.purge_all_caches(),
259 _ => Err(EINVAL),
260 }
261 }

common/drivers/staging/android/ashmem.c
828 static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
829 {
830 struct ashmem_area *asma = file->private_data;
831 unsigned long ino;
832 long ret = -ENOTTY;
-> For the c-version, it's ENOTTY

Bug: 430143362
Change-Id: Ie316e7f3670ecdf59b75ff127283a6744763361d
Signed-off-by: Justin Jiang <justinjiang@vivo.corp-partner.google.com>
This commit is contained in:
Justin Jiang
2025-07-08 10:59:36 +08:00
committed by Treehugger Robot
parent a7e1300b95
commit b62fe47ba2

View File

@@ -258,7 +258,7 @@ impl MiscDevice for Ashmem {
me.pin_unpin(cmd, UserSlice::new(arg, size).reader())
}
bindings::ASHMEM_PURGE_ALL_CACHES => me.purge_all_caches(),
_ => Err(EINVAL),
_ => Err(ENOTTY),
}
}