aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/util.c')
-rw-r--r--ipc/util.c131
1 files changed, 122 insertions, 9 deletions
diff --git a/ipc/util.c b/ipc/util.c
index fd1b50da9db8..3339177b336c 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -33,6 +33,7 @@
33#include <linux/audit.h> 33#include <linux/audit.h>
34#include <linux/nsproxy.h> 34#include <linux/nsproxy.h>
35#include <linux/rwsem.h> 35#include <linux/rwsem.h>
36#include <linux/memory.h>
36#include <linux/ipc_namespace.h> 37#include <linux/ipc_namespace.h>
37 38
38#include <asm/unistd.h> 39#include <asm/unistd.h>
@@ -52,11 +53,57 @@ struct ipc_namespace init_ipc_ns = {
52 }, 53 },
53}; 54};
54 55
56atomic_t nr_ipc_ns = ATOMIC_INIT(1);
57
58
59#ifdef CONFIG_MEMORY_HOTPLUG
60
61static void ipc_memory_notifier(struct work_struct *work)
62{
63 ipcns_notify(IPCNS_MEMCHANGED);
64}
65
66static DECLARE_WORK(ipc_memory_wq, ipc_memory_notifier);
67
68
69static int ipc_memory_callback(struct notifier_block *self,
70 unsigned long action, void *arg)
71{
72 switch (action) {
73 case MEM_ONLINE: /* memory successfully brought online */
74 case MEM_OFFLINE: /* or offline: it's time to recompute msgmni */
75 /*
76 * This is done by invoking the ipcns notifier chain with the
77 * IPC_MEMCHANGED event.
78 * In order not to keep the lock on the hotplug memory chain
79 * for too long, queue a work item that will, when waken up,
80 * activate the ipcns notification chain.
81 * No need to keep several ipc work items on the queue.
82 */
83 if (!work_pending(&ipc_memory_wq))
84 schedule_work(&ipc_memory_wq);
85 break;
86 case MEM_GOING_ONLINE:
87 case MEM_GOING_OFFLINE:
88 case MEM_CANCEL_ONLINE:
89 case MEM_CANCEL_OFFLINE:
90 default:
91 break;
92 }
93
94 return NOTIFY_OK;
95}
96
97#endif /* CONFIG_MEMORY_HOTPLUG */
98
55/** 99/**
56 * ipc_init - initialise IPC subsystem 100 * ipc_init - initialise IPC subsystem
57 * 101 *
58 * The various system5 IPC resources (semaphores, messages and shared 102 * The various system5 IPC resources (semaphores, messages and shared
59 * memory) are initialised 103 * memory) are initialised
104 * A callback routine is registered into the memory hotplug notifier
105 * chain: since msgmni scales to lowmem this callback routine will be
106 * called upon successful memory add / remove to recompute msmgni.
60 */ 107 */
61 108
62static int __init ipc_init(void) 109static int __init ipc_init(void)
@@ -64,6 +111,8 @@ static int __init ipc_init(void)
64 sem_init(); 111 sem_init();
65 msg_init(); 112 msg_init();
66 shm_init(); 113 shm_init();
114 hotplug_memory_notifier(ipc_memory_callback, IPC_CALLBACK_PRI);
115 register_ipcns_notifier(&init_ipc_ns);
67 return 0; 116 return 0;
68} 117}
69__initcall(ipc_init); 118__initcall(ipc_init);
@@ -84,8 +133,8 @@ void ipc_init_ids(struct ipc_ids *ids)
84 ids->seq = 0; 133 ids->seq = 0;
85 { 134 {
86 int seq_limit = INT_MAX/SEQ_MULTIPLIER; 135 int seq_limit = INT_MAX/SEQ_MULTIPLIER;
87 if(seq_limit > USHRT_MAX) 136 if (seq_limit > USHORT_MAX)
88 ids->seq_max = USHRT_MAX; 137 ids->seq_max = USHORT_MAX;
89 else 138 else
90 ids->seq_max = seq_limit; 139 ids->seq_max = seq_limit;
91 } 140 }
@@ -116,13 +165,12 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
116 iface->ids = ids; 165 iface->ids = ids;
117 iface->show = show; 166 iface->show = show;
118 167
119 pde = create_proc_entry(path, 168 pde = proc_create_data(path,
120 S_IRUGO, /* world readable */ 169 S_IRUGO, /* world readable */
121 NULL /* parent dir */); 170 NULL, /* parent dir */
122 if (pde) { 171 &sysvipc_proc_fops,
123 pde->data = iface; 172 iface);
124 pde->proc_fops = &sysvipc_proc_fops; 173 if (!pde) {
125 } else {
126 kfree(iface); 174 kfree(iface);
127 } 175 }
128} 176}
@@ -231,6 +279,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
231 if(ids->seq > ids->seq_max) 279 if(ids->seq > ids->seq_max)
232 ids->seq = 0; 280 ids->seq = 0;
233 281
282 new->id = ipc_buildid(id, new->seq);
234 spin_lock_init(&new->lock); 283 spin_lock_init(&new->lock);
235 new->deleted = 0; 284 new->deleted = 0;
236 rcu_read_lock(); 285 rcu_read_lock();
@@ -761,6 +810,70 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
761 return ipcget_public(ns, ids, ops, params); 810 return ipcget_public(ns, ids, ops, params);
762} 811}
763 812
813/**
814 * ipc_update_perm - update the permissions of an IPC.
815 * @in: the permission given as input.
816 * @out: the permission of the ipc to set.
817 */
818void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
819{
820 out->uid = in->uid;
821 out->gid = in->gid;
822 out->mode = (out->mode & ~S_IRWXUGO)
823 | (in->mode & S_IRWXUGO);
824}
825
826/**
827 * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd
828 * @ids: the table of ids where to look for the ipc
829 * @id: the id of the ipc to retrieve
830 * @cmd: the cmd to check
831 * @perm: the permission to set
832 * @extra_perm: one extra permission parameter used by msq
833 *
834 * This function does some common audit and permissions check for some IPC_XXX
835 * cmd and is called from semctl_down, shmctl_down and msgctl_down.
836 * It must be called without any lock held and
837 * - retrieves the ipc with the given id in the given table.
838 * - performs some audit and permission check, depending on the given cmd
839 * - returns the ipc with both ipc and rw_mutex locks held in case of success
840 * or an err-code without any lock held otherwise.
841 */
842struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
843 struct ipc64_perm *perm, int extra_perm)
844{
845 struct kern_ipc_perm *ipcp;
846 int err;
847
848 down_write(&ids->rw_mutex);
849 ipcp = ipc_lock_check_down(ids, id);
850 if (IS_ERR(ipcp)) {
851 err = PTR_ERR(ipcp);
852 goto out_up;
853 }
854
855 err = audit_ipc_obj(ipcp);
856 if (err)
857 goto out_unlock;
858
859 if (cmd == IPC_SET) {
860 err = audit_ipc_set_perm(extra_perm, perm->uid,
861 perm->gid, perm->mode);
862 if (err)
863 goto out_unlock;
864 }
865 if (current->euid == ipcp->cuid ||
866 current->euid == ipcp->uid || capable(CAP_SYS_ADMIN))
867 return ipcp;
868
869 err = -EPERM;
870out_unlock:
871 ipc_unlock(ipcp);
872out_up:
873 up_write(&ids->rw_mutex);
874 return ERR_PTR(err);
875}
876
764#ifdef __ARCH_WANT_IPC_PARSE_VERSION 877#ifdef __ARCH_WANT_IPC_PARSE_VERSION
765 878
766 879