Blame view

ipc/compat_mq.c 3.89 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   *  ipc/compat_mq.c
   *    32 bit emulation for POSIX message queue system calls
   *
   *    Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
   *    Author: Arnd Bergmann <arnd@arndb.de>
   */
  
  #include <linux/compat.h>
  #include <linux/fs.h>
  #include <linux/kernel.h>
  #include <linux/mqueue.h>
  #include <linux/syscalls.h>
7153e4027   Paul McQuade   ipc, kernel: use ...
14
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
  
  struct compat_mq_attr {
  	compat_long_t mq_flags;      /* message queue flags		     */
  	compat_long_t mq_maxmsg;     /* maximum number of messages	     */
  	compat_long_t mq_msgsize;    /* maximum message size		     */
  	compat_long_t mq_curmsgs;    /* number of messages currently queued  */
  	compat_long_t __reserved[4]; /* ignored for input, zeroed for output */
  };
  
  static inline int get_compat_mq_attr(struct mq_attr *attr,
  			const struct compat_mq_attr __user *uattr)
  {
  	if (!access_ok(VERIFY_READ, uattr, sizeof *uattr))
  		return -EFAULT;
  
  	return __get_user(attr->mq_flags, &uattr->mq_flags)
  		| __get_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
  		| __get_user(attr->mq_msgsize, &uattr->mq_msgsize)
  		| __get_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
  }
  
  static inline int put_compat_mq_attr(const struct mq_attr *attr,
  			struct compat_mq_attr __user *uattr)
  {
  	if (clear_user(uattr, sizeof *uattr))
  		return -EFAULT;
  
  	return __put_user(attr->mq_flags, &uattr->mq_flags)
  		| __put_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
  		| __put_user(attr->mq_msgsize, &uattr->mq_msgsize)
  		| __put_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
  }
5d70a5963   Heiko Carstens   ipc/compat: conve...
47
48
49
  COMPAT_SYSCALL_DEFINE4(mq_open, const char __user *, u_name,
  		       int, oflag, compat_mode_t, mode,
  		       struct compat_mq_attr __user *, u_attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
53
  {
  	void __user *p = NULL;
  	if (u_attr && oflag & O_CREAT) {
  		struct mq_attr attr;
03145beb4   Dan Rosenberg   ipc: initialize s...
54
55
  
  		memset(&attr, 0, sizeof(attr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
61
62
  		p = compat_alloc_user_space(sizeof(attr));
  		if (get_compat_mq_attr(&attr, u_attr) ||
  		    copy_to_user(p, &attr, sizeof(attr)))
  			return -EFAULT;
  	}
  	return sys_mq_open(u_name, oflag, mode, p);
  }
8eee9093c   Heiko Carstens   ipc/compat: conve...
63
64
65
66
  COMPAT_SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes,
  		       const char __user *, u_msg_ptr,
  		       compat_size_t, msg_len, unsigned int, msg_prio,
  		       const struct compat_timespec __user *, u_abs_timeout)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
  {
  	struct timespec __user *u_ts;
81993e81a   H. Peter Anvin   compat: Get rid o...
69
  	if (compat_convert_timespec(&u_ts, u_abs_timeout))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
74
  		return -EFAULT;
  
  	return sys_mq_timedsend(mqdes, u_msg_ptr, msg_len,
  			msg_prio, u_ts);
  }
8eee9093c   Heiko Carstens   ipc/compat: conve...
75
76
77
78
  COMPAT_SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes,
  		       char __user *, u_msg_ptr,
  		       compat_size_t, msg_len, unsigned int __user *, u_msg_prio,
  		       const struct compat_timespec __user *, u_abs_timeout)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
  {
  	struct timespec __user *u_ts;
81993e81a   H. Peter Anvin   compat: Get rid o...
81
82
  
  	if (compat_convert_timespec(&u_ts, u_abs_timeout))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
  		return -EFAULT;
  
  	return sys_mq_timedreceive(mqdes, u_msg_ptr, msg_len,
  			u_msg_prio, u_ts);
  }
5d70a5963   Heiko Carstens   ipc/compat: conve...
88
89
  COMPAT_SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
  		       const struct compat_sigevent __user *, u_notification)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  {
  	struct sigevent __user *p = NULL;
  	if (u_notification) {
  		struct sigevent n;
  		p = compat_alloc_user_space(sizeof(*p));
  		if (get_compat_sigevent(&n, u_notification))
  			return -EFAULT;
  		if (n.sigev_notify == SIGEV_THREAD)
  			n.sigev_value.sival_ptr = compat_ptr(n.sigev_value.sival_int);
  		if (copy_to_user(p, &n, sizeof(*p)))
  			return -EFAULT;
  	}
  	return sys_mq_notify(mqdes, p);
  }
5d70a5963   Heiko Carstens   ipc/compat: conve...
104
105
106
  COMPAT_SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
  		       const struct compat_mq_attr __user *, u_mqstat,
  		       struct compat_mq_attr __user *, u_omqstat)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
  {
  	struct mq_attr mqstat;
  	struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
  	long ret;
03145beb4   Dan Rosenberg   ipc: initialize s...
111
  	memset(&mqstat, 0, sizeof(mqstat));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  	if (u_mqstat) {
  		if (get_compat_mq_attr(&mqstat, u_mqstat) ||
  		    copy_to_user(p, &mqstat, sizeof(mqstat)))
  			return -EFAULT;
  	}
  	ret = sys_mq_getsetattr(mqdes,
  				u_mqstat ? p : NULL,
  				u_omqstat ? p + 1 : NULL);
  	if (ret)
  		return ret;
  	if (u_omqstat) {
  		if (copy_from_user(&mqstat, p + 1, sizeof(mqstat)) ||
  		    put_compat_mq_attr(&mqstat, u_omqstat))
  			return -EFAULT;
  	}
  	return 0;
  }