Linux 7.0.2
Greg Kroah-Hartman
maintainerI'm announcing the release of the 7.0.2 kernel.
All users of the 7.0 kernel series must upgrade.
The updated 7.0.y git tree can be found at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-7.0.y
and can be browsed at the normal kernel.org git web browser:
https://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=summary
thanks,
greg k-h
------------
Makefile | 2 crypto/authencesn.c | 6 + crypto/krb5enc.c | 51 +++++++----- drivers/crypto/ccp/sev-dev.c | 19 ++++ drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 39 ++++----- drivers/hv/mshv_vtl_main.c | 12 ++- drivers/pwm/pwm_th1520.rs | 5 - fs/f2fs/compress.c | 14 ++- fs/f2fs/data.c | 7 + fs/f2fs/f2fs.h | 2 fs/f2fs/namei.c | 1 fs/f2fs/segment.c | 6 - fs/f2fs/super.c | 11 ++ fs/fs-writeback.c | 36 ++++----- fs/fuse/control.c | 4 - fs/fuse/dev.c | 30 ++++--- fs/fuse/fuse_i.h | 1 fs/fuse/inode.c | 1 fs/fuse/readdir.c | 4 + fs/ntfs3/fslog.c | 12 ++- fs/smb/client/cifsacl.c | 117 +++++++++++++++++++++-------- fs/smb/client/connect.c | 10 +- fs/smb/client/smb1ops.c | 19 ++-- fs/smb/client/smb2ops.c | 6 + fs/smb/server/connection.c | 5 - fs/smb/server/mgmt/user_config.c | 6 - fs/smb/server/mgmt/user_session.c | 8 -- fs/smb/server/oplock.c | 7 + fs/smb/server/oplock.h | 1 fs/smb/server/smb2pdu.c | 5 + fs/smb/server/smbacl.c | 61 ++++++++++++--- fs/smb/server/transport_ipc.c | 16 +++- fs/smb/server/transport_tcp.c | 4 - fs/smb/server/vfs_cache.c | 128 +++++++++++++++++++++++++++----- fs/smb/server/vfs_cache.h | 12 ++- include/uapi/linux/mshv.h | 2 net/packet/af_packet.c | 21 +++-- net/rxrpc/key.c | 4 + scripts/dtc/dtc-lexer.l | 3 scripts/generate_rust_analyzer.py | 14 +++ sound/hda/codecs/realtek/alc269.c | 1 sound/usb/caiaq/device.c | 4 - sound/usb/mixer.c | 7 + 43 files changed, 512 insertions(+), 212 deletions(-)
Anderson Nascimento (1):
rxrpc: Fix missing validation of ticket length in non-XDR key preparsing
Berk Cem Goksel (1):
ALSA: caiaq: take a reference on the USB device in create_card()
Bernd Schubert (1):
fuse: Check for large folio with SPLICE_F_MOVE
Bingquan Chen (1):
net/packet: fix TOCTOU race on mmap'd vnet_hdr in tpacket_snd()
Chao Yu (3):
f2fs: fix to do sanity check on dcc->discard_cmd_cnt conditionally
f2fs: fix to avoid memory leak in f2fs_rename()
f2fs: fix to avoid uninit-value access in f2fs_sanity_check_node_footer
Cryolitia PukNgae (1):
ALSA: usb-audio: apply quirk for MOONDROP JU Jiu
DaeMyung Kang (2):
smb: server: fix max_connections off-by-one in tcp accept path
ksmbd: reset rcount per connection in ksmbd_conn_wait_idle_sess_id()
Darrick J. Wong (1):
fuse: quiet down complaints in fuse_conn_limit_write
Dudu Lu (1):
crypto: krb5enc - fix async decrypt skipping hash verification
Eric Naim (1):
ALSA: hda/realtek: Add quirk for Legion S7 15IMH
George Saad (1):
f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
Greg Kroah-Hartman (2):
fs/ntfs3: validate rec->used in journal-replay file record check
Linux 7.0.2Herbert Xu (1):
crypto: authencesn - Fix src offset when decrypting in-place
Jan Kara (1):
writeback: Fix use after free in inode_switch_wbs_work_fn()
Michael Bommarito (7):
ksmbd: require minimum ACE size in smb_check_perm_dacl()
smb: server: fix active_num_conn leak on transport allocation failure
smb: client: require a full NFS mode SID before reading mode bits
smb: client: validate the whole DACL before rewriting it in cifsacl
smb: client: fix OOB read in smb2_ioctl_query_info QUERY_INFO path
ksmbd: validate response sizes in ipc_validate_msg()
ksmbd: validate num_aces and harden ACE walk in smb_inherit_dacl()
Miguel Ojeda (1):
pwm: th1520: fix `CLIPPY=1` warning
Mikhail Gavrilov (1):
drm/amdgpu: replace PASID IDR with XArray
Miklos Szeredi (2):
fuse: abort on fatal signal during sync init
fuse: fuse_dev_ioctl_clone() should wait for device file to be initialized
Naman Jain (1):
mshv_vtl: Fix vmemmap_shift exceeding MAX_FOLIO_ORDER
Namjae Jeon (2):
ksmbd: fix use-after-free in __ksmbd_close_fd() via durable scavenger
ksmbd: validate owner of durable handle on reconnect
Nathan Chancellor (1):
scripts/dtc: Remove unused dts_version in dtc-lexer.l
Paulo Alcantara (1):
smb: client: fix dir separator in SMB1 UNIX mounts
Samuel Page (1):
fuse: reject oversized dirents in page cache
Sean Christopherson (3):
crypto: ccp: Don't attempt to copy CSR to userspace if PSP command failed
crypto: ccp: Don't attempt to copy PDH cert to userspace if PSP command failed
crypto: ccp: Don't attempt to copy ID to userspace if PSP command failed
Tamir Duberstein (1):
scripts: generate_rust_analyzer.py: define scripts
Tristan Madani (2):
ksmbd: fix out-of-bounds write in smb2_get_ea() EA alignment
ksmbd: use check_add_overflow() to prevent u16 DACL size overflow
Wesley Atwell (1):
crypto: krb5enc - fix sleepable flag handling in encrypt dispatch
Yongpeng Yang (1):
f2fs: fix UAF caused by decrementing sbi->nr_pages[] in f2fs_write_end_io()
Greg Kroah-Hartman
maintainerMakefile +1 -1
@@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 7 PATCHLEVEL = 0 -SUBLEVEL = 1 +SUBLEVEL = 2 EXTRAVERSION = NAME = Baby Opossum Posse
crypto/authencesn.c +4 -2
@@ -228,9 +228,11 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req, decrypt: -if (src != dst) - src =scatterwalk_ffwd (areq_ctx->src, src, assoclen); dst =scatterwalk_ffwd (areq_ctx->dst, dst, assoclen); +if (req->src == req->dst) + src = dst; +else + src =scatterwalk_ffwd (areq_ctx->src, src, assoclen);skcipher_request_set_tfm (skreq, ctx->enc); skcipher_request_set_callback(skreq, flags,
crypto/krb5enc.c +31 -20
114 lines not on this page · raw message
drivers/crypto/ccp/sev-dev.c +17 -2
@@ -1860,7 +1860,10 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable) ret =__sev_do_cmd_locked (SEV_CMD_PEK_CSR , &data, &argp->error); -/* If we query the CSR length, FW responded with expected data. */ +/* +* Firmware will returns the length of the CSR blob (either the minimum +* required length or the actual length written), return it to the user. +*/ input.length = data.len;if (copy_to_user ((void __user *)argp->data, &input,sizeof (input))) {
@@ -1868,6 +1871,9 @@ static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp, bool writable) goto e_free_blob; } +if (ret ||WARN_ON_ONCE (argp->error)) + goto e_free_blob; +if (blob) {if (copy_to_user (input_address, blob, input.length)) ret = -EFAULT ;
@@ -2218,6 +2224,9 @@ static int sev_ioctl_do_get_id2(struct sev_issue_cmd *argp) goto e_free; } +if (ret ||WARN_ON_ONCE (argp->error)) + goto e_free; +if (id_blob) {if (copy_to_user (input_address, id_blob, data.len)) { ret = -EFAULT ;
@@ -2334,7 +2343,10 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) ret =__sev_do_cmd_locked (SEV_CMD_PDH_CERT_EXPORT , &data, &argp->error); -/* If we query the length, FW responded with expected data. */ +/* +* Firmware will return the length of the blobs (either the minimum +* required length or the actual length written), return 'em to the user. +*/ input.cert_chain_len = data.cert_chain_len; input.pdh_cert_len = data.pdh_cert_len;
@@ -2343,6 +2355,9 @@ static int sev_ioctl_do_pdh_export(struct sev_issue_cmd *argp, bool writable) goto e_free_cert; } +if (ret ||WARN_ON_ONCE (argp->error)) + goto e_free_cert; +if (pdh_blob) {if (copy_to_user (input_pdh_cert_address, pdh_blob, input.pdh_cert_len)) {
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +19 -20
@@ -22,7 +22,7 @@*/ #include "amdgpu_ids.h" -#include <linux/idr.h> +#include <linux/xarray.h> #include <linux/dma-fence-array.h>
@@ -40,8 +40,8 @@* VMs are looked up from the PASID per amdgpu_device. */ -static DEFINE_IDR (amdgpu_pasid_idr); -static DEFINE_SPINLOCK (amdgpu_pasid_idr_lock); +static DEFINE_XARRAY_FLAGS(amdgpu_pasid_xa, XA_FLAGS_LOCK_IRQ | XA_FLAGS_ALLOC1); +static u32 amdgpu_pasid_xa_next;/* Helper to free pasid from a fence callback */ struct amdgpu_pasid_cb {
@@ -62,36 +62,37 @@ struct amdgpu_pasid_cb {*/ int amdgpu_pasid_alloc (unsigned int bits) { -int pasid; +u32 pasid; +int r;if (bits ==0 )return -EINVAL ; -spin_lock (&amdgpu_pasid_idr_lock); -/* TODO: Need to replace the idr with an xarry, and then -* handle the internal locking with ATOMIC safe paths. -*/ - pasid =idr_alloc_cyclic (&amdgpu_pasid_idr,NULL ,1 , -1U << bits,GFP_ATOMIC ); -spin_unlock (&amdgpu_pasid_idr_lock); - -if (pasid >=0 ) -trace_amdgpu_pasid_allocated (pasid); + r =xa_alloc_cyclic_irq (&amdgpu_pasid_xa, &pasid,xa_mk_value (0 ), +XA_LIMIT (1 , (1U << bits) -1 ), + &amdgpu_pasid_xa_next,GFP_KERNEL ); +if (r <0 ) +return r; +trace_amdgpu_pasid_allocated (pasid);return pasid; }/** * amdgpu_pasid_free - Free a PASID * @pasid: PASID to free +* +* Called in IRQ context. */ void amdgpu_pasid_free (u32 pasid) { +unsigned long flags; +trace_amdgpu_pasid_freed (pasid); -spin_lock (&amdgpu_pasid_idr_lock); -idr_remove (&amdgpu_pasid_idr, pasid); -spin_unlock (&amdgpu_pasid_idr_lock); +xa_lock_irqsave (&amdgpu_pasid_xa, flags); +__xa_erase (&amdgpu_pasid_xa, pasid); +xa_unlock_irqrestore (&amdgpu_pasid_xa, flags); } static void amdgpu_pasid_free_cb(struct dma_fence *fence,
@@ -634,7 +635,5 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)*/ void amdgpu_pasid_mgr_cleanup (void ) { -spin_lock (&amdgpu_pasid_idr_lock); -idr_destroy (&amdgpu_pasid_idr); -spin_unlock (&amdgpu_pasid_idr_lock); +xa_destroy (&amdgpu_pasid_xa); }
drivers/hv/mshv_vtl_main.c +9 -3
@@ -386,7 +386,6 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg)if (copy_from_user (&vtl0_mem, arg,sizeof (vtl0_mem)))return -EFAULT ; -/* vtl0_mem.last_pfn is excluded in the pagemap range for VTL0 as per design */ if (vtl0_mem.last_pfn <= vtl0_mem.start_pfn) {dev_err (vtl->module_dev,"range start pfn (%llx) > end pfn (%llx)\n" , vtl0_mem.start_pfn, vtl0_mem.last_pfn);
@@ -397,6 +396,10 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg)if (!pgmap)return -ENOMEM ; +/* +* vtl0_mem.last_pfn is excluded in the pagemap range for VTL0 as per design. +* last_pfn is not reserved or wasted, and reflects 'start_pfn + size' of pagemap range. +*/ pgmap->ranges[0 ].start =PFN_PHYS (vtl0_mem.start_pfn); pgmap->ranges[0 ].end =PFN_PHYS (vtl0_mem.last_pfn) -1 ; pgmap->nr_range =1 ;
@@ -405,8 +408,11 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg)/* * Determine the highest page order that can be used for the given memory range. * This works best when the range is aligned; i.e. both the start and the length. +* Clamp to MAX_FOLIO_ORDER to avoid a WARN in memremap_pages() when the range +* alignment exceeds the maximum supported folio order for this kernel config. */ - pgmap->vmemmap_shift =count_trailing_zeros (vtl0_mem.start_pfn | vtl0_mem.last_pfn); + pgmap->vmemmap_shift =min (count_trailing_zeros (vtl0_mem.start_pfn | vtl0_mem.last_pfn), +MAX_FOLIO_ORDER );dev_dbg (vtl->module_dev,"Add VTL0 memory: start: 0x%llx, end_pfn: 0x%llx, page order: %lu\n" , vtl0_mem.start_pfn, vtl0_mem.last_pfn, pgmap->vmemmap_shift);
@@ -415,7 +421,7 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg)if (IS_ERR (addr)) {dev_err (vtl->module_dev,"devm_memremap_pages error: %ld\n" ,PTR_ERR (addr));kfree (pgmap); -return -EFAULT ; +return PTR_ERR (addr); }/* Don't free pgmap, since it has to stick around until the memory
drivers/pwm/pwm_th1520.rs +1 -4
@@ -64,10 +64,7 @@ const fn th1520_pwm_fp(n: u32) -> usize {fn ns_to_cycles (ns:u64 , rate_hz:u64 ) ->u64 {const NSEC_PER_SEC_U64 :u64 = time::NSEC_PER_SEC as u64 ; - (match ns.checked_mul (rate_hz) { -Some (product) => product, -None => u64::MAX , - }) /NSEC_PER_SEC_U64 + ns.saturating_mul (rate_hz) /NSEC_PER_SEC_U64 }fn cycles_to_ns (cycles:u64 , rate_hz:u64 ) ->u64 {
fs/f2fs/compress.c +11 -3
@@ -1491,10 +1491,10 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)f2fs_compress_free_page (page); -dec_page_count (sbi, type); - -if (atomic_dec_return (&cic->pending_pages)) +if (atomic_dec_return (&cic->pending_pages)) { +dec_page_count (sbi, type);return ; + }for (i =0 ; i < cic->nr_rpages; i++) {WARN_ON (!cic->rpages[i]);
@@ -1504,6 +1504,14 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)page_array_free (sbi, cic->rpages, cic->nr_rpages);kmem_cache_free (cic_entry_slab, cic); + +/* +* Make sure dec_page_count() is the last access to sbi. +* Once it drops the F2FS_WB_CP_DATA counter to zero, the +* unmount thread can proceed to destroy sbi and +* sbi->page_array_slab. +*/ +dec_page_count (sbi, type); } static int f2fs_write_raw_pages(struct compress_ctx *cc,
fs/f2fs/data.c +4 -3
@@ -173,7 +173,8 @@ static void f2fs_finish_read_bio(struct bio *bio, bool in_task)while (nr_pages--)dec_page_count (F2FS_F_SB (folio),__read_io_type (folio)); -if (F2FS_F_SB (folio)->node_inode &&is_node_folio (folio) && +if (bio->bi_status ==BLK_STS_OK && +F2FS_F_SB (folio)->node_inode &&is_node_folio (folio) &&f2fs_sanity_check_node_footer (F2FS_F_SB (folio), folio, folio->index,NODE_TYPE_REGULAR , true)) bio->bi_status =BLK_STS_IOERR ;
@@ -386,6 +387,8 @@ static void f2fs_write_end_io(struct bio *bio) folio->index, NODE_TYPE_REGULAR, true);f2fs_bug_on (sbi, folio->index !=nid_of_node (folio)); } +if (f2fs_in_warm_node_list (sbi, folio)) +f2fs_del_fsync_node_entry (sbi, folio);dec_page_count (sbi, type);
@@ -397,8 +400,6 @@ static void f2fs_write_end_io(struct bio *bio) wq_has_sleeper(&sbi->cp_wait))wake_up (&sbi->cp_wait); -if (f2fs_in_warm_node_list (sbi, folio)) -f2fs_del_fsync_node_entry (sbi, folio);folio_clear_f2fs_gcing (folio);folio_end_writeback (folio); }
fs/f2fs/f2fs.h +1 -1
@@ -3989,7 +3989,7 @@ bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr);int f2fs_start_discard_thread (struct f2fs_sb_info *sbi);void f2fs_drop_discard_cmd (struct f2fs_sb_info *sbi);void f2fs_stop_discard_thread (struct f2fs_sb_info *sbi); -bool f2fs_issue_discard_timeout (struct f2fs_sb_info *sbi); +bool f2fs_issue_discard_timeout (struct f2fs_sb_info *sbi,bool need_check);void f2fs_clear_prefree_segments (struct f2fs_sb_info *sbi,struct cp_control *cpc);void f2fs_dirty_to_prefree (struct f2fs_sb_info *sbi);
fs/f2fs/namei.c +1 -0
@@ -964,6 +964,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,return err; err =f2fs_create_whiteout (idmap, old_dir, &whiteout, &fname); +f2fs_free_filename (&fname);if (err)return err; }
fs/f2fs/segment.c +3 -3
@@ -1880,7 +1880,7 @@ void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi)* * Return true if issued all discard cmd or no discard cmd need issue, otherwise return false. */ -bool f2fs_issue_discard_timeout (struct f2fs_sb_info *sbi) +bool f2fs_issue_discard_timeout (struct f2fs_sb_info *sbi,bool need_check) {struct discard_cmd_control *dcc =SM_I (sbi)->dcc_info;struct discard_policy dpolicy;
@@ -1897,7 +1897,7 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)/* just to make sure there is no pending discard commands */ __wait_all_discard_cmd (sbi,NULL ); -f2fs_bug_on (sbi,atomic_read (&dcc->discard_cmd_cnt)); +f2fs_bug_on (sbi, need_check &&atomic_read (&dcc->discard_cmd_cnt));return !dropped; }
@@ -2367,7 +2367,7 @@ static void destroy_discard_cmd_control(struct f2fs_sb_info *sbi)* Recovery can cache discard commands, so in error path of * fill_super(), it needs to give a chance to handle them. */ -f2fs_issue_discard_timeout (sbi); +f2fs_issue_discard_timeout (sbi, true);kfree (dcc);SM_I (sbi)->dcc_info =NULL ;
fs/f2fs/super.c +8 -3
@@ -2009,7 +2009,7 @@ static void f2fs_put_super(struct super_block *sb) }/* be sure to wait for any on-going discard commands */ - done =f2fs_issue_discard_timeout (sbi); + done =f2fs_issue_discard_timeout (sbi, true);if (f2fs_realtime_discard_enable (sbi) && !sbi->discard_blks && done) {struct cp_control cpc = { .reason =CP_UMOUNT |CP_TRIMMED ,
@@ -2152,7 +2152,7 @@ static int f2fs_unfreeze(struct super_block *sb)* will recover after removal of snapshot. */ if (test_opt (sbi,DISCARD ) && !f2fs_hw_support_discard (sbi)) -f2fs_issue_discard_timeout (sbi); +f2fs_issue_discard_timeout (sbi, true);clear_sbi_flag (F2FS_SB (sb),SBI_IS_FREEZING );return 0 ;
@@ -2957,7 +2957,12 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb) need_stop_discard = true; }else {f2fs_stop_discard_thread (sbi); -f2fs_issue_discard_timeout (sbi); +/* +* f2fs_ioc_fitrim() won't race w/ "remount ro" +* so it's safe to check discard_cmd_cnt in +* f2fs_issue_discard_timeout(). +*/ +f2fs_issue_discard_timeout (sbi, flags &SB_RDONLY ); need_restart_discard = true; } }
fs/fs-writeback.c +19 -17
@@ -570,28 +570,30 @@ void inode_switch_wbs_work_fn(struct work_struct *work)struct inode_switch_wbs_context *isw, *next_isw;struct llist_node *list; + list =llist_del_all (&new_wb->switch_wbs_ctxs);/* -* Grab out reference to wb so that it cannot get freed under us +* Nothing to do? That would be a problem as references held by isw +* items protect wb from freeing... +*/ +if (WARN_ON_ONCE (!list)) +return ; + +/* +* Grab our reference to wb so that it cannot get freed under us * after we process all the isw items. */ wb_get (new_wb); -while (1 ) { - list =llist_del_all (&new_wb->switch_wbs_ctxs); -/* Nothing to do? */ -if (!list) -break ; -/* -* In addition to synchronizing among switchers, I_WB_SWITCH -* tells the RCU protected stat update paths to grab the i_page -* lock so that stat transfer can synchronize against them. -* Let's continue after I_WB_SWITCH is guaranteed to be -* visible. -*/ -synchronize_rcu (); +/* +* In addition to synchronizing among switchers, I_WB_SWITCH +* tells the RCU protected stat update paths to grab the i_page +* lock so that stat transfer can synchronize against them. +* Let's continue after I_WB_SWITCH is guaranteed to be +* visible. +*/ +synchronize_rcu (); -llist_for_each_entry_safe (isw, next_isw, list, list) -process_inode_switch_wbs (new_wb, isw); - } +llist_for_each_entry_safe (isw, next_isw, list, list) +process_inode_switch_wbs (new_wb, isw);wb_put (new_wb); }
fs/fuse/control.c +2 -2
@@ -121,7 +121,7 @@ static ssize_t fuse_conn_max_background_write(struct file *file,const char __user *buf, size_t count, loff_t *ppos) { - unsigned val; + unsigned int val = 0;ssize_t ret; ret = fuse_conn_limit_write(file, buf, count, ppos, &val,
@@ -163,7 +163,7 @@ static ssize_t fuse_conn_congestion_threshold_write(struct file *file,const char __user *buf, size_t count, loff_t *ppos) { - unsigned val; + unsigned int val = 0;struct fuse_conn *fc;ssize_t ret;
fs/fuse/dev.c +18 -12
@@ -570,6 +570,11 @@ static void request_wait_answer(struct fuse_req *req)if (!err)return ; +if (req->args->abort_on_kill) { +fuse_abort_conn (fc); +return ; + } +if (test_bit (FR_URING , &req->flags)) removed =fuse_uring_remove_pending_req (req);else
@@ -676,7 +681,8 @@ ssize_t __fuse_simple_request(struct mnt_idmap *idmap,fuse_force_creds (req);__set_bit (FR_WAITING , &req->flags); -__set_bit (FR_FORCE , &req->flags); +if (!args->abort_on_kill) +__set_bit (FR_FORCE , &req->flags); }else {WARN_ON (args->nocreds); req =fuse_get_req (idmap, fm, false);
@@ -1011,6 +1017,9 @@ static int fuse_try_move_folio(struct fuse_copy_state *cs, struct folio **foliopfolio_clear_uptodate (newfolio);folio_clear_mappedtodisk (newfolio); +if (folio_test_large (newfolio)) + goto out_fallback_unlock; +if (fuse_check_folio (newfolio) !=0 ) goto out_fallback_unlock;
@@ -2590,9 +2599,8 @@ static int fuse_device_clone(struct fuse_conn *fc, struct file *new)static long fuse_dev_ioctl_clone (struct file *file,__u32 __user *argp) { -int res;int oldfd; -struct fuse_dev *fud =NULL ; +struct fuse_dev *fud;if (get_user (oldfd, argp))return -EFAULT ;
@@ -2605,17 +2613,15 @@ static long fuse_dev_ioctl_clone(struct file *file, __u32 __user *argp)* Check against file->f_op because CUSE * uses the same ioctl handler. */ -if (fd_file (f)->f_op == file->f_op) - fud =__fuse_get_dev (fd_file (f)); +if (fd_file (f)->f_op != file->f_op) +return -EINVAL ; - res = -EINVAL ; -if (fud) { -mutex_lock (&fuse_mutex); - res =fuse_device_clone (fud->fc, file); -mutex_unlock (&fuse_mutex); - } + fud =fuse_get_dev (fd_file (f)); +if (IS_ERR (fud)) +return PTR_ERR (fud); -return res; +guard (mutex)(&fuse_mutex); +return fuse_device_clone (fud->fc, file); } static long fuse_dev_ioctl_backing_open(struct file *file,
fs/fuse/fuse_i.h +1 -0
@@ -345,6 +345,7 @@ struct fuse_args { bool is_ext:1; bool is_pinned:1; bool invalidate_vmap:1; + bool abort_on_kill:1;struct fuse_in_arg in_args[4 ];struct fuse_arg out_args[2 ];void (*end)(struct fuse_mount *fm,struct fuse_args *args,int error);
fs/fuse/inode.c +1 -0
@@ -1551,6 +1551,7 @@ int fuse_send_init(struct fuse_mount *fm)int err;if (fm->fc->sync_init) { + ia->args.abort_on_kill = true; err =fuse_simple_request (fm, &ia->args);/* Ignore size of init reply */ if (err >0 )
fs/fuse/readdir.c +4 -0
@@ -41,6 +41,10 @@ static void fuse_add_dirent_to_cache(struct file *file,unsigned int offset;void *addr; +/* Dirent doesn't fit in readdir cache page? Skip caching. */ +if (reclen >PAGE_SIZE ) +return ; +spin_lock (&fi->rdc.lock);/* * Is cache already completed? Or this entry does not go at the end of
fs/ntfs3/fslog.c +11 -1
@@ -2791,13 +2791,14 @@ static inline bool check_file_record(const struct MFT_REC *rec,u16 fn =le16_to_cpu (rec->rhdr.fix_num);u16 ao =le16_to_cpu (rec->attr_off);u32 rs = sbi->record_size; +u32 used =le32_to_cpu (rec->used);/* Check the file record header for consistency. */ if (rec->rhdr.sign !=NTFS_FILE_SIGNATURE || fo > (SECTOR_SIZE - ((rs >>SECTOR_SHIFT ) +1 ) *sizeof (short )) || (fn -1 ) *SECTOR_SIZE != rs || ao <MFTRECORD_FIXUP_OFFSET_1 || ao > sbi->record_size -SIZEOF_RESIDENT || !is_rec_inuse (rec) || -le32_to_cpu (rec->total) != rs) { +le32_to_cpu (rec->total) != rs || used > rs || used < ao) {return false; }
@@ -2809,6 +2810,15 @@ static inline bool check_file_record(const struct MFT_REC *rec,return false; } +/* +* The do_action() handlers compute memmove lengths as +* "rec->used - <offset of validated attr>", which underflows when +* rec->used is smaller than the attribute walk reached. At this +* point attr is the ATTR_END marker; rec->used must cover it. +*/ +if (used <PtrOffset (rec, attr) +sizeof (attr->type)) +return false; +return true; }
fs/smb/client/cifsacl.c +86 -31
176 lines not on this page · raw message
fs/smb/client/connect.c +5 -5
@@ -3610,7 +3610,6 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx) server = mnt_ctx->server; ctx = mnt_ctx->fs_ctx; cifs_sb = mnt_ctx->cifs_sb; - sbflags =cifs_sb_flags (cifs_sb);/* search for existing tcon to this server share */ tcon =cifs_get_tcon (mnt_ctx->ses, ctx);
@@ -3625,9 +3624,10 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)* path (i.e., do not remap / and \ and do not map any special characters) */ if (tcon->posix_extensions) { - sbflags |=CIFS_MOUNT_POSIX_PATHS ; - sbflags &= ~(CIFS_MOUNT_MAP_SFM_CHR | -CIFS_MOUNT_MAP_SPECIAL_CHR ); +atomic_or (CIFS_MOUNT_POSIX_PATHS , &cifs_sb->mnt_cifs_flags); +atomic_andnot (CIFS_MOUNT_MAP_SFM_CHR | +CIFS_MOUNT_MAP_SPECIAL_CHR , + &cifs_sb->mnt_cifs_flags); }#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
@@ -3651,6 +3651,7 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ tcon->unix_ext =0 ;/* server does not support them */ + sbflags =cifs_sb_flags (cifs_sb);/* do not care if a following call succeed - informational */ if (!tcon->pipe && server->ops->qfs_tcon) { server->ops->qfs_tcon (mnt_ctx->xid, tcon, cifs_sb);
@@ -3675,7 +3676,6 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx) out: mnt_ctx->tcon = tcon; -atomic_set (&cifs_sb->mnt_cifs_flags, sbflags);return rc; }
fs/smb/client/smb1ops.c +8 -11
@@ -49,7 +49,6 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,if (!CIFSSMBQFSUnixInfo (xid, tcon)) {__u64 cap =le64_to_cpu (tcon->fsUnixInfo.Capability); -unsigned int sbflags;cifs_dbg (FYI ,"unix caps which server supports %lld\n" , cap);/*
@@ -76,29 +75,27 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon,if (cap &CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP )cifs_dbg (VFS ,"per-share encryption not supported yet\n" ); -if (cifs_sb) - sbflags =cifs_sb_flags (cifs_sb); - cap &=CIFS_UNIX_CAP_MASK ;if (ctx && ctx->no_psx_acl) cap &= ~CIFS_UNIX_POSIX_ACL_CAP ;else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {cifs_dbg (FYI ,"negotiated posix acl support\n" ); -if (cifs_sb) - sbflags |=CIFS_MOUNT_POSIXACL ; +if (cifs_sb) { +atomic_or (CIFS_MOUNT_POSIXACL , + &cifs_sb->mnt_cifs_flags); + } }if (ctx && ctx->posix_paths ==0 ) cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP ;else if (cap &CIFS_UNIX_POSIX_PATHNAMES_CAP ) {cifs_dbg (FYI ,"negotiate posix pathnames\n" ); -if (cifs_sb) - sbflags |=CIFS_MOUNT_POSIX_PATHS ; +if (cifs_sb) { +atomic_or (CIFS_MOUNT_POSIX_PATHS , + &cifs_sb->mnt_cifs_flags); + } } -if (cifs_sb) -atomic_set (&cifs_sb->mnt_cifs_flags, sbflags); -cifs_dbg (FYI ,"Negotiate caps 0x%x\n" , (int )cap);#ifdef CONFIG_CIFS_DEBUG2 if (cap &CIFS_UNIX_FCNTL_CAP )
fs/smb/client/smb2ops.c +6 -0
@@ -1783,6 +1783,12 @@ smb2_ioctl_query_info(const unsigned int xid, qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1 ].iov_base;if (le32_to_cpu (qi_rsp->OutputBufferLength) < qi.input_buffer_length) qi.input_buffer_length =le32_to_cpu (qi_rsp->OutputBufferLength); +if (qi.input_buffer_length >0 && +struct_size (qi_rsp, Buffer, qi.input_buffer_length) > + rsp_iov[1 ].iov_len) { + rc = -EFAULT ; + goto out; + }if (copy_to_user (&pqi->input_buffer_length, &qi.input_buffer_length,sizeof (qi.input_buffer_length))) {
fs/smb/server/connection.c +2 -3
@@ -237,7 +237,7 @@ int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id) {struct ksmbd_conn *conn;int rc, retry_count =0 , max_timeout =120 ; -int rcount =1 , bkt; +int rcount, bkt; retry_idle:if (retry_count >= max_timeout)
@@ -246,8 +246,7 @@ int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id)down_read (&conn_list_lock);hash_for_each (conn_list, bkt, conn, hlist) {if (conn->binding ||xa_load (&conn->sessions, sess_id)) { -if (conn == curr_conn) - rcount =2 ; + rcount = (conn == curr_conn) ?2 :1 ;if (atomic_read (&conn->req_running) >= rcount) { rc = wait_event_timeout(conn->req_running_q, atomic_read(&conn->req_running) < rcount,
fs/smb/server/mgmt/user_config.c +0 -6
@@ -56,12 +56,6 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp, goto err_free;if (resp_ext) { -if (resp_ext->ngroups >NGROUPS_MAX ) { -pr_err ("ngroups(%u) from login response exceeds max groups(%d)\n" , - resp_ext->ngroups,NGROUPS_MAX ); - goto err_free; - } - user->sgid =kmemdup (resp_ext->____payload, resp_ext->ngroups *sizeof (gid_t),KSMBD_DEFAULT_GFP );
fs/smb/server/mgmt/user_session.c +3 -5
@@ -382,12 +382,10 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)return ;delete_proc_session (sess); - +ksmbd_tree_conn_session_logoff (sess); +ksmbd_destroy_file_table (sess);if (sess->user)ksmbd_free_user (sess->user); - -ksmbd_tree_conn_session_logoff (sess); -ksmbd_destroy_file_table (&sess->file_table);ksmbd_launch_ksmbd_durable_scavenger ();ksmbd_session_rpc_clear_list (sess);free_channel_list (sess);
@@ -618,7 +616,7 @@ void destroy_previous_session(struct ksmbd_conn *conn, goto out; } -ksmbd_destroy_file_table (&prev_sess->file_table); +ksmbd_destroy_file_table (prev_sess); prev_sess->state =SMB2_SESSION_EXPIRED ;ksmbd_all_conn_set_status (id,KSMBD_SESS_NEED_SETUP );ksmbd_launch_ksmbd_durable_scavenger ();
fs/smb/server/oplock.c +7 -0
@@ -1841,6 +1841,7 @@ int smb2_check_durable_oplock(struct ksmbd_conn *conn,struct ksmbd_share_config *share, struct ksmbd_file *fp, struct lease_ctx_info *lctx, + struct ksmbd_user *user, char *name) { struct oplock_info *opinfo = opinfo_get(fp);
@@ -1849,6 +1850,12 @@ int smb2_check_durable_oplock(struct ksmbd_conn *conn,if (!opinfo)return 0 ; +if (ksmbd_vfs_compare_durable_owner (fp, user) == false) { +ksmbd_debug (SMB ,"Durable handle reconnect failed: owner mismatch\n" ); + ret = -EBADF ; + goto out; + } +if (opinfo->is_lease == false) {if (lctx) {pr_err ("create context include lease\n" );
fs/smb/server/oplock.h +1 -0
@@ -126,5 +126,6 @@ int smb2_check_durable_oplock(struct ksmbd_conn *conn,struct ksmbd_share_config *share, struct ksmbd_file *fp, struct lease_ctx_info *lctx, + struct ksmbd_user *user, char *name);#endif /* __KSMBD_OPLOCK_H */
fs/smb/server/smb2pdu.c +4 -1
@@ -3013,7 +3013,8 @@ int smb2_open(struct ksmbd_work *work) }if (dh_info.reconnected == true) { - rc =smb2_check_durable_oplock (conn, share, dh_info.fp, lc, name); + rc =smb2_check_durable_oplock (conn, share, dh_info.fp, + lc, sess->user, name);if (rc) {ksmbd_put_durable_fd (dh_info.fp); goto err_out2;
@@ -4821,6 +4822,8 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,/* align next xattr entry at 4 byte bundary */ alignment_bytes = ((next_offset +3 ) & ~3 ) - next_offset;if (alignment_bytes) { +if (buf_free_len < alignment_bytes) +break ;memset (ptr,'\0' , alignment_bytes); ptr += alignment_bytes; next_offset += alignment_bytes;
fs/smb/server/smbacl.c +48 -13
134 lines not on this page · raw message
fs/smb/server/transport_ipc.c +13 -3
@@ -13,6 +13,7 @@#include <net/genetlink.h> #include <linux/socket.h> #include <linux/workqueue.h> +#include <linux/overflow.h> #include "vfs_cache.h" #include "transport_ipc.h"
@@ -497,7 +498,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) {struct ksmbd_rpc_command *resp = entry->response; - msg_sz =sizeof (struct ksmbd_rpc_command ) + resp->payload_sz; +if (check_add_overflow (sizeof (struct ksmbd_rpc_command ), + resp->payload_sz, &msg_sz)) +return -EINVAL ;break ; }case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST :
@@ -516,8 +519,9 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)if (resp->payload_sz < resp->veto_list_sz)return -EINVAL ; - msg_sz =sizeof (struct ksmbd_share_config_response ) + - resp->payload_sz; +if (check_add_overflow (sizeof (struct ksmbd_share_config_response ), + resp->payload_sz, &msg_sz)) +return -EINVAL ; }break ; }
@@ -526,6 +530,12 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry)struct ksmbd_login_response_ext *resp = entry->response;if (resp->ngroups) { +if (resp->ngroups <0 || + resp->ngroups >NGROUPS_MAX ) { +pr_err ("ngroups(%d) from login response exceeds max groups(%d)\n" , + resp->ngroups,NGROUPS_MAX ); +return -EINVAL ; + } msg_sz =sizeof (struct ksmbd_login_response_ext ) + resp->ngroups *sizeof (gid_t); }
fs/smb/server/transport_tcp.c +3 -1
@@ -183,6 +183,8 @@ static int ksmbd_tcp_new_connection(struct socket *client_sk) t =alloc_transport (client_sk);if (!t) {sock_release (client_sk); +if (server_conf.max_connections) +atomic_dec (&active_num_conn);return -ENOMEM ; }
@@ -279,7 +281,7 @@ static int ksmbd_kthread_fn(void *p) skip_max_ip_conns_limit:if (server_conf.max_connections && -atomic_inc_return (&active_num_conn) >= server_conf.max_connections) { +atomic_inc_return (&active_num_conn) > server_conf.max_connections) {pr_info_ratelimited ("Limit the maximum number of connections(%u)\n" ,atomic_read (&active_num_conn));atomic_dec (&active_num_conn);
fs/smb/server/vfs_cache.c +108 -20
230 lines not on this page · raw message
fs/smb/server/vfs_cache.h +11 -1
@@ -68,6 +68,13 @@ enum {FP_CLOSED }; +/* Owner information for durable handle reconnect */ +struct durable_owner { +unsigned int uid; +unsigned int gid; +char *name; +}; +struct ksmbd_file {struct file *filp;u64 persistent_id;
@@ -114,6 +121,7 @@ struct ksmbd_file {bool is_resilient;bool is_posix_ctxt; +struct durable_owner owner; }; static inline void set_ctx_actor(struct dir_context *ctx,
@@ -140,7 +148,7 @@ static inline bool ksmbd_stream_fd(struct ksmbd_file *fp) }int ksmbd_init_file_table (struct ksmbd_file_table *ft); -void ksmbd_destroy_file_table (struct ksmbd_file_table *ft); +void ksmbd_destroy_file_table (struct ksmbd_session *sess);int ksmbd_close_fd (struct ksmbd_work *work,u64 id);struct ksmbd_file *ksmbd_lookup_fd_fast (struct ksmbd_work *work,u64 id);struct ksmbd_file *ksmbd_lookup_foreign_fd (struct ksmbd_work *work,u64 id);
@@ -166,6 +174,8 @@ void ksmbd_free_global_file_table(void);void ksmbd_set_fd_limit (unsigned long limit);void ksmbd_update_fstate (struct ksmbd_file_table *ft,struct ksmbd_file *fp,unsigned int state); +bool ksmbd_vfs_compare_durable_owner (struct ksmbd_file *fp, +struct ksmbd_user *user);/* * INODE hash
include/uapi/linux/mshv.h +1 -1
@@ -357,7 +357,7 @@ struct mshv_vtl_sint_post_msg {struct mshv_vtl_ram_disposition {__u64 start_pfn; -__u64 last_pfn; +__u64 last_pfn;/* last_pfn is excluded from the range [start_pfn, last_pfn) */ };struct mshv_vtl_set_poll_file {
net/packet/af_packet.c +13 -8
@@ -2717,7 +2717,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) {struct sk_buff *skb =NULL ;struct net_device *dev; -struct virtio_net_hdr *vnet_hdr =NULL ; +struct virtio_net_hdr vnet_hdr; +bool has_vnet_hdr = false;struct sockcm_cookie sockc;__be16 proto;int err, reserve =0 ;
@@ -2818,16 +2819,20 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) hlen =LL_RESERVED_SPACE (dev); tlen = dev->needed_tailroom;if (vnet_hdr_sz) { - vnet_hdr = data; data += vnet_hdr_sz; tp_len -= vnet_hdr_sz; -if (tp_len <0 || -__packet_snd_vnet_parse (vnet_hdr, tp_len)) { +if (tp_len <0 ) { + tp_len = -EINVAL ; + goto tpacket_error; + } +memcpy (&vnet_hdr, data - vnet_hdr_sz,sizeof (vnet_hdr)); +if (__packet_snd_vnet_parse (&vnet_hdr, tp_len)) { tp_len = -EINVAL ; goto tpacket_error; } copylen =__virtio16_to_cpu (vio_le (), - vnet_hdr->hdr_len); + vnet_hdr.hdr_len); + has_vnet_hdr = true; } copylen =max_t (int, copylen, dev->hard_header_len); skb = sock_alloc_send_skb(&po->sk,
@@ -2864,12 +2869,12 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) } } -if (vnet_hdr_sz) { -if (virtio_net_hdr_to_skb (skb, vnet_hdr,vio_le ())) { +if (has_vnet_hdr) { +if (virtio_net_hdr_to_skb (skb, &vnet_hdr,vio_le ())) { tp_len = -EINVAL ; goto tpacket_error; } -virtio_net_hdr_set_proto (skb, vnet_hdr); +virtio_net_hdr_set_proto (skb, &vnet_hdr); } skb->destructor = tpacket_destruct_skb;
net/rxrpc/key.c +4 -0
@@ -502,6 +502,10 @@ static int rxrpc_preparse(struct key_preparsed_payload *prep)if (v1->security_index !=RXRPC_SECURITY_RXKAD ) goto error; + ret = -EKEYREJECTED ; +if (v1->ticket_length >AFSTOKEN_RK_TIX_MAX ) + goto error; + plen =sizeof (*token->kad) + v1->ticket_length; prep->quotalen += plen +sizeof (*token);
scripts/dtc/dtc-lexer.l +0 -3
@@ -39,8 +39,6 @@ extern bool treesource_error; #define DPRINT(fmt, ...) do { } while (0) #endif -static int dts_version = 1; - #define BEGIN_DEFAULT() DPRINT("<V1>\n"); \ BEGIN(V1); \
@@ -101,7 +99,6 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); <*>"/dts-v1/" { DPRINT("Keyword: /dts-v1/\n"); - dts_version = 1; BEGIN_DEFAULT(); return DT_V1; }
scripts/generate_rust_analyzer.py +13 -1
@@ -188,6 +188,18 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit append_crate_with_generated("uapi", ["core", "ffi", "pin_init"]) append_crate_with_generated("kernel", ["core", "macros", "build_error", "pin_init", "ffi", "bindings", "uapi"]) + scripts = srctree / "scripts" + makefile = (scripts / "Makefile").read_text() + for path in scripts.glob("*.rs"): + name = path.stem + if f"{name}-rust" not in makefile: + continue + append_crate( + name, + path, + ["std"], + ) + def is_root_crate(build_file, target): try: contents = build_file.read_text()
@@ -204,7 +216,7 @@ def generate_crates(srctree, objtree, sysroot_src, external_src, cfgs, core_edit for folder in extra_dirs: for path in folder.rglob("*.rs"): logging.info("Checking %s", path) - name = path.name.replace(".rs", "") + name = path.stem # Skip those that are not crate roots. if not is_root_crate(path.parent / "Makefile", name) and \
sound/hda/codecs/realtek/alc269.c +1 -0
@@ -7605,6 +7605,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {SND_PCI_QUIRK (0x17aa ,0x3801 ,"Lenovo Yoga9 14IAP7" ,ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN ),HDA_CODEC_QUIRK (0x17aa ,0x3802 ,"DuetITL 2021" ,ALC287_FIXUP_YOGA7_14ITL_SPEAKERS ),SND_PCI_QUIRK (0x17aa ,0x3802 ,"Lenovo Yoga Pro 9 14IRP8" ,ALC287_FIXUP_TAS2781_I2C ), +SND_PCI_QUIRK (0x17aa ,0x3811 ,"Legion S7 15IMH05" ,ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS ),SND_PCI_QUIRK (0x17aa ,0x3813 ,"Legion 7i 15IMHG05" ,ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS ),SND_PCI_QUIRK (0x17aa ,0x3818 ,"Lenovo C940 / Yoga Duet 7" ,ALC298_FIXUP_LENOVO_C940_DUET7 ), SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS),
sound/usb/caiaq/device.c +2 -2
@@ -384,7 +384,7 @@ static void card_free(struct snd_card *card)snd_usb_caiaq_input_free (cdev);#endif snd_usb_caiaq_audio_free (cdev); -usb_reset_device (cdev->chip.dev); +usb_put_dev (cdev->chip.dev); } static int create_card(struct usb_device *usb_dev,
@@ -410,7 +410,7 @@ static int create_card(struct usb_device *usb_dev,return err; cdev =caiaqdev (card); - cdev->chip.dev = usb_dev; + cdev->chip.dev =usb_get_dev (usb_dev); cdev->chip.card = card; cdev->chip.usb_id =USB_ID (le16_to_cpu (usb_dev->descriptor.idVendor),le16_to_cpu (usb_dev->descriptor.idProduct));
sound/usb/mixer.c +7 -0
@@ -1204,6 +1204,13 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, cval->min =-11264 ;/* Mute under it */ }break ; +case USB_ID (0x31b2 ,0x0111 ):/* MOONDROP JU Jiu */ +if (!strcmp (kctl->id.name,"PCM Playback Volume" )) { +usb_audio_info (chip, +"set volume quirk for MOONDROP JU Jiu\n" ); + cval->min =-10880 ;/* Mute under it */ + } +break ; } }