linux-user pull request 20211122
Fixes for CID 1464101 and gilab #704 -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEEzS913cjjpNwuT1Fz8ww4vT8vvjwFAmGbU00SHGxhdXJlbnRA dml2aWVyLmV1AAoJEPMMOL0/L748pFAP/RQiwsG5q8WILlsb+MUhObr0v9dJPbAM el4Fo21OHYL9Jc/gPrOCRgP1Ey3EJzxwtzAIQojf2hm/KgUuTWZMdpjTc6pv3epl VB2Fi+Kz4sUznTWWB7Hbp+vX9VDlxzOIvbGJqwiasm9pKhffhsIRDOJgii7yQTSh qX2dOBkN5i4uSia/FAMpldf/uqz8J4/zVFM/IB52LnF5h8+qnTKWfcq8UpkfFF9s wKw6hgtaYZw+bcP1n+d2Lovz8gdXTXHw4KFl5g3+wx7Aj9tizzbkytJbUcc14pEu DoHPDqJxx3DULtza1hKuEYbB4onG2z0xw+MXtIbqqK3tp3UDLmgOXTlr7VBnqiLH mKzZL0eDDQVA5dgBnaKyE0lHl44G7PhOOPZZ8jDKnytyK1A3VEH6D6GJGe5nQhrG NJaTN91c6FtHM0iVQHMJsm9Un/EDDOb/kRzBUDpihFmlvZq6sgwDXlobMN4CAsDa 1YXU0sZfDUBFRChL9gfvJgrVBmnLAjpgDbXRURH+GwFuzlAvC56FAokFQwUxNuiW JwHhV+rudvAy2KuEYNAsTd1LP+Di7x5wNhPHKvKTPIf6pxL7JW2oAt1IPow/nlMc GtvWYWDhyI37pI8/BkyErqwmxaMDfmn5ATJsHi/hCFLn8JkxJDpKSiIhLqdrhgkS DWHJ9rrOPmnd =UZXm -----END PGP SIGNATURE----- Merge tag 'linux-user-for-6.2-pull-request' of git://github.com/vivier/qemu into staging linux-user pull request 20211122 Fixes for CID 1464101 and gilab #704 # gpg: Signature made Mon 22 Nov 2021 09:22:37 AM CET # gpg: using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C # gpg: issuer "laurent@vivier.eu" # gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full] # gpg: aka "Laurent Vivier <laurent@vivier.eu>" [full] # gpg: aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full] * tag 'linux-user-for-6.2-pull-request' of git://github.com/vivier/qemu: linux-user: fix Coverity CID 1464101 linux-user: Rewrite do_getdents, do_getdents64 linux-user: Fix member types of target_dirent64 linux-user: Always use flexible arrays for dirent d_name linux-user: Split out do_getdents, do_getdents64 Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
49aaac3548
@ -3254,9 +3254,13 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
|
|||||||
* Otherwise, allocate a private page to hold them.
|
* Otherwise, allocate a private page to hold them.
|
||||||
*/
|
*/
|
||||||
if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
|
if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
|
||||||
abi_ulong tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
|
abi_long tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
|
||||||
PROT_READ | PROT_WRITE,
|
PROT_READ | PROT_WRITE,
|
||||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||||
|
if (tramp_page == -1) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
setup_sigtramp(tramp_page);
|
setup_sigtramp(tramp_page);
|
||||||
target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
|
target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
|
||||||
}
|
}
|
||||||
|
@ -197,8 +197,10 @@
|
|||||||
//#define DEBUG_ERESTARTSYS
|
//#define DEBUG_ERESTARTSYS
|
||||||
|
|
||||||
//#include <linux/msdos_fs.h>
|
//#include <linux/msdos_fs.h>
|
||||||
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct linux_dirent [2])
|
#define VFAT_IOCTL_READDIR_BOTH \
|
||||||
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct linux_dirent [2])
|
_IOC(_IOC_READ, 'r', 1, (sizeof(struct linux_dirent) + 256) * 2)
|
||||||
|
#define VFAT_IOCTL_READDIR_SHORT \
|
||||||
|
_IOC(_IOC_READ, 'r', 2, (sizeof(struct linux_dirent) + 256) * 2)
|
||||||
|
|
||||||
#undef _syscall0
|
#undef _syscall0
|
||||||
#undef _syscall1
|
#undef _syscall1
|
||||||
@ -8137,6 +8139,159 @@ static int host_to_target_cpu_mask(const unsigned long *host_mask,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TARGET_NR_getdents
|
||||||
|
static int do_getdents(abi_long dirfd, abi_long arg2, abi_long count)
|
||||||
|
{
|
||||||
|
g_autofree void *hdirp = NULL;
|
||||||
|
void *tdirp;
|
||||||
|
int hlen, hoff, toff;
|
||||||
|
int hreclen, treclen;
|
||||||
|
off64_t prev_diroff = 0;
|
||||||
|
|
||||||
|
hdirp = g_try_malloc(count);
|
||||||
|
if (!hdirp) {
|
||||||
|
return -TARGET_ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef EMULATE_GETDENTS_WITH_GETDENTS
|
||||||
|
hlen = sys_getdents(dirfd, hdirp, count);
|
||||||
|
#else
|
||||||
|
hlen = sys_getdents64(dirfd, hdirp, count);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hlen = get_errno(hlen);
|
||||||
|
if (is_error(hlen)) {
|
||||||
|
return hlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
tdirp = lock_user(VERIFY_WRITE, arg2, count, 0);
|
||||||
|
if (!tdirp) {
|
||||||
|
return -TARGET_EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (hoff = toff = 0; hoff < hlen; hoff += hreclen, toff += treclen) {
|
||||||
|
#ifdef EMULATE_GETDENTS_WITH_GETDENTS
|
||||||
|
struct linux_dirent *hde = hdirp + hoff;
|
||||||
|
#else
|
||||||
|
struct linux_dirent64 *hde = hdirp + hoff;
|
||||||
|
#endif
|
||||||
|
struct target_dirent *tde = tdirp + toff;
|
||||||
|
int namelen;
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
namelen = strlen(hde->d_name);
|
||||||
|
hreclen = hde->d_reclen;
|
||||||
|
treclen = offsetof(struct target_dirent, d_name) + namelen + 2;
|
||||||
|
treclen = QEMU_ALIGN_UP(treclen, __alignof(struct target_dirent));
|
||||||
|
|
||||||
|
if (toff + treclen > count) {
|
||||||
|
/*
|
||||||
|
* If the host struct is smaller than the target struct, or
|
||||||
|
* requires less alignment and thus packs into less space,
|
||||||
|
* then the host can return more entries than we can pass
|
||||||
|
* on to the guest.
|
||||||
|
*/
|
||||||
|
if (toff == 0) {
|
||||||
|
toff = -TARGET_EINVAL; /* result buffer is too small */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Return what we have, resetting the file pointer to the
|
||||||
|
* location of the first record not returned.
|
||||||
|
*/
|
||||||
|
lseek64(dirfd, prev_diroff, SEEK_SET);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_diroff = hde->d_off;
|
||||||
|
tde->d_ino = tswapal(hde->d_ino);
|
||||||
|
tde->d_off = tswapal(hde->d_off);
|
||||||
|
tde->d_reclen = tswap16(treclen);
|
||||||
|
memcpy(tde->d_name, hde->d_name, namelen + 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The getdents type is in what was formerly a padding byte at the
|
||||||
|
* end of the structure.
|
||||||
|
*/
|
||||||
|
#ifdef EMULATE_GETDENTS_WITH_GETDENTS
|
||||||
|
type = *((uint8_t *)hde + hreclen - 1);
|
||||||
|
#else
|
||||||
|
type = hde->d_type;
|
||||||
|
#endif
|
||||||
|
*((uint8_t *)tde + treclen - 1) = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock_user(tdirp, arg2, toff);
|
||||||
|
return toff;
|
||||||
|
}
|
||||||
|
#endif /* TARGET_NR_getdents */
|
||||||
|
|
||||||
|
#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
|
||||||
|
static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
|
||||||
|
{
|
||||||
|
g_autofree void *hdirp = NULL;
|
||||||
|
void *tdirp;
|
||||||
|
int hlen, hoff, toff;
|
||||||
|
int hreclen, treclen;
|
||||||
|
off64_t prev_diroff = 0;
|
||||||
|
|
||||||
|
hdirp = g_try_malloc(count);
|
||||||
|
if (!hdirp) {
|
||||||
|
return -TARGET_ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
hlen = get_errno(sys_getdents64(dirfd, hdirp, count));
|
||||||
|
if (is_error(hlen)) {
|
||||||
|
return hlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
tdirp = lock_user(VERIFY_WRITE, arg2, count, 0);
|
||||||
|
if (!tdirp) {
|
||||||
|
return -TARGET_EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (hoff = toff = 0; hoff < hlen; hoff += hreclen, toff += treclen) {
|
||||||
|
struct linux_dirent64 *hde = hdirp + hoff;
|
||||||
|
struct target_dirent64 *tde = tdirp + toff;
|
||||||
|
int namelen;
|
||||||
|
|
||||||
|
namelen = strlen(hde->d_name) + 1;
|
||||||
|
hreclen = hde->d_reclen;
|
||||||
|
treclen = offsetof(struct target_dirent64, d_name) + namelen;
|
||||||
|
treclen = QEMU_ALIGN_UP(treclen, __alignof(struct target_dirent64));
|
||||||
|
|
||||||
|
if (toff + treclen > count) {
|
||||||
|
/*
|
||||||
|
* If the host struct is smaller than the target struct, or
|
||||||
|
* requires less alignment and thus packs into less space,
|
||||||
|
* then the host can return more entries than we can pass
|
||||||
|
* on to the guest.
|
||||||
|
*/
|
||||||
|
if (toff == 0) {
|
||||||
|
toff = -TARGET_EINVAL; /* result buffer is too small */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Return what we have, resetting the file pointer to the
|
||||||
|
* location of the first record not returned.
|
||||||
|
*/
|
||||||
|
lseek64(dirfd, prev_diroff, SEEK_SET);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_diroff = hde->d_off;
|
||||||
|
tde->d_ino = tswap64(hde->d_ino);
|
||||||
|
tde->d_off = tswap64(hde->d_off);
|
||||||
|
tde->d_reclen = tswap16(treclen);
|
||||||
|
tde->d_type = hde->d_type;
|
||||||
|
memcpy(tde->d_name, hde->d_name, namelen);
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock_user(tdirp, arg2, toff);
|
||||||
|
return toff;
|
||||||
|
}
|
||||||
|
#endif /* TARGET_NR_getdents64 */
|
||||||
|
|
||||||
#if defined(TARGET_NR_pivot_root) && defined(__NR_pivot_root)
|
#if defined(TARGET_NR_pivot_root) && defined(__NR_pivot_root)
|
||||||
_syscall2(int, pivot_root, const char *, new_root, const char *, put_old)
|
_syscall2(int, pivot_root, const char *, new_root, const char *, put_old)
|
||||||
#endif
|
#endif
|
||||||
@ -10227,162 +10382,11 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
|||||||
#endif
|
#endif
|
||||||
#ifdef TARGET_NR_getdents
|
#ifdef TARGET_NR_getdents
|
||||||
case TARGET_NR_getdents:
|
case TARGET_NR_getdents:
|
||||||
#ifdef EMULATE_GETDENTS_WITH_GETDENTS
|
return do_getdents(arg1, arg2, arg3);
|
||||||
#if TARGET_ABI_BITS == 32 && HOST_LONG_BITS == 64
|
|
||||||
{
|
|
||||||
struct target_dirent *target_dirp;
|
|
||||||
struct linux_dirent *dirp;
|
|
||||||
abi_long count = arg3;
|
|
||||||
|
|
||||||
dirp = g_try_malloc(count);
|
|
||||||
if (!dirp) {
|
|
||||||
return -TARGET_ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = get_errno(sys_getdents(arg1, dirp, count));
|
|
||||||
if (!is_error(ret)) {
|
|
||||||
struct linux_dirent *de;
|
|
||||||
struct target_dirent *tde;
|
|
||||||
int len = ret;
|
|
||||||
int reclen, treclen;
|
|
||||||
int count1, tnamelen;
|
|
||||||
|
|
||||||
count1 = 0;
|
|
||||||
de = dirp;
|
|
||||||
if (!(target_dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
|
|
||||||
return -TARGET_EFAULT;
|
|
||||||
tde = target_dirp;
|
|
||||||
while (len > 0) {
|
|
||||||
reclen = de->d_reclen;
|
|
||||||
tnamelen = reclen - offsetof(struct linux_dirent, d_name);
|
|
||||||
assert(tnamelen >= 0);
|
|
||||||
treclen = tnamelen + offsetof(struct target_dirent, d_name);
|
|
||||||
assert(count1 + treclen <= count);
|
|
||||||
tde->d_reclen = tswap16(treclen);
|
|
||||||
tde->d_ino = tswapal(de->d_ino);
|
|
||||||
tde->d_off = tswapal(de->d_off);
|
|
||||||
memcpy(tde->d_name, de->d_name, tnamelen);
|
|
||||||
de = (struct linux_dirent *)((char *)de + reclen);
|
|
||||||
len -= reclen;
|
|
||||||
tde = (struct target_dirent *)((char *)tde + treclen);
|
|
||||||
count1 += treclen;
|
|
||||||
}
|
|
||||||
ret = count1;
|
|
||||||
unlock_user(target_dirp, arg2, ret);
|
|
||||||
}
|
|
||||||
g_free(dirp);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
struct linux_dirent *dirp;
|
|
||||||
abi_long count = arg3;
|
|
||||||
|
|
||||||
if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
|
|
||||||
return -TARGET_EFAULT;
|
|
||||||
ret = get_errno(sys_getdents(arg1, dirp, count));
|
|
||||||
if (!is_error(ret)) {
|
|
||||||
struct linux_dirent *de;
|
|
||||||
int len = ret;
|
|
||||||
int reclen;
|
|
||||||
de = dirp;
|
|
||||||
while (len > 0) {
|
|
||||||
reclen = de->d_reclen;
|
|
||||||
if (reclen > len)
|
|
||||||
break;
|
|
||||||
de->d_reclen = tswap16(reclen);
|
|
||||||
tswapls(&de->d_ino);
|
|
||||||
tswapls(&de->d_off);
|
|
||||||
de = (struct linux_dirent *)((char *)de + reclen);
|
|
||||||
len -= reclen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unlock_user(dirp, arg2, ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
/* Implement getdents in terms of getdents64 */
|
|
||||||
{
|
|
||||||
struct linux_dirent64 *dirp;
|
|
||||||
abi_long count = arg3;
|
|
||||||
|
|
||||||
dirp = lock_user(VERIFY_WRITE, arg2, count, 0);
|
|
||||||
if (!dirp) {
|
|
||||||
return -TARGET_EFAULT;
|
|
||||||
}
|
|
||||||
ret = get_errno(sys_getdents64(arg1, dirp, count));
|
|
||||||
if (!is_error(ret)) {
|
|
||||||
/* Convert the dirent64 structs to target dirent. We do this
|
|
||||||
* in-place, since we can guarantee that a target_dirent is no
|
|
||||||
* larger than a dirent64; however this means we have to be
|
|
||||||
* careful to read everything before writing in the new format.
|
|
||||||
*/
|
|
||||||
struct linux_dirent64 *de;
|
|
||||||
struct target_dirent *tde;
|
|
||||||
int len = ret;
|
|
||||||
int tlen = 0;
|
|
||||||
|
|
||||||
de = dirp;
|
|
||||||
tde = (struct target_dirent *)dirp;
|
|
||||||
while (len > 0) {
|
|
||||||
int namelen, treclen;
|
|
||||||
int reclen = de->d_reclen;
|
|
||||||
uint64_t ino = de->d_ino;
|
|
||||||
int64_t off = de->d_off;
|
|
||||||
uint8_t type = de->d_type;
|
|
||||||
|
|
||||||
namelen = strlen(de->d_name);
|
|
||||||
treclen = offsetof(struct target_dirent, d_name)
|
|
||||||
+ namelen + 2;
|
|
||||||
treclen = QEMU_ALIGN_UP(treclen, sizeof(abi_long));
|
|
||||||
|
|
||||||
memmove(tde->d_name, de->d_name, namelen + 1);
|
|
||||||
tde->d_ino = tswapal(ino);
|
|
||||||
tde->d_off = tswapal(off);
|
|
||||||
tde->d_reclen = tswap16(treclen);
|
|
||||||
/* The target_dirent type is in what was formerly a padding
|
|
||||||
* byte at the end of the structure:
|
|
||||||
*/
|
|
||||||
*(((char *)tde) + treclen - 1) = type;
|
|
||||||
|
|
||||||
de = (struct linux_dirent64 *)((char *)de + reclen);
|
|
||||||
tde = (struct target_dirent *)((char *)tde + treclen);
|
|
||||||
len -= reclen;
|
|
||||||
tlen += treclen;
|
|
||||||
}
|
|
||||||
ret = tlen;
|
|
||||||
}
|
|
||||||
unlock_user(dirp, arg2, ret);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return ret;
|
|
||||||
#endif /* TARGET_NR_getdents */
|
#endif /* TARGET_NR_getdents */
|
||||||
#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
|
#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
|
||||||
case TARGET_NR_getdents64:
|
case TARGET_NR_getdents64:
|
||||||
{
|
return do_getdents64(arg1, arg2, arg3);
|
||||||
struct linux_dirent64 *dirp;
|
|
||||||
abi_long count = arg3;
|
|
||||||
if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0)))
|
|
||||||
return -TARGET_EFAULT;
|
|
||||||
ret = get_errno(sys_getdents64(arg1, dirp, count));
|
|
||||||
if (!is_error(ret)) {
|
|
||||||
struct linux_dirent64 *de;
|
|
||||||
int len = ret;
|
|
||||||
int reclen;
|
|
||||||
de = dirp;
|
|
||||||
while (len > 0) {
|
|
||||||
reclen = de->d_reclen;
|
|
||||||
if (reclen > len)
|
|
||||||
break;
|
|
||||||
de->d_reclen = tswap16(reclen);
|
|
||||||
tswap64s((uint64_t *)&de->d_ino);
|
|
||||||
tswap64s((uint64_t *)&de->d_off);
|
|
||||||
de = (struct linux_dirent64 *)((char *)de + reclen);
|
|
||||||
len -= reclen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unlock_user(dirp, arg2, ret);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
#endif /* TARGET_NR_getdents64 */
|
#endif /* TARGET_NR_getdents64 */
|
||||||
#if defined(TARGET_NR__newselect)
|
#if defined(TARGET_NR__newselect)
|
||||||
case TARGET_NR__newselect:
|
case TARGET_NR__newselect:
|
||||||
|
@ -437,11 +437,11 @@ struct target_dirent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct target_dirent64 {
|
struct target_dirent64 {
|
||||||
uint64_t d_ino;
|
abi_ullong d_ino;
|
||||||
int64_t d_off;
|
abi_llong d_off;
|
||||||
unsigned short d_reclen;
|
abi_ushort d_reclen;
|
||||||
unsigned char d_type;
|
unsigned char d_type;
|
||||||
char d_name[256];
|
char d_name[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -2714,7 +2714,7 @@ struct linux_dirent {
|
|||||||
long d_ino;
|
long d_ino;
|
||||||
unsigned long d_off;
|
unsigned long d_off;
|
||||||
unsigned short d_reclen;
|
unsigned short d_reclen;
|
||||||
char d_name[256]; /* We must not include limits.h! */
|
char d_name[];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct linux_dirent64 {
|
struct linux_dirent64 {
|
||||||
@ -2722,7 +2722,7 @@ struct linux_dirent64 {
|
|||||||
int64_t d_off;
|
int64_t d_off;
|
||||||
unsigned short d_reclen;
|
unsigned short d_reclen;
|
||||||
unsigned char d_type;
|
unsigned char d_type;
|
||||||
char d_name[256];
|
char d_name[];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct target_mq_attr {
|
struct target_mq_attr {
|
||||||
|
Loading…
Reference in New Issue
Block a user