// SPDX-License-Identifier: GPL-2.01/*2* linux/ipc/util.c3* Copyright (C) 1992 Krishna Balasubramanian4*5* Sep 1997 - Call suser() last after "normal" permission checks so we6* get BSD style process accounting right.7* Occurs in several places in the IPC code.8* Chris Evans, <[email protected]>9* Nov 1999 - ipc helper functions, unified SMP locking10* Manfred Spraul <[email protected]>11* Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary().12* Mingming Cao <[email protected]>13* Mar 2006 - support for audit of ipc object properties14* Dustin Kirkland <[email protected]>15* Jun 2006 - namespaces ssupport16* OpenVZ, SWsoft Inc.17* Pavel Emelianov <[email protected]>18*19* General sysv ipc locking scheme:20* rcu_read_lock()21* obtain the ipc object (kern_ipc_perm) by looking up the id in an idr22* tree.23* - perform initial checks (capabilities, auditing and permission,24* etc).25* - perform read-only operations, such as INFO command, that26* do not demand atomicity27* acquire the ipc lock (kern_ipc_perm.lock) through28* ipc_lock_object()29* - perform read-only operations that demand atomicity,30* such as STAT command.31* - perform data updates, such as SET, RMID commands and32* mechanism-specific operations (semop/semtimedop,33* msgsnd/msgrcv, shmat/shmdt).34* drop the ipc lock, through ipc_unlock_object().35* rcu_read_unlock()36*37* The ids->rwsem must be taken when:38* - creating, removing and iterating the existing entries in ipc39* identifier sets.40* - iterating through files under /proc/sysvipc/41*42* Note that sems have a special fast path that avoids kern_ipc_perm.lock -43* see sem_lock().44*/4546#include <linux/mm.h>47#include <linux/shm.h>48#include <linux/init.h>49#include <linux/msg.h>50#include <linux/vmalloc.h>51#include <linux/slab.h>52#include <linux/notifier.h>53#include <linux/capability.h>54#include <linux/highuid.h>55#include <linux/security.h>56#include <linux/rcupdate.h>57#include <linux/workqueue.h>58#include <linux/seq_file.h>59#include <linux/proc_fs.h>60#include <linux/audit.h>61#include <linux/nsproxy.h>62#include <linux/rwsem.h>63#include <linux/memory.h>64#include <linux/ipc_namespace.h>65#include <linux/rhashtable.h>66#include <linux/log2.h>6768#include <asm/unistd.h>6970#include "util.h"7172struct ipc_proc_iface {73const char *path;74const char *header;75int ids;76int (*show)(struct seq_file *, void *);77};7879/**80* ipc_init - initialise ipc subsystem81*82* The various sysv ipc resources (semaphores, messages and shared83* memory) are initialised.84*85* A callback routine is registered into the memory hotplug notifier86* chain: since msgmni scales to lowmem this callback routine will be87* called upon successful memory add / remove to recompute msmgni.88*/89static int __init ipc_init(void)90{91proc_mkdir("sysvipc", NULL);92sem_init();93msg_init();94shm_init();9596return 0;97}98device_initcall(ipc_init);99100static const struct rhashtable_params ipc_kht_params = {101.head_offset = offsetof(struct kern_ipc_perm, khtnode),102.key_offset = offsetof(struct kern_ipc_perm, key),103.key_len = sizeof_field(struct kern_ipc_perm, key),104.automatic_shrinking = true,105};106107/**108* ipc_init_ids - initialise ipc identifiers109* @ids: ipc identifier set110*111* Set up the sequence range to use for the ipc identifier range (limited112* below ipc_mni) then initialise the keys hashtable and ids idr.113*/114void ipc_init_ids(struct ipc_ids *ids)115{116ids->in_use = 0;117ids->seq = 0;118init_rwsem(&ids->rwsem);119rhashtable_init(&ids->key_ht, &ipc_kht_params);120idr_init(&ids->ipcs_idr);121ids->max_idx = -1;122ids->last_idx = -1;123#ifdef CONFIG_CHECKPOINT_RESTORE124ids->next_id = -1;125#endif126}127128#ifdef CONFIG_PROC_FS129static const struct proc_ops sysvipc_proc_ops;130/**131* ipc_init_proc_interface - create a proc interface for sysipc types using a seq_file interface.132* @path: Path in procfs133* @header: Banner to be printed at the beginning of the file.134* @ids: ipc id table to iterate.135* @show: show routine.136*/137void __init ipc_init_proc_interface(const char *path, const char *header,138int ids, int (*show)(struct seq_file *, void *))139{140struct proc_dir_entry *pde;141struct ipc_proc_iface *iface;142143iface = kmalloc(sizeof(*iface), GFP_KERNEL);144if (!iface)145return;146iface->path = path;147iface->header = header;148iface->ids = ids;149iface->show = show;150151pde = proc_create_data(path,152S_IRUGO, /* world readable */153NULL, /* parent dir */154&sysvipc_proc_ops,155iface);156if (!pde)157kfree(iface);158}159#endif160161/**162* ipc_findkey - find a key in an ipc identifier set163* @ids: ipc identifier set164* @key: key to find165*166* Returns the locked pointer to the ipc structure if found or NULL167* otherwise. If key is found ipc points to the owning ipc structure168*169* Called with writer ipc_ids.rwsem held.170*/171static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)172{173struct kern_ipc_perm *ipcp;174175ipcp = rhashtable_lookup_fast(&ids->key_ht, &key,176ipc_kht_params);177if (!ipcp)178return NULL;179180rcu_read_lock();181ipc_lock_object(ipcp);182return ipcp;183}184185/*186* Insert new IPC object into idr tree, and set sequence number and id187* in the correct order.188* Especially:189* - the sequence number must be set before inserting the object into the idr,190* because the sequence number is accessed without a lock.191* - the id can/must be set after inserting the object into the idr.192* All accesses must be done after getting kern_ipc_perm.lock.193*194* The caller must own kern_ipc_perm.lock.of the new object.195* On error, the function returns a (negative) error code.196*197* To conserve sequence number space, especially with extended ipc_mni,198* the sequence number is incremented only when the returned ID is less than199* the last one.200*/201static inline int ipc_idr_alloc(struct ipc_ids *ids, struct kern_ipc_perm *new)202{203int idx, next_id = -1;204205#ifdef CONFIG_CHECKPOINT_RESTORE206next_id = ids->next_id;207ids->next_id = -1;208#endif209210/*211* As soon as a new object is inserted into the idr,212* ipc_obtain_object_idr() or ipc_obtain_object_check() can find it,213* and the lockless preparations for ipc operations can start.214* This means especially: permission checks, audit calls, allocation215* of undo structures, ...216*217* Thus the object must be fully initialized, and if something fails,218* then the full tear-down sequence must be followed.219* (i.e.: set new->deleted, reduce refcount, call_rcu())220*/221222if (next_id < 0) { /* !CHECKPOINT_RESTORE or next_id is unset */223int max_idx;224225max_idx = max(ids->in_use*3/2, ipc_min_cycle);226max_idx = min(max_idx, ipc_mni);227228/* allocate the idx, with a NULL struct kern_ipc_perm */229idx = idr_alloc_cyclic(&ids->ipcs_idr, NULL, 0, max_idx,230GFP_NOWAIT);231232if (idx >= 0) {233/*234* idx got allocated successfully.235* Now calculate the sequence number and set the236* pointer for real.237*/238if (idx <= ids->last_idx) {239ids->seq++;240if (ids->seq >= ipcid_seq_max())241ids->seq = 0;242}243ids->last_idx = idx;244245new->seq = ids->seq;246/* no need for smp_wmb(), this is done247* inside idr_replace, as part of248* rcu_assign_pointer249*/250idr_replace(&ids->ipcs_idr, new, idx);251}252} else {253new->seq = ipcid_to_seqx(next_id);254idx = idr_alloc(&ids->ipcs_idr, new, ipcid_to_idx(next_id),2550, GFP_NOWAIT);256}257if (idx >= 0)258new->id = (new->seq << ipcmni_seq_shift()) + idx;259return idx;260}261262/**263* ipc_addid - add an ipc identifier264* @ids: ipc identifier set265* @new: new ipc permission set266* @limit: limit for the number of used ids267*268* Add an entry 'new' to the ipc ids idr. The permissions object is269* initialised and the first free entry is set up and the index assigned270* is returned. The 'new' entry is returned in a locked state on success.271*272* On failure the entry is not locked and a negative err-code is returned.273* The caller must use ipc_rcu_putref() to free the identifier.274*275* Called with writer ipc_ids.rwsem held.276*/277int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)278{279kuid_t euid;280kgid_t egid;281int idx, err;282283/* 1) Initialize the refcount so that ipc_rcu_putref works */284refcount_set(&new->refcount, 1);285286if (limit > ipc_mni)287limit = ipc_mni;288289if (ids->in_use >= limit)290return -ENOSPC;291292idr_preload(GFP_KERNEL);293294spin_lock_init(&new->lock);295rcu_read_lock();296spin_lock(&new->lock);297298current_euid_egid(&euid, &egid);299new->cuid = new->uid = euid;300new->gid = new->cgid = egid;301302new->deleted = false;303304idx = ipc_idr_alloc(ids, new);305idr_preload_end();306307if (idx >= 0 && new->key != IPC_PRIVATE) {308err = rhashtable_insert_fast(&ids->key_ht, &new->khtnode,309ipc_kht_params);310if (err < 0) {311idr_remove(&ids->ipcs_idr, idx);312idx = err;313}314}315if (idx < 0) {316new->deleted = true;317spin_unlock(&new->lock);318rcu_read_unlock();319return idx;320}321322ids->in_use++;323if (idx > ids->max_idx)324ids->max_idx = idx;325return idx;326}327328/**329* ipcget_new - create a new ipc object330* @ns: ipc namespace331* @ids: ipc identifier set332* @ops: the actual creation routine to call333* @params: its parameters334*335* This routine is called by sys_msgget, sys_semget() and sys_shmget()336* when the key is IPC_PRIVATE.337*/338static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,339const struct ipc_ops *ops, struct ipc_params *params)340{341int err;342343down_write(&ids->rwsem);344err = ops->getnew(ns, params);345up_write(&ids->rwsem);346return err;347}348349/**350* ipc_check_perms - check security and permissions for an ipc object351* @ns: ipc namespace352* @ipcp: ipc permission set353* @ops: the actual security routine to call354* @params: its parameters355*356* This routine is called by sys_msgget(), sys_semget() and sys_shmget()357* when the key is not IPC_PRIVATE and that key already exists in the358* ds IDR.359*360* On success, the ipc id is returned.361*362* It is called with ipc_ids.rwsem and ipcp->lock held.363*/364static int ipc_check_perms(struct ipc_namespace *ns,365struct kern_ipc_perm *ipcp,366const struct ipc_ops *ops,367struct ipc_params *params)368{369int err;370371if (ipcperms(ns, ipcp, params->flg))372err = -EACCES;373else {374err = ops->associate(ipcp, params->flg);375if (!err)376err = ipcp->id;377}378379return err;380}381382/**383* ipcget_public - get an ipc object or create a new one384* @ns: ipc namespace385* @ids: ipc identifier set386* @ops: the actual creation routine to call387* @params: its parameters388*389* This routine is called by sys_msgget, sys_semget() and sys_shmget()390* when the key is not IPC_PRIVATE.391* It adds a new entry if the key is not found and does some permission392* / security checkings if the key is found.393*394* On success, the ipc id is returned.395*/396static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,397const struct ipc_ops *ops, struct ipc_params *params)398{399struct kern_ipc_perm *ipcp;400int flg = params->flg;401int err;402403/*404* Take the lock as a writer since we are potentially going to add405* a new entry + read locks are not "upgradable"406*/407down_write(&ids->rwsem);408ipcp = ipc_findkey(ids, params->key);409if (ipcp == NULL) {410/* key not used */411if (!(flg & IPC_CREAT))412err = -ENOENT;413else414err = ops->getnew(ns, params);415} else {416/* ipc object has been locked by ipc_findkey() */417418if (flg & IPC_CREAT && flg & IPC_EXCL)419err = -EEXIST;420else {421err = 0;422if (ops->more_checks)423err = ops->more_checks(ipcp, params);424if (!err)425/*426* ipc_check_perms returns the IPC id on427* success428*/429err = ipc_check_perms(ns, ipcp, ops, params);430}431ipc_unlock(ipcp);432}433up_write(&ids->rwsem);434435return err;436}437438/**439* ipc_kht_remove - remove an ipc from the key hashtable440* @ids: ipc identifier set441* @ipcp: ipc perm structure containing the key to remove442*443* ipc_ids.rwsem (as a writer) and the spinlock for this ID are held444* before this function is called, and remain locked on the exit.445*/446static void ipc_kht_remove(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)447{448if (ipcp->key != IPC_PRIVATE)449WARN_ON_ONCE(rhashtable_remove_fast(&ids->key_ht, &ipcp->khtnode,450ipc_kht_params));451}452453/**454* ipc_search_maxidx - search for the highest assigned index455* @ids: ipc identifier set456* @limit: known upper limit for highest assigned index457*458* The function determines the highest assigned index in @ids. It is intended459* to be called when ids->max_idx needs to be updated.460* Updating ids->max_idx is necessary when the current highest index ipc461* object is deleted.462* If no ipc object is allocated, then -1 is returned.463*464* ipc_ids.rwsem needs to be held by the caller.465*/466static int ipc_search_maxidx(struct ipc_ids *ids, int limit)467{468int tmpidx;469int i;470int retval;471472i = ilog2(limit+1);473474retval = 0;475for (; i >= 0; i--) {476tmpidx = retval | (1<<i);477/*478* "0" is a possible index value, thus search using479* e.g. 15,7,3,1,0 instead of 16,8,4,2,1.480*/481tmpidx = tmpidx-1;482if (idr_get_next(&ids->ipcs_idr, &tmpidx))483retval |= (1<<i);484}485return retval - 1;486}487488/**489* ipc_rmid - remove an ipc identifier490* @ids: ipc identifier set491* @ipcp: ipc perm structure containing the identifier to remove492*493* ipc_ids.rwsem (as a writer) and the spinlock for this ID are held494* before this function is called, and remain locked on the exit.495*/496void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)497{498int idx = ipcid_to_idx(ipcp->id);499500WARN_ON_ONCE(idr_remove(&ids->ipcs_idr, idx) != ipcp);501ipc_kht_remove(ids, ipcp);502ids->in_use--;503ipcp->deleted = true;504505if (unlikely(idx == ids->max_idx)) {506idx = ids->max_idx-1;507if (idx >= 0)508idx = ipc_search_maxidx(ids, idx);509ids->max_idx = idx;510}511}512513/**514* ipc_set_key_private - switch the key of an existing ipc to IPC_PRIVATE515* @ids: ipc identifier set516* @ipcp: ipc perm structure containing the key to modify517*518* ipc_ids.rwsem (as a writer) and the spinlock for this ID are held519* before this function is called, and remain locked on the exit.520*/521void ipc_set_key_private(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)522{523ipc_kht_remove(ids, ipcp);524ipcp->key = IPC_PRIVATE;525}526527bool ipc_rcu_getref(struct kern_ipc_perm *ptr)528{529return refcount_inc_not_zero(&ptr->refcount);530}531532void ipc_rcu_putref(struct kern_ipc_perm *ptr,533void (*func)(struct rcu_head *head))534{535if (!refcount_dec_and_test(&ptr->refcount))536return;537538call_rcu(&ptr->rcu, func);539}540541/**542* ipcperms - check ipc permissions543* @ns: ipc namespace544* @ipcp: ipc permission set545* @flag: desired permission set546*547* Check user, group, other permissions for access548* to ipc resources. return 0 if allowed549*550* @flag will most probably be 0 or ``S_...UGO`` from <linux/stat.h>551*/552int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)553{554kuid_t euid = current_euid();555int requested_mode, granted_mode;556557audit_ipc_obj(ipcp);558requested_mode = (flag >> 6) | (flag >> 3) | flag;559granted_mode = ipcp->mode;560if (uid_eq(euid, ipcp->cuid) ||561uid_eq(euid, ipcp->uid))562granted_mode >>= 6;563else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))564granted_mode >>= 3;565/* is there some bit set in requested_mode but not in granted_mode? */566if ((requested_mode & ~granted_mode & 0007) &&567!ns_capable(ns->user_ns, CAP_IPC_OWNER))568return -1;569570return security_ipc_permission(ipcp, flag);571}572573/*574* Functions to convert between the kern_ipc_perm structure and the575* old/new ipc_perm structures576*/577578/**579* kernel_to_ipc64_perm - convert kernel ipc permissions to user580* @in: kernel permissions581* @out: new style ipc permissions582*583* Turn the kernel object @in into a set of permissions descriptions584* for returning to userspace (@out).585*/586void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out)587{588out->key = in->key;589out->uid = from_kuid_munged(current_user_ns(), in->uid);590out->gid = from_kgid_munged(current_user_ns(), in->gid);591out->cuid = from_kuid_munged(current_user_ns(), in->cuid);592out->cgid = from_kgid_munged(current_user_ns(), in->cgid);593out->mode = in->mode;594out->seq = in->seq;595}596597/**598* ipc64_perm_to_ipc_perm - convert new ipc permissions to old599* @in: new style ipc permissions600* @out: old style ipc permissions601*602* Turn the new style permissions object @in into a compatibility603* object and store it into the @out pointer.604*/605void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out)606{607out->key = in->key;608SET_UID(out->uid, in->uid);609SET_GID(out->gid, in->gid);610SET_UID(out->cuid, in->cuid);611SET_GID(out->cgid, in->cgid);612out->mode = in->mode;613out->seq = in->seq;614}615616/**617* ipc_obtain_object_idr - Look for an id in the ipc ids idr and618* return associated ipc object.619* @ids: ipc identifier set620* @id: ipc id to look for621*622* Call inside the RCU critical section.623* The ipc object is *not* locked on exit.624*/625struct kern_ipc_perm *ipc_obtain_object_idr(struct ipc_ids *ids, int id)626{627struct kern_ipc_perm *out;628int idx = ipcid_to_idx(id);629630out = idr_find(&ids->ipcs_idr, idx);631if (!out)632return ERR_PTR(-EINVAL);633634return out;635}636637/**638* ipc_obtain_object_check - Similar to ipc_obtain_object_idr() but639* also checks the ipc object sequence number.640* @ids: ipc identifier set641* @id: ipc id to look for642*643* Call inside the RCU critical section.644* The ipc object is *not* locked on exit.645*/646struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id)647{648struct kern_ipc_perm *out = ipc_obtain_object_idr(ids, id);649650if (IS_ERR(out))651goto out;652653if (ipc_checkid(out, id))654return ERR_PTR(-EINVAL);655out:656return out;657}658659/**660* ipcget - Common sys_*get() code661* @ns: namespace662* @ids: ipc identifier set663* @ops: operations to be called on ipc object creation, permission checks664* and further checks665* @params: the parameters needed by the previous operations.666*667* Common routine called by sys_msgget(), sys_semget() and sys_shmget().668*/669int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,670const struct ipc_ops *ops, struct ipc_params *params)671{672if (params->key == IPC_PRIVATE)673return ipcget_new(ns, ids, ops, params);674else675return ipcget_public(ns, ids, ops, params);676}677678/**679* ipc_update_perm - update the permissions of an ipc object680* @in: the permission given as input.681* @out: the permission of the ipc to set.682*/683int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)684{685kuid_t uid = make_kuid(current_user_ns(), in->uid);686kgid_t gid = make_kgid(current_user_ns(), in->gid);687if (!uid_valid(uid) || !gid_valid(gid))688return -EINVAL;689690out->uid = uid;691out->gid = gid;692out->mode = (out->mode & ~S_IRWXUGO)693| (in->mode & S_IRWXUGO);694695return 0;696}697698/**699* ipcctl_obtain_check - retrieve an ipc object and check permissions700* @ns: ipc namespace701* @ids: the table of ids where to look for the ipc702* @id: the id of the ipc to retrieve703* @cmd: the cmd to check704* @perm: the permission to set705* @extra_perm: one extra permission parameter used by msq706*707* This function does some common audit and permissions check for some IPC_XXX708* cmd and is called from semctl_down, shmctl_down and msgctl_down.709*710* It:711* - retrieves the ipc object with the given id in the given table.712* - performs some audit and permission check, depending on the given cmd713* - returns a pointer to the ipc object or otherwise, the corresponding714* error.715*716* Call holding the both the rwsem and the rcu read lock.717*/718struct kern_ipc_perm *ipcctl_obtain_check(struct ipc_namespace *ns,719struct ipc_ids *ids, int id, int cmd,720struct ipc64_perm *perm, int extra_perm)721{722kuid_t euid;723int err = -EPERM;724struct kern_ipc_perm *ipcp;725726ipcp = ipc_obtain_object_check(ids, id);727if (IS_ERR(ipcp)) {728err = PTR_ERR(ipcp);729goto err;730}731732audit_ipc_obj(ipcp);733if (cmd == IPC_SET)734audit_ipc_set_perm(extra_perm, perm->uid,735perm->gid, perm->mode);736737euid = current_euid();738if (uid_eq(euid, ipcp->cuid) || uid_eq(euid, ipcp->uid) ||739ns_capable(ns->user_ns, CAP_SYS_ADMIN))740return ipcp; /* successful lookup */741err:742return ERR_PTR(err);743}744745#ifdef CONFIG_ARCH_WANT_IPC_PARSE_VERSION746747748/**749* ipc_parse_version - ipc call version750* @cmd: pointer to command751*752* Return IPC_64 for new style IPC and IPC_OLD for old style IPC.753* The @cmd value is turned from an encoding command and version into754* just the command code.755*/756int ipc_parse_version(int *cmd)757{758if (*cmd & IPC_64) {759*cmd ^= IPC_64;760return IPC_64;761} else {762return IPC_OLD;763}764}765766#endif /* CONFIG_ARCH_WANT_IPC_PARSE_VERSION */767768#ifdef CONFIG_PROC_FS769struct ipc_proc_iter {770struct ipc_namespace *ns;771struct pid_namespace *pid_ns;772struct ipc_proc_iface *iface;773};774775struct pid_namespace *ipc_seq_pid_ns(struct seq_file *s)776{777struct ipc_proc_iter *iter = s->private;778return iter->pid_ns;779}780781/**782* sysvipc_find_ipc - Find and lock the ipc structure based on seq pos783* @ids: ipc identifier set784* @pos: expected position785*786* The function finds an ipc structure, based on the sequence file787* position @pos. If there is no ipc structure at position @pos, then788* the successor is selected.789* If a structure is found, then it is locked (both rcu_read_lock() and790* ipc_lock_object()) and @pos is set to the position needed to locate791* the found ipc structure.792* If nothing is found (i.e. EOF), @pos is not modified.793*794* The function returns the found ipc structure, or NULL at EOF.795*/796static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t *pos)797{798int tmpidx;799struct kern_ipc_perm *ipc;800801/* convert from position to idr index -> "-1" */802tmpidx = *pos - 1;803804ipc = idr_get_next(&ids->ipcs_idr, &tmpidx);805if (ipc != NULL) {806rcu_read_lock();807ipc_lock_object(ipc);808809/* convert from idr index to position -> "+1" */810*pos = tmpidx + 1;811}812return ipc;813}814815static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)816{817struct ipc_proc_iter *iter = s->private;818struct ipc_proc_iface *iface = iter->iface;819struct kern_ipc_perm *ipc = it;820821/* If we had an ipc id locked before, unlock it */822if (ipc && ipc != SEQ_START_TOKEN)823ipc_unlock(ipc);824825/* Next -> search for *pos+1 */826(*pos)++;827return sysvipc_find_ipc(&iter->ns->ids[iface->ids], pos);828}829830/*831* File positions: pos 0 -> header, pos n -> ipc idx = n - 1.832* SeqFile iterator: iterator value locked ipc pointer or SEQ_TOKEN_START.833*/834static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)835{836struct ipc_proc_iter *iter = s->private;837struct ipc_proc_iface *iface = iter->iface;838struct ipc_ids *ids;839840ids = &iter->ns->ids[iface->ids];841842/*843* Take the lock - this will be released by the corresponding844* call to stop().845*/846down_read(&ids->rwsem);847848/* pos < 0 is invalid */849if (*pos < 0)850return NULL;851852/* pos == 0 means header */853if (*pos == 0)854return SEQ_START_TOKEN;855856/* Otherwise return the correct ipc structure */857return sysvipc_find_ipc(ids, pos);858}859860static void sysvipc_proc_stop(struct seq_file *s, void *it)861{862struct kern_ipc_perm *ipc = it;863struct ipc_proc_iter *iter = s->private;864struct ipc_proc_iface *iface = iter->iface;865struct ipc_ids *ids;866867/* If we had a locked structure, release it */868if (ipc && ipc != SEQ_START_TOKEN)869ipc_unlock(ipc);870871ids = &iter->ns->ids[iface->ids];872/* Release the lock we took in start() */873up_read(&ids->rwsem);874}875876static int sysvipc_proc_show(struct seq_file *s, void *it)877{878struct ipc_proc_iter *iter = s->private;879struct ipc_proc_iface *iface = iter->iface;880881if (it == SEQ_START_TOKEN) {882seq_puts(s, iface->header);883return 0;884}885886return iface->show(s, it);887}888889static const struct seq_operations sysvipc_proc_seqops = {890.start = sysvipc_proc_start,891.stop = sysvipc_proc_stop,892.next = sysvipc_proc_next,893.show = sysvipc_proc_show,894};895896static int sysvipc_proc_open(struct inode *inode, struct file *file)897{898struct ipc_proc_iter *iter;899900iter = __seq_open_private(file, &sysvipc_proc_seqops, sizeof(*iter));901if (!iter)902return -ENOMEM;903904iter->iface = pde_data(inode);905iter->ns = get_ipc_ns(current->nsproxy->ipc_ns);906iter->pid_ns = get_pid_ns(task_active_pid_ns(current));907908return 0;909}910911static int sysvipc_proc_release(struct inode *inode, struct file *file)912{913struct seq_file *seq = file->private_data;914struct ipc_proc_iter *iter = seq->private;915put_ipc_ns(iter->ns);916put_pid_ns(iter->pid_ns);917return seq_release_private(inode, file);918}919920static const struct proc_ops sysvipc_proc_ops = {921.proc_flags = PROC_ENTRY_PERMANENT,922.proc_open = sysvipc_proc_open,923.proc_read = seq_read,924.proc_lseek = seq_lseek,925.proc_release = sysvipc_proc_release,926};927#endif /* CONFIG_PROC_FS */928929930