Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull user namespace rlimit handling update from Eric Biederman: "This is the work mainly by Alexey Gladkov to limit rlimits to the rlimits of the user that created a user namespace, and to allow users to have stricter limits on the resources created within a user namespace." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: cred: add missing return error code when set_cred_ucounts() failed ucounts: Silence warning in dec_rlimit_ucounts ucounts: Set ucount_max to the largest positive value the type can hold kselftests: Add test to check for rlimit changes in different user namespaces Reimplement RLIMIT_MEMLOCK on top of ucounts Reimplement RLIMIT_SIGPENDING on top of ucounts Reimplement RLIMIT_MSGQUEUE on top of ucounts Reimplement RLIMIT_NPROC on top of ucounts Use atomic_t for ucounts reference counting Add a reference to ucounts for each cred Increase size of ucounts to atomic_long_t
This commit is contained in:
commit
c54b245d01
29 changed files with 469 additions and 128 deletions
|
|
@ -143,6 +143,7 @@ struct cred {
|
|||
#endif
|
||||
struct user_struct *user; /* real user ID subscription */
|
||||
struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
|
||||
struct ucounts *ucounts;
|
||||
struct group_info *group_info; /* supplementary groups for euid/fsgid */
|
||||
/* RCU deletion */
|
||||
union {
|
||||
|
|
@ -169,6 +170,7 @@ extern int set_security_override_from_ctx(struct cred *, const char *);
|
|||
extern int set_create_files_as(struct cred *, struct inode *);
|
||||
extern int cred_fscmp(const struct cred *, const struct cred *);
|
||||
extern void __init cred_init(void);
|
||||
extern int set_cred_ucounts(struct cred *);
|
||||
|
||||
/*
|
||||
* check for validity of credentials
|
||||
|
|
@ -369,6 +371,7 @@ static inline void put_cred(const struct cred *_cred)
|
|||
|
||||
#define task_uid(task) (task_cred_xxx((task), uid))
|
||||
#define task_euid(task) (task_cred_xxx((task), euid))
|
||||
#define task_ucounts(task) (task_cred_xxx((task), ucounts))
|
||||
|
||||
#define current_cred_xxx(xxx) \
|
||||
({ \
|
||||
|
|
@ -385,6 +388,7 @@ 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_ucounts() (current_cred_xxx(ucounts))
|
||||
|
||||
extern struct user_namespace init_user_ns;
|
||||
#ifdef CONFIG_USER_NS
|
||||
|
|
|
|||
|
|
@ -451,7 +451,7 @@ static inline struct hugetlbfs_inode_info *HUGETLBFS_I(struct inode *inode)
|
|||
extern const struct file_operations hugetlbfs_file_operations;
|
||||
extern const struct vm_operations_struct hugetlb_vm_ops;
|
||||
struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct,
|
||||
struct user_struct **user, int creat_flags,
|
||||
struct ucounts **ucounts, int creat_flags,
|
||||
int page_size_log);
|
||||
|
||||
static inline bool is_file_hugepages(struct file *file)
|
||||
|
|
@ -471,7 +471,7 @@ static inline struct hstate *hstate_inode(struct inode *i)
|
|||
#define is_file_hugepages(file) false
|
||||
static inline struct file *
|
||||
hugetlb_file_setup(const char *name, size_t size, vm_flags_t acctflag,
|
||||
struct user_struct **user, int creat_flags,
|
||||
struct ucounts **ucounts, int creat_flags,
|
||||
int page_size_log)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
|
|
|
|||
|
|
@ -1709,8 +1709,8 @@ extern bool can_do_mlock(void);
|
|||
#else
|
||||
static inline bool can_do_mlock(void) { return false; }
|
||||
#endif
|
||||
extern int user_shm_lock(size_t, struct user_struct *);
|
||||
extern void user_shm_unlock(size_t, struct user_struct *);
|
||||
extern int user_shm_lock(size_t, struct ucounts *);
|
||||
extern void user_shm_unlock(size_t, struct ucounts *);
|
||||
|
||||
/*
|
||||
* Parameter block passed down to zap_pte_range in exceptional cases.
|
||||
|
|
|
|||
|
|
@ -12,16 +12,9 @@
|
|||
*/
|
||||
struct user_struct {
|
||||
refcount_t __count; /* reference count */
|
||||
atomic_t processes; /* How many processes does this user have? */
|
||||
atomic_t sigpending; /* How many pending signals does this user have? */
|
||||
#ifdef CONFIG_EPOLL
|
||||
atomic_long_t epoll_watches; /* The number of file descriptors currently watched */
|
||||
#endif
|
||||
#ifdef CONFIG_POSIX_MQUEUE
|
||||
/* protected by mq_lock */
|
||||
unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */
|
||||
#endif
|
||||
unsigned long locked_shm; /* How many pages of mlocked shm ? */
|
||||
unsigned long unix_inflight; /* How many files in flight in unix sockets */
|
||||
atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ extern struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt,
|
|||
extern int shmem_zero_setup(struct vm_area_struct *);
|
||||
extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
|
||||
unsigned long len, unsigned long pgoff, unsigned long flags);
|
||||
extern int shmem_lock(struct file *file, int lock, struct user_struct *user);
|
||||
extern int shmem_lock(struct file *file, int lock, struct ucounts *ucounts);
|
||||
#ifdef CONFIG_SHMEM
|
||||
extern const struct address_space_operations shmem_aops;
|
||||
static inline bool shmem_mapping(struct address_space *mapping)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ typedef struct kernel_siginfo {
|
|||
__SIGINFO;
|
||||
} kernel_siginfo_t;
|
||||
|
||||
struct ucounts;
|
||||
|
||||
/*
|
||||
* Real Time signals may be queued.
|
||||
*/
|
||||
|
|
@ -21,7 +23,7 @@ struct sigqueue {
|
|||
struct list_head list;
|
||||
int flags;
|
||||
kernel_siginfo_t info;
|
||||
struct user_struct *user;
|
||||
struct ucounts *ucounts;
|
||||
};
|
||||
|
||||
/* flags values. */
|
||||
|
|
|
|||
|
|
@ -54,9 +54,15 @@ enum ucount_type {
|
|||
UCOUNT_FANOTIFY_GROUPS,
|
||||
UCOUNT_FANOTIFY_MARKS,
|
||||
#endif
|
||||
UCOUNT_RLIMIT_NPROC,
|
||||
UCOUNT_RLIMIT_MSGQUEUE,
|
||||
UCOUNT_RLIMIT_SIGPENDING,
|
||||
UCOUNT_RLIMIT_MEMLOCK,
|
||||
UCOUNT_COUNTS,
|
||||
};
|
||||
|
||||
#define MAX_PER_NAMESPACE_UCOUNTS UCOUNT_RLIMIT_NPROC
|
||||
|
||||
struct user_namespace {
|
||||
struct uid_gid_map uid_map;
|
||||
struct uid_gid_map gid_map;
|
||||
|
|
@ -92,23 +98,42 @@ struct user_namespace {
|
|||
struct ctl_table_header *sysctls;
|
||||
#endif
|
||||
struct ucounts *ucounts;
|
||||
int ucount_max[UCOUNT_COUNTS];
|
||||
long ucount_max[UCOUNT_COUNTS];
|
||||
} __randomize_layout;
|
||||
|
||||
struct ucounts {
|
||||
struct hlist_node node;
|
||||
struct user_namespace *ns;
|
||||
kuid_t uid;
|
||||
int count;
|
||||
atomic_t ucount[UCOUNT_COUNTS];
|
||||
atomic_t count;
|
||||
atomic_long_t ucount[UCOUNT_COUNTS];
|
||||
};
|
||||
|
||||
extern struct user_namespace init_user_ns;
|
||||
extern struct ucounts init_ucounts;
|
||||
|
||||
bool setup_userns_sysctls(struct user_namespace *ns);
|
||||
void retire_userns_sysctls(struct user_namespace *ns);
|
||||
struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type);
|
||||
void dec_ucount(struct ucounts *ucounts, enum ucount_type type);
|
||||
struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid);
|
||||
struct ucounts * __must_check get_ucounts(struct ucounts *ucounts);
|
||||
void put_ucounts(struct ucounts *ucounts);
|
||||
|
||||
static inline long get_ucounts_value(struct ucounts *ucounts, enum ucount_type type)
|
||||
{
|
||||
return atomic_long_read(&ucounts->ucount[type]);
|
||||
}
|
||||
|
||||
long inc_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);
|
||||
bool dec_rlimit_ucounts(struct ucounts *ucounts, enum ucount_type type, long v);
|
||||
bool is_ucounts_overlimit(struct ucounts *ucounts, enum ucount_type type, unsigned long max);
|
||||
|
||||
static inline void set_rlimit_ucount_max(struct user_namespace *ns,
|
||||
enum ucount_type type, unsigned long max)
|
||||
{
|
||||
ns->ucount_max[type] = max <= LONG_MAX ? max : LONG_MAX;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USER_NS
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue