linux-user: allow NULL arguments to mount

Calls to the mount syscall can legitimately provide NULL as the value
for the source of filesystemtype arguments, which QEMU would previously
reject & return -EFAULT to the target program. An example of this is
remounting an already mounted filesystem with different properties.

Instead of rejecting such syscalls with -EFAULT, pass NULL along to the
kernel as the target program expects.

Additionally this patch fixes a potential memory leak when DEBUG_REMAP
is enabled and lock_user_string fails on the target or filesystemtype
arguments but a prior argument was non-NULL and already locked.

Since the patch already touched most lines of the TARGET_NR_mount case,
it fixes the indentation & coding style for good measure.

Signed-off-by: Paul Burton <paul@archlinuxmips.org>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
This commit is contained in:
Paul Burton 2014-06-22 11:25:37 +01:00 committed by Riku Voipio
parent 82d0fe6b7a
commit 356d771b30

View File

@ -5614,29 +5614,60 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break; break;
#endif #endif
case TARGET_NR_mount: case TARGET_NR_mount:
{ {
/* need to look at the data field */ /* need to look at the data field */
void *p2, *p3; void *p2, *p3;
p = lock_user_string(arg1);
p2 = lock_user_string(arg2); if (arg1) {
p3 = lock_user_string(arg3); p = lock_user_string(arg1);
if (!p || !p2 || !p3) if (!p) {
ret = -TARGET_EFAULT; goto efault;
else { }
/* FIXME - arg5 should be locked, but it isn't clear how to } else {
* do that since it's not guaranteed to be a NULL-terminated p = NULL;
* string. }
*/
if ( ! arg5 ) p2 = lock_user_string(arg2);
ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, NULL)); if (!p2) {
else if (arg1) {
ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, g2h(arg5))); unlock_user(p, arg1, 0);
} }
goto efault;
}
if (arg3) {
p3 = lock_user_string(arg3);
if (!p3) {
if (arg1) {
unlock_user(p, arg1, 0); unlock_user(p, arg1, 0);
unlock_user(p2, arg2, 0); }
unlock_user(p3, arg3, 0); unlock_user(p2, arg2, 0);
break; goto efault;
} }
} else {
p3 = NULL;
}
/* FIXME - arg5 should be locked, but it isn't clear how to
* do that since it's not guaranteed to be a NULL-terminated
* string.
*/
if (!arg5) {
ret = mount(p, p2, p3, (unsigned long)arg4, NULL);
} else {
ret = mount(p, p2, p3, (unsigned long)arg4, g2h(arg5));
}
ret = get_errno(ret);
if (arg1) {
unlock_user(p, arg1, 0);
}
unlock_user(p2, arg2, 0);
if (arg3) {
unlock_user(p3, arg3, 0);
}
}
break;
#ifdef TARGET_NR_umount #ifdef TARGET_NR_umount
case TARGET_NR_umount: case TARGET_NR_umount:
if (!(p = lock_user_string(arg1))) if (!(p = lock_user_string(arg1)))