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/malloc.h>
21 #include <linux/highuid.h>
23 #if defined(CONFIG_SYSVIPC)
28 * ipc_init - initialise IPC subsystem
30 * The various system5 IPC resources (semaphores, messages and shared
31 * memory are initialised
34 void __init
ipc_init (void)
43 * ipc_init_ids - initialise IPC identifiers
44 * @ids: Identifier set
45 * @size: Number of identifiers
47 * Given a size for the ipc identifier range (limited below IPCMNI)
48 * set up the sequence range to use then allocate and initialise the
52 void __init
ipc_init_ids(struct ipc_ids
* ids
, int size
)
55 sema_init(&ids
->sem
,1);
64 int seq_limit
= INT_MAX
/SEQ_MULTIPLIER
;
65 if(seq_limit
> USHRT_MAX
)
66 ids
->seq_max
= USHRT_MAX
;
68 ids
->seq_max
= seq_limit
;
71 ids
->entries
= ipc_alloc(sizeof(struct ipc_id
)*size
);
73 if(ids
->entries
== NULL
) {
74 printk(KERN_ERR
"ipc_init_ids() failed, ipc service disabled.\n");
77 ids
->ary
= SPIN_LOCK_UNLOCKED
;
79 ids
->entries
[i
].p
= NULL
;
83 * ipc_findkey - find a key in an ipc identifier set
84 * @ids: Identifier set
85 * @key: The key to find
87 * Returns the identifier if found or -1 if not.
90 int ipc_findkey(struct ipc_ids
* ids
, key_t key
)
93 struct kern_ipc_perm
* p
;
95 for (id
= 0; id
<= ids
->max_id
; id
++) {
96 p
= ids
->entries
[id
].p
;
105 static int grow_ary(struct ipc_ids
* ids
, int newsize
)
113 if(newsize
<= ids
->size
)
116 new = ipc_alloc(sizeof(struct ipc_id
)*newsize
);
119 memcpy(new, ids
->entries
, sizeof(struct ipc_id
)*ids
->size
);
120 for(i
=ids
->size
;i
<newsize
;i
++) {
123 spin_lock(&ids
->ary
);
129 spin_unlock(&ids
->ary
);
130 ipc_free(old
, sizeof(struct ipc_id
)*i
);
135 * ipc_addid - add an IPC identifier
136 * @ids: IPC identifier set
137 * @new: new IPC permission set
138 * @size: new size limit for the id array
140 * Add an entry 'new' to the IPC arrays. The permissions object is
141 * initialised and the first free entry is set up and the id assigned
142 * is returned. The list is returned in a locked state on success.
143 * On failure the list is not locked and -1 is returned.
146 int ipc_addid(struct ipc_ids
* ids
, struct kern_ipc_perm
* new, int size
)
150 size
= grow_ary(ids
,size
);
151 for (id
= 0; id
< size
; id
++) {
152 if(ids
->entries
[id
].p
== NULL
)
158 if (id
> ids
->max_id
)
161 new->cuid
= new->uid
= current
->euid
;
162 new->gid
= new->cgid
= current
->egid
;
164 new->seq
= ids
->seq
++;
165 if(ids
->seq
> ids
->seq_max
)
168 spin_lock(&ids
->ary
);
169 ids
->entries
[id
].p
= new;
174 * ipc_rmid - remove an IPC identifier
175 * @ids: identifier set
176 * @id: Identifier to remove
178 * The identifier must be valid, and in use. The kernel will panic if
179 * fed an invalid identifier. The entry is removed and internal
180 * variables recomputed. The object associated with the identifier
184 struct kern_ipc_perm
* ipc_rmid(struct ipc_ids
* ids
, int id
)
186 struct kern_ipc_perm
* p
;
187 int lid
= id
% SEQ_MULTIPLIER
;
190 p
= ids
->entries
[lid
].p
;
191 ids
->entries
[lid
].p
= NULL
;
196 if (lid
== ids
->max_id
) {
201 } while (ids
->entries
[lid
].p
== NULL
);
208 * ipc_alloc - allocate ipc space
209 * @size: size desired
211 * Allocate memory from the appropriate pools and return a pointer to it.
212 * NULL is returned if the allocation fails
215 void* ipc_alloc(int size
)
221 out
= kmalloc(size
, GFP_KERNEL
);
226 * ipc_free - free ipc space
227 * @ptr: pointer returned by ipc_alloc
228 * @size: size of block
230 * Free a block created with ipc_alloc. The caller must know the size
231 * used in the allocation call.
234 void ipc_free(void* ptr
, int size
)
243 * ipcperms - check IPC permissions
244 * @ipcp: IPC permission set
245 * @flag: desired permission set.
247 * Check user, group, other permissions for access
248 * to ipc resources. return 0 if allowed
251 int ipcperms (struct kern_ipc_perm
*ipcp
, short flag
)
252 { /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
253 int requested_mode
, granted_mode
;
255 requested_mode
= (flag
>> 6) | (flag
>> 3) | flag
;
256 granted_mode
= ipcp
->mode
;
257 if (current
->euid
== ipcp
->cuid
|| current
->euid
== ipcp
->uid
)
259 else if (in_group_p(ipcp
->cgid
) || in_group_p(ipcp
->gid
))
261 /* is there some bit set in requested_mode but not in granted_mode? */
262 if ((requested_mode
& ~granted_mode
& 0007) &&
263 !capable(CAP_IPC_OWNER
))
270 * Functions to convert between the kern_ipc_perm structure and the
271 * old/new ipc_perm structures
275 * kernel_to_ipc64_perm - convert kernel ipc permissions to user
276 * @in: kernel permissions
277 * @out: new style IPC permissions
279 * Turn the kernel object 'in' into a set of permissions descriptions
280 * for returning to userspace (out).
284 void kernel_to_ipc64_perm (struct kern_ipc_perm
*in
, struct ipc64_perm
*out
)
289 out
->cuid
= in
->cuid
;
290 out
->cgid
= in
->cgid
;
291 out
->mode
= in
->mode
;
296 * ipc64_perm_to_ipc_perm - convert old ipc permissions to new
297 * @in: new style IPC permissions
298 * @out: old style IPC permissions
300 * Turn the new style permissions object in into a compatibility
301 * object and store it into the 'out' pointer.
304 void ipc64_perm_to_ipc_perm (struct ipc64_perm
*in
, struct ipc_perm
*out
)
307 out
->uid
= NEW_TO_OLD_UID(in
->uid
);
308 out
->gid
= NEW_TO_OLD_GID(in
->gid
);
309 out
->cuid
= NEW_TO_OLD_UID(in
->cuid
);
310 out
->cgid
= NEW_TO_OLD_GID(in
->cgid
);
311 out
->mode
= in
->mode
;
316 * ipc_parse_version - IPC call version
317 * @cmd: pointer to command
319 * Return IPC_64 for new style IPC and IPC_OLD for old style IPC.
320 * The cmd value is turned from an encoding command and version into
321 * just the command code.
324 int ipc_parse_version (int *cmd
)
336 * Dummy functions when SYSV IPC isn't configured
344 int shm_swap (int prio
, int gfp_mask
)
349 asmlinkage
long sys_semget (key_t key
, int nsems
, int semflg
)
354 asmlinkage
long sys_semop (int semid
, struct sembuf
*sops
, unsigned nsops
)
359 asmlinkage
long sys_semctl (int semid
, int semnum
, int cmd
, union semun arg
)
364 asmlinkage
long sys_msgget (key_t key
, int msgflg
)
369 asmlinkage
long sys_msgsnd (int msqid
, struct msgbuf
*msgp
, size_t msgsz
, int msgflg
)
374 asmlinkage
long sys_msgrcv (int msqid
, struct msgbuf
*msgp
, size_t msgsz
, long msgtyp
,
380 asmlinkage
long sys_msgctl (int msqid
, int cmd
, struct msqid_ds
*buf
)
385 asmlinkage
long sys_shmget (key_t key
, size_t size
, int shmflag
)
390 asmlinkage
long sys_shmat (int shmid
, char *shmaddr
, int shmflg
, ulong
*addr
)
395 asmlinkage
long sys_shmdt (char *shmaddr
)
400 asmlinkage
long sys_shmctl (int shmid
, int cmd
, struct shmid_ds
*buf
)
405 void shm_unuse(swp_entry_t entry
, struct page
*page
)
409 int map_zero_setup(struct vm_area_struct
*vma
)
414 #endif /* CONFIG_SYSVIPC */