Commit 7dc5dbc8 authored by Eric W. Biederman's avatar Eric W. Biederman

sysfs: Restrict mounting sysfs

Don't allow mounting sysfs unless the caller has CAP_SYS_ADMIN rights
over the net namespace.  The principle here is if you create or have
capabilities over it you can mount it, otherwise you get to live with
what other people have mounted.

Instead of testing this with a straight forward ns_capable call,
perform this check the long and torturous way with kobject helpers,
this keeps direct knowledge of namespaces out of sysfs, and preserves
the existing sysfs abstractions.
Acked-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent e51db735
...@@ -112,10 +112,16 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, ...@@ -112,10 +112,16 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
struct super_block *sb; struct super_block *sb;
int error; int error;
if (!(flags & MS_KERNMOUNT) && !capable(CAP_SYS_ADMIN) && if (!(flags & MS_KERNMOUNT)) {
!fs_fully_visible(fs_type)) if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
return ERR_PTR(-EPERM); return ERR_PTR(-EPERM);
for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) {
if (!kobj_ns_current_may_mount(type))
return ERR_PTR(-EPERM);
}
}
info = kzalloc(sizeof(*info), GFP_KERNEL); info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -39,6 +39,7 @@ enum kobj_ns_type { ...@@ -39,6 +39,7 @@ enum kobj_ns_type {
*/ */
struct kobj_ns_type_operations { struct kobj_ns_type_operations {
enum kobj_ns_type type; enum kobj_ns_type type;
bool (*current_may_mount)(void);
void *(*grab_current_ns)(void); void *(*grab_current_ns)(void);
const void *(*netlink_ns)(struct sock *sk); const void *(*netlink_ns)(struct sock *sk);
const void *(*initial_ns)(void); const void *(*initial_ns)(void);
...@@ -50,6 +51,7 @@ int kobj_ns_type_registered(enum kobj_ns_type type); ...@@ -50,6 +51,7 @@ int kobj_ns_type_registered(enum kobj_ns_type type);
const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent);
const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj);
bool kobj_ns_current_may_mount(enum kobj_ns_type type);
void *kobj_ns_grab_current(enum kobj_ns_type type); void *kobj_ns_grab_current(enum kobj_ns_type type);
const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk);
const void *kobj_ns_initial(enum kobj_ns_type type); const void *kobj_ns_initial(enum kobj_ns_type type);
......
...@@ -915,6 +915,21 @@ const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj) ...@@ -915,6 +915,21 @@ const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj)
return kobj_child_ns_ops(kobj->parent); return kobj_child_ns_ops(kobj->parent);
} }
bool kobj_ns_current_may_mount(enum kobj_ns_type type)
{
bool may_mount = false;
if (type == KOBJ_NS_TYPE_NONE)
return true;
spin_lock(&kobj_ns_type_lock);
if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) &&
kobj_ns_ops_tbl[type])
may_mount = kobj_ns_ops_tbl[type]->current_may_mount();
spin_unlock(&kobj_ns_type_lock);
return may_mount;
}
void *kobj_ns_grab_current(enum kobj_ns_type type) void *kobj_ns_grab_current(enum kobj_ns_type type)
{ {
......
...@@ -1157,6 +1157,13 @@ static void remove_queue_kobjects(struct net_device *net) ...@@ -1157,6 +1157,13 @@ static void remove_queue_kobjects(struct net_device *net)
#endif #endif
} }
static bool net_current_may_mount(void)
{
struct net *net = current->nsproxy->net_ns;
return ns_capable(net->user_ns, CAP_SYS_ADMIN);
}
static void *net_grab_current_ns(void) static void *net_grab_current_ns(void)
{ {
struct net *ns = current->nsproxy->net_ns; struct net *ns = current->nsproxy->net_ns;
...@@ -1179,6 +1186,7 @@ static const void *net_netlink_ns(struct sock *sk) ...@@ -1179,6 +1186,7 @@ static const void *net_netlink_ns(struct sock *sk)
struct kobj_ns_type_operations net_ns_type_operations = { struct kobj_ns_type_operations net_ns_type_operations = {
.type = KOBJ_NS_TYPE_NET, .type = KOBJ_NS_TYPE_NET,
.current_may_mount = net_current_may_mount,
.grab_current_ns = net_grab_current_ns, .grab_current_ns = net_grab_current_ns,
.netlink_ns = net_netlink_ns, .netlink_ns = net_netlink_ns,
.initial_ns = net_initial_ns, .initial_ns = net_initial_ns,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment