The following patchset attempts to make knfsd more friendly to
containers that are set up with container-level uid/gid mapping. The
principles used are as follows:
- Assume upcalls for idmapping and RPCSEC_GSS should make use of the
user namespace of the idmapper/rpcsec_gss daemon, which can be
extracted from the cred used to open the upcall/downcall pseudo file.
- Assume downcalls may use the current_user_ns(), since the process
context is that of the userland daemon that performs the downcall.
- Assume that wire protocols are mapped with of the user namespace of
the process that started the knfsd server in the first place.
i.e. that AUTH_UNIX and possibly the SETATTR/GETATTR uids and gids
belong to the same user namespace as the process that started knfsd.
This should ensure that knfsd matches the behaviour of a generic
userspace NFS server running in the same circumstances.
Trond Myklebust (5):
SUNRPC: Cache the process user cred in the RPC server listener
lockd: Pass the user cred from knfsd when starting the lockd server
SUNRPC: Fix the server AUTH_UNIX userspace mappings
SUNRPC: rsi_parse() should use the current user namespace
nfsd: knfsd must use the container user namespace
fs/lockd/clntlock.c | 4 ++--
fs/lockd/svc.c | 29 +++++++++++++++++------------
fs/nfs/callback.c | 7 +++++--
fs/nfs/client.c | 1 +
fs/nfsd/export.c | 18 ++++++++++--------
fs/nfsd/nfs3xdr.c | 21 +++++++++++----------
fs/nfsd/nfs4idmap.c | 8 ++++----
fs/nfsd/nfs4xdr.c | 5 +++--
fs/nfsd/nfsctl.c | 16 ++++++++--------
fs/nfsd/nfsd.h | 9 ++++++++-
fs/nfsd/nfssvc.c | 16 ++++++++--------
fs/nfsd/nfsxdr.c | 17 +++++++++--------
include/linux/lockd/bind.h | 3 ++-
include/linux/sunrpc/svc_xprt.h | 4 +++-
include/linux/sunrpc/svcsock.h | 3 ++-
net/sunrpc/auth_gss/svcauth_gss.c | 6 +++---
net/sunrpc/svc_xprt.c | 12 ++++++++----
net/sunrpc/svcauth_unix.c | 15 +++++++++------
net/sunrpc/svcsock.c | 4 +++-
19 files changed, 116 insertions(+), 82 deletions(-)
--
2.20.1
In order to be able to interpret uids and gids correctly in knfsd, we
should cache the user namespace of the process that created the RPC
server's listener. To do so, we refcount the credential of that process.
Signed-off-by: Trond Myklebust <[email protected]>
---
fs/lockd/svc.c | 3 ++-
fs/nfs/callback.c | 7 +++++--
fs/nfsd/nfsctl.c | 16 ++++++++--------
fs/nfsd/nfsd.h | 2 +-
fs/nfsd/nfssvc.c | 14 +++++++-------
include/linux/sunrpc/svc_xprt.h | 4 +++-
include/linux/sunrpc/svcsock.h | 3 ++-
net/sunrpc/svc_xprt.c | 12 ++++++++----
net/sunrpc/svcsock.c | 4 +++-
9 files changed, 39 insertions(+), 26 deletions(-)
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 96bb74c919f9..82aa0f35e43d 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -190,12 +190,13 @@ static int create_lockd_listener(struct svc_serv *serv, const char *name,
struct net *net, const int family,
const unsigned short port)
{
+ const struct cred *cred = current_cred();
struct svc_xprt *xprt;
xprt = svc_find_xprt(serv, name, net, family, 0);
if (xprt == NULL)
return svc_create_xprt(serv, name, net, family, port,
- SVC_SOCK_DEFAULTS);
+ SVC_SOCK_DEFAULTS, cred);
svc_xprt_put(xprt);
return 0;
}
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 15c9575e0e7a..7817ad94a6ba 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -41,11 +41,13 @@ static struct svc_program nfs4_callback_program;
static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)
{
+ const struct cred *cred = current_cred();
int ret;
struct nfs_net *nn = net_generic(net, nfs_net_id);
ret = svc_create_xprt(serv, "tcp", net, PF_INET,
- nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+ nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS,
+ cred);
if (ret <= 0)
goto out_err;
nn->nfs_callback_tcpport = ret;
@@ -53,7 +55,8 @@ static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net)
nn->nfs_callback_tcpport, PF_INET, net->ns.inum);
ret = svc_create_xprt(serv, "tcp", net, PF_INET6,
- nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
+ nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS,
+ cred);
if (ret > 0) {
nn->nfs_callback_tcpport6 = ret;
dprintk("NFS: Callback listener port = %u (af %u, net %x)\n",
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 2dc5a73cc464..4f9d9ea9ddfd 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -439,7 +439,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
return rv;
if (newthreads < 0)
return -EINVAL;
- rv = nfsd_svc(newthreads, net);
+ rv = nfsd_svc(newthreads, net, file->f_cred);
if (rv < 0)
return rv;
} else
@@ -717,7 +717,7 @@ static ssize_t __write_ports_names(char *buf, struct net *net)
* a socket of a supported family/protocol, and we use it as an
* nfsd listener.
*/
-static ssize_t __write_ports_addfd(char *buf, struct net *net)
+static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred *cred)
{
char *mesg = buf;
int fd, err;
@@ -736,7 +736,7 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net)
if (err != 0)
return err;
- err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
+ err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred);
if (err < 0) {
nfsd_destroy(net);
return err;
@@ -751,7 +751,7 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net)
* A transport listener is added by writing it's transport name and
* a port number.
*/
-static ssize_t __write_ports_addxprt(char *buf, struct net *net)
+static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cred *cred)
{
char transport[16];
struct svc_xprt *xprt;
@@ -769,12 +769,12 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net)
return err;
err = svc_create_xprt(nn->nfsd_serv, transport, net,
- PF_INET, port, SVC_SOCK_ANONYMOUS);
+ PF_INET, port, SVC_SOCK_ANONYMOUS, cred);
if (err < 0)
goto out_err;
err = svc_create_xprt(nn->nfsd_serv, transport, net,
- PF_INET6, port, SVC_SOCK_ANONYMOUS);
+ PF_INET6, port, SVC_SOCK_ANONYMOUS, cred);
if (err < 0 && err != -EAFNOSUPPORT)
goto out_close;
@@ -799,10 +799,10 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size,
return __write_ports_names(buf, net);
if (isdigit(buf[0]))
- return __write_ports_addfd(buf, net);
+ return __write_ports_addfd(buf, net, file->f_cred);
if (isalpha(buf[0]))
- return __write_ports_addxprt(buf, net);
+ return __write_ports_addxprt(buf, net, file->f_cred);
return -EINVAL;
}
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 6bae2554b2b2..d200c8680259 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -73,7 +73,7 @@ extern const struct seq_operations nfs_exports_op;
/*
* Function prototypes.
*/
-int nfsd_svc(int nrservs, struct net *net);
+int nfsd_svc(int nrservs, struct net *net, const struct cred *cred);
int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
int nfsd_nrthreads(struct net *);
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 16fd157e7651..c98d4e2bc619 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -289,7 +289,7 @@ int nfsd_nrthreads(struct net *net)
return rv;
}
-static int nfsd_init_socks(struct net *net)
+static int nfsd_init_socks(struct net *net, const struct cred *cred)
{
int error;
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
@@ -298,12 +298,12 @@ static int nfsd_init_socks(struct net *net)
return 0;
error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT,
- SVC_SOCK_DEFAULTS);
+ SVC_SOCK_DEFAULTS, cred);
if (error < 0)
return error;
error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT,
- SVC_SOCK_DEFAULTS);
+ SVC_SOCK_DEFAULTS, cred);
if (error < 0)
return error;
@@ -354,7 +354,7 @@ static bool nfsd_needs_lockd(struct nfsd_net *nn)
return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST);
}
-static int nfsd_startup_net(int nrservs, struct net *net)
+static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cred)
{
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
int ret;
@@ -365,7 +365,7 @@ static int nfsd_startup_net(int nrservs, struct net *net)
ret = nfsd_startup_generic(nrservs);
if (ret)
return ret;
- ret = nfsd_init_socks(net);
+ ret = nfsd_init_socks(net, cred);
if (ret)
goto out_socks;
@@ -703,7 +703,7 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
* this is the first time nrservs is nonzero.
*/
int
-nfsd_svc(int nrservs, struct net *net)
+nfsd_svc(int nrservs, struct net *net, const struct cred *cred)
{
int error;
bool nfsd_up_before;
@@ -725,7 +725,7 @@ nfsd_svc(int nrservs, struct net *net)
nfsd_up_before = nn->nfsd_net_up;
- error = nfsd_startup_net(nrservs, net);
+ error = nfsd_startup_net(nrservs, net, cred);
if (error)
goto out_destroy;
error = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv,
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index b3f9577e17d6..ea6f46be9cb7 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -86,6 +86,7 @@ struct svc_xprt {
struct list_head xpt_users; /* callbacks on free */
struct net *xpt_net;
+ const struct cred *xpt_cred;
struct rpc_xprt *xpt_bc_xprt; /* NFSv4.1 backchannel */
struct rpc_xprt_switch *xpt_bc_xps; /* NFSv4.1 backchannel */
};
@@ -119,7 +120,8 @@ void svc_unreg_xprt_class(struct svc_xprt_class *);
void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *,
struct svc_serv *);
int svc_create_xprt(struct svc_serv *, const char *, struct net *,
- const int, const unsigned short, int);
+ const int, const unsigned short, int,
+ const struct cred *);
void svc_xprt_do_enqueue(struct svc_xprt *xprt);
void svc_xprt_enqueue(struct svc_xprt *xprt);
void svc_xprt_put(struct svc_xprt *xprt);
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 119718a922f2..771baadaee9d 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -59,7 +59,8 @@ void svc_drop(struct svc_rqst *);
void svc_sock_update_bufs(struct svc_serv *serv);
bool svc_alien_sock(struct net *net, int fd);
int svc_addsock(struct svc_serv *serv, const int fd,
- char *name_return, const size_t len);
+ char *name_return, const size_t len,
+ const struct cred *cred);
void svc_init_xprt_sock(void);
void svc_cleanup_xprt_sock(void);
struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot);
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index 61530b1b7754..b76ee83d4d43 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -136,6 +136,7 @@ static void svc_xprt_free(struct kref *kref)
struct module *owner = xprt->xpt_class->xcl_owner;
if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags))
svcauth_unix_info_release(xprt);
+ put_cred(xprt->xpt_cred);
put_net(xprt->xpt_net);
/* See comment on corresponding get in xs_setup_bc_tcp(): */
if (xprt->xpt_bc_xprt)
@@ -252,7 +253,8 @@ void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new)
static int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
struct net *net, const int family,
- const unsigned short port, int flags)
+ const unsigned short port, int flags,
+ const struct cred *cred)
{
struct svc_xprt_class *xcl;
@@ -273,6 +275,7 @@ static int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
module_put(xcl->xcl_owner);
return PTR_ERR(newxprt);
}
+ newxprt->xpt_cred = get_cred(cred);
svc_add_new_perm_xprt(serv, newxprt);
newport = svc_xprt_local_port(newxprt);
return newport;
@@ -286,15 +289,16 @@ static int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
int svc_create_xprt(struct svc_serv *serv, const char *xprt_name,
struct net *net, const int family,
- const unsigned short port, int flags)
+ const unsigned short port, int flags,
+ const struct cred *cred)
{
int err;
dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
- err = _svc_create_xprt(serv, xprt_name, net, family, port, flags);
+ err = _svc_create_xprt(serv, xprt_name, net, family, port, flags, cred);
if (err == -EPROTONOSUPPORT) {
request_module("svc%s", xprt_name);
- err = _svc_create_xprt(serv, xprt_name, net, family, port, flags);
+ err = _svc_create_xprt(serv, xprt_name, net, family, port, flags, cred);
}
if (err < 0)
dprintk("svc: transport %s not found, err %d\n",
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 43590a968b73..540fde2804d0 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1332,13 +1332,14 @@ EXPORT_SYMBOL_GPL(svc_alien_sock);
* @fd: file descriptor of the new listener
* @name_return: pointer to buffer to fill in with name of listener
* @len: size of the buffer
+ * @cred: credential
*
* Fills in socket name and returns positive length of name if successful.
* Name is terminated with '\n'. On error, returns a negative errno
* value.
*/
int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
- const size_t len)
+ const size_t len, const struct cred *cred)
{
int err = 0;
struct socket *so = sockfd_lookup(fd, &err);
@@ -1371,6 +1372,7 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
salen = kernel_getsockname(svsk->sk_sock, sin);
if (salen >= 0)
svc_xprt_set_local(&svsk->sk_xprt, sin, salen);
+ svsk->sk_xprt.xpt_cred = get_cred(cred);
svc_add_new_perm_xprt(serv, &svsk->sk_xprt);
return svc_one_sock_name(svsk, name_return, len);
out:
--
2.20.1
When starting up a new knfsd server, pass the user cred to the
supporting lockd server.
Signed-off-by: Trond Myklebust <[email protected]>
---
fs/lockd/clntlock.c | 4 ++--
fs/lockd/svc.c | 28 ++++++++++++++++------------
fs/nfs/client.c | 1 +
fs/nfsd/nfssvc.c | 2 +-
include/linux/lockd/bind.h | 3 ++-
5 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index c2a128678e6e..d61b72b693cf 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -56,7 +56,7 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4;
int status;
- status = lockd_up(nlm_init->net);
+ status = lockd_up(nlm_init->net, nlm_init->cred);
if (status < 0)
return ERR_PTR(status);
@@ -241,7 +241,7 @@ reclaimer(void *ptr)
allow_signal(SIGKILL);
down_write(&host->h_rwsem);
- lockd_up(net); /* note: this cannot fail as lockd is already running */
+ lockd_up(net, NULL); /* note: this cannot fail as lockd is already running */
dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 82aa0f35e43d..3056f3a0c270 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -188,9 +188,9 @@ lockd(void *vrqstp)
static int create_lockd_listener(struct svc_serv *serv, const char *name,
struct net *net, const int family,
- const unsigned short port)
+ const unsigned short port,
+ const struct cred *cred)
{
- const struct cred *cred = current_cred();
struct svc_xprt *xprt;
xprt = svc_find_xprt(serv, name, net, family, 0);
@@ -202,15 +202,17 @@ static int create_lockd_listener(struct svc_serv *serv, const char *name,
}
static int create_lockd_family(struct svc_serv *serv, struct net *net,
- const int family)
+ const int family, const struct cred *cred)
{
int err;
- err = create_lockd_listener(serv, "udp", net, family, nlm_udpport);
+ err = create_lockd_listener(serv, "udp", net, family, nlm_udpport,
+ cred);
if (err < 0)
return err;
- return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport);
+ return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport,
+ cred);
}
/*
@@ -223,16 +225,17 @@ static int create_lockd_family(struct svc_serv *serv, struct net *net,
* Returns zero if all listeners are available; otherwise a
* negative errno value is returned.
*/
-static int make_socks(struct svc_serv *serv, struct net *net)
+static int make_socks(struct svc_serv *serv, struct net *net,
+ const struct cred *cred)
{
static int warned;
int err;
- err = create_lockd_family(serv, net, PF_INET);
+ err = create_lockd_family(serv, net, PF_INET, cred);
if (err < 0)
goto out_err;
- err = create_lockd_family(serv, net, PF_INET6);
+ err = create_lockd_family(serv, net, PF_INET6, cred);
if (err < 0 && err != -EAFNOSUPPORT)
goto out_err;
@@ -247,7 +250,8 @@ static int make_socks(struct svc_serv *serv, struct net *net)
return err;
}
-static int lockd_up_net(struct svc_serv *serv, struct net *net)
+static int lockd_up_net(struct svc_serv *serv, struct net *net,
+ const struct cred *cred)
{
struct lockd_net *ln = net_generic(net, lockd_net_id);
int error;
@@ -259,7 +263,7 @@ static int lockd_up_net(struct svc_serv *serv, struct net *net)
if (error)
goto err_bind;
- error = make_socks(serv, net);
+ error = make_socks(serv, net, cred);
if (error < 0)
goto err_bind;
set_grace_period(net);
@@ -462,7 +466,7 @@ static struct svc_serv *lockd_create_svc(void)
/*
* Bring up the lockd process if it's not already up.
*/
-int lockd_up(struct net *net)
+int lockd_up(struct net *net, const struct cred *cred)
{
struct svc_serv *serv;
int error;
@@ -475,7 +479,7 @@ int lockd_up(struct net *net)
goto err_create;
}
- error = lockd_up_net(serv, net);
+ error = lockd_up_net(serv, net, cred);
if (error < 0) {
lockd_unregister_notifiers();
goto err_put;
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 90d71fda65ce..92d07d99829d 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -552,6 +552,7 @@ static int nfs_start_lockd(struct nfs_server *server)
1 : 0,
.net = clp->cl_net,
.nlmclnt_ops = clp->cl_nfs_mod->rpc_ops->nlmclnt_ops,
+ .cred = current_cred(),
};
if (nlm_init.nfs_version > 3)
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index c98d4e2bc619..2a05dfe7c111 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -370,7 +370,7 @@ static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cre
goto out_socks;
if (nfsd_needs_lockd(nn) && !nn->lockd_up) {
- ret = lockd_up(net);
+ ret = lockd_up(net, cred);
if (ret)
goto out_socks;
nn->lockd_up = 1;
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index 053a4ef3d431..0520c0cd73f4 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -46,6 +46,7 @@ struct nlmclnt_initdata {
int noresvport;
struct net *net;
const struct nlmclnt_operations *nlmclnt_ops;
+ const struct cred *cred;
};
/*
@@ -75,7 +76,7 @@ struct nlmclnt_operations {
};
extern int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl, void *data);
-extern int lockd_up(struct net *net);
+extern int lockd_up(struct net *net, const struct cred *cred);
extern void lockd_down(struct net *net);
#endif /* LINUX_LOCKD_BIND_H */
--
2.20.1
gid_parse() is part of a downcall, so uids and gids should be assumed
encoded using the current user namespace.
svcauth_unix_accept() is, on the other hand, decoding uids and gids from
the wire, so we assume those are encoded to match the user namespace of
the server process.
Signed-off-by: Trond Myklebust <[email protected]>
---
net/sunrpc/svcauth_unix.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index fb9041b92f72..f92ef79c8ea5 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -500,7 +500,7 @@ static int unix_gid_parse(struct cache_detail *cd,
rv = get_int(&mesg, &id);
if (rv)
return -EINVAL;
- uid = make_kuid(&init_user_ns, id);
+ uid = make_kuid(current_user_ns(), id);
ug.uid = uid;
expiry = get_expiry(&mesg);
@@ -522,7 +522,7 @@ static int unix_gid_parse(struct cache_detail *cd,
err = -EINVAL;
if (rv)
goto out;
- kgid = make_kgid(&init_user_ns, gid);
+ kgid = make_kgid(current_user_ns(), gid);
if (!gid_valid(kgid))
goto out;
ug.gi->gid[i] = kgid;
@@ -555,7 +555,7 @@ static int unix_gid_show(struct seq_file *m,
struct cache_detail *cd,
struct cache_head *h)
{
- struct user_namespace *user_ns = &init_user_ns;
+ struct user_namespace *user_ns = m->file->f_cred->user_ns;
struct unix_gid *ug;
int i;
int glen;
@@ -796,6 +796,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0];
struct svc_cred *cred = &rqstp->rq_cred;
+ struct user_namespace *userns;
u32 slen, i;
int len = argv->iov_len;
@@ -816,8 +817,10 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
* (export-specific) anonymous id by nfsd_setuser.
* Supplementary gid's will be left alone.
*/
- cred->cr_uid = make_kuid(&init_user_ns, svc_getnl(argv)); /* uid */
- cred->cr_gid = make_kgid(&init_user_ns, svc_getnl(argv)); /* gid */
+ userns = (rqstp->rq_xprt && rqstp->rq_xprt->xpt_cred) ?
+ rqstp->rq_xprt->xpt_cred->user_ns : &init_user_ns;
+ cred->cr_uid = make_kuid(userns, svc_getnl(argv)); /* uid */
+ cred->cr_gid = make_kgid(userns, svc_getnl(argv)); /* gid */
slen = svc_getnl(argv); /* gids length */
if (slen > UNX_NGROUPS || (len -= (slen + 2)*4) < 0)
goto badcred;
@@ -825,7 +828,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
if (cred->cr_group_info == NULL)
return SVC_CLOSE;
for (i = 0; i < slen; i++) {
- kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv));
+ kgid_t kgid = make_kgid(userns, svc_getnl(argv));
cred->cr_group_info->gid[i] = kgid;
}
groups_sort(cred->cr_group_info);
--
2.20.1
rsi_parse() is part of a downcall, so we must assume that the uids
and gids are encoded using the current user namespace.
Signed-off-by: Trond Myklebust <[email protected]>
---
net/sunrpc/auth_gss/svcauth_gss.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 0c5d7896d6dd..8be2f209982b 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -474,12 +474,12 @@ static int rsc_parse(struct cache_detail *cd,
* treatment so are checked for validity here.)
*/
/* uid */
- rsci.cred.cr_uid = make_kuid(&init_user_ns, id);
+ rsci.cred.cr_uid = make_kuid(current_user_ns(), id);
/* gid */
if (get_int(&mesg, &id))
goto out;
- rsci.cred.cr_gid = make_kgid(&init_user_ns, id);
+ rsci.cred.cr_gid = make_kgid(current_user_ns(), id);
/* number of additional gid's */
if (get_int(&mesg, &N))
@@ -497,7 +497,7 @@ static int rsc_parse(struct cache_detail *cd,
kgid_t kgid;
if (get_int(&mesg, &id))
goto out;
- kgid = make_kgid(&init_user_ns, id);
+ kgid = make_kgid(current_user_ns(), id);
if (!gid_valid(kgid))
goto out;
rsci.cred.cr_group_info->gid[i] = kgid;
--
2.20.1
Convert knfsd to use the user namespace of the container that started
the server processes.
Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfsd/export.c | 18 ++++++++++--------
fs/nfsd/nfs3xdr.c | 21 +++++++++++----------
fs/nfsd/nfs4idmap.c | 8 ++++----
fs/nfsd/nfs4xdr.c | 5 +++--
fs/nfsd/nfsd.h | 7 +++++++
fs/nfsd/nfsxdr.c | 17 +++++++++--------
6 files changed, 44 insertions(+), 32 deletions(-)
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 802993d8912f..baa01956a5b3 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -570,13 +570,13 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
err = get_int(&mesg, &an_int);
if (err)
goto out3;
- exp.ex_anon_uid= make_kuid(&init_user_ns, an_int);
+ exp.ex_anon_uid= make_kuid(current_user_ns(), an_int);
/* anon gid */
err = get_int(&mesg, &an_int);
if (err)
goto out3;
- exp.ex_anon_gid= make_kgid(&init_user_ns, an_int);
+ exp.ex_anon_gid= make_kgid(current_user_ns(), an_int);
/* fsid */
err = get_int(&mesg, &an_int);
@@ -1170,15 +1170,17 @@ static void show_secinfo(struct seq_file *m, struct svc_export *exp)
static void exp_flags(struct seq_file *m, int flag, int fsid,
kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fsloc)
{
+ struct user_namespace *userns = m->file->f_cred->user_ns;
+
show_expflags(m, flag, NFSEXP_ALLFLAGS);
if (flag & NFSEXP_FSID)
seq_printf(m, ",fsid=%d", fsid);
- if (!uid_eq(anonu, make_kuid(&init_user_ns, (uid_t)-2)) &&
- !uid_eq(anonu, make_kuid(&init_user_ns, 0x10000-2)))
- seq_printf(m, ",anonuid=%u", from_kuid(&init_user_ns, anonu));
- if (!gid_eq(anong, make_kgid(&init_user_ns, (gid_t)-2)) &&
- !gid_eq(anong, make_kgid(&init_user_ns, 0x10000-2)))
- seq_printf(m, ",anongid=%u", from_kgid(&init_user_ns, anong));
+ if (!uid_eq(anonu, make_kuid(userns, (uid_t)-2)) &&
+ !uid_eq(anonu, make_kuid(userns, 0x10000-2)))
+ seq_printf(m, ",anonuid=%u", from_kuid_munged(userns, anonu));
+ if (!gid_eq(anong, make_kgid(userns, (gid_t)-2)) &&
+ !gid_eq(anong, make_kgid(userns, 0x10000-2)))
+ seq_printf(m, ",anongid=%u", from_kgid_munged(userns, anong));
if (fsloc && fsloc->locations_count > 0) {
char *loctype = (fsloc->migrated) ? "refer" : "replicas";
int i;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 93fea246f676..9c9d0dffbb32 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -96,7 +96,7 @@ decode_filename(__be32 *p, char **namp, unsigned int *lenp)
}
static __be32 *
-decode_sattr3(__be32 *p, struct iattr *iap)
+decode_sattr3(__be32 *p, struct iattr *iap, struct user_namespace *userns)
{
u32 tmp;
@@ -107,12 +107,12 @@ decode_sattr3(__be32 *p, struct iattr *iap)
iap->ia_mode = ntohl(*p++);
}
if (*p++) {
- iap->ia_uid = make_kuid(&init_user_ns, ntohl(*p++));
+ iap->ia_uid = make_kuid(userns, ntohl(*p++));
if (uid_valid(iap->ia_uid))
iap->ia_valid |= ATTR_UID;
}
if (*p++) {
- iap->ia_gid = make_kgid(&init_user_ns, ntohl(*p++));
+ iap->ia_gid = make_kgid(userns, ntohl(*p++));
if (gid_valid(iap->ia_gid))
iap->ia_valid |= ATTR_GID;
}
@@ -165,12 +165,13 @@ static __be32 *
encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
struct kstat *stat)
{
+ struct user_namespace *userns = nfsd_user_namespace(rqstp);
struct timespec ts;
*p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
*p++ = htonl((u32) (stat->mode & S_IALLUGO));
*p++ = htonl((u32) stat->nlink);
- *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
- *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
+ *p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
+ *p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
} else {
@@ -325,7 +326,7 @@ nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p)
p = decode_fh(p, &args->fh);
if (!p)
return 0;
- p = decode_sattr3(p, &args->attrs);
+ p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
if ((args->check_guard = ntohl(*p++)) != 0) {
struct timespec time;
@@ -455,7 +456,7 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p)
switch (args->createmode = ntohl(*p++)) {
case NFS3_CREATE_UNCHECKED:
case NFS3_CREATE_GUARDED:
- p = decode_sattr3(p, &args->attrs);
+ p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
break;
case NFS3_CREATE_EXCLUSIVE:
args->verf = p;
@@ -476,7 +477,7 @@ nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p)
if (!(p = decode_fh(p, &args->fh)) ||
!(p = decode_filename(p, &args->name, &args->len)))
return 0;
- p = decode_sattr3(p, &args->attrs);
+ p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
return xdr_argsize_check(rqstp, p);
}
@@ -491,7 +492,7 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
if (!(p = decode_fh(p, &args->ffh)) ||
!(p = decode_filename(p, &args->fname, &args->flen)))
return 0;
- p = decode_sattr3(p, &args->attrs);
+ p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
args->tlen = ntohl(*p++);
@@ -519,7 +520,7 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p)
if (args->ftype == NF3BLK || args->ftype == NF3CHR
|| args->ftype == NF3SOCK || args->ftype == NF3FIFO)
- p = decode_sattr3(p, &args->attrs);
+ p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
args->major = ntohl(*p++);
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index bf137fec33ff..2961016097ac 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -634,7 +634,7 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
return nfserr_inval;
status = do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, &id);
- *uid = make_kuid(&init_user_ns, id);
+ *uid = make_kuid(nfsd_user_namespace(rqstp), id);
if (!uid_valid(*uid))
status = nfserr_badowner;
return status;
@@ -651,7 +651,7 @@ nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
return nfserr_inval;
status = do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, &id);
- *gid = make_kgid(&init_user_ns, id);
+ *gid = make_kgid(nfsd_user_namespace(rqstp), id);
if (!gid_valid(*gid))
status = nfserr_badowner;
return status;
@@ -660,13 +660,13 @@ nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
__be32 nfsd4_encode_user(struct xdr_stream *xdr, struct svc_rqst *rqstp,
kuid_t uid)
{
- u32 id = from_kuid(&init_user_ns, uid);
+ u32 id = from_kuid_munged(nfsd_user_namespace(rqstp), uid);
return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_USER, id);
}
__be32 nfsd4_encode_group(struct xdr_stream *xdr, struct svc_rqst *rqstp,
kgid_t gid)
{
- u32 id = from_kgid(&init_user_ns, gid);
+ u32 id = from_kgid_munged(nfsd_user_namespace(rqstp), gid);
return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_GROUP, id);
}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 3de42a729093..0a8063c94c79 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -521,6 +521,7 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access
static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
{
DECODE_HEAD;
+ struct user_namespace *userns = nfsd_user_namespace(argp->rqstp);
u32 dummy, uid, gid;
char *machine_name;
int i;
@@ -563,8 +564,8 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_
dummy = be32_to_cpup(p++);
READ_BUF(dummy * 4);
if (cbs->flavor == (u32)(-1)) {
- kuid_t kuid = make_kuid(&init_user_ns, uid);
- kgid_t kgid = make_kgid(&init_user_ns, gid);
+ kuid_t kuid = make_kuid(userns, uid);
+ kgid_t kgid = make_kgid(userns, gid);
if (uid_valid(kuid) && gid_valid(kgid)) {
cbs->uid = kuid;
cbs->gid = kgid;
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index d200c8680259..24187b5dd638 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -17,6 +17,7 @@
#include <linux/nfs3.h>
#include <linux/nfs4.h>
#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/svc_xprt.h>
#include <linux/sunrpc/msg_prot.h>
#include <uapi/linux/nfsd/debug.h>
@@ -112,6 +113,12 @@ static inline int nfsd_v4client(struct svc_rqst *rq)
{
return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4;
}
+static inline struct user_namespace *
+nfsd_user_namespace(const struct svc_rqst *rqstp)
+{
+ const struct cred *cred = rqstp->rq_xprt->xpt_cred;
+ return cred ? cred->user_ns : &init_user_ns;
+}
/*
* NFSv4 State
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 6b2e8b73d36e..b51fe515f06f 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -71,7 +71,7 @@ decode_filename(__be32 *p, char **namp, unsigned int *lenp)
}
static __be32 *
-decode_sattr(__be32 *p, struct iattr *iap)
+decode_sattr(__be32 *p, struct iattr *iap, struct user_namespace *userns)
{
u32 tmp, tmp1;
@@ -86,12 +86,12 @@ decode_sattr(__be32 *p, struct iattr *iap)
iap->ia_mode = tmp;
}
if ((tmp = ntohl(*p++)) != (u32)-1) {
- iap->ia_uid = make_kuid(&init_user_ns, tmp);
+ iap->ia_uid = make_kuid(userns, tmp);
if (uid_valid(iap->ia_uid))
iap->ia_valid |= ATTR_UID;
}
if ((tmp = ntohl(*p++)) != (u32)-1) {
- iap->ia_gid = make_kgid(&init_user_ns, tmp);
+ iap->ia_gid = make_kgid(userns, tmp);
if (gid_valid(iap->ia_gid))
iap->ia_valid |= ATTR_GID;
}
@@ -129,6 +129,7 @@ static __be32 *
encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
struct kstat *stat)
{
+ struct user_namespace *userns = nfsd_user_namespace(rqstp);
struct dentry *dentry = fhp->fh_dentry;
int type;
struct timespec64 time;
@@ -139,8 +140,8 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
*p++ = htonl(nfs_ftypes[type >> 12]);
*p++ = htonl((u32) stat->mode);
*p++ = htonl((u32) stat->nlink);
- *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
- *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
+ *p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
+ *p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {
*p++ = htonl(NFS_MAXPATHLEN);
@@ -216,7 +217,7 @@ nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p)
p = decode_fh(p, &args->fh);
if (!p)
return 0;
- p = decode_sattr(p, &args->attrs);
+ p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
return xdr_argsize_check(rqstp, p);
}
@@ -319,7 +320,7 @@ nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p)
if ( !(p = decode_fh(p, &args->fh))
|| !(p = decode_filename(p, &args->name, &args->len)))
return 0;
- p = decode_sattr(p, &args->attrs);
+ p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
return xdr_argsize_check(rqstp, p);
}
@@ -398,7 +399,7 @@ nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
return 0;
p += xdrlen;
}
- decode_sattr(p, &args->attrs);
+ decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
return 1;
}
--
2.20.1
On Tue, Apr 02, 2019 at 04:44:11PM -0700, Trond Myklebust wrote:
> Convert knfsd to use the user namespace of the container that started
> the server processes.
The container that created the socket, right? The processes are still
shared.
--b.
>
> Signed-off-by: Trond Myklebust <[email protected]>
> ---
> fs/nfsd/export.c | 18 ++++++++++--------
> fs/nfsd/nfs3xdr.c | 21 +++++++++++----------
> fs/nfsd/nfs4idmap.c | 8 ++++----
> fs/nfsd/nfs4xdr.c | 5 +++--
> fs/nfsd/nfsd.h | 7 +++++++
> fs/nfsd/nfsxdr.c | 17 +++++++++--------
> 6 files changed, 44 insertions(+), 32 deletions(-)
>
> diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
> index 802993d8912f..baa01956a5b3 100644
> --- a/fs/nfsd/export.c
> +++ b/fs/nfsd/export.c
> @@ -570,13 +570,13 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
> err = get_int(&mesg, &an_int);
> if (err)
> goto out3;
> - exp.ex_anon_uid= make_kuid(&init_user_ns, an_int);
> + exp.ex_anon_uid= make_kuid(current_user_ns(), an_int);
>
> /* anon gid */
> err = get_int(&mesg, &an_int);
> if (err)
> goto out3;
> - exp.ex_anon_gid= make_kgid(&init_user_ns, an_int);
> + exp.ex_anon_gid= make_kgid(current_user_ns(), an_int);
>
> /* fsid */
> err = get_int(&mesg, &an_int);
> @@ -1170,15 +1170,17 @@ static void show_secinfo(struct seq_file *m, struct svc_export *exp)
> static void exp_flags(struct seq_file *m, int flag, int fsid,
> kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fsloc)
> {
> + struct user_namespace *userns = m->file->f_cred->user_ns;
> +
> show_expflags(m, flag, NFSEXP_ALLFLAGS);
> if (flag & NFSEXP_FSID)
> seq_printf(m, ",fsid=%d", fsid);
> - if (!uid_eq(anonu, make_kuid(&init_user_ns, (uid_t)-2)) &&
> - !uid_eq(anonu, make_kuid(&init_user_ns, 0x10000-2)))
> - seq_printf(m, ",anonuid=%u", from_kuid(&init_user_ns, anonu));
> - if (!gid_eq(anong, make_kgid(&init_user_ns, (gid_t)-2)) &&
> - !gid_eq(anong, make_kgid(&init_user_ns, 0x10000-2)))
> - seq_printf(m, ",anongid=%u", from_kgid(&init_user_ns, anong));
> + if (!uid_eq(anonu, make_kuid(userns, (uid_t)-2)) &&
> + !uid_eq(anonu, make_kuid(userns, 0x10000-2)))
> + seq_printf(m, ",anonuid=%u", from_kuid_munged(userns, anonu));
> + if (!gid_eq(anong, make_kgid(userns, (gid_t)-2)) &&
> + !gid_eq(anong, make_kgid(userns, 0x10000-2)))
> + seq_printf(m, ",anongid=%u", from_kgid_munged(userns, anong));
> if (fsloc && fsloc->locations_count > 0) {
> char *loctype = (fsloc->migrated) ? "refer" : "replicas";
> int i;
> diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
> index 93fea246f676..9c9d0dffbb32 100644
> --- a/fs/nfsd/nfs3xdr.c
> +++ b/fs/nfsd/nfs3xdr.c
> @@ -96,7 +96,7 @@ decode_filename(__be32 *p, char **namp, unsigned int *lenp)
> }
>
> static __be32 *
> -decode_sattr3(__be32 *p, struct iattr *iap)
> +decode_sattr3(__be32 *p, struct iattr *iap, struct user_namespace *userns)
> {
> u32 tmp;
>
> @@ -107,12 +107,12 @@ decode_sattr3(__be32 *p, struct iattr *iap)
> iap->ia_mode = ntohl(*p++);
> }
> if (*p++) {
> - iap->ia_uid = make_kuid(&init_user_ns, ntohl(*p++));
> + iap->ia_uid = make_kuid(userns, ntohl(*p++));
> if (uid_valid(iap->ia_uid))
> iap->ia_valid |= ATTR_UID;
> }
> if (*p++) {
> - iap->ia_gid = make_kgid(&init_user_ns, ntohl(*p++));
> + iap->ia_gid = make_kgid(userns, ntohl(*p++));
> if (gid_valid(iap->ia_gid))
> iap->ia_valid |= ATTR_GID;
> }
> @@ -165,12 +165,13 @@ static __be32 *
> encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
> struct kstat *stat)
> {
> + struct user_namespace *userns = nfsd_user_namespace(rqstp);
> struct timespec ts;
> *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
> *p++ = htonl((u32) (stat->mode & S_IALLUGO));
> *p++ = htonl((u32) stat->nlink);
> - *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
> - *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
> + *p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
> + *p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
> if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
> p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
> } else {
> @@ -325,7 +326,7 @@ nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p)
> p = decode_fh(p, &args->fh);
> if (!p)
> return 0;
> - p = decode_sattr3(p, &args->attrs);
> + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
>
> if ((args->check_guard = ntohl(*p++)) != 0) {
> struct timespec time;
> @@ -455,7 +456,7 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p)
> switch (args->createmode = ntohl(*p++)) {
> case NFS3_CREATE_UNCHECKED:
> case NFS3_CREATE_GUARDED:
> - p = decode_sattr3(p, &args->attrs);
> + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
> break;
> case NFS3_CREATE_EXCLUSIVE:
> args->verf = p;
> @@ -476,7 +477,7 @@ nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p)
> if (!(p = decode_fh(p, &args->fh)) ||
> !(p = decode_filename(p, &args->name, &args->len)))
> return 0;
> - p = decode_sattr3(p, &args->attrs);
> + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
>
> return xdr_argsize_check(rqstp, p);
> }
> @@ -491,7 +492,7 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
> if (!(p = decode_fh(p, &args->ffh)) ||
> !(p = decode_filename(p, &args->fname, &args->flen)))
> return 0;
> - p = decode_sattr3(p, &args->attrs);
> + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
>
> args->tlen = ntohl(*p++);
>
> @@ -519,7 +520,7 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p)
>
> if (args->ftype == NF3BLK || args->ftype == NF3CHR
> || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
> - p = decode_sattr3(p, &args->attrs);
> + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
>
> if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
> args->major = ntohl(*p++);
> diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
> index bf137fec33ff..2961016097ac 100644
> --- a/fs/nfsd/nfs4idmap.c
> +++ b/fs/nfsd/nfs4idmap.c
> @@ -634,7 +634,7 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
> return nfserr_inval;
>
> status = do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, &id);
> - *uid = make_kuid(&init_user_ns, id);
> + *uid = make_kuid(nfsd_user_namespace(rqstp), id);
> if (!uid_valid(*uid))
> status = nfserr_badowner;
> return status;
> @@ -651,7 +651,7 @@ nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
> return nfserr_inval;
>
> status = do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, &id);
> - *gid = make_kgid(&init_user_ns, id);
> + *gid = make_kgid(nfsd_user_namespace(rqstp), id);
> if (!gid_valid(*gid))
> status = nfserr_badowner;
> return status;
> @@ -660,13 +660,13 @@ nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
> __be32 nfsd4_encode_user(struct xdr_stream *xdr, struct svc_rqst *rqstp,
> kuid_t uid)
> {
> - u32 id = from_kuid(&init_user_ns, uid);
> + u32 id = from_kuid_munged(nfsd_user_namespace(rqstp), uid);
> return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_USER, id);
> }
>
> __be32 nfsd4_encode_group(struct xdr_stream *xdr, struct svc_rqst *rqstp,
> kgid_t gid)
> {
> - u32 id = from_kgid(&init_user_ns, gid);
> + u32 id = from_kgid_munged(nfsd_user_namespace(rqstp), gid);
> return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_GROUP, id);
> }
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 3de42a729093..0a8063c94c79 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -521,6 +521,7 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access
> static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
> {
> DECODE_HEAD;
> + struct user_namespace *userns = nfsd_user_namespace(argp->rqstp);
> u32 dummy, uid, gid;
> char *machine_name;
> int i;
> @@ -563,8 +564,8 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_
> dummy = be32_to_cpup(p++);
> READ_BUF(dummy * 4);
> if (cbs->flavor == (u32)(-1)) {
> - kuid_t kuid = make_kuid(&init_user_ns, uid);
> - kgid_t kgid = make_kgid(&init_user_ns, gid);
> + kuid_t kuid = make_kuid(userns, uid);
> + kgid_t kgid = make_kgid(userns, gid);
> if (uid_valid(kuid) && gid_valid(kgid)) {
> cbs->uid = kuid;
> cbs->gid = kgid;
> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> index d200c8680259..24187b5dd638 100644
> --- a/fs/nfsd/nfsd.h
> +++ b/fs/nfsd/nfsd.h
> @@ -17,6 +17,7 @@
> #include <linux/nfs3.h>
> #include <linux/nfs4.h>
> #include <linux/sunrpc/svc.h>
> +#include <linux/sunrpc/svc_xprt.h>
> #include <linux/sunrpc/msg_prot.h>
>
> #include <uapi/linux/nfsd/debug.h>
> @@ -112,6 +113,12 @@ static inline int nfsd_v4client(struct svc_rqst *rq)
> {
> return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4;
> }
> +static inline struct user_namespace *
> +nfsd_user_namespace(const struct svc_rqst *rqstp)
> +{
> + const struct cred *cred = rqstp->rq_xprt->xpt_cred;
> + return cred ? cred->user_ns : &init_user_ns;
> +}
>
> /*
> * NFSv4 State
> diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
> index 6b2e8b73d36e..b51fe515f06f 100644
> --- a/fs/nfsd/nfsxdr.c
> +++ b/fs/nfsd/nfsxdr.c
> @@ -71,7 +71,7 @@ decode_filename(__be32 *p, char **namp, unsigned int *lenp)
> }
>
> static __be32 *
> -decode_sattr(__be32 *p, struct iattr *iap)
> +decode_sattr(__be32 *p, struct iattr *iap, struct user_namespace *userns)
> {
> u32 tmp, tmp1;
>
> @@ -86,12 +86,12 @@ decode_sattr(__be32 *p, struct iattr *iap)
> iap->ia_mode = tmp;
> }
> if ((tmp = ntohl(*p++)) != (u32)-1) {
> - iap->ia_uid = make_kuid(&init_user_ns, tmp);
> + iap->ia_uid = make_kuid(userns, tmp);
> if (uid_valid(iap->ia_uid))
> iap->ia_valid |= ATTR_UID;
> }
> if ((tmp = ntohl(*p++)) != (u32)-1) {
> - iap->ia_gid = make_kgid(&init_user_ns, tmp);
> + iap->ia_gid = make_kgid(userns, tmp);
> if (gid_valid(iap->ia_gid))
> iap->ia_valid |= ATTR_GID;
> }
> @@ -129,6 +129,7 @@ static __be32 *
> encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
> struct kstat *stat)
> {
> + struct user_namespace *userns = nfsd_user_namespace(rqstp);
> struct dentry *dentry = fhp->fh_dentry;
> int type;
> struct timespec64 time;
> @@ -139,8 +140,8 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
> *p++ = htonl(nfs_ftypes[type >> 12]);
> *p++ = htonl((u32) stat->mode);
> *p++ = htonl((u32) stat->nlink);
> - *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
> - *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
> + *p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
> + *p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
>
> if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {
> *p++ = htonl(NFS_MAXPATHLEN);
> @@ -216,7 +217,7 @@ nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p)
> p = decode_fh(p, &args->fh);
> if (!p)
> return 0;
> - p = decode_sattr(p, &args->attrs);
> + p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
>
> return xdr_argsize_check(rqstp, p);
> }
> @@ -319,7 +320,7 @@ nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p)
> if ( !(p = decode_fh(p, &args->fh))
> || !(p = decode_filename(p, &args->name, &args->len)))
> return 0;
> - p = decode_sattr(p, &args->attrs);
> + p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
>
> return xdr_argsize_check(rqstp, p);
> }
> @@ -398,7 +399,7 @@ nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
> return 0;
> p += xdrlen;
> }
> - decode_sattr(p, &args->attrs);
> + decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
>
> return 1;
> }
> --
> 2.20.1
>
On Tue, 2019-04-02 at 21:03 -0400, J. Bruce Fields wrote:
> On Tue, Apr 02, 2019 at 04:44:11PM -0700, Trond Myklebust wrote:
> > Convert knfsd to use the user namespace of the container that
> > started
> > the server processes.
>
> The container that created the socket, right? The processes are
> still
> shared.
>
Correct.
> --b.
>
> > Signed-off-by: Trond Myklebust <[email protected]>
> > ---
> > fs/nfsd/export.c | 18 ++++++++++--------
> > fs/nfsd/nfs3xdr.c | 21 +++++++++++----------
> > fs/nfsd/nfs4idmap.c | 8 ++++----
> > fs/nfsd/nfs4xdr.c | 5 +++--
> > fs/nfsd/nfsd.h | 7 +++++++
> > fs/nfsd/nfsxdr.c | 17 +++++++++--------
> > 6 files changed, 44 insertions(+), 32 deletions(-)
> >
> > diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
> > index 802993d8912f..baa01956a5b3 100644
> > --- a/fs/nfsd/export.c
> > +++ b/fs/nfsd/export.c
> > @@ -570,13 +570,13 @@ static int svc_export_parse(struct
> > cache_detail *cd, char *mesg, int mlen)
> > err = get_int(&mesg, &an_int);
> > if (err)
> > goto out3;
> > - exp.ex_anon_uid= make_kuid(&init_user_ns, an_int);
> > + exp.ex_anon_uid= make_kuid(current_user_ns(), an_int);
> >
> > /* anon gid */
> > err = get_int(&mesg, &an_int);
> > if (err)
> > goto out3;
> > - exp.ex_anon_gid= make_kgid(&init_user_ns, an_int);
> > + exp.ex_anon_gid= make_kgid(current_user_ns(), an_int);
> >
> > /* fsid */
> > err = get_int(&mesg, &an_int);
> > @@ -1170,15 +1170,17 @@ static void show_secinfo(struct seq_file
> > *m, struct svc_export *exp)
> > static void exp_flags(struct seq_file *m, int flag, int fsid,
> > kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations
> > *fsloc)
> > {
> > + struct user_namespace *userns = m->file->f_cred->user_ns;
> > +
> > show_expflags(m, flag, NFSEXP_ALLFLAGS);
> > if (flag & NFSEXP_FSID)
> > seq_printf(m, ",fsid=%d", fsid);
> > - if (!uid_eq(anonu, make_kuid(&init_user_ns, (uid_t)-2)) &&
> > - !uid_eq(anonu, make_kuid(&init_user_ns, 0x10000-2)))
> > - seq_printf(m, ",anonuid=%u", from_kuid(&init_user_ns,
> > anonu));
> > - if (!gid_eq(anong, make_kgid(&init_user_ns, (gid_t)-2)) &&
> > - !gid_eq(anong, make_kgid(&init_user_ns, 0x10000-2)))
> > - seq_printf(m, ",anongid=%u", from_kgid(&init_user_ns,
> > anong));
> > + if (!uid_eq(anonu, make_kuid(userns, (uid_t)-2)) &&
> > + !uid_eq(anonu, make_kuid(userns, 0x10000-2)))
> > + seq_printf(m, ",anonuid=%u", from_kuid_munged(userns,
> > anonu));
> > + if (!gid_eq(anong, make_kgid(userns, (gid_t)-2)) &&
> > + !gid_eq(anong, make_kgid(userns, 0x10000-2)))
> > + seq_printf(m, ",anongid=%u", from_kgid_munged(userns,
> > anong));
> > if (fsloc && fsloc->locations_count > 0) {
> > char *loctype = (fsloc->migrated) ? "refer" :
> > "replicas";
> > int i;
> > diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
> > index 93fea246f676..9c9d0dffbb32 100644
> > --- a/fs/nfsd/nfs3xdr.c
> > +++ b/fs/nfsd/nfs3xdr.c
> > @@ -96,7 +96,7 @@ decode_filename(__be32 *p, char **namp, unsigned
> > int *lenp)
> > }
> >
> > static __be32 *
> > -decode_sattr3(__be32 *p, struct iattr *iap)
> > +decode_sattr3(__be32 *p, struct iattr *iap, struct user_namespace
> > *userns)
> > {
> > u32 tmp;
> >
> > @@ -107,12 +107,12 @@ decode_sattr3(__be32 *p, struct iattr *iap)
> > iap->ia_mode = ntohl(*p++);
> > }
> > if (*p++) {
> > - iap->ia_uid = make_kuid(&init_user_ns, ntohl(*p++));
> > + iap->ia_uid = make_kuid(userns, ntohl(*p++));
> > if (uid_valid(iap->ia_uid))
> > iap->ia_valid |= ATTR_UID;
> > }
> > if (*p++) {
> > - iap->ia_gid = make_kgid(&init_user_ns, ntohl(*p++));
> > + iap->ia_gid = make_kgid(userns, ntohl(*p++));
> > if (gid_valid(iap->ia_gid))
> > iap->ia_valid |= ATTR_GID;
> > }
> > @@ -165,12 +165,13 @@ static __be32 *
> > encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh
> > *fhp,
> > struct kstat *stat)
> > {
> > + struct user_namespace *userns = nfsd_user_namespace(rqstp);
> > struct timespec ts;
> > *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
> > *p++ = htonl((u32) (stat->mode & S_IALLUGO));
> > *p++ = htonl((u32) stat->nlink);
> > - *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
> > - *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
> > + *p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
> > + *p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
> > if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
> > p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
> > } else {
> > @@ -325,7 +326,7 @@ nfs3svc_decode_sattrargs(struct svc_rqst
> > *rqstp, __be32 *p)
> > p = decode_fh(p, &args->fh);
> > if (!p)
> > return 0;
> > - p = decode_sattr3(p, &args->attrs);
> > + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
> >
> > if ((args->check_guard = ntohl(*p++)) != 0) {
> > struct timespec time;
> > @@ -455,7 +456,7 @@ nfs3svc_decode_createargs(struct svc_rqst
> > *rqstp, __be32 *p)
> > switch (args->createmode = ntohl(*p++)) {
> > case NFS3_CREATE_UNCHECKED:
> > case NFS3_CREATE_GUARDED:
> > - p = decode_sattr3(p, &args->attrs);
> > + p = decode_sattr3(p, &args->attrs,
> > nfsd_user_namespace(rqstp));
> > break;
> > case NFS3_CREATE_EXCLUSIVE:
> > args->verf = p;
> > @@ -476,7 +477,7 @@ nfs3svc_decode_mkdirargs(struct svc_rqst
> > *rqstp, __be32 *p)
> > if (!(p = decode_fh(p, &args->fh)) ||
> > !(p = decode_filename(p, &args->name, &args->len)))
> > return 0;
> > - p = decode_sattr3(p, &args->attrs);
> > + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
> >
> > return xdr_argsize_check(rqstp, p);
> > }
> > @@ -491,7 +492,7 @@ nfs3svc_decode_symlinkargs(struct svc_rqst
> > *rqstp, __be32 *p)
> > if (!(p = decode_fh(p, &args->ffh)) ||
> > !(p = decode_filename(p, &args->fname, &args->flen)))
> > return 0;
> > - p = decode_sattr3(p, &args->attrs);
> > + p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
> >
> > args->tlen = ntohl(*p++);
> >
> > @@ -519,7 +520,7 @@ nfs3svc_decode_mknodargs(struct svc_rqst
> > *rqstp, __be32 *p)
> >
> > if (args->ftype == NF3BLK || args->ftype == NF3CHR
> > || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
> > - p = decode_sattr3(p, &args->attrs);
> > + p = decode_sattr3(p, &args->attrs,
> > nfsd_user_namespace(rqstp));
> >
> > if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
> > args->major = ntohl(*p++);
> > diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
> > index bf137fec33ff..2961016097ac 100644
> > --- a/fs/nfsd/nfs4idmap.c
> > +++ b/fs/nfsd/nfs4idmap.c
> > @@ -634,7 +634,7 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp,
> > const char *name, size_t namelen,
> > return nfserr_inval;
> >
> > status = do_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen,
> > &id);
> > - *uid = make_kuid(&init_user_ns, id);
> > + *uid = make_kuid(nfsd_user_namespace(rqstp), id);
> > if (!uid_valid(*uid))
> > status = nfserr_badowner;
> > return status;
> > @@ -651,7 +651,7 @@ nfsd_map_name_to_gid(struct svc_rqst *rqstp,
> > const char *name, size_t namelen,
> > return nfserr_inval;
> >
> > status = do_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen,
> > &id);
> > - *gid = make_kgid(&init_user_ns, id);
> > + *gid = make_kgid(nfsd_user_namespace(rqstp), id);
> > if (!gid_valid(*gid))
> > status = nfserr_badowner;
> > return status;
> > @@ -660,13 +660,13 @@ nfsd_map_name_to_gid(struct svc_rqst *rqstp,
> > const char *name, size_t namelen,
> > __be32 nfsd4_encode_user(struct xdr_stream *xdr, struct svc_rqst
> > *rqstp,
> > kuid_t uid)
> > {
> > - u32 id = from_kuid(&init_user_ns, uid);
> > + u32 id = from_kuid_munged(nfsd_user_namespace(rqstp), uid);
> > return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_USER, id);
> > }
> >
> > __be32 nfsd4_encode_group(struct xdr_stream *xdr, struct svc_rqst
> > *rqstp,
> > kgid_t gid)
> > {
> > - u32 id = from_kgid(&init_user_ns, gid);
> > + u32 id = from_kgid_munged(nfsd_user_namespace(rqstp), gid);
> > return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_GROUP, id);
> > }
> > diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> > index 3de42a729093..0a8063c94c79 100644
> > --- a/fs/nfsd/nfs4xdr.c
> > +++ b/fs/nfsd/nfs4xdr.c
> > @@ -521,6 +521,7 @@ nfsd4_decode_access(struct nfsd4_compoundargs
> > *argp, struct nfsd4_access *access
> > static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp,
> > struct nfsd4_cb_sec *cbs)
> > {
> > DECODE_HEAD;
> > + struct user_namespace *userns = nfsd_user_namespace(argp-
> > >rqstp);
> > u32 dummy, uid, gid;
> > char *machine_name;
> > int i;
> > @@ -563,8 +564,8 @@ static __be32 nfsd4_decode_cb_sec(struct
> > nfsd4_compoundargs *argp, struct nfsd4_
> > dummy = be32_to_cpup(p++);
> > READ_BUF(dummy * 4);
> > if (cbs->flavor == (u32)(-1)) {
> > - kuid_t kuid = make_kuid(&init_user_ns,
> > uid);
> > - kgid_t kgid = make_kgid(&init_user_ns,
> > gid);
> > + kuid_t kuid = make_kuid(userns, uid);
> > + kgid_t kgid = make_kgid(userns, gid);
> > if (uid_valid(kuid) && gid_valid(kgid))
> > {
> > cbs->uid = kuid;
> > cbs->gid = kgid;
> > diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> > index d200c8680259..24187b5dd638 100644
> > --- a/fs/nfsd/nfsd.h
> > +++ b/fs/nfsd/nfsd.h
> > @@ -17,6 +17,7 @@
> > #include <linux/nfs3.h>
> > #include <linux/nfs4.h>
> > #include <linux/sunrpc/svc.h>
> > +#include <linux/sunrpc/svc_xprt.h>
> > #include <linux/sunrpc/msg_prot.h>
> >
> > #include <uapi/linux/nfsd/debug.h>
> > @@ -112,6 +113,12 @@ static inline int nfsd_v4client(struct
> > svc_rqst *rq)
> > {
> > return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4;
> > }
> > +static inline struct user_namespace *
> > +nfsd_user_namespace(const struct svc_rqst *rqstp)
> > +{
> > + const struct cred *cred = rqstp->rq_xprt->xpt_cred;
> > + return cred ? cred->user_ns : &init_user_ns;
> > +}
> >
> > /*
> > * NFSv4 State
> > diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
> > index 6b2e8b73d36e..b51fe515f06f 100644
> > --- a/fs/nfsd/nfsxdr.c
> > +++ b/fs/nfsd/nfsxdr.c
> > @@ -71,7 +71,7 @@ decode_filename(__be32 *p, char **namp, unsigned
> > int *lenp)
> > }
> >
> > static __be32 *
> > -decode_sattr(__be32 *p, struct iattr *iap)
> > +decode_sattr(__be32 *p, struct iattr *iap, struct user_namespace
> > *userns)
> > {
> > u32 tmp, tmp1;
> >
> > @@ -86,12 +86,12 @@ decode_sattr(__be32 *p, struct iattr *iap)
> > iap->ia_mode = tmp;
> > }
> > if ((tmp = ntohl(*p++)) != (u32)-1) {
> > - iap->ia_uid = make_kuid(&init_user_ns, tmp);
> > + iap->ia_uid = make_kuid(userns, tmp);
> > if (uid_valid(iap->ia_uid))
> > iap->ia_valid |= ATTR_UID;
> > }
> > if ((tmp = ntohl(*p++)) != (u32)-1) {
> > - iap->ia_gid = make_kgid(&init_user_ns, tmp);
> > + iap->ia_gid = make_kgid(userns, tmp);
> > if (gid_valid(iap->ia_gid))
> > iap->ia_valid |= ATTR_GID;
> > }
> > @@ -129,6 +129,7 @@ static __be32 *
> > encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh
> > *fhp,
> > struct kstat *stat)
> > {
> > + struct user_namespace *userns = nfsd_user_namespace(rqstp);
> > struct dentry *dentry = fhp->fh_dentry;
> > int type;
> > struct timespec64 time;
> > @@ -139,8 +140,8 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p,
> > struct svc_fh *fhp,
> > *p++ = htonl(nfs_ftypes[type >> 12]);
> > *p++ = htonl((u32) stat->mode);
> > *p++ = htonl((u32) stat->nlink);
> > - *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
> > - *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
> > + *p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
> > + *p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
> >
> > if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {
> > *p++ = htonl(NFS_MAXPATHLEN);
> > @@ -216,7 +217,7 @@ nfssvc_decode_sattrargs(struct svc_rqst *rqstp,
> > __be32 *p)
> > p = decode_fh(p, &args->fh);
> > if (!p)
> > return 0;
> > - p = decode_sattr(p, &args->attrs);
> > + p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
> >
> > return xdr_argsize_check(rqstp, p);
> > }
> > @@ -319,7 +320,7 @@ nfssvc_decode_createargs(struct svc_rqst
> > *rqstp, __be32 *p)
> > if ( !(p = decode_fh(p, &args->fh))
> > || !(p = decode_filename(p, &args->name, &args->len)))
> > return 0;
> > - p = decode_sattr(p, &args->attrs);
> > + p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
> >
> > return xdr_argsize_check(rqstp, p);
> > }
> > @@ -398,7 +399,7 @@ nfssvc_decode_symlinkargs(struct svc_rqst
> > *rqstp, __be32 *p)
> > return 0;
> > p += xdrlen;
> > }
> > - decode_sattr(p, &args->attrs);
> > + decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
> >
> > return 1;
> > }
> > --
> > 2.20.1
> >
--
Trond Myklebust
Linux NFS client maintainer, Hammerspace
[email protected]