diff options
-rw-r--r-- | include/linux/ipc_namespace.h | 39 | ||||
-rw-r--r-- | init/Kconfig | 4 | ||||
-rw-r--r-- | ipc/mqueue.c | 124 | ||||
-rw-r--r-- | ipc/msgutil.c | 22 | ||||
-rw-r--r-- | ipc/namespace.c | 2 | ||||
-rw-r--r-- | ipc/util.c | 9 | ||||
-rw-r--r-- | ipc/util.h | 16 |
7 files changed, 145 insertions, 71 deletions
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h index ea330f9e7100..3e6fcacebe8a 100644 --- a/include/linux/ipc_namespace.h +++ b/include/linux/ipc_namespace.h | |||
@@ -44,24 +44,55 @@ struct ipc_namespace { | |||
44 | int shm_tot; | 44 | int shm_tot; |
45 | 45 | ||
46 | struct notifier_block ipcns_nb; | 46 | struct notifier_block ipcns_nb; |
47 | |||
48 | /* The kern_mount of the mqueuefs sb. We take a ref on it */ | ||
49 | struct vfsmount *mq_mnt; | ||
50 | |||
51 | /* # queues in this ns, protected by mq_lock */ | ||
52 | unsigned int mq_queues_count; | ||
53 | |||
54 | /* next fields are set through sysctl */ | ||
55 | unsigned int mq_queues_max; /* initialized to DFLT_QUEUESMAX */ | ||
56 | unsigned int mq_msg_max; /* initialized to DFLT_MSGMAX */ | ||
57 | unsigned int mq_msgsize_max; /* initialized to DFLT_MSGSIZEMAX */ | ||
58 | |||
47 | }; | 59 | }; |
48 | 60 | ||
49 | extern struct ipc_namespace init_ipc_ns; | 61 | extern struct ipc_namespace init_ipc_ns; |
50 | extern atomic_t nr_ipc_ns; | 62 | extern atomic_t nr_ipc_ns; |
51 | 63 | ||
52 | #ifdef CONFIG_SYSVIPC | 64 | #if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC) |
53 | #define INIT_IPC_NS(ns) .ns = &init_ipc_ns, | 65 | #define INIT_IPC_NS(ns) .ns = &init_ipc_ns, |
66 | #else | ||
67 | #define INIT_IPC_NS(ns) | ||
68 | #endif | ||
54 | 69 | ||
70 | #ifdef CONFIG_SYSVIPC | ||
55 | extern int register_ipcns_notifier(struct ipc_namespace *); | 71 | extern int register_ipcns_notifier(struct ipc_namespace *); |
56 | extern int cond_register_ipcns_notifier(struct ipc_namespace *); | 72 | extern int cond_register_ipcns_notifier(struct ipc_namespace *); |
57 | extern void unregister_ipcns_notifier(struct ipc_namespace *); | 73 | extern void unregister_ipcns_notifier(struct ipc_namespace *); |
58 | extern int ipcns_notify(unsigned long); | 74 | extern int ipcns_notify(unsigned long); |
59 | |||
60 | #else /* CONFIG_SYSVIPC */ | 75 | #else /* CONFIG_SYSVIPC */ |
61 | #define INIT_IPC_NS(ns) | 76 | static inline int register_ipcns_notifier(struct ipc_namespace *ns) |
77 | { return 0; } | ||
78 | static inline int cond_register_ipcns_notifier(struct ipc_namespace *ns) | ||
79 | { return 0; } | ||
80 | static inline void unregister_ipcns_notifier(struct ipc_namespace *ns) { } | ||
81 | static inline int ipcns_notify(unsigned long l) { return 0; } | ||
62 | #endif /* CONFIG_SYSVIPC */ | 82 | #endif /* CONFIG_SYSVIPC */ |
63 | 83 | ||
64 | #if defined(CONFIG_SYSVIPC) && defined(CONFIG_IPC_NS) | 84 | #ifdef CONFIG_POSIX_MQUEUE |
85 | extern void mq_init_ns(struct ipc_namespace *ns); | ||
86 | /* default values */ | ||
87 | #define DFLT_QUEUESMAX 256 /* max number of message queues */ | ||
88 | #define DFLT_MSGMAX 10 /* max number of messages in each queue */ | ||
89 | #define HARD_MSGMAX (131072/sizeof(void *)) | ||
90 | #define DFLT_MSGSIZEMAX 8192 /* max message size */ | ||
91 | #else | ||
92 | #define mq_init_ns(ns) ((void) 0) | ||
93 | #endif | ||
94 | |||
95 | #if defined(CONFIG_IPC_NS) | ||
65 | extern void free_ipc_ns(struct kref *kref); | 96 | extern void free_ipc_ns(struct kref *kref); |
66 | extern struct ipc_namespace *copy_ipcs(unsigned long flags, | 97 | extern struct ipc_namespace *copy_ipcs(unsigned long flags, |
67 | struct ipc_namespace *ns); | 98 | struct ipc_namespace *ns); |
diff --git a/init/Kconfig b/init/Kconfig index c52d1d48272a..a0807ba91644 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -670,10 +670,10 @@ config UTS_NS | |||
670 | 670 | ||
671 | config IPC_NS | 671 | config IPC_NS |
672 | bool "IPC namespace" | 672 | bool "IPC namespace" |
673 | depends on NAMESPACES && SYSVIPC | 673 | depends on NAMESPACES && (SYSVIPC || POSIX_MQUEUE) |
674 | help | 674 | help |
675 | In this namespace tasks work with IPC ids which correspond to | 675 | In this namespace tasks work with IPC ids which correspond to |
676 | different IPC objects in different namespaces | 676 | different IPC objects in different namespaces. |
677 | 677 | ||
678 | config USER_NS | 678 | config USER_NS |
679 | bool "User namespace (EXPERIMENTAL)" | 679 | bool "User namespace (EXPERIMENTAL)" |
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 916785363f0f..a3673a09069a 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <linux/nsproxy.h> | 32 | #include <linux/nsproxy.h> |
33 | #include <linux/pid.h> | 33 | #include <linux/pid.h> |
34 | #include <linux/ipc_namespace.h> | ||
34 | 35 | ||
35 | #include <net/sock.h> | 36 | #include <net/sock.h> |
36 | #include "util.h" | 37 | #include "util.h" |
@@ -46,12 +47,6 @@ | |||
46 | #define STATE_PENDING 1 | 47 | #define STATE_PENDING 1 |
47 | #define STATE_READY 2 | 48 | #define STATE_READY 2 |
48 | 49 | ||
49 | /* default values */ | ||
50 | #define DFLT_QUEUESMAX 256 /* max number of message queues */ | ||
51 | #define DFLT_MSGMAX 10 /* max number of messages in each queue */ | ||
52 | #define HARD_MSGMAX (131072/sizeof(void*)) | ||
53 | #define DFLT_MSGSIZEMAX 8192 /* max message size */ | ||
54 | |||
55 | /* | 50 | /* |
56 | * Define the ranges various user-specified maximum values can | 51 | * Define the ranges various user-specified maximum values can |
57 | * be set to. | 52 | * be set to. |
@@ -95,12 +90,6 @@ static void remove_notification(struct mqueue_inode_info *info); | |||
95 | 90 | ||
96 | static spinlock_t mq_lock; | 91 | static spinlock_t mq_lock; |
97 | static struct kmem_cache *mqueue_inode_cachep; | 92 | static struct kmem_cache *mqueue_inode_cachep; |
98 | static struct vfsmount *mqueue_mnt; | ||
99 | |||
100 | static unsigned int queues_count; | ||
101 | static unsigned int queues_max = DFLT_QUEUESMAX; | ||
102 | static unsigned int msg_max = DFLT_MSGMAX; | ||
103 | static unsigned int msgsize_max = DFLT_MSGSIZEMAX; | ||
104 | 93 | ||
105 | static struct ctl_table_header * mq_sysctl_table; | 94 | static struct ctl_table_header * mq_sysctl_table; |
106 | 95 | ||
@@ -109,11 +98,27 @@ static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode) | |||
109 | return container_of(inode, struct mqueue_inode_info, vfs_inode); | 98 | return container_of(inode, struct mqueue_inode_info, vfs_inode); |
110 | } | 99 | } |
111 | 100 | ||
101 | void mq_init_ns(struct ipc_namespace *ns) | ||
102 | { | ||
103 | ns->mq_queues_count = 0; | ||
104 | ns->mq_queues_max = DFLT_QUEUESMAX; | ||
105 | ns->mq_msg_max = DFLT_MSGMAX; | ||
106 | ns->mq_msgsize_max = DFLT_MSGSIZEMAX; | ||
107 | ns->mq_mnt = mntget(init_ipc_ns.mq_mnt); | ||
108 | } | ||
109 | |||
110 | void mq_exit_ns(struct ipc_namespace *ns) | ||
111 | { | ||
112 | /* will need to clear out ns->mq_mnt->mnt_sb->s_fs_info here */ | ||
113 | mntput(ns->mq_mnt); | ||
114 | } | ||
115 | |||
112 | static struct inode *mqueue_get_inode(struct super_block *sb, int mode, | 116 | static struct inode *mqueue_get_inode(struct super_block *sb, int mode, |
113 | struct mq_attr *attr) | 117 | struct mq_attr *attr) |
114 | { | 118 | { |
115 | struct user_struct *u = current_user(); | 119 | struct user_struct *u = current_user(); |
116 | struct inode *inode; | 120 | struct inode *inode; |
121 | struct ipc_namespace *ipc_ns = &init_ipc_ns; | ||
117 | 122 | ||
118 | inode = new_inode(sb); | 123 | inode = new_inode(sb); |
119 | if (inode) { | 124 | if (inode) { |
@@ -141,8 +146,8 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, | |||
141 | info->qsize = 0; | 146 | info->qsize = 0; |
142 | info->user = NULL; /* set when all is ok */ | 147 | info->user = NULL; /* set when all is ok */ |
143 | memset(&info->attr, 0, sizeof(info->attr)); | 148 | memset(&info->attr, 0, sizeof(info->attr)); |
144 | info->attr.mq_maxmsg = msg_max; | 149 | info->attr.mq_maxmsg = ipc_ns->mq_msg_max; |
145 | info->attr.mq_msgsize = msgsize_max; | 150 | info->attr.mq_msgsize = ipc_ns->mq_msgsize_max; |
146 | if (attr) { | 151 | if (attr) { |
147 | info->attr.mq_maxmsg = attr->mq_maxmsg; | 152 | info->attr.mq_maxmsg = attr->mq_maxmsg; |
148 | info->attr.mq_msgsize = attr->mq_msgsize; | 153 | info->attr.mq_msgsize = attr->mq_msgsize; |
@@ -242,6 +247,7 @@ static void mqueue_delete_inode(struct inode *inode) | |||
242 | struct user_struct *user; | 247 | struct user_struct *user; |
243 | unsigned long mq_bytes; | 248 | unsigned long mq_bytes; |
244 | int i; | 249 | int i; |
250 | struct ipc_namespace *ipc_ns = &init_ipc_ns; | ||
245 | 251 | ||
246 | if (S_ISDIR(inode->i_mode)) { | 252 | if (S_ISDIR(inode->i_mode)) { |
247 | clear_inode(inode); | 253 | clear_inode(inode); |
@@ -262,7 +268,7 @@ static void mqueue_delete_inode(struct inode *inode) | |||
262 | if (user) { | 268 | if (user) { |
263 | spin_lock(&mq_lock); | 269 | spin_lock(&mq_lock); |
264 | user->mq_bytes -= mq_bytes; | 270 | user->mq_bytes -= mq_bytes; |
265 | queues_count--; | 271 | ipc_ns->mq_queues_count--; |
266 | spin_unlock(&mq_lock); | 272 | spin_unlock(&mq_lock); |
267 | free_uid(user); | 273 | free_uid(user); |
268 | } | 274 | } |
@@ -274,21 +280,23 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry, | |||
274 | struct inode *inode; | 280 | struct inode *inode; |
275 | struct mq_attr *attr = dentry->d_fsdata; | 281 | struct mq_attr *attr = dentry->d_fsdata; |
276 | int error; | 282 | int error; |
283 | struct ipc_namespace *ipc_ns = &init_ipc_ns; | ||
277 | 284 | ||
278 | spin_lock(&mq_lock); | 285 | spin_lock(&mq_lock); |
279 | if (queues_count >= queues_max && !capable(CAP_SYS_RESOURCE)) { | 286 | if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max && |
287 | !capable(CAP_SYS_RESOURCE)) { | ||
280 | error = -ENOSPC; | 288 | error = -ENOSPC; |
281 | goto out_lock; | 289 | goto out_unlock; |
282 | } | 290 | } |
283 | queues_count++; | 291 | ipc_ns->mq_queues_count++; |
284 | spin_unlock(&mq_lock); | 292 | spin_unlock(&mq_lock); |
285 | 293 | ||
286 | inode = mqueue_get_inode(dir->i_sb, mode, attr); | 294 | inode = mqueue_get_inode(dir->i_sb, mode, attr); |
287 | if (!inode) { | 295 | if (!inode) { |
288 | error = -ENOMEM; | 296 | error = -ENOMEM; |
289 | spin_lock(&mq_lock); | 297 | spin_lock(&mq_lock); |
290 | queues_count--; | 298 | ipc_ns->mq_queues_count--; |
291 | goto out_lock; | 299 | goto out_unlock; |
292 | } | 300 | } |
293 | 301 | ||
294 | dir->i_size += DIRENT_SIZE; | 302 | dir->i_size += DIRENT_SIZE; |
@@ -297,7 +305,7 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry, | |||
297 | d_instantiate(dentry, inode); | 305 | d_instantiate(dentry, inode); |
298 | dget(dentry); | 306 | dget(dentry); |
299 | return 0; | 307 | return 0; |
300 | out_lock: | 308 | out_unlock: |
301 | spin_unlock(&mq_lock); | 309 | spin_unlock(&mq_lock); |
302 | return error; | 310 | return error; |
303 | } | 311 | } |
@@ -562,7 +570,7 @@ static void remove_notification(struct mqueue_inode_info *info) | |||
562 | info->notify_owner = NULL; | 570 | info->notify_owner = NULL; |
563 | } | 571 | } |
564 | 572 | ||
565 | static int mq_attr_ok(struct mq_attr *attr) | 573 | static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr) |
566 | { | 574 | { |
567 | if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) | 575 | if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) |
568 | return 0; | 576 | return 0; |
@@ -570,8 +578,8 @@ static int mq_attr_ok(struct mq_attr *attr) | |||
570 | if (attr->mq_maxmsg > HARD_MSGMAX) | 578 | if (attr->mq_maxmsg > HARD_MSGMAX) |
571 | return 0; | 579 | return 0; |
572 | } else { | 580 | } else { |
573 | if (attr->mq_maxmsg > msg_max || | 581 | if (attr->mq_maxmsg > ipc_ns->mq_msg_max || |
574 | attr->mq_msgsize > msgsize_max) | 582 | attr->mq_msgsize > ipc_ns->mq_msgsize_max) |
575 | return 0; | 583 | return 0; |
576 | } | 584 | } |
577 | /* check for overflow */ | 585 | /* check for overflow */ |
@@ -587,8 +595,9 @@ static int mq_attr_ok(struct mq_attr *attr) | |||
587 | /* | 595 | /* |
588 | * Invoked when creating a new queue via sys_mq_open | 596 | * Invoked when creating a new queue via sys_mq_open |
589 | */ | 597 | */ |
590 | static struct file *do_create(struct dentry *dir, struct dentry *dentry, | 598 | static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir, |
591 | int oflag, mode_t mode, struct mq_attr *attr) | 599 | struct dentry *dentry, int oflag, mode_t mode, |
600 | struct mq_attr *attr) | ||
592 | { | 601 | { |
593 | const struct cred *cred = current_cred(); | 602 | const struct cred *cred = current_cred(); |
594 | struct file *result; | 603 | struct file *result; |
@@ -596,14 +605,14 @@ static struct file *do_create(struct dentry *dir, struct dentry *dentry, | |||
596 | 605 | ||
597 | if (attr) { | 606 | if (attr) { |
598 | ret = -EINVAL; | 607 | ret = -EINVAL; |
599 | if (!mq_attr_ok(attr)) | 608 | if (!mq_attr_ok(ipc_ns, attr)) |
600 | goto out; | 609 | goto out; |
601 | /* store for use during create */ | 610 | /* store for use during create */ |
602 | dentry->d_fsdata = attr; | 611 | dentry->d_fsdata = attr; |
603 | } | 612 | } |
604 | 613 | ||
605 | mode &= ~current_umask(); | 614 | mode &= ~current_umask(); |
606 | ret = mnt_want_write(mqueue_mnt); | 615 | ret = mnt_want_write(ipc_ns->mq_mnt); |
607 | if (ret) | 616 | if (ret) |
608 | goto out; | 617 | goto out; |
609 | ret = vfs_create(dir->d_inode, dentry, mode, NULL); | 618 | ret = vfs_create(dir->d_inode, dentry, mode, NULL); |
@@ -611,24 +620,25 @@ static struct file *do_create(struct dentry *dir, struct dentry *dentry, | |||
611 | if (ret) | 620 | if (ret) |
612 | goto out_drop_write; | 621 | goto out_drop_write; |
613 | 622 | ||
614 | result = dentry_open(dentry, mqueue_mnt, oflag, cred); | 623 | result = dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred); |
615 | /* | 624 | /* |
616 | * dentry_open() took a persistent mnt_want_write(), | 625 | * dentry_open() took a persistent mnt_want_write(), |
617 | * so we can now drop this one. | 626 | * so we can now drop this one. |
618 | */ | 627 | */ |
619 | mnt_drop_write(mqueue_mnt); | 628 | mnt_drop_write(ipc_ns->mq_mnt); |
620 | return result; | 629 | return result; |
621 | 630 | ||
622 | out_drop_write: | 631 | out_drop_write: |
623 | mnt_drop_write(mqueue_mnt); | 632 | mnt_drop_write(ipc_ns->mq_mnt); |
624 | out: | 633 | out: |
625 | dput(dentry); | 634 | dput(dentry); |
626 | mntput(mqueue_mnt); | 635 | mntput(ipc_ns->mq_mnt); |
627 | return ERR_PTR(ret); | 636 | return ERR_PTR(ret); |
628 | } | 637 | } |
629 | 638 | ||
630 | /* Opens existing queue */ | 639 | /* Opens existing queue */ |
631 | static struct file *do_open(struct dentry *dentry, int oflag) | 640 | static struct file *do_open(struct ipc_namespace *ipc_ns, |
641 | struct dentry *dentry, int oflag) | ||
632 | { | 642 | { |
633 | const struct cred *cred = current_cred(); | 643 | const struct cred *cred = current_cred(); |
634 | 644 | ||
@@ -637,17 +647,17 @@ static struct file *do_open(struct dentry *dentry, int oflag) | |||
637 | 647 | ||
638 | if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) { | 648 | if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) { |
639 | dput(dentry); | 649 | dput(dentry); |
640 | mntput(mqueue_mnt); | 650 | mntput(ipc_ns->mq_mnt); |
641 | return ERR_PTR(-EINVAL); | 651 | return ERR_PTR(-EINVAL); |
642 | } | 652 | } |
643 | 653 | ||
644 | if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) { | 654 | if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) { |
645 | dput(dentry); | 655 | dput(dentry); |
646 | mntput(mqueue_mnt); | 656 | mntput(ipc_ns->mq_mnt); |
647 | return ERR_PTR(-EACCES); | 657 | return ERR_PTR(-EACCES); |
648 | } | 658 | } |
649 | 659 | ||
650 | return dentry_open(dentry, mqueue_mnt, oflag, cred); | 660 | return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred); |
651 | } | 661 | } |
652 | 662 | ||
653 | SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, | 663 | SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, |
@@ -658,6 +668,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, | |||
658 | char *name; | 668 | char *name; |
659 | struct mq_attr attr; | 669 | struct mq_attr attr; |
660 | int fd, error; | 670 | int fd, error; |
671 | struct ipc_namespace *ipc_ns = &init_ipc_ns; | ||
661 | 672 | ||
662 | if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) | 673 | if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) |
663 | return -EFAULT; | 674 | return -EFAULT; |
@@ -671,13 +682,13 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, | |||
671 | if (fd < 0) | 682 | if (fd < 0) |
672 | goto out_putname; | 683 | goto out_putname; |
673 | 684 | ||
674 | mutex_lock(&mqueue_mnt->mnt_root->d_inode->i_mutex); | 685 | mutex_lock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); |
675 | dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name)); | 686 | dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name)); |
676 | if (IS_ERR(dentry)) { | 687 | if (IS_ERR(dentry)) { |
677 | error = PTR_ERR(dentry); | 688 | error = PTR_ERR(dentry); |
678 | goto out_err; | 689 | goto out_err; |
679 | } | 690 | } |
680 | mntget(mqueue_mnt); | 691 | mntget(ipc_ns->mq_mnt); |
681 | 692 | ||
682 | if (oflag & O_CREAT) { | 693 | if (oflag & O_CREAT) { |
683 | if (dentry->d_inode) { /* entry already exists */ | 694 | if (dentry->d_inode) { /* entry already exists */ |
@@ -685,10 +696,10 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, | |||
685 | error = -EEXIST; | 696 | error = -EEXIST; |
686 | if (oflag & O_EXCL) | 697 | if (oflag & O_EXCL) |
687 | goto out; | 698 | goto out; |
688 | filp = do_open(dentry, oflag); | 699 | filp = do_open(ipc_ns, dentry, oflag); |
689 | } else { | 700 | } else { |
690 | filp = do_create(mqueue_mnt->mnt_root, dentry, | 701 | filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root, |
691 | oflag, mode, | 702 | dentry, oflag, mode, |
692 | u_attr ? &attr : NULL); | 703 | u_attr ? &attr : NULL); |
693 | } | 704 | } |
694 | } else { | 705 | } else { |
@@ -696,7 +707,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, | |||
696 | if (!dentry->d_inode) | 707 | if (!dentry->d_inode) |
697 | goto out; | 708 | goto out; |
698 | audit_inode(name, dentry); | 709 | audit_inode(name, dentry); |
699 | filp = do_open(dentry, oflag); | 710 | filp = do_open(ipc_ns, dentry, oflag); |
700 | } | 711 | } |
701 | 712 | ||
702 | if (IS_ERR(filp)) { | 713 | if (IS_ERR(filp)) { |
@@ -709,13 +720,13 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, | |||
709 | 720 | ||
710 | out: | 721 | out: |
711 | dput(dentry); | 722 | dput(dentry); |
712 | mntput(mqueue_mnt); | 723 | mntput(ipc_ns->mq_mnt); |
713 | out_putfd: | 724 | out_putfd: |
714 | put_unused_fd(fd); | 725 | put_unused_fd(fd); |
715 | out_err: | 726 | out_err: |
716 | fd = error; | 727 | fd = error; |
717 | out_upsem: | 728 | out_upsem: |
718 | mutex_unlock(&mqueue_mnt->mnt_root->d_inode->i_mutex); | 729 | mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); |
719 | out_putname: | 730 | out_putname: |
720 | putname(name); | 731 | putname(name); |
721 | return fd; | 732 | return fd; |
@@ -727,14 +738,15 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) | |||
727 | char *name; | 738 | char *name; |
728 | struct dentry *dentry; | 739 | struct dentry *dentry; |
729 | struct inode *inode = NULL; | 740 | struct inode *inode = NULL; |
741 | struct ipc_namespace *ipc_ns = &init_ipc_ns; | ||
730 | 742 | ||
731 | name = getname(u_name); | 743 | name = getname(u_name); |
732 | if (IS_ERR(name)) | 744 | if (IS_ERR(name)) |
733 | return PTR_ERR(name); | 745 | return PTR_ERR(name); |
734 | 746 | ||
735 | mutex_lock_nested(&mqueue_mnt->mnt_root->d_inode->i_mutex, | 747 | mutex_lock_nested(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex, |
736 | I_MUTEX_PARENT); | 748 | I_MUTEX_PARENT); |
737 | dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name)); | 749 | dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name)); |
738 | if (IS_ERR(dentry)) { | 750 | if (IS_ERR(dentry)) { |
739 | err = PTR_ERR(dentry); | 751 | err = PTR_ERR(dentry); |
740 | goto out_unlock; | 752 | goto out_unlock; |
@@ -748,16 +760,16 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) | |||
748 | inode = dentry->d_inode; | 760 | inode = dentry->d_inode; |
749 | if (inode) | 761 | if (inode) |
750 | atomic_inc(&inode->i_count); | 762 | atomic_inc(&inode->i_count); |
751 | err = mnt_want_write(mqueue_mnt); | 763 | err = mnt_want_write(ipc_ns->mq_mnt); |
752 | if (err) | 764 | if (err) |
753 | goto out_err; | 765 | goto out_err; |
754 | err = vfs_unlink(dentry->d_parent->d_inode, dentry); | 766 | err = vfs_unlink(dentry->d_parent->d_inode, dentry); |
755 | mnt_drop_write(mqueue_mnt); | 767 | mnt_drop_write(ipc_ns->mq_mnt); |
756 | out_err: | 768 | out_err: |
757 | dput(dentry); | 769 | dput(dentry); |
758 | 770 | ||
759 | out_unlock: | 771 | out_unlock: |
760 | mutex_unlock(&mqueue_mnt->mnt_root->d_inode->i_mutex); | 772 | mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); |
761 | putname(name); | 773 | putname(name); |
762 | if (inode) | 774 | if (inode) |
763 | iput(inode); | 775 | iput(inode); |
@@ -1214,14 +1226,14 @@ static int msg_maxsize_limit_max = MAX_MSGSIZEMAX; | |||
1214 | static ctl_table mq_sysctls[] = { | 1226 | static ctl_table mq_sysctls[] = { |
1215 | { | 1227 | { |
1216 | .procname = "queues_max", | 1228 | .procname = "queues_max", |
1217 | .data = &queues_max, | 1229 | .data = &init_ipc_ns.mq_queues_max, |
1218 | .maxlen = sizeof(int), | 1230 | .maxlen = sizeof(int), |
1219 | .mode = 0644, | 1231 | .mode = 0644, |
1220 | .proc_handler = &proc_dointvec, | 1232 | .proc_handler = &proc_dointvec, |
1221 | }, | 1233 | }, |
1222 | { | 1234 | { |
1223 | .procname = "msg_max", | 1235 | .procname = "msg_max", |
1224 | .data = &msg_max, | 1236 | .data = &init_ipc_ns.mq_msg_max, |
1225 | .maxlen = sizeof(int), | 1237 | .maxlen = sizeof(int), |
1226 | .mode = 0644, | 1238 | .mode = 0644, |
1227 | .proc_handler = &proc_dointvec_minmax, | 1239 | .proc_handler = &proc_dointvec_minmax, |
@@ -1230,7 +1242,7 @@ static ctl_table mq_sysctls[] = { | |||
1230 | }, | 1242 | }, |
1231 | { | 1243 | { |
1232 | .procname = "msgsize_max", | 1244 | .procname = "msgsize_max", |
1233 | .data = &msgsize_max, | 1245 | .data = &init_ipc_ns.mq_msgsize_max, |
1234 | .maxlen = sizeof(int), | 1246 | .maxlen = sizeof(int), |
1235 | .mode = 0644, | 1247 | .mode = 0644, |
1236 | .proc_handler = &proc_dointvec_minmax, | 1248 | .proc_handler = &proc_dointvec_minmax, |
@@ -1276,13 +1288,13 @@ static int __init init_mqueue_fs(void) | |||
1276 | if (error) | 1288 | if (error) |
1277 | goto out_sysctl; | 1289 | goto out_sysctl; |
1278 | 1290 | ||
1279 | if (IS_ERR(mqueue_mnt = kern_mount(&mqueue_fs_type))) { | 1291 | init_ipc_ns.mq_mnt = kern_mount(&mqueue_fs_type); |
1280 | error = PTR_ERR(mqueue_mnt); | 1292 | if (IS_ERR(init_ipc_ns.mq_mnt)) { |
1293 | error = PTR_ERR(init_ipc_ns.mq_mnt); | ||
1281 | goto out_filesystem; | 1294 | goto out_filesystem; |
1282 | } | 1295 | } |
1283 | 1296 | ||
1284 | /* internal initialization - not common for vfs */ | 1297 | /* internal initialization - not common for vfs */ |
1285 | queues_count = 0; | ||
1286 | spin_lock_init(&mq_lock); | 1298 | spin_lock_init(&mq_lock); |
1287 | 1299 | ||
1288 | return 0; | 1300 | return 0; |
diff --git a/ipc/msgutil.c b/ipc/msgutil.c index c82c215693d7..73c316cb8613 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c | |||
@@ -13,10 +13,32 @@ | |||
13 | #include <linux/security.h> | 13 | #include <linux/security.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/ipc.h> | 15 | #include <linux/ipc.h> |
16 | #include <linux/ipc_namespace.h> | ||
16 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
17 | 18 | ||
18 | #include "util.h" | 19 | #include "util.h" |
19 | 20 | ||
21 | /* | ||
22 | * The next 2 defines are here bc this is the only file | ||
23 | * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE | ||
24 | * and not CONFIG_IPC_NS. | ||
25 | */ | ||
26 | struct ipc_namespace init_ipc_ns = { | ||
27 | .kref = { | ||
28 | /* It's not for this patch to change, but should this be 1? */ | ||
29 | .refcount = ATOMIC_INIT(2), | ||
30 | }, | ||
31 | #ifdef CONFIG_POSIX_MQUEUE | ||
32 | .mq_mnt = NULL, | ||
33 | .mq_queues_count = 0, | ||
34 | .mq_queues_max = DFLT_QUEUESMAX, | ||
35 | .mq_msg_max = DFLT_MSGMAX, | ||
36 | .mq_msgsize_max = DFLT_MSGSIZEMAX, | ||
37 | #endif | ||
38 | }; | ||
39 | |||
40 | atomic_t nr_ipc_ns = ATOMIC_INIT(1); | ||
41 | |||
20 | struct msg_msgseg { | 42 | struct msg_msgseg { |
21 | struct msg_msgseg* next; | 43 | struct msg_msgseg* next; |
22 | /* the next part of the message follows immediately */ | 44 | /* the next part of the message follows immediately */ |
diff --git a/ipc/namespace.c b/ipc/namespace.c index 9171d948751e..4b4dc6d847f1 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c | |||
@@ -25,6 +25,7 @@ static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns) | |||
25 | sem_init_ns(ns); | 25 | sem_init_ns(ns); |
26 | msg_init_ns(ns); | 26 | msg_init_ns(ns); |
27 | shm_init_ns(ns); | 27 | shm_init_ns(ns); |
28 | mq_init_ns(ns); | ||
28 | 29 | ||
29 | /* | 30 | /* |
30 | * msgmni has already been computed for the new ipc ns. | 31 | * msgmni has already been computed for the new ipc ns. |
@@ -101,6 +102,7 @@ void free_ipc_ns(struct kref *kref) | |||
101 | sem_exit_ns(ns); | 102 | sem_exit_ns(ns); |
102 | msg_exit_ns(ns); | 103 | msg_exit_ns(ns); |
103 | shm_exit_ns(ns); | 104 | shm_exit_ns(ns); |
105 | mq_exit_ns(ns); | ||
104 | kfree(ns); | 106 | kfree(ns); |
105 | atomic_dec(&nr_ipc_ns); | 107 | atomic_dec(&nr_ipc_ns); |
106 | 108 | ||
diff --git a/ipc/util.c b/ipc/util.c index 7585a72e259b..b8e4ba92f6d1 100644 --- a/ipc/util.c +++ b/ipc/util.c | |||
@@ -47,15 +47,6 @@ struct ipc_proc_iface { | |||
47 | int (*show)(struct seq_file *, void *); | 47 | int (*show)(struct seq_file *, void *); |
48 | }; | 48 | }; |
49 | 49 | ||
50 | struct ipc_namespace init_ipc_ns = { | ||
51 | .kref = { | ||
52 | .refcount = ATOMIC_INIT(2), | ||
53 | }, | ||
54 | }; | ||
55 | |||
56 | atomic_t nr_ipc_ns = ATOMIC_INIT(1); | ||
57 | |||
58 | |||
59 | #ifdef CONFIG_MEMORY_HOTPLUG | 50 | #ifdef CONFIG_MEMORY_HOTPLUG |
60 | 51 | ||
61 | static void ipc_memory_notifier(struct work_struct *work) | 52 | static void ipc_memory_notifier(struct work_struct *work) |
diff --git a/ipc/util.h b/ipc/util.h index 3646b45a03c9..0e7d9223acc1 100644 --- a/ipc/util.h +++ b/ipc/util.h | |||
@@ -20,6 +20,13 @@ void shm_init (void); | |||
20 | 20 | ||
21 | struct ipc_namespace; | 21 | struct ipc_namespace; |
22 | 22 | ||
23 | #ifdef CONFIG_POSIX_MQUEUE | ||
24 | void mq_exit_ns(struct ipc_namespace *ns); | ||
25 | #else | ||
26 | static inline void mq_exit_ns(struct ipc_namespace *ns) { } | ||
27 | #endif | ||
28 | |||
29 | #ifdef CONFIG_SYSVIPC | ||
23 | void sem_init_ns(struct ipc_namespace *ns); | 30 | void sem_init_ns(struct ipc_namespace *ns); |
24 | void msg_init_ns(struct ipc_namespace *ns); | 31 | void msg_init_ns(struct ipc_namespace *ns); |
25 | void shm_init_ns(struct ipc_namespace *ns); | 32 | void shm_init_ns(struct ipc_namespace *ns); |
@@ -27,6 +34,15 @@ void shm_init_ns(struct ipc_namespace *ns); | |||
27 | void sem_exit_ns(struct ipc_namespace *ns); | 34 | void sem_exit_ns(struct ipc_namespace *ns); |
28 | void msg_exit_ns(struct ipc_namespace *ns); | 35 | void msg_exit_ns(struct ipc_namespace *ns); |
29 | void shm_exit_ns(struct ipc_namespace *ns); | 36 | void shm_exit_ns(struct ipc_namespace *ns); |
37 | #else | ||
38 | static inline void sem_init_ns(struct ipc_namespace *ns) { } | ||
39 | static inline void msg_init_ns(struct ipc_namespace *ns) { } | ||
40 | static inline void shm_init_ns(struct ipc_namespace *ns) { } | ||
41 | |||
42 | static inline void sem_exit_ns(struct ipc_namespace *ns) { } | ||
43 | static inline void msg_exit_ns(struct ipc_namespace *ns) { } | ||
44 | static inline void shm_exit_ns(struct ipc_namespace *ns) { } | ||
45 | #endif | ||
30 | 46 | ||
31 | /* | 47 | /* |
32 | * Structure that holds the parameters needed by the ipc operations | 48 | * Structure that holds the parameters needed by the ipc operations |