From: Sargun Dhillon <sargun@sargun.me>
To: linux-fsdevel@vger.kernel.org
Cc: Anna.Schumaker@Netapp.com, kinglongmee@gmail.com, ebiederm@xmission.com
Subject: [PATCH] net/sunrpc: Add user namespace support
Date: Thu, 19 Jul 2018 17:42:48 +0000 [thread overview]
Message-ID: <20180719174246.GA19824@ircssh-2.c.rugged-nimbus-611.internal> (raw)
This adds the ability to pass a non-init user namespace to rpcauth_create,
via rpc_auth_create_args. If the specific authentication mechanism
does not support non-init user namespaces, then it will return an
error.
Currently, the only two authentication mechanisms that support
non-init user namespaces are auth_null, and auth_unix. auth_unix
will send the UID / GID from the user namespace for authentication.
Signed-off-by: Sargun Dhillon <sargun@sargun.me>
---
fs/nfs/nfs4proc.c | 3 +-
include/linux/sunrpc/auth.h | 9 ++--
net/sunrpc/auth.c | 17 +++-----
net/sunrpc/auth_generic.c | 1 +
net/sunrpc/auth_gss/auth_gss.c | 10 +++--
net/sunrpc/auth_null.c | 3 +-
net/sunrpc/auth_unix.c | 97 ++++++++++++++++++++++++++++--------------
net/sunrpc/clnt.c | 5 ++-
8 files changed, 89 insertions(+), 56 deletions(-)
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 6dd146885da9..ab92ac8d48a8 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3657,7 +3657,8 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
struct nfs_fsinfo *info, rpc_authflavor_t flavor)
{
struct rpc_auth_create_args auth_args = {
- .pseudoflavor = flavor,
+ .pseudoflavor = flavor,
+ .user_ns = &init_user_ns,
};
struct rpc_auth *auth;
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index d9af474a857d..7f320be28efc 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -111,6 +111,7 @@ struct rpc_auth {
struct rpc_auth_create_args {
rpc_authflavor_t pseudoflavor;
+ struct user_namespace *user_ns;
const char *target_name;
};
@@ -125,7 +126,9 @@ struct rpc_authops {
struct module *owner;
rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */
char * au_name;
- struct rpc_auth * (*create)(struct rpc_auth_create_args *, struct rpc_clnt *);
+ bool user_ns; /* supports user namespaces */
+ struct rpc_auth * (*create)(const struct rpc_auth_create_args *,
+ struct rpc_clnt *);
void (*destroy)(struct rpc_auth *);
int (*hash_cred)(struct auth_cred *, unsigned int);
@@ -161,12 +164,10 @@ struct rpc_credops {
extern const struct rpc_authops authunix_ops;
extern const struct rpc_authops authnull_ops;
-int __init rpc_init_authunix(void);
int __init rpc_init_generic_auth(void);
int __init rpcauth_init_module(void);
void rpcauth_remove_module(void);
void rpc_destroy_generic_auth(void);
-void rpc_destroy_authunix(void);
struct rpc_cred * rpc_lookup_cred(void);
struct rpc_cred * rpc_lookup_cred_nonblock(void);
@@ -174,7 +175,7 @@ struct rpc_cred * rpc_lookup_generic_cred(struct auth_cred *, int, gfp_t);
struct rpc_cred * rpc_lookup_machine_cred(const char *service_name);
int rpcauth_register(const struct rpc_authops *);
int rpcauth_unregister(const struct rpc_authops *);
-struct rpc_auth * rpcauth_create(struct rpc_auth_create_args *,
+struct rpc_auth * rpcauth_create(const struct rpc_auth_create_args *,
struct rpc_clnt *);
void rpcauth_release(struct rpc_auth *);
rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t,
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index d2623b9f23d6..9cf1076375d5 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -253,7 +253,7 @@ rpcauth_list_flavors(rpc_authflavor_t *array, int size)
EXPORT_SYMBOL_GPL(rpcauth_list_flavors);
struct rpc_auth *
-rpcauth_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
+rpcauth_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
{
struct rpc_auth *auth;
const struct rpc_authops *ops;
@@ -272,7 +272,8 @@ rpcauth_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
goto out;
}
spin_unlock(&rpc_authflavor_lock);
- auth = ops->create(args, clnt);
+ if (args->user_ns == &init_user_ns || ops->user_ns)
+ auth = ops->create(args, clnt);
module_put(ops->owner);
if (IS_ERR(auth))
return auth;
@@ -870,27 +871,21 @@ int __init rpcauth_init_module(void)
{
int err;
- err = rpc_init_authunix();
- if (err < 0)
- goto out1;
err = rpc_init_generic_auth();
if (err < 0)
- goto out2;
+ goto out1;
err = register_shrinker(&rpc_cred_shrinker);
if (err < 0)
- goto out3;
+ goto out2;
return 0;
-out3:
- rpc_destroy_generic_auth();
out2:
- rpc_destroy_authunix();
+ rpc_destroy_generic_auth();
out1:
return err;
}
void rpcauth_remove_module(void)
{
- rpc_destroy_authunix();
rpc_destroy_generic_auth();
unregister_shrinker(&rpc_cred_shrinker);
}
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c
index f1df9837f1ac..2ce9dc8a843b 100644
--- a/net/sunrpc/auth_generic.c
+++ b/net/sunrpc/auth_generic.c
@@ -270,6 +270,7 @@ static const struct rpc_authops generic_auth_ops = {
.lookup_cred = generic_lookup_cred,
.crcreate = generic_create_cred,
.key_timeout = generic_key_timeout,
+ .user_ns = false,
};
static struct rpc_auth generic_auth = {
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index be8f103d22fd..34ec2770c71c 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -985,7 +985,7 @@ static void gss_pipe_free(struct gss_pipe *p)
* parameters based on the input flavor (which must be a pseudoflavor)
*/
static struct gss_auth *
-gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
+gss_create_new(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
{
rpc_authflavor_t flavor = args->pseudoflavor;
struct gss_auth *gss_auth;
@@ -1132,7 +1132,7 @@ gss_destroy(struct rpc_auth *auth)
* (which is guaranteed to last as long as any of its descendants).
*/
static struct gss_auth *
-gss_auth_find_or_add_hashed(struct rpc_auth_create_args *args,
+gss_auth_find_or_add_hashed(const struct rpc_auth_create_args *args,
struct rpc_clnt *clnt,
struct gss_auth *new)
{
@@ -1169,7 +1169,8 @@ gss_auth_find_or_add_hashed(struct rpc_auth_create_args *args,
}
static struct gss_auth *
-gss_create_hashed(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
+gss_create_hashed(const struct rpc_auth_create_args *args,
+ struct rpc_clnt *clnt)
{
struct gss_auth *gss_auth;
struct gss_auth *new;
@@ -1188,7 +1189,7 @@ gss_create_hashed(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
}
static struct rpc_auth *
-gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
+gss_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
{
struct gss_auth *gss_auth;
struct rpc_xprt_switch *xps = rcu_access_pointer(clnt->cl_xpi.xpi_xpswitch);
@@ -2005,6 +2006,7 @@ static const struct rpc_authops authgss_ops = {
.list_pseudoflavors = gss_mech_list_pseudoflavors,
.info2flavor = gss_mech_info2flavor,
.flavor2info = gss_mech_flavor2info,
+ .user_ns = false,
};
static const struct rpc_credops gss_credops = {
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
index 75d72e109a04..a2743bfc79f9 100644
--- a/net/sunrpc/auth_null.c
+++ b/net/sunrpc/auth_null.c
@@ -19,7 +19,7 @@ static struct rpc_auth null_auth;
static struct rpc_cred null_cred;
static struct rpc_auth *
-nul_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
+nul_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
{
atomic_inc(&null_auth.au_count);
return &null_auth;
@@ -110,6 +110,7 @@ const struct rpc_authops authnull_ops = {
.create = nul_create,
.destroy = nul_destroy,
.lookup_cred = nul_lookup_cred,
+ .user_ns = true,
};
static
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index dafd6b870ba3..9935e878aac0 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -15,10 +15,16 @@
#include <linux/sunrpc/auth.h>
#include <linux/user_namespace.h>
+struct unix_auth {
+ struct rpc_auth rpc_auth;
+ struct user_namespace *user_ns;
+};
+
struct unx_cred {
struct rpc_cred uc_base;
kgid_t uc_gid;
kgid_t uc_gids[UNX_NGROUPS];
+ struct user_namespace *user_ns;
};
#define uc_uid uc_base.cr_uid
@@ -26,31 +32,71 @@ struct unx_cred {
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
-static struct rpc_auth unix_auth;
static const struct rpc_credops unix_credops;
static struct rpc_auth *
-unx_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
+unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
{
+ struct unix_auth *unix_auth;
+ struct rpc_auth *auth;
+ int err = -ENOMEM;
+
dprintk("RPC: creating UNIX authenticator for client %p\n",
clnt);
- atomic_inc(&unix_auth.au_count);
- return &unix_auth;
+ if (!try_module_get(THIS_MODULE))
+ return ERR_PTR(-EINVAL);
+ unix_auth = kmalloc(sizeof(*unix_auth), GFP_KERNEL);
+ if (!unix_auth)
+ goto error;
+
+ unix_auth->user_ns = get_user_ns(args->user_ns);
+ auth = &unix_auth->rpc_auth;
+
+ auth->au_cslack = UNX_CALLSLACK;
+ auth->au_rslack = NUL_REPLYSLACK,
+ auth->au_flags = RPCAUTH_AUTH_NO_CRKEY_TIMEOUT,
+ auth->au_ops = &authunix_ops,
+ auth->au_flavor = RPC_AUTH_UNIX;
+ atomic_set(&unix_auth->rpc_auth.au_count, 1);
+
+ err = rpcauth_init_credcache(auth);
+ if (err)
+ goto error_free_auth;
+
+ return auth;
+
+error_free_auth:
+ put_user_ns(unix_auth->user_ns);
+ kfree(unix_auth);
+error:
+ module_put(THIS_MODULE);
+ return ERR_PTR(err);
}
static void
unx_destroy(struct rpc_auth *auth)
{
+ struct unix_auth *unix_auth;
+
+ unix_auth = container_of(auth, struct unix_auth, rpc_auth);
dprintk("RPC: destroying UNIX authenticator %p\n", auth);
- rpcauth_clear_credcache(auth->au_credcache);
+ rpcauth_destroy_credcache(auth);
+ put_user_ns(unix_auth->user_ns);
+ kfree(unix_auth);
+ module_put(THIS_MODULE);
}
static int
unx_hash_cred(struct auth_cred *acred, unsigned int hashbits)
{
- return hash_64(from_kgid(&init_user_ns, acred->gid) |
- ((u64)from_kuid(&init_user_ns, acred->uid) <<
- (sizeof(gid_t) * 8)), hashbits);
+ /*
+ * No need to convert this based on the user namespace, because
+ * the cred cache is only scoped to the unix_auth instances
+ */
+ uid_t uid = __kuid_val(acred->uid);
+ gid_t gid = __kgid_val(acred->gid);
+
+ return hash_64(gid | ((u64)uid << (sizeof(gid_t) * 8)), hashbits);
}
/*
@@ -65,19 +111,22 @@ unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
static struct rpc_cred *
unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags, gfp_t gfp)
{
+ struct unix_auth *unix_auth;
struct unx_cred *cred;
unsigned int groups = 0;
unsigned int i;
+ unix_auth = container_of(auth, struct unix_auth, rpc_auth);
dprintk("RPC: allocating UNIX cred for uid %d gid %d\n",
- from_kuid(&init_user_ns, acred->uid),
- from_kgid(&init_user_ns, acred->gid));
+ from_kuid(unix_auth->user_ns, acred->uid),
+ from_kgid(unix_auth->user_ns, acred->gid));
if (!(cred = kmalloc(sizeof(*cred), gfp)))
return ERR_PTR(-ENOMEM);
rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops);
cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
+ cred->user_ns = get_user_ns(unix_auth->user_ns);
if (acred->group_info != NULL)
groups = acred->group_info->ngroups;
@@ -97,6 +146,7 @@ static void
unx_free_cred(struct unx_cred *unx_cred)
{
dprintk("RPC: unx_free_cred %p\n", unx_cred);
+ put_user_ns(unx_cred->user_ns);
kfree(unx_cred);
}
@@ -162,11 +212,11 @@ unx_marshal(struct rpc_task *task, __be32 *p)
*/
p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
- *p++ = htonl((u32) from_kuid(&init_user_ns, cred->uc_uid));
- *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gid));
+ *p++ = htonl((u32)from_kuid(cred->user_ns, cred->uc_uid));
+ *p++ = htonl((u32)from_kgid(cred->user_ns, cred->uc_gid));
hold = p++;
for (i = 0; i < UNX_NGROUPS && gid_valid(cred->uc_gids[i]); i++)
- *p++ = htonl((u32) from_kgid(&init_user_ns, cred->uc_gids[i]));
+ *p++ = htonl((u32)from_kgid(cred->user_ns, cred->uc_gids[i]));
*hold = htonl(p - hold - 1); /* gid array length */
*base = htonl((p - base - 1) << 2); /* cred length */
@@ -211,16 +261,6 @@ unx_validate(struct rpc_task *task, __be32 *p)
return p;
}
-int __init rpc_init_authunix(void)
-{
- return rpcauth_init_credcache(&unix_auth);
-}
-
-void rpc_destroy_authunix(void)
-{
- rpcauth_destroy_credcache(&unix_auth);
-}
-
const struct rpc_authops authunix_ops = {
.owner = THIS_MODULE,
.au_flavor = RPC_AUTH_UNIX,
@@ -230,16 +270,7 @@ const struct rpc_authops authunix_ops = {
.hash_cred = unx_hash_cred,
.lookup_cred = unx_lookup_cred,
.crcreate = unx_create_cred,
-};
-
-static
-struct rpc_auth unix_auth = {
- .au_cslack = UNX_CALLSLACK,
- .au_rslack = NUL_REPLYSLACK,
- .au_flags = RPCAUTH_AUTH_NO_CRKEY_TIMEOUT,
- .au_ops = &authunix_ops,
- .au_flavor = RPC_AUTH_UNIX,
- .au_count = ATOMIC_INIT(0),
+ .user_ns = false,
};
static
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index d839c33ae7d9..33d4c18060e4 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -294,8 +294,9 @@ static int rpc_client_register(struct rpc_clnt *clnt,
const char *client_name)
{
struct rpc_auth_create_args auth_args = {
- .pseudoflavor = pseudoflavor,
- .target_name = client_name,
+ .pseudoflavor = pseudoflavor,
+ .target_name = client_name,
+ .user_ns = &init_user_ns,
};
struct rpc_auth *auth;
struct net *net = rpc_net_ns(clnt);
--
2.14.1
next reply other threads:[~2018-07-19 18:27 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-07-19 17:42 Sargun Dhillon [this message]
2018-07-19 19:45 ` [PATCH] net/sunrpc: Add user namespace support Trond Myklebust
2018-07-20 0:00 ` Sargun Dhillon
2018-07-20 0:37 ` Trond Myklebust
2018-07-20 6:12 ` Sargun Dhillon
2018-07-20 11:48 ` Trond Myklebust
2018-07-20 17:06 ` Sargun Dhillon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180719174246.GA19824@ircssh-2.c.rugged-nimbus-611.internal \
--to=sargun@sargun.me \
--cc=Anna.Schumaker@Netapp.com \
--cc=ebiederm@xmission.com \
--cc=kinglongmee@gmail.com \
--cc=linux-fsdevel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).