2005-04-17 02:20:36 +04:00
/*
* 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>
2014-06-07 01:37:37 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
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 ) ;
}
2014-03-04 14:17:50 +04:00
COMPAT_SYSCALL_DEFINE4 ( mq_open , const char __user * , u_name ,
int , oflag , compat_mode_t , mode ,
struct compat_mq_attr __user * , u_attr )
2005-04-17 02:20:36 +04:00
{
void __user * p = NULL ;
if ( u_attr & & oflag & O_CREAT ) {
struct mq_attr attr ;
2010-10-28 02:34:17 +04:00
memset ( & attr , 0 , sizeof ( attr ) ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
}
2014-03-04 19:19:16 +04:00
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 )
2005-04-17 02:20:36 +04:00
{
struct timespec __user * u_ts ;
2014-02-02 06:54:11 +04:00
if ( compat_convert_timespec ( & u_ts , u_abs_timeout ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
return sys_mq_timedsend ( mqdes , u_msg_ptr , msg_len ,
msg_prio , u_ts ) ;
}
2014-03-04 19:19:16 +04:00
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 )
2005-04-17 02:20:36 +04:00
{
struct timespec __user * u_ts ;
2014-02-02 06:54:11 +04:00
if ( compat_convert_timespec ( & u_ts , u_abs_timeout ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
return sys_mq_timedreceive ( mqdes , u_msg_ptr , msg_len ,
u_msg_prio , u_ts ) ;
}
2014-03-04 14:17:50 +04:00
COMPAT_SYSCALL_DEFINE2 ( mq_notify , mqd_t , mqdes ,
const struct compat_sigevent __user * , u_notification )
2005-04-17 02:20:36 +04:00
{
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 ) ;
}
2014-03-04 14:17:50 +04:00
COMPAT_SYSCALL_DEFINE3 ( mq_getsetattr , mqd_t , mqdes ,
const struct compat_mq_attr __user * , u_mqstat ,
struct compat_mq_attr __user * , u_omqstat )
2005-04-17 02:20:36 +04:00
{
struct mq_attr mqstat ;
struct mq_attr __user * p = compat_alloc_user_space ( 2 * sizeof ( * p ) ) ;
long ret ;
2010-10-28 02:34:17 +04:00
memset ( & mqstat , 0 , sizeof ( mqstat ) ) ;
2005-04-17 02:20:36 +04:00
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 ;
}