Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/riku/tags/pull-linux-user-20150…
Browse files Browse the repository at this point in the history
…616' into staging

linux-user patches for 2.4 softfreeze
second spin with ioctl patch refreshed

# gpg: Signature made Tue Jun 16 08:03:14 2015 BST using RSA key ID DE3C9BC0
# gpg: Good signature from "Riku Voipio <riku.voipio@iki.fi>"
# gpg:                 aka "Riku Voipio <riku.voipio@linaro.org>"

* remotes/riku/tags/pull-linux-user-20150616:
  linux-user: ioctl() command type is int
  linux-user: fix the breakpoint inheritance in spawned threads
  linux-user: use __get_user and __put_user in cmsg conversions
  linux-user: Fix length handling in host_to_target_cmsg
  linux-user: Use abi_ulong for TARGET_ELF_PAGESTART
  linux-user: Allocate thunk size dynamically

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Jun 16, 2015
2 parents 1dfe73b + 45c874e commit 4316536
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 33 deletions.
4 changes: 3 additions & 1 deletion include/exec/user/thunk.h
Expand Up @@ -74,7 +74,7 @@ const argtype *thunk_convert(void *dst, const void *src,
const argtype *type_ptr, int to_host);
#ifndef NO_THUNK_TYPE_SIZE

extern StructEntry struct_entries[];
extern StructEntry *struct_entries;

int thunk_type_size_array(const argtype *type_ptr, int is_host);
int thunk_type_align_array(const argtype *type_ptr, int is_host);
Expand Down Expand Up @@ -186,4 +186,6 @@ unsigned int target_to_host_bitmask(unsigned int x86_mask,
unsigned int host_to_target_bitmask(unsigned int alpha_mask,
const bitmask_transtbl * trans_tbl);

void thunk_init(unsigned int max_structs);

#endif
3 changes: 2 additions & 1 deletion linux-user/elfload.c
Expand Up @@ -1256,7 +1256,8 @@ struct exec

/* Necessary parameters */
#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
#define TARGET_ELF_PAGESTART(_v) ((_v) & \
~(abi_ulong)(TARGET_ELF_EXEC_PAGESIZE-1))
#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))

#define DLINFO_ITEMS 14
Expand Down
4 changes: 2 additions & 2 deletions linux-user/main.c
Expand Up @@ -3459,8 +3459,8 @@ CPUArchState *cpu_copy(CPUArchState *env)
/* Clone all break/watchpoints.
Note: Once we support ptrace with hw-debug register access, make sure
BP_CPU break/watchpoints are handled correctly on clone. */
QTAILQ_INIT(&cpu->breakpoints);
QTAILQ_INIT(&cpu->watchpoints);
QTAILQ_INIT(&new_cpu->breakpoints);
QTAILQ_INIT(&new_cpu->watchpoints);
QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
}
Expand Down
108 changes: 83 additions & 25 deletions linux-user/syscall.c
Expand Up @@ -1202,6 +1202,15 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
space += CMSG_SPACE(len);
if (space > msgh->msg_controllen) {
space -= CMSG_SPACE(len);
/* This is a QEMU bug, since we allocated the payload
* area ourselves (unlike overflow in host-to-target
* conversion, which is just the guest giving us a buffer
* that's too small). It can't happen for the payload types
* we currently support; if it becomes an issue in future
* we would need to improve our allocation strategy to
* something more intelligent than "twice the size of the
* target buffer we're reading from".
*/
gemu_log("Host cmsg overflow\n");
break;
}
Expand All @@ -1219,17 +1228,18 @@ static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
int *target_fd = (int *)target_data;
int i, numfds = len / sizeof(int);

for (i = 0; i < numfds; i++)
fd[i] = tswap32(target_fd[i]);
for (i = 0; i < numfds; i++) {
__get_user(fd[i], target_fd + i);
}
} else if (cmsg->cmsg_level == SOL_SOCKET
&& cmsg->cmsg_type == SCM_CREDENTIALS) {
struct ucred *cred = (struct ucred *)data;
struct target_ucred *target_cred =
(struct target_ucred *)target_data;

__put_user(target_cred->pid, &cred->pid);
__put_user(target_cred->uid, &cred->uid);
__put_user(target_cred->gid, &cred->gid);
__get_user(cred->pid, &target_cred->pid);
__get_user(cred->uid, &target_cred->uid);
__get_user(cred->gid, &target_cred->gid);
} else {
gemu_log("Unsupported ancillary data: %d/%d\n",
cmsg->cmsg_level, cmsg->cmsg_type);
Expand Down Expand Up @@ -1267,11 +1277,16 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
void *target_data = TARGET_CMSG_DATA(target_cmsg);

int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
int tgt_len, tgt_space;

space += TARGET_CMSG_SPACE(len);
if (space > msg_controllen) {
space -= TARGET_CMSG_SPACE(len);
gemu_log("Target cmsg overflow\n");
/* We never copy a half-header but may copy half-data;
* this is Linux's behaviour in put_cmsg(). Note that
* truncation here is a guest problem (which we report
* to the guest via the CTRUNC bit), unlike truncation
* in target_to_host_cmsg, which is a QEMU bug.
*/
if (msg_controllen < sizeof(struct cmsghdr)) {
target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
break;
}

Expand All @@ -1281,19 +1296,47 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
}
target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
target_cmsg->cmsg_len = tswapal(TARGET_CMSG_LEN(len));

tgt_len = TARGET_CMSG_LEN(len);

/* Payload types which need a different size of payload on
* the target must adjust tgt_len here.
*/
switch (cmsg->cmsg_level) {
case SOL_SOCKET:
switch (cmsg->cmsg_type) {
case SO_TIMESTAMP:
tgt_len = sizeof(struct target_timeval);
break;
default:
break;
}
default:
break;
}

if (msg_controllen < tgt_len) {
target_msgh->msg_flags |= tswap32(MSG_CTRUNC);
tgt_len = msg_controllen;
}

/* We must now copy-and-convert len bytes of payload
* into tgt_len bytes of destination space. Bear in mind
* that in both source and destination we may be dealing
* with a truncated value!
*/
switch (cmsg->cmsg_level) {
case SOL_SOCKET:
switch (cmsg->cmsg_type) {
case SCM_RIGHTS:
{
int *fd = (int *)data;
int *target_fd = (int *)target_data;
int i, numfds = len / sizeof(int);
int i, numfds = tgt_len / sizeof(int);

for (i = 0; i < numfds; i++)
target_fd[i] = tswap32(fd[i]);
for (i = 0; i < numfds; i++) {
__put_user(fd[i], target_fd + i);
}
break;
}
case SO_TIMESTAMP:
Expand All @@ -1302,12 +1345,14 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
struct target_timeval *target_tv =
(struct target_timeval *)target_data;

if (len != sizeof(struct timeval))
if (len != sizeof(struct timeval) ||
tgt_len != sizeof(struct target_timeval)) {
goto unimplemented;
}

/* copy struct timeval to target */
target_tv->tv_sec = tswapal(tv->tv_sec);
target_tv->tv_usec = tswapal(tv->tv_usec);
__put_user(tv->tv_sec, &target_tv->tv_sec);
__put_user(tv->tv_usec, &target_tv->tv_usec);
break;
}
case SCM_CREDENTIALS:
Expand All @@ -1330,9 +1375,19 @@ static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh,
unimplemented:
gemu_log("Unsupported ancillary data: %d/%d\n",
cmsg->cmsg_level, cmsg->cmsg_type);
memcpy(target_data, data, len);
memcpy(target_data, data, MIN(len, tgt_len));
if (tgt_len > len) {
memset(target_data + len, 0, tgt_len - len);
}
}

target_cmsg->cmsg_len = tswapal(tgt_len);
tgt_space = TARGET_CMSG_SPACE(tgt_len);
if (msg_controllen < tgt_space) {
tgt_space = msg_controllen;
}
msg_controllen -= tgt_space;
space += tgt_space;
cmsg = CMSG_NXTHDR(msgh, cmsg);
target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
}
Expand Down Expand Up @@ -3277,6 +3332,7 @@ static abi_long do_ipc(unsigned int call, abi_long first,
#define STRUCT_SPECIAL(name) STRUCT_ ## name,
enum {
#include "syscall_types.h"
STRUCT_MAX
};
#undef STRUCT
#undef STRUCT_SPECIAL
Expand All @@ -3290,7 +3346,7 @@ enum {
typedef struct IOCTLEntry IOCTLEntry;

typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
int fd, abi_long cmd, abi_long arg);
int fd, int cmd, abi_long arg);

struct IOCTLEntry {
int target_cmd;
Expand All @@ -3316,7 +3372,7 @@ struct IOCTLEntry {
/ sizeof(struct fiemap_extent))

static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
int fd, abi_long cmd, abi_long arg)
int fd, int cmd, abi_long arg)
{
/* The parameter for this ioctl is a struct fiemap followed
* by an array of struct fiemap_extent whose size is set
Expand Down Expand Up @@ -3397,7 +3453,7 @@ static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t *buf_temp,
#endif

static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
int fd, abi_long cmd, abi_long arg)
int fd, int cmd, abi_long arg)
{
const argtype *arg_type = ie->arg_type;
int target_size;
Expand Down Expand Up @@ -3491,7 +3547,7 @@ static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
}

static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
abi_long cmd, abi_long arg)
int cmd, abi_long arg)
{
void *argptr;
struct dm_ioctl *host_dm;
Expand Down Expand Up @@ -3716,7 +3772,7 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
}

static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
abi_long cmd, abi_long arg)
int cmd, abi_long arg)
{
void *argptr;
int target_size;
Expand Down Expand Up @@ -3769,7 +3825,7 @@ static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
}

static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
int fd, abi_long cmd, abi_long arg)
int fd, int cmd, abi_long arg)
{
const argtype *arg_type = ie->arg_type;
const StructEntry *se;
Expand Down Expand Up @@ -3832,7 +3888,7 @@ static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp,
}

static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
int fd, abi_long cmd, abi_long arg)
int fd, int cmd, abi_long arg)
{
int sig = target_to_host_signal(arg);
return get_errno(ioctl(fd, ie->host_cmd, sig));
Expand All @@ -3849,7 +3905,7 @@ static IOCTLEntry ioctl_entries[] = {

/* ??? Implement proper locking for ioctls. */
/* do_ioctl() Must return target values and target errnos. */
static abi_long do_ioctl(int fd, abi_long cmd, abi_long arg)
static abi_long do_ioctl(int fd, int cmd, abi_long arg)
{
const IOCTLEntry *ie;
const argtype *arg_type;
Expand Down Expand Up @@ -4879,6 +4935,8 @@ void syscall_init(void)
int size;
int i;

thunk_init(STRUCT_MAX);

#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
#include "syscall_types.h"
Expand Down
16 changes: 12 additions & 4 deletions thunk.c
Expand Up @@ -25,10 +25,8 @@

//#define DEBUG

#define MAX_STRUCTS 128

/* XXX: make it dynamic */
StructEntry struct_entries[MAX_STRUCTS];
static unsigned int max_struct_entries;
StructEntry *struct_entries;

static const argtype *thunk_type_next_ptr(const argtype *type_ptr);

Expand Down Expand Up @@ -70,6 +68,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types)
StructEntry *se;
int nb_fields, offset, max_align, align, size, i, j;

assert(id < max_struct_entries);
se = struct_entries + id;

/* first we count the number of fields */
Expand Down Expand Up @@ -117,6 +116,8 @@ void thunk_register_struct_direct(int id, const char *name,
const StructEntry *se1)
{
StructEntry *se;

assert(id < max_struct_entries);
se = struct_entries + id;
*se = *se1;
se->name = name;
Expand Down Expand Up @@ -244,6 +245,7 @@ const argtype *thunk_convert(void *dst, const void *src,
const argtype *field_types;
const int *dst_offsets, *src_offsets;

assert(*type_ptr < max_struct_entries);
se = struct_entries + *type_ptr++;
if (se->convert[0] != NULL) {
/* specific conversion is needed */
Expand Down Expand Up @@ -314,3 +316,9 @@ int thunk_type_align_array(const argtype *type_ptr, int is_host)
return thunk_type_align(type_ptr, is_host);
}
#endif /* ndef NO_THUNK_TYPE_SIZE */

void thunk_init(unsigned int max_structs)
{
max_struct_entries = max_structs;
struct_entries = g_new0(StructEntry, max_structs);
}

0 comments on commit 4316536

Please sign in to comment.