nfsd-7.1 fixes:
Issues reported with v7.1-rc: - Tighten bounds checking for sunrpc cache hash tables - Don't report key material in the ftrace log Issues that need expedient stable backports: - Fix lockd's implementation of the NLM TEST procedure -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEKLLlsBKG3yQ88j7+M2qzM29mf5cFAmoV9/kACgkQM2qzM29m f5fdpxAAtT3hl4wKNJsVLhFlFhG+9ABL74fwaQ06j5vTSIgXqPm12NuO5YbrkC78 ZzV/B/YqoHLAw/t8Pgq2taBBuSeLF+H8JqjJRDYE5H2NB/KQOT8n9KTLZtac4/1V Dvrk3mP2h12Q//BC3pF9bU9gMR1DO/+yLt9SkH+dtqcW+dWxiyVZWtK0eESIsMfh IzkHNKOS0edMZmHl5O7VZSlbyq1jPA4hTZT+NCG7JwnK6YqSkpRGDiZdZIT2FBEI C9a9hZHoP9JAJs9fR+xzTCVsIPpNW9OO3fknR2Lg7IScssVc1GIpqjU+g1O1XSVf XsMfAl+pEipDBpULu46KM1TDqAKtjaAx8Z+hDmiPxSOCKWuPn/9LMdzwVrzC7Bw8 S7ftOxUZQLHtbS8Y0eECzwK9tdfBUHN26LAJfvg4P5ZOIsFoUj0LeDryPy0r9xxb aEdEI8wro0O3p0krjtW2i+FJB8dtlKEu19LT6PN4MQtmv5a+DY4Hypt4Xovol0i+ eEugZVmLYE11b52ZFfcTcXf8n89jiWg7rgRBdBdy+vQl/32dKK3SMSIB/zCZYmBc JZNywtri6JHeJjkohWJ4xmwrmMaDj4hNr3OqWh7bOQTHleg7igpCuy+9/LHzEF6G BX4DgMJ6LqcdG8p4biGr2I2NF/+MJpXO5kNAdS44wpP983T26WE= =onHe -----END PGP SIGNATURE----- Merge tag 'nfsd-7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux Pull nfsd fixes from Chuck Lever: "Regressions: - Tighten bounds checking for sunrpc cache hash tables - Don't report key material in the ftrace log Stable fix: - Fix lockd's implementation of the NLM TEST procedure" * tag 'nfsd-7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: lockd: fix TEST handling when not all permissions are available. NFSD: Report whether fh_key was actually updated sunrpc: prevent out-of-bounds read in __cache_seq_start()master
commit
eb3f4b7426
|
|
@ -332,7 +332,7 @@ int nlmsvc_dispatch(struct svc_rqst *rqstp);
|
||||||
* File handling for the server personality
|
* File handling for the server personality
|
||||||
*/
|
*/
|
||||||
__be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
|
__be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
|
||||||
struct nlm_lock *);
|
struct nlm_lock *, int);
|
||||||
void nlm_release_file(struct nlm_file *);
|
void nlm_release_file(struct nlm_file *);
|
||||||
void nlmsvc_put_lockowner(struct nlm_lockowner *);
|
void nlmsvc_put_lockowner(struct nlm_lockowner *);
|
||||||
void nlmsvc_release_lockowner(struct nlm_lock *);
|
void nlmsvc_release_lockowner(struct nlm_lock *);
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,11 @@ nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
|
||||||
struct nlm_lock *lock, struct nlm_file **filp,
|
struct nlm_lock *lock, struct nlm_file **filp,
|
||||||
struct nlm4_lock *xdr_lock, unsigned char type)
|
struct nlm4_lock *xdr_lock, unsigned char type)
|
||||||
{
|
{
|
||||||
|
bool is_test = (rqstp->rq_proc == NLMPROC4_TEST ||
|
||||||
|
rqstp->rq_proc == NLMPROC4_TEST_MSG);
|
||||||
struct file_lock *fl = &lock->fl;
|
struct file_lock *fl = &lock->fl;
|
||||||
struct nlm_file *file = NULL;
|
struct nlm_file *file = NULL;
|
||||||
|
int mode;
|
||||||
__be32 error;
|
__be32 error;
|
||||||
|
|
||||||
if (xdr_lock->fh.len > NFS_MAXFHSIZE)
|
if (xdr_lock->fh.len > NFS_MAXFHSIZE)
|
||||||
|
|
@ -170,7 +173,8 @@ nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
|
||||||
fl->c.flc_type = type;
|
fl->c.flc_type = type;
|
||||||
lockd_set_file_lock_range4(fl, lock->lock_start, lock->lock_len);
|
lockd_set_file_lock_range4(fl, lock->lock_start, lock->lock_len);
|
||||||
|
|
||||||
error = nlm_lookup_file(rqstp, &file, lock);
|
mode = is_test ? O_RDWR : lock_to_openmode(fl);
|
||||||
|
error = nlm_lookup_file(rqstp, &file, lock, mode);
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case nlm_granted:
|
case nlm_granted:
|
||||||
break;
|
break;
|
||||||
|
|
@ -184,7 +188,8 @@ nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
|
||||||
*filp = file;
|
*filp = file;
|
||||||
|
|
||||||
fl->c.flc_flags = FL_POSIX;
|
fl->c.flc_flags = FL_POSIX;
|
||||||
fl->c.flc_file = file->f_file[lock_to_openmode(fl)];
|
fl->c.flc_file = is_test ? nlmsvc_file_file(file)
|
||||||
|
: file->f_file[mode];
|
||||||
fl->c.flc_pid = current->tgid;
|
fl->c.flc_pid = current->tgid;
|
||||||
fl->fl_lmops = &nlmsvc_lock_operations;
|
fl->fl_lmops = &nlmsvc_lock_operations;
|
||||||
nlmsvc_locks_init_private(fl, host, (pid_t)lock->svid);
|
nlmsvc_locks_init_private(fl, host, (pid_t)lock->svid);
|
||||||
|
|
|
||||||
|
|
@ -613,7 +613,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||||
struct nlm_lock *conflock)
|
struct nlm_lock *conflock)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
int mode;
|
|
||||||
__be32 ret;
|
__be32 ret;
|
||||||
|
|
||||||
dprintk("lockd: nlmsvc_testlock(%s/%llu, ty=%d, %Ld-%Ld)\n",
|
dprintk("lockd: nlmsvc_testlock(%s/%llu, ty=%d, %Ld-%Ld)\n",
|
||||||
|
|
@ -631,14 +630,13 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
mode = lock_to_openmode(&lock->fl);
|
|
||||||
locks_init_lock(&conflock->fl);
|
locks_init_lock(&conflock->fl);
|
||||||
/* vfs_test_lock only uses start, end, and owner, but tests flc_file */
|
/* vfs_test_lock only uses start, end, and owner, but tests flc_file */
|
||||||
conflock->fl.c.flc_file = lock->fl.c.flc_file;
|
conflock->fl.c.flc_file = lock->fl.c.flc_file;
|
||||||
conflock->fl.fl_start = lock->fl.fl_start;
|
conflock->fl.fl_start = lock->fl.fl_start;
|
||||||
conflock->fl.fl_end = lock->fl.fl_end;
|
conflock->fl.fl_end = lock->fl.fl_end;
|
||||||
conflock->fl.c.flc_owner = lock->fl.c.flc_owner;
|
conflock->fl.c.flc_owner = lock->fl.c.flc_owner;
|
||||||
error = vfs_test_lock(file->f_file[mode], &conflock->fl);
|
error = vfs_test_lock(lock->fl.c.flc_file, &conflock->fl);
|
||||||
if (error) {
|
if (error) {
|
||||||
ret = nlm_lck_denied_nolocks;
|
ret = nlm_lck_denied_nolocks;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
struct nlm_host *host = NULL;
|
struct nlm_host *host = NULL;
|
||||||
struct nlm_file *file = NULL;
|
struct nlm_file *file = NULL;
|
||||||
struct nlm_lock *lock = &argp->lock;
|
struct nlm_lock *lock = &argp->lock;
|
||||||
|
bool is_test = (rqstp->rq_proc == NLMPROC_TEST ||
|
||||||
|
rqstp->rq_proc == NLMPROC_TEST_MSG);
|
||||||
int mode;
|
int mode;
|
||||||
__be32 error = 0;
|
__be32 error = 0;
|
||||||
|
|
||||||
|
|
@ -83,14 +85,21 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
|
||||||
|
|
||||||
/* Obtain file pointer. Not used by FREE_ALL call. */
|
/* Obtain file pointer. Not used by FREE_ALL call. */
|
||||||
if (filp != NULL) {
|
if (filp != NULL) {
|
||||||
error = cast_status(nlm_lookup_file(rqstp, &file, lock));
|
mode = lock_to_openmode(&lock->fl);
|
||||||
|
|
||||||
|
if (is_test)
|
||||||
|
mode = O_RDWR;
|
||||||
|
|
||||||
|
error = cast_status(nlm_lookup_file(rqstp, &file, lock, mode));
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
goto no_locks;
|
goto no_locks;
|
||||||
*filp = file;
|
*filp = file;
|
||||||
|
|
||||||
/* Set up the missing parts of the file_lock structure */
|
/* Set up the missing parts of the file_lock structure */
|
||||||
mode = lock_to_openmode(&lock->fl);
|
|
||||||
lock->fl.c.flc_flags = FL_POSIX;
|
lock->fl.c.flc_flags = FL_POSIX;
|
||||||
|
if (is_test)
|
||||||
|
lock->fl.c.flc_file = nlmsvc_file_file(file);
|
||||||
|
else
|
||||||
lock->fl.c.flc_file = file->f_file[mode];
|
lock->fl.c.flc_file = file->f_file[mode];
|
||||||
lock->fl.c.flc_pid = current->tgid;
|
lock->fl.c.flc_pid = current->tgid;
|
||||||
lock->fl.fl_lmops = &nlmsvc_lock_operations;
|
lock->fl.fl_lmops = &nlmsvc_lock_operations;
|
||||||
|
|
|
||||||
|
|
@ -83,23 +83,36 @@ int lock_to_openmode(struct file_lock *lock)
|
||||||
*
|
*
|
||||||
* We have to make sure we have the right credential to open
|
* We have to make sure we have the right credential to open
|
||||||
* the file.
|
* the file.
|
||||||
|
*
|
||||||
|
* @mode is O_RDONLY, O_WRONLY, or O_RDWR. O_RDWR means success
|
||||||
|
* is achieved with EITHER O_RDONLY or O_WRONLY; it does not
|
||||||
|
* require both.
|
||||||
*/
|
*/
|
||||||
static __be32 nlm_do_fopen(struct svc_rqst *rqstp,
|
static __be32 nlm_do_fopen(struct svc_rqst *rqstp,
|
||||||
struct nlm_file *file, int mode)
|
struct nlm_file *file, int mode)
|
||||||
{
|
{
|
||||||
struct file **fp = &file->f_file[mode];
|
__be32 nlmerr = nlm__int__failed;
|
||||||
__be32 nlmerr = nlm_granted;
|
__be32 deferred = 0;
|
||||||
int error;
|
int error;
|
||||||
|
int m;
|
||||||
|
|
||||||
|
for (m = O_RDONLY; m <= O_WRONLY; m++) {
|
||||||
|
struct file **fp = &file->f_file[m];
|
||||||
|
|
||||||
|
if (mode != O_RDWR && mode != m)
|
||||||
|
continue;
|
||||||
if (*fp)
|
if (*fp)
|
||||||
return nlmerr;
|
return nlm_granted;
|
||||||
|
|
||||||
|
error = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, m);
|
||||||
|
if (!error)
|
||||||
|
return nlm_granted;
|
||||||
|
|
||||||
error = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode);
|
|
||||||
if (error) {
|
|
||||||
dprintk("lockd: open failed (errno %d)\n", error);
|
dprintk("lockd: open failed (errno %d)\n", error);
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case -EWOULDBLOCK:
|
case -EWOULDBLOCK:
|
||||||
nlmerr = nlm__int__drop_reply;
|
nlmerr = nlm__int__drop_reply;
|
||||||
|
deferred = nlmerr;
|
||||||
break;
|
break;
|
||||||
case -ESTALE:
|
case -ESTALE:
|
||||||
nlmerr = nlm__int__stale_fh;
|
nlmerr = nlm__int__stale_fh;
|
||||||
|
|
@ -110,7 +123,7 @@ static __be32 nlm_do_fopen(struct svc_rqst *rqstp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nlmerr;
|
return deferred ? deferred : nlmerr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -119,17 +132,15 @@ static __be32 nlm_do_fopen(struct svc_rqst *rqstp,
|
||||||
*/
|
*/
|
||||||
__be32
|
__be32
|
||||||
nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
|
nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
|
||||||
struct nlm_lock *lock)
|
struct nlm_lock *lock, int mode)
|
||||||
{
|
{
|
||||||
struct nlm_file *file;
|
struct nlm_file *file;
|
||||||
unsigned int hash;
|
unsigned int hash;
|
||||||
__be32 nfserr;
|
__be32 nfserr;
|
||||||
int mode;
|
|
||||||
|
|
||||||
nlm_debug_print_fh("nlm_lookup_file", &lock->fh);
|
nlm_debug_print_fh("nlm_lookup_file", &lock->fh);
|
||||||
|
|
||||||
hash = file_hash(&lock->fh);
|
hash = file_hash(&lock->fh);
|
||||||
mode = lock_to_openmode(&lock->fl);
|
|
||||||
|
|
||||||
/* Lock file table */
|
/* Lock file table */
|
||||||
mutex_lock(&nlm_file_mutex);
|
mutex_lock(&nlm_file_mutex);
|
||||||
|
|
|
||||||
|
|
@ -1594,16 +1594,27 @@ out_unlock:
|
||||||
static int nfsd_nl_fh_key_set(const struct nlattr *attr, struct nfsd_net *nn)
|
static int nfsd_nl_fh_key_set(const struct nlattr *attr, struct nfsd_net *nn)
|
||||||
{
|
{
|
||||||
siphash_key_t *fh_key = nn->fh_key;
|
siphash_key_t *fh_key = nn->fh_key;
|
||||||
|
u64 k0, k1;
|
||||||
|
bool changed;
|
||||||
|
|
||||||
|
k0 = get_unaligned_le64(nla_data(attr));
|
||||||
|
k1 = get_unaligned_le64(nla_data(attr) + 8);
|
||||||
|
|
||||||
if (!fh_key) {
|
if (!fh_key) {
|
||||||
fh_key = kmalloc(sizeof(siphash_key_t), GFP_KERNEL);
|
fh_key = kmalloc(sizeof(siphash_key_t), GFP_KERNEL);
|
||||||
if (!fh_key)
|
if (!fh_key) {
|
||||||
|
trace_nfsd_ctl_fh_key_set(false, -ENOMEM);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
nn->fh_key = fh_key;
|
nn->fh_key = fh_key;
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
changed = fh_key->key[0] != k0 || fh_key->key[1] != k1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fh_key->key[0] = get_unaligned_le64(nla_data(attr));
|
fh_key->key[0] = k0;
|
||||||
fh_key->key[1] = get_unaligned_le64(nla_data(attr) + 8);
|
fh_key->key[1] = k1;
|
||||||
|
trace_nfsd_ctl_fh_key_set(changed, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1682,7 +1693,6 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||||
attr = info->attrs[NFSD_A_SERVER_FH_KEY];
|
attr = info->attrs[NFSD_A_SERVER_FH_KEY];
|
||||||
if (attr) {
|
if (attr) {
|
||||||
ret = nfsd_nl_fh_key_set(attr, nn);
|
ret = nfsd_nl_fh_key_set(attr, nn);
|
||||||
trace_nfsd_ctl_fh_key_set((const char *)nn->fh_key, ret);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2243,23 +2243,21 @@ TRACE_EVENT(nfsd_end_grace,
|
||||||
|
|
||||||
TRACE_EVENT(nfsd_ctl_fh_key_set,
|
TRACE_EVENT(nfsd_ctl_fh_key_set,
|
||||||
TP_PROTO(
|
TP_PROTO(
|
||||||
const char *key,
|
bool changed,
|
||||||
int result
|
int result
|
||||||
),
|
),
|
||||||
TP_ARGS(key, result),
|
TP_ARGS(changed, result),
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
__field(u32, key_hash)
|
__field(bool, changed)
|
||||||
__field(int, result)
|
__field(int, result)
|
||||||
),
|
),
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
if (key)
|
__entry->changed = changed;
|
||||||
__entry->key_hash = ~crc32_le(0xFFFFFFFF, key, 16);
|
|
||||||
else
|
|
||||||
__entry->key_hash = 0;
|
|
||||||
__entry->result = result;
|
__entry->result = result;
|
||||||
),
|
),
|
||||||
TP_printk("key=0x%08x result=%d",
|
TP_printk("key %s, result=%d",
|
||||||
__entry->key_hash, __entry->result
|
__entry->changed ? "updated" : "unmodified",
|
||||||
|
__entry->result
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1348,6 +1348,9 @@ static void *__cache_seq_start(struct seq_file *m, loff_t *pos)
|
||||||
hash = n >> 32;
|
hash = n >> 32;
|
||||||
entry = n & ((1LL<<32) - 1);
|
entry = n & ((1LL<<32) - 1);
|
||||||
|
|
||||||
|
if (hash >= cd->hash_size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
hlist_for_each_entry_rcu(ch, &cd->hash_table[hash], cache_list)
|
hlist_for_each_entry_rcu(ch, &cd->hash_table[hash], cache_list)
|
||||||
if (!entry--)
|
if (!entry--)
|
||||||
return ch;
|
return ch;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue