Skip to content

Commit 41e8456

Browse files
mjguzikpcmoore
authored andcommitted
cred: add get_cred_many and put_cred_many
Some of the frequent consumers of get_cred and put_cred operate on 2 references on the same creds back-to-back. Switch them to doing the work in one go instead. Signed-off-by: Mateusz Guzik <mjguzik@gmail.com> [PM: removed changelog from commit description] Signed-off-by: Paul Moore <paul@paul-moore.com>
1 parent 20a2aa4 commit 41e8456

2 files changed

Lines changed: 65 additions & 20 deletions

File tree

include/linux/cred.h

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,20 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred)
218218
cred->cap_inheritable));
219219
}
220220

221+
/**
222+
* get_new_cred_many - Get references on a new set of credentials
223+
* @cred: The new credentials to reference
224+
* @nr: Number of references to acquire
225+
*
226+
* Get references on the specified set of new credentials. The caller must
227+
* release all acquired references.
228+
*/
229+
static inline struct cred *get_new_cred_many(struct cred *cred, int nr)
230+
{
231+
atomic_add(nr, &cred->usage);
232+
return cred;
233+
}
234+
221235
/**
222236
* get_new_cred - Get a reference on a new set of credentials
223237
* @cred: The new credentials to reference
@@ -227,31 +241,45 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred)
227241
*/
228242
static inline struct cred *get_new_cred(struct cred *cred)
229243
{
230-
atomic_inc(&cred->usage);
231-
return cred;
244+
return get_new_cred_many(cred, 1);
232245
}
233246

234247
/**
235-
* get_cred - Get a reference on a set of credentials
248+
* get_cred_many - Get references on a set of credentials
236249
* @cred: The credentials to reference
250+
* @nr: Number of references to acquire
237251
*
238-
* Get a reference on the specified set of credentials. The caller must
239-
* release the reference. If %NULL is passed, it is returned with no action.
252+
* Get references on the specified set of credentials. The caller must release
253+
* all acquired reference. If %NULL is passed, it is returned with no action.
240254
*
241255
* This is used to deal with a committed set of credentials. Although the
242256
* pointer is const, this will temporarily discard the const and increment the
243257
* usage count. The purpose of this is to attempt to catch at compile time the
244258
* accidental alteration of a set of credentials that should be considered
245259
* immutable.
246260
*/
247-
static inline const struct cred *get_cred(const struct cred *cred)
261+
static inline const struct cred *get_cred_many(const struct cred *cred, int nr)
248262
{
249263
struct cred *nonconst_cred = (struct cred *) cred;
250264
if (!cred)
251265
return cred;
252266
validate_creds(cred);
253267
nonconst_cred->non_rcu = 0;
254-
return get_new_cred(nonconst_cred);
268+
return get_new_cred_many(nonconst_cred, nr);
269+
}
270+
271+
/*
272+
* get_cred - Get a reference on a set of credentials
273+
* @cred: The credentials to reference
274+
*
275+
* Get a reference on the specified set of credentials. The caller must
276+
* release the reference. If %NULL is passed, it is returned with no action.
277+
*
278+
* This is used to deal with a committed set of credentials.
279+
*/
280+
static inline const struct cred *get_cred(const struct cred *cred)
281+
{
282+
return get_cred_many(cred, 1);
255283
}
256284

257285
static inline const struct cred *get_cred_rcu(const struct cred *cred)
@@ -269,6 +297,7 @@ static inline const struct cred *get_cred_rcu(const struct cred *cred)
269297
/**
270298
* put_cred - Release a reference to a set of credentials
271299
* @cred: The credentials to release
300+
* @nr: Number of references to release
272301
*
273302
* Release a reference to a set of credentials, deleting them when the last ref
274303
* is released. If %NULL is passed, nothing is done.
@@ -277,17 +306,29 @@ static inline const struct cred *get_cred_rcu(const struct cred *cred)
277306
* on task_struct are attached by const pointers to prevent accidental
278307
* alteration of otherwise immutable credential sets.
279308
*/
280-
static inline void put_cred(const struct cred *_cred)
309+
static inline void put_cred_many(const struct cred *_cred, int nr)
281310
{
282311
struct cred *cred = (struct cred *) _cred;
283312

284313
if (cred) {
285314
validate_creds(cred);
286-
if (atomic_dec_and_test(&(cred)->usage))
315+
if (atomic_sub_and_test(nr, &cred->usage))
287316
__put_cred(cred);
288317
}
289318
}
290319

320+
/*
321+
* put_cred - Release a reference to a set of credentials
322+
* @cred: The credentials to release
323+
*
324+
* Release a reference to a set of credentials, deleting them when the last ref
325+
* is released. If %NULL is passed, nothing is done.
326+
*/
327+
static inline void put_cred(const struct cred *cred)
328+
{
329+
put_cred_many(cred, 1);
330+
}
331+
291332
/**
292333
* current_cred - Access the current task's subjective credentials
293334
*

kernel/cred.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,23 +162,29 @@ EXPORT_SYMBOL(__put_cred);
162162
*/
163163
void exit_creds(struct task_struct *tsk)
164164
{
165-
struct cred *cred;
165+
struct cred *real_cred, *cred;
166166

167167
kdebug("exit_creds(%u,%p,%p,{%d,%d})", tsk->pid, tsk->real_cred, tsk->cred,
168168
atomic_read(&tsk->cred->usage),
169169
read_cred_subscribers(tsk->cred));
170170

171-
cred = (struct cred *) tsk->real_cred;
171+
real_cred = (struct cred *) tsk->real_cred;
172172
tsk->real_cred = NULL;
173-
validate_creds(cred);
174-
alter_cred_subscribers(cred, -1);
175-
put_cred(cred);
176173

177174
cred = (struct cred *) tsk->cred;
178175
tsk->cred = NULL;
176+
179177
validate_creds(cred);
180-
alter_cred_subscribers(cred, -1);
181-
put_cred(cred);
178+
if (real_cred == cred) {
179+
alter_cred_subscribers(cred, -2);
180+
put_cred_many(cred, 2);
181+
} else {
182+
validate_creds(real_cred);
183+
alter_cred_subscribers(real_cred, -1);
184+
put_cred(real_cred);
185+
alter_cred_subscribers(cred, -1);
186+
put_cred(cred);
187+
}
182188

183189
#ifdef CONFIG_KEYS_REQUEST_CACHE
184190
key_put(tsk->cached_requested_key);
@@ -355,8 +361,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
355361
#endif
356362
clone_flags & CLONE_THREAD
357363
) {
358-
p->real_cred = get_cred(p->cred);
359-
get_cred(p->cred);
364+
p->real_cred = get_cred_many(p->cred, 2);
360365
alter_cred_subscribers(p->cred, 2);
361366
kdebug("share_creds(%p{%d,%d})",
362367
p->cred, atomic_read(&p->cred->usage),
@@ -520,8 +525,7 @@ int commit_creds(struct cred *new)
520525
proc_id_connector(task, PROC_EVENT_GID);
521526

522527
/* release the old obj and subj refs both */
523-
put_cred(old);
524-
put_cred(old);
528+
put_cred_many(old, 2);
525529
return 0;
526530
}
527531
EXPORT_SYMBOL(commit_creds);

0 commit comments

Comments
 (0)