Re: [PATCH] ipc: Convert kern_ipc_perm.refcount to refcount_t

From: kbuild test robot
Date: Sat May 27 2017 - 17:57:58 EST


Hi Elena,

[auto build test ERROR on next-20170526]
[cannot apply to linus/master linux/master kees/for-next/pstore v4.9-rc8 v4.9-rc7 v4.9-rc6 v4.12-rc2]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Kees-Cook/ipc-Convert-kern_ipc_perm-refcount-to-refcount_t/20170528-040601
config: m32r-m32104ut_defconfig (attached as .config)
compiler: m32r-linux-gcc (GCC) 6.2.0
reproduce:
wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=m32r

All errors (new ones prefixed by >>):

In file included from include/uapi/linux/shm.h:4:0,
from include/linux/shm.h:6,
from ipc/util.c:44:
include/linux/ipc.h:25:2: error: unknown type name 'refcount_t'
refcount_t refcount;
^~~~~~~~~~
ipc/util.c: In function 'ipc_addid':
>> ipc/util.c:235:15: error: passing argument 1 of 'refcount_set' from incompatible pointer type [-Werror=incompatible-pointer-types]
refcount_set(&new->refcount, 1);
^
In file included from include/linux/key.h:26:0,
from include/linux/security.h:26,
from ipc/util.c:52:
include/linux/refcount.h:28:20: note: expected 'refcount_t * {aka struct refcount_struct *}' but argument is of type 'int *'
static inline void refcount_set(refcount_t *r, unsigned int n)
^~~~~~~~~~~~
ipc/util.c: In function 'ipc_rcu_getref':
>> ipc/util.c:400:31: error: passing argument 1 of 'refcount_inc_not_zero' from incompatible pointer type [-Werror=incompatible-pointer-types]
return refcount_inc_not_zero(&ptr->refcount);
^
In file included from include/linux/key.h:26:0,
from include/linux/security.h:26,
from ipc/util.c:52:
include/linux/refcount.h:47:26: note: expected 'refcount_t * {aka struct refcount_struct *}' but argument is of type 'int *'
extern __must_check bool refcount_inc_not_zero(refcount_t *r);
^~~~~~~~~~~~~~~~~~~~~
ipc/util.c: In function 'ipc_rcu_putref':
>> ipc/util.c:406:29: error: passing argument 1 of 'refcount_dec_and_test' from incompatible pointer type [-Werror=incompatible-pointer-types]
if (!refcount_dec_and_test(&ptr->refcount))
^
In file included from include/linux/key.h:26:0,
from include/linux/security.h:26,
from ipc/util.c:52:
include/linux/refcount.h:53:26: note: expected 'refcount_t * {aka struct refcount_struct *}' but argument is of type 'int *'
extern __must_check bool refcount_dec_and_test(refcount_t *r);
^~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors

vim +/refcount_set +235 ipc/util.c

38 *
39 * Note that sems have a special fast path that avoids kern_ipc_perm.lock -
40 * see sem_lock().
41 */
42
43 #include <linux/mm.h>
> 44 #include <linux/shm.h>
45 #include <linux/init.h>
46 #include <linux/msg.h>
47 #include <linux/vmalloc.h>
48 #include <linux/slab.h>
49 #include <linux/notifier.h>
50 #include <linux/capability.h>
51 #include <linux/highuid.h>
> 52 #include <linux/security.h>
53 #include <linux/rcupdate.h>
54 #include <linux/workqueue.h>
55 #include <linux/seq_file.h>
56 #include <linux/proc_fs.h>
57 #include <linux/audit.h>
58 #include <linux/nsproxy.h>
59 #include <linux/rwsem.h>
60 #include <linux/memory.h>
61 #include <linux/ipc_namespace.h>
62
63 #include <asm/unistd.h>
64
65 #include "util.h"
66
67 struct ipc_proc_iface {
68 const char *path;
69 const char *header;
70 int ids;
71 int (*show)(struct seq_file *, void *);
72 };
73
74 /**
75 * ipc_init - initialise ipc subsystem
76 *
77 * The various sysv ipc resources (semaphores, messages and shared
78 * memory) are initialised.
79 *
80 * A callback routine is registered into the memory hotplug notifier
81 * chain: since msgmni scales to lowmem this callback routine will be
82 * called upon successful memory add / remove to recompute msmgni.
83 */
84 static int __init ipc_init(void)
85 {
86 sem_init();
87 msg_init();
88 shm_init();
89 return 0;
90 }
91 device_initcall(ipc_init);
92
93 /**
94 * ipc_init_ids - initialise ipc identifiers
95 * @ids: ipc identifier set
96 *
97 * Set up the sequence range to use for the ipc identifier range (limited
98 * below IPCMNI) then initialise the ids idr.
99 */
100 void ipc_init_ids(struct ipc_ids *ids)
101 {
102 ids->in_use = 0;
103 ids->seq = 0;
104 ids->next_id = -1;
105 init_rwsem(&ids->rwsem);
106 idr_init(&ids->ipcs_idr);
107 }
108
109 #ifdef CONFIG_PROC_FS
110 static const struct file_operations sysvipc_proc_fops;
111 /**
112 * ipc_init_proc_interface - create a proc interface for sysipc types using a seq_file interface.
113 * @path: Path in procfs
114 * @header: Banner to be printed at the beginning of the file.
115 * @ids: ipc id table to iterate.
116 * @show: show routine.
117 */
118 void __init ipc_init_proc_interface(const char *path, const char *header,
119 int ids, int (*show)(struct seq_file *, void *))
120 {
121 struct proc_dir_entry *pde;
122 struct ipc_proc_iface *iface;
123
124 iface = kmalloc(sizeof(*iface), GFP_KERNEL);
125 if (!iface)
126 return;
127 iface->path = path;
128 iface->header = header;
129 iface->ids = ids;
130 iface->show = show;
131
132 pde = proc_create_data(path,
133 S_IRUGO, /* world readable */
134 NULL, /* parent dir */
135 &sysvipc_proc_fops,
136 iface);
137 if (!pde)
138 kfree(iface);
139 }
140 #endif
141
142 /**
143 * ipc_findkey - find a key in an ipc identifier set
144 * @ids: ipc identifier set
145 * @key: key to find
146 *
147 * Returns the locked pointer to the ipc structure if found or NULL
148 * otherwise. If key is found ipc points to the owning ipc structure
149 *
150 * Called with ipc_ids.rwsem held.
151 */
152 static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
153 {
154 struct kern_ipc_perm *ipc;
155 int next_id;
156 int total;
157
158 for (total = 0, next_id = 0; total < ids->in_use; next_id++) {
159 ipc = idr_find(&ids->ipcs_idr, next_id);
160
161 if (ipc == NULL)
162 continue;
163
164 if (ipc->key != key) {
165 total++;
166 continue;
167 }
168
169 rcu_read_lock();
170 ipc_lock_object(ipc);
171 return ipc;
172 }
173
174 return NULL;
175 }
176
177 /**
178 * ipc_get_maxid - get the last assigned id
179 * @ids: ipc identifier set
180 *
181 * Called with ipc_ids.rwsem held.
182 */
183 int ipc_get_maxid(struct ipc_ids *ids)
184 {
185 struct kern_ipc_perm *ipc;
186 int max_id = -1;
187 int total, id;
188
189 if (ids->in_use == 0)
190 return -1;
191
192 if (ids->in_use == IPCMNI)
193 return IPCMNI - 1;
194
195 /* Look for the last assigned id */
196 total = 0;
197 for (id = 0; id < IPCMNI && total < ids->in_use; id++) {
198 ipc = idr_find(&ids->ipcs_idr, id);
199 if (ipc != NULL) {
200 max_id = id;
201 total++;
202 }
203 }
204 return max_id;
205 }
206
207 /**
208 * ipc_addid - add an ipc identifier
209 * @ids: ipc identifier set
210 * @new: new ipc permission set
211 * @size: limit for the number of used ids
212 *
213 * Add an entry 'new' to the ipc ids idr. The permissions object is
214 * initialised and the first free entry is set up and the id assigned
215 * is returned. The 'new' entry is returned in a locked state on success.
216 * On failure the entry is not locked and a negative err-code is returned.
217 *
218 * Called with writer ipc_ids.rwsem held.
219 */
220 int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
221 {
222 kuid_t euid;
223 kgid_t egid;
224 int id;
225 int next_id = ids->next_id;
226
227 if (size > IPCMNI)
228 size = IPCMNI;
229
230 if (ids->in_use >= size)
231 return -ENOSPC;
232
233 idr_preload(GFP_KERNEL);
234
> 235 refcount_set(&new->refcount, 1);
236 spin_lock_init(&new->lock);
237 new->deleted = false;
238 rcu_read_lock();
239 spin_lock(&new->lock);
240
241 current_euid_egid(&euid, &egid);
242 new->cuid = new->uid = euid;
243 new->gid = new->cgid = egid;
244
245 id = idr_alloc(&ids->ipcs_idr, new,
246 (next_id < 0) ? 0 : ipcid_to_idx(next_id), 0,
247 GFP_NOWAIT);
248 idr_preload_end();
249 if (id < 0) {
250 spin_unlock(&new->lock);
251 rcu_read_unlock();
252 return id;
253 }
254
255 ids->in_use++;
256
257 if (next_id < 0) {
258 new->seq = ids->seq++;
259 if (ids->seq > IPCID_SEQ_MAX)
260 ids->seq = 0;
261 } else {
262 new->seq = ipcid_to_seqx(next_id);
263 ids->next_id = -1;
264 }
265
266 new->id = ipc_buildid(id, new->seq);
267 return id;
268 }
269
270 /**
271 * ipcget_new - create a new ipc object
272 * @ns: ipc namespace
273 * @ids: ipc identifier set
274 * @ops: the actual creation routine to call
275 * @params: its parameters
276 *
277 * This routine is called by sys_msgget, sys_semget() and sys_shmget()
278 * when the key is IPC_PRIVATE.
279 */
280 static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
281 const struct ipc_ops *ops, struct ipc_params *params)
282 {
283 int err;
284
285 down_write(&ids->rwsem);
286 err = ops->getnew(ns, params);
287 up_write(&ids->rwsem);
288 return err;
289 }
290
291 /**
292 * ipc_check_perms - check security and permissions for an ipc object
293 * @ns: ipc namespace
294 * @ipcp: ipc permission set
295 * @ops: the actual security routine to call
296 * @params: its parameters
297 *
298 * This routine is called by sys_msgget(), sys_semget() and sys_shmget()
299 * when the key is not IPC_PRIVATE and that key already exists in the
300 * ds IDR.
301 *
302 * On success, the ipc id is returned.
303 *
304 * It is called with ipc_ids.rwsem and ipcp->lock held.
305 */
306 static int ipc_check_perms(struct ipc_namespace *ns,
307 struct kern_ipc_perm *ipcp,
308 const struct ipc_ops *ops,
309 struct ipc_params *params)
310 {
311 int err;
312
313 if (ipcperms(ns, ipcp, params->flg))
314 err = -EACCES;
315 else {
316 err = ops->associate(ipcp, params->flg);
317 if (!err)
318 err = ipcp->id;
319 }
320
321 return err;
322 }
323
324 /**
325 * ipcget_public - get an ipc object or create a new one
326 * @ns: ipc namespace
327 * @ids: ipc identifier set
328 * @ops: the actual creation routine to call
329 * @params: its parameters
330 *
331 * This routine is called by sys_msgget, sys_semget() and sys_shmget()
332 * when the key is not IPC_PRIVATE.
333 * It adds a new entry if the key is not found and does some permission
334 * / security checkings if the key is found.
335 *
336 * On success, the ipc id is returned.
337 */
338 static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
339 const struct ipc_ops *ops, struct ipc_params *params)
340 {
341 struct kern_ipc_perm *ipcp;
342 int flg = params->flg;
343 int err;
344
345 /*
346 * Take the lock as a writer since we are potentially going to add
347 * a new entry + read locks are not "upgradable"
348 */
349 down_write(&ids->rwsem);
350 ipcp = ipc_findkey(ids, params->key);
351 if (ipcp == NULL) {
352 /* key not used */
353 if (!(flg & IPC_CREAT))
354 err = -ENOENT;
355 else
356 err = ops->getnew(ns, params);
357 } else {
358 /* ipc object has been locked by ipc_findkey() */
359
360 if (flg & IPC_CREAT && flg & IPC_EXCL)
361 err = -EEXIST;
362 else {
363 err = 0;
364 if (ops->more_checks)
365 err = ops->more_checks(ipcp, params);
366 if (!err)
367 /*
368 * ipc_check_perms returns the IPC id on
369 * success
370 */
371 err = ipc_check_perms(ns, ipcp, ops, params);
372 }
373 ipc_unlock(ipcp);
374 }
375 up_write(&ids->rwsem);
376
377 return err;
378 }
379
380
381 /**
382 * ipc_rmid - remove an ipc identifier
383 * @ids: ipc identifier set
384 * @ipcp: ipc perm structure containing the identifier to remove
385 *
386 * ipc_ids.rwsem (as a writer) and the spinlock for this ID are held
387 * before this function is called, and remain locked on the exit.
388 */
389 void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
390 {
391 int lid = ipcid_to_idx(ipcp->id);
392
393 idr_remove(&ids->ipcs_idr, lid);
394 ids->in_use--;
395 ipcp->deleted = true;
396 }
397
398 int ipc_rcu_getref(struct kern_ipc_perm *ptr)
399 {
> 400 return refcount_inc_not_zero(&ptr->refcount);
401 }
402
403 void ipc_rcu_putref(struct kern_ipc_perm *ptr,
404 void (*func)(struct rcu_head *head))
405 {
> 406 if (!refcount_dec_and_test(&ptr->refcount))
407 return;
408
409 call_rcu(&ptr->rcu, func);

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

Attachment: .config.gz
Description: application/gzip