Merge tag 'nfs-for-3.17-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust: "Highlights include: - stable fix for a bug in nfs3_list_one_acl() - speed up NFS path walks by supporting LOOKUP_RCU - more read/write code cleanups - pNFS fixes for layout return on close - fixes for the RCU handling in the rpcsec_gss code - more NFS/RDMA fixes" * tag 'nfs-for-3.17-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (79 commits) nfs: reject changes to resvport and sharecache during remount NFS: Avoid infinite loop when RELEASE_LOCKOWNER getting expired error SUNRPC: remove all refcounting of groupinfo from rpcauth_lookupcred NFS: fix two problems in lookup_revalidate in RCU-walk NFS: allow lockless access to access_cache NFS: teach nfs_lookup_verify_inode to handle LOOKUP_RCU NFS: teach nfs_neg_need_reval to understand LOOKUP_RCU NFS: support RCU_WALK in nfs_permission() sunrpc/auth: allow lockless (rcu) lookup of credential cache. NFS: prepare for RCU-walk support but pushing tests later in code. NFS: nfs4_lookup_revalidate: only evaluate parent if it will be used. NFS: add checks for returned value of try_module_get() nfs: clear_request_commit while holding i_lock pnfs: add pnfs_put_lseg_async pnfs: find swapped pages on pnfs commit lists too nfs: fix comment and add warn_on for PG_INODE_REF nfs: check wait_on_bit_lock err in page_group_lock sunrpc: remove "ec" argument from encrypt_v2 operation sunrpc: clean up sparse endianness warnings in gss_krb5_wrap.c sunrpc: clean up sparse endianness warnings in gss_krb5_seal.c ...
This commit is contained in:
@@ -183,8 +183,9 @@ gss_cred_get_ctx(struct rpc_cred *cred)
|
||||
struct gss_cl_ctx *ctx = NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
if (gss_cred->gc_ctx)
|
||||
ctx = gss_get_ctx(gss_cred->gc_ctx);
|
||||
ctx = rcu_dereference(gss_cred->gc_ctx);
|
||||
if (ctx)
|
||||
gss_get_ctx(ctx);
|
||||
rcu_read_unlock();
|
||||
return ctx;
|
||||
}
|
||||
@@ -262,9 +263,22 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
|
||||
p = ERR_PTR(ret);
|
||||
goto err;
|
||||
}
|
||||
dprintk("RPC: %s Success. gc_expiry %lu now %lu timeout %u\n",
|
||||
__func__, ctx->gc_expiry, now, timeout);
|
||||
return q;
|
||||
|
||||
/* is there any trailing data? */
|
||||
if (q == end) {
|
||||
p = q;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* pull in acceptor name (if there is one) */
|
||||
p = simple_get_netobj(q, end, &ctx->gc_acceptor);
|
||||
if (IS_ERR(p))
|
||||
goto err;
|
||||
done:
|
||||
dprintk("RPC: %s Success. gc_expiry %lu now %lu timeout %u acceptor %.*s\n",
|
||||
__func__, ctx->gc_expiry, now, timeout, ctx->gc_acceptor.len,
|
||||
ctx->gc_acceptor.data);
|
||||
return p;
|
||||
err:
|
||||
dprintk("RPC: %s returns error %ld\n", __func__, -PTR_ERR(p));
|
||||
return p;
|
||||
@@ -1194,13 +1208,13 @@ gss_destroying_context(struct rpc_cred *cred)
|
||||
{
|
||||
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
|
||||
struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth);
|
||||
struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1);
|
||||
struct rpc_task *task;
|
||||
|
||||
if (gss_cred->gc_ctx == NULL ||
|
||||
test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
|
||||
if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
|
||||
return 0;
|
||||
|
||||
gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY;
|
||||
ctx->gc_proc = RPC_GSS_PROC_DESTROY;
|
||||
cred->cr_ops = &gss_nullops;
|
||||
|
||||
/* Take a reference to ensure the cred will be destroyed either
|
||||
@@ -1225,6 +1239,7 @@ gss_do_free_ctx(struct gss_cl_ctx *ctx)
|
||||
|
||||
gss_delete_sec_context(&ctx->gc_gss_ctx);
|
||||
kfree(ctx->gc_wire_ctx.data);
|
||||
kfree(ctx->gc_acceptor.data);
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
@@ -1260,7 +1275,7 @@ gss_destroy_nullcred(struct rpc_cred *cred)
|
||||
{
|
||||
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
|
||||
struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth);
|
||||
struct gss_cl_ctx *ctx = gss_cred->gc_ctx;
|
||||
struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1);
|
||||
|
||||
RCU_INIT_POINTER(gss_cred->gc_ctx, NULL);
|
||||
call_rcu(&cred->cr_rcu, gss_free_cred_callback);
|
||||
@@ -1332,6 +1347,36 @@ gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred)
|
||||
return err;
|
||||
}
|
||||
|
||||
static char *
|
||||
gss_stringify_acceptor(struct rpc_cred *cred)
|
||||
{
|
||||
char *string = NULL;
|
||||
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
|
||||
struct gss_cl_ctx *ctx;
|
||||
struct xdr_netobj *acceptor;
|
||||
|
||||
rcu_read_lock();
|
||||
ctx = rcu_dereference(gss_cred->gc_ctx);
|
||||
if (!ctx)
|
||||
goto out;
|
||||
|
||||
acceptor = &ctx->gc_acceptor;
|
||||
|
||||
/* no point if there's no string */
|
||||
if (!acceptor->len)
|
||||
goto out;
|
||||
|
||||
string = kmalloc(acceptor->len + 1, GFP_KERNEL);
|
||||
if (!string)
|
||||
goto out;
|
||||
|
||||
memcpy(string, acceptor->data, acceptor->len);
|
||||
string[acceptor->len] = '\0';
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
return string;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns -EACCES if GSS context is NULL or will expire within the
|
||||
* timeout (miliseconds)
|
||||
@@ -1340,15 +1385,16 @@ static int
|
||||
gss_key_timeout(struct rpc_cred *rc)
|
||||
{
|
||||
struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
|
||||
struct gss_cl_ctx *ctx;
|
||||
unsigned long now = jiffies;
|
||||
unsigned long expire;
|
||||
|
||||
if (gss_cred->gc_ctx == NULL)
|
||||
return -EACCES;
|
||||
|
||||
expire = gss_cred->gc_ctx->gc_expiry - (gss_key_expire_timeo * HZ);
|
||||
|
||||
if (time_after(now, expire))
|
||||
rcu_read_lock();
|
||||
ctx = rcu_dereference(gss_cred->gc_ctx);
|
||||
if (ctx)
|
||||
expire = ctx->gc_expiry - (gss_key_expire_timeo * HZ);
|
||||
rcu_read_unlock();
|
||||
if (!ctx || time_after(now, expire))
|
||||
return -EACCES;
|
||||
return 0;
|
||||
}
|
||||
@@ -1357,13 +1403,19 @@ static int
|
||||
gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
|
||||
{
|
||||
struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
|
||||
struct gss_cl_ctx *ctx;
|
||||
int ret;
|
||||
|
||||
if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
|
||||
goto out;
|
||||
/* Don't match with creds that have expired. */
|
||||
if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
|
||||
rcu_read_lock();
|
||||
ctx = rcu_dereference(gss_cred->gc_ctx);
|
||||
if (!ctx || time_after(jiffies, ctx->gc_expiry)) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags))
|
||||
return 0;
|
||||
out:
|
||||
@@ -1909,29 +1961,31 @@ static const struct rpc_authops authgss_ops = {
|
||||
};
|
||||
|
||||
static const struct rpc_credops gss_credops = {
|
||||
.cr_name = "AUTH_GSS",
|
||||
.crdestroy = gss_destroy_cred,
|
||||
.cr_init = gss_cred_init,
|
||||
.crbind = rpcauth_generic_bind_cred,
|
||||
.crmatch = gss_match,
|
||||
.crmarshal = gss_marshal,
|
||||
.crrefresh = gss_refresh,
|
||||
.crvalidate = gss_validate,
|
||||
.crwrap_req = gss_wrap_req,
|
||||
.crunwrap_resp = gss_unwrap_resp,
|
||||
.crkey_timeout = gss_key_timeout,
|
||||
.cr_name = "AUTH_GSS",
|
||||
.crdestroy = gss_destroy_cred,
|
||||
.cr_init = gss_cred_init,
|
||||
.crbind = rpcauth_generic_bind_cred,
|
||||
.crmatch = gss_match,
|
||||
.crmarshal = gss_marshal,
|
||||
.crrefresh = gss_refresh,
|
||||
.crvalidate = gss_validate,
|
||||
.crwrap_req = gss_wrap_req,
|
||||
.crunwrap_resp = gss_unwrap_resp,
|
||||
.crkey_timeout = gss_key_timeout,
|
||||
.crstringify_acceptor = gss_stringify_acceptor,
|
||||
};
|
||||
|
||||
static const struct rpc_credops gss_nullops = {
|
||||
.cr_name = "AUTH_GSS",
|
||||
.crdestroy = gss_destroy_nullcred,
|
||||
.crbind = rpcauth_generic_bind_cred,
|
||||
.crmatch = gss_match,
|
||||
.crmarshal = gss_marshal,
|
||||
.crrefresh = gss_refresh_null,
|
||||
.crvalidate = gss_validate,
|
||||
.crwrap_req = gss_wrap_req,
|
||||
.crunwrap_resp = gss_unwrap_resp,
|
||||
.cr_name = "AUTH_GSS",
|
||||
.crdestroy = gss_destroy_nullcred,
|
||||
.crbind = rpcauth_generic_bind_cred,
|
||||
.crmatch = gss_match,
|
||||
.crmarshal = gss_marshal,
|
||||
.crrefresh = gss_refresh_null,
|
||||
.crvalidate = gss_validate,
|
||||
.crwrap_req = gss_wrap_req,
|
||||
.crunwrap_resp = gss_unwrap_resp,
|
||||
.crstringify_acceptor = gss_stringify_acceptor,
|
||||
};
|
||||
|
||||
static const struct rpc_pipe_ops gss_upcall_ops_v0 = {
|
||||
|
@@ -641,7 +641,7 @@ out:
|
||||
|
||||
u32
|
||||
gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
|
||||
struct xdr_buf *buf, int ec, struct page **pages)
|
||||
struct xdr_buf *buf, struct page **pages)
|
||||
{
|
||||
u32 err;
|
||||
struct xdr_netobj hmac;
|
||||
@@ -684,13 +684,8 @@ gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
|
||||
ecptr = buf->tail[0].iov_base;
|
||||
}
|
||||
|
||||
memset(ecptr, 'X', ec);
|
||||
buf->tail[0].iov_len += ec;
|
||||
buf->len += ec;
|
||||
|
||||
/* copy plaintext gss token header after filler (if any) */
|
||||
memcpy(ecptr + ec, buf->head[0].iov_base + offset,
|
||||
GSS_KRB5_TOK_HDR_LEN);
|
||||
memcpy(ecptr, buf->head[0].iov_base + offset, GSS_KRB5_TOK_HDR_LEN);
|
||||
buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN;
|
||||
buf->len += GSS_KRB5_TOK_HDR_LEN;
|
||||
|
||||
|
@@ -70,31 +70,37 @@
|
||||
|
||||
DEFINE_SPINLOCK(krb5_seq_lock);
|
||||
|
||||
static char *
|
||||
static void *
|
||||
setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token)
|
||||
{
|
||||
__be16 *ptr, *krb5_hdr;
|
||||
u16 *ptr;
|
||||
void *krb5_hdr;
|
||||
int body_size = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength;
|
||||
|
||||
token->len = g_token_size(&ctx->mech_used, body_size);
|
||||
|
||||
ptr = (__be16 *)token->data;
|
||||
ptr = (u16 *)token->data;
|
||||
g_make_token_header(&ctx->mech_used, body_size, (unsigned char **)&ptr);
|
||||
|
||||
/* ptr now at start of header described in rfc 1964, section 1.2.1: */
|
||||
krb5_hdr = ptr;
|
||||
*ptr++ = KG_TOK_MIC_MSG;
|
||||
*ptr++ = cpu_to_le16(ctx->gk5e->signalg);
|
||||
/*
|
||||
* signalg is stored as if it were converted from LE to host endian, even
|
||||
* though it's an opaque pair of bytes according to the RFC.
|
||||
*/
|
||||
*ptr++ = (__force u16)cpu_to_le16(ctx->gk5e->signalg);
|
||||
*ptr++ = SEAL_ALG_NONE;
|
||||
*ptr++ = 0xffff;
|
||||
*ptr = 0xffff;
|
||||
|
||||
return (char *)krb5_hdr;
|
||||
return krb5_hdr;
|
||||
}
|
||||
|
||||
static void *
|
||||
setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token)
|
||||
{
|
||||
__be16 *ptr, *krb5_hdr;
|
||||
u16 *ptr;
|
||||
void *krb5_hdr;
|
||||
u8 *p, flags = 0x00;
|
||||
|
||||
if ((ctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0)
|
||||
@@ -104,15 +110,15 @@ setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token)
|
||||
|
||||
/* Per rfc 4121, sec 4.2.6.1, there is no header,
|
||||
* just start the token */
|
||||
krb5_hdr = ptr = (__be16 *)token->data;
|
||||
krb5_hdr = ptr = (u16 *)token->data;
|
||||
|
||||
*ptr++ = KG2_TOK_MIC;
|
||||
p = (u8 *)ptr;
|
||||
*p++ = flags;
|
||||
*p++ = 0xff;
|
||||
ptr = (__be16 *)p;
|
||||
*ptr++ = 0xffff;
|
||||
ptr = (u16 *)p;
|
||||
*ptr++ = 0xffff;
|
||||
*ptr = 0xffff;
|
||||
|
||||
token->len = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength;
|
||||
return krb5_hdr;
|
||||
@@ -181,7 +187,7 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
|
||||
spin_lock(&krb5_seq_lock);
|
||||
seq_send = ctx->seq_send64++;
|
||||
spin_unlock(&krb5_seq_lock);
|
||||
*((u64 *)(krb5_hdr + 8)) = cpu_to_be64(seq_send);
|
||||
*((__be64 *)(krb5_hdr + 8)) = cpu_to_be64(seq_send);
|
||||
|
||||
if (ctx->initiate) {
|
||||
cksumkey = ctx->initiator_sign;
|
||||
|
@@ -201,9 +201,15 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset,
|
||||
|
||||
msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength;
|
||||
|
||||
*(__be16 *)(ptr + 2) = cpu_to_le16(kctx->gk5e->signalg);
|
||||
memset(ptr + 4, 0xff, 4);
|
||||
*(__be16 *)(ptr + 4) = cpu_to_le16(kctx->gk5e->sealalg);
|
||||
/*
|
||||
* signalg and sealalg are stored as if they were converted from LE
|
||||
* to host endian, even though they're opaque pairs of bytes according
|
||||
* to the RFC.
|
||||
*/
|
||||
*(__le16 *)(ptr + 2) = cpu_to_le16(kctx->gk5e->signalg);
|
||||
*(__le16 *)(ptr + 4) = cpu_to_le16(kctx->gk5e->sealalg);
|
||||
ptr[6] = 0xff;
|
||||
ptr[7] = 0xff;
|
||||
|
||||
gss_krb5_make_confounder(msg_start, conflen);
|
||||
|
||||
@@ -438,7 +444,7 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
|
||||
u8 *ptr, *plainhdr;
|
||||
s32 now;
|
||||
u8 flags = 0x00;
|
||||
__be16 *be16ptr, ec = 0;
|
||||
__be16 *be16ptr;
|
||||
__be64 *be64ptr;
|
||||
u32 err;
|
||||
|
||||
@@ -468,16 +474,16 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset,
|
||||
be16ptr = (__be16 *)ptr;
|
||||
|
||||
blocksize = crypto_blkcipher_blocksize(kctx->acceptor_enc);
|
||||
*be16ptr++ = cpu_to_be16(ec);
|
||||
*be16ptr++ = 0;
|
||||
/* "inner" token header always uses 0 for RRC */
|
||||
*be16ptr++ = cpu_to_be16(0);
|
||||
*be16ptr++ = 0;
|
||||
|
||||
be64ptr = (__be64 *)be16ptr;
|
||||
spin_lock(&krb5_seq_lock);
|
||||
*be64ptr = cpu_to_be64(kctx->seq_send64++);
|
||||
spin_unlock(&krb5_seq_lock);
|
||||
|
||||
err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, ec, pages);
|
||||
err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, pages);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
Reference in New Issue
Block a user