Re: updated ksmbd (cifsd)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On (20/12/16 13:21), Sergey Senozhatsky wrote:
> So SMB_SERVER_CHECK_CAP_NET_ADMIN enforces the "user-space must
> be a privileged process" policy. Even CAP_NET_ADMIN is too huge,
> not to mention that _probably_ this CAP requirement means that
> people will just "sudo cifsd". One way or another a malformed
> RPC request can do quite a bit of damage to the system, because
> user-space runs with the CAPs it doesn't really need.
> 
> It would be better to enforce a different policy, IMHO.
> Something like:
> 
> 	groupadd ... CIFSD_GROUP
> 	useradd -g CIFSD_GID -p CIFSD_PASSWORD CIFSD_LOGIN
> 	chmod 0700 smb.conf and password db
> 	chown CIFSD_LOGIN:CIFSD_GROUP smb.conf and password db

Just a sketch. Completely untested (wasn't even compile tested).
Merely an idea.

This removes the requirement for user-space to run as a privileged
process. Because "let's grant some random user-space daemon
administrative privileges" most likely doesn't improve security
of the system.

So the idea is to provide CIFSD administrator UID and GID during
kcifsd modprobe and then in IPC handlers check if the app issuing
a netlink syscall has the same UID and GID as the CIFSD administrator
or not.

This untested, sorry. Just checking the idea.

---

diff --git a/fs/cifsd/Kconfig b/fs/cifsd/Kconfig
index e12616cf8477..9f221a37223d 100644
--- a/fs/cifsd/Kconfig
+++ b/fs/cifsd/Kconfig
@@ -50,14 +50,6 @@ config SMB_SERVER_SMBDIRECT
 	  SMB Direct allows transferring SMB packets over RDMA. If unsure,
 	  say N.
 
-config SMB_SERVER_CHECK_CAP_NET_ADMIN
-	bool "Enable check network administration capability"
-	depends on SMB_SERVER
-	default n
-
-	help
-	  Prevent unprivileged processes to start the cifsd kernel server.
-
 config SMB_SERVER_KERBEROS5
 	bool "Support for Kerberos 5"
 	depends on SMB_SERVER
diff --git a/fs/cifsd/server.c b/fs/cifsd/server.c
index b9e114f8a5d2..dbbdb3503b0d 100644
--- a/fs/cifsd/server.c
+++ b/fs/cifsd/server.c
@@ -25,6 +25,7 @@
 
 int ksmbd_debug_types;
 
+static int admin_uid = -1, admin_gid = -1;
 struct ksmbd_server_config server_conf;
 
 enum SERVER_CTRL_TYPE {
@@ -335,6 +336,26 @@ static void server_conf_free(void)
 	}
 }
 
+static int server_admin_cred_init(void)
+{
+	if (admin_uid == -1 || admin_gid == -1)
+		return 0;
+
+	server_conf.admin_cred = kmalloc(sizeof(struct admin_cred), GFP_KERNEL);
+	if (!server_conf.admin_cred)
+		return -ENOMEM;
+
+	server_conf.admin_cred.uid = make_kuid(&init_user_ns, admin_uid);
+	server_conf.admin_cred.gid = make_kgid(&init_user_ns, admin_gid);
+	if (!(uid_validserver_conf.admin_cred.uid() &&
+	      gid_valid(server_conf.admin_cred.gid))) {
+		kfree(server_conf.admin_cred);
+		server_conf.admin_cred = NULL;
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int server_conf_init(void)
 {
 	WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP);
@@ -343,10 +364,9 @@ static int server_conf_init(void)
 	server_conf.max_protocol = ksmbd_max_protocol();
 	server_conf.auth_mechs = KSMBD_AUTH_NTLMSSP;
 #ifdef CONFIG_SMB_SERVER_KERBEROS5
-	server_conf.auth_mechs |= KSMBD_AUTH_KRB5 |
-				KSMBD_AUTH_MSKRB5;
+	server_conf.auth_mechs |= KSMBD_AUTH_KRB5 | KSMBD_AUTH_MSKRB5;
 #endif
-	return 0;
+	return server_admin_cred_init();
 }
 
 static void server_ctrl_handle_init(struct server_ctrl_struct *ctrl)
@@ -418,6 +438,21 @@ int server_queue_ctrl_reset_work(void)
 	return __queue_ctrl_work(SERVER_CTRL_TYPE_RESET);
 }
 
+int server_validate_admin_cred(void)
+{
+	if (admin_uid == -1 || admin_gid == -1)
+		return 0;
+
+	/* We couldn't init server admin UID/GID */
+	if (!server_conf.admin_cred)
+		return -EINVAL;
+
+	if (uid_eq(task_uid(current), server_conf.admin_cred.uid) &&
+	    gid_eq(task_gid(current), server_conf.admin_cred.gid))
+		return 0;
+	return -EINVAL;
+}
+
 static ssize_t stats_show(struct class *class,
 			  struct class_attribute *attr,
 			  char *buf)
@@ -614,6 +649,11 @@ static void __exit ksmbd_server_exit(void)
 	ksmbd_release_inode_hash();
 }
 
+module_param(admin_uid, int, 0);
+MODULE_PARM_DESC(admin_uid, "ksmb administrator user id");
+module_param(admin_gid, int, 0);
+MODULE_PARM_DESC(admin_gid, "ksmb administrator group id");
+
 MODULE_AUTHOR("Namjae Jeon <linkinjeon@xxxxxxxxxx>");
 MODULE_VERSION(KSMBD_VERSION);
 MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER");
diff --git a/fs/cifsd/server.h b/fs/cifsd/server.h
index 7b2f6318fcff..ed0249061470 100644
--- a/fs/cifsd/server.h
+++ b/fs/cifsd/server.h
@@ -19,6 +19,11 @@
 
 extern int ksmbd_debugging;
 
+struct admin_cred {
+	kuid_t			uid;
+	kgid_t			gid;
+};
+
 struct ksmbd_server_config {
 	unsigned int		flags;
 	unsigned int		state;
@@ -34,6 +39,7 @@ struct ksmbd_server_config {
 	struct smb_sid		domain_sid;
 	unsigned int		auth_mechs;
 
+	struct admin_cred	*admin_cred;
 	char			*conf[SERVER_CONF_WORK_GROUP + 1];
 };
 
@@ -57,6 +63,7 @@ static inline int ksmbd_server_configurable(void)
 	return READ_ONCE(server_conf.state) < SERVER_STATE_RESETTING;
 }
 
+int server_verify_admin_cred(void);
 int server_queue_ctrl_init_work(void);
 int server_queue_ctrl_reset_work(void);
 #endif /* __SERVER_H__ */
diff --git a/fs/cifsd/transport_ipc.c b/fs/cifsd/transport_ipc.c
index 5f24a1ed5c34..b2a42f6ce6e3 100644
--- a/fs/cifsd/transport_ipc.c
+++ b/fs/cifsd/transport_ipc.c
@@ -345,10 +345,8 @@ static int handle_startup_event(struct sk_buff *skb, struct genl_info *info)
 {
 	int ret = 0;
 
-#ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN
-	if (!netlink_capable(skb, CAP_NET_ADMIN))
+	if (server_validate_admin_cred())
 		return -EPERM;
-#endif
 
 	if (!ksmbd_ipc_validate_version(info))
 		return -EINVAL;
@@ -401,10 +399,8 @@ static int handle_generic_event(struct sk_buff *skb, struct genl_info *info)
 	int sz;
 	int type = info->genlhdr->cmd;
 
-#ifdef CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN
-	if (!netlink_capable(skb, CAP_NET_ADMIN))
+	if (server_validate_admin_cred())
 		return -EPERM;
-#endif
 
 	if (type >= KSMBD_EVENT_MAX) {
 		WARN_ON(1);



[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux