mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
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()
This commit is contained in:
commit
eb3f4b7426
|
|
@ -332,7 +332,7 @@ int nlmsvc_dispatch(struct svc_rqst *rqstp);
|
|||
* File handling for the server personality
|
||||
*/
|
||||
__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 nlmsvc_put_lockowner(struct nlm_lockowner *);
|
||||
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 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 nlm_file *file = NULL;
|
||||
int mode;
|
||||
__be32 error;
|
||||
|
||||
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;
|
||||
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) {
|
||||
case nlm_granted:
|
||||
break;
|
||||
|
|
@ -184,7 +188,8 @@ nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
|
|||
*filp = file;
|
||||
|
||||
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->fl_lmops = &nlmsvc_lock_operations;
|
||||
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)
|
||||
{
|
||||
int error;
|
||||
int mode;
|
||||
__be32 ret;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mode = lock_to_openmode(&lock->fl);
|
||||
locks_init_lock(&conflock->fl);
|
||||
/* 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.fl_start = lock->fl.fl_start;
|
||||
conflock->fl.fl_end = lock->fl.fl_end;
|
||||
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) {
|
||||
ret = nlm_lck_denied_nolocks;
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
|
|||
struct nlm_host *host = NULL;
|
||||
struct nlm_file *file = NULL;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
bool is_test = (rqstp->rq_proc == NLMPROC_TEST ||
|
||||
rqstp->rq_proc == NLMPROC_TEST_MSG);
|
||||
int mode;
|
||||
__be32 error = 0;
|
||||
|
||||
|
|
@ -83,15 +85,22 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
|
|||
|
||||
/* Obtain file pointer. Not used by FREE_ALL call. */
|
||||
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)
|
||||
goto no_locks;
|
||||
*filp = file;
|
||||
|
||||
/* 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_file = file->f_file[mode];
|
||||
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_pid = current->tgid;
|
||||
lock->fl.fl_lmops = &nlmsvc_lock_operations;
|
||||
nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid);
|
||||
|
|
|
|||
|
|
@ -83,23 +83,36 @@ int lock_to_openmode(struct file_lock *lock)
|
|||
*
|
||||
* We have to make sure we have the right credential to open
|
||||
* 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,
|
||||
struct nlm_file *file, int mode)
|
||||
{
|
||||
struct file **fp = &file->f_file[mode];
|
||||
__be32 nlmerr = nlm_granted;
|
||||
__be32 nlmerr = nlm__int__failed;
|
||||
__be32 deferred = 0;
|
||||
int error;
|
||||
int m;
|
||||
|
||||
if (*fp)
|
||||
return nlmerr;
|
||||
for (m = O_RDONLY; m <= O_WRONLY; m++) {
|
||||
struct file **fp = &file->f_file[m];
|
||||
|
||||
if (mode != O_RDWR && mode != m)
|
||||
continue;
|
||||
if (*fp)
|
||||
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);
|
||||
switch (error) {
|
||||
case -EWOULDBLOCK:
|
||||
nlmerr = nlm__int__drop_reply;
|
||||
deferred = nlmerr;
|
||||
break;
|
||||
case -ESTALE:
|
||||
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
|
||||
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;
|
||||
unsigned int hash;
|
||||
__be32 nfserr;
|
||||
int mode;
|
||||
|
||||
nlm_debug_print_fh("nlm_lookup_file", &lock->fh);
|
||||
|
||||
hash = file_hash(&lock->fh);
|
||||
mode = lock_to_openmode(&lock->fl);
|
||||
|
||||
/* Lock file table */
|
||||
mutex_lock(&nlm_file_mutex);
|
||||
|
|
|
|||
|
|
@ -1594,16 +1594,27 @@ int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
|
|||
static int nfsd_nl_fh_key_set(const struct nlattr *attr, struct nfsd_net *nn)
|
||||
{
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
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[1] = get_unaligned_le64(nla_data(attr) + 8);
|
||||
fh_key->key[0] = k0;
|
||||
fh_key->key[1] = k1;
|
||||
trace_nfsd_ctl_fh_key_set(changed, 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];
|
||||
if (attr) {
|
||||
ret = nfsd_nl_fh_key_set(attr, nn);
|
||||
trace_nfsd_ctl_fh_key_set((const char *)nn->fh_key, ret);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2243,23 +2243,21 @@ TRACE_EVENT(nfsd_end_grace,
|
|||
|
||||
TRACE_EVENT(nfsd_ctl_fh_key_set,
|
||||
TP_PROTO(
|
||||
const char *key,
|
||||
bool changed,
|
||||
int result
|
||||
),
|
||||
TP_ARGS(key, result),
|
||||
TP_ARGS(changed, result),
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, key_hash)
|
||||
__field(bool, changed)
|
||||
__field(int, result)
|
||||
),
|
||||
TP_fast_assign(
|
||||
if (key)
|
||||
__entry->key_hash = ~crc32_le(0xFFFFFFFF, key, 16);
|
||||
else
|
||||
__entry->key_hash = 0;
|
||||
__entry->changed = changed;
|
||||
__entry->result = result;
|
||||
),
|
||||
TP_printk("key=0x%08x result=%d",
|
||||
__entry->key_hash, __entry->result
|
||||
TP_printk("key %s, result=%d",
|
||||
__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;
|
||||
entry = n & ((1LL<<32) - 1);
|
||||
|
||||
if (hash >= cd->hash_size)
|
||||
return NULL;
|
||||
|
||||
hlist_for_each_entry_rcu(ch, &cd->hash_table[hash], cache_list)
|
||||
if (!entry--)
|
||||
return ch;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user