From 57a39aa3e3ca00e371cec37be4f7c2e950eb1f1f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 16 Nov 2011 22:06:16 -0800 Subject: userns: Kill bogus declaration of function release_uids There is no release_uids function remove the declaration from sched.h Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/sched.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/sched.h b/include/linux/sched.h index 81a173c0897..720ce8d98a7 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2184,7 +2184,6 @@ static inline struct user_struct *get_uid(struct user_struct *u) return u; } extern void free_uid(struct user_struct *); -extern void release_uids(struct user_namespace *ns); #include -- cgit v1.2.3-18-g5258 From 7e6bd8fadd1216f50468f965d0308f45e5109ced Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 14 Nov 2011 19:29:17 -0800 Subject: cred: Add forward declaration of init_user_ns in all cases. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/cred.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/cred.h b/include/linux/cred.h index adadf71a732..d12c4e475c1 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -357,11 +357,11 @@ static inline void put_cred(const struct cred *_cred) #define current_user() (current_cred_xxx(user)) #define current_security() (current_cred_xxx(security)) +extern struct user_namespace init_user_ns; #ifdef CONFIG_USER_NS #define current_user_ns() (current_cred_xxx(user_ns)) #define task_user_ns(task) (task_cred_xxx((task), user_ns)) #else -extern struct user_namespace init_user_ns; #define current_user_ns() (&init_user_ns) #define task_user_ns(task) (&init_user_ns) #endif -- cgit v1.2.3-18-g5258 From 0093ccb68f3753c0ba4d74c89d7e0f444b8d6123 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 16 Nov 2011 21:52:53 -0800 Subject: cred: Refcount the user_ns pointed to by the cred. struct user_struct will shortly loose it's user_ns reference so make the cred user_ns reference a proper reference complete with reference counting. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/cred.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/cred.h b/include/linux/cred.h index d12c4e475c1..2c60ec80267 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -146,7 +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 user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */ struct group_info *group_info; /* supplementary groups for euid/fsgid */ struct rcu_head rcu; /* RCU deletion hook */ }; -- cgit v1.2.3-18-g5258 From aeb3ae9da9b50a386b22af786d19b623e8d9f0fa Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 16 Nov 2011 21:59:43 -0800 Subject: userns: Add an explicit reference to the parent user namespace I am about to remove the struct user_namespace reference from struct user_struct. So keep an explicit track of the parent user namespace. Take advantage of this new reference and replace instances of user_ns->creator->user_ns with user_ns->parent. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/user_namespace.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index faf467944ba..dc2d85a7637 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -12,6 +12,7 @@ struct user_namespace { struct kref kref; struct hlist_head uidhash_table[UIDHASH_SZ]; + struct user_namespace *parent; struct user_struct *creator; struct work_struct destroyer; }; -- cgit v1.2.3-18-g5258 From d0bd6594e286bd6145e04e19e8d3fa2e902cb800 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 16 Nov 2011 23:20:58 -0800 Subject: userns: Deprecate and rename the user_namespace reference in the user_struct With a user_ns reference in struct cred the only user of the user namespace reference in struct user_struct is to keep the uid hash table alive. The user_namespace reference in struct user_struct will be going away soon, and I have removed all of the references. Rename the field from user_ns to _user_ns so that the compiler can verify nothing follows the user struct to the user namespace anymore. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/sched.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/sched.h b/include/linux/sched.h index 720ce8d98a7..6867ae9bc8a 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -729,7 +729,7 @@ struct user_struct { /* Hash table maintenance information */ struct hlist_node uidhash_node; uid_t uid; - struct user_namespace *user_ns; + struct user_namespace *_user_ns; /* Don't use will be removed soon */ #ifdef CONFIG_PERF_EVENTS atomic_long_t locked_vm; -- cgit v1.2.3-18-g5258 From 1a48e2ac034d47ed843081c4523b63c46b46888b Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 14 Nov 2011 16:24:06 -0800 Subject: userns: Replace the hard to write inode_userns with inode_capable. This represents a change in strategy of how to handle user namespaces. Instead of tagging everything explicitly with a user namespace and bulking up all of the comparisons of uids and gids in the kernel, all uids and gids in use will have a mapping to a flat kuid and kgid spaces respectively. This allows much more of the existing logic to be preserved and in general allows for faster code. In this new and improved world we allow someone to utiliize capabilities over an inode if the inodes owner mapps into the capabilities holders user namespace and the user has capabilities in their user namespace. Which is simple and efficient. Moving the fs uid comparisons to be comparisons in a flat kuid space follows in later patches, something that is only significant if you are using user namespaces. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/capability.h | 2 ++ include/linux/fs.h | 6 ------ 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/linux/capability.h b/include/linux/capability.h index 12d52dedb22..a76eca90747 100644 --- a/include/linux/capability.h +++ b/include/linux/capability.h @@ -374,6 +374,7 @@ struct cpu_vfs_cap_data { #ifdef __KERNEL__ +struct inode; struct dentry; struct user_namespace; @@ -548,6 +549,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t, extern bool capable(int cap); extern bool ns_capable(struct user_namespace *ns, int cap); extern bool nsown_capable(int cap); +extern bool inode_capable(const struct inode *inode, 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); diff --git a/include/linux/fs.h b/include/linux/fs.h index 135693e79f2..a6c5efbee0d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1522,12 +1522,6 @@ enum { #define vfs_check_frozen(sb, level) \ wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level))) -/* - * until VFS tracks user namespaces for inodes, just make all files - * belong to init_user_ns - */ -extern struct user_namespace init_user_ns; -#define inode_userns(inode) (&init_user_ns) extern bool inode_owner_or_capable(const struct inode *inode); /* not quite ready to be deprecated, but... */ -- cgit v1.2.3-18-g5258 From 7a4e7408c5cadb240e068a662251754a562355e3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 14 Nov 2011 14:29:51 -0800 Subject: userns: Add kuid_t and kgid_t and associated infrastructure in uidgid.h Start distinguishing between internal kernel uids and gids and values that userspace can use. This is done by introducing two new types: kuid_t and kgid_t. These types and their associated functions are infrastructure are declared in the new header uidgid.h. Ultimately there will be a different implementation of the mapping functions for use with user namespaces. But to keep it simple we introduce the mapping functions first to separate the meat from the mechanical code conversions. Export overflowuid and overflowgid so we can use from_kuid_munged and from_kgid_munged in modular code. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/uidgid.h | 176 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 include/linux/uidgid.h (limited to 'include') diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h new file mode 100644 index 00000000000..a0addb8e588 --- /dev/null +++ b/include/linux/uidgid.h @@ -0,0 +1,176 @@ +#ifndef _LINUX_UIDGID_H +#define _LINUX_UIDGID_H + +/* + * A set of types for the internal kernel types representing uids and gids. + * + * The types defined in this header allow distinguishing which uids and gids in + * the kernel are values used by userspace and which uid and gid values are + * the internal kernel values. With the addition of user namespaces the values + * can be different. Using the type system makes it possible for the compiler + * to detect when we overlook these differences. + * + */ +#include +#include + +struct user_namespace; +extern struct user_namespace init_user_ns; + +#if defined(NOTYET) + +typedef struct { + uid_t val; +} kuid_t; + + +typedef struct { + gid_t val; +} kgid_t; + +#define KUIDT_INIT(value) (kuid_t){ value } +#define KGIDT_INIT(value) (kgid_t){ value } + +static inline uid_t __kuid_val(kuid_t uid) +{ + return uid.val; +} + +static inline gid_t __kgid_val(kgid_t gid) +{ + return gid.val; +} + +#else + +typedef uid_t kuid_t; +typedef gid_t kgid_t; + +static inline uid_t __kuid_val(kuid_t uid) +{ + return uid; +} + +static inline gid_t __kgid_val(kgid_t gid) +{ + return gid; +} + +#define KUIDT_INIT(value) ((kuid_t) value ) +#define KGIDT_INIT(value) ((kgid_t) value ) + +#endif + +#define GLOBAL_ROOT_UID KUIDT_INIT(0) +#define GLOBAL_ROOT_GID KGIDT_INIT(0) + +#define INVALID_UID KUIDT_INIT(-1) +#define INVALID_GID KGIDT_INIT(-1) + +static inline bool uid_eq(kuid_t left, kuid_t right) +{ + return __kuid_val(left) == __kuid_val(right); +} + +static inline bool gid_eq(kgid_t left, kgid_t right) +{ + return __kgid_val(left) == __kgid_val(right); +} + +static inline bool uid_gt(kuid_t left, kuid_t right) +{ + return __kuid_val(left) > __kuid_val(right); +} + +static inline bool gid_gt(kgid_t left, kgid_t right) +{ + return __kgid_val(left) > __kgid_val(right); +} + +static inline bool uid_gte(kuid_t left, kuid_t right) +{ + return __kuid_val(left) >= __kuid_val(right); +} + +static inline bool gid_gte(kgid_t left, kgid_t right) +{ + return __kgid_val(left) >= __kgid_val(right); +} + +static inline bool uid_lt(kuid_t left, kuid_t right) +{ + return __kuid_val(left) < __kuid_val(right); +} + +static inline bool gid_lt(kgid_t left, kgid_t right) +{ + return __kgid_val(left) < __kgid_val(right); +} + +static inline bool uid_lte(kuid_t left, kuid_t right) +{ + return __kuid_val(left) <= __kuid_val(right); +} + +static inline bool gid_lte(kgid_t left, kgid_t right) +{ + return __kgid_val(left) <= __kgid_val(right); +} + +static inline bool uid_valid(kuid_t uid) +{ + return !uid_eq(uid, INVALID_UID); +} + +static inline bool gid_valid(kgid_t gid) +{ + return !gid_eq(gid, INVALID_GID); +} + +static inline kuid_t make_kuid(struct user_namespace *from, uid_t uid) +{ + return KUIDT_INIT(uid); +} + +static inline kgid_t make_kgid(struct user_namespace *from, gid_t gid) +{ + return KGIDT_INIT(gid); +} + +static inline uid_t from_kuid(struct user_namespace *to, kuid_t kuid) +{ + return __kuid_val(kuid); +} + +static inline gid_t from_kgid(struct user_namespace *to, kgid_t kgid) +{ + return __kgid_val(kgid); +} + +static inline uid_t from_kuid_munged(struct user_namespace *to, kuid_t kuid) +{ + uid_t uid = from_kuid(to, kuid); + if (uid == (uid_t)-1) + uid = overflowuid; + return uid; +} + +static inline gid_t from_kgid_munged(struct user_namespace *to, kgid_t kgid) +{ + gid_t gid = from_kgid(to, kgid); + if (gid == (gid_t)-1) + gid = overflowgid; + return gid; +} + +static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid) +{ + return true; +} + +static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid) +{ + return true; +} + +#endif /* _LINUX_UIDGID_H */ -- cgit v1.2.3-18-g5258 From 5673a94c14574d7c6495c320c6b0e480673d54bd Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 17 Nov 2011 10:23:55 -0800 Subject: userns: Add a Kconfig option to enforce strict kuid and kgid type checks Make it possible to easily switch between strong mandatory type checks and relaxed type checks so that the code can easily be tested with the type checks and then built with the strong type checks disabled so the resulting code can be used. Require strong mandatory type checks when enabling the user namespace. It is very simple to make a typo and use the wrong type allowing conversions to/from userspace values to be bypassed by accident, the strong type checks prevent this. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/uidgid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h index a0addb8e588..539856829ca 100644 --- a/include/linux/uidgid.h +++ b/include/linux/uidgid.h @@ -17,7 +17,7 @@ struct user_namespace; extern struct user_namespace init_user_ns; -#if defined(NOTYET) +#ifdef CONFIG_UIDGID_STRICT_TYPE_CHECKS typedef struct { uid_t val; -- cgit v1.2.3-18-g5258 From 7b44ab978b77a91b327058a0f4db7e6fcdb90b92 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 16 Nov 2011 23:20:58 -0800 Subject: userns: Disassociate user_struct from the user_namespace. Modify alloc_uid to take a kuid and make the user hash table global. Stop holding a reference to the user namespace in struct user_struct. This simplifies the code and makes the per user accounting not care about which user namespace a uid happens to appear in. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/sched.h | 8 ++++---- include/linux/user_namespace.h | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/linux/sched.h b/include/linux/sched.h index 6867ae9bc8a..5fdc1ebbcbc 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -90,6 +90,7 @@ struct sched_param { #include #include #include +#include #include @@ -728,8 +729,7 @@ struct user_struct { /* Hash table maintenance information */ struct hlist_node uidhash_node; - uid_t uid; - struct user_namespace *_user_ns; /* Don't use will be removed soon */ + kuid_t uid; #ifdef CONFIG_PERF_EVENTS atomic_long_t locked_vm; @@ -738,7 +738,7 @@ struct user_struct { extern int uids_sysfs_init(void); -extern struct user_struct *find_user(uid_t); +extern struct user_struct *find_user(kuid_t); extern struct user_struct root_user; #define INIT_USER (&root_user) @@ -2177,7 +2177,7 @@ extern struct task_struct *find_task_by_pid_ns(pid_t nr, extern void __set_special_pids(struct pid *pid); /* per-UID process charging. */ -extern struct user_struct * alloc_uid(struct user_namespace *, uid_t); +extern struct user_struct * alloc_uid(kuid_t); static inline struct user_struct *get_uid(struct user_struct *u) { atomic_inc(&u->__count); diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index dc2d85a7637..d767508db4f 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -6,12 +6,8 @@ #include #include -#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7) -#define UIDHASH_SZ (1 << UIDHASH_BITS) - struct user_namespace { struct kref kref; - struct hlist_head uidhash_table[UIDHASH_SZ]; struct user_namespace *parent; struct user_struct *creator; struct work_struct destroyer; -- cgit v1.2.3-18-g5258 From 783291e6900292521a3895583785e0c04a56c5b3 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 17 Nov 2011 01:32:59 -0800 Subject: userns: Simplify the user_namespace by making userns->creator a kuid. - Transform userns->creator from a user_struct reference to a simple kuid_t, kgid_t pair. In cap_capable this allows the check to see if we are the creator of a namespace to become the classic suser style euid permission check. This allows us to remove the need for a struct cred in the mapping functions and still be able to dispaly the user namespace creators uid and gid as 0. - Remove the now unnecessary delayed_work in free_user_ns. All that is left for free_user_ns to do is to call kmem_cache_free and put_user_ns. Those functions can be called in any context so call them directly from free_user_ns removing the need for delayed work. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/user_namespace.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index d767508db4f..8a391bd53de 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -9,8 +9,8 @@ struct user_namespace { struct kref kref; struct user_namespace *parent; - struct user_struct *creator; - struct work_struct destroyer; + kuid_t owner; + kgid_t group; }; extern struct user_namespace init_user_ns; -- cgit v1.2.3-18-g5258 From 22d917d80e842829d0ca0a561967d728eb1d6303 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 17 Nov 2011 00:11:58 -0800 Subject: userns: Rework the user_namespace adding uid/gid mapping support - Convert the old uid mapping functions into compatibility wrappers - Add a uid/gid mapping layer from user space uid and gids to kernel internal uids and gids that is extent based for simplicty and speed. * Working with number space after mapping uids/gids into their kernel internal version adds only mapping complexity over what we have today, leaving the kernel code easy to understand and test. - Add proc files /proc/self/uid_map /proc/self/gid_map These files display the mapping and allow a mapping to be added if a mapping does not exist. - Allow entering the user namespace without a uid or gid mapping. Since we are starting with an existing user our uids and gids still have global mappings so are still valid and useful they just don't have local mappings. The requirement for things to work are global uid and gid so it is odd but perfectly fine not to have a local uid and gid mapping. Not requiring global uid and gid mappings greatly simplifies the logic of setting up the uid and gid mappings by allowing the mappings to be set after the namespace is created which makes the slight weirdness worth it. - Make the mappings in the initial user namespace to the global uid/gid space explicit. Today it is an identity mapping but in the future we may want to twist this for debugging, similar to what we do with jiffies. - Document the memory ordering requirements of setting the uid and gid mappings. We only allow the mappings to be set once and there are no pointers involved so the requirments are trivial but a little atypical. Performance: In this scheme for the permission checks the performance is expected to stay the same as the actuall machine instructions should remain the same. The worst case I could think of is ls -l on a large directory where all of the stat results need to be translated with from kuids and kgids to uids and gids. So I benchmarked that case on my laptop with a dual core hyperthread Intel i5-2520M cpu with 3M of cpu cache. My benchmark consisted of going to single user mode where nothing else was running. On an ext4 filesystem opening 1,000,000 files and looping through all of the files 1000 times and calling fstat on the individuals files. This was to ensure I was benchmarking stat times where the inodes were in the kernels cache, but the inode values were not in the processors cache. My results: v3.4-rc1: ~= 156ns (unmodified v3.4-rc1 with user namespace support disabled) v3.4-rc1-userns-: ~= 155ns (v3.4-rc1 with my user namespace patches and user namespace support disabled) v3.4-rc1-userns+: ~= 164ns (v3.4-rc1 with my user namespace patches and user namespace support enabled) All of the configurations ran in roughly 120ns when I performed tests that ran in the cpu cache. So in summary the performance impact is: 1ns improvement in the worst case with user namespace support compiled out. 8ns aka 5% slowdown in the worst case with user namespace support compiled in. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/uidgid.h | 24 ++++++++++++++++++++++++ include/linux/user_namespace.h | 30 +++++++++++++++++++++++------- 2 files changed, 47 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h index 539856829ca..8e522cbcef2 100644 --- a/include/linux/uidgid.h +++ b/include/linux/uidgid.h @@ -127,6 +127,28 @@ static inline bool gid_valid(kgid_t gid) return !gid_eq(gid, INVALID_GID); } +#ifdef CONFIG_USER_NS + +extern kuid_t make_kuid(struct user_namespace *from, uid_t uid); +extern kgid_t make_kgid(struct user_namespace *from, gid_t gid); + +extern uid_t from_kuid(struct user_namespace *to, kuid_t uid); +extern gid_t from_kgid(struct user_namespace *to, kgid_t gid); +extern uid_t from_kuid_munged(struct user_namespace *to, kuid_t uid); +extern gid_t from_kgid_munged(struct user_namespace *to, kgid_t gid); + +static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid) +{ + return from_kuid(ns, uid) != (uid_t) -1; +} + +static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid) +{ + return from_kgid(ns, gid) != (gid_t) -1; +} + +#else + static inline kuid_t make_kuid(struct user_namespace *from, uid_t uid) { return KUIDT_INIT(uid); @@ -173,4 +195,6 @@ static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid) return true; } +#endif /* CONFIG_USER_NS */ + #endif /* _LINUX_UIDGID_H */ diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 8a391bd53de..4c9846d9074 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -6,7 +6,20 @@ #include #include +#define UID_GID_MAP_MAX_EXTENTS 5 + +struct uid_gid_map { /* 64 bytes -- 1 cache line */ + u32 nr_extents; + struct uid_gid_extent { + u32 first; + u32 lower_first; + u32 count; + } extent[UID_GID_MAP_MAX_EXTENTS]; +}; + struct user_namespace { + struct uid_gid_map uid_map; + struct uid_gid_map gid_map; struct kref kref; struct user_namespace *parent; kuid_t owner; @@ -33,9 +46,11 @@ static inline void put_user_ns(struct user_namespace *ns) kref_put(&ns->kref, free_user_ns); } -uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid); -gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid); - +struct seq_operations; +extern struct seq_operations proc_uid_seq_operations; +extern struct seq_operations proc_gid_seq_operations; +extern ssize_t proc_uid_map_write(struct file *, const char __user *, size_t, loff_t *); +extern ssize_t proc_gid_map_write(struct file *, const char __user *, size_t, loff_t *); #else static inline struct user_namespace *get_user_ns(struct user_namespace *ns) @@ -52,17 +67,18 @@ static inline void put_user_ns(struct user_namespace *ns) { } +#endif + static inline uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid) { - return uid; + return from_kuid_munged(to, make_kuid(cred->user_ns, uid)); } + static inline gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid) { - return gid; + return from_kgid_munged(to, make_kgid(cred->user_ns, gid)); } -#endif - #endif /* _LINUX_USER_H */ -- cgit v1.2.3-18-g5258 From ae2975bc3476243b45a1e2344236d7920c268f38 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 14 Nov 2011 15:56:38 -0800 Subject: userns: Convert group_info values from gid_t to kgid_t. As a first step to converting struct cred to be all kuid_t and kgid_t values convert the group values stored in group_info to always be kgid_t values. Unless user namespaces are used this change should have no effect. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/cred.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/cred.h b/include/linux/cred.h index 2c60ec80267..0ab3cda4a77 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -17,6 +17,7 @@ #include #include #include +#include struct user_struct; struct cred; @@ -26,14 +27,14 @@ struct inode; * COW Supplementary groups list */ #define NGROUPS_SMALL 32 -#define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(gid_t))) +#define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(kgid_t))) struct group_info { atomic_t usage; int ngroups; int nblocks; - gid_t small_block[NGROUPS_SMALL]; - gid_t *blocks[0]; + kgid_t small_block[NGROUPS_SMALL]; + kgid_t *blocks[0]; }; /** @@ -66,7 +67,7 @@ extern struct group_info init_groups; extern void groups_free(struct group_info *); extern int set_current_groups(struct group_info *); extern int set_groups(struct cred *, struct group_info *); -extern int groups_search(const struct group_info *, gid_t); +extern int groups_search(const struct group_info *, kgid_t); /* access the groups "array" with this macro */ #define GROUP_AT(gi, i) \ -- cgit v1.2.3-18-g5258 From 078de5f706ece36afd73bb4b8283314132d2dfdf Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 8 Feb 2012 07:00:08 -0800 Subject: userns: Store uid and gid values in struct cred with kuid_t and kgid_t types cred.h and a few trivial users of struct cred are changed. The rest of the users of struct cred are left for other patches as there are too many changes to make in one go and leave the change reviewable. If the user namespace is disabled and CONFIG_UIDGID_STRICT_TYPE_CHECKS are disabled the code will contiue to compile and behave correctly. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/cred.h | 16 ++++++++-------- include/linux/user_namespace.h | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/linux/cred.h b/include/linux/cred.h index 0ab3cda4a77..fac0579258f 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -123,14 +123,14 @@ struct cred { #define CRED_MAGIC 0x43736564 #define CRED_MAGIC_DEAD 0x44656144 #endif - uid_t uid; /* real UID of the task */ - gid_t gid; /* real GID of the task */ - uid_t suid; /* saved UID of the task */ - gid_t sgid; /* saved GID of the task */ - uid_t euid; /* effective UID of the task */ - gid_t egid; /* effective GID of the task */ - uid_t fsuid; /* UID for VFS ops */ - gid_t fsgid; /* GID for VFS ops */ + kuid_t uid; /* real UID of the task */ + kgid_t gid; /* real GID of the task */ + kuid_t suid; /* saved UID of the task */ + kgid_t sgid; /* saved GID of the task */ + kuid_t euid; /* effective UID of the task */ + kgid_t egid; /* effective GID of the task */ + kuid_t fsuid; /* UID for VFS ops */ + kgid_t fsgid; /* GID for VFS ops */ unsigned securebits; /* SUID-less security management */ kernel_cap_t cap_inheritable; /* caps our children can inherit */ kernel_cap_t cap_permitted; /* caps we're permitted */ diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 4c9846d9074..a2c61457cba 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -70,15 +70,15 @@ static inline void put_user_ns(struct user_namespace *ns) #endif static inline uid_t user_ns_map_uid(struct user_namespace *to, - const struct cred *cred, uid_t uid) + const struct cred *cred, kuid_t uid) { - return from_kuid_munged(to, make_kuid(cred->user_ns, uid)); + return from_kuid_munged(to, uid); } static inline gid_t user_ns_map_gid(struct user_namespace *to, - const struct cred *cred, gid_t gid) + const struct cred *cred, kgid_t gid) { - return from_kgid_munged(to, make_kgid(cred->user_ns, gid)); + return from_kgid_munged(to, gid); } #endif /* _LINUX_USER_H */ -- cgit v1.2.3-18-g5258 From 76b6db010297d4928ab7b7e7c78dd982f413f0a4 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 14 Mar 2012 15:24:19 -0700 Subject: userns: Replace user_ns_map_uid and user_ns_map_gid with from_kuid and from_kgid These function are no longer needed replace them with their more useful equivalents. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/user_namespace.h | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'include') diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index a2c61457cba..4e72922e5a7 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -69,16 +69,4 @@ static inline void put_user_ns(struct user_namespace *ns) #endif -static inline uid_t user_ns_map_uid(struct user_namespace *to, - const struct cred *cred, kuid_t uid) -{ - return from_kuid_munged(to, uid); -} - -static inline gid_t user_ns_map_gid(struct user_namespace *to, - const struct cred *cred, kgid_t gid) -{ - return from_kgid_munged(to, gid); -} - #endif /* _LINUX_USER_H */ -- cgit v1.2.3-18-g5258 From 92361636e0153bd0cb22e7dfe3fc6287f6537c66 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 8 Feb 2012 07:07:50 -0800 Subject: userns: Store uid and gid types in vfs structures with kuid_t and kgid_t types The conversion of all of the users is not done yet there are too many to change in one go and leave the code reviewable. For now I change just the header and a few trivial users and rely on CONFIG_UIDGID_STRICT_TYPE_CHECKS not being set to ensure that the code will still compile during the transition. Helper functions i_uid_read, i_uid_write, i_gid_read, i_gid_write are added so that in most cases filesystems can avoid the complexities of multiple user namespaces and can concentrate on moving their raw numeric values into and out of the vfs data structures. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/fs.h | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/linux/fs.h b/include/linux/fs.h index a6c5efbee0d..797eb262d9f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -402,6 +402,7 @@ struct inodes_stat_t { #include #include #include +#include #include @@ -469,8 +470,8 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset, struct iattr { unsigned int ia_valid; umode_t ia_mode; - uid_t ia_uid; - gid_t ia_gid; + kuid_t ia_uid; + kgid_t ia_gid; loff_t ia_size; struct timespec ia_atime; struct timespec ia_mtime; @@ -761,8 +762,8 @@ struct posix_acl; struct inode { umode_t i_mode; unsigned short i_opflags; - uid_t i_uid; - gid_t i_gid; + kuid_t i_uid; + kgid_t i_gid; unsigned int i_flags; #ifdef CONFIG_FS_POSIX_ACL @@ -927,6 +928,31 @@ static inline void i_size_write(struct inode *inode, loff_t i_size) #endif } +/* Helper functions so that in most cases filesystems will + * not need to deal directly with kuid_t and kgid_t and can + * instead deal with the raw numeric values that are stored + * in the filesystem. + */ +static inline uid_t i_uid_read(const struct inode *inode) +{ + return from_kuid(&init_user_ns, inode->i_uid); +} + +static inline gid_t i_gid_read(const struct inode *inode) +{ + return from_kgid(&init_user_ns, inode->i_gid); +} + +static inline void i_uid_write(struct inode *inode, uid_t uid) +{ + inode->i_uid = make_kuid(&init_user_ns, uid); +} + +static inline void i_gid_write(struct inode *inode, gid_t gid) +{ + inode->i_gid = make_kgid(&init_user_ns, gid); +} + static inline unsigned iminor(const struct inode *inode) { return MINOR(inode->i_rdev); @@ -943,7 +969,7 @@ struct fown_struct { rwlock_t lock; /* protects pid, uid, euid fields */ struct pid *pid; /* pid or -pgrp where SIGIO should be sent */ enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */ - uid_t uid, euid; /* uid/euid of process setting the owner */ + kuid_t uid, euid; /* uid/euid of process setting the owner */ int signum; /* posix.1b rt signal to be delivered on IO */ }; -- cgit v1.2.3-18-g5258 From 72cda3d1ef24ab0a9a89c15e9776ca737b75f45a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 9 Feb 2012 09:09:39 -0800 Subject: userns: Convert in_group_p and in_egroup_p to use kgid_t Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/cred.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/cred.h b/include/linux/cred.h index fac0579258f..917dc5aeb1d 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -73,8 +73,8 @@ extern int groups_search(const struct group_info *, kgid_t); #define GROUP_AT(gi, i) \ ((gi)->blocks[(i) / NGROUPS_PER_BLOCK][(i) % NGROUPS_PER_BLOCK]) -extern int in_group_p(gid_t); -extern int in_egroup_p(gid_t); +extern int in_group_p(kgid_t); +extern int in_egroup_p(kgid_t); /* * The common credentials for a thread group -- cgit v1.2.3-18-g5258 From 8e96e3b7b8407be794ab1fd8e4b332818a358e78 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 3 Mar 2012 21:17:15 -0800 Subject: userns: Use uid_eq gid_eq helpers when comparing kuids and kgids in the vfs Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/quotaops.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index d93f95e6177..17b977304a0 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -22,8 +22,8 @@ static inline struct quota_info *sb_dqopt(struct super_block *sb) static inline bool is_quota_modification(struct inode *inode, struct iattr *ia) { return (ia->ia_valid & ATTR_SIZE && ia->ia_size != inode->i_size) || - (ia->ia_valid & ATTR_UID && ia->ia_uid != inode->i_uid) || - (ia->ia_valid & ATTR_GID && ia->ia_gid != inode->i_gid); + (ia->ia_valid & ATTR_UID && !uid_eq(ia->ia_uid, inode->i_uid)) || + (ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid)); } #if defined(CONFIG_QUOTA) -- cgit v1.2.3-18-g5258 From a7c1938e22c02b008655524c766d185ae99d9d53 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 9 Feb 2012 09:10:30 -0800 Subject: userns: Convert stat to return values mapped from kuids and kgids - Store uids and gids with kuid_t and kgid_t in struct kstat - Convert uid and gids to userspace usable values with from_kuid and from_kgid Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/stat.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/stat.h b/include/linux/stat.h index 611c398dab7..46132409a3f 100644 --- a/include/linux/stat.h +++ b/include/linux/stat.h @@ -58,14 +58,15 @@ #include #include +#include struct kstat { u64 ino; dev_t dev; umode_t mode; unsigned int nlink; - uid_t uid; - gid_t gid; + kuid_t uid; + kgid_t gid; dev_t rdev; loff_t size; struct timespec atime; -- cgit v1.2.3-18-g5258 From 1523299d5817773e344d135d4b1c485f269400bc Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 7 Feb 2012 15:41:24 -0800 Subject: userns: Convert ext3 to use kuid/kgid where appropriate Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/trace/events/ext3.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/trace/events/ext3.h b/include/trace/events/ext3.h index 7b53c0573dc..15d11a39be4 100644 --- a/include/trace/events/ext3.h +++ b/include/trace/events/ext3.h @@ -24,8 +24,8 @@ TRACE_EVENT(ext3_free_inode, __entry->dev = inode->i_sb->s_dev; __entry->ino = inode->i_ino; __entry->mode = inode->i_mode; - __entry->uid = inode->i_uid; - __entry->gid = inode->i_gid; + __entry->uid = i_uid_read(inode); + __entry->gid = i_gid_read(inode); __entry->blocks = inode->i_blocks; ), -- cgit v1.2.3-18-g5258 From 08cefc7ab839cf3ece44b8033968a4732eac06d8 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 7 Feb 2012 15:41:49 -0800 Subject: userns: Convert ext4 to user kuid/kgid where appropriate Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/trace/events/ext4.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h index 319538bf17d..69d8a69ea83 100644 --- a/include/trace/events/ext4.h +++ b/include/trace/events/ext4.h @@ -36,8 +36,8 @@ TRACE_EVENT(ext4_free_inode, __entry->dev = inode->i_sb->s_dev; __entry->ino = inode->i_ino; __entry->mode = inode->i_mode; - __entry->uid = inode->i_uid; - __entry->gid = inode->i_gid; + __entry->uid = i_uid_read(inode); + __entry->gid = i_gid_read(inode); __entry->blocks = inode->i_blocks; ), -- cgit v1.2.3-18-g5258 From dcb0f22282e680ee5202ab7574ce78beb3803a9f Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 9 Feb 2012 08:48:21 -0800 Subject: userns: Convert proc to use kuid/kgid where appropriate Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/pid_namespace.h | 2 +- include/linux/proc_fs.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index b067bd8c49d..00474b04714 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h @@ -31,7 +31,7 @@ struct pid_namespace { #ifdef CONFIG_BSD_PROCESS_ACCT struct bsd_acct_struct *bacct; #endif - gid_t pid_gid; + kgid_t pid_gid; int hide_pid; int reboot; /* group exit code if this pidns was rebooted */ }; diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 85c50730623..3fd2e871ff1 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -52,8 +52,8 @@ struct proc_dir_entry { unsigned int low_ino; umode_t mode; nlink_t nlink; - uid_t uid; - gid_t gid; + kuid_t uid; + kgid_t gid; loff_t size; const struct inode_operations *proc_iops; /* -- cgit v1.2.3-18-g5258 From 8751e03958f2adbfba6a0f186f4c5797c950c22a Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 7 Feb 2012 16:46:12 -0800 Subject: userns: Convert tmpfs to use kuid and kgid where appropriate Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/shmem_fs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index 79ab2555b3b..bef2cf00b3b 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h @@ -28,8 +28,8 @@ struct shmem_sb_info { unsigned long max_inodes; /* How many inodes are allowed */ unsigned long free_inodes; /* How many are left for allocation */ spinlock_t stat_lock; /* Serialize shmem_sb_info changes */ - uid_t uid; /* Mount uid for root directory */ - gid_t gid; /* Mount gid for root directory */ + kuid_t uid; /* Mount uid for root directory */ + kgid_t gid; /* Mount gid for root directory */ umode_t mode; /* Mount mode for root directory */ struct mempolicy *mpol; /* default memory policy for mappings */ }; -- cgit v1.2.3-18-g5258