3 * Copyright (C) 1992 Krishna Balasubramanian
5 * Sep 1997 - Call suser() last after "normal" permission checks so we
6 * get BSD style process accounting right.
7 * Occurs in several places in the IPC code.
8 * Chris Evans, <chris@ferret.lmh.ox.ac.uk>
9 * Nov 1999 - ipc helper functions, unified SMP locking
10 * Manfred Spraul <manfreds@colorfullife.com>
13 #include <linux/config.h>
15 #include <linux/shm.h>
16 #include <linux/init.h>
17 #include <linux/msg.h>
18 #include <linux/smp_lock.h>
19 #include <linux/vmalloc.h>
20 #include <linux/slab.h>
21 #include <linux/highuid.h>
22 #include <linux/security.h>
24 #if defined(CONFIG_SYSVIPC)
29 * ipc_init - initialise IPC subsystem
31 * The various system5 IPC resources (semaphores, messages and shared
32 * memory are initialised
35 void __init
ipc_init (void)
44 * ipc_init_ids - initialise IPC identifiers
45 * @ids: Identifier set
46 * @size: Number of identifiers
48 * Given a size for the ipc identifier range (limited below IPCMNI)
49 * set up the sequence range to use then allocate and initialise the
53 void __init
ipc_init_ids(struct ipc_ids
* ids
, int size
)
56 sema_init(&ids
->sem
,1);
65 int seq_limit
= INT_MAX
/SEQ_MULTIPLIER
;
66 if(seq_limit
> USHRT_MAX
)
67 ids
->seq_max
= USHRT_MAX
;
69 ids
->seq_max
= seq_limit
;
72 ids
->entries
= ipc_alloc(sizeof(struct ipc_id
)*size
);
74 if(ids
->entries
== NULL
) {
75 printk(KERN_ERR
"ipc_init_ids() failed, ipc service disabled.\n");
78 ids
->ary
= SPIN_LOCK_UNLOCKED
;
79 for(i
=0;i
<ids
->size
;i
++)
80 ids
->entries
[i
].p
= NULL
;
84 * ipc_findkey - find a key in an ipc identifier set
85 * @ids: Identifier set
86 * @key: The key to find
88 * Returns the identifier if found or -1 if not.
91 int ipc_findkey(struct ipc_ids
* ids
, key_t key
)
94 struct kern_ipc_perm
* p
;
96 for (id
= 0; id
<= ids
->max_id
; id
++) {
97 p
= ids
->entries
[id
].p
;
106 static int grow_ary(struct ipc_ids
* ids
, int newsize
)
114 if(newsize
<= ids
->size
)
117 new = ipc_alloc(sizeof(struct ipc_id
)*newsize
);
120 memcpy(new, ids
->entries
, sizeof(struct ipc_id
)*ids
->size
);
121 for(i
=ids
->size
;i
<newsize
;i
++) {
124 spin_lock(&ids
->ary
);
130 spin_unlock(&ids
->ary
);
131 ipc_free(old
, sizeof(struct ipc_id
)*i
);
136 * ipc_addid - add an IPC identifier
137 * @ids: IPC identifier set
138 * @new: new IPC permission set
139 * @size: new size limit for the id array
141 * Add an entry 'new' to the IPC arrays. The permissions object is
142 * initialised and the first free entry is set up and the id assigned
143 * is returned. The list is returned in a locked state on success.
144 * On failure the list is not locked and -1 is returned.
147 int ipc_addid(struct ipc_ids
* ids
, struct kern_ipc_perm
* new, int size
)
151 size
= grow_ary(ids
,size
);
152 for (id
= 0; id
< size
; id
++) {
153 if(ids
->entries
[id
].p
== NULL
)
159 if (id
> ids
->max_id
)
162 new->cuid
= new->uid
= current
->euid
;
163 new->gid
= new->cgid
= current
->egid
;
165 new->seq
= ids
->seq
++;
166 if(ids
->seq
> ids
->seq_max
)
169 spin_lock(&ids
->ary
);
170 ids
->entries
[id
].p
= new;
175 * ipc_rmid - remove an IPC identifier
176 * @ids: identifier set
177 * @id: Identifier to remove
179 * The identifier must be valid, and in use. The kernel will panic if
180 * fed an invalid identifier. The entry is removed and internal
181 * variables recomputed. The object associated with the identifier
185 struct kern_ipc_perm
* ipc_rmid(struct ipc_ids
* ids
, int id
)
187 struct kern_ipc_perm
* p
;
188 int lid
= id
% SEQ_MULTIPLIER
;
191 p
= ids
->entries
[lid
].p
;
192 ids
->entries
[lid
].p
= NULL
;
197 if (lid
== ids
->max_id
) {
202 } while (ids
->entries
[lid
].p
== NULL
);
209 * ipc_alloc - allocate ipc space
210 * @size: size desired
212 * Allocate memory from the appropriate pools and return a pointer to it.
213 * NULL is returned if the allocation fails
216 void* ipc_alloc(int size
)
222 out
= kmalloc(size
, GFP_KERNEL
);
227 * ipc_free - free ipc space
228 * @ptr: pointer returned by ipc_alloc
229 * @size: size of block
231 * Free a block created with ipc_alloc. The caller must know the size
232 * used in the allocation call.
235 void ipc_free(void* ptr
, int size
)
244 * ipcperms - check IPC permissions
245 * @ipcp: IPC permission set
246 * @flag: desired permission set.
248 * Check user, group, other permissions for access
249 * to ipc resources. return 0 if allowed
252 int ipcperms (struct kern_ipc_perm
*ipcp
, short flag
)
253 { /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
254 int requested_mode
, granted_mode
;
256 requested_mode
= (flag
>> 6) | (flag
>> 3) | flag
;
257 granted_mode
= ipcp
->mode
;
258 if (current
->euid
== ipcp
->cuid
|| current
->euid
== ipcp
->uid
)
260 else if (in_group_p(ipcp
->cgid
) || in_group_p(ipcp
->gid
))
262 /* is there some bit set in requested_mode but not in granted_mode? */
263 if ((requested_mode
& ~granted_mode
& 0007) &&
264 !capable(CAP_IPC_OWNER
))
267 return security_ops
->ipc_permission(ipcp
, flag
);
271 * Functions to convert between the kern_ipc_perm structure and the
272 * old/new ipc_perm structures
276 * kernel_to_ipc64_perm - convert kernel ipc permissions to user
277 * @in: kernel permissions
278 * @out: new style IPC permissions
280 * Turn the kernel object 'in' into a set of permissions descriptions
281 * for returning to userspace (out).
285 void kernel_to_ipc64_perm (struct kern_ipc_perm
*in
, struct ipc64_perm
*out
)
290 out
->cuid
= in
->cuid
;
291 out
->cgid
= in
->cgid
;
292 out
->mode
= in
->mode
;
297 * ipc64_perm_to_ipc_perm - convert old ipc permissions to new
298 * @in: new style IPC permissions
299 * @out: old style IPC permissions
301 * Turn the new style permissions object in into a compatibility
302 * object and store it into the 'out' pointer.
305 void ipc64_perm_to_ipc_perm (struct ipc64_perm
*in
, struct ipc_perm
*out
)
308 out
->uid
= NEW_TO_OLD_UID(in
->uid
);
309 out
->gid
= NEW_TO_OLD_GID(in
->gid
);
310 out
->cuid
= NEW_TO_OLD_UID(in
->cuid
);
311 out
->cgid
= NEW_TO_OLD_GID(in
->cgid
);
312 out
->mode
= in
->mode
;
319 * ipc_parse_version - IPC call version
320 * @cmd: pointer to command
322 * Return IPC_64 for new style IPC and IPC_OLD for old style IPC.
323 * The cmd value is turned from an encoding command and version into
324 * just the command code.
327 int ipc_parse_version (int *cmd
)
337 #endif /* __ia64__ */
341 * Dummy functions when SYSV IPC isn't configured
344 int copy_semundo(unsigned long clone_flags
, struct task_struct
*tsk
)
349 void exit_semundo(struct task_struct
*tsk
)
360 asmlinkage
long sys_semget (key_t key
, int nsems
, int semflg
)
365 asmlinkage
long sys_semop (int semid
, struct sembuf
*sops
, unsigned nsops
)
370 asmlinkage
long sys_semctl (int semid
, int semnum
, int cmd
, union semun arg
)
375 asmlinkage
long sys_msgget (key_t key
, int msgflg
)
380 asmlinkage
long sys_msgsnd (int msqid
, struct msgbuf
*msgp
, size_t msgsz
, int msgflg
)
385 asmlinkage
long sys_msgrcv (int msqid
, struct msgbuf
*msgp
, size_t msgsz
, long msgtyp
,
391 asmlinkage
long sys_msgctl (int msqid
, int cmd
, struct msqid_ds
*buf
)
396 asmlinkage
long sys_shmget (key_t key
, size_t size
, int shmflag
)
401 asmlinkage
long sys_shmat (int shmid
, char *shmaddr
, int shmflg
, ulong
*addr
)
406 asmlinkage
long sys_shmdt (char *shmaddr
)
411 asmlinkage
long sys_shmctl (int shmid
, int cmd
, struct shmid_ds
*buf
)
416 #endif /* CONFIG_SYSVIPC */