Skip to content

Commit

Permalink
Cache user_ns in struct cred
Browse files Browse the repository at this point in the history
If !CONFIG_USERNS, have current_user_ns() defined to (&init_user_ns).

Get rid of _current_user_ns.  This requires nsown_capable() to be
defined in capability.c rather than as static inline in capability.h,
so do that.

Request_key needs init_user_ns defined at current_user_ns if
!CONFIG_USERNS, so forward-declare that in cred.h if !CONFIG_USERNS
at current_user_ns() define.

Compile-tested with and without CONFIG_USERNS.

Signed-off-by: Serge E. Hallyn <[email protected]>
[ This makes a huge performance difference for acl_permission_check(),
  up to 30%.  And that is one of the hottest kernel functions for loads
  that are pathname-lookup heavy.  ]
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
hallyn authored and torvalds committed May 13, 2011
1 parent 381e786 commit 47a150e
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 20 deletions.
13 changes: 1 addition & 12 deletions include/linux/capability.h
Original file line number Diff line number Diff line change
Expand Up @@ -546,18 +546,7 @@ extern bool has_capability_noaudit(struct task_struct *t, int cap);
extern bool capable(int cap);
extern bool ns_capable(struct user_namespace *ns, int cap);
extern bool task_ns_capable(struct task_struct *t, int cap);

/**
* nsown_capable - Check superior capability to one's own user_ns
* @cap: The capability in question
*
* Return true if the current task has the given superior capability
* targeted at its own user namespace.
*/
static inline bool nsown_capable(int cap)
{
return ns_capable(current_user_ns(), cap);
}
extern bool nsown_capable(int cap);

/* audit system wants to get cap info from files as well */
extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
Expand Down
10 changes: 8 additions & 2 deletions include/linux/cred.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ struct cred {
void *security; /* subjective LSM security */
#endif
struct user_struct *user; /* real user ID subscription */
struct user_namespace *user_ns; /* cached user->user_ns */
struct group_info *group_info; /* supplementary groups for euid/fsgid */
struct rcu_head rcu; /* RCU deletion hook */
};
Expand Down Expand Up @@ -354,10 +355,15 @@ static inline void put_cred(const struct cred *_cred)
#define current_fsgid() (current_cred_xxx(fsgid))
#define current_cap() (current_cred_xxx(cap_effective))
#define current_user() (current_cred_xxx(user))
#define _current_user_ns() (current_cred_xxx(user)->user_ns)
#define current_security() (current_cred_xxx(security))

extern struct user_namespace *current_user_ns(void);
#ifdef CONFIG_USER_NS
#define current_user_ns() (current_cred_xxx(user_ns))
#else
extern struct user_namespace init_user_ns;
#define current_user_ns() (&init_user_ns)
#endif


#define current_uid_gid(_uid, _gid) \
do { \
Expand Down
12 changes: 12 additions & 0 deletions kernel/capability.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,15 @@ bool task_ns_capable(struct task_struct *t, int cap)
return ns_capable(task_cred_xxx(t, user)->user_ns, cap);
}
EXPORT_SYMBOL(task_ns_capable);

/**
* nsown_capable - Check superior capability to one's own user_ns
* @cap: The capability in question
*
* Return true if the current task has the given superior capability
* targeted at its own user namespace.
*/
bool nsown_capable(int cap)
{
return ns_capable(current_user_ns(), cap);
}
12 changes: 6 additions & 6 deletions kernel/cred.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ struct cred init_cred = {
.cap_effective = CAP_INIT_EFF_SET,
.cap_bset = CAP_INIT_BSET,
.user = INIT_USER,
.user_ns = &init_user_ns,
.group_info = &init_groups,
#ifdef CONFIG_KEYS
.tgcred = &init_tgcred,
Expand Down Expand Up @@ -410,6 +411,11 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
goto error_put;
}

/* cache user_ns in cred. Doesn't need a refcount because it will
* stay pinned by cred->user
*/
new->user_ns = new->user->user_ns;

#ifdef CONFIG_KEYS
/* new threads get their own thread keyrings if their parent already
* had one */
Expand Down Expand Up @@ -741,12 +747,6 @@ int set_create_files_as(struct cred *new, struct inode *inode)
}
EXPORT_SYMBOL(set_create_files_as);

struct user_namespace *current_user_ns(void)
{
return _current_user_ns();
}
EXPORT_SYMBOL(current_user_ns);

#ifdef CONFIG_DEBUG_CREDENTIALS

bool creds_are_invalid(const struct cred *cred)
Expand Down

0 comments on commit 47a150e

Please sign in to comment.