This is the start of the stable review cycle for the 3.16.83 release. There are 245 patches in this series, which will be posted as responses to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Tue Apr 28 18:00:00 UTC 2020. Anything received after that time might be too late.
All the patches have also been committed to the linux-3.16.y-rc branch of https://git.kernel.org/pub/scm/linux/kernel/git/bwh/linux-stable-rc.git . A shortlog and diffstat can be found below.
Ben.
-------------
Al Viro (2): do_last(): fetch directory ->i_mode and ->i_uid before it's too late [d0cb50185ae942b03c4327be322055d622dc79f6] vfs: fix do_last() regression [6404674acd596de41fd3ad5f267b4525494a891a]
Alan Cox (1): usb: dwc3: pci: Add PCI ID for Intel Braswell [7d643664ea559b36188cae264047ce3c9bfec3a2]
Alan Stern (1): HID: Fix slab-out-of-bounds read in hid_field_extract [8ec321e96e056de84022c032ffea253431a83c3c]
Alberto Aguirre (2): ALSA: usb-audio: add implicit fb quirk for Axe-Fx II [17f08b0d9aafccdb10038ab6dbd9ddb6433c13e2] ALSA: usb-audio: simplify set_sync_ep_implicit_fb_quirk [103e9625647ad74d201e26fb74afcd8479142a37]
Alex Sverdlin (1): ARM: 8950/1: ftrace/recordmcount: filter relocation types [927d780ee371d7e121cea4fc7812f6ef2cea461c]
Amir Goldstein (1): locks: print unsigned ino in /proc/locks [98ca480a8f22fdbd768e3dad07024c8d4856576c]
Ard Biesheuvel (1): x86/efistub: Disable paging at mixed mode entry [4911ee401b7ceff8f38e0ac597cbf503d71e690c]
Arnd Bergmann (2): btrfs: tree-checker: use %zu format string for size_t [7cfad65297bfe0aa2996cd72d21c898aa84436d9] scsi: fnic: fix invalid stack access [42ec15ceaea74b5f7a621fc6686cbf69ca66c4cf]
Avinash Patil (1): mwifiex: fix probable memory corruption while processing TDLS frame [3c99832d74777c9ec5545a92450fac5d37b0d0e1]
Brian Norris (1): mwifiex: fix unbalanced locking in mwifiex_process_country_ie() [65b1aae0d9d5962faccc06bdb8e91a2a0b09451c]
Cengiz Can (1): blktrace: fix dereference after null check [153031a301bb07194e9c37466cfce8eacb977621]
Chao Yu (1): quota: fix wrong condition in is_quota_modification() [6565c182094f69e4ffdece337d395eb7ec760efc]
Chen-Yu Tsai (1): net: stmmac: dwmac-sunxi: Allow all RGMII modes [52cc73e5404c7ba0cbfc50cb4c265108c84b3d5a]
Christian Brauner (1): taskstats: fix data-race [0b8d616fb5a8ffa307b1d3af37f55c15dae14f28]
Christophe Leroy (1): powerpc/irq: fix stack overflow verification [099bc4812f09155da77eeb960a983470249c9ce1]
Cong Wang (2): net_sched: fix datalen for ematch [61678d28d4a45ef376f5d02a839cc37509ae9281] netfilter: fix a use-after-free in mtype_destroy() [c120959387efa51479056fd01dc90adfba7a590c]
Dan Carpenter (1): scsi: iscsi: qla4xxx: fix double free in probe [fee92f25777789d73e1936b91472e9c4644457c8]
David Hildenbrand (1): virtio-balloon: fix managed page counts when migrating pages between zones [63341ab03706e11a31e3dd8ccc0fbc9beaf723f0]
David Sterba (6): btrfs: add more checks to btrfs_read_sys_array [e3540eab29e1b2260bc4b9b3979a49a00e3e3af8] btrfs: cleanup, rename a few variables in btrfs_read_sys_array [1ffb22cf8c322bbfea6b35fe23d025841b49fede] btrfs: handle invalid num_stripes in sys_array [f5cdedd73fa71b74dcc42f2a11a5735d89ce7c4f] btrfs: kill extent_buffer_page helper [fb85fc9a675738ee2746b51c3aedde944b18ca02] btrfs: new define for the inline extent data start [7ec20afbcb7b257aec82ea5d66e6b0b7499abaca] btrfs: tree-check: reduce stack consumption in check_dir_item [e2683fc9d219430f5b78889b50cde7f40efeba7b]
Davidlohr Bueso (1): blktrace: re-write setting q->blk_trace [cdea01b2bf98affb7e9c44530108a4a28535eee8]
Dedy Lansky (1): cfg80211/mac80211: make ieee80211_send_layer2_update a public function [30ca1aa536211f5ac3de0173513a7a99a98a97f3]
Dmitry Torokhov (5): HID: hid-input: clear unmapped usages [4f3882177240a1f55e45a3d241d3121341bead78] Input: add safety guards to input_set_keycode() [cb222aed03d798fc074be55e59d9a112338ee784] ptp: create "pins" together with the rest of attributes [85a66e55019583da1e0f18706b7a8281c9f6de5b] ptp: do not explicitly set drvdata in ptp_clock_register() [882f312dc0751c973db26478f07f082c584d16aa] ptp: use is_visible method to hide unused attributes [af59e717d5ff9c8dbf9bcc581c0dfb3b2a9c9030]
Emiliano Ingrassia (1): usb: core: urb: fix URB structure initialization function [1cd17f7f0def31e3695501c4f86cd3faf8489840]
Eric Dumazet (9): 6pack,mkiss: fix possible deadlock [5c9934b6767b16ba60be22ec3cbd4379ad64170d] bonding: fix bond_neigh_init() [9e99bfefdbce2e23ef37487a3bcb4adf90a791d1] macvlan: do not assume mac_header is set in macvlan_broadcast() [96cc4b69581db68efc9749ef32e9cf8e0160c509] macvlan: use skb_reset_mac_header() in macvlan_queue_xmit() [1712b2fff8c682d145c7889d2290696647d82dab] neighbour: remove neigh_cleanup() method [f394722fb0d0f701119368959d7cd0ecbc46363a] netfilter: bridge: make sure to pull arp header in br_nf_forward_arp() [5604285839aaedfb23ebe297799c6e558939334d] pkt_sched: fq: do not accept silly TCA_FQ_QUANTUM [d9e15a2733067c9328fb56d98fe8e574fa19ec31] tcp: do not send empty skb from tcp_write_xmit() [1f85e6267caca44b30c54711652b0726fadbb131] vlan: vlan_changelink() should propagate errors [eb8ef2a3c50092bb018077c047b8dba1ce0e78e3]
Erkka Talvitie (1): USB: EHCI: Do not return -EPIPE when hub is disconnected [64cc3f12d1c7dd054a215bc1ff9cc2abcfe35832]
Eryu Guan (1): ext4: update c/mtime on truncate up [911af577de4e444622d46500c1f9a37ab4335d3a]
Eugenio Pérez (1): vhost: Check docket sk_family instead of call getname [42d84c8490f9f0931786f1623191fcab397c3d64]
Fabian Henneke (1): hidraw: Return EPOLLOUT from hidraw_poll [378b80370aa1fe50f9c48a3ac8af3e416e73b89f]
Felipe Balbi (3): usb: dwc3: pci: Add Support for Intel Elkhart Lake Devices [dbb0569de852fb4576d6f62078d515f989a181ca] usb: dwc3: pci: add support for Comet Lake PCH ID [7ae622c978db6b2e28b4fced6ecd2a174492059d] usb: dwc3: pci: add support for TigerLake Devices [b3649dee5fbb0f6585010e6e9313dfcbb075b22b]
Filipe Manana (3): Btrfs: fix emptiness check for dirtied extent buffers at check_leaf() [f177d73949bf758542ca15a1c1945bd2e802cc65] Btrfs: fix infinite loop during nocow writeback due to race [de7999afedff02c6631feab3ea726a0e8f8c3d40] Btrfs: fix removal logic of the tree mod log that leads to use-after-free issues [6609fee8897ac475378388238456c84298bff802]
Finn Thain (4): net/sonic: Add mutual exclusion for accessing shared state [865ad2f2201dc18685ba2686f13217f8b3a9c52c] net/sonic: Fix receive buffer handling [9e311820f67e740f4fb8dcb82b4c4b5b05bdd1a5] net/sonic: Quiesce SONIC before re-initializing descriptor memory [3f4b7e6a2be982fd8820a2b54d46dd9c351db899] net/sonic: Use MMIO accessors [e3885f576196ddfc670b3d53e745de96ffcb49ab]
Florian Faber (1): can: mscan: mscan_rx_poll(): fix rx path lockup when returning from polling to irq mode [2d77bd61a2927be8f4e00d9478fe6996c47e8d45]
Florian Westphal (6): netfilter: arp_tables: init netns pointer in xt_tgchk_param struct [1b789577f655060d98d20ed0c6f9fbd469d6ba63] netfilter: arp_tables: init netns pointer in xt_tgdtor_param struct [212e7f56605ef9688d0846db60c6c6ec06544095] netfilter: ctnetlink: netns exit must wait for callbacks [18a110b022a5c02e7dc9f6109d0bd93e58ac6ebb] netfilter: ebtables: compat: reject all padding in matches/watchers [e608f631f0ba5f1fc5ee2e260a3a35d13107cbfe] netfilter: ebtables: convert BUG_ONs to WARN_ONs [fc6a5d0601c5ac1d02f283a46f60b87b2033e5ca] netfilter: ipset: avoid null deref when IPSET_ATTR_LINENO is present [22dad713b8a5ff488e07b821195270672f486eb2]
Geert Uytterhoeven (1): gpio: Fix error message on out-of-range GPIO in lookup table [d935bd50dd14a7714cbdba9a76435dbb56edb1ae]
Goldwyn Rodrigues (1): dm flakey: check for null arg_name in parse_features() [7690e25302dc7d0cd42b349e746fe44b44a94f2b]
Gu Jinxiang (1): btrfs: validate type when reading a chunk [315409b0098fb2651d86553f0436b70502b29bb2]
Hangbin Liu (1): vxlan: fix tos value before xmit [71130f29979c7c7956b040673e6b9d5643003176]
Hans de Goede (2): pinctrl: baytrail: Really serialize all register accesses [40ecab551232972a39cdd8b6f17ede54a3fdb296] platform/x86: hp-wmi: Make buffer for HPWMI_FEATURE2_QUERY 128 bytes [133b2acee3871ae6bf123b8fe34be14464aa3d2c]
Heikki Krogerus (8): usb: dwc3: pci: add ID for one more Intel Broxton platform [1ffb4d5cc78a3a99109ff0808ce6915de07a0588] usb: dwc3: pci: add ID for the Intel Comet Lake -H variant [3c3caae4cd6e122472efcf64759ff6392fb6bce2] usb: dwc3: pci: add Intel Cannonlake PCI IDs [682179592e48fa66056fbad1a86604be4992f885] usb: dwc3: pci: add Intel Gemini Lake PCI ID [8f8983a5683623b62b339d159573f95a1fce44f3] usb: dwc3: pci: add Intel Kabylake PCI ID [4491ed5042f0419b22a4b08331adb54af31e2caa] usb: dwc3: pci: add support for Intel Broxton SOC [b4c580a43d520b7812c0fd064fbab929ce2f1da0] usb: dwc3: pci: add support for Intel IceLake [00908693c481f7298adf8cf4d2ff3dfbea8c375f] usb: dwc3: pci: add support for Intel Sunrise Point PCH [84a2b61b6eb94036093531cdabc448dddfbae45a]
Hou Tao (1): dm btree: increase rebalance threshold in __rebalance2() [474e559567fa631dea8fb8407ab1b6090c903755]
James Bottomley (1): scsi: enclosure: Fix stale device oops with hot replug [529244bd1afc102ab164429d338d310d5d65e60d]
Jan Kara (7): blktrace: Protect q->blk_trace with RCU [c780e86dd48ef6467a1146cf7d0fe1e05a635039] ext4: check for directory entries too close to block end [109ba779d6cca2d519c5dd624a3276d03e21948e] ext4: fix races between buffered IO and collapse / insert range [32ebffd3bbb4162da5ff88f9a35dd32d0a28ea70] ext4: fix races between page faults and hole punching [ea3d7209ca01da209cda6f0dea8be9cc4b7a933b] ext4: fix races of writeback with punch hole and zero range [011278485ecc3cd2a3954b5d4c73101d919bf1fa] ext4: move unlocked dio protection from ext4_alloc_file_blocks() [17048e8a083fec7ad841d88ef0812707fbc7e39f] kobject: Export kobject_get_unless_zero() [c70c176ff8c3ff0ac6ef9a831cd591ea9a66bd1a]
Jari Ruusu (1): Fix built-in early-load Intel microcode alignment [f5ae2ea6347a308cfe91f53b53682ce635497d0d]
Jeff Mahoney (2): btrfs: cleanup, stop casting for extent_map->lookup everywhere [95617d69326ce386c95e33db7aeb832b45ee9f8f] btrfs: struct-funcs, constify readers [1cbb1f454e5321e47fc1e6b233066c7ccc979d15]
Jerónimo Borque (1): USB: serial: simple: Add Motorola Solutions TETRA MTP3xxx and MTP85xx [260e41ac4dd3e5acb90be624c03ba7f019615b75]
Jian-Hong Pan (1): platform/x86: asus-wmi: Fix keyboard brightness cannot be set to 0 [176a7fca81c5090a7240664e3002c106d296bf31]
Jim Mattson (1): kvm: x86: Host feature SSBD doesn't imply guest feature SPEC_CTRL_SSBD [396d2e878f92ec108e4293f1c77ea3bc90b414ff]
Jiri Kosina (1): HID: hidraw, uhid: Always report EPOLLOUT [9e635c2851df6caee651e589fbf937b637973c91]
Jiri Slaby (4): vt: selection, close sel_buffer race [07e6124a1a46b4b5a9b3cacc0c306b50da87abf5] vt: selection, handle pending signals in paste_selection [687bff0cd08f790d540cfb7b2349f0d876cdddec] vt: selection, push console lock down [4b70dd57a15d2f4685ac6e38056bad93e81e982f] vt: selection, push sel_lock up [e8c75a30a23c6ba63f4ef6895cbf41fd42f21aa2]
Johan Hovold (29): ALSA: usb-audio: fix sync-ep altsetting sanity check [5d1b71226dc4d44b4b65766fa9d74492f9d4587b] Input: aiptek - fix endpoint sanity check [3111491fca4f01764e0c158c5e0f7ced808eef51] Input: gtco - fix endpoint sanity check [a8eeb74df5a6bdb214b2b581b14782c5f5a0cf83] Input: keyspan-remote - fix control-message timeouts [ba9a103f40fc4a3ec7558ec9b0b97d4f92034249] Input: sur40 - fix interface sanity checks [6b32391ed675827f8425a414abbc6fbd54ea54fe] USB: adutux: fix interface sanity check [3c11c4bed02b202e278c0f5c319ae435d7fb9815] USB: atm: ueagle-atm: add missing endpoint check [09068c1ad53fb077bdac288869dec2435420bdc4] USB: core: add endpoint-blacklist quirk [73f8bda9b5dc1c69df2bc55c0cbb24461a6391a9] USB: core: fix check for duplicate endpoints [3e4f8e21c4f27bcf30a48486b9dcc269512b79ff] USB: idmouse: fix interface sanity checks [59920635b89d74b9207ea803d5e91498d39e8b69] USB: quirks: blacklist duplicate ep on Sound Devices USBPre2 [bdd1b147b8026df0e4260b387026b251d888ed01] USB: serial: ch341: handle unbound port at reset_resume [4d5ef53f75c22d28f490bcc5c771fcc610a9afa4] USB: serial: io_edgeport: add missing active-port sanity check [1568c58d11a7c851bd09341aeefd6a1c308ac40d] USB: serial: io_edgeport: fix epic endpoint lookup [7c5a2df3367a2c4984f1300261345817d95b71f8] USB: serial: io_edgeport: handle unbound ports on URB completion [e37d1aeda737a20b1846a91a3da3f8b0f00cf690] USB: serial: keyspan: handle unbound ports [3018dd3fa114b13261e9599ddb5656ef97a1fa17] USB: serial: opticon: fix control-message timeouts [5e28055f340275a8616eee88ef19186631b4d136] USB: serial: quatech2: handle unbound ports [9715a43eea77e42678a1002623f2d9a78f5b81a1] USB: serial: suppress driver bind attributes [fdb838efa31e1ed9a13ae6ad0b64e30fdbd00570] can: gs_usb: gs_usb_probe(): use descriptors of current altsetting [2f361cd9474ab2c4ab9ac8db20faf81e66c6279b] media: ov519: add missing endpoint sanity checks [998912346c0da53a6dbb71fab3a138586b596b30] media: stv06xx: add missing descriptor sanity checks [485b06aadb933190f4bc44e006076bc27a23f205] media: xirlink_cit: add missing descriptor sanity checks [a246b4d547708f33ff4d4b9a7a5dbac741dc89d8] r8152: add missing endpoint sanity check [86f3f4cd53707ceeec079b83205c8d3c756eca93] staging: gigaset: add endpoint-type sanity check [ed9ed5a89acba51b82bdff61144d4e4a4245ec8a] staging: gigaset: fix general protection fault on probe [53f35a39c3860baac1e5ca80bf052751cfb24a99] staging: gigaset: fix illegal free on probe errors [84f60ca7b326ed8c08582417493982fe2573a9ad] staging: rtl8188eu: fix interface sanity check [74ca34118a0e05793935d804ccffcedd6eb56596] staging: rtl8712: fix interface sanity check [c724f776f048538ecfdf53a52b7a522309f5c504]
Johannes Thumshirn (1): btrfs: ensure that a DUP or RAID1 block group has exactly two stripes [349ae63f40638a28c6fce52e8447c2d14b84cc0c]
Jose Abreu (2): net: stmmac: 16KB buffer must be 16 byte aligned [8605131747e7e1fd8f6c9f97a00287aae2b2c640] net: stmmac: Enable 16KB buffer size [b2f3a481c4cd62f78391b836b64c0a6e72b503d2]
Josef Bacik (9): Btrfs: fix em leak in find_first_block_group [187ee58c62c1d0d238d3dc4835869d33e1869906] btrfs: abort transaction after failed inode updates in create_subvol [c7e54b5102bf3614cadb9ca32d7be73bad6cecf0] btrfs: check rw_devices, not num_devices for balance [b35cf1f0bf1f2b0b193093338414b9bd63b29015] btrfs: do not call synchronize_srcu() in inode_tree_del [f72ff01df9cf5db25c76674cac16605992d15467] btrfs: do not delete mismatched root refs [423a716cd7be16fb08690760691befe3be97d3fc] btrfs: do not leak reloc root if we fail to read the fs root [ca1aa2818a53875cfdd175fb5e9a2984e997cce9] btrfs: handle ENOENT in btrfs_uuid_tree_iterate [714cd3e8cba6841220dce9063a7388a81de03825] btrfs: skip log replay on orphaned roots [9bc574de590510eff899c3ca8dbaf013566b5efe] ext4: only call ext4_truncate when size <= isize [3da40c7b089810ac9cf2bb1e59633f619f3a7312]
Jouni Malinen (1): mac80211: Do not send Layer 2 Update frame before authorization [3e493173b7841259a08c5c8e5cbe90adb349da7e]
Kaitao Cheng (1): kernel/trace: Fix do not unregister tracepoints when register sched_migrate_task fail [50f9ad607ea891a9308e67b81f774c71736d1098]
Keiya Nobuta (1): usb: core: hub: Improved device recognition on remote wakeup [9c06ac4c83df6d6fbdbf7488fbad822b4002ba19]
Kenneth Klette Jonassen (1): pkt_sched: fq: avoid hang when quantum 0 [3725a269815ba6dbb415feddc47da5af7d1fac58]
Lars Möllendorf (1): iio: buffer: align the size of scan bytes to size of the largest element [883f616530692d81cb70f8a32d85c0d2afc05f69]
Leo Yan (1): tty: serial: msm_serial: Fix lockup for sysrq and oops [0e4f7f920a5c6bfe5e851e989f27b35a0cc7fb7e]
Linus Torvalds (1): floppy: check FDC index for errors before assigning it [2e90ca68b0d2f5548804f22f0dd61145516171e3]
Liu Bo (9): Btrfs: add validadtion checks for chunk loading [e06cd3dd7cea50e87663a88acdfdb7ac1c53a5ca] Btrfs: check btree node's nritems [053ab70f0604224c7893b43f9d9d5efa283580d6] Btrfs: check inconsistence between chunk and block group [6fb37b756acce6d6e045f79c3764206033f617b4] Btrfs: detect corruption when non-root leaf has zero item [1ba98d086fe3a14d6a31f2f66dbab70c45d00f63] Btrfs: fix BUG_ON in btrfs_mark_buffer_dirty [ef85b25e982b5bba1530b936e283ef129f02ab9d] Btrfs: improve check_node to avoid reading corrupted nodes [6b722c1747d533ac6d4df110dc8233db46918b65] Btrfs: kill BUG_ON in run_delayed_tree_ref [02794222c4132ac003e7281fb71f4ec1645ffc87] Btrfs: memset to avoid stale content in btree leaf [851cd173f06045816528176001cf82948282029c] Btrfs: memset to avoid stale content in btree node block [3eb548ee3a8042d95ad81be254e67a5222c24e03]
Logan Gunthorpe (1): chardev: add helper function to register char devs with a struct device [233ed09d7fdacf592ee91e6c97ce5f4364fbe7c0]
Lu Fengqi (1): btrfs: Remove redundant btrfs_release_path from btrfs_unlink_subvol [5b7d687ad5913a56b6a8788435d7a53990b4176d]
Lukas Czerner (1): ext4: wait for existing dio workers in ext4_alloc_file_blocks() [0d306dcf86e8f065dff42a4a934ae9d99af35ba5]
Luuk Paulussen (1): hwmon: (adt7475) Make volt2reg return same reg as reg2volt input [cf3ca1877574a306c0207cbf7fdf25419d9229df]
Mao Wenan (2): af_packet: set defaule value for tmo [b43d1f9f7067c6759b1051e8ecb84e82cef569fe] net: sonic: return NETDEV_TX_OK if failed to map buffer [6e1cdedcf0362fed3aedfe051d46bd7ee2a85fe1]
Marcel Holtmann (2): HID: hidraw: Fix returning EPOLLOUT from hidraw_poll [9f3b61dc1dd7b81e99e7ed23776bb64a35f39e1a] HID: uhid: Fix returning EPOLLOUT from uhid_char_poll [be54e7461ffdc5809b67d2aeefc1ddc9a91470c7]
Mathias Nyman (2): xhci: handle some XHCI_TRUST_TX_LENGTH quirks cases as default behaviour. [7ff11162808cc2ec66353fc012c58bb449c892c3] xhci: make sure interrupts are restored to correct state [bd82873f23c9a6ad834348f8b83f3b6a5bca2c65]
Mauro Carvalho Chehab (3): [media] media-device: dynamically allocate struct media_devnode [a087ce704b802becbb4b0f2a20f2cb3f6911802e] [media] media-devnode: fix namespace mess [163f1e93e995048b894c5fc86a6034d16beed740] [media] media-devnode: just return 0 instead of using a var [8b37c6455fc8f43e0e95db2847284e618db6a4f8]
Max Kellermann (2): [media] drivers/media/media-devnode: clear private_data before put_device() [bf244f665d76d20312c80524689b32a752888838] [media] media-devnode: add missing mutex lock in error handler [88336e174645948da269e1812f138f727cd2896b]
Michael Straube (1): staging: rtl8188eu: Add device code for TP-Link TL-WN727N v5.21 [58dcc5bf4030cab548d5c98cd4cd3632a5444d5a]
Michał Mirosław (1): mmc: sdhci: fix minimum clock rate for v3 controller [2a187d03352086e300daa2044051db00044cd171]
Mika Westerberg (4): pinctrl: baytrail: Clear interrupt triggering from pins that are in GPIO mode [95f0972c7e4cbf3fc68160131c5ac2f033481d00] pinctrl: baytrail: Relax GPIO request rules [f8323b6bb2cc7d26941d4838dd4375952980a88a] pinctrl: baytrail: Rework interrupt handling [31e4329f99062a06dca5a493bb4495a63b2dc6ba] pinctrl: baytrail: Serialize all register access [39ce8150a079e3ae6ed9abf26d7918a558ef7c19]
Mike Snitzer (1): dm flakey: fix reads to be issued if drop_writes configured [299f6230bc6d0ccd5f95bb0fb865d80a9c7d5ccc]
Mikulas Patocka (1): block: fix an integer overflow in logical block size [ad6bf88a6c19a39fb3b0045d78ea880325dfcf15]
Moni Shoua (1): IB/mlx4: Avoid executing gid task when device is being removed [4bf9715f184969dc703bde7be94919995024a6a9]
Nicolai Stange (2): libertas: don't exit from lbs_ibss_join_existing() with RCU read lock held [c7bf1fb7ddca331780b9a733ae308737b39f1ad4] libertas: make lbs_ibss_join_existing() return error code on rates overflow [1754c4f60aaf1e17d886afefee97e94d7f27b4cb]
Nikos Tsironis (1): dm thin metadata: Add support for a pre-commit callback [ecda7c0280e6b3398459dc589b9a41c1adb45529]
Pablo Neira Ayuso (2): netfilter: nf_tables: missing sanitization in data from userspace [71df14b0ce094be46d105b5a3ededd83b8e779a0] netfilter: nf_tables: validate NFT_DATA_VALUE after nft_data_init() [0d2c96af797ba149e559c5875c0151384ab6dd14]
Paolo Bonzini (1): KVM: nVMX: Don't emulate instructions in guest mode [07721feee46b4b248402133228235318199b05ec]
Parav Pandit (1): IB/mlx4: Follow mirror sequence of device add during device removal [89f988d93c62384758b19323c886db917a80c371]
Paul Cercueil (1): usb: musb: dma: Correct parameter passed to IRQ handler [c80d0f4426c7fdc7efd6ae8d8b021dcfc89b4254]
Pavel Tatashin (1): x86/pti/efi: broken conversion from efi to kernel page table [not upstream; fixes a bug specific to KAISER]
Pengcheng Yang (1): tcp: fix "old stuff" D-SACK causing SACK to be treated as D-SACK [c9655008e7845bcfdaac10a1ed8554ec167aea88]
Pete Zaitcev (1): usb: mon: Fix a deadlock in usbmon between mmap and read [19e6317d24c25ee737c65d1ffb7483bdda4bb54a]
Peter Hurley (1): tty: vt: Fix !TASK_RUNNING diagnostic warning from paste_selection() [61e86cc90af49cecef9c54ccea1f572fbcb695ac]
Qize Wang (1): mwifiex: Fix heap overflow in mmwifiex_process_tdls_action_frame() [1e58252e334dc3f3756f424a157d1b7484464c40]
Qu Wenruo (14): btrfs: Add checker for EXTENT_CSUM [4b865cab96fe2a30ed512cf667b354bd291b3b0a] btrfs: Add sanity check for EXTENT_DATA when reading out leaf [40c3c40947324d9f40bf47830c92c59a9bbadf4a] btrfs: Check if item pointer overlaps with the item itself [7f43d4affb2a254d421ab20b0cf65ac2569909fb] btrfs: Check that each block group has corresponding chunk at mount time [514c7dca85a0bf40be984dab0b477403a6db901f] btrfs: Enhance chunk validation check [f04b772bfc17f502703794f4d100d12155c1a1a9] btrfs: Move leaf and node validation checker to tree-checker.c [557ea5dd003d371536f6b4e8f7c8209a2b6fd4e3] btrfs: Refactor check_leaf function for later expansion [c3267bbaa9cae09b62960eafe33ad19196803285] btrfs: Verify that every chunk has corresponding block group at mount time [7ef49515fa6727cb4b6f2f5b0ffbc5fc20a9f8c6] btrfs: tree-checker: Add checker for dir item [ad7b0368f33cffe67fecd302028915926e50ef7e] btrfs: tree-checker: Check level for leaves and nodes [f556faa46eb4e96d0d0772e74ecf66781e132f72] btrfs: tree-checker: Detect invalid and empty essential trees [ba480dd4db9f1798541eb2d1c423fc95feee8d36] btrfs: tree-checker: Enhance btrfs_check_node output [bba4f29896c986c4cec17bc0f19f2ce644fceae1] btrfs: tree-checker: Fix false panic for sanity test [69fc6cbbac542c349b3d350d10f6e394c253c81d] btrfs: tree-checker: Verify block_group_item [fce466eab7ac6baa9d2dcd88abcf945be3d4a089]
Radoslaw Tyl (1): ixgbevf: Remove limit of 10 entries for unicast filter list [aa604651d523b1493988d0bf6710339f3ee60272]
Rafael J. Wysocki (1): ACPI: PM: Avoid attaching ACPI PM domain to certain devices [b9ea0bae260f6aae546db224daa6ac1bd9d94b91]
Randy Dunlap (1): mm: mempolicy: require at least one nodeid for MPOL_PREFERRED [aa9f7d5172fac9bf1f09e678c35e287a40a7b7dd]
Richard Palethorpe (2): can, slip: Protect tty->disc_data in write_wakeup and close with RCU [0ace17d56824165c7f4c68785d6b58971db954dd] slcan: Don't transmit uninitialized stack data in padding [b9258a2cece4ec1f020715fe3554bc2e360f6264]
Russell King (2): gpiolib: fix up emulated open drain outputs [256efaea1fdc4e38970489197409a26125ee0aaa] mod_devicetable: fix PHY module format [d2ed49cf6c13e379c5819aa5ac20e1f9674ebc89]
Sabrina Dubroca (1): net: ipv6_stub: use ip6_dst_lookup_flow instead of ip6_dst_lookup [6c8991f41546c3c472503dff1ea9daaddf9331c2]
Salvatore Mesoraca (1): namei: allow restricted O_CREAT of FIFOs and regular files [30aba6656f61ed44cba445a3c0d38b296fa9e8f5]
Shaokun Zhang (1): btrfs: tree-checker: Fix misleading group system information [761333f2f50ccc887aa9957ae829300262c0d15b]
Shengjiu Wang (1): ASoC: wm8962: fix lambda value [556672d75ff486e0b6786056da624131679e0576]
Shuah Khan (3): [media] media: Fix media_open() to clear filp->private_data in error leg [d40ec6fdb0b03b7be4c7923a3da0e46bf943740a] [media] media: fix media devnode ioctl/syscall and unregister race [6f0dd24a084a17f9984dd49dffbf7055bf123993] [media] media: fix use-after-free in cdev_put() when app exits after driver unbind [5b28dde51d0ccc54cee70756e1800d70bed7114a]
Steven Rostedt (1): tracing: Have stack tracer compile when MCOUNT_INSN_SIZE is not defined [b8299d362d0837ae39e87e9019ebe6b736e0f035]
Sudip Mukherjee (2): tty: always relink the port [273f632912f1b24b642ba5b7eb5022e43a72f3b5] tty: link tty and port before configuring it as console [fb2b90014d782d80d7ebf663e50f96d8c507a73c]
Suren Baghdasaryan (1): staging: android: ashmem: Disallow ashmem memory from being remapped [6d67b0290b4b84c477e6a2fc6e005e174d3c7786]
Suwan Kim (1): usbip: Fix error path of vhci_recv_ret_submit() [aabb5b833872524eaf28f52187e5987984982264]
Sven Eckelmann (1): batman-adv: Fix DAT candidate selection on little endian systems [4cc4a1708903f404d2ca0dfde30e71e052c6cbc9]
Takashi Iwai (4): ALSA: hda/ca0132 - Avoid endless loop [cb04fc3b6b076f67d228a0b7d096c69ad486c09c] ALSA: ice1724: Fix sleep-in-atomic in Infrasonic Quartet support code [0aec96f5897ac16ad9945f531b4bef9a2edd2ebd] ALSA: pcm: Avoid possible info leaks from PCM stream buffers [add9d56d7b3781532208afbff5509d7382fb6efe] ALSA: seq: Fix racy access for queue timer in proc read [60adcfde92fa40fcb2dbf7cc52f9b096e0cd109a]
Tom Lendacky (1): x86/microcode/AMD: Add support for fam17h microcode loading [f4e9b7af0cd58dd039a0fb2cd67d57cea4889abf]
Vivek Goyal (1): dm: do not override error code returned from dm_get_device() [e80d1c805a3b2f0ad2081369be5dc5deedd5ee59]
Vladis Dronov (2): ptp: fix the race between the release of ptp_clock and cdev [a33121e5487b424339636b25c35d3a180eaa5f5e] ptp: free ptp device pin descriptors properly [75718584cb3c64e6269109d4d54f888ac5a5fd15]
Wang Shilong (1): Btrfs: fix wrong max inline data size limit [c01a5c074c0f6f85a3b02e39432b9e5576ab51de]
Wei Yongjun (1): dm flakey: return -EINVAL on interval bounds error in flakey_ctr() [bff7e067ee518f9ed7e1cbc63e4c9e01670d0b71]
Wen Huang (1): libertas: Fix two buffer overflows at parsing bss descriptor [e5e884b42639c74b5b57dc277909915c0aefc8bb]
Wen Yang (1): ftrace: Avoid potential division by zero in function profiler [e31f7939c1c27faa5d0e3f14519eaf7c89e8a69d]
Will Deacon (1): chardev: Avoid potential use-after-free in 'chrdev_open()' [68faa679b8be1a74e6663c21c3a9d25d32f1c079]
Xiang Chen (1): scsi: sd: Clear sdkp->protection_type if disk is reformatted without PI [465f4edaecc6c37f81349233e84d46246bcac11a]
Xin Long (1): sctp: free cmd->obj.chunk for the unprocessed SCTP_CMD_REPLY [be7a7729207797476b6666f046d765bdf9630407]
YueHaibing (1): ptp: Fix pass zero to ERR_PTR() in ptp_clock_register [aea0a897af9e44c258e8ab9296fad417f1bc063a]
Zhang Xiaoxu (1): vgacon: Fix a UAF in vgacon_invert_region [513dc792d6060d5ef572e43852683097a8420f56]
Documentation/sysctl/fs.txt | 36 ++++ Makefile | 4 +- arch/powerpc/kernel/irq.c | 4 +- arch/x86/boot/compressed/head_64.S | 5 + arch/x86/include/asm/kaiser.h | 10 + arch/x86/kernel/cpu/microcode/amd.c | 4 + arch/x86/kvm/cpuid.c | 3 +- arch/x86/kvm/vmx.c | 2 +- arch/x86/realmode/init.c | 4 +- arch/x86/realmode/rm/trampoline_64.S | 3 +- block/blk-settings.c | 2 +- drivers/acpi/device_pm.c | 12 +- drivers/block/floppy.c | 7 +- drivers/gpio/gpiolib.c | 13 +- drivers/hid/hid-core.c | 6 + drivers/hid/hid-input.c | 16 +- drivers/hid/hidraw.c | 7 +- drivers/hid/uhid.c | 5 +- drivers/hwmon/adt7475.c | 5 +- drivers/iio/industrialio-buffer.c | 6 +- drivers/infiniband/hw/mlx4/main.c | 16 +- drivers/input/input.c | 26 ++- drivers/input/misc/keyspan_remote.c | 9 +- drivers/input/tablet/aiptek.c | 6 +- drivers/input/tablet/gtco.c | 10 +- drivers/input/touchscreen/sur40.c | 2 +- drivers/isdn/gigaset/usb-gigaset.c | 23 ++- drivers/md/dm-crypt.c | 4 +- drivers/md/dm-delay.c | 16 +- drivers/md/dm-flakey.c | 40 ++-- drivers/md/dm-linear.c | 7 +- drivers/md/dm-raid1.c | 8 +- drivers/md/dm-snap-persistent.c | 2 +- drivers/md/dm-stripe.c | 8 +- drivers/md/dm-thin-metadata.c | 29 +++ drivers/md/dm-thin-metadata.h | 7 + drivers/md/persistent-data/dm-btree-remove.c | 8 +- drivers/md/raid0.c | 2 +- drivers/media/media-device.c | 43 +++-- drivers/media/media-devnode.c | 171 +++++++++-------- drivers/media/usb/gspca/ov519.c | 10 + drivers/media/usb/gspca/stv06xx/stv06xx.c | 19 +- drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c | 4 + drivers/media/usb/gspca/xirlink_cit.c | 18 +- drivers/media/usb/uvc/uvc_driver.c | 2 +- drivers/misc/enclosure.c | 3 +- drivers/mmc/host/sdhci.c | 10 +- drivers/net/bonding/bond_main.c | 40 ++-- drivers/net/can/mscan/mscan.c | 21 +-- drivers/net/can/slcan.c | 16 +- drivers/net/can/usb/gs_usb.c | 4 +- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 5 - drivers/net/ethernet/natsemi/sonic.c | 113 +++++++++--- drivers/net/ethernet/natsemi/sonic.h | 25 ++- drivers/net/ethernet/stmicro/stmmac/common.h | 5 +- drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +- drivers/net/hamradio/6pack.c | 4 +- drivers/net/hamradio/mkiss.c | 4 +- drivers/net/macvlan.c | 3 +- drivers/net/slip/slip.c | 12 +- drivers/net/usb/r8152.c | 3 + drivers/net/vxlan.c | 5 +- drivers/net/wireless/libertas/cfg.c | 18 +- drivers/net/wireless/mwifiex/sta_ioctl.c | 1 + drivers/net/wireless/mwifiex/tdls.c | 74 +++++++- drivers/pinctrl/pinctrl-baytrail.c | 212 +++++++++++++--------- drivers/platform/x86/asus-wmi.c | 8 +- drivers/platform/x86/hp-wmi.c | 2 +- drivers/ptp/ptp_clock.c | 42 ++--- drivers/ptp/ptp_private.h | 9 +- drivers/ptp/ptp_sysfs.c | 162 +++++++---------- drivers/scsi/fnic/vnic_dev.c | 20 +- drivers/scsi/qla4xxx/ql4_os.c | 1 - drivers/scsi/sd.c | 4 +- drivers/staging/android/ashmem.c | 28 +++ drivers/staging/rtl8188eu/os_dep/usb_intf.c | 3 +- drivers/staging/rtl8712/usb_intf.c | 2 +- drivers/staging/usbip/vhci_rx.c | 13 +- drivers/tty/serial/msm_serial.c | 13 +- drivers/tty/serial/serial_core.c | 1 + drivers/tty/vt/selection.c | 34 +++- drivers/tty/vt/vt.c | 2 - drivers/usb/atm/ueagle-atm.c | 18 +- drivers/usb/core/config.c | 77 +++++++- drivers/usb/core/hub.c | 1 + drivers/usb/core/quirks.c | 37 ++++ drivers/usb/core/urb.c | 1 + drivers/usb/core/usb.h | 3 + drivers/usb/dwc3/dwc3-pci.c | 30 +++ drivers/usb/host/ehci-q.c | 13 +- drivers/usb/host/xhci-hub.c | 8 +- drivers/usb/host/xhci-ring.c | 3 +- drivers/usb/misc/adutux.c | 2 +- drivers/usb/misc/idmouse.c | 2 +- drivers/usb/mon/mon_bin.c | 32 ++-- drivers/usb/musb/musbhsdma.c | 2 +- drivers/usb/serial/ch341.c | 6 +- drivers/usb/serial/io_edgeport.c | 26 +-- drivers/usb/serial/keyspan.c | 4 + drivers/usb/serial/opticon.c | 2 +- drivers/usb/serial/quatech2.c | 6 + drivers/usb/serial/usb-serial-simple.c | 2 + drivers/usb/serial/usb-serial.c | 3 + drivers/vhost/net.c | 13 +- drivers/video/console/vgacon.c | 3 + drivers/virtio/virtio_balloon.c | 10 + firmware/Makefile | 2 +- fs/btrfs/Makefile | 2 +- fs/btrfs/ctree.c | 19 +- fs/btrfs/ctree.h | 157 +++++++++------- fs/btrfs/dev-replace.c | 2 +- fs/btrfs/disk-io.c | 80 ++------ fs/btrfs/extent-tree.c | 110 ++++++++++- fs/btrfs/extent_io.c | 98 +++++----- fs/btrfs/extent_io.h | 25 +-- fs/btrfs/extent_map.c | 2 +- fs/btrfs/extent_map.h | 10 +- fs/btrfs/inode.c | 8 +- fs/btrfs/ioctl.c | 10 +- fs/btrfs/relocation.c | 1 + fs/btrfs/root-tree.c | 10 +- fs/btrfs/scrub.c | 2 +- fs/btrfs/struct-funcs.c | 9 +- fs/btrfs/tree-log.c | 24 ++- fs/btrfs/uuid-tree.c | 2 + fs/btrfs/volumes.c | 206 +++++++++++++++++---- fs/btrfs/volumes.h | 2 + fs/char_dev.c | 88 ++++++++- fs/ext4/dir.c | 5 + fs/ext4/ext4.h | 13 ++ fs/ext4/extents.c | 89 +++++---- fs/ext4/file.c | 2 +- fs/ext4/inode.c | 117 +++++++++--- fs/ext4/super.c | 1 + fs/ext4/truncate.h | 2 + fs/locks.c | 2 +- fs/namei.c | 56 +++++- include/linux/blkdev.h | 10 +- include/linux/blktrace_api.h | 6 +- include/linux/cdev.h | 5 + include/linux/fs.h | 2 + include/linux/if_ether.h | 8 + include/linux/kobject.h | 2 + include/linux/mod_devicetable.h | 4 +- include/linux/netfilter_arp/arp_tables.h | 2 +- include/linux/posix-clock.h | 19 +- include/linux/quotaops.h | 2 +- include/linux/usb/quirks.h | 3 + include/media/media-device.h | 5 +- include/media/media-devnode.h | 32 +++- include/net/addrconf.h | 5 +- include/net/cfg80211.h | 11 ++ include/net/neighbour.h | 1 - kernel/sysctl.c | 18 ++ kernel/taskstats.c | 30 +-- kernel/time/posix-clock.c | 31 ++-- kernel/trace/blktrace.c | 129 ++++++++----- kernel/trace/ftrace.c | 6 +- kernel/trace/trace_sched_wakeup.c | 4 +- kernel/trace/trace_stack.c | 5 + lib/kobject.c | 5 +- mm/mempolicy.c | 6 +- net/8021q/vlan_netlink.c | 10 +- net/batman-adv/distributed-arp-table.c | 4 +- net/bridge/br_netfilter.c | 3 + net/bridge/netfilter/ebtables.c | 58 +++--- net/core/neighbour.c | 3 - net/ipv4/netfilter/arp_tables.c | 42 +++-- net/ipv4/netfilter/arptable_filter.c | 2 +- net/ipv4/tcp_input.c | 5 +- net/ipv4/tcp_output.c | 8 + net/ipv6/af_inet6.c | 2 +- net/mac80211/cfg.c | 55 +----- net/mac80211/sta_info.c | 4 + net/netfilter/ipset/ip_set_bitmap_gen.h | 2 +- net/netfilter/ipset/ip_set_core.c | 3 +- net/netfilter/nf_conntrack_netlink.c | 3 + net/netfilter/nft_bitwise.c | 19 +- net/netfilter/nft_cmp.c | 18 +- net/packet/af_packet.c | 3 +- net/sched/ematch.c | 2 +- net/sched/sch_fq.c | 10 +- net/sctp/sm_sideeffect.c | 28 ++- net/wireless/util.c | 45 +++++ scripts/recordmcount.c | 17 ++ sound/core/pcm_native.c | 4 + sound/core/seq/seq_timer.c | 14 +- sound/pci/hda/patch_ca0132.c | 5 +- sound/pci/ice1712/ice1724.c | 9 +- sound/soc/codecs/wm8962.c | 4 +- sound/usb/pcm.c | 44 +++-- 192 files changed, 2624 insertions(+), 1185 deletions(-)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Brian Norris briannorris@chromium.org
commit 65b1aae0d9d5962faccc06bdb8e91a2a0b09451c upstream.
We called rcu_read_lock(), so we need to call rcu_read_unlock() before we return.
Fixes: 3d94a4a8373b ("mwifiex: fix possible heap overflow in mwifiex_process_country_ie()") Cc: huangwen huangwenabc@gmail.com Cc: Ganapathi Bhat ganapathi.bhat@nxp.com Signed-off-by: Brian Norris briannorris@chromium.org Acked-by: Ganapathi Bhat ganapathi.bhat@nxp.com Signed-off-by: Kalle Valo kvalo@codeaurora.org [bwh: Backported to 3.16: adjust filename, context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/wireless/mwifiex/sta_ioctl.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -226,6 +226,7 @@ static int mwifiex_process_country_ie(st
if (country_ie_len > (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) { + rcu_read_unlock(); wiphy_dbg(priv->wdev->wiphy, "11D: country_ie_len overflow!, deauth AP\n"); return -EINVAL;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Wen Huang huangwenabc@gmail.com
commit e5e884b42639c74b5b57dc277909915c0aefc8bb upstream.
add_ie_rates() copys rates without checking the length in bss descriptor from remote AP.when victim connects to remote attacker, this may trigger buffer overflow. lbs_ibss_join_existing() copys rates without checking the length in bss descriptor from remote IBSS node.when victim connects to remote attacker, this may trigger buffer overflow. Fix them by putting the length check before performing copy.
This fix addresses CVE-2019-14896 and CVE-2019-14897. This also fix build warning of mixed declarations and code.
Reported-by: kbuild test robot lkp@intel.com Signed-off-by: Wen Huang huangwenabc@gmail.com Signed-off-by: Kalle Valo kvalo@codeaurora.org [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/wireless/libertas/cfg.c | 8 ++++++++ 1 file changed, 8 insertions(+)
--- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -272,6 +272,10 @@ add_ie_rates(u8 *tlv, const u8 *ie, int int hw, ap, ap_max = ie[1]; u8 hw_rate;
+ if (ap_max > MAX_RATES) { + lbs_deb_assoc("invalid rates\n"); + return tlv; + } /* Advance past IE header */ ie += 2;
@@ -1785,6 +1789,9 @@ static int lbs_ibss_join_existing(struct struct cmd_ds_802_11_ad_hoc_join cmd; u8 preamble = RADIO_PREAMBLE_SHORT; int ret = 0; + int hw, i; + u8 rates_max; + u8 *rates;
lbs_deb_enter(LBS_DEB_CFG80211);
@@ -1845,9 +1852,12 @@ static int lbs_ibss_join_existing(struct if (!rates_eid) { lbs_add_rates(cmd.bss.rates); } else { - int hw, i; - u8 rates_max = rates_eid[1]; - u8 *rates = cmd.bss.rates; + rates_max = rates_eid[1]; + if (rates_max > MAX_RATES) { + lbs_deb_join("invalid rates"); + goto out; + } + rates = cmd.bss.rates; for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) { u8 hw_rate = lbs_rates[hw].bitrate / 5; for (i = 0; i < rates_max; i++) {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Nicolai Stange nstange@suse.de
commit c7bf1fb7ddca331780b9a733ae308737b39f1ad4 upstream.
Commit e5e884b42639 ("libertas: Fix two buffer overflows at parsing bss descriptor") introduced a bounds check on the number of supplied rates to lbs_ibss_join_existing().
Unfortunately, it introduced a return path from within a RCU read side critical section without a corresponding rcu_read_unlock(). Fix this.
Fixes: e5e884b42639 ("libertas: Fix two buffer overflows at parsing bss descriptor") Signed-off-by: Nicolai Stange nstange@suse.de Signed-off-by: Kalle Valo kvalo@codeaurora.org [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/wireless/libertas/cfg.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -1855,6 +1855,7 @@ static int lbs_ibss_join_existing(struct rates_max = rates_eid[1]; if (rates_max > MAX_RATES) { lbs_deb_join("invalid rates"); + rcu_read_unlock(); goto out; } rates = cmd.bss.rates;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Nicolai Stange nstange@suse.de
commit 1754c4f60aaf1e17d886afefee97e94d7f27b4cb upstream.
Commit e5e884b42639 ("libertas: Fix two buffer overflows at parsing bss descriptor") introduced a bounds check on the number of supplied rates to lbs_ibss_join_existing() and made it to return on overflow.
However, the aforementioned commit doesn't set the return value accordingly and thus, lbs_ibss_join_existing() would return with zero even though it failed.
Make lbs_ibss_join_existing return -EINVAL in case the bounds check on the number of supplied rates fails.
Fixes: e5e884b42639 ("libertas: Fix two buffer overflows at parsing bss descriptor") Signed-off-by: Nicolai Stange nstange@suse.de Signed-off-by: Kalle Valo kvalo@codeaurora.org [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/wireless/libertas/cfg.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -1856,6 +1856,7 @@ static int lbs_ibss_join_existing(struct if (rates_max > MAX_RATES) { lbs_deb_join("invalid rates"); rcu_read_unlock(); + ret = -EINVAL; goto out; } rates = cmd.bss.rates;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Avinash Patil patila@marvell.com
commit 3c99832d74777c9ec5545a92450fac5d37b0d0e1 upstream.
Size of RSN IE buffer in driver is 254 while maximum size of received buffer to be copied to RSN IE buffer can be 255. Add boundary check to copy maximum of 254 bytes into RSN IE buffer.
Reported-by: Dan Carpenter dan.carpenter@oracle.com Signed-off-by: Avinash Patil patila@marvell.com Signed-off-by: John W. Linville linville@tuxdriver.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/wireless/mwifiex/tdls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
--- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -877,7 +877,9 @@ void mwifiex_process_tdls_action_frame(s break; case WLAN_EID_RSN: memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos, - sizeof(struct ieee_types_header) + pos[1]); + sizeof(struct ieee_types_header) + + min_t(u8, pos[1], IEEE_MAX_IE_SIZE - + sizeof(struct ieee_types_header))); break; case WLAN_EID_QOS_CAPA: sta_ptr->tdls_cap.qos_info = pos[2];
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: qize wang wangqize888888888@gmail.com
commit 1e58252e334dc3f3756f424a157d1b7484464c40 upstream.
mwifiex_process_tdls_action_frame() without checking the incoming tdls infomation element's vality before use it, this may cause multi heap buffer overflows.
Fix them by putting vality check before use it.
IE is TLV struct, but ht_cap and ht_oper aren’t TLV struct. the origin marvell driver code is wrong:
memcpy(&sta_ptr->tdls_cap.ht_oper, pos,.... memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos,...
Fix the bug by changing pos(the address of IE) to pos+2 ( the address of IE value ).
Signed-off-by: qize wang wangqize888888888@gmail.com Signed-off-by: Kalle Valo kvalo@codeaurora.org [bwh: Backported to 3.16: adjust filename, context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/wireless/mwifiex/tdls.c | 70 +++++++++++++++++++-- 1 file changed, 64 insertions(+), 6 deletions(-)
--- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -847,59 +847,117 @@ void mwifiex_process_tdls_action_frame(s
switch (*pos) { case WLAN_EID_SUPP_RATES: + if (pos[1] > 32) + return; sta_ptr->tdls_cap.rates_len = pos[1]; for (i = 0; i < pos[1]; i++) sta_ptr->tdls_cap.rates[i] = pos[i + 2]; break;
case WLAN_EID_EXT_SUPP_RATES: + if (pos[1] > 32) + return; basic = sta_ptr->tdls_cap.rates_len; + if (pos[1] > 32 - basic) + return; for (i = 0; i < pos[1]; i++) sta_ptr->tdls_cap.rates[basic + i] = pos[i + 2]; sta_ptr->tdls_cap.rates_len += pos[1]; break; case WLAN_EID_HT_CAPABILITY: - memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos, + if (pos > end - sizeof(struct ieee80211_ht_cap) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_ht_cap)) + return; + /* copy the ie's value into ht_capb*/ + memcpy((u8 *)&sta_ptr->tdls_cap.ht_capb, pos + 2, sizeof(struct ieee80211_ht_cap)); sta_ptr->is_11n_enabled = 1; break; case WLAN_EID_HT_OPERATION: - memcpy(&sta_ptr->tdls_cap.ht_oper, pos, + if (pos > end - + sizeof(struct ieee80211_ht_operation) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_ht_operation)) + return; + /* copy the ie's value into ht_oper*/ + memcpy(&sta_ptr->tdls_cap.ht_oper, pos + 2, sizeof(struct ieee80211_ht_operation)); break; case WLAN_EID_BSS_COEX_2040: + if (pos > end - 3) + return; + if (pos[1] != 1) + return; sta_ptr->tdls_cap.coex_2040 = pos[2]; break; case WLAN_EID_EXT_CAPABILITY: + if (pos > end - sizeof(struct ieee_types_header)) + return; + if (pos[1] < sizeof(struct ieee_types_header)) + return; + if (pos[1] > 8) + return; memcpy((u8 *)&sta_ptr->tdls_cap.extcap, pos, sizeof(struct ieee_types_header) + min_t(u8, pos[1], 8)); break; case WLAN_EID_RSN: + if (pos > end - sizeof(struct ieee_types_header)) + return; + if (pos[1] < sizeof(struct ieee_types_header)) + return; + if (pos[1] > IEEE_MAX_IE_SIZE - + sizeof(struct ieee_types_header)) + return; memcpy((u8 *)&sta_ptr->tdls_cap.rsn_ie, pos, sizeof(struct ieee_types_header) + min_t(u8, pos[1], IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header))); break; case WLAN_EID_QOS_CAPA: + if (pos > end - 3) + return; + if (pos[1] != 1) + return; sta_ptr->tdls_cap.qos_info = pos[2]; break; case WLAN_EID_VHT_OPERATION: - if (priv->adapter->is_hw_11ac_capable) - memcpy(&sta_ptr->tdls_cap.vhtoper, pos, + if (priv->adapter->is_hw_11ac_capable) { + if (pos > end - + sizeof(struct ieee80211_vht_operation) - 2) + return; + if (pos[1] != + sizeof(struct ieee80211_vht_operation)) + return; + /* copy the ie's value into vhtoper*/ + memcpy(&sta_ptr->tdls_cap.vhtoper, pos + 2, sizeof(struct ieee80211_vht_operation)); + } break; case WLAN_EID_VHT_CAPABILITY: if (priv->adapter->is_hw_11ac_capable) { - memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos, + if (pos > end - + sizeof(struct ieee80211_vht_cap) - 2) + return; + if (pos[1] != sizeof(struct ieee80211_vht_cap)) + return; + /* copy the ie's value into vhtcap*/ + memcpy((u8 *)&sta_ptr->tdls_cap.vhtcap, pos + 2, sizeof(struct ieee80211_vht_cap)); sta_ptr->is_11ac_enabled = 1; } break; case WLAN_EID_AID: - if (priv->adapter->is_hw_11ac_capable) + if (priv->adapter->is_hw_11ac_capable) { + if (pos > end - 4) + return; + if (pos[1] != 2) + return; sta_ptr->tdls_cap.aid = le16_to_cpu(*(__le16 *)(pos + 2)); + } + break; default: break; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dedy Lansky dlansky@codeaurora.org
commit 30ca1aa536211f5ac3de0173513a7a99a98a97f3 upstream.
Make ieee80211_send_layer2_update() a common function so other drivers can re-use it.
Signed-off-by: Dedy Lansky dlansky@codeaurora.org Signed-off-by: Johannes Berg johannes.berg@intel.com [bwh: Backported to 3.16 as dependency of commit 3e493173b784 "mac80211: Do not send Layer 2 Update frame before authorization": - Retain type-casting of skb_put() return value - Adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- include/net/cfg80211.h | 11 ++++++++++ net/mac80211/cfg.c | 48 ++---------------------------------------- net/wireless/util.c | 45 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 46 deletions(-)
--- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3627,6 +3627,17 @@ const u8 *cfg80211_find_vendor_ie(unsign const u8 *ies, int len);
/** + * cfg80211_send_layer2_update - send layer 2 update frame + * + * @dev: network device + * @addr: STA MAC address + * + * Wireless drivers can use this function to update forwarding tables in bridge + * devices upon STA association. + */ +void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr); + +/** * DOC: Regulatory enforcement infrastructure * * TODO --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1196,50 +1196,6 @@ static int ieee80211_stop_ap(struct wiph return 0; }
-/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ -struct iapp_layer2_update { - u8 da[ETH_ALEN]; /* broadcast */ - u8 sa[ETH_ALEN]; /* STA addr */ - __be16 len; /* 6 */ - u8 dsap; /* 0 */ - u8 ssap; /* 0 */ - u8 control; - u8 xid_info[3]; -} __packed; - -static void ieee80211_send_layer2_update(struct sta_info *sta) -{ - struct iapp_layer2_update *msg; - struct sk_buff *skb; - - /* Send Level 2 Update Frame to update forwarding tables in layer 2 - * bridge devices */ - - skb = dev_alloc_skb(sizeof(*msg)); - if (!skb) - return; - msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg)); - - /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) - * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ - - eth_broadcast_addr(msg->da); - memcpy(msg->sa, sta->sta.addr, ETH_ALEN); - msg->len = htons(6); - msg->dsap = 0; - msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ - msg->control = 0xaf; /* XID response lsb.1111F101. - * F=0 (no poll command; unsolicited frame) */ - msg->xid_info[0] = 0x81; /* XID format identifier */ - msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ - msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ - - skb->dev = sta->sdata->dev; - skb->protocol = eth_type_trans(skb, sta->sdata->dev); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx_ni(skb); -} - static int sta_apply_auth_flags(struct ieee80211_local *local, struct sta_info *sta, u32 mask, u32 set) @@ -1535,7 +1491,7 @@ static int ieee80211_add_station(struct }
if (layer2_update) - ieee80211_send_layer2_update(sta); + cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr);
rcu_read_unlock();
@@ -1640,7 +1596,7 @@ static int ieee80211_change_station(stru atomic_inc(&sta->sdata->bss->num_mcast_sta); }
- ieee80211_send_layer2_update(sta); + cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr); }
err = sta_apply_parameters(local, sta, params); --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -1583,3 +1583,48 @@ EXPORT_SYMBOL(rfc1042_header); const unsigned char bridge_tunnel_header[] __aligned(2) = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; EXPORT_SYMBOL(bridge_tunnel_header); + +/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ +struct iapp_layer2_update { + u8 da[ETH_ALEN]; /* broadcast */ + u8 sa[ETH_ALEN]; /* STA addr */ + __be16 len; /* 6 */ + u8 dsap; /* 0 */ + u8 ssap; /* 0 */ + u8 control; + u8 xid_info[3]; +} __packed; + +void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr) +{ + struct iapp_layer2_update *msg; + struct sk_buff *skb; + + /* Send Level 2 Update Frame to update forwarding tables in layer 2 + * bridge devices */ + + skb = dev_alloc_skb(sizeof(*msg)); + if (!skb) + return; + msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg)); + + /* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID) + * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ + + eth_broadcast_addr(msg->da); + ether_addr_copy(msg->sa, addr); + msg->len = htons(6); + msg->dsap = 0; + msg->ssap = 0x01; /* NULL LSAP, CR Bit: Response */ + msg->control = 0xaf; /* XID response lsb.1111F101. + * F=0 (no poll command; unsolicited frame) */ + msg->xid_info[0] = 0x81; /* XID format identifier */ + msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ + msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + memset(skb->cb, 0, sizeof(skb->cb)); + netif_rx_ni(skb); +} +EXPORT_SYMBOL(cfg80211_send_layer2_update);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jouni Malinen jouni@codeaurora.org
commit 3e493173b7841259a08c5c8e5cbe90adb349da7e upstream.
The Layer 2 Update frame is used to update bridges when a station roams to another AP even if that STA does not transmit any frames after the reassociation. This behavior was described in IEEE Std 802.11F-2003 as something that would happen based on MLME-ASSOCIATE.indication, i.e., before completing 4-way handshake. However, this IEEE trial-use recommended practice document was published before RSN (IEEE Std 802.11i-2004) and as such, did not consider RSN use cases. Furthermore, IEEE Std 802.11F-2003 was withdrawn in 2006 and as such, has not been maintained amd should not be used anymore.
Sending out the Layer 2 Update frame immediately after association is fine for open networks (and also when using SAE, FT protocol, or FILS authentication when the station is actually authenticated by the time association completes). However, it is not appropriate for cases where RSN is used with PSK or EAP authentication since the station is actually fully authenticated only once the 4-way handshake completes after authentication and attackers might be able to use the unauthenticated triggering of Layer 2 Update frame transmission to disrupt bridge behavior.
Fix this by postponing transmission of the Layer 2 Update frame from station entry addition to the point when the station entry is marked authorized. Similarly, send out the VLAN binding update only if the STA entry has already been authorized.
Signed-off-by: Jouni Malinen jouni@codeaurora.org Reviewed-by: Johannes Berg johannes@sipsolutions.net Signed-off-by: David S. Miller davem@davemloft.net [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/mac80211/cfg.c | 11 +++-------- net/mac80211/sta_info.c | 4 ++++ 2 files changed, 7 insertions(+), 8 deletions(-)
--- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1436,7 +1436,6 @@ static int ieee80211_add_station(struct struct sta_info *sta; struct ieee80211_sub_if_data *sdata; int err; - int layer2_update;
if (params->vlan) { sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); @@ -1481,18 +1480,12 @@ static int ieee80211_add_station(struct if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) rate_control_rate_init(sta);
- layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || - sdata->vif.type == NL80211_IFTYPE_AP; - err = sta_info_insert_rcu(sta); if (err) { rcu_read_unlock(); return err; }
- if (layer2_update) - cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr); - rcu_read_unlock();
return 0; @@ -1596,7 +1589,9 @@ static int ieee80211_change_station(stru atomic_inc(&sta->sdata->bss->num_mcast_sta); }
- cfg80211_send_layer2_update(sta->sdata->dev, sta->sta.addr); + if (sta->sta_state == IEEE80211_STA_AUTHORIZED) + cfg80211_send_layer2_update(sta->sdata->dev, + sta->sta.addr); }
err = sta_apply_parameters(local, sta, params); --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -1666,6 +1666,10 @@ int sta_info_move_state(struct sta_info atomic_inc(&sta->sdata->bss->num_mcast_sta); set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); } + if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN || + sta->sdata->vif.type == NL80211_IFTYPE_AP) + cfg80211_send_layer2_update(sta->sdata->dev, + sta->sta.addr); break; default: break;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Tom Lendacky thomas.lendacky@amd.com
commit f4e9b7af0cd58dd039a0fb2cd67d57cea4889abf upstream.
The size for the Microcode Patch Block (MPB) for an AMD family 17h processor is 3200 bytes. Add a #define for fam17h so that it does not default to 2048 bytes and fail a microcode load/update.
Signed-off-by: Tom Lendacky thomas.lendacky@amd.com Signed-off-by: Thomas Gleixner tglx@linutronix.de Reviewed-by: Borislav Petkov bp@alien8.de Link: https://lkml.kernel.org/r/20171130224640.15391.40247.stgit@tlendack-t1.amdof... Signed-off-by: Ingo Molnar mingo@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- arch/x86/kernel/cpu/microcode/amd.c | 4 ++++ 1 file changed, 4 insertions(+)
--- a/arch/x86/kernel/cpu/microcode/amd.c +++ b/arch/x86/kernel/cpu/microcode/amd.c @@ -154,6 +154,7 @@ static unsigned int verify_patch_size(u8 #define F14H_MPB_MAX_SIZE 1824 #define F15H_MPB_MAX_SIZE 4096 #define F16H_MPB_MAX_SIZE 3458 +#define F17H_MPB_MAX_SIZE 3200
switch (family) { case 0x14: @@ -165,6 +166,9 @@ static unsigned int verify_patch_size(u8 case 0x16: max_size = F16H_MPB_MAX_SIZE; break; + case 0x17: + max_size = F17H_MPB_MAX_SIZE; + break; default: max_size = F1XH_MPB_MAX_SIZE; break;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Lukas Czerner lczerner@redhat.com
commit 0d306dcf86e8f065dff42a4a934ae9d99af35ba5 upstream.
Currently existing dio workers can jump in and potentially increase extent tree depth while we're allocating blocks in ext4_alloc_file_blocks(). This may cause us to underestimate the number of credits needed for the transaction because the extent tree depth can change after our estimation.
Fix this by waiting for all the existing dio workers in the same way as we do it in ext4_punch_hole. We've seen errors caused by this in xfstest generic/299, however it's really hard to reproduce.
Signed-off-by: Lukas Czerner lczerner@redhat.com Signed-off-by: Theodore Ts'o tytso@mit.edu Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/ext4/extents.c | 6 ++++++ 1 file changed, 6 insertions(+)
--- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4707,6 +4707,10 @@ static int ext4_alloc_file_blocks(struct if (len <= EXT_UNWRITTEN_MAX_LEN) flags |= EXT4_GET_BLOCKS_NO_NORMALIZE;
+ /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); + /* * credits to insert 1 extent into extent tree */ @@ -4756,6 +4760,8 @@ retry: goto retry; }
+ ext4_inode_resume_unlocked_dio(inode); + return ret > 0 ? ret2 : ret; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik jbacik@fb.com
commit 3da40c7b089810ac9cf2bb1e59633f619f3a7312 upstream.
At LSF we decided that if we truncate up from isize we shouldn't trim fallocated blocks that were fallocated with KEEP_SIZE and are past the new i_size. This patch fixes ext4 to do this.
[ Completely reworked patch so that i_disksize would actually get set when truncating up. Also reworked the code for handling truncate so that it's easier to handle. -- tytso ]
Signed-off-by: Josef Bacik jbacik@fb.com Signed-off-by: Theodore Ts'o tytso@mit.edu Reviewed-by: Lukas Czerner lczerner@redhat.com [bwh: Backported to 3.16 as dependency of commit ea3d7209ca01 "ext4: fix races between page faults and hole punching": - Adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/ext4/inode.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-)
--- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4809,8 +4809,10 @@ int ext4_setattr(struct dentry *dentry, ext4_journal_stop(handle); }
- if (attr->ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) { + if (attr->ia_valid & ATTR_SIZE) { handle_t *handle; + loff_t oldsize = inode->i_size; + int shrink = (attr->ia_size <= inode->i_size);
if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); @@ -4818,24 +4820,26 @@ int ext4_setattr(struct dentry *dentry, if (attr->ia_size > sbi->s_bitmap_maxbytes) return -EFBIG; } + if (!S_ISREG(inode->i_mode)) + return -EINVAL;
if (IS_I_VERSION(inode) && attr->ia_size != inode->i_size) inode_inc_iversion(inode);
- if (S_ISREG(inode->i_mode) && + if (ext4_should_order_data(inode) && (attr->ia_size < inode->i_size)) { - if (ext4_should_order_data(inode)) { - error = ext4_begin_ordered_truncate(inode, + error = ext4_begin_ordered_truncate(inode, attr->ia_size); - if (error) - goto err_out; - } + if (error) + goto err_out; + } + if (attr->ia_size != inode->i_size) { handle = ext4_journal_start(inode, EXT4_HT_INODE, 3); if (IS_ERR(handle)) { error = PTR_ERR(handle); goto err_out; } - if (ext4_handle_valid(handle)) { + if (ext4_handle_valid(handle) && shrink) { error = ext4_orphan_add(handle, inode); orphan = 1; } @@ -4854,15 +4858,13 @@ int ext4_setattr(struct dentry *dentry, up_write(&EXT4_I(inode)->i_data_sem); ext4_journal_stop(handle); if (error) { - ext4_orphan_del(NULL, inode); + if (orphan) + ext4_orphan_del(NULL, inode); goto err_out; } - } else { - loff_t oldsize = inode->i_size; - - i_size_write(inode, attr->ia_size); - pagecache_isize_extended(inode, oldsize, inode->i_size); } + if (!shrink) + pagecache_isize_extended(inode, oldsize, inode->i_size);
/* * Blocks are going to be removed from the inode. Wait @@ -4882,13 +4884,9 @@ int ext4_setattr(struct dentry *dentry, * in data=journal mode to make pages freeable. */ truncate_pagecache(inode, inode->i_size); + if (shrink) + ext4_truncate(inode); } - /* - * We want to call ext4_truncate() even if attr->ia_size == - * inode->i_size for cases like truncation of fallocated space - */ - if (attr->ia_valid & ATTR_SIZE) - ext4_truncate(inode);
if (!rc) { setattr_copy(inode, attr);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eryu Guan guaneryu@gmail.com
commit 911af577de4e444622d46500c1f9a37ab4335d3a upstream.
Commit 3da40c7b0898 ("ext4: only call ext4_truncate when size <= isize") introduced a bug that c/mtime is not updated on truncate up.
Fix the issue by setting c/mtime explicitly in the truncate up case.
Note that ftruncate(2) is not affected, so you won't see this bug using truncate(1) and xfs_io(1).
Signed-off-by: Zirong Lang zorro.lang@gmail.com Signed-off-by: Eryu Guan guaneryu@gmail.com Signed-off-by: Theodore Ts'o tytso@mit.edu Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/ext4/inode.c | 8 ++++++++ 1 file changed, 8 insertions(+)
--- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4843,6 +4843,14 @@ int ext4_setattr(struct dentry *dentry, error = ext4_orphan_add(handle, inode); orphan = 1; } + /* + * Update c/mtime on truncate up, ext4_truncate() will + * update c/mtime in shrink case below + */ + if (!shrink) { + inode->i_mtime = ext4_current_time(inode); + inode->i_ctime = inode->i_mtime; + } down_write(&EXT4_I(inode)->i_data_sem); EXT4_I(inode)->i_disksize = attr->ia_size; rc = ext4_mark_inode_dirty(handle, inode);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Chao Yu yuchao0@huawei.com
commit 6565c182094f69e4ffdece337d395eb7ec760efc upstream.
Quoted from commit 3da40c7b0898 ("ext4: only call ext4_truncate when size <= isize")
" At LSF we decided that if we truncate up from isize we shouldn't trim fallocated blocks that were fallocated with KEEP_SIZE and are past the new i_size. This patch fixes ext4 to do this. "
And generic/092 of fstest have covered this case for long time, however is_quota_modification() didn't adjust based on that rule, so that in below condition, we will lose to quota block change: - fallocate blocks beyond EOF - remount - truncate(file_path, file_size)
Fix it.
Link: https://lore.kernel.org/r/20190911093650.35329-1-yuchao0@huawei.com Fixes: 3da40c7b0898 ("ext4: only call ext4_truncate when size <= isize") Signed-off-by: Chao Yu yuchao0@huawei.com Signed-off-by: Jan Kara jack@suse.cz Signed-off-by: Ben Hutchings ben@decadent.org.uk --- include/linux/quotaops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -21,7 +21,7 @@ static inline struct quota_info *sb_dqop /* i_mutex must being held */ static inline bool is_quota_modification(struct inode *inode, struct iattr *ia) { - return (ia->ia_valid & ATTR_SIZE && ia->ia_size != inode->i_size) || + return (ia->ia_valid & ATTR_SIZE) || (ia->ia_valid & ATTR_UID && !uid_eq(ia->ia_uid, inode->i_uid)) || (ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid)); }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara jack@suse.com
commit ea3d7209ca01da209cda6f0dea8be9cc4b7a933b upstream.
Currently, page faults and hole punching are completely unsynchronized. This can result in page fault faulting in a page into a range that we are punching after truncate_pagecache_range() has been called and thus we can end up with a page mapped to disk blocks that will be shortly freed. Filesystem corruption will shortly follow. Note that the same race is avoided for truncate by checking page fault offset against i_size but there isn't similar mechanism available for punching holes.
Fix the problem by creating new rw semaphore i_mmap_sem in inode and grab it for writing over truncate, hole punching, and other functions removing blocks from extent tree and for read over page faults. We cannot easily use i_data_sem for this since that ranks below transaction start and we need something ranking above it so that it can be held over the whole truncate / hole punching operation. Also remove various workarounds we had in the code to reduce race window when page fault could have created pages with stale mapping information.
Signed-off-by: Jan Kara jack@suse.com Signed-off-by: Theodore Ts'o tytso@mit.edu [bwh: Backported to 3.16: - Drop changes in ext4_insert_range(), ext4_dax_* - Adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -937,6 +937,15 @@ struct ext4_inode_info { * by other means, so we have i_data_sem. */ struct rw_semaphore i_data_sem; + /* + * i_mmap_sem is for serializing page faults with truncate / punch hole + * operations. We have to make sure that new page cannot be faulted in + * a section of the inode that is being punched. We cannot easily use + * i_data_sem for this since we need protection for the whole punch + * operation and i_data_sem ranks below transaction start so we have + * to occasionally drop it. + */ + struct rw_semaphore i_mmap_sem; struct inode vfs_inode; struct jbd2_inode *jinode;
@@ -2205,6 +2214,7 @@ extern int ext4_chunk_trans_blocks(struc extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode, loff_t lstart, loff_t lend); extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); +extern int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf); extern qsize_t *ext4_get_reserved_space(struct inode *inode); extern void ext4_da_update_reserve_space(struct inode *inode, int used, int quota_claim); --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4778,7 +4778,6 @@ static long ext4_zero_range(struct file int partial_begin, partial_end; loff_t start, end; ext4_lblk_t lblk; - struct address_space *mapping = inode->i_mapping; unsigned int blkbits = inode->i_blkbits;
trace_ext4_zero_range(inode, offset, len, mode); @@ -4794,17 +4793,6 @@ static long ext4_zero_range(struct file }
/* - * Write out all dirty pages to avoid race conditions - * Then release them. - */ - if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { - ret = filemap_write_and_wait_range(mapping, offset, - offset + len - 1); - if (ret) - return ret; - } - - /* * Round up offset. This is not fallocate, we neet to zero out * blocks, so convert interior block aligned part of the range to * unwritten and possibly manually zero out unaligned parts of the @@ -4865,16 +4853,22 @@ static long ext4_zero_range(struct file flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN | EXT4_EX_NOCACHE);
- /* Now release the pages and zero block aligned part of pages*/ - truncate_pagecache_range(inode, start, end - 1); - inode->i_mtime = inode->i_ctime = ext4_current_time(inode); - /* Wait all existing dio workers, newcomers will block on i_mutex */ ext4_inode_block_unlocked_dio(inode); inode_dio_wait(inode);
+ /* + * Prevent page faults from reinstantiating pages we have + * released from page cache. + */ + down_write(&EXT4_I(inode)->i_mmap_sem); + /* Now release the pages and zero block aligned part of pages */ + truncate_pagecache_range(inode, start, end - 1); + inode->i_mtime = inode->i_ctime = ext4_current_time(inode); + ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags, mode); + up_write(&EXT4_I(inode)->i_mmap_sem); if (ret) goto out_dio; } @@ -5490,17 +5484,22 @@ int ext4_collapse_range(struct inode *in goto out_mutex; }
- truncate_pagecache(inode, ioffset); - /* Wait for existing dio to complete */ ext4_inode_block_unlocked_dio(inode); inode_dio_wait(inode);
+ /* + * Prevent page faults from reinstantiating pages we have released from + * page cache. + */ + down_write(&EXT4_I(inode)->i_mmap_sem); + truncate_pagecache(inode, ioffset); + credits = ext4_writepage_trans_blocks(inode); handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits); if (IS_ERR(handle)) { ret = PTR_ERR(handle); - goto out_dio; + goto out_mmap; }
down_write(&EXT4_I(inode)->i_data_sem); @@ -5540,7 +5539,8 @@ int ext4_collapse_range(struct inode *in
out_stop: ext4_journal_stop(handle); -out_dio: +out_mmap: + up_write(&EXT4_I(inode)->i_mmap_sem); ext4_inode_resume_unlocked_dio(inode); out_mutex: mutex_unlock(&inode->i_mutex); --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -199,7 +199,7 @@ errout: }
static const struct vm_operations_struct ext4_file_vm_ops = { - .fault = filemap_fault, + .fault = ext4_filemap_fault, .map_pages = filemap_map_pages, .page_mkwrite = ext4_page_mkwrite, }; --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3716,6 +3716,15 @@ int ext4_punch_hole(struct inode *inode,
}
+ /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); + + /* + * Prevent page faults from reinstantiating pages we have released from + * page cache. + */ + down_write(&EXT4_I(inode)->i_mmap_sem); first_block_offset = round_up(offset, sb->s_blocksize); last_block_offset = round_down((offset + length), sb->s_blocksize) - 1;
@@ -3724,10 +3733,6 @@ int ext4_punch_hole(struct inode *inode, truncate_pagecache_range(inode, first_block_offset, last_block_offset);
- /* Wait all existing dio workers, newcomers will block on i_mutex */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) credits = ext4_writepage_trans_blocks(inode); else @@ -3773,11 +3778,6 @@ int ext4_punch_hole(struct inode *inode, if (IS_SYNC(inode)) ext4_handle_sync(handle);
- /* Now release the pages again to reduce race window */ - if (last_block_offset > first_block_offset) - truncate_pagecache_range(inode, first_block_offset, - last_block_offset); - inode->i_mtime = inode->i_ctime = ext4_current_time(inode); ext4_mark_inode_dirty(handle, inode); if (ret >= 0) @@ -3785,6 +3785,7 @@ int ext4_punch_hole(struct inode *inode, out_stop: ext4_journal_stop(handle); out_dio: + up_write(&EXT4_I(inode)->i_mmap_sem); ext4_inode_resume_unlocked_dio(inode); out_mutex: mutex_unlock(&inode->i_mutex); @@ -4879,6 +4880,7 @@ int ext4_setattr(struct dentry *dentry, } else ext4_wait_for_tail_page_commit(inode); } + down_write(&EXT4_I(inode)->i_mmap_sem); /* * Truncate pagecache after we've waited for commit * in data=journal mode to make pages freeable. @@ -4886,6 +4888,7 @@ int ext4_setattr(struct dentry *dentry, truncate_pagecache(inode, inode->i_size); if (shrink) ext4_truncate(inode); + up_write(&EXT4_I(inode)->i_mmap_sem); }
if (!rc) { @@ -5338,6 +5341,8 @@ int ext4_page_mkwrite(struct vm_area_str sb_start_pagefault(inode->i_sb); file_update_time(vma->vm_file);
+ down_read(&EXT4_I(inode)->i_mmap_sem); + ret = ext4_convert_inline_data(inode); if (ret) goto out_ret; @@ -5411,6 +5416,19 @@ retry_alloc: out_ret: ret = block_page_mkwrite_return(ret); out: + up_read(&EXT4_I(inode)->i_mmap_sem); sb_end_pagefault(inode->i_sb); return ret; } + +int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct inode *inode = file_inode(vma->vm_file); + int err; + + down_read(&EXT4_I(inode)->i_mmap_sem); + err = filemap_fault(vma, vmf); + up_read(&EXT4_I(inode)->i_mmap_sem); + + return err; +} --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -967,6 +967,7 @@ static void init_once(void *foo) INIT_LIST_HEAD(&ei->i_orphan); init_rwsem(&ei->xattr_sem); init_rwsem(&ei->i_data_sem); + init_rwsem(&ei->i_mmap_sem); inode_init_once(&ei->vfs_inode); }
--- a/fs/ext4/truncate.h +++ b/fs/ext4/truncate.h @@ -10,8 +10,10 @@ */ static inline void ext4_truncate_failed_write(struct inode *inode) { + down_write(&EXT4_I(inode)->i_mmap_sem); truncate_inode_pages(inode->i_mapping, inode->i_size); ext4_truncate(inode); + up_write(&EXT4_I(inode)->i_mmap_sem); }
/*
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara jack@suse.com
commit 17048e8a083fec7ad841d88ef0812707fbc7e39f upstream.
Currently ext4_alloc_file_blocks() was handling protection against unlocked DIO. However we now need to sometimes call it under i_mmap_sem and sometimes not and DIO protection ranks above it (although strictly speaking this cannot currently create any deadlocks). Also ext4_zero_range() was actually getting & releasing unlocked DIO protection twice in some cases. Luckily it didn't introduce any real bug but it was a land mine waiting to be stepped on. So move DIO protection out from ext4_alloc_file_blocks() into the two callsites.
Signed-off-by: Jan Kara jack@suse.com Signed-off-by: Theodore Ts'o tytso@mit.edu Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/ext4/extents.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-)
--- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4707,10 +4707,6 @@ static int ext4_alloc_file_blocks(struct if (len <= EXT_UNWRITTEN_MAX_LEN) flags |= EXT4_GET_BLOCKS_NO_NORMALIZE;
- /* Wait all existing dio workers, newcomers will block on i_mutex */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - /* * credits to insert 1 extent into extent tree */ @@ -4760,8 +4756,6 @@ retry: goto retry; }
- ext4_inode_resume_unlocked_dio(inode); - return ret > 0 ? ret2 : ret; }
@@ -4836,6 +4830,10 @@ static long ext4_zero_range(struct file if (mode & FALLOC_FL_KEEP_SIZE) flags |= EXT4_GET_BLOCKS_KEEP_SIZE;
+ /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); + /* Preallocate the range including the unaligned edges */ if (partial_begin || partial_end) { ret = ext4_alloc_file_blocks(file, @@ -4844,7 +4842,7 @@ static long ext4_zero_range(struct file round_down(offset, 1 << blkbits)) >> blkbits, new_size, flags, mode); if (ret) - goto out_mutex; + goto out_dio;
}
@@ -4853,10 +4851,6 @@ static long ext4_zero_range(struct file flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN | EXT4_EX_NOCACHE);
- /* Wait all existing dio workers, newcomers will block on i_mutex */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - /* * Prevent page faults from reinstantiating pages we have * released from page cache. @@ -4985,8 +4979,13 @@ long ext4_fallocate(struct file *file, i goto out; }
+ /* Wait all existing dio workers, newcomers will block on i_mutex */ + ext4_inode_block_unlocked_dio(inode); + inode_dio_wait(inode); + ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags, mode); + ext4_inode_resume_unlocked_dio(inode); if (ret) goto out;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara jack@suse.com
commit 32ebffd3bbb4162da5ff88f9a35dd32d0a28ea70 upstream.
Current code implementing FALLOC_FL_COLLAPSE_RANGE and FALLOC_FL_INSERT_RANGE is prone to races with buffered writes and page faults. If buffered write or write via mmap manages to squeeze between filemap_write_and_wait_range() and truncate_pagecache() in the fallocate implementations, the written data is simply discarded by truncate_pagecache() although it should have been shifted.
Fix the problem by moving filemap_write_and_wait_range() call inside i_mutex and i_mmap_sem. That way we are protected against races with both buffered writes and page faults.
Signed-off-by: Jan Kara jack@suse.com Signed-off-by: Theodore Ts'o tytso@mit.edu [bwh: Backported to 3.16: drop changes in ext4_insert_range()] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -5453,21 +5453,7 @@ int ext4_collapse_range(struct inode *in return ret; }
- /* - * Need to round down offset to be aligned with page size boundary - * for page size > block size. - */ - ioffset = round_down(offset, PAGE_SIZE); - - /* Write out all dirty pages */ - ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, - LLONG_MAX); - if (ret) - return ret; - - /* Take mutex lock */ mutex_lock(&inode->i_mutex); - /* * There is no need to overlap collapse range with EOF, in which case * it is effectively a truncate operation @@ -5492,6 +5478,27 @@ int ext4_collapse_range(struct inode *in * page cache. */ down_write(&EXT4_I(inode)->i_mmap_sem); + /* + * Need to round down offset to be aligned with page size boundary + * for page size > block size. + */ + ioffset = round_down(offset, PAGE_SIZE); + /* + * Write tail of the last page before removed range since it will get + * removed from the page cache below. + */ + ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, offset); + if (ret) + goto out_mmap; + /* + * Write data that will be shifted to preserve them when discarding + * page cache below. We are also protected from pages becoming dirty + * by i_mmap_sem. + */ + ret = filemap_write_and_wait_range(inode->i_mapping, offset + len, + LLONG_MAX); + if (ret) + goto out_mmap; truncate_pagecache(inode, ioffset);
credits = ext4_writepage_trans_blocks(inode);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara jack@suse.com
commit 011278485ecc3cd2a3954b5d4c73101d919bf1fa upstream.
When doing delayed allocation, update of on-disk inode size is postponed until IO submission time. However hole punch or zero range fallocate calls can end up discarding the tail page cache page and thus on-disk inode size would never be properly updated.
Make sure the on-disk inode size is updated before truncating page cache.
Signed-off-by: Jan Kara jack@suse.com Signed-off-by: Theodore Ts'o tytso@mit.edu Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/ext4/ext4.h | 3 +++ fs/ext4/extents.c | 5 +++++ fs/ext4/inode.c | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-)
--- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2560,6 +2560,9 @@ static inline int ext4_update_inode_size return changed; }
+int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, + loff_t len); + struct ext4_group_info { unsigned long bb_state; struct rb_root bb_free_root; --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -4856,6 +4856,11 @@ static long ext4_zero_range(struct file * released from page cache. */ down_write(&EXT4_I(inode)->i_mmap_sem); + ret = ext4_update_disksize_before_punch(inode, offset, len); + if (ret) { + up_write(&EXT4_I(inode)->i_mmap_sem); + goto out_dio; + } /* Now release the pages and zero block aligned part of pages */ truncate_pagecache_range(inode, start, end - 1); inode->i_mtime = inode->i_ctime = ext4_current_time(inode); --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3652,6 +3652,35 @@ int ext4_can_truncate(struct inode *inod }
/* + * We have to make sure i_disksize gets properly updated before we truncate + * page cache due to hole punching or zero range. Otherwise i_disksize update + * can get lost as it may have been postponed to submission of writeback but + * that will never happen after we truncate page cache. + */ +int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, + loff_t len) +{ + handle_t *handle; + loff_t size = i_size_read(inode); + + WARN_ON(!mutex_is_locked(&inode->i_mutex)); + if (offset > size || offset + len < size) + return 0; + + if (EXT4_I(inode)->i_disksize >= size) + return 0; + + handle = ext4_journal_start(inode, EXT4_HT_MISC, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + ext4_update_i_disksize(inode, size); + ext4_mark_inode_dirty(handle, inode); + ext4_journal_stop(handle); + + return 0; +} + +/* * ext4_punch_hole: punches a hole in a file by releaseing the blocks * associated with the given offset and length * @@ -3729,9 +3758,13 @@ int ext4_punch_hole(struct inode *inode, last_block_offset = round_down((offset + length), sb->s_blocksize) - 1;
/* Now release the pages and zero block aligned part of pages*/ - if (last_block_offset > first_block_offset) + if (last_block_offset > first_block_offset) { + ret = ext4_update_disksize_before_punch(inode, offset, length); + if (ret) + goto out_dio; truncate_pagecache_range(inode, first_block_offset, last_block_offset); + }
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) credits = ext4_writepage_trans_blocks(inode);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Wang Shilong wangsl.fnst@cn.fujitsu.com
commit c01a5c074c0f6f85a3b02e39432b9e5576ab51de upstream.
inline data is stored from offset of @disk_bytenr in struct btrfs_file_extent_item. So substracting total size of struct btrfs_file_extent_item is wrong, fix it.
Signed-off-by: Wang Shilong wangsl.fnst@cn.fujitsu.com Reviewed-by: David Sterba dsterba@suse.cz Signed-off-by: Chris Mason clm@fb.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/ctree.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -394,7 +394,7 @@ struct btrfs_header { #define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->leafsize)) #define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \ sizeof(struct btrfs_item) - \ - sizeof(struct btrfs_file_extent_item)) + offsetof(struct btrfs_file_extent_item, disk_bytenr)) #define BTRFS_MAX_XATTR_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \ sizeof(struct btrfs_item) -\ sizeof(struct btrfs_dir_item))
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Sterba dsterba@suse.cz
commit 7ec20afbcb7b257aec82ea5d66e6b0b7499abaca upstream.
Use a common definition for the inline data start so we don't have to open-code it and introduce bugs like "Btrfs: fix wrong max inline data size limit" fixed.
Signed-off-by: David Sterba dsterba@suse.cz [bwh: Backported to 3.16 as dependency of various fixes: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/ctree.c | 3 +-- fs/btrfs/ctree.h | 16 ++++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-)
--- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -4609,8 +4609,7 @@ void btrfs_truncate_item(struct btrfs_ro ptr = btrfs_item_ptr_offset(leaf, slot); memmove_extent_buffer(leaf, ptr, (unsigned long)fi, - offsetof(struct btrfs_file_extent_item, - disk_bytenr)); + BTRFS_FILE_EXTENT_INLINE_DATA_START); } }
--- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -392,9 +392,11 @@ struct btrfs_header { sizeof(struct btrfs_key_ptr)) #define __BTRFS_LEAF_DATA_SIZE(bs) ((bs) - sizeof(struct btrfs_header)) #define BTRFS_LEAF_DATA_SIZE(r) (__BTRFS_LEAF_DATA_SIZE(r->leafsize)) +#define BTRFS_FILE_EXTENT_INLINE_DATA_START \ + (offsetof(struct btrfs_file_extent_item, disk_bytenr)) #define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \ sizeof(struct btrfs_item) - \ - offsetof(struct btrfs_file_extent_item, disk_bytenr)) + BTRFS_FILE_EXTENT_INLINE_DATA_START) #define BTRFS_MAX_XATTR_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \ sizeof(struct btrfs_item) -\ sizeof(struct btrfs_dir_item)) @@ -904,6 +906,8 @@ struct btrfs_file_extent_item { /* * disk space consumed by the extent, checksum blocks are included * in these numbers + * + * At this offset in the structure, the inline extent data start. */ __le64 disk_bytenr; __le64 disk_num_bytes; @@ -3050,14 +3054,12 @@ BTRFS_SETGET_STACK_FUNCS(stack_file_exte static inline unsigned long btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e) { - unsigned long offset = (unsigned long)e; - offset += offsetof(struct btrfs_file_extent_item, disk_bytenr); - return offset; + return (unsigned long)e + BTRFS_FILE_EXTENT_INLINE_DATA_START; }
static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize) { - return offsetof(struct btrfs_file_extent_item, disk_bytenr) + datasize; + return BTRFS_FILE_EXTENT_INLINE_DATA_START + datasize; }
BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item, @@ -3087,9 +3089,7 @@ BTRFS_SETGET_FUNCS(file_extent_other_enc static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb, struct btrfs_item *e) { - unsigned long offset; - offset = offsetof(struct btrfs_file_extent_item, disk_bytenr); - return btrfs_item_size(eb, e) - offset; + return btrfs_item_size(eb, e) - BTRFS_FILE_EXTENT_INLINE_DATA_START; }
/* this returns the number of file bytes represented by the inline item.
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Sterba dsterba@suse.cz
commit fb85fc9a675738ee2746b51c3aedde944b18ca02 upstream.
It used to be more complex but now it's just a simple array access.
Signed-off-by: David Sterba dsterba@suse.cz [bwh: Backported to 3.16 as dependency of various fixes: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/extent_io.c | 55 +++++++++++++++++++++----------------------- fs/btrfs/extent_io.h | 6 ----- 2 files changed, 26 insertions(+), 35 deletions(-)
--- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2082,7 +2082,7 @@ int repair_eb_io_failure(struct btrfs_ro return -EROFS;
for (i = 0; i < num_pages; i++) { - struct page *p = extent_buffer_page(eb, i); + struct page *p = eb->pages[i]; ret = repair_io_failure(root->fs_info, start, PAGE_CACHE_SIZE, start, p, mirror_num); if (ret) @@ -3558,7 +3558,7 @@ lock_extent_buffer_for_io(struct extent_
num_pages = num_extent_pages(eb->start, eb->len); for (i = 0; i < num_pages; i++) { - struct page *p = extent_buffer_page(eb, i); + struct page *p = eb->pages[i];
if (!trylock_page(p)) { if (!flush) { @@ -3629,7 +3629,7 @@ static noinline_for_stack int write_one_ bio_flags = EXTENT_BIO_TREE_LOG;
for (i = 0; i < num_pages; i++) { - struct page *p = extent_buffer_page(eb, i); + struct page *p = eb->pages[i];
clear_page_dirty_for_io(p); set_page_writeback(p); @@ -3652,10 +3652,8 @@ static noinline_for_stack int write_one_ }
if (unlikely(ret)) { - for (; i < num_pages; i++) { - struct page *p = extent_buffer_page(eb, i); - unlock_page(p); - } + for (; i < num_pages; i++) + unlock_page(eb->pages[i]); }
return ret; @@ -4459,7 +4457,7 @@ static void btrfs_release_extent_buffer_
do { index--; - page = extent_buffer_page(eb, index); + page = eb->pages[index]; if (page && mapped) { spin_lock(&page->mapping->private_lock); /* @@ -4641,7 +4639,8 @@ static void mark_extent_buffer_accessed(
num_pages = num_extent_pages(eb->start, eb->len); for (i = 0; i < num_pages; i++) { - struct page *p = extent_buffer_page(eb, i); + struct page *p = eb->pages[i]; + if (p != accessed) mark_page_accessed(p); } @@ -4810,7 +4809,7 @@ again: */ SetPageChecked(eb->pages[0]); for (i = 1; i < num_pages; i++) { - p = extent_buffer_page(eb, i); + p = eb->pages[i]; ClearPageChecked(p); unlock_page(p); } @@ -4921,7 +4920,7 @@ void clear_extent_buffer_dirty(struct ex num_pages = num_extent_pages(eb->start, eb->len);
for (i = 0; i < num_pages; i++) { - page = extent_buffer_page(eb, i); + page = eb->pages[i]; if (!PageDirty(page)) continue;
@@ -4957,7 +4956,7 @@ int set_extent_buffer_dirty(struct exten WARN_ON(!test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags));
for (i = 0; i < num_pages; i++) - set_page_dirty(extent_buffer_page(eb, i)); + set_page_dirty(eb->pages[i]); return was_dirty; }
@@ -4970,7 +4969,7 @@ int clear_extent_buffer_uptodate(struct clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); num_pages = num_extent_pages(eb->start, eb->len); for (i = 0; i < num_pages; i++) { - page = extent_buffer_page(eb, i); + page = eb->pages[i]; if (page) ClearPageUptodate(page); } @@ -4986,7 +4985,7 @@ int set_extent_buffer_uptodate(struct ex set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); num_pages = num_extent_pages(eb->start, eb->len); for (i = 0; i < num_pages; i++) { - page = extent_buffer_page(eb, i); + page = eb->pages[i]; SetPageUptodate(page); } return 0; @@ -5026,7 +5025,7 @@ int read_extent_buffer_pages(struct exte
num_pages = num_extent_pages(eb->start, eb->len); for (i = start_i; i < num_pages; i++) { - page = extent_buffer_page(eb, i); + page = eb->pages[i]; if (wait == WAIT_NONE) { if (!trylock_page(page)) goto unlock_exit; @@ -5049,7 +5048,7 @@ int read_extent_buffer_pages(struct exte eb->read_mirror = 0; atomic_set(&eb->io_pages, num_reads); for (i = start_i; i < num_pages; i++) { - page = extent_buffer_page(eb, i); + page = eb->pages[i]; if (!PageUptodate(page)) { ClearPageError(page); err = __extent_read_full_page(tree, page, @@ -5074,7 +5073,7 @@ int read_extent_buffer_pages(struct exte return ret;
for (i = start_i; i < num_pages; i++) { - page = extent_buffer_page(eb, i); + page = eb->pages[i]; wait_on_page_locked(page); if (!PageUptodate(page)) ret = -EIO; @@ -5085,7 +5084,7 @@ int read_extent_buffer_pages(struct exte unlock_exit: i = start_i; while (locked_pages > 0) { - page = extent_buffer_page(eb, i); + page = eb->pages[i]; i++; unlock_page(page); locked_pages--; @@ -5111,7 +5110,7 @@ void read_extent_buffer(struct extent_bu offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
while (len > 0) { - page = extent_buffer_page(eb, i); + page = eb->pages[i];
cur = min(len, (PAGE_CACHE_SIZE - offset)); kaddr = page_address(page); @@ -5143,7 +5142,7 @@ int read_extent_buffer_to_user(struct ex offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
while (len > 0) { - page = extent_buffer_page(eb, i); + page = eb->pages[i];
cur = min(len, (PAGE_CACHE_SIZE - offset)); kaddr = page_address(page); @@ -5192,7 +5191,7 @@ int map_private_extent_buffer(struct ext return -EINVAL; }
- p = extent_buffer_page(eb, i); + p = eb->pages[i]; kaddr = page_address(p); *map = kaddr + offset; *map_len = PAGE_CACHE_SIZE - offset; @@ -5218,7 +5217,7 @@ int memcmp_extent_buffer(struct extent_b offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
while (len > 0) { - page = extent_buffer_page(eb, i); + page = eb->pages[i];
cur = min(len, (PAGE_CACHE_SIZE - offset));
@@ -5252,7 +5251,7 @@ void write_extent_buffer(struct extent_b offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
while (len > 0) { - page = extent_buffer_page(eb, i); + page = eb->pages[i]; WARN_ON(!PageUptodate(page));
cur = min(len, PAGE_CACHE_SIZE - offset); @@ -5282,7 +5281,7 @@ void memset_extent_buffer(struct extent_ offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
while (len > 0) { - page = extent_buffer_page(eb, i); + page = eb->pages[i]; WARN_ON(!PageUptodate(page));
cur = min(len, PAGE_CACHE_SIZE - offset); @@ -5313,7 +5312,7 @@ void copy_extent_buffer(struct extent_bu (PAGE_CACHE_SIZE - 1);
while (len > 0) { - page = extent_buffer_page(dst, i); + page = dst->pages[i]; WARN_ON(!PageUptodate(page));
cur = min(len, (unsigned long)(PAGE_CACHE_SIZE - offset)); @@ -5391,8 +5390,7 @@ void memcpy_extent_buffer(struct extent_ cur = min_t(unsigned long, cur, (unsigned long)(PAGE_CACHE_SIZE - dst_off_in_page));
- copy_pages(extent_buffer_page(dst, dst_i), - extent_buffer_page(dst, src_i), + copy_pages(dst->pages[dst_i], dst->pages[src_i], dst_off_in_page, src_off_in_page, cur);
src_offset += cur; @@ -5438,8 +5436,7 @@ void memmove_extent_buffer(struct extent
cur = min_t(unsigned long, len, src_off_in_page + 1); cur = min(cur, dst_off_in_page + 1); - copy_pages(extent_buffer_page(dst, dst_i), - extent_buffer_page(dst, src_i), + copy_pages(dst->pages[dst_i], dst->pages[src_i], dst_off_in_page - cur + 1, src_off_in_page - cur + 1, cur);
--- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -286,12 +286,6 @@ static inline unsigned long num_extent_p (start >> PAGE_CACHE_SHIFT); }
-static inline struct page *extent_buffer_page(struct extent_buffer *eb, - unsigned long i) -{ - return eb->pages[i]; -} - static inline void extent_buffer_get(struct extent_buffer *eb) { atomic_inc(&eb->refs);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Sterba dsterba@suse.cz
commit 1ffb22cf8c322bbfea6b35fe23d025841b49fede upstream.
There's a pointer to buffer, integer offset and offset passed as pointer, try to find matching names for them.
Signed-off-by: David Sterba dsterba@suse.cz Signed-off-by: Chris Mason clm@fb.com [bwh: Backported to 3.16 as dependency of fixes to this function] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/volumes.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-)
--- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6032,13 +6032,13 @@ int btrfs_read_sys_array(struct btrfs_ro struct extent_buffer *sb; struct btrfs_disk_key *disk_key; struct btrfs_chunk *chunk; - u8 *ptr; - unsigned long sb_ptr; + u8 *array_ptr; + unsigned long sb_array_offset; int ret = 0; u32 num_stripes; u32 array_size; u32 len = 0; - u32 cur; + u32 cur_offset; struct btrfs_key key;
sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET, @@ -6065,20 +6065,21 @@ int btrfs_read_sys_array(struct btrfs_ro write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE); array_size = btrfs_super_sys_array_size(super_copy);
- ptr = super_copy->sys_chunk_array; - sb_ptr = offsetof(struct btrfs_super_block, sys_chunk_array); - cur = 0; + array_ptr = super_copy->sys_chunk_array; + sb_array_offset = offsetof(struct btrfs_super_block, sys_chunk_array); + cur_offset = 0;
- while (cur < array_size) { - disk_key = (struct btrfs_disk_key *)ptr; + while (cur_offset < array_size) { + disk_key = (struct btrfs_disk_key *)array_ptr; btrfs_disk_key_to_cpu(&key, disk_key);
- len = sizeof(*disk_key); ptr += len; - sb_ptr += len; - cur += len; + len = sizeof(*disk_key); + array_ptr += len; + sb_array_offset += len; + cur_offset += len;
if (key.type == BTRFS_CHUNK_ITEM_KEY) { - chunk = (struct btrfs_chunk *)sb_ptr; + chunk = (struct btrfs_chunk *)sb_array_offset; ret = read_one_chunk(root, &key, sb, chunk); if (ret) break; @@ -6088,9 +6089,9 @@ int btrfs_read_sys_array(struct btrfs_ro ret = -EIO; break; } - ptr += len; - sb_ptr += len; - cur += len; + array_ptr += len; + sb_array_offset += len; + cur_offset += len; } free_extent_buffer(sb); return ret;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Sterba dsterba@suse.cz
commit e3540eab29e1b2260bc4b9b3979a49a00e3e3af8 upstream.
Verify that the sys_array has enough bytes to read the next item.
Signed-off-by: David Sterba dsterba@suse.cz Signed-off-by: Chris Mason clm@fb.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/volumes.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-)
--- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6071,20 +6071,34 @@ int btrfs_read_sys_array(struct btrfs_ro
while (cur_offset < array_size) { disk_key = (struct btrfs_disk_key *)array_ptr; + len = sizeof(*disk_key); + if (cur_offset + len > array_size) + goto out_short_read; + btrfs_disk_key_to_cpu(&key, disk_key);
- len = sizeof(*disk_key); array_ptr += len; sb_array_offset += len; cur_offset += len;
if (key.type == BTRFS_CHUNK_ITEM_KEY) { chunk = (struct btrfs_chunk *)sb_array_offset; + /* + * At least one btrfs_chunk with one stripe must be + * present, exact stripe count check comes afterwards + */ + len = btrfs_chunk_item_size(1); + if (cur_offset + len > array_size) + goto out_short_read; + + num_stripes = btrfs_chunk_num_stripes(sb, chunk); + len = btrfs_chunk_item_size(num_stripes); + if (cur_offset + len > array_size) + goto out_short_read; + ret = read_one_chunk(root, &key, sb, chunk); if (ret) break; - num_stripes = btrfs_chunk_num_stripes(sb, chunk); - len = btrfs_chunk_item_size(num_stripes); } else { ret = -EIO; break; @@ -6095,6 +6109,12 @@ int btrfs_read_sys_array(struct btrfs_ro } free_extent_buffer(sb); return ret; + +out_short_read: + printk(KERN_ERR "BTRFS: sys_array too short to read %u bytes at offset %u\n", + len, cur_offset); + free_extent_buffer(sb); + return -EIO; }
int btrfs_read_chunk_tree(struct btrfs_root *root)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Mahoney jeffm@suse.com
commit 95617d69326ce386c95e33db7aeb832b45ee9f8f upstream.
Overloading extent_map->bdev to struct map_lookup * might have started out as a means to an end, but it's a pattern that's used all over the place now. Let's get rid of the casting and just add a union instead.
Signed-off-by: Jeff Mahoney jeffm@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: drop changes in btrfs_start_trans_remove_block_group(), btrfs_update_commit_device_bytes_used()] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -614,7 +614,7 @@ static void btrfs_dev_replace_update_dev em = lookup_extent_mapping(em_tree, start, (u64)-1); if (!em) break; - map = (struct map_lookup *)em->bdev; + map = em->map_lookup; for (i = 0; i < map->num_stripes; i++) if (srcdev == map->stripes[i].dev) map->stripes[i].dev = tgtdev; --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -76,7 +76,7 @@ void free_extent_map(struct extent_map * WARN_ON(extent_map_in_tree(em)); WARN_ON(!list_empty(&em->list)); if (test_bit(EXTENT_FLAG_FS_MAPPING, &em->flags)) - kfree(em->bdev); + kfree(em->map_lookup); kmem_cache_free(extent_map_cache, em); } } --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h @@ -32,7 +32,15 @@ struct extent_map { u64 block_len; u64 generation; unsigned long flags; - struct block_device *bdev; + union { + struct block_device *bdev; + + /* + * used for chunk mappings + * flags & EXTENT_FLAG_FS_MAPPING must be set + */ + struct map_lookup *map_lookup; + }; atomic_t refs; unsigned int compress_type; struct list_head list; --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -2637,7 +2637,7 @@ static noinline_for_stack int scrub_chun if (!em) return -EINVAL;
- map = (struct map_lookup *)em->bdev; + map = em->map_lookup; if (em->start != chunk_offset) goto out;
--- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1047,7 +1047,7 @@ static int contains_pending_extent(struc struct map_lookup *map; int i;
- map = (struct map_lookup *)em->bdev; + map = em->map_lookup; for (i = 0; i < map->num_stripes; i++) { if (map->stripes[i].dev != device) continue; @@ -2533,7 +2533,7 @@ static int btrfs_relocate_chunk(struct b
BUG_ON(!em || em->start > chunk_offset || em->start + em->len < chunk_offset); - map = (struct map_lookup *)em->bdev; + map = em->map_lookup;
for (i = 0; i < map->num_stripes; i++) { ret = btrfs_free_dev_extent(trans, map->stripes[i].dev, @@ -4322,7 +4322,7 @@ static int __btrfs_alloc_chunk(struct bt goto error; } set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags); - em->bdev = (struct block_device *)map; + em->map_lookup = map; em->start = start; em->len = num_bytes; em->block_start = 0; @@ -4405,7 +4405,7 @@ int btrfs_finish_chunk_alloc(struct btrf return -EINVAL; }
- map = (struct map_lookup *)em->bdev; + map = em->map_lookup; item_size = btrfs_chunk_item_size(map->num_stripes); stripe_size = em->orig_block_len;
@@ -4547,7 +4547,7 @@ int btrfs_chunk_readonly(struct btrfs_ro return 0; }
- map = (struct map_lookup *)em->bdev; + map = em->map_lookup; for (i = 0; i < map->num_stripes; i++) { if (!map->stripes[i].dev->writeable) { readonly = 1; @@ -4613,7 +4613,7 @@ int btrfs_num_copies(struct btrfs_fs_inf return 1; }
- map = (struct map_lookup *)em->bdev; + map = em->map_lookup; if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1)) ret = map->num_stripes; else if (map->type & BTRFS_BLOCK_GROUP_RAID10) @@ -4649,7 +4649,7 @@ unsigned long btrfs_full_stripe_len(stru BUG_ON(!em);
BUG_ON(em->start > logical || em->start + em->len < logical); - map = (struct map_lookup *)em->bdev; + map = em->map_lookup; if (map->type & (BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6)) { len = map->stripe_len * nr_data_stripes(map); @@ -4672,7 +4672,7 @@ int btrfs_is_parity_mirror(struct btrfs_ BUG_ON(!em);
BUG_ON(em->start > logical || em->start + em->len < logical); - map = (struct map_lookup *)em->bdev; + map = em->map_lookup; if (map->type & (BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6)) ret = 1; @@ -4794,7 +4794,7 @@ static int __btrfs_map_block(struct btrf return -EINVAL; }
- map = (struct map_lookup *)em->bdev; + map = em->map_lookup; offset = logical - em->start;
stripe_len = map->stripe_len; @@ -5321,7 +5321,7 @@ int btrfs_rmap_block(struct btrfs_mappin free_extent_map(em); return -EIO; } - map = (struct map_lookup *)em->bdev; + map = em->map_lookup;
length = em->len; rmap_len = map->stripe_len; @@ -5846,7 +5846,7 @@ static int read_one_chunk(struct btrfs_r }
set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags); - em->bdev = (struct block_device *)map; + em->map_lookup = map; em->start = logical; em->len = length; em->orig_start = 0;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Sterba dsterba@suse.com
commit f5cdedd73fa71b74dcc42f2a11a5735d89ce7c4f upstream.
We can handle the special case of num_stripes == 0 directly inside btrfs_read_sys_array. The BUG_ON in btrfs_chunk_item_size is there to catch other unhandled cases where we fail to validate external data.
A crafted or corrupted image crashes at mount time:
BTRFS: device fsid 9006933e-2a9a-44f0-917f-514252aeec2c devid 1 transid 7 /dev/loop0 BTRFS info (device loop0): disk space caching is enabled BUG: failure at fs/btrfs/ctree.h:337/btrfs_chunk_item_size()! Kernel panic - not syncing: BUG! CPU: 0 PID: 313 Comm: mount Not tainted 4.2.5-00657-ge047887-dirty #25 Stack: 637af890 60062489 602aeb2e 604192ba 60387961 00000011 637af8a0 6038a835 637af9c0 6038776b 634ef32b 00000000 Call Trace: [<6001c86d>] show_stack+0xfe/0x15b [<6038a835>] dump_stack+0x2a/0x2c [<6038776b>] panic+0x13e/0x2b3 [<6020f099>] btrfs_read_sys_array+0x25d/0x2ff [<601cfbbe>] open_ctree+0x192d/0x27af [<6019c2c1>] btrfs_mount+0x8f5/0xb9a [<600bc9a7>] mount_fs+0x11/0xf3 [<600d5167>] vfs_kern_mount+0x75/0x11a [<6019bcb0>] btrfs_mount+0x2e4/0xb9a [<600bc9a7>] mount_fs+0x11/0xf3 [<600d5167>] vfs_kern_mount+0x75/0x11a [<600d710b>] do_mount+0xa35/0xbc9 [<600d7557>] SyS_mount+0x95/0xc8 [<6001e884>] handle_syscall+0x6b/0x8e
Reported-by: Jiri Slaby jslaby@suse.com Reported-by: Vegard Nossum vegard.nossum@oracle.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/volumes.c | 8 ++++++++ 1 file changed, 8 insertions(+)
--- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -6092,6 +6092,14 @@ int btrfs_read_sys_array(struct btrfs_ro goto out_short_read;
num_stripes = btrfs_chunk_num_stripes(sb, chunk); + if (!num_stripes) { + printk(KERN_ERR + "BTRFS: invalid number of stripes %u in sys_array at offset %u\n", + num_stripes, cur_offset); + ret = -EIO; + break; + } + len = btrfs_chunk_item_size(num_stripes); if (cur_offset + len > array_size) goto out_short_read;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo quwenruo@cn.fujitsu.com
commit f04b772bfc17f502703794f4d100d12155c1a1a9 upstream.
Enhance chunk validation: 1) Num_stripes We already have such check but it's only in super block sys chunk array. Now check all on-disk chunks.
2) Chunk logical It should be aligned to sector size. This behavior should be *DOUBLE CHECKED* for 64K sector size like PPC64 or AArch64. Maybe we can found some hidden bugs.
3) Chunk length Same as chunk logical, should be aligned to sector size.
4) Stripe length It should be power of 2.
5) Chunk type Any bit out of TYPE_MAS | PROFILE_MASK is invalid.
With all these much restrict rules, several fuzzed image reported in mail list should no longer cause kernel panic.
Reported-by: Vegard Nossum vegard.nossum@oracle.com Signed-off-by: Qu Wenruo quwenruo@cn.fujitsu.com Signed-off-by: Chris Mason clm@fb.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/volumes.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-)
--- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5814,6 +5814,7 @@ static int read_one_chunk(struct btrfs_r struct extent_map *em; u64 logical; u64 length; + u64 stripe_len; u64 devid; u8 uuid[BTRFS_UUID_SIZE]; int num_stripes; @@ -5822,6 +5823,37 @@ static int read_one_chunk(struct btrfs_r
logical = key->offset; length = btrfs_chunk_length(leaf, chunk); + stripe_len = btrfs_chunk_stripe_len(leaf, chunk); + num_stripes = btrfs_chunk_num_stripes(leaf, chunk); + /* Validation check */ + if (!num_stripes) { + btrfs_err(root->fs_info, "invalid chunk num_stripes: %u", + num_stripes); + return -EIO; + } + if (!IS_ALIGNED(logical, root->sectorsize)) { + btrfs_err(root->fs_info, + "invalid chunk logical %llu", logical); + return -EIO; + } + if (!length || !IS_ALIGNED(length, root->sectorsize)) { + btrfs_err(root->fs_info, + "invalid chunk length %llu", length); + return -EIO; + } + if (!is_power_of_2(stripe_len)) { + btrfs_err(root->fs_info, "invalid chunk stripe length: %llu", + stripe_len); + return -EIO; + } + if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & + btrfs_chunk_type(leaf, chunk)) { + btrfs_err(root->fs_info, "unrecognized chunk type: %llu", + ~(BTRFS_BLOCK_GROUP_TYPE_MASK | + BTRFS_BLOCK_GROUP_PROFILE_MASK) & + btrfs_chunk_type(leaf, chunk)); + return -EIO; + }
read_lock(&map_tree->map_tree.lock); em = lookup_extent_mapping(&map_tree->map_tree, logical, 1); @@ -5838,7 +5870,6 @@ static int read_one_chunk(struct btrfs_r em = alloc_extent_map(); if (!em) return -ENOMEM; - num_stripes = btrfs_chunk_num_stripes(leaf, chunk); map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); if (!map) { free_extent_map(em);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Liu Bo bo.li.liu@oracle.com
commit e06cd3dd7cea50e87663a88acdfdb7ac1c53a5ca upstream.
To prevent fuzzed filesystem images from panic the whole system, we need various validation checks to refuse to mount such an image if btrfs finds any invalid value during loading chunks, including both sys_array and regular chunks.
Note that these checks may not be sufficient to cover all corner cases, feel free to add more checks.
Reported-by: Vegard Nossum vegard.nossum@oracle.com Reported-by: Quentin Casasnovas quentin.casasnovas@oracle.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: Liu Bo bo.li.liu@oracle.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/volumes.c | 82 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 15 deletions(-)
--- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5805,27 +5805,23 @@ struct btrfs_device *btrfs_alloc_device( return dev; }
-static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, - struct extent_buffer *leaf, - struct btrfs_chunk *chunk) +/* Return -EIO if any error, otherwise return 0. */ +static int btrfs_check_chunk_valid(struct btrfs_root *root, + struct extent_buffer *leaf, + struct btrfs_chunk *chunk, u64 logical) { - struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; - struct map_lookup *map; - struct extent_map *em; - u64 logical; u64 length; u64 stripe_len; - u64 devid; - u8 uuid[BTRFS_UUID_SIZE]; - int num_stripes; - int ret; - int i; + u16 num_stripes; + u16 sub_stripes; + u64 type;
- logical = key->offset; length = btrfs_chunk_length(leaf, chunk); stripe_len = btrfs_chunk_stripe_len(leaf, chunk); num_stripes = btrfs_chunk_num_stripes(leaf, chunk); - /* Validation check */ + sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk); + type = btrfs_chunk_type(leaf, chunk); + if (!num_stripes) { btrfs_err(root->fs_info, "invalid chunk num_stripes: %u", num_stripes); @@ -5836,6 +5832,11 @@ static int read_one_chunk(struct btrfs_r "invalid chunk logical %llu", logical); return -EIO; } + if (btrfs_chunk_sector_size(leaf, chunk) != root->sectorsize) { + btrfs_err(root->fs_info, "invalid chunk sectorsize %u", + btrfs_chunk_sector_size(leaf, chunk)); + return -EIO; + } if (!length || !IS_ALIGNED(length, root->sectorsize)) { btrfs_err(root->fs_info, "invalid chunk length %llu", length); @@ -5847,13 +5848,54 @@ static int read_one_chunk(struct btrfs_r return -EIO; } if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & - btrfs_chunk_type(leaf, chunk)) { + type) { btrfs_err(root->fs_info, "unrecognized chunk type: %llu", ~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & btrfs_chunk_type(leaf, chunk)); return -EIO; } + if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) || + (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) || + (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) || + (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3) || + (type & BTRFS_BLOCK_GROUP_DUP && num_stripes > 2) || + ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 && + num_stripes != 1)) { + btrfs_err(root->fs_info, + "invalid num_stripes:sub_stripes %u:%u for profile %llu", + num_stripes, sub_stripes, + type & BTRFS_BLOCK_GROUP_PROFILE_MASK); + return -EIO; + } + + return 0; +} + +static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, + struct extent_buffer *leaf, + struct btrfs_chunk *chunk) +{ + struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; + struct map_lookup *map; + struct extent_map *em; + u64 logical; + u64 length; + u64 stripe_len; + u64 devid; + u8 uuid[BTRFS_UUID_SIZE]; + int num_stripes; + int ret; + int i; + + logical = key->offset; + length = btrfs_chunk_length(leaf, chunk); + stripe_len = btrfs_chunk_stripe_len(leaf, chunk); + num_stripes = btrfs_chunk_num_stripes(leaf, chunk); + + ret = btrfs_check_chunk_valid(root, leaf, chunk, logical); + if (ret) + return ret;
read_lock(&map_tree->map_tree.lock); em = lookup_extent_mapping(&map_tree->map_tree, logical, 1); @@ -6070,6 +6112,7 @@ int btrfs_read_sys_array(struct btrfs_ro u32 array_size; u32 len = 0; u32 cur_offset; + u64 type; struct btrfs_key key;
sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET, @@ -6130,6 +6173,15 @@ int btrfs_read_sys_array(struct btrfs_ro ret = -EIO; break; } + + type = btrfs_chunk_type(sb, chunk); + if ((type & BTRFS_BLOCK_GROUP_SYSTEM) == 0) { + btrfs_err(root->fs_info, + "invalid chunk type %llu in sys_array at offset %u", + type, cur_offset); + ret = -EIO; + break; + }
len = btrfs_chunk_item_size(num_stripes); if (cur_offset + len > array_size)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Liu Bo bo.li.liu@oracle.com
commit 6fb37b756acce6d6e045f79c3764206033f617b4 upstream.
With btrfs-corrupt-block, one can drop one chunk item and mounting will end up with a panic in btrfs_full_stripe_len().
This doesn't not remove the BUG_ON, but instead checks it a bit earlier when we find the block group item.
Signed-off-by: Liu Bo bo.li.liu@oracle.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/extent-tree.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-)
--- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8571,7 +8571,22 @@ static int find_first_block_group(struct
if (found_key.objectid >= key->objectid && found_key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) { - ret = 0; + struct extent_map_tree *em_tree; + struct extent_map *em; + + em_tree = &root->fs_info->mapping_tree.map_tree; + read_lock(&em_tree->lock); + em = lookup_extent_mapping(em_tree, found_key.objectid, + found_key.offset); + read_unlock(&em_tree->lock); + if (!em) { + btrfs_err(root->fs_info, + "logical %llu len %llu found bg but no related chunk", + found_key.objectid, found_key.offset); + ret = -ENOENT; + } else { + ret = 0; + } goto out; } path->slots[0]++;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik jbacik@fb.com
commit 187ee58c62c1d0d238d3dc4835869d33e1869906 upstream.
We need to call free_extent_map() on the em we look up.
Signed-off-by: Josef Bacik jbacik@fb.com Reviewed-by: Omar Sandoval osandov@fb.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Chris Mason clm@fb.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/extent-tree.c | 1 + 1 file changed, 1 insertion(+)
--- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8587,6 +8587,7 @@ static int find_first_block_group(struct } else { ret = 0; } + free_extent_map(em); goto out; } path->slots[0]++;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Liu Bo bo.li.liu@oracle.com
commit 1ba98d086fe3a14d6a31f2f66dbab70c45d00f63 upstream.
Right now we treat leaf which has zero item as a valid one because we could have an empty tree, that is, a root that is also a leaf without any item, however, in the same case but when the leaf is not a root, we can end up with hitting the BUG_ON(1) in btrfs_extend_item() called by setup_inline_extent_backref().
This makes us check the situation as a corruption if leaf is not its own root.
Signed-off-by: Liu Bo bo.li.liu@oracle.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Chris Mason clm@fb.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/disk-io.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
--- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -520,8 +520,29 @@ static noinline int check_leaf(struct bt u32 nritems = btrfs_header_nritems(leaf); int slot;
- if (nritems == 0) + if (nritems == 0) { + struct btrfs_root *check_root; + + key.objectid = btrfs_header_owner(leaf); + key.type = BTRFS_ROOT_ITEM_KEY; + key.offset = (u64)-1; + + check_root = btrfs_get_fs_root(root->fs_info, &key, false); + /* + * The only reason we also check NULL here is that during + * open_ctree() some roots has not yet been set up. + */ + if (!IS_ERR_OR_NULL(check_root)) { + /* if leaf is the root, then it's fine */ + if (leaf->start != + btrfs_root_bytenr(&check_root->root_item)) { + CORRUPT("non-root leaf's nritems is 0", + leaf, root, 0); + return -EIO; + } + } return 0; + }
/* Check the 0 item */ if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) !=
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Liu Bo bo.li.liu@oracle.com
commit 053ab70f0604224c7893b43f9d9d5efa283580d6 upstream.
When btree node (level = 1) has nritems which equals to zero, we can end up with panic due to insert_ptr()'s
BUG_ON(slot > nritems);
where slot is 1 and nritems is 0, as copy_for_split() calls insert_ptr(.., path->slots[1] + 1, ...);
A invalid value results in the whole mess, this adds the check for btree's node nritems so that we stop reading block when when something is wrong.
Signed-off-by: Liu Bo bo.li.liu@oracle.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Chris Mason clm@fb.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/disk-io.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
--- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -594,6 +594,19 @@ static noinline int check_leaf(struct bt return 0; }
+static int check_node(struct btrfs_root *root, struct extent_buffer *node) +{ + unsigned long nr = btrfs_header_nritems(node); + + if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) { + btrfs_crit(root->fs_info, + "corrupt node: block %llu root %llu nritems %lu", + node->start, root->objectid, nr); + return -EIO; + } + return 0; +} + static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, u64 phy_offset, struct page *page, u64 start, u64 end, int mirror) @@ -666,6 +679,9 @@ static int btree_readpage_end_io_hook(st ret = -EIO; }
+ if (found_level > 0 && check_node(root, eb)) + ret = -EIO; + if (!ret) set_extent_buffer_uptodate(eb); err:
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Liu Bo bo.li.liu@oracle.com
commit ef85b25e982b5bba1530b936e283ef129f02ab9d upstream.
This can only happen with CONFIG_BTRFS_FS_CHECK_INTEGRITY=y.
Commit 1ba98d0 ("Btrfs: detect corruption when non-root leaf has zero item") assumes that a leaf is its root when leaf->bytenr == btrfs_root_bytenr(root), however, we should not use btrfs_root_bytenr(root) since it's mainly got updated during committing transaction. So the check can fail when doing COW on this leaf while it is a root.
This changes to use "if (leaf == btrfs_root_node(root))" instead, just like how we check whether leaf is a root in __btrfs_cow_block().
Fixes: 1ba98d086fe3 (Btrfs: detect corruption when non-root leaf has zero item) Reported-by: Jeff Mahoney jeffm@suse.com Signed-off-by: Liu Bo bo.li.liu@oracle.com Reviewed-by: Filipe Manana fdmanana@suse.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/disk-io.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
--- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -533,13 +533,17 @@ static noinline int check_leaf(struct bt * open_ctree() some roots has not yet been set up. */ if (!IS_ERR_OR_NULL(check_root)) { + struct extent_buffer *eb; + + eb = btrfs_root_node(check_root); /* if leaf is the root, then it's fine */ - if (leaf->start != - btrfs_root_bytenr(&check_root->root_item)) { + if (leaf != eb) { CORRUPT("non-root leaf's nritems is 0", - leaf, root, 0); + leaf, check_root, 0); + free_extent_buffer(eb); return -EIO; } + free_extent_buffer(eb); } return 0; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Liu Bo bo.li.liu@oracle.com
commit 3eb548ee3a8042d95ad81be254e67a5222c24e03 upstream.
During updating btree, we could push items between sibling nodes/leaves, for leaves data sections starts reversely from the end of the block while for nodes we only have key pairs which are stored one by one from the start of the block.
So we could do try to push key pairs from one node to the next node right in the tree, and after that, we update the node's nritems to reflect the correct end while leaving the stale content in the node. One may intentionally corrupt the fs image and access the stale content by bumping the nritems and causes various crashes.
This takes the in-memory @nritems as the correct one and gets to memset the unused part of a btree node.
Signed-off-by: Liu Bo bo.li.liu@oracle.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/extent_io.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
--- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -3628,6 +3628,17 @@ static noinline_for_stack int write_one_ if (btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID) bio_flags = EXTENT_BIO_TREE_LOG;
+ /* set btree node beyond nritems with 0 to avoid stale content */ + if (btrfs_header_level(eb) > 0) { + u32 nritems; + unsigned long end; + + nritems = btrfs_header_nritems(eb); + end = btrfs_node_key_ptr_offset(nritems); + + memset_extent_buffer(eb, 0, end, eb->len - end); + } + for (i = 0; i < num_pages; i++) { struct page *p = eb->pages[i];
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Liu Bo bo.li.liu@oracle.com
commit 6b722c1747d533ac6d4df110dc8233db46918b65 upstream.
We need to check items in a node to make sure that we're reading a valid one, otherwise we could get various crashes while processing delayed_refs.
Signed-off-by: Liu Bo bo.li.liu@oracle.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/disk-io.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-)
--- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -508,9 +508,10 @@ static int check_tree_block_fsid(struct }
#define CORRUPT(reason, eb, root, slot) \ - btrfs_crit(root->fs_info, "corrupt leaf, %s: block=%llu," \ - "root=%llu, slot=%d", reason, \ - btrfs_header_bytenr(eb), root->objectid, slot) + btrfs_crit(root->fs_info, "corrupt %s, %s: block=%llu," \ + " root=%llu, slot=%d", \ + btrfs_header_level(eb) == 0 ? "leaf" : "node",\ + reason, btrfs_header_bytenr(eb), root->objectid, slot)
static noinline int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf) @@ -601,6 +602,10 @@ static noinline int check_leaf(struct bt static int check_node(struct btrfs_root *root, struct extent_buffer *node) { unsigned long nr = btrfs_header_nritems(node); + struct btrfs_key key, next_key; + int slot; + u64 bytenr; + int ret = 0;
if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) { btrfs_crit(root->fs_info, @@ -608,7 +613,26 @@ static int check_node(struct btrfs_root node->start, root->objectid, nr); return -EIO; } - return 0; + + for (slot = 0; slot < nr - 1; slot++) { + bytenr = btrfs_node_blockptr(node, slot); + btrfs_node_key_to_cpu(node, &key, slot); + btrfs_node_key_to_cpu(node, &next_key, slot + 1); + + if (!bytenr) { + CORRUPT("invalid item slot", node, root, slot); + ret = -EIO; + goto out; + } + + if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) { + CORRUPT("bad key order", node, root, slot); + ret = -EIO; + goto out; + } + } +out: + return ret; }
static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Liu Bo bo.li.liu@oracle.com
commit 02794222c4132ac003e7281fb71f4ec1645ffc87 upstream.
In a corrupted btrfs image, we can come across this BUG_ON and get an unreponsive system, but if we return errors instead, its caller can handle everything gracefully by aborting the current transaction.
Signed-off-by: Liu Bo bo.li.liu@oracle.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/extent-tree.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
--- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -2258,7 +2258,13 @@ static int run_delayed_tree_ref(struct b ins.type = BTRFS_EXTENT_ITEM_KEY; }
- BUG_ON(node->ref_mod != 1); + if (node->ref_mod != 1) { + btrfs_err(root->fs_info, + "btree block(%llu) has %d references rather than 1: action %d ref_root %llu parent %llu", + node->bytenr, node->ref_mod, node->action, ref_root, + parent); + return -EIO; + } if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) { BUG_ON(!extent_op || !extent_op->update_flags); ret = alloc_reserved_tree_block(trans, root,
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Liu Bo bo.li.liu@oracle.com
commit 851cd173f06045816528176001cf82948282029c upstream.
This is an additional patch to "Btrfs: memset to avoid stale content in btree node block".
This uses memset to initialize the unused space in a leaf to avoid potential stale content, which may be incurred by pushing items between sibling leaves.
Signed-off-by: Liu Bo bo.li.liu@oracle.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/ctree.c | 14 -------------- fs/btrfs/ctree.h | 15 +++++++++++++++ fs/btrfs/extent_io.c | 18 +++++++++++++----- 3 files changed, 28 insertions(+), 19 deletions(-)
--- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1721,20 +1721,6 @@ int btrfs_realloc_node(struct btrfs_tran return err; }
-/* - * The leaf data grows from end-to-front in the node. - * this returns the address of the start of the last item, - * which is the stop of the leaf data stack - */ -static inline unsigned int leaf_data_end(struct btrfs_root *root, - struct extent_buffer *leaf) -{ - u32 nr = btrfs_header_nritems(leaf); - if (nr == 0) - return BTRFS_LEAF_DATA_SIZE(root); - return btrfs_item_offset_nr(leaf, nr - 1); -} -
/* * search for key in the extent_buffer. The items start at offset p, --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -3036,6 +3036,21 @@ static inline unsigned long btrfs_leaf_d return offsetof(struct btrfs_leaf, items); }
+/* + * The leaf data grows from end-to-front in the node. + * this returns the address of the start of the last item, + * which is the stop of the leaf data stack + */ +static inline unsigned int leaf_data_end(struct btrfs_root *root, + struct extent_buffer *leaf) +{ + u32 nr = btrfs_header_nritems(leaf); + + if (nr == 0) + return BTRFS_LEAF_DATA_SIZE(root); + return btrfs_item_offset_nr(leaf, nr - 1); +} + /* struct btrfs_file_extent_item */ BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8); BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr, --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -3617,8 +3617,10 @@ static noinline_for_stack int write_one_ struct block_device *bdev = fs_info->fs_devices->latest_bdev; struct extent_io_tree *tree = &BTRFS_I(fs_info->btree_inode)->io_tree; u64 offset = eb->start; + u32 nritems; unsigned long i, num_pages; unsigned long bio_flags = 0; + unsigned long start, end; int rw = (epd->sync_io ? WRITE_SYNC : WRITE) | REQ_META; int ret = 0;
@@ -3628,15 +3630,21 @@ static noinline_for_stack int write_one_ if (btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID) bio_flags = EXTENT_BIO_TREE_LOG;
- /* set btree node beyond nritems with 0 to avoid stale content */ + /* set btree blocks beyond nritems with 0 to avoid stale content. */ + nritems = btrfs_header_nritems(eb); if (btrfs_header_level(eb) > 0) { - u32 nritems; - unsigned long end; - - nritems = btrfs_header_nritems(eb); end = btrfs_node_key_ptr_offset(nritems);
memset_extent_buffer(eb, 0, end, eb->len - end); + } else { + /* + * leaf: + * header 0 1 2 .. N ... data_N .. data_2 data_1 data_0 + */ + start = btrfs_item_nr_offset(nritems); + end = btrfs_leaf_data(eb) + + leaf_data_end(fs_info->tree_root, eb); + memset_extent_buffer(eb, 0, start, end - start); }
for (i = 0; i < num_pages; i++) {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Filipe Manana fdmanana@suse.com
commit f177d73949bf758542ca15a1c1945bd2e802cc65 upstream.
We can not simply use the owner field from an extent buffer's header to get the id of the respective tree when the extent buffer is from a relocation tree. When we create the root for a relocation tree we leave (on purpose) the owner field with the same value as the subvolume's tree root (we do this at ctree.c:btrfs_copy_root()). So we must ignore extent buffers from relocation trees, which have the BTRFS_HEADER_FLAG_RELOC flag set, because otherwise we will always consider the extent buffer as not being the root of the tree (the root of original subvolume tree is always different from the root of the respective relocation tree).
This lead to assertion failures when running with the integrity checker enabled (CONFIG_BTRFS_FS_CHECK_INTEGRITY=y) such as the following:
[ 643.393409] BTRFS critical (device sdg): corrupt leaf, non-root leaf's nritems is 0: block=38506496, root=260, slot=0 [ 643.397609] BTRFS info (device sdg): leaf 38506496 total ptrs 0 free space 3995 [ 643.407075] assertion failed: 0, file: fs/btrfs/disk-io.c, line: 4078 [ 643.408425] ------------[ cut here ]------------ [ 643.409112] kernel BUG at fs/btrfs/ctree.h:3419! [ 643.409773] invalid opcode: 0000 [#1] PREEMPT SMP [ 643.410447] Modules linked in: dm_flakey dm_mod crc32c_generic btrfs xor raid6_pq ppdev psmouse acpi_cpufreq parport_pc evdev parport tpm_tis tpm_tis_core pcspkr serio_raw i2c_piix4 sg tpm i2c_core button processor loop autofs4 ext4 crc16 jbd2 mbcache sr_mod cdrom sd_mod ata_generic virtio_scsi ata_piix libata virtio_pci virtio_ring scsi_mod virtio e1000 floppy [ 643.414356] CPU: 11 PID: 32726 Comm: btrfs Not tainted 4.8.0-rc8-btrfs-next-35+ #1 [ 643.414356] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.9.1-0-gb3ef39f-prebuilt.qemu-project.org 04/01/2014 [ 643.414356] task: ffff880145e95b00 task.stack: ffff88014826c000 [ 643.414356] RIP: 0010:[<ffffffffa0352759>] [<ffffffffa0352759>] assfail.constprop.41+0x1c/0x1e [btrfs] [ 643.414356] RSP: 0018:ffff88014826fa28 EFLAGS: 00010292 [ 643.414356] RAX: 0000000000000039 RBX: ffff88014e2d7c38 RCX: 0000000000000001 [ 643.414356] RDX: ffff88023f4d2f58 RSI: ffffffff81806c63 RDI: 00000000ffffffff [ 643.414356] RBP: ffff88014826fa28 R08: 0000000000000001 R09: 0000000000000000 [ 643.414356] R10: ffff88014826f918 R11: ffffffff82f3c5ed R12: ffff880172910000 [ 643.414356] R13: ffff880233992230 R14: ffff8801a68a3310 R15: fffffffffffffff8 [ 643.414356] FS: 00007f9ca305e8c0(0000) GS:ffff88023f4c0000(0000) knlGS:0000000000000000 [ 643.414356] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 643.414356] CR2: 00007f9ca3071000 CR3: 000000015d01b000 CR4: 00000000000006e0 [ 643.414356] Stack: [ 643.414356] ffff88014826fa50 ffffffffa02d655a 000000000000000a ffff88014e2d7c38 [ 643.414356] 0000000000000000 ffff88014826faa8 ffffffffa02b72f3 ffff88014826fab8 [ 643.414356] 00ffffffa03228e4 0000000000000000 0000000000000000 ffff8801bbd4e000 [ 643.414356] Call Trace: [ 643.414356] [<ffffffffa02d655a>] btrfs_mark_buffer_dirty+0xdf/0xe5 [btrfs] [ 643.414356] [<ffffffffa02b72f3>] btrfs_copy_root+0x18a/0x1d1 [btrfs] [ 643.414356] [<ffffffffa0322921>] create_reloc_root+0x72/0x1ba [btrfs] [ 643.414356] [<ffffffffa03267c2>] btrfs_init_reloc_root+0x7b/0xa7 [btrfs] [ 643.414356] [<ffffffffa02d9e44>] record_root_in_trans+0xdf/0xed [btrfs] [ 643.414356] [<ffffffffa02db04e>] btrfs_record_root_in_trans+0x50/0x6a [btrfs] [ 643.414356] [<ffffffffa030ad2b>] create_subvol+0x472/0x773 [btrfs] [ 643.414356] [<ffffffffa030b406>] btrfs_mksubvol+0x3da/0x463 [btrfs] [ 643.414356] [<ffffffffa030b406>] ? btrfs_mksubvol+0x3da/0x463 [btrfs] [ 643.414356] [<ffffffff810781ac>] ? preempt_count_add+0x65/0x68 [ 643.414356] [<ffffffff811a6e97>] ? __mnt_want_write+0x62/0x77 [ 643.414356] [<ffffffffa030b55d>] btrfs_ioctl_snap_create_transid+0xce/0x187 [btrfs] [ 643.414356] [<ffffffffa030b67d>] btrfs_ioctl_snap_create+0x67/0x81 [btrfs] [ 643.414356] [<ffffffffa030ecfd>] btrfs_ioctl+0x508/0x20dd [btrfs] [ 643.414356] [<ffffffff81293e39>] ? __this_cpu_preempt_check+0x13/0x15 [ 643.414356] [<ffffffff81155eca>] ? handle_mm_fault+0x976/0x9ab [ 643.414356] [<ffffffff81091300>] ? arch_local_irq_save+0x9/0xc [ 643.414356] [<ffffffff8119a2b0>] vfs_ioctl+0x18/0x34 [ 643.414356] [<ffffffff8119a8e8>] do_vfs_ioctl+0x581/0x600 [ 643.414356] [<ffffffff814b9552>] ? entry_SYSCALL_64_fastpath+0x5/0xa8 [ 643.414356] [<ffffffff81093fe9>] ? trace_hardirqs_on_caller+0x17b/0x197 [ 643.414356] [<ffffffff8119a9be>] SyS_ioctl+0x57/0x79 [ 643.414356] [<ffffffff814b9565>] entry_SYSCALL_64_fastpath+0x18/0xa8 [ 643.414356] [<ffffffff81091b08>] ? trace_hardirqs_off_caller+0x3f/0xaa [ 643.414356] Code: 89 83 88 00 00 00 31 c0 5b 41 5c 41 5d 5d c3 55 89 f1 48 c7 c2 98 bc 35 a0 48 89 fe 48 c7 c7 05 be 35 a0 48 89 e5 e8 13 46 dd e0 <0f> 0b 55 89 f1 48 c7 c2 9f d3 35 a0 48 89 fe 48 c7 c7 7a d5 35 [ 643.414356] RIP [<ffffffffa0352759>] assfail.constprop.41+0x1c/0x1e [btrfs] [ 643.414356] RSP <ffff88014826fa28> [ 643.468267] ---[ end trace 6a1b3fb1a9d7d6e3 ]---
This can be easily reproduced by running xfstests with the integrity checker enabled.
Fixes: 1ba98d086fe3 (Btrfs: detect corruption when non-root leaf has zero item) Signed-off-by: Filipe Manana fdmanana@suse.com Reviewed-by: Liu Bo bo.li.liu@oracle.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/disk-io.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
--- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -521,7 +521,15 @@ static noinline int check_leaf(struct bt u32 nritems = btrfs_header_nritems(leaf); int slot;
- if (nritems == 0) { + /* + * Extent buffers from a relocation tree have a owner field that + * corresponds to the subvolume tree they are based on. So just from an + * extent buffer alone we can not find out what is the id of the + * corresponding subvolume tree, so we can not figure out if the extent + * buffer corresponds to the root of the relocation tree or not. So skip + * this check for relocation trees. + */ + if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) { struct btrfs_root *check_root;
key.objectid = btrfs_header_owner(leaf); @@ -549,6 +557,9 @@ static noinline int check_leaf(struct bt return 0; }
+ if (nritems == 0) + return 0; + /* Check the 0 item */ if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) != BTRFS_LEAF_DATA_SIZE(root)) {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jeff Mahoney jeffm@suse.com
commit 1cbb1f454e5321e47fc1e6b233066c7ccc979d15 upstream.
We have reader helpers for most of the on-disk structures that use an extent_buffer and pointer as offset into the buffer that are read-only. We should mark them as const and, in turn, allow consumers of these interfaces to mark the buffers const as well.
No impact on code, but serves as documentation that a buffer is intended not to be modified.
Signed-off-by: Jeff Mahoney jeffm@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/ctree.h | 128 +++++++++++++++++++++------------------- fs/btrfs/extent_io.c | 24 ++++---- fs/btrfs/extent_io.h | 19 +++--- fs/btrfs/struct-funcs.c | 9 +-- 4 files changed, 91 insertions(+), 89 deletions(-)
--- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -2138,7 +2138,7 @@ struct btrfs_ioctl_defrag_range_args { #define BTRFS_INODE_ROOT_ITEM_INIT (1 << 31)
struct btrfs_map_token { - struct extent_buffer *eb; + const struct extent_buffer *eb; char *kaddr; unsigned long offset; }; @@ -2169,18 +2169,19 @@ static inline void btrfs_init_map_token sizeof(((type *)0)->member)))
#define DECLARE_BTRFS_SETGET_BITS(bits) \ -u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr, \ - unsigned long off, \ - struct btrfs_map_token *token); \ -void btrfs_set_token_##bits(struct extent_buffer *eb, void *ptr, \ +u##bits btrfs_get_token_##bits(const struct extent_buffer *eb, \ + const void *ptr, unsigned long off, \ + struct btrfs_map_token *token); \ +void btrfs_set_token_##bits(struct extent_buffer *eb, const void *ptr, \ unsigned long off, u##bits val, \ struct btrfs_map_token *token); \ -static inline u##bits btrfs_get_##bits(struct extent_buffer *eb, void *ptr, \ +static inline u##bits btrfs_get_##bits(const struct extent_buffer *eb, \ + const void *ptr, \ unsigned long off) \ { \ return btrfs_get_token_##bits(eb, ptr, off, NULL); \ } \ -static inline void btrfs_set_##bits(struct extent_buffer *eb, void *ptr, \ +static inline void btrfs_set_##bits(struct extent_buffer *eb, void *ptr,\ unsigned long off, u##bits val) \ { \ btrfs_set_token_##bits(eb, ptr, off, val, NULL); \ @@ -2192,7 +2193,8 @@ DECLARE_BTRFS_SETGET_BITS(32) DECLARE_BTRFS_SETGET_BITS(64)
#define BTRFS_SETGET_FUNCS(name, type, member, bits) \ -static inline u##bits btrfs_##name(struct extent_buffer *eb, type *s) \ +static inline u##bits btrfs_##name(const struct extent_buffer *eb, \ + const type *s) \ { \ BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member); \ return btrfs_get_##bits(eb, s, offsetof(type, member)); \ @@ -2203,7 +2205,8 @@ static inline void btrfs_set_##name(stru BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member); \ btrfs_set_##bits(eb, s, offsetof(type, member), val); \ } \ -static inline u##bits btrfs_token_##name(struct extent_buffer *eb, type *s, \ +static inline u##bits btrfs_token_##name(const struct extent_buffer *eb,\ + const type *s, \ struct btrfs_map_token *token) \ { \ BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member); \ @@ -2218,9 +2221,9 @@ static inline void btrfs_set_token_##nam }
#define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \ -static inline u##bits btrfs_##name(struct extent_buffer *eb) \ +static inline u##bits btrfs_##name(const struct extent_buffer *eb) \ { \ - type *p = page_address(eb->pages[0]); \ + const type *p = page_address(eb->pages[0]); \ u##bits res = le##bits##_to_cpu(p->member); \ return res; \ } \ @@ -2232,7 +2235,7 @@ static inline void btrfs_set_##name(stru }
#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \ -static inline u##bits btrfs_##name(type *s) \ +static inline u##bits btrfs_##name(const type *s) \ { \ return le##bits##_to_cpu(s->member); \ } \ @@ -2558,7 +2561,7 @@ static inline unsigned long btrfs_node_k sizeof(struct btrfs_key_ptr) * nr; }
-void btrfs_node_key(struct extent_buffer *eb, +void btrfs_node_key(const struct extent_buffer *eb, struct btrfs_disk_key *disk_key, int nr);
static inline void btrfs_set_node_key(struct extent_buffer *eb, @@ -2587,28 +2590,28 @@ static inline struct btrfs_item *btrfs_i return (struct btrfs_item *)btrfs_item_nr_offset(nr); }
-static inline u32 btrfs_item_end(struct extent_buffer *eb, +static inline u32 btrfs_item_end(const struct extent_buffer *eb, struct btrfs_item *item) { return btrfs_item_offset(eb, item) + btrfs_item_size(eb, item); }
-static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr) +static inline u32 btrfs_item_end_nr(const struct extent_buffer *eb, int nr) { return btrfs_item_end(eb, btrfs_item_nr(nr)); }
-static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr) +static inline u32 btrfs_item_offset_nr(const struct extent_buffer *eb, int nr) { return btrfs_item_offset(eb, btrfs_item_nr(nr)); }
-static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr) +static inline u32 btrfs_item_size_nr(const struct extent_buffer *eb, int nr) { return btrfs_item_size(eb, btrfs_item_nr(nr)); }
-static inline void btrfs_item_key(struct extent_buffer *eb, +static inline void btrfs_item_key(const struct extent_buffer *eb, struct btrfs_disk_key *disk_key, int nr) { struct btrfs_item *item = btrfs_item_nr(nr); @@ -2644,8 +2647,8 @@ BTRFS_SETGET_STACK_FUNCS(stack_dir_name_ BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item, transid, 64);
-static inline void btrfs_dir_item_key(struct extent_buffer *eb, - struct btrfs_dir_item *item, +static inline void btrfs_dir_item_key(const struct extent_buffer *eb, + const struct btrfs_dir_item *item, struct btrfs_disk_key *key) { read_eb_member(eb, item, struct btrfs_dir_item, location, key); @@ -2653,7 +2656,7 @@ static inline void btrfs_dir_item_key(st
static inline void btrfs_set_dir_item_key(struct extent_buffer *eb, struct btrfs_dir_item *item, - struct btrfs_disk_key *key) + const struct btrfs_disk_key *key) { write_eb_member(eb, item, struct btrfs_dir_item, location, key); } @@ -2665,8 +2668,8 @@ BTRFS_SETGET_FUNCS(free_space_bitmaps, s BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header, generation, 64);
-static inline void btrfs_free_space_key(struct extent_buffer *eb, - struct btrfs_free_space_header *h, +static inline void btrfs_free_space_key(const struct extent_buffer *eb, + const struct btrfs_free_space_header *h, struct btrfs_disk_key *key) { read_eb_member(eb, h, struct btrfs_free_space_header, location, key); @@ -2674,7 +2677,7 @@ static inline void btrfs_free_space_key(
static inline void btrfs_set_free_space_key(struct extent_buffer *eb, struct btrfs_free_space_header *h, - struct btrfs_disk_key *key) + const struct btrfs_disk_key *key) { write_eb_member(eb, h, struct btrfs_free_space_header, location, key); } @@ -2701,25 +2704,25 @@ static inline void btrfs_cpu_key_to_disk disk->objectid = cpu_to_le64(cpu->objectid); }
-static inline void btrfs_node_key_to_cpu(struct extent_buffer *eb, - struct btrfs_key *key, int nr) +static inline void btrfs_node_key_to_cpu(const struct extent_buffer *eb, + struct btrfs_key *key, int nr) { struct btrfs_disk_key disk_key; btrfs_node_key(eb, &disk_key, nr); btrfs_disk_key_to_cpu(key, &disk_key); }
-static inline void btrfs_item_key_to_cpu(struct extent_buffer *eb, - struct btrfs_key *key, int nr) +static inline void btrfs_item_key_to_cpu(const struct extent_buffer *eb, + struct btrfs_key *key, int nr) { struct btrfs_disk_key disk_key; btrfs_item_key(eb, &disk_key, nr); btrfs_disk_key_to_cpu(key, &disk_key); }
-static inline void btrfs_dir_item_key_to_cpu(struct extent_buffer *eb, - struct btrfs_dir_item *item, - struct btrfs_key *key) +static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb, + const struct btrfs_dir_item *item, + struct btrfs_key *key) { struct btrfs_disk_key disk_key; btrfs_dir_item_key(eb, item, &disk_key); @@ -2752,7 +2755,7 @@ BTRFS_SETGET_STACK_FUNCS(stack_header_nr nritems, 32); BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64);
-static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag) +static inline int btrfs_header_flag(const struct extent_buffer *eb, u64 flag) { return (btrfs_header_flags(eb) & flag) == flag; } @@ -2771,7 +2774,7 @@ static inline int btrfs_clear_header_fla return (flags & flag) == flag; }
-static inline int btrfs_header_backref_rev(struct extent_buffer *eb) +static inline int btrfs_header_backref_rev(const struct extent_buffer *eb) { u64 flags = btrfs_header_flags(eb); return flags >> BTRFS_BACKREF_REV_SHIFT; @@ -2791,12 +2794,12 @@ static inline unsigned long btrfs_header return offsetof(struct btrfs_header, fsid); }
-static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb) +static inline unsigned long btrfs_header_chunk_tree_uuid(const struct extent_buffer *eb) { return offsetof(struct btrfs_header, chunk_tree_uuid); }
-static inline int btrfs_is_leaf(struct extent_buffer *eb) +static inline int btrfs_is_leaf(const struct extent_buffer *eb) { return btrfs_header_level(eb) == 0; } @@ -2830,12 +2833,12 @@ BTRFS_SETGET_STACK_FUNCS(root_stransid, BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item, rtransid, 64);
-static inline bool btrfs_root_readonly(struct btrfs_root *root) +static inline bool btrfs_root_readonly(const struct btrfs_root *root) { return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_RDONLY)) != 0; }
-static inline bool btrfs_root_dead(struct btrfs_root *root) +static inline bool btrfs_root_dead(const struct btrfs_root *root) { return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0; } @@ -2892,51 +2895,51 @@ BTRFS_SETGET_STACK_FUNCS(backup_num_devi /* struct btrfs_balance_item */ BTRFS_SETGET_FUNCS(balance_flags, struct btrfs_balance_item, flags, 64);
-static inline void btrfs_balance_data(struct extent_buffer *eb, - struct btrfs_balance_item *bi, +static inline void btrfs_balance_data(const struct extent_buffer *eb, + const struct btrfs_balance_item *bi, struct btrfs_disk_balance_args *ba) { read_eb_member(eb, bi, struct btrfs_balance_item, data, ba); }
static inline void btrfs_set_balance_data(struct extent_buffer *eb, - struct btrfs_balance_item *bi, - struct btrfs_disk_balance_args *ba) + struct btrfs_balance_item *bi, + const struct btrfs_disk_balance_args *ba) { write_eb_member(eb, bi, struct btrfs_balance_item, data, ba); }
-static inline void btrfs_balance_meta(struct extent_buffer *eb, - struct btrfs_balance_item *bi, +static inline void btrfs_balance_meta(const struct extent_buffer *eb, + const struct btrfs_balance_item *bi, struct btrfs_disk_balance_args *ba) { read_eb_member(eb, bi, struct btrfs_balance_item, meta, ba); }
static inline void btrfs_set_balance_meta(struct extent_buffer *eb, - struct btrfs_balance_item *bi, - struct btrfs_disk_balance_args *ba) + struct btrfs_balance_item *bi, + const struct btrfs_disk_balance_args *ba) { write_eb_member(eb, bi, struct btrfs_balance_item, meta, ba); }
-static inline void btrfs_balance_sys(struct extent_buffer *eb, - struct btrfs_balance_item *bi, +static inline void btrfs_balance_sys(const struct extent_buffer *eb, + const struct btrfs_balance_item *bi, struct btrfs_disk_balance_args *ba) { read_eb_member(eb, bi, struct btrfs_balance_item, sys, ba); }
static inline void btrfs_set_balance_sys(struct extent_buffer *eb, - struct btrfs_balance_item *bi, - struct btrfs_disk_balance_args *ba) + struct btrfs_balance_item *bi, + const struct btrfs_disk_balance_args *ba) { write_eb_member(eb, bi, struct btrfs_balance_item, sys, ba); }
static inline void btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu, - struct btrfs_disk_balance_args *disk) + const struct btrfs_disk_balance_args *disk) { memset(cpu, 0, sizeof(*cpu));
@@ -2954,7 +2957,7 @@ btrfs_disk_balance_args_to_cpu(struct bt
static inline void btrfs_cpu_balance_args_to_disk(struct btrfs_disk_balance_args *disk, - struct btrfs_balance_args *cpu) + const struct btrfs_balance_args *cpu) { memset(disk, 0, sizeof(*disk));
@@ -3022,7 +3025,7 @@ BTRFS_SETGET_STACK_FUNCS(super_magic, st BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block, uuid_tree_generation, 64);
-static inline int btrfs_super_csum_size(struct btrfs_super_block *s) +static inline int btrfs_super_csum_size(const struct btrfs_super_block *s) { u16 t = btrfs_super_csum_type(s); /* @@ -3041,8 +3044,8 @@ static inline unsigned long btrfs_leaf_d * this returns the address of the start of the last item, * which is the stop of the leaf data stack */ -static inline unsigned int leaf_data_end(struct btrfs_root *root, - struct extent_buffer *leaf) +static inline unsigned int leaf_data_end(const struct btrfs_root *root, + const struct extent_buffer *leaf) { u32 nr = btrfs_header_nritems(leaf);
@@ -3067,7 +3070,7 @@ BTRFS_SETGET_STACK_FUNCS(stack_file_exte struct btrfs_file_extent_item, compression, 8);
static inline unsigned long -btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e) +btrfs_file_extent_inline_start(const struct btrfs_file_extent_item *e) { return (unsigned long)e + BTRFS_FILE_EXTENT_INLINE_DATA_START; } @@ -3101,8 +3104,9 @@ BTRFS_SETGET_FUNCS(file_extent_other_enc * size of any extent headers. If a file is compressed on disk, this is * the compressed size */ -static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb, - struct btrfs_item *e) +static inline u32 btrfs_file_extent_inline_item_len( + const struct extent_buffer *eb, + struct btrfs_item *e) { return btrfs_item_size(eb, e) - BTRFS_FILE_EXTENT_INLINE_DATA_START; } @@ -3110,9 +3114,9 @@ static inline u32 btrfs_file_extent_inli /* this returns the number of file bytes represented by the inline item. * If an item is compressed, this is the uncompressed size */ -static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb, - int slot, - struct btrfs_file_extent_item *fi) +static inline u32 btrfs_file_extent_inline_len(const struct extent_buffer *eb, + int slot, + const struct btrfs_file_extent_item *fi) { struct btrfs_map_token token;
@@ -3134,8 +3138,8 @@ static inline u32 btrfs_file_extent_inli
/* btrfs_dev_stats_item */ -static inline u64 btrfs_dev_stats_value(struct extent_buffer *eb, - struct btrfs_dev_stats_item *ptr, +static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb, + const struct btrfs_dev_stats_item *ptr, int index) { u64 val; --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -5111,9 +5111,8 @@ unlock_exit: return ret; }
-void read_extent_buffer(struct extent_buffer *eb, void *dstv, - unsigned long start, - unsigned long len) +void read_extent_buffer(const struct extent_buffer *eb, void *dstv, + unsigned long start, unsigned long len) { size_t cur; size_t offset; @@ -5142,9 +5141,9 @@ void read_extent_buffer(struct extent_bu } }
-int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dstv, - unsigned long start, - unsigned long len) +int read_extent_buffer_to_user(const struct extent_buffer *eb, + void __user *dstv, + unsigned long start, unsigned long len) { size_t cur; size_t offset; @@ -5179,10 +5178,10 @@ int read_extent_buffer_to_user(struct ex return ret; }
-int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, - unsigned long min_len, char **map, - unsigned long *map_start, - unsigned long *map_len) +int map_private_extent_buffer(const struct extent_buffer *eb, + unsigned long start, unsigned long min_len, + char **map, unsigned long *map_start, + unsigned long *map_len) { size_t offset = start & (PAGE_CACHE_SIZE - 1); char *kaddr; @@ -5217,9 +5216,8 @@ int map_private_extent_buffer(struct ext return 0; }
-int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv, - unsigned long start, - unsigned long len) +int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv, + unsigned long start, unsigned long len) { size_t cur; size_t offset; --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -291,14 +291,13 @@ static inline void extent_buffer_get(str atomic_inc(&eb->refs); }
-int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv, - unsigned long start, - unsigned long len); -void read_extent_buffer(struct extent_buffer *eb, void *dst, +int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv, + unsigned long start, unsigned long len); +void read_extent_buffer(const struct extent_buffer *eb, void *dst, unsigned long start, unsigned long len); -int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dst, - unsigned long start, +int read_extent_buffer_to_user(const struct extent_buffer *eb, + void __user *dst, unsigned long start, unsigned long len); void write_extent_buffer(struct extent_buffer *eb, const void *src, unsigned long start, unsigned long len); @@ -317,10 +316,10 @@ int set_extent_buffer_uptodate(struct ex int clear_extent_buffer_uptodate(struct extent_buffer *eb); int extent_buffer_uptodate(struct extent_buffer *eb); int extent_buffer_under_io(struct extent_buffer *eb); -int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset, - unsigned long min_len, char **map, - unsigned long *map_start, - unsigned long *map_len); +int map_private_extent_buffer(const struct extent_buffer *eb, + unsigned long offset, unsigned long min_len, + char **map, unsigned long *map_start, + unsigned long *map_len); int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end); int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end); int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end, --- a/fs/btrfs/struct-funcs.c +++ b/fs/btrfs/struct-funcs.c @@ -50,8 +50,8 @@ static inline void put_unaligned_le8(u8 */
#define DEFINE_BTRFS_SETGET_BITS(bits) \ -u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr, \ - unsigned long off, \ +u##bits btrfs_get_token_##bits(const struct extent_buffer *eb, \ + const void *ptr, unsigned long off, \ struct btrfs_map_token *token) \ { \ unsigned long part_offset = (unsigned long)ptr; \ @@ -90,7 +90,8 @@ u##bits btrfs_get_token_##bits(struct ex return res; \ } \ void btrfs_set_token_##bits(struct extent_buffer *eb, \ - void *ptr, unsigned long off, u##bits val, \ + const void *ptr, unsigned long off, \ + u##bits val, \ struct btrfs_map_token *token) \ { \ unsigned long part_offset = (unsigned long)ptr; \ @@ -133,7 +134,7 @@ DEFINE_BTRFS_SETGET_BITS(16) DEFINE_BTRFS_SETGET_BITS(32) DEFINE_BTRFS_SETGET_BITS(64)
-void btrfs_node_key(struct extent_buffer *eb, +void btrfs_node_key(const struct extent_buffer *eb, struct btrfs_disk_key *disk_key, int nr) { unsigned long ptr = btrfs_node_key_ptr_offset(nr);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo quwenruo.btrfs@gmx.com
commit c3267bbaa9cae09b62960eafe33ad19196803285 upstream.
Current check_leaf() function does a good job checking key order and item offset/size.
However it only checks from slot 0 to the last but one slot, this is good but makes later expansion hard.
So this refactoring iterates from slot 0 to the last slot. For key comparison, it uses a key with all 0 as initial key, so all valid keys should be larger than that.
And for item size/offset checks, it compares current item end with previous item offset. For slot 0, use leaf end as a special case.
This makes later item/key offset checks and item size checks easier to be implemented.
Also, makes check_leaf() to return -EUCLEAN other than -EIO to indicate error.
Signed-off-by: Qu Wenruo quwenruo.btrfs@gmx.com Reviewed-by: Nikolay Borisov nborisov@suse.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: - BTRFS_LEAF_DATA_SIZE() takes a root rather than an fs_info - Adjust context] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/disk-io.c | 50 +++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 23 deletions(-)
--- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -516,8 +516,9 @@ static int check_tree_block_fsid(struct static noinline int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf) { + /* No valid key type is 0, so all key should be larger than this key */ + struct btrfs_key prev_key = {0, 0, 0}; struct btrfs_key key; - struct btrfs_key leaf_key; u32 nritems = btrfs_header_nritems(leaf); int slot;
@@ -550,7 +551,7 @@ static noinline int check_leaf(struct bt CORRUPT("non-root leaf's nritems is 0", leaf, check_root, 0); free_extent_buffer(eb); - return -EIO; + return -EUCLEAN; } free_extent_buffer(eb); } @@ -560,28 +561,23 @@ static noinline int check_leaf(struct bt if (nritems == 0) return 0;
- /* Check the 0 item */ - if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) != - BTRFS_LEAF_DATA_SIZE(root)) { - CORRUPT("invalid item offset size pair", leaf, root, 0); - return -EIO; - } - /* - * Check to make sure each items keys are in the correct order and their - * offsets make sense. We only have to loop through nritems-1 because - * we check the current slot against the next slot, which verifies the - * next slot's offset+size makes sense and that the current's slot - * offset is correct. + * Check the following things to make sure this is a good leaf, and + * leaf users won't need to bother with similar sanity checks: + * + * 1) key order + * 2) item offset and size + * No overlap, no hole, all inside the leaf. */ - for (slot = 0; slot < nritems - 1; slot++) { - btrfs_item_key_to_cpu(leaf, &leaf_key, slot); - btrfs_item_key_to_cpu(leaf, &key, slot + 1); + for (slot = 0; slot < nritems; slot++) { + u32 item_end_expected; + + btrfs_item_key_to_cpu(leaf, &key, slot);
/* Make sure the keys are in the right order */ - if (btrfs_comp_cpu_keys(&leaf_key, &key) >= 0) { + if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) { CORRUPT("bad key order", leaf, root, slot); - return -EIO; + return -EUCLEAN; }
/* @@ -589,10 +585,14 @@ static noinline int check_leaf(struct bt * item data starts at the end of the leaf and grows towards the * front. */ - if (btrfs_item_offset_nr(leaf, slot) != - btrfs_item_end_nr(leaf, slot + 1)) { + if (slot == 0) + item_end_expected = BTRFS_LEAF_DATA_SIZE(root); + else + item_end_expected = btrfs_item_offset_nr(leaf, + slot - 1); + if (btrfs_item_end_nr(leaf, slot) != item_end_expected) { CORRUPT("slot offset bad", leaf, root, slot); - return -EIO; + return -EUCLEAN; }
/* @@ -603,8 +603,12 @@ static noinline int check_leaf(struct bt if (btrfs_item_end_nr(leaf, slot) > BTRFS_LEAF_DATA_SIZE(root)) { CORRUPT("slot end outside of leaf", leaf, root, slot); - return -EIO; + return -EUCLEAN; } + + prev_key.objectid = key.objectid; + prev_key.type = key.type; + prev_key.offset = key.offset; }
return 0;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo quwenruo.btrfs@gmx.com
commit 7f43d4affb2a254d421ab20b0cf65ac2569909fb upstream.
Function check_leaf() checks if any item pointer points outside of the leaf, but it doesn't check if the pointer overlaps with the item itself.
Normally only the last item may be the victim, but adding such check is never a bad idea anyway.
Signed-off-by: Qu Wenruo quwenruo.btrfs@gmx.com Reviewed-by: Nikolay Borisov nborisov@suse.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/disk-io.c | 7 +++++++ 1 file changed, 7 insertions(+)
--- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -606,6 +606,13 @@ static noinline int check_leaf(struct bt return -EUCLEAN; }
+ /* Also check if the item pointer overlaps with btrfs item. */ + if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) > + btrfs_item_ptr_offset(leaf, slot)) { + CORRUPT("slot overlap with its data", leaf, root, slot); + return -EUCLEAN; + } + prev_key.objectid = key.objectid; prev_key.type = key.type; prev_key.offset = key.offset;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo quwenruo.btrfs@gmx.com
commit 40c3c40947324d9f40bf47830c92c59a9bbadf4a upstream.
Add extra checks for item with EXTENT_DATA type. This checks the following thing:
0) Key offset All key offsets must be aligned to sectorsize. Inline extent must have 0 for key offset.
1) Item size Uncompressed inline file extent size must match item size. (Compressed inline file extent has no information about its on-disk size.) Regular/preallocated file extent size must be a fixed value.
2) Every member of regular file extent item Including alignment for bytenr and offset, possible value for compression/encryption/type.
3) Type/compression/encode must be one of the valid values.
This should be the most comprehensive and strict check in the context of btrfs_item for EXTENT_DATA.
Signed-off-by: Qu Wenruo quwenruo.btrfs@gmx.com Reviewed-by: Nikolay Borisov nborisov@suse.com Reviewed-by: David Sterba dsterba@suse.com [ switch to BTRFS_FILE_EXTENT_TYPES, similar to what BTRFS_COMPRESS_TYPES does ] Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: - Use root->sectorsize instead of root->fs_info->sectorsize - Adjust filename] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/ctree.h | 1 + fs/btrfs/disk-io.c | 103 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+)
--- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -874,6 +874,7 @@ struct btrfs_balance_item { #define BTRFS_FILE_EXTENT_INLINE 0 #define BTRFS_FILE_EXTENT_REG 1 #define BTRFS_FILE_EXTENT_PREALLOC 2 +#define BTRFS_FILE_EXTENT_TYPES 2
struct btrfs_file_extent_item { /* --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -513,6 +513,100 @@ static int check_tree_block_fsid(struct btrfs_header_level(eb) == 0 ? "leaf" : "node",\ reason, btrfs_header_bytenr(eb), root->objectid, slot)
+static int check_extent_data_item(struct btrfs_root *root, + struct extent_buffer *leaf, + struct btrfs_key *key, int slot) +{ + struct btrfs_file_extent_item *fi; + u32 sectorsize = root->sectorsize; + u32 item_size = btrfs_item_size_nr(leaf, slot); + + if (!IS_ALIGNED(key->offset, sectorsize)) { + CORRUPT("unaligned key offset for file extent", + leaf, root, slot); + return -EUCLEAN; + } + + fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); + + if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) { + CORRUPT("invalid file extent type", leaf, root, slot); + return -EUCLEAN; + } + + /* + * Support for new compression/encrption must introduce incompat flag, + * and must be caught in open_ctree(). + */ + if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) { + CORRUPT("invalid file extent compression", leaf, root, slot); + return -EUCLEAN; + } + if (btrfs_file_extent_encryption(leaf, fi)) { + CORRUPT("invalid file extent encryption", leaf, root, slot); + return -EUCLEAN; + } + if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) { + /* Inline extent must have 0 as key offset */ + if (key->offset) { + CORRUPT("inline extent has non-zero key offset", + leaf, root, slot); + return -EUCLEAN; + } + + /* Compressed inline extent has no on-disk size, skip it */ + if (btrfs_file_extent_compression(leaf, fi) != + BTRFS_COMPRESS_NONE) + return 0; + + /* Uncompressed inline extent size must match item size */ + if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START + + btrfs_file_extent_ram_bytes(leaf, fi)) { + CORRUPT("plaintext inline extent has invalid size", + leaf, root, slot); + return -EUCLEAN; + } + return 0; + } + + /* Regular or preallocated extent has fixed item size */ + if (item_size != sizeof(*fi)) { + CORRUPT( + "regluar or preallocated extent data item size is invalid", + leaf, root, slot); + return -EUCLEAN; + } + if (!IS_ALIGNED(btrfs_file_extent_ram_bytes(leaf, fi), sectorsize) || + !IS_ALIGNED(btrfs_file_extent_disk_bytenr(leaf, fi), sectorsize) || + !IS_ALIGNED(btrfs_file_extent_disk_num_bytes(leaf, fi), sectorsize) || + !IS_ALIGNED(btrfs_file_extent_offset(leaf, fi), sectorsize) || + !IS_ALIGNED(btrfs_file_extent_num_bytes(leaf, fi), sectorsize)) { + CORRUPT( + "regular or preallocated extent data item has unaligned value", + leaf, root, slot); + return -EUCLEAN; + } + + return 0; +} + +/* + * Common point to switch the item-specific validation. + */ +static int check_leaf_item(struct btrfs_root *root, + struct extent_buffer *leaf, + struct btrfs_key *key, int slot) +{ + int ret = 0; + + switch (key->type) { + case BTRFS_EXTENT_DATA_KEY: + ret = check_extent_data_item(root, leaf, key, slot); + break; + } + return ret; +} + static noinline int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf) { @@ -568,9 +662,13 @@ static noinline int check_leaf(struct bt * 1) key order * 2) item offset and size * No overlap, no hole, all inside the leaf. + * 3) item content + * If possible, do comprehensive sanity check. + * NOTE: All checks must only rely on the item data itself. */ for (slot = 0; slot < nritems; slot++) { u32 item_end_expected; + int ret;
btrfs_item_key_to_cpu(leaf, &key, slot);
@@ -613,6 +711,11 @@ static noinline int check_leaf(struct bt return -EUCLEAN; }
+ /* Check if the item size and content meet other criteria */ + ret = check_leaf_item(root, leaf, &key, slot); + if (ret < 0) + return ret; + prev_key.objectid = key.objectid; prev_key.type = key.type; prev_key.offset = key.offset;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo quwenruo.btrfs@gmx.com
commit 4b865cab96fe2a30ed512cf667b354bd291b3b0a upstream.
EXTENT_CSUM checker is a relatively easy one, only needs to check:
1) Objectid Fixed to BTRFS_EXTENT_CSUM_OBJECTID
2) Key offset alignment Must be aligned to sectorsize
3) Item size alignedment Must be aligned to csum size
Signed-off-by: Qu Wenruo quwenruo.btrfs@gmx.com Reviewed-by: Nikolay Borisov nborisov@suse.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: Use root->sectorsize instead of root->fs_info->sectorsize] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/disk-io.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
--- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -590,6 +590,27 @@ static int check_extent_data_item(struct return 0; }
+static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf, + struct btrfs_key *key, int slot) +{ + u32 sectorsize = root->sectorsize; + u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy); + + if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) { + CORRUPT("invalid objectid for csum item", leaf, root, slot); + return -EUCLEAN; + } + if (!IS_ALIGNED(key->offset, sectorsize)) { + CORRUPT("unaligned key offset for csum item", leaf, root, slot); + return -EUCLEAN; + } + if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) { + CORRUPT("unaligned csum item size", leaf, root, slot); + return -EUCLEAN; + } + return 0; +} + /* * Common point to switch the item-specific validation. */ @@ -603,6 +624,9 @@ static int check_leaf_item(struct btrfs_ case BTRFS_EXTENT_DATA_KEY: ret = check_extent_data_item(root, leaf, key, slot); break; + case BTRFS_EXTENT_CSUM_KEY: + ret = check_csum_item(root, leaf, key, slot); + break; } return ret; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo quwenruo.btrfs@gmx.com
commit 557ea5dd003d371536f6b4e8f7c8209a2b6fd4e3 upstream.
It's no doubt the comprehensive tree block checker will become larger, so moving them into their own files is quite reasonable.
Signed-off-by: Qu Wenruo quwenruo.btrfs@gmx.com [ wording adjustments ] Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: - The moved code is slightly different - Adjust context] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/Makefile | 2 +- fs/btrfs/disk-io.c | 284 +----------------------------------- fs/btrfs/tree-checker.c | 309 ++++++++++++++++++++++++++++++++++++++++ fs/btrfs/tree-checker.h | 26 ++++ 4 files changed, 340 insertions(+), 281 deletions(-) create mode 100644 fs/btrfs/tree-checker.c create mode 100644 fs/btrfs/tree-checker.h
--- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile @@ -9,7 +9,7 @@ btrfs-y += super.o ctree.o extent-tree.o export.o tree-log.o free-space-cache.o zlib.o lzo.o \ compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \ reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \ - uuid-tree.o props.o hash.o + uuid-tree.o props.o hash.o tree-checker.o
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -49,6 +49,7 @@ #include "raid56.h" #include "sysfs.h" #include "qgroup.h" +#include "tree-checker.h"
#ifdef CONFIG_X86 #include <asm/cpufeature.h> @@ -507,283 +508,6 @@ static int check_tree_block_fsid(struct return ret; }
-#define CORRUPT(reason, eb, root, slot) \ - btrfs_crit(root->fs_info, "corrupt %s, %s: block=%llu," \ - " root=%llu, slot=%d", \ - btrfs_header_level(eb) == 0 ? "leaf" : "node",\ - reason, btrfs_header_bytenr(eb), root->objectid, slot) - -static int check_extent_data_item(struct btrfs_root *root, - struct extent_buffer *leaf, - struct btrfs_key *key, int slot) -{ - struct btrfs_file_extent_item *fi; - u32 sectorsize = root->sectorsize; - u32 item_size = btrfs_item_size_nr(leaf, slot); - - if (!IS_ALIGNED(key->offset, sectorsize)) { - CORRUPT("unaligned key offset for file extent", - leaf, root, slot); - return -EUCLEAN; - } - - fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); - - if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) { - CORRUPT("invalid file extent type", leaf, root, slot); - return -EUCLEAN; - } - - /* - * Support for new compression/encrption must introduce incompat flag, - * and must be caught in open_ctree(). - */ - if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) { - CORRUPT("invalid file extent compression", leaf, root, slot); - return -EUCLEAN; - } - if (btrfs_file_extent_encryption(leaf, fi)) { - CORRUPT("invalid file extent encryption", leaf, root, slot); - return -EUCLEAN; - } - if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) { - /* Inline extent must have 0 as key offset */ - if (key->offset) { - CORRUPT("inline extent has non-zero key offset", - leaf, root, slot); - return -EUCLEAN; - } - - /* Compressed inline extent has no on-disk size, skip it */ - if (btrfs_file_extent_compression(leaf, fi) != - BTRFS_COMPRESS_NONE) - return 0; - - /* Uncompressed inline extent size must match item size */ - if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START + - btrfs_file_extent_ram_bytes(leaf, fi)) { - CORRUPT("plaintext inline extent has invalid size", - leaf, root, slot); - return -EUCLEAN; - } - return 0; - } - - /* Regular or preallocated extent has fixed item size */ - if (item_size != sizeof(*fi)) { - CORRUPT( - "regluar or preallocated extent data item size is invalid", - leaf, root, slot); - return -EUCLEAN; - } - if (!IS_ALIGNED(btrfs_file_extent_ram_bytes(leaf, fi), sectorsize) || - !IS_ALIGNED(btrfs_file_extent_disk_bytenr(leaf, fi), sectorsize) || - !IS_ALIGNED(btrfs_file_extent_disk_num_bytes(leaf, fi), sectorsize) || - !IS_ALIGNED(btrfs_file_extent_offset(leaf, fi), sectorsize) || - !IS_ALIGNED(btrfs_file_extent_num_bytes(leaf, fi), sectorsize)) { - CORRUPT( - "regular or preallocated extent data item has unaligned value", - leaf, root, slot); - return -EUCLEAN; - } - - return 0; -} - -static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf, - struct btrfs_key *key, int slot) -{ - u32 sectorsize = root->sectorsize; - u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy); - - if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) { - CORRUPT("invalid objectid for csum item", leaf, root, slot); - return -EUCLEAN; - } - if (!IS_ALIGNED(key->offset, sectorsize)) { - CORRUPT("unaligned key offset for csum item", leaf, root, slot); - return -EUCLEAN; - } - if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) { - CORRUPT("unaligned csum item size", leaf, root, slot); - return -EUCLEAN; - } - return 0; -} - -/* - * Common point to switch the item-specific validation. - */ -static int check_leaf_item(struct btrfs_root *root, - struct extent_buffer *leaf, - struct btrfs_key *key, int slot) -{ - int ret = 0; - - switch (key->type) { - case BTRFS_EXTENT_DATA_KEY: - ret = check_extent_data_item(root, leaf, key, slot); - break; - case BTRFS_EXTENT_CSUM_KEY: - ret = check_csum_item(root, leaf, key, slot); - break; - } - return ret; -} - -static noinline int check_leaf(struct btrfs_root *root, - struct extent_buffer *leaf) -{ - /* No valid key type is 0, so all key should be larger than this key */ - struct btrfs_key prev_key = {0, 0, 0}; - struct btrfs_key key; - u32 nritems = btrfs_header_nritems(leaf); - int slot; - - /* - * Extent buffers from a relocation tree have a owner field that - * corresponds to the subvolume tree they are based on. So just from an - * extent buffer alone we can not find out what is the id of the - * corresponding subvolume tree, so we can not figure out if the extent - * buffer corresponds to the root of the relocation tree or not. So skip - * this check for relocation trees. - */ - if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) { - struct btrfs_root *check_root; - - key.objectid = btrfs_header_owner(leaf); - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - check_root = btrfs_get_fs_root(root->fs_info, &key, false); - /* - * The only reason we also check NULL here is that during - * open_ctree() some roots has not yet been set up. - */ - if (!IS_ERR_OR_NULL(check_root)) { - struct extent_buffer *eb; - - eb = btrfs_root_node(check_root); - /* if leaf is the root, then it's fine */ - if (leaf != eb) { - CORRUPT("non-root leaf's nritems is 0", - leaf, check_root, 0); - free_extent_buffer(eb); - return -EUCLEAN; - } - free_extent_buffer(eb); - } - return 0; - } - - if (nritems == 0) - return 0; - - /* - * Check the following things to make sure this is a good leaf, and - * leaf users won't need to bother with similar sanity checks: - * - * 1) key order - * 2) item offset and size - * No overlap, no hole, all inside the leaf. - * 3) item content - * If possible, do comprehensive sanity check. - * NOTE: All checks must only rely on the item data itself. - */ - for (slot = 0; slot < nritems; slot++) { - u32 item_end_expected; - int ret; - - btrfs_item_key_to_cpu(leaf, &key, slot); - - /* Make sure the keys are in the right order */ - if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) { - CORRUPT("bad key order", leaf, root, slot); - return -EUCLEAN; - } - - /* - * Make sure the offset and ends are right, remember that the - * item data starts at the end of the leaf and grows towards the - * front. - */ - if (slot == 0) - item_end_expected = BTRFS_LEAF_DATA_SIZE(root); - else - item_end_expected = btrfs_item_offset_nr(leaf, - slot - 1); - if (btrfs_item_end_nr(leaf, slot) != item_end_expected) { - CORRUPT("slot offset bad", leaf, root, slot); - return -EUCLEAN; - } - - /* - * Check to make sure that we don't point outside of the leaf, - * just incase all the items are consistent to eachother, but - * all point outside of the leaf. - */ - if (btrfs_item_end_nr(leaf, slot) > - BTRFS_LEAF_DATA_SIZE(root)) { - CORRUPT("slot end outside of leaf", leaf, root, slot); - return -EUCLEAN; - } - - /* Also check if the item pointer overlaps with btrfs item. */ - if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) > - btrfs_item_ptr_offset(leaf, slot)) { - CORRUPT("slot overlap with its data", leaf, root, slot); - return -EUCLEAN; - } - - /* Check if the item size and content meet other criteria */ - ret = check_leaf_item(root, leaf, &key, slot); - if (ret < 0) - return ret; - - prev_key.objectid = key.objectid; - prev_key.type = key.type; - prev_key.offset = key.offset; - } - - return 0; -} - -static int check_node(struct btrfs_root *root, struct extent_buffer *node) -{ - unsigned long nr = btrfs_header_nritems(node); - struct btrfs_key key, next_key; - int slot; - u64 bytenr; - int ret = 0; - - if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) { - btrfs_crit(root->fs_info, - "corrupt node: block %llu root %llu nritems %lu", - node->start, root->objectid, nr); - return -EIO; - } - - for (slot = 0; slot < nr - 1; slot++) { - bytenr = btrfs_node_blockptr(node, slot); - btrfs_node_key_to_cpu(node, &key, slot); - btrfs_node_key_to_cpu(node, &next_key, slot + 1); - - if (!bytenr) { - CORRUPT("invalid item slot", node, root, slot); - ret = -EIO; - goto out; - } - - if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) { - CORRUPT("bad key order", node, root, slot); - ret = -EIO; - goto out; - } - } -out: - return ret; -} - static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, u64 phy_offset, struct page *page, u64 start, u64 end, int mirror) @@ -851,12 +575,12 @@ static int btree_readpage_end_io_hook(st * that we don't try and read the other copies of this block, just * return -EIO. */ - if (found_level == 0 && check_leaf(root, eb)) { + if (found_level == 0 && btrfs_check_leaf(root, eb)) { set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags); ret = -EIO; }
- if (found_level > 0 && check_node(root, eb)) + if (found_level > 0 && btrfs_check_node(root, eb)) ret = -EIO;
if (!ret) @@ -3978,7 +3702,7 @@ void btrfs_mark_buffer_dirty(struct exte buf->len, root->fs_info->dirty_metadata_batch); #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - if (btrfs_header_level(buf) == 0 && check_leaf(root, buf)) { + if (btrfs_header_level(buf) == 0 && btrfs_check_leaf(root, buf)) { btrfs_print_leaf(root, buf); ASSERT(0); } --- /dev/null +++ b/fs/btrfs/tree-checker.c @@ -0,0 +1,309 @@ +/* + * Copyright (C) Qu Wenruo 2017. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + */ + +/* + * The module is used to catch unexpected/corrupted tree block data. + * Such behavior can be caused either by a fuzzed image or bugs. + * + * The objective is to do leaf/node validation checks when tree block is read + * from disk, and check *every* possible member, so other code won't + * need to checking them again. + * + * Due to the potential and unwanted damage, every checker needs to be + * carefully reviewed otherwise so it does not prevent mount of valid images. + */ + +#include "ctree.h" +#include "tree-checker.h" +#include "disk-io.h" +#include "compression.h" + +#define CORRUPT(reason, eb, root, slot) \ + btrfs_crit(root->fs_info, \ + "corrupt %s, %s: block=%llu, root=%llu, slot=%d", \ + btrfs_header_level(eb) == 0 ? "leaf" : "node", \ + reason, btrfs_header_bytenr(eb), root->objectid, slot) + +static int check_extent_data_item(struct btrfs_root *root, + struct extent_buffer *leaf, + struct btrfs_key *key, int slot) +{ + struct btrfs_file_extent_item *fi; + u32 sectorsize = root->sectorsize; + u32 item_size = btrfs_item_size_nr(leaf, slot); + + if (!IS_ALIGNED(key->offset, sectorsize)) { + CORRUPT("unaligned key offset for file extent", + leaf, root, slot); + return -EUCLEAN; + } + + fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); + + if (btrfs_file_extent_type(leaf, fi) > BTRFS_FILE_EXTENT_TYPES) { + CORRUPT("invalid file extent type", leaf, root, slot); + return -EUCLEAN; + } + + /* + * Support for new compression/encrption must introduce incompat flag, + * and must be caught in open_ctree(). + */ + if (btrfs_file_extent_compression(leaf, fi) > BTRFS_COMPRESS_TYPES) { + CORRUPT("invalid file extent compression", leaf, root, slot); + return -EUCLEAN; + } + if (btrfs_file_extent_encryption(leaf, fi)) { + CORRUPT("invalid file extent encryption", leaf, root, slot); + return -EUCLEAN; + } + if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) { + /* Inline extent must have 0 as key offset */ + if (key->offset) { + CORRUPT("inline extent has non-zero key offset", + leaf, root, slot); + return -EUCLEAN; + } + + /* Compressed inline extent has no on-disk size, skip it */ + if (btrfs_file_extent_compression(leaf, fi) != + BTRFS_COMPRESS_NONE) + return 0; + + /* Uncompressed inline extent size must match item size */ + if (item_size != BTRFS_FILE_EXTENT_INLINE_DATA_START + + btrfs_file_extent_ram_bytes(leaf, fi)) { + CORRUPT("plaintext inline extent has invalid size", + leaf, root, slot); + return -EUCLEAN; + } + return 0; + } + + /* Regular or preallocated extent has fixed item size */ + if (item_size != sizeof(*fi)) { + CORRUPT( + "regluar or preallocated extent data item size is invalid", + leaf, root, slot); + return -EUCLEAN; + } + if (!IS_ALIGNED(btrfs_file_extent_ram_bytes(leaf, fi), sectorsize) || + !IS_ALIGNED(btrfs_file_extent_disk_bytenr(leaf, fi), sectorsize) || + !IS_ALIGNED(btrfs_file_extent_disk_num_bytes(leaf, fi), sectorsize) || + !IS_ALIGNED(btrfs_file_extent_offset(leaf, fi), sectorsize) || + !IS_ALIGNED(btrfs_file_extent_num_bytes(leaf, fi), sectorsize)) { + CORRUPT( + "regular or preallocated extent data item has unaligned value", + leaf, root, slot); + return -EUCLEAN; + } + + return 0; +} + +static int check_csum_item(struct btrfs_root *root, struct extent_buffer *leaf, + struct btrfs_key *key, int slot) +{ + u32 sectorsize = root->sectorsize; + u32 csumsize = btrfs_super_csum_size(root->fs_info->super_copy); + + if (key->objectid != BTRFS_EXTENT_CSUM_OBJECTID) { + CORRUPT("invalid objectid for csum item", leaf, root, slot); + return -EUCLEAN; + } + if (!IS_ALIGNED(key->offset, sectorsize)) { + CORRUPT("unaligned key offset for csum item", leaf, root, slot); + return -EUCLEAN; + } + if (!IS_ALIGNED(btrfs_item_size_nr(leaf, slot), csumsize)) { + CORRUPT("unaligned csum item size", leaf, root, slot); + return -EUCLEAN; + } + return 0; +} + +/* + * Common point to switch the item-specific validation. + */ +static int check_leaf_item(struct btrfs_root *root, + struct extent_buffer *leaf, + struct btrfs_key *key, int slot) +{ + int ret = 0; + + switch (key->type) { + case BTRFS_EXTENT_DATA_KEY: + ret = check_extent_data_item(root, leaf, key, slot); + break; + case BTRFS_EXTENT_CSUM_KEY: + ret = check_csum_item(root, leaf, key, slot); + break; + } + return ret; +} + +int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf) +{ + struct btrfs_fs_info *fs_info = root->fs_info; + /* No valid key type is 0, so all key should be larger than this key */ + struct btrfs_key prev_key = {0, 0, 0}; + struct btrfs_key key; + u32 nritems = btrfs_header_nritems(leaf); + int slot; + + /* + * Extent buffers from a relocation tree have a owner field that + * corresponds to the subvolume tree they are based on. So just from an + * extent buffer alone we can not find out what is the id of the + * corresponding subvolume tree, so we can not figure out if the extent + * buffer corresponds to the root of the relocation tree or not. So + * skip this check for relocation trees. + */ + if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) { + struct btrfs_root *check_root; + + key.objectid = btrfs_header_owner(leaf); + key.type = BTRFS_ROOT_ITEM_KEY; + key.offset = (u64)-1; + + check_root = btrfs_get_fs_root(fs_info, &key, false); + /* + * The only reason we also check NULL here is that during + * open_ctree() some roots has not yet been set up. + */ + if (!IS_ERR_OR_NULL(check_root)) { + struct extent_buffer *eb; + + eb = btrfs_root_node(check_root); + /* if leaf is the root, then it's fine */ + if (leaf != eb) { + CORRUPT("non-root leaf's nritems is 0", + leaf, check_root, 0); + free_extent_buffer(eb); + return -EUCLEAN; + } + free_extent_buffer(eb); + } + return 0; + } + + if (nritems == 0) + return 0; + + /* + * Check the following things to make sure this is a good leaf, and + * leaf users won't need to bother with similar sanity checks: + * + * 1) key ordering + * 2) item offset and size + * No overlap, no hole, all inside the leaf. + * 3) item content + * If possible, do comprehensive sanity check. + * NOTE: All checks must only rely on the item data itself. + */ + for (slot = 0; slot < nritems; slot++) { + u32 item_end_expected; + int ret; + + btrfs_item_key_to_cpu(leaf, &key, slot); + + /* Make sure the keys are in the right order */ + if (btrfs_comp_cpu_keys(&prev_key, &key) >= 0) { + CORRUPT("bad key order", leaf, root, slot); + return -EUCLEAN; + } + + /* + * Make sure the offset and ends are right, remember that the + * item data starts at the end of the leaf and grows towards the + * front. + */ + if (slot == 0) + item_end_expected = BTRFS_LEAF_DATA_SIZE(root); + else + item_end_expected = btrfs_item_offset_nr(leaf, + slot - 1); + if (btrfs_item_end_nr(leaf, slot) != item_end_expected) { + CORRUPT("slot offset bad", leaf, root, slot); + return -EUCLEAN; + } + + /* + * Check to make sure that we don't point outside of the leaf, + * just in case all the items are consistent to each other, but + * all point outside of the leaf. + */ + if (btrfs_item_end_nr(leaf, slot) > + BTRFS_LEAF_DATA_SIZE(root)) { + CORRUPT("slot end outside of leaf", leaf, root, slot); + return -EUCLEAN; + } + + /* Also check if the item pointer overlaps with btrfs item. */ + if (btrfs_item_nr_offset(slot) + sizeof(struct btrfs_item) > + btrfs_item_ptr_offset(leaf, slot)) { + CORRUPT("slot overlap with its data", leaf, root, slot); + return -EUCLEAN; + } + + /* Check if the item size and content meet other criteria */ + ret = check_leaf_item(root, leaf, &key, slot); + if (ret < 0) + return ret; + + prev_key.objectid = key.objectid; + prev_key.type = key.type; + prev_key.offset = key.offset; + } + + return 0; +} + +int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node) +{ + unsigned long nr = btrfs_header_nritems(node); + struct btrfs_key key, next_key; + int slot; + u64 bytenr; + int ret = 0; + + if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) { + btrfs_crit(root->fs_info, + "corrupt node: block %llu root %llu nritems %lu", + node->start, root->objectid, nr); + return -EIO; + } + + for (slot = 0; slot < nr - 1; slot++) { + bytenr = btrfs_node_blockptr(node, slot); + btrfs_node_key_to_cpu(node, &key, slot); + btrfs_node_key_to_cpu(node, &next_key, slot + 1); + + if (!bytenr) { + CORRUPT("invalid item slot", node, root, slot); + ret = -EIO; + goto out; + } + + if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) { + CORRUPT("bad key order", node, root, slot); + ret = -EIO; + goto out; + } + } +out: + return ret; +} --- /dev/null +++ b/fs/btrfs/tree-checker.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) Qu Wenruo 2017. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + */ + +#ifndef __BTRFS_TREE_CHECKER__ +#define __BTRFS_TREE_CHECKER__ + +#include "ctree.h" +#include "extent_io.h" + +int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf); +int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node); + +#endif
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo quwenruo.btrfs@gmx.com
commit bba4f29896c986c4cec17bc0f19f2ce644fceae1 upstream.
Use inline function to replace macro since we don't need stringification. (Macro still exists until all callers get updated)
And add more info about the error, and replace EIO with EUCLEAN.
For nr_items error, report if it's too large or too small, and output the valid value range.
For node block pointer, added a new alignment checker.
For key order, also output the next key to make the problem more obvious.
Signed-off-by: Qu Wenruo quwenruo.btrfs@gmx.com [ wording adjustments, unindented long strings ] Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: - Use root->sectorsize instead of root->fs_info->sectorsize - BTRFS_NODEPTRS_PER_BLOCK() takes a root instead of an fs_info, and yields a value of type size_t instead of unsigned int] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/tree-checker.c | 68 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 7 deletions(-)
--- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -37,6 +37,46 @@ btrfs_header_level(eb) == 0 ? "leaf" : "node", \ reason, btrfs_header_bytenr(eb), root->objectid, slot)
+/* + * Error message should follow the following format: + * corrupt <type>: <identifier>, <reason>[, <bad_value>] + * + * @type: leaf or node + * @identifier: the necessary info to locate the leaf/node. + * It's recommened to decode key.objecitd/offset if it's + * meaningful. + * @reason: describe the error + * @bad_value: optional, it's recommened to output bad value and its + * expected value (range). + * + * Since comma is used to separate the components, only space is allowed + * inside each component. + */ + +/* + * Append generic "corrupt leaf/node root=%llu block=%llu slot=%d: " to @fmt. + * Allows callers to customize the output. + */ +__printf(4, 5) +static void generic_err(const struct btrfs_root *root, + const struct extent_buffer *eb, int slot, + const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + btrfs_crit(root->fs_info, + "corrupt %s: root=%llu block=%llu slot=%d, %pV", + btrfs_header_level(eb) == 0 ? "leaf" : "node", + root->objectid, btrfs_header_bytenr(eb), slot, &vaf); + va_end(args); +} + static int check_extent_data_item(struct btrfs_root *root, struct extent_buffer *leaf, struct btrfs_key *key, int slot) @@ -282,9 +322,11 @@ int btrfs_check_node(struct btrfs_root *
if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) { btrfs_crit(root->fs_info, - "corrupt node: block %llu root %llu nritems %lu", - node->start, root->objectid, nr); - return -EIO; +"corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%zu]", + root->objectid, node->start, + nr == 0 ? "small" : "large", nr, + BTRFS_NODEPTRS_PER_BLOCK(root)); + return -EUCLEAN; }
for (slot = 0; slot < nr - 1; slot++) { @@ -293,14 +335,26 @@ int btrfs_check_node(struct btrfs_root * btrfs_node_key_to_cpu(node, &next_key, slot + 1);
if (!bytenr) { - CORRUPT("invalid item slot", node, root, slot); - ret = -EIO; + generic_err(root, node, slot, + "invalid NULL node pointer"); + ret = -EUCLEAN; + goto out; + } + if (!IS_ALIGNED(bytenr, root->sectorsize)) { + generic_err(root, node, slot, + "unaligned pointer, have %llu should be aligned to %u", + bytenr, root->sectorsize); + ret = -EUCLEAN; goto out; }
if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) { - CORRUPT("bad key order", node, root, slot); - ret = -EIO; + generic_err(root, node, slot, + "bad key order, current (%llu %u %llu) next (%llu %u %llu)", + key.objectid, key.type, key.offset, + next_key.objectid, next_key.type, + next_key.offset); + ret = -EUCLEAN; goto out; } }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo wqu@suse.com
commit 69fc6cbbac542c349b3d350d10f6e394c253c81d upstream.
[BUG] If we run btrfs with CONFIG_BTRFS_FS_RUN_SANITY_TESTS=y, it will instantly cause kernel panic like:
------ ... assertion failed: 0, file: fs/btrfs/disk-io.c, line: 3853 ... Call Trace: btrfs_mark_buffer_dirty+0x187/0x1f0 [btrfs] setup_items_for_insert+0x385/0x650 [btrfs] __btrfs_drop_extents+0x129a/0x1870 [btrfs] ... -----
[Cause] Btrfs will call btrfs_check_leaf() in btrfs_mark_buffer_dirty() to check if the leaf is valid with CONFIG_BTRFS_FS_RUN_SANITY_TESTS=y.
However quite some btrfs_mark_buffer_dirty() callers(*) don't really initialize its item data but only initialize its item pointers, leaving item data uninitialized.
This makes tree-checker catch uninitialized data as error, causing such panic.
*: These callers include but not limited to setup_items_for_insert() btrfs_split_item() btrfs_expand_item()
[Fix] Add a new parameter @check_item_data to btrfs_check_leaf(). With @check_item_data set to false, item data check will be skipped and fallback to old btrfs_check_leaf() behavior.
So we can still get early warning if we screw up item pointers, and avoid false panic.
Cc: Filipe Manana fdmanana@gmail.com Reported-by: Lakshmipathi.G lakshmipathi.g@gmail.com Signed-off-by: Qu Wenruo wqu@suse.com Reviewed-by: Liu Bo bo.li.liu@oracle.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: adjust context] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/disk-io.c | 10 ++++++++-- fs/btrfs/tree-checker.c | 27 ++++++++++++++++++++++----- fs/btrfs/tree-checker.h | 14 +++++++++++++- 3 files changed, 43 insertions(+), 8 deletions(-)
--- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -575,7 +575,7 @@ static int btree_readpage_end_io_hook(st * that we don't try and read the other copies of this block, just * return -EIO. */ - if (found_level == 0 && btrfs_check_leaf(root, eb)) { + if (found_level == 0 && btrfs_check_leaf_full(root, eb)) { set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags); ret = -EIO; } @@ -3702,7 +3702,13 @@ void btrfs_mark_buffer_dirty(struct exte buf->len, root->fs_info->dirty_metadata_batch); #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - if (btrfs_header_level(buf) == 0 && btrfs_check_leaf(root, buf)) { + /* + * Since btrfs_mark_buffer_dirty() can be called with item pointer set + * but item data not updated. + * So here we should only check item pointers, not item data. + */ + if (btrfs_header_level(buf) == 0 && + btrfs_check_leaf_relaxed(root, buf)) { btrfs_print_leaf(root, buf); ASSERT(0); } --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -195,7 +195,8 @@ static int check_leaf_item(struct btrfs_ return ret; }
-int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf) +static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf, + bool check_item_data) { struct btrfs_fs_info *fs_info = root->fs_info; /* No valid key type is 0, so all key should be larger than this key */ @@ -299,10 +300,15 @@ int btrfs_check_leaf(struct btrfs_root * return -EUCLEAN; }
- /* Check if the item size and content meet other criteria */ - ret = check_leaf_item(root, leaf, &key, slot); - if (ret < 0) - return ret; + if (check_item_data) { + /* + * Check if the item size and content meet other + * criteria + */ + ret = check_leaf_item(root, leaf, &key, slot); + if (ret < 0) + return ret; + }
prev_key.objectid = key.objectid; prev_key.type = key.type; @@ -312,6 +318,17 @@ int btrfs_check_leaf(struct btrfs_root * return 0; }
+int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf) +{ + return check_leaf(root, leaf, true); +} + +int btrfs_check_leaf_relaxed(struct btrfs_root *root, + struct extent_buffer *leaf) +{ + return check_leaf(root, leaf, false); +} + int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node) { unsigned long nr = btrfs_header_nritems(node); --- a/fs/btrfs/tree-checker.h +++ b/fs/btrfs/tree-checker.h @@ -20,7 +20,19 @@ #include "ctree.h" #include "extent_io.h"
-int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf); +/* + * Comprehensive leaf checker. + * Will check not only the item pointers, but also every possible member + * in item data. + */ +int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf); + +/* + * Less strict leaf checker. + * Will only check item pointers, not reading item data. + */ +int btrfs_check_leaf_relaxed(struct btrfs_root *root, + struct extent_buffer *leaf); int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node);
#endif
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo wqu@suse.com
commit ad7b0368f33cffe67fecd302028915926e50ef7e upstream.
Add checker for dir item, for key types DIR_ITEM, DIR_INDEX and XATTR_ITEM.
This checker does comprehensive checks for:
1) dir_item header and its data size Against item boundary and maximum name/xattr length. This part is mostly the same as old verify_dir_item().
2) dir_type Against maximum file types, and against key type. Since XATTR key should only have FT_XATTR dir item, and normal dir item type should not have XATTR key.
The check between key->type and dir_type is newly introduced by this patch.
3) name hash For XATTR and DIR_ITEM key, key->offset is name hash (crc32c). Check the hash of the name against the key to ensure it's correct.
The name hash check is only found in btrfs-progs before this patch.
Signed-off-by: Qu Wenruo wqu@suse.com Reviewed-by: Nikolay Borisov nborisov@suse.com Reviewed-by: Su Yue suy.fnst@cn.fujitsu.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: BTRFS_MAX_XATTR_SIZE() takes a root instead of an fs_info, and yields a value of type size_t instead of unsigned int] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/tree-checker.c | 141 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+)
--- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -30,6 +30,7 @@ #include "tree-checker.h" #include "disk-io.h" #include "compression.h" +#include "hash.h"
#define CORRUPT(reason, eb, root, slot) \ btrfs_crit(root->fs_info, \ @@ -176,6 +177,141 @@ static int check_csum_item(struct btrfs_ }
/* + * Customized reported for dir_item, only important new info is key->objectid, + * which represents inode number + */ +__printf(4, 5) +static void dir_item_err(const struct btrfs_root *root, + const struct extent_buffer *eb, int slot, + const char *fmt, ...) +{ + struct btrfs_key key; + struct va_format vaf; + va_list args; + + btrfs_item_key_to_cpu(eb, &key, slot); + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + btrfs_crit(root->fs_info, + "corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV", + btrfs_header_level(eb) == 0 ? "leaf" : "node", root->objectid, + btrfs_header_bytenr(eb), slot, key.objectid, &vaf); + va_end(args); +} + +static int check_dir_item(struct btrfs_root *root, + struct extent_buffer *leaf, + struct btrfs_key *key, int slot) +{ + struct btrfs_dir_item *di; + u32 item_size = btrfs_item_size_nr(leaf, slot); + u32 cur = 0; + + di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); + while (cur < item_size) { + char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)]; + u32 name_len; + u32 data_len; + u32 max_name_len; + u32 total_size; + u32 name_hash; + u8 dir_type; + + /* header itself should not cross item boundary */ + if (cur + sizeof(*di) > item_size) { + dir_item_err(root, leaf, slot, + "dir item header crosses item boundary, have %lu boundary %u", + cur + sizeof(*di), item_size); + return -EUCLEAN; + } + + /* dir type check */ + dir_type = btrfs_dir_type(leaf, di); + if (dir_type >= BTRFS_FT_MAX) { + dir_item_err(root, leaf, slot, + "invalid dir item type, have %u expect [0, %u)", + dir_type, BTRFS_FT_MAX); + return -EUCLEAN; + } + + if (key->type == BTRFS_XATTR_ITEM_KEY && + dir_type != BTRFS_FT_XATTR) { + dir_item_err(root, leaf, slot, + "invalid dir item type for XATTR key, have %u expect %u", + dir_type, BTRFS_FT_XATTR); + return -EUCLEAN; + } + if (dir_type == BTRFS_FT_XATTR && + key->type != BTRFS_XATTR_ITEM_KEY) { + dir_item_err(root, leaf, slot, + "xattr dir type found for non-XATTR key"); + return -EUCLEAN; + } + if (dir_type == BTRFS_FT_XATTR) + max_name_len = XATTR_NAME_MAX; + else + max_name_len = BTRFS_NAME_LEN; + + /* Name/data length check */ + name_len = btrfs_dir_name_len(leaf, di); + data_len = btrfs_dir_data_len(leaf, di); + if (name_len > max_name_len) { + dir_item_err(root, leaf, slot, + "dir item name len too long, have %u max %u", + name_len, max_name_len); + return -EUCLEAN; + } + if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root)) { + dir_item_err(root, leaf, slot, + "dir item name and data len too long, have %u max %zu", + name_len + data_len, + BTRFS_MAX_XATTR_SIZE(root)); + return -EUCLEAN; + } + + if (data_len && dir_type != BTRFS_FT_XATTR) { + dir_item_err(root, leaf, slot, + "dir item with invalid data len, have %u expect 0", + data_len); + return -EUCLEAN; + } + + total_size = sizeof(*di) + name_len + data_len; + + /* header and name/data should not cross item boundary */ + if (cur + total_size > item_size) { + dir_item_err(root, leaf, slot, + "dir item data crosses item boundary, have %u boundary %u", + cur + total_size, item_size); + return -EUCLEAN; + } + + /* + * Special check for XATTR/DIR_ITEM, as key->offset is name + * hash, should match its name + */ + if (key->type == BTRFS_DIR_ITEM_KEY || + key->type == BTRFS_XATTR_ITEM_KEY) { + read_extent_buffer(leaf, namebuf, + (unsigned long)(di + 1), name_len); + name_hash = btrfs_name_hash(namebuf, name_len); + if (key->offset != name_hash) { + dir_item_err(root, leaf, slot, + "name hash mismatch with key, have 0x%016x expect 0x%016llx", + name_hash, key->offset); + return -EUCLEAN; + } + } + cur += total_size; + di = (struct btrfs_dir_item *)((void *)di + total_size); + } + return 0; +} + +/* * Common point to switch the item-specific validation. */ static int check_leaf_item(struct btrfs_root *root, @@ -191,6 +327,11 @@ static int check_leaf_item(struct btrfs_ case BTRFS_EXTENT_CSUM_KEY: ret = check_csum_item(root, leaf, key, slot); break; + case BTRFS_DIR_ITEM_KEY: + case BTRFS_DIR_INDEX_KEY: + case BTRFS_XATTR_ITEM_KEY: + ret = check_dir_item(root, leaf, key, slot); + break; } return ret; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Arnd Bergmann arnd@arndb.de
commit 7cfad65297bfe0aa2996cd72d21c898aa84436d9 upstream.
The return value of sizeof() is of type size_t, so we must print it using the %z format modifier rather than %l to avoid this warning on some architectures:
fs/btrfs/tree-checker.c: In function 'check_dir_item': fs/btrfs/tree-checker.c:273:50: error: format '%lu' expects argument of type 'long unsigned int', but argument 5 has type 'u32' {aka 'unsigned int'} [-Werror=format=]
Fixes: 005887f2e3e0 ("btrfs: tree-checker: Add checker for dir item") Signed-off-by: Arnd Bergmann arnd@arndb.de Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/tree-checker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -223,7 +223,7 @@ static int check_dir_item(struct btrfs_r /* header itself should not cross item boundary */ if (cur + sizeof(*di) > item_size) { dir_item_err(root, leaf, slot, - "dir item header crosses item boundary, have %lu boundary %u", + "dir item header crosses item boundary, have %zu boundary %u", cur + sizeof(*di), item_size); return -EUCLEAN; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Sterba dsterba@suse.com
commit e2683fc9d219430f5b78889b50cde7f40efeba7b upstream.
I've noticed that the updated item checker stack consumption increased dramatically in 542f5385e20cf97447 ("btrfs: tree-checker: Add checker for dir item")
tree-checker.c:check_leaf +552 (176 -> 728)
The array is 255 bytes long, dynamic allocation would slow down the sanity checks so it's more reasonable to keep it on-stack. Moving the variable to the scope of use reduces the stack usage again
tree-checker.c:check_leaf -264 (728 -> 464)
Reviewed-by: Josef Bacik jbacik@fb.com Reviewed-by: Qu Wenruo wqu@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/tree-checker.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
--- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -212,7 +212,6 @@ static int check_dir_item(struct btrfs_r
di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); while (cur < item_size) { - char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)]; u32 name_len; u32 data_len; u32 max_name_len; @@ -295,6 +294,8 @@ static int check_dir_item(struct btrfs_r */ if (key->type == BTRFS_DIR_ITEM_KEY || key->type == BTRFS_XATTR_ITEM_KEY) { + char namebuf[max(BTRFS_NAME_LEN, XATTR_NAME_MAX)]; + read_extent_buffer(leaf, namebuf, (unsigned long)(di + 1), name_len); name_hash = btrfs_name_hash(namebuf, name_len);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo wqu@suse.com
commit fce466eab7ac6baa9d2dcd88abcf945be3d4a089 upstream.
A crafted image with invalid block group items could make free space cache code to cause panic.
We could detect such invalid block group item by checking: 1) Item size Known fixed value. 2) Block group size (key.offset) We have an upper limit on block group item (10G) 3) Chunk objectid Known fixed value. 4) Type Only 4 valid type values, DATA, METADATA, SYSTEM and DATA|METADATA. No more than 1 bit set for profile type. 5) Used space No more than the block group size.
This should allow btrfs to detect and refuse to mount the crafted image.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=199849 Reported-by: Xu Wen wen.xu@gatech.edu Signed-off-by: Qu Wenruo wqu@suse.com Reviewed-by: Gu Jinxiang gujx@cn.fujitsu.com Reviewed-by: Nikolay Borisov nborisov@suse.com Tested-by: Gu Jinxiang gujx@cn.fujitsu.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: - In check_leaf_item(), pass root->fs_info to check_block_group_item() - Include <linux/sizes.h> (in ctree.h, to match upstream) - Adjust context] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/ctree.h | 1 + fs/btrfs/tree-checker.c | 100 ++++++++++++++++++++++++++++++++++++++++ fs/btrfs/volumes.c | 2 +- fs/btrfs/volumes.h | 2 + 4 files changed, 104 insertions(+), 1 deletion(-)
--- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -34,6 +34,7 @@ #include <linux/pagemap.h> #include <linux/btrfs.h> #include <linux/workqueue.h> +#include <linux/sizes.h> #include "extent_io.h" #include "extent_map.h" #include "async-thread.h" --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -31,6 +31,7 @@ #include "disk-io.h" #include "compression.h" #include "hash.h" +#include "volumes.h"
#define CORRUPT(reason, eb, root, slot) \ btrfs_crit(root->fs_info, \ @@ -312,6 +313,102 @@ static int check_dir_item(struct btrfs_r return 0; }
+__printf(4, 5) +__cold +static void block_group_err(const struct btrfs_fs_info *fs_info, + const struct extent_buffer *eb, int slot, + const char *fmt, ...) +{ + struct btrfs_key key; + struct va_format vaf; + va_list args; + + btrfs_item_key_to_cpu(eb, &key, slot); + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + btrfs_crit(fs_info, + "corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu bg_len=%llu, %pV", + btrfs_header_level(eb) == 0 ? "leaf" : "node", + btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, + key.objectid, key.offset, &vaf); + va_end(args); +} + +static int check_block_group_item(struct btrfs_fs_info *fs_info, + struct extent_buffer *leaf, + struct btrfs_key *key, int slot) +{ + struct btrfs_block_group_item bgi; + u32 item_size = btrfs_item_size_nr(leaf, slot); + u64 flags; + u64 type; + + /* + * Here we don't really care about alignment since extent allocator can + * handle it. We care more about the size, as if one block group is + * larger than maximum size, it's must be some obvious corruption. + */ + if (key->offset > BTRFS_MAX_DATA_CHUNK_SIZE || key->offset == 0) { + block_group_err(fs_info, leaf, slot, + "invalid block group size, have %llu expect (0, %llu]", + key->offset, BTRFS_MAX_DATA_CHUNK_SIZE); + return -EUCLEAN; + } + + if (item_size != sizeof(bgi)) { + block_group_err(fs_info, leaf, slot, + "invalid item size, have %u expect %zu", + item_size, sizeof(bgi)); + return -EUCLEAN; + } + + read_extent_buffer(leaf, &bgi, btrfs_item_ptr_offset(leaf, slot), + sizeof(bgi)); + if (btrfs_block_group_chunk_objectid(&bgi) != + BTRFS_FIRST_CHUNK_TREE_OBJECTID) { + block_group_err(fs_info, leaf, slot, + "invalid block group chunk objectid, have %llu expect %llu", + btrfs_block_group_chunk_objectid(&bgi), + BTRFS_FIRST_CHUNK_TREE_OBJECTID); + return -EUCLEAN; + } + + if (btrfs_block_group_used(&bgi) > key->offset) { + block_group_err(fs_info, leaf, slot, + "invalid block group used, have %llu expect [0, %llu)", + btrfs_block_group_used(&bgi), key->offset); + return -EUCLEAN; + } + + flags = btrfs_block_group_flags(&bgi); + if (hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) > 1) { + block_group_err(fs_info, leaf, slot, +"invalid profile flags, have 0x%llx (%lu bits set) expect no more than 1 bit set", + flags & BTRFS_BLOCK_GROUP_PROFILE_MASK, + hweight64(flags & BTRFS_BLOCK_GROUP_PROFILE_MASK)); + return -EUCLEAN; + } + + type = flags & BTRFS_BLOCK_GROUP_TYPE_MASK; + if (type != BTRFS_BLOCK_GROUP_DATA && + type != BTRFS_BLOCK_GROUP_METADATA && + type != BTRFS_BLOCK_GROUP_SYSTEM && + type != (BTRFS_BLOCK_GROUP_METADATA | + BTRFS_BLOCK_GROUP_DATA)) { + block_group_err(fs_info, leaf, slot, +"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llu or 0x%llx", + type, hweight64(type), + BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_METADATA, + BTRFS_BLOCK_GROUP_SYSTEM, + BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA); + return -EUCLEAN; + } + return 0; +} + /* * Common point to switch the item-specific validation. */ @@ -333,6 +430,9 @@ static int check_leaf_item(struct btrfs_ case BTRFS_XATTR_ITEM_KEY: ret = check_dir_item(root, leaf, key, slot); break; + case BTRFS_BLOCK_GROUP_ITEM_KEY: + ret = check_block_group_item(root->fs_info, leaf, key, slot); + break; } return ret; } --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4134,7 +4134,7 @@ static int __btrfs_alloc_chunk(struct bt
if (type & BTRFS_BLOCK_GROUP_DATA) { max_stripe_size = 1024 * 1024 * 1024; - max_chunk_size = 10 * max_stripe_size; + max_chunk_size = BTRFS_MAX_DATA_CHUNK_SIZE; if (!devs_max) devs_max = BTRFS_MAX_DEVS(info->chunk_root); } else if (type & BTRFS_BLOCK_GROUP_METADATA) { --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -24,6 +24,8 @@ #include <linux/btrfs.h> #include "async-thread.h"
+#define BTRFS_MAX_DATA_CHUNK_SIZE (10ULL * SZ_1G) + #define BTRFS_STRIPE_LEN (64 * 1024)
struct buffer_head;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo wqu@suse.com
commit ba480dd4db9f1798541eb2d1c423fc95feee8d36 upstream.
A crafted image has empty root tree block, which will later cause NULL pointer dereference.
The following trees should never be empty: 1) Tree root Must contain at least root items for extent tree, device tree and fs tree
2) Chunk tree Or we can't even bootstrap as it contains the mapping.
3) Fs tree At least inode item for top level inode (.).
4) Device tree Dev extents for chunks
5) Extent tree Must have corresponding extent for each chunk.
If any of them is empty, we are sure the fs is corrupted and no need to mount it.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=199847 Reported-by: Xu Wen wen.xu@gatech.edu Signed-off-by: Qu Wenruo wqu@suse.com Tested-by: Gu Jinxiang gujx@cn.fujitsu.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: Pass root instead of fs_info to generic_err()] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/tree-checker.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
--- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -456,9 +456,22 @@ static int check_leaf(struct btrfs_root * skip this check for relocation trees. */ if (nritems == 0 && !btrfs_header_flag(leaf, BTRFS_HEADER_FLAG_RELOC)) { + u64 owner = btrfs_header_owner(leaf); struct btrfs_root *check_root;
- key.objectid = btrfs_header_owner(leaf); + /* These trees must never be empty */ + if (owner == BTRFS_ROOT_TREE_OBJECTID || + owner == BTRFS_CHUNK_TREE_OBJECTID || + owner == BTRFS_EXTENT_TREE_OBJECTID || + owner == BTRFS_DEV_TREE_OBJECTID || + owner == BTRFS_FS_TREE_OBJECTID || + owner == BTRFS_DATA_RELOC_TREE_OBJECTID) { + generic_err(root, leaf, 0, + "invalid root, root %llu must never be empty", + owner); + return -EUCLEAN; + } + key.objectid = owner; key.type = BTRFS_ROOT_ITEM_KEY; key.offset = (u64)-1;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Gu Jinxiang gujx@cn.fujitsu.com
commit 315409b0098fb2651d86553f0436b70502b29bb2 upstream.
Reported in https://bugzilla.kernel.org/show_bug.cgi?id=199839, with an image that has an invalid chunk type but does not return an error.
Add chunk type check in btrfs_check_chunk_valid, to detect the wrong type combinations.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=199839 Reported-by: Xu Wen wen.xu@gatech.edu Reviewed-by: Qu Wenruo wqu@suse.com Signed-off-by: Gu Jinxiang gujx@cn.fujitsu.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: Use root->fs_info instead of fs_info] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/volumes.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
--- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5815,6 +5815,8 @@ static int btrfs_check_chunk_valid(struc u16 num_stripes; u16 sub_stripes; u64 type; + u64 features; + bool mixed = false;
length = btrfs_chunk_length(leaf, chunk); stripe_len = btrfs_chunk_stripe_len(leaf, chunk); @@ -5855,6 +5857,32 @@ static int btrfs_check_chunk_valid(struc btrfs_chunk_type(leaf, chunk)); return -EIO; } + + if ((type & BTRFS_BLOCK_GROUP_TYPE_MASK) == 0) { + btrfs_err(root->fs_info, "missing chunk type flag: 0x%llx", type); + return -EIO; + } + + if ((type & BTRFS_BLOCK_GROUP_SYSTEM) && + (type & (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA))) { + btrfs_err(root->fs_info, + "system chunk with data or metadata type: 0x%llx", type); + return -EIO; + } + + features = btrfs_super_incompat_flags(root->fs_info->super_copy); + if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) + mixed = true; + + if (!mixed) { + if ((type & BTRFS_BLOCK_GROUP_METADATA) && + (type & BTRFS_BLOCK_GROUP_DATA)) { + btrfs_err(root->fs_info, + "mixed chunk type in non-mixed mode: 0x%llx", type); + return -EIO; + } + } + if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) || (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) || (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) ||
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo wqu@suse.com
commit 514c7dca85a0bf40be984dab0b477403a6db901f upstream.
A crafted btrfs image with incorrect chunk<->block group mapping will trigger a lot of unexpected things as the mapping is essential.
Although the problem can be caught by block group item checker added in "btrfs: tree-checker: Verify block_group_item", it's still not sufficient. A sufficiently valid block group item can pass the check added by the mentioned patch but could fail to match the existing chunk.
This patch will add extra block group -> chunk mapping check, to ensure we have a completely matching (start, len, flags) chunk for each block group at mount time.
Here we reuse the original helper find_first_block_group(), which is already doing the basic bg -> chunk checks, adding further checks of the start/len and type flags.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=199837 Reported-by: Xu Wen wen.xu@gatech.edu Signed-off-by: Qu Wenruo wqu@suse.com Reviewed-by: Su Yue suy.fnst@cn.fujitsu.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: Use root->fs_info instead of fs_info] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/extent-tree.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)
--- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8556,6 +8556,8 @@ static int find_first_block_group(struct int ret = 0; struct btrfs_key found_key; struct extent_buffer *leaf; + struct btrfs_block_group_item bg; + u64 flags; int slot;
ret = btrfs_search_slot(NULL, root, key, path, 0, 0); @@ -8590,8 +8592,32 @@ static int find_first_block_group(struct "logical %llu len %llu found bg but no related chunk", found_key.objectid, found_key.offset); ret = -ENOENT; + } else if (em->start != found_key.objectid || + em->len != found_key.offset) { + btrfs_err(root->fs_info, + "block group %llu len %llu mismatch with chunk %llu len %llu", + found_key.objectid, found_key.offset, + em->start, em->len); + ret = -EUCLEAN; } else { - ret = 0; + read_extent_buffer(leaf, &bg, + btrfs_item_ptr_offset(leaf, slot), + sizeof(bg)); + flags = btrfs_block_group_flags(&bg) & + BTRFS_BLOCK_GROUP_TYPE_MASK; + + if (flags != (em->map_lookup->type & + BTRFS_BLOCK_GROUP_TYPE_MASK)) { + btrfs_err(root->fs_info, +"block group %llu len %llu type flags 0x%llx mismatch with chunk type flags 0x%llx", + found_key.objectid, + found_key.offset, flags, + (BTRFS_BLOCK_GROUP_TYPE_MASK & + em->map_lookup->type)); + ret = -EUCLEAN; + } else { + ret = 0; + } } free_extent_map(em); goto out;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo wqu@suse.com
commit 7ef49515fa6727cb4b6f2f5b0ffbc5fc20a9f8c6 upstream.
If a crafted image has missing block group items, it could cause unexpected behavior and breaks the assumption of 1:1 chunk<->block group mapping.
Although we have the block group -> chunk mapping check, we still need chunk -> block group mapping check.
This patch will do extra check to ensure each chunk has its corresponding block group.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=199847 Reported-by: Xu Wen wen.xu@gatech.edu Signed-off-by: Qu Wenruo wqu@suse.com Reviewed-by: Gu Jinxiang gujx@cn.fujitsu.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: adjust context] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/extent-tree.c | 58 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-)
--- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -8819,6 +8819,62 @@ btrfs_create_block_group_cache(struct bt return cache; }
+ +/* + * Iterate all chunks and verify that each of them has the corresponding block + * group + */ +static int check_chunk_block_group_mappings(struct btrfs_fs_info *fs_info) +{ + struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; + struct extent_map *em; + struct btrfs_block_group_cache *bg; + u64 start = 0; + int ret = 0; + + while (1) { + read_lock(&map_tree->map_tree.lock); + /* + * lookup_extent_mapping will return the first extent map + * intersecting the range, so setting @len to 1 is enough to + * get the first chunk. + */ + em = lookup_extent_mapping(&map_tree->map_tree, start, 1); + read_unlock(&map_tree->map_tree.lock); + if (!em) + break; + + bg = btrfs_lookup_block_group(fs_info, em->start); + if (!bg) { + btrfs_err(fs_info, + "chunk start=%llu len=%llu doesn't have corresponding block group", + em->start, em->len); + ret = -EUCLEAN; + free_extent_map(em); + break; + } + if (bg->key.objectid != em->start || + bg->key.offset != em->len || + (bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK) != + (em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK)) { + btrfs_err(fs_info, +"chunk start=%llu len=%llu flags=0x%llx doesn't match block group start=%llu len=%llu flags=0x%llx", + em->start, em->len, + em->map_lookup->type & BTRFS_BLOCK_GROUP_TYPE_MASK, + bg->key.objectid, bg->key.offset, + bg->flags & BTRFS_BLOCK_GROUP_TYPE_MASK); + ret = -EUCLEAN; + free_extent_map(em); + btrfs_put_block_group(bg); + break; + } + start = em->start + em->len; + free_extent_map(em); + btrfs_put_block_group(bg); + } + return ret; +} + int btrfs_read_block_groups(struct btrfs_root *root) { struct btrfs_path *path; @@ -8981,7 +9037,7 @@ int btrfs_read_block_groups(struct btrfs }
init_global_block_rsv(info); - ret = 0; + ret = check_chunk_block_group_mappings(info); error: btrfs_free_path(path); return ret;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Qu Wenruo wqu@suse.com
commit f556faa46eb4e96d0d0772e74ecf66781e132f72 upstream.
Although we have tree level check at tree read runtime, it's completely based on its parent level. We still need to do accurate level check to avoid invalid tree blocks sneak into kernel space.
The check itself is simple, for leaf its level should always be 0. For nodes its level should be in range [1, BTRFS_MAX_LEVEL - 1].
Signed-off-by: Qu Wenruo wqu@suse.com Reviewed-by: Su Yue suy.fnst@cn.fujitsu.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 4.4: - Pass root instead of fs_info to generic_err() - Adjust context] Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/tree-checker.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
--- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -447,6 +447,13 @@ static int check_leaf(struct btrfs_root u32 nritems = btrfs_header_nritems(leaf); int slot;
+ if (btrfs_header_level(leaf) != 0) { + generic_err(root, leaf, 0, + "invalid level for leaf, have %d expect 0", + btrfs_header_level(leaf)); + return -EUCLEAN; + } + /* * Extent buffers from a relocation tree have a owner field that * corresponds to the subvolume tree they are based on. So just from an @@ -589,9 +596,16 @@ int btrfs_check_node(struct btrfs_root * unsigned long nr = btrfs_header_nritems(node); struct btrfs_key key, next_key; int slot; + int level = btrfs_header_level(node); u64 bytenr; int ret = 0;
+ if (level <= 0 || level >= BTRFS_MAX_LEVEL) { + generic_err(root, node, 0, + "invalid level for node, have %d expect [1, %d]", + level, BTRFS_MAX_LEVEL - 1); + return -EUCLEAN; + } if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) { btrfs_crit(root->fs_info, "corrupt node: root=%llu block=%llu, nritems too %s, have %lu expect range [1,%zu]",
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Shaokun Zhang zhangshaokun@hisilicon.com
commit 761333f2f50ccc887aa9957ae829300262c0d15b upstream.
block_group_err shows the group system as a decimal value with a '0x' prefix, which is somewhat misleading.
Fix it to print hexadecimal, as was intended.
Fixes: fce466eab7ac6 ("btrfs: tree-checker: Verify block_group_item") Reviewed-by: Nikolay Borisov nborisov@suse.com Reviewed-by: Qu Wenruo wqu@suse.com Signed-off-by: Shaokun Zhang zhangshaokun@hisilicon.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben.hutchings@codethink.co.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/tree-checker.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -399,7 +399,7 @@ static int check_block_group_item(struct type != (BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA)) { block_group_err(fs_info, leaf, slot, -"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llu or 0x%llx", +"invalid type, have 0x%llx (%lu bits set) expect either 0x%llx, 0x%llx, 0x%llx or 0x%llx", type, hweight64(type), BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_METADATA, BTRFS_BLOCK_GROUP_SYSTEM,
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johannes Thumshirn jthumshirn@suse.de
commit 349ae63f40638a28c6fce52e8447c2d14b84cc0c upstream.
We recently had a customer issue with a corrupted filesystem. When trying to mount this image btrfs panicked with a division by zero in calc_stripe_length().
The corrupt chunk had a 'num_stripes' value of 1. calc_stripe_length() takes this value and divides it by the number of copies the RAID profile is expected to have to calculate the amount of data stripes. As a DUP profile is expected to have 2 copies this division resulted in 1/2 = 0. Later then the 'data_stripes' variable is used as a divisor in the stripe length calculation which results in a division by 0 and thus a kernel panic.
When encountering a filesystem with a DUP block group and a 'num_stripes' value unequal to 2, refuse mounting as the image is corrupted and will lead to unexpected behaviour.
Code inspection showed a RAID1 block group has the same issues.
Fixes: e06cd3dd7cea ("Btrfs: add validadtion checks for chunk loading") Reviewed-by: Qu Wenruo wqu@suse.com Reviewed-by: Nikolay Borisov nborisov@suse.com Signed-off-by: Johannes Thumshirn jthumshirn@suse.de Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/volumes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5884,10 +5884,10 @@ static int btrfs_check_chunk_valid(struc }
if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) || - (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) || + (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes != 2) || (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) || (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3) || - (type & BTRFS_BLOCK_GROUP_DUP && num_stripes > 2) || + (type & BTRFS_BLOCK_GROUP_DUP && num_stripes != 2) || ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 && num_stripes != 1)) { btrfs_err(root->fs_info,
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Vivek Goyal vgoyal@redhat.com
commit e80d1c805a3b2f0ad2081369be5dc5deedd5ee59 upstream.
Some of the device mapper targets override the error code returned by dm_get_device() and return either -EINVAL or -ENXIO. There is nothing gained by this override. It is better to propagate the returned error code unchanged to caller.
This work was motivated by hitting an issue where the underlying device was busy but -EINVAL was being returned. After this change we get -EBUSY instead and it is easier to figure out the problem.
Signed-off-by: Vivek Goyal vgoyal@redhat.com Signed-off-by: Mike Snitzer snitzer@redhat.com [bwh: Backported to 3.16: drop changes to dm-log-writes] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1762,11 +1762,13 @@ static int crypt_ctr(struct dm_target *t } cc->iv_offset = tmpll;
- if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &cc->dev)) { + ret = dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), &cc->dev); + if (ret) { ti->error = "Device lookup failed"; goto bad; }
+ ret = -EINVAL; if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) { ti->error = "Invalid device sector"; goto bad; --- a/drivers/md/dm-delay.c +++ b/drivers/md/dm-delay.c @@ -129,6 +129,7 @@ static int delay_ctr(struct dm_target *t struct delay_c *dc; unsigned long long tmpll; char dummy; + int ret;
if (argc != 3 && argc != 6) { ti->error = "requires exactly 3 or 6 arguments"; @@ -143,6 +144,7 @@ static int delay_ctr(struct dm_target *t
dc->reads = dc->writes = 0;
+ ret = -EINVAL; if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1) { ti->error = "Invalid device sector"; goto bad; @@ -154,12 +156,14 @@ static int delay_ctr(struct dm_target *t goto bad; }
- if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), - &dc->dev_read)) { + ret = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), + &dc->dev_read); + if (ret) { ti->error = "Device lookup failed"; goto bad; }
+ ret = -EINVAL; dc->dev_write = NULL; if (argc == 3) goto out; @@ -175,13 +179,15 @@ static int delay_ctr(struct dm_target *t goto bad_dev_read; }
- if (dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), - &dc->dev_write)) { + ret = dm_get_device(ti, argv[3], dm_table_get_mode(ti->table), + &dc->dev_write); + if (ret) { ti->error = "Write device lookup failed"; goto bad_dev_read; }
out: + ret = -EINVAL; dc->kdelayd_wq = alloc_workqueue("kdelayd", WQ_MEM_RECLAIM, 0); if (!dc->kdelayd_wq) { DMERR("Couldn't start kdelayd"); @@ -208,7 +214,7 @@ bad_dev_read: dm_put_device(ti, dc->dev_read); bad: kfree(dc); - return -EINVAL; + return ret; }
static void delay_dtr(struct dm_target *ti) --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -183,6 +183,7 @@ static int flakey_ctr(struct dm_target *
devname = dm_shift_arg(&as);
+ r = -EINVAL; if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1) { ti->error = "Invalid device sector"; goto bad; @@ -211,7 +212,8 @@ static int flakey_ctr(struct dm_target * if (r) goto bad;
- if (dm_get_device(ti, devname, dm_table_get_mode(ti->table), &fc->dev)) { + r = dm_get_device(ti, devname, dm_table_get_mode(ti->table), &fc->dev); + if (r) { ti->error = "Device lookup failed"; goto bad; } @@ -224,7 +226,7 @@ static int flakey_ctr(struct dm_target *
bad: kfree(fc); - return -EINVAL; + return r; }
static void flakey_dtr(struct dm_target *ti) --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -30,6 +30,7 @@ static int linear_ctr(struct dm_target * struct linear_c *lc; unsigned long long tmp; char dummy; + int ret;
if (argc != 2) { ti->error = "Invalid argument count"; @@ -42,13 +43,15 @@ static int linear_ctr(struct dm_target * return -ENOMEM; }
+ ret = -EINVAL; if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1) { ti->error = "dm-linear: Invalid device sector"; goto bad; } lc->start = tmp;
- if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &lc->dev)) { + ret = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &lc->dev); + if (ret) { ti->error = "dm-linear: Device lookup failed"; goto bad; } @@ -61,7 +64,7 @@ static int linear_ctr(struct dm_target *
bad: kfree(lc); - return -EINVAL; + return ret; }
static void linear_dtr(struct dm_target *ti) --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -923,16 +923,18 @@ static int get_mirror(struct mirror_set { unsigned long long offset; char dummy; + int ret;
if (sscanf(argv[1], "%llu%c", &offset, &dummy) != 1) { ti->error = "Invalid offset"; return -EINVAL; }
- if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), - &ms->mirror[mirror].dev)) { + ret = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), + &ms->mirror[mirror].dev); + if (ret) { ti->error = "Device lookup failure"; - return -ENXIO; + return ret; }
ms->mirror[mirror].ms = ms; --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -75,13 +75,15 @@ static int get_stripe(struct dm_target * { unsigned long long start; char dummy; + int ret;
if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1) return -EINVAL;
- if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), - &sc->stripe[stripe].dev)) - return -ENXIO; + ret = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), + &sc->stripe[stripe].dev); + if (ret) + return ret;
sc->stripe[stripe].physical_start = start;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Wei Yongjun weiyj.lk@gmail.com
commit bff7e067ee518f9ed7e1cbc63e4c9e01670d0b71 upstream.
Fix to return error code -EINVAL instead of 0, as is done elsewhere in this function.
Fixes: e80d1c805a3b ("dm: do not override error code returned from dm_get_device()") Signed-off-by: Wei Yongjun weiyj.lk@gmail.com Signed-off-by: Mike Snitzer snitzer@redhat.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/md/dm-flakey.c | 2 ++ 1 file changed, 2 insertions(+)
--- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -200,11 +200,13 @@ static int flakey_ctr(struct dm_target *
if (!(fc->up_interval + fc->down_interval)) { ti->error = "Total (up + down) interval is zero"; + r = -EINVAL; goto bad; }
if (fc->up_interval + fc->down_interval < fc->up_interval) { ti->error = "Interval overflow"; + r = -EINVAL; goto bad; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mike Snitzer snitzer@redhat.com
commit 299f6230bc6d0ccd5f95bb0fb865d80a9c7d5ccc upstream.
v4.8-rc3 commit 99f3c90d0d ("dm flakey: error READ bios during the down_interval") overlooked the 'drop_writes' feature, which is meant to allow reads to be issued rather than errored, during the down_interval.
Fixes: 99f3c90d0d ("dm flakey: error READ bios during the down_interval") Reported-by: Qu Wenruo quwenruo@cn.fujitsu.com Signed-off-by: Mike Snitzer snitzer@redhat.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/md/dm-flakey.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-)
--- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -291,15 +291,13 @@ static int flakey_map(struct dm_target * pb->bio_submitted = true;
/* - * Map reads as normal only if corrupt_bio_byte set. + * Error reads if neither corrupt_bio_byte or drop_writes are set. + * Otherwise, flakey_end_io() will decide if the reads should be modified. */ if (bio_data_dir(bio) == READ) { - /* If flags were specified, only corrupt those that match. */ - if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == READ) && - all_corrupt_bio_flags_match(bio, fc)) - goto map_bio; - else + if (!fc->corrupt_bio_byte && !test_bit(DROP_WRITES, &fc->flags)) return -EIO; + goto map_bio; }
/* @@ -336,14 +334,21 @@ static int flakey_end_io(struct dm_targe struct flakey_c *fc = ti->private; struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
- /* - * Corrupt successful READs while in down state. - */ if (!error && pb->bio_submitted && (bio_data_dir(bio) == READ)) { - if (fc->corrupt_bio_byte) + if (fc->corrupt_bio_byte && (fc->corrupt_bio_rw == READ) && + all_corrupt_bio_flags_match(bio, fc)) { + /* + * Corrupt successful matching READs while in down state. + */ corrupt_bio_data(bio, fc); - else + + } else if (!test_bit(DROP_WRITES, &fc->flags)) { + /* + * Error read during the down_interval if drop_writes + * wasn't configured. + */ return -EIO; + } }
return error;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Goldwyn Rodrigues rgoldwyn@suse.com
commit 7690e25302dc7d0cd42b349e746fe44b44a94f2b upstream.
One can crash dm-flakey by specifying more feature arguments than the number of features supplied. Checking for null in arg_name avoids this.
dmsetup create flakey-test --table "0 66076080 flakey /dev/sdb9 0 0 180 2 drop_writes"
Signed-off-by: Goldwyn Rodrigues rgoldwyn@suse.com Signed-off-by: Mike Snitzer snitzer@redhat.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/md/dm-flakey.c | 5 +++++ 1 file changed, 5 insertions(+)
--- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -69,6 +69,11 @@ static int parse_features(struct dm_arg_ arg_name = dm_shift_arg(as); argc--;
+ if (!arg_name) { + ti->error = "Insufficient feature arguments"; + return -EINVAL; + } + /* * drop_writes */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Pavel Tatashin pasha.tatashin@oracle.com
In entry_64.S we have code like this:
/* Unconditionally use kernel CR3 for do_nmi() */ /* %rax is saved above, so OK to clobber here */ ALTERNATIVE "jmp 2f", "movq %cr3, %rax", X86_FEATURE_KAISER /* If PCID enabled, NOFLUSH now and NOFLUSH on return */ ALTERNATIVE "", "bts $63, %rax", X86_FEATURE_PCID pushq %rax /* mask off "user" bit of pgd address and 12 PCID bits: */ andq $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), %rax movq %rax, %cr3 2:
/* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */ call do_nmi
With this instruction: andq $(~(X86_CR3_PCID_ASID_MASK | KAISER_SHADOW_PGD_OFFSET)), %rax
We unconditionally switch from whatever our CR3 was to kernel page table. But, in arch/x86/platform/efi/efi_64.c We temporarily set a different page table, that does not have the kernel page table with 0x1000 offset from it.
Look in efi_thunk() and efi_thunk_set_virtual_address_map().
So, while CR3 points to the other page table, we get an NMI interrupt, and clear 0x1000 from CR3, resulting in a bogus CR3 if the 0x1000 bit was set.
The efi page table comes from realmode/rm/trampoline_64.S:
arch/x86/realmode/rm/trampoline_64.S
141 .bss 142 .balign PAGE_SIZE 143 GLOBAL(trampoline_pgd) .space PAGE_SIZE
Notice: alignment is PAGE_SIZE, so after applying KAISER_SHADOW_PGD_OFFSET which equal to PAGE_SIZE, we can get a different page table.
But, even if we fix alignment, here the trampoline binary is later copied into dynamically allocated memory in reserve_real_mode(), so we need to fix that place as well.
Fixes: f9a1666f97b3 ("KAISER: Kernel Address Isolation") Signed-off-by: Pavel Tatashin pasha.tatashin@oracle.com Reviewed-by: Steven Sistare steven.sistare@oracle.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Adjust the Fixes field for 3.16] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- arch/x86/include/asm/kaiser.h | 10 ++++++++++ arch/x86/realmode/init.c | 4 +++- arch/x86/realmode/rm/trampoline_64.S | 3 ++- 3 files changed, 15 insertions(+), 2 deletions(-)
--- a/arch/x86/include/asm/kaiser.h +++ b/arch/x86/include/asm/kaiser.h @@ -19,6 +19,16 @@
#define KAISER_SHADOW_PGD_OFFSET 0x1000
+#ifdef CONFIG_PAGE_TABLE_ISOLATION +/* + * A page table address must have this alignment to stay the same when + * KAISER_SHADOW_PGD_OFFSET mask is applied + */ +#define KAISER_KERNEL_PGD_ALIGNMENT (KAISER_SHADOW_PGD_OFFSET << 1) +#else +#define KAISER_KERNEL_PGD_ALIGNMENT PAGE_SIZE +#endif + #ifdef __ASSEMBLY__ #ifdef CONFIG_PAGE_TABLE_ISOLATION
--- a/arch/x86/realmode/init.c +++ b/arch/x86/realmode/init.c @@ -4,6 +4,7 @@ #include <asm/cacheflush.h> #include <asm/pgtable.h> #include <asm/realmode.h> +#include <asm/kaiser.h>
struct real_mode_header *real_mode_header; u32 *trampoline_cr4_features; @@ -15,7 +16,8 @@ void __init reserve_real_mode(void) size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob);
/* Has to be under 1M so we can execute real-mode AP code. */ - mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); + mem = memblock_find_in_range(0, 1 << 20, size, + KAISER_KERNEL_PGD_ALIGNMENT); if (!mem) panic("Cannot allocate trampoline\n");
--- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -30,6 +30,7 @@ #include <asm/msr.h> #include <asm/segment.h> #include <asm/processor-flags.h> +#include <asm/kaiser.h> #include "realmode.h"
.text @@ -139,7 +140,7 @@ tr_gdt: tr_gdt_end:
.bss - .balign PAGE_SIZE + .balign KAISER_KERNEL_PGD_ALIGNMENT GLOBAL(trampoline_pgd) .space PAGE_SIZE
.balign 8
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann sven@narfation.org
commit 4cc4a1708903f404d2ca0dfde30e71e052c6cbc9 upstream.
The distributed arp table is using a DHT to store and retrieve MAC address information for an IP address. This is done using unicast messages to selected peers. The potential peers are looked up using the IP address and the VID.
While the IP address is always stored in big endian byte order, this is not the case of the VID. It can (depending on the host system) either be big endian or little endian. The host must therefore always convert it to big endian to ensure that all devices calculate the same peers for the same lookup data.
Fixes: be1db4f6615b ("batman-adv: make the Distributed ARP Table vlan aware") Signed-off-by: Sven Eckelmann sven@narfation.org Signed-off-by: Simon Wunderlich sw@simonwunderlich.de [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/batman-adv/distributed-arp-table.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
--- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -207,9 +207,11 @@ static uint32_t batadv_hash_dat(const vo { uint32_t hash = 0; const struct batadv_dat_entry *dat = data; + __be16 vid;
hash = batadv_hash_bytes(hash, &dat->ip, sizeof(dat->ip)); - hash = batadv_hash_bytes(hash, &dat->vid, sizeof(dat->vid)); + vid = htons(dat->vid); + hash = batadv_hash_bytes(hash, &vid, sizeof(vid));
hash += (hash << 3); hash ^= (hash >> 11);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal fw@strlen.de
commit 18a110b022a5c02e7dc9f6109d0bd93e58ac6ebb upstream.
Curtis Taylor and Jon Maxwell reported and debugged a crash on 3.10 based kernel.
Crash occurs in ctnetlink_conntrack_events because net->nfnl socket is NULL. The nfnl socket was set to NULL by netns destruction running on another cpu.
The exiting network namespace calls the relevant destructors in the following order:
1. ctnetlink_net_exit_batch
This nulls out the event callback pointer in struct netns.
2. nfnetlink_net_exit_batch
This nulls net->nfnl socket and frees it.
3. nf_conntrack_cleanup_net_list
This removes all remaining conntrack entries.
This is order is correct. The only explanation for the crash so ar is:
cpu1: conntrack is dying, eviction occurs: -> nf_ct_delete() -> nf_conntrack_event_report \ -> nf_conntrack_eventmask_report -> notify->fcn() (== ctnetlink_conntrack_events).
cpu1: a. fetches rcu protected pointer to obtain ctnetlink event callback. b. gets interrupted. cpu2: runs netns exit handlers: a runs ctnetlink destructor, event cb pointer set to NULL. b runs nfnetlink destructor, nfnl socket is closed and set to NULL. cpu1: c. resumes and trips over NULL net->nfnl.
Problem appears to be that ctnetlink_net_exit_batch only prevents future callers of nf_conntrack_eventmask_report() from obtaining the callback. It doesn't wait of other cpus that might have already obtained the callbacks address.
I don't see anything in upstream kernels that would prevent similar crash: We need to wait for all cpus to have exited the event callback.
Fixes: 9592a5c01e79dbc59eb56fa ("netfilter: ctnetlink: netns support") Signed-off-by: Florian Westphal fw@strlen.de Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/netfilter/nf_conntrack_netlink.c | 3 +++ 1 file changed, 3 insertions(+)
--- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -3225,6 +3225,9 @@ static void __net_exit ctnetlink_net_exi
list_for_each_entry(net, net_exit_list, exit_list) ctnetlink_net_exit(net); + + /* wait for other cpus until they are done with ctnl_notifiers */ + synchronize_rcu(); }
static struct pernet_operations ctnetlink_net_ops = {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner christian.brauner@ubuntu.com
commit 0b8d616fb5a8ffa307b1d3af37f55c15dae14f28 upstream.
When assiging and testing taskstats in taskstats_exit() there's a race when setting up and reading sig->stats when a thread-group with more than one thread exits:
write to 0xffff8881157bbe10 of 8 bytes by task 7951 on cpu 0: taskstats_tgid_alloc kernel/taskstats.c:567 [inline] taskstats_exit+0x6b7/0x717 kernel/taskstats.c:596 do_exit+0x2c2/0x18e0 kernel/exit.c:864 do_group_exit+0xb4/0x1c0 kernel/exit.c:983 get_signal+0x2a2/0x1320 kernel/signal.c:2734 do_signal+0x3b/0xc00 arch/x86/kernel/signal.c:815 exit_to_usermode_loop+0x250/0x2c0 arch/x86/entry/common.c:159 prepare_exit_to_usermode arch/x86/entry/common.c:194 [inline] syscall_return_slowpath arch/x86/entry/common.c:274 [inline] do_syscall_64+0x2d7/0x2f0 arch/x86/entry/common.c:299 entry_SYSCALL_64_after_hwframe+0x44/0xa9
read to 0xffff8881157bbe10 of 8 bytes by task 7949 on cpu 1: taskstats_tgid_alloc kernel/taskstats.c:559 [inline] taskstats_exit+0xb2/0x717 kernel/taskstats.c:596 do_exit+0x2c2/0x18e0 kernel/exit.c:864 do_group_exit+0xb4/0x1c0 kernel/exit.c:983 __do_sys_exit_group kernel/exit.c:994 [inline] __se_sys_exit_group kernel/exit.c:992 [inline] __x64_sys_exit_group+0x2e/0x30 kernel/exit.c:992 do_syscall_64+0xcf/0x2f0 arch/x86/entry/common.c:296 entry_SYSCALL_64_after_hwframe+0x44/0xa9
Fix this by using smp_load_acquire() and smp_store_release().
Reported-by: syzbot+c5d03165a1bd1dead0c1@syzkaller.appspotmail.com Fixes: 34ec12349c8a ("taskstats: cleanup ->signal->stats allocation") Signed-off-by: Christian Brauner christian.brauner@ubuntu.com Acked-by: Marco Elver elver@google.com Reviewed-by: Will Deacon will@kernel.org Reviewed-by: Andrea Parri parri.andrea@gmail.com Reviewed-by: Dmitry Vyukov dvyukov@google.com Link: https://lore.kernel.org/r/20191009114809.8643-1-christian.brauner@ubuntu.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- kernel/taskstats.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-)
--- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -591,25 +591,33 @@ static int taskstats_user_cmd(struct sk_ static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk) { struct signal_struct *sig = tsk->signal; - struct taskstats *stats; + struct taskstats *stats_new, *stats;
- if (sig->stats || thread_group_empty(tsk)) - goto ret; + /* Pairs with smp_store_release() below. */ + stats = smp_load_acquire(&sig->stats); + if (stats || thread_group_empty(tsk)) + return stats;
/* No problem if kmem_cache_zalloc() fails */ - stats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL); + stats_new = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL);
spin_lock_irq(&tsk->sighand->siglock); - if (!sig->stats) { - sig->stats = stats; - stats = NULL; + stats = sig->stats; + if (!stats) { + /* + * Pairs with smp_store_release() above and order the + * kmem_cache_zalloc(). + */ + smp_store_release(&sig->stats, stats_new); + stats = stats_new; + stats_new = NULL; } spin_unlock_irq(&tsk->sighand->siglock);
- if (stats) - kmem_cache_free(taskstats_cache, stats); -ret: - return sig->stats; + if (stats_new) + kmem_cache_free(taskstats_cache, stats_new); + + return stats; }
/* Send pid data out on exit */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Hou Tao houtao1@huawei.com
commit 474e559567fa631dea8fb8407ab1b6090c903755 upstream.
We got the following warnings from thin_check during thin-pool setup:
$ thin_check /dev/vdb examining superblock examining devices tree missing devices: [1, 84] too few entries in btree_node: 41, expected at least 42 (block 138, max_entries = 126) examining mapping tree
The phenomenon is the number of entries in one node of details_info tree is less than (max_entries / 3). And it can be easily reproduced by the following procedures:
$ new a thin pool $ presume the max entries of details_info tree is 126 $ new 127 thin devices (e.g. 1~127) to make the root node being full and then split $ remove the first 43 (e.g. 1~43) thin devices to make the children reblance repeatedly $ stop the thin pool $ thin_check
The root cause is that the B-tree removal procedure in __rebalance2() doesn't guarantee the invariance: the minimal number of entries in non-root node should be >= (max_entries / 3).
Simply fix the problem by increasing the rebalance threshold to make sure the number of entries in each child will be greater than or equal to (max_entries / 3 + 1), so no matter which child is used for removal, the number will still be valid.
Signed-off-by: Hou Tao houtao1@huawei.com Acked-by: Joe Thornber ejt@redhat.com Signed-off-by: Mike Snitzer snitzer@redhat.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/md/persistent-data/dm-btree-remove.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
--- a/drivers/md/persistent-data/dm-btree-remove.c +++ b/drivers/md/persistent-data/dm-btree-remove.c @@ -203,7 +203,13 @@ static void __rebalance2(struct dm_btree struct btree_node *right = r->n; uint32_t nr_left = le32_to_cpu(left->header.nr_entries); uint32_t nr_right = le32_to_cpu(right->header.nr_entries); - unsigned threshold = 2 * merge_threshold(left) + 1; + /* + * Ensure the number of entries in each child will be greater + * than or equal to (max_entries / 3 + 1), so no matter which + * child is used for removal, the number will still be not + * less than (max_entries / 3). + */ + unsigned int threshold = 2 * (merge_threshold(left) + 1);
if (nr_left + nr_right < threshold) { /*
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Nikos Tsironis ntsironis@arrikto.com
commit ecda7c0280e6b3398459dc589b9a41c1adb45529 upstream.
Add support for one pre-commit callback which is run right before the metadata are committed.
This allows the thin provisioning target to run a callback before the metadata are committed and is required by the next commit.
Signed-off-by: Nikos Tsironis ntsironis@arrikto.com Acked-by: Joe Thornber ejt@redhat.com Signed-off-by: Mike Snitzer snitzer@redhat.com [bwh: Backported to 3.16: - Open-code pmd_write_{lock_in_core,unlock}() - Adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/md/dm-thin-metadata.c | 29 +++++++++++++++++++++++++++++ drivers/md/dm-thin-metadata.h | 7 +++++++ 2 files changed, 36 insertions(+)
--- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -198,6 +198,15 @@ struct dm_pool_metadata { bool fail_io:1;
/* + * Pre-commit callback. + * + * This allows the thin provisioning target to run a callback before + * the metadata are committed. + */ + dm_pool_pre_commit_fn pre_commit_fn; + void *pre_commit_context; + + /* * Reading the space map roots can fail, so we read it into these * buffers before the superblock is locked and updated. */ @@ -784,6 +793,14 @@ static int __commit_transaction(struct d */ BUILD_BUG_ON(sizeof(struct thin_disk_superblock) > 512);
+ if (pmd->pre_commit_fn) { + r = pmd->pre_commit_fn(pmd->pre_commit_context); + if (r < 0) { + DMERR("pre-commit callback failed"); + return r; + } + } + r = __write_changed_details(pmd); if (r < 0) return r; @@ -844,6 +861,8 @@ struct dm_pool_metadata *dm_pool_metadat pmd->fail_io = false; pmd->bdev = bdev; pmd->data_block_size = data_block_size; + pmd->pre_commit_fn = NULL; + pmd->pre_commit_context = NULL;
r = __create_persistent_data_objects(pmd, format_device); if (r) { @@ -1789,6 +1808,16 @@ int dm_pool_register_metadata_threshold( return r; }
+void dm_pool_register_pre_commit_callback(struct dm_pool_metadata *pmd, + dm_pool_pre_commit_fn fn, + void *context) +{ + down_write(&pmd->root_lock); + pmd->pre_commit_fn = fn; + pmd->pre_commit_context = context; + up_write(&pmd->root_lock); +} + int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd) { int r; --- a/drivers/md/dm-thin-metadata.h +++ b/drivers/md/dm-thin-metadata.h @@ -213,6 +213,13 @@ int dm_pool_register_metadata_threshold( int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd); bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd);
+/* Pre-commit callback */ +typedef int (*dm_pool_pre_commit_fn)(void *context); + +void dm_pool_register_pre_commit_callback(struct dm_pool_metadata *pmd, + dm_pool_pre_commit_fn fn, + void *context); + /*----------------------------------------------------------------*/
#endif
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mika Westerberg mika.westerberg@linux.intel.com
commit f8323b6bb2cc7d26941d4838dd4375952980a88a upstream.
Zotac ZBOX PI320, a Baytrail based mini-PC, has power button connected to a GPIO pin and it is exposed to the operating system as Windows 8 button array. This is implemented in Linux as a driver using gpio_keys.
However, BIOS on this particula machine forgot to mux the pin to be a GPIO instead of native function, which results following message to be seen on the console:
byt_gpio INT33FC:02: pin 16 cannot be used as GPIO.
This causes power button to not work as the driver was not able to request the GPIO it needs.
So instead of completely preventing this we allow turning the pin as GPIO but issue warning that something might be wrong.
Reported-by: Benjamin Adler benadler@gmx.net Signed-off-by: Mika Westerberg mika.westerberg@linux.intel.com Signed-off-by: Linus Walleij linus.walleij@linaro.org [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/pinctrl/pinctrl-baytrail.c | 35 +++++++++++++++--------- 1 file changed, 22 insertions(+), 13 deletions(-)
--- a/drivers/pinctrl/pinctrl-baytrail.c +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -160,40 +160,49 @@ static void __iomem *byt_gpio_reg(struct return vg->reg_base + reg_offset + reg; }
-static bool is_special_pin(struct byt_gpio *vg, unsigned offset) +static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset) { /* SCORE pin 92-93 */ if (!strcmp(vg->range->name, BYT_SCORE_ACPI_UID) && offset >= 92 && offset <= 93) - return true; + return 1;
/* SUS pin 11-21 */ if (!strcmp(vg->range->name, BYT_SUS_ACPI_UID) && offset >= 11 && offset <= 21) - return true; + return 1;
- return false; + return 0; }
static int byt_gpio_request(struct gpio_chip *chip, unsigned offset) { struct byt_gpio *vg = to_byt_gpio(chip); void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG); - u32 value; - bool special; + u32 value, gpio_mux;
/* * In most cases, func pin mux 000 means GPIO function. * But, some pins may have func pin mux 001 represents - * GPIO function. Only allow user to export pin with - * func pin mux preset as GPIO function by BIOS/FW. + * GPIO function. + * + * Because there are devices out there where some pins were not + * configured correctly we allow changing the mux value from + * request (but print out warning about that). */ value = readl(reg) & BYT_PIN_MUX; - special = is_special_pin(vg, offset); - if ((special && value != 1) || (!special && value)) { - dev_err(&vg->pdev->dev, - "pin %u cannot be used as GPIO.\n", offset); - return -EINVAL; + gpio_mux = byt_get_gpio_mux(vg, offset); + if (WARN_ON(gpio_mux != value)) { + unsigned long flags; + + spin_lock_irqsave(&vg->lock, flags); + value = readl(reg) & ~BYT_PIN_MUX; + value |= gpio_mux; + writel(value, reg); + spin_unlock_irqrestore(&vg->lock, flags); + + dev_warn(&vg->pdev->dev, + "pin %u forcibly re-configured as GPIO\n", offset); }
pm_runtime_get(&vg->pdev->dev);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mika Westerberg mika.westerberg@linux.intel.com
commit 95f0972c7e4cbf3fc68160131c5ac2f033481d00 upstream.
If the pin is already configured as GPIO and it has any of the triggering flags set, we may get spurious interrupts depending on the state of the pin.
Prevent this by clearing the triggering flags on such pins. However, if the pin is also configured as "direct IRQ" we leave the flags as is. Otherwise it will prevent interrupts that are routed directly to IO-APIC.
Signed-off-by: Mika Westerberg mika.westerberg@linux.intel.com Signed-off-by: Linus Walleij linus.walleij@linaro.org [bwh: Backported to 3.16: - Add definition of BYT_DIRECT_IRQ_EN - Adjust filename] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/pinctrl/pinctrl-baytrail.c +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -44,6 +44,7 @@
/* BYT_CONF0_REG register bits */ #define BYT_IODEN BIT(31) +#define BYT_DIRECT_IRQ_EN BIT(27) #define BYT_TRIG_NEG BIT(26) #define BYT_TRIG_POS BIT(25) #define BYT_TRIG_LVL BIT(24) @@ -160,6 +161,19 @@ static void __iomem *byt_gpio_reg(struct return vg->reg_base + reg_offset + reg; }
+static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned offset) +{ + void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); + unsigned long flags; + u32 value; + + spin_lock_irqsave(&vg->lock, flags); + value = readl(reg); + value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); + writel(value, reg); + spin_unlock_irqrestore(&vg->lock, flags); +} + static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset) { /* SCORE pin 92-93 */ @@ -213,14 +227,8 @@ static int byt_gpio_request(struct gpio_ static void byt_gpio_free(struct gpio_chip *chip, unsigned offset) { struct byt_gpio *vg = to_byt_gpio(chip); - void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); - u32 value; - - /* clear interrupt triggering */ - value = readl(reg); - value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); - writel(value, reg);
+ byt_gpio_clear_triggering(vg, offset); pm_runtime_put(&vg->pdev->dev); }
@@ -496,6 +504,21 @@ static void byt_gpio_irq_init_hw(struct { void __iomem *reg; u32 base, value; + int i; + + /* + * Clear interrupt triggers for all pins that are GPIOs and + * do not use direct IRQ mode. This will prevent spurious + * interrupts from misconfigured pins. + */ + for (i = 0; i < vg->chip.ngpio; i++) { + value = readl(byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG)); + if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i) && + !(value & BYT_DIRECT_IRQ_EN)) { + byt_gpio_clear_triggering(vg, i); + dev_dbg(&vg->pdev->dev, "disabling GPIO %d\n", i); + } + }
/* clear interrupt status trigger registers */ for (base = 0; base < vg->chip.ngpio; base += 32) {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mika Westerberg mika.westerberg@linux.intel.com
commit 31e4329f99062a06dca5a493bb4495a63b2dc6ba upstream.
Instead of handling everything in the driver's first level interrupt handler, we can take advantage of already existing flow handlers that are provided by the IRQ core.
This changes the functionality a bit also. Previously the driver looped over pending interrupts in a single loop, restarting the loop if some interrupt changed state. This caused problem with Lenovo Thinkpad 10 digitizer that it was not able to deassert the interrupt before the driver disabled the interrupt for good (looplimit was exhausted).
Rework the interrupt handling logic a bit so that we provide proper mask, ack and unmask operations in terms of Baytrail GPIO hardware and loop over pending interrupts only once. If the interrupt remains asserted the first level handler will be re-triggered automatically.
Signed-off-by: Mika Westerberg mika.westerberg@linux.intel.com Signed-off-by: Linus Walleij linus.walleij@linaro.org [bwh: Backported to 3.16 as dependency of commit 39ce8150a079 "pinctrl: baytrail: Serialize all register access": - Adjust filename, context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/pinctrl/pinctrl-baytrail.c | 100 +++++++++++++---------- 1 file changed, 56 insertions(+), 44 deletions(-)
--- a/drivers/pinctrl/pinctrl-baytrail.c +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -251,23 +251,13 @@ static int byt_irq_type(struct irq_data */ value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
- switch (type) { - case IRQ_TYPE_LEVEL_HIGH: - value |= BYT_TRIG_LVL; - case IRQ_TYPE_EDGE_RISING: - value |= BYT_TRIG_POS; - break; - case IRQ_TYPE_LEVEL_LOW: - value |= BYT_TRIG_LVL; - case IRQ_TYPE_EDGE_FALLING: - value |= BYT_TRIG_NEG; - break; - case IRQ_TYPE_EDGE_BOTH: - value |= (BYT_TRIG_NEG | BYT_TRIG_POS); - break; - } writel(value, reg);
+ if (type & IRQ_TYPE_EDGE_BOTH) + __irq_set_handler_locked(d->irq, handle_edge_irq); + else if (type & IRQ_TYPE_LEVEL_MASK) + __irq_set_handler_locked(d->irq, handle_level_irq); + spin_unlock_irqrestore(&vg->lock, flags);
return 0; @@ -421,54 +411,75 @@ static void byt_gpio_irq_handler(unsigne struct irq_data *data = irq_desc_get_irq_data(desc); struct byt_gpio *vg = irq_data_get_irq_handler_data(data); struct irq_chip *chip = irq_data_get_irq_chip(data); - u32 base, pin, mask; + u32 base, pin; void __iomem *reg; - u32 pending; + unsigned long pending; unsigned virq; - int looplimit = 0;
/* check from GPIO controller which pin triggered the interrupt */ for (base = 0; base < vg->chip.ngpio; base += 32) { - reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG); - - while ((pending = readl(reg))) { - pin = __ffs(pending); - mask = BIT(pin); - /* Clear before handling so we can't lose an edge */ - writel(mask, reg); - + pending = readl(reg); + for_each_set_bit(pin, &pending, 32) { virq = irq_find_mapping(vg->domain, base + pin); generic_handle_irq(virq); - - /* In case bios or user sets triggering incorretly a pin - * might remain in "interrupt triggered" state. - */ - if (looplimit++ > 32) { - dev_err(&vg->pdev->dev, - "Gpio %d interrupt flood, disabling\n", - base + pin); - - reg = byt_gpio_reg(&vg->chip, base + pin, - BYT_CONF0_REG); - mask = readl(reg); - mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS | - BYT_TRIG_LVL); - writel(mask, reg); - mask = readl(reg); /* flush */ - break; - } } } chip->irq_eoi(data); }
+static void byt_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct byt_gpio *vg = to_byt_gpio(gc); + unsigned offset = irqd_to_hwirq(d); + void __iomem *reg; + + reg = byt_gpio_reg(&vg->chip, offset, BYT_INT_STAT_REG); + writel(BIT(offset % 32), reg); +} + static void byt_irq_unmask(struct irq_data *d) { + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct byt_gpio *vg = to_byt_gpio(gc); + unsigned offset = irqd_to_hwirq(d); + unsigned long flags; + void __iomem *reg; + u32 value; + + spin_lock_irqsave(&vg->lock, flags); + + reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); + value = readl(reg); + + switch (irqd_get_trigger_type(d)) { + case IRQ_TYPE_LEVEL_HIGH: + value |= BYT_TRIG_LVL; + case IRQ_TYPE_EDGE_RISING: + value |= BYT_TRIG_POS; + break; + case IRQ_TYPE_LEVEL_LOW: + value |= BYT_TRIG_LVL; + case IRQ_TYPE_EDGE_FALLING: + value |= BYT_TRIG_NEG; + break; + case IRQ_TYPE_EDGE_BOTH: + value |= (BYT_TRIG_NEG | BYT_TRIG_POS); + break; + } + + writel(value, reg); + + spin_unlock_irqrestore(&vg->lock, flags); }
static void byt_irq_mask(struct irq_data *d) { + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct byt_gpio *vg = to_byt_gpio(gc); + + byt_gpio_clear_triggering(vg, irqd_to_hwirq(d)); }
static int byt_irq_reqres(struct irq_data *d) @@ -493,6 +504,7 @@ static void byt_irq_relres(struct irq_da
static struct irq_chip byt_irqchip = { .name = "BYT-GPIO", + .irq_ack = byt_irq_ack, .irq_mask = byt_irq_mask, .irq_unmask = byt_irq_unmask, .irq_set_type = byt_irq_type,
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mika Westerberg mika.westerberg@linux.intel.com
commit 39ce8150a079e3ae6ed9abf26d7918a558ef7c19 upstream.
There is a hardware issue in Intel Baytrail where concurrent GPIO register access might result reads of 0xffffffff and writes might get dropped completely.
Prevent this from happening by taking the serializing lock in all places where it is possible that more than one thread might be accessing the hardware concurrently.
Signed-off-by: Mika Westerberg mika.westerberg@linux.intel.com Signed-off-by: Linus Walleij linus.walleij@linaro.org [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/pinctrl/pinctrl-baytrail.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-)
--- a/drivers/pinctrl/pinctrl-baytrail.c +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -194,6 +194,9 @@ static int byt_gpio_request(struct gpio_ struct byt_gpio *vg = to_byt_gpio(chip); void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG); u32 value, gpio_mux; + unsigned long flags; + + spin_lock_irqsave(&vg->lock, flags);
/* * In most cases, func pin mux 000 means GPIO function. @@ -207,18 +210,16 @@ static int byt_gpio_request(struct gpio_ value = readl(reg) & BYT_PIN_MUX; gpio_mux = byt_get_gpio_mux(vg, offset); if (WARN_ON(gpio_mux != value)) { - unsigned long flags; - - spin_lock_irqsave(&vg->lock, flags); value = readl(reg) & ~BYT_PIN_MUX; value |= gpio_mux; writel(value, reg); - spin_unlock_irqrestore(&vg->lock, flags);
dev_warn(&vg->pdev->dev, "pin %u forcibly re-configured as GPIO\n", offset); }
+ spin_unlock_irqrestore(&vg->lock, flags); + pm_runtime_get(&vg->pdev->dev);
return 0; @@ -266,7 +267,15 @@ static int byt_irq_type(struct irq_data static int byt_gpio_get(struct gpio_chip *chip, unsigned offset) { void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); - return readl(reg) & BYT_LEVEL; + struct byt_gpio *vg = to_byt_gpio(chip); + unsigned long flags; + u32 val; + + spin_lock_irqsave(&vg->lock, flags); + val = readl(reg); + spin_unlock_irqrestore(&vg->lock, flags); + + return val & BYT_LEVEL; }
static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value) @@ -435,8 +444,10 @@ static void byt_irq_ack(struct irq_data unsigned offset = irqd_to_hwirq(d); void __iomem *reg;
+ spin_lock(&vg->lock); reg = byt_gpio_reg(&vg->chip, offset, BYT_INT_STAT_REG); writel(BIT(offset % 32), reg); + spin_unlock(&vg->lock); }
static void byt_irq_unmask(struct irq_data *d)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Hans de Goede hdegoede@redhat.com
commit 40ecab551232972a39cdd8b6f17ede54a3fdb296 upstream.
Commit 39ce8150a079 ("pinctrl: baytrail: Serialize all register access") added a spinlock around all register accesses because:
"There is a hardware issue in Intel Baytrail where concurrent GPIO register access might result reads of 0xffffffff and writes might get dropped completely."
Testing has shown that this does not catch all cases, there are still 2 problems remaining
1) The original fix uses a spinlock per byt_gpio device / struct, additional testing has shown that this is not sufficient concurent accesses to 2 different GPIO banks also suffer from the same problem.
This commit fixes this by moving to a single global lock.
2) The original fix did not add a lock around the register accesses in the suspend/resume handling.
Since pinctrl-baytrail.c is using normal suspend/resume handlers, interrupts are still enabled during suspend/resume handling. Nothing should be using the GPIOs when they are being taken down, _but_ the GPIOs themselves may still cause interrupts, which are likely to use (read) the triggering GPIO. So we need to protect against concurrent GPIO register accesses in the suspend/resume handlers too.
This commit fixes this by adding the missing spin_lock / unlock calls.
The 2 fixes together fix the Acer Switch 10 SW5-012 getting completely confused after a suspend resume. The DSDT for this device has a bug in its _LID method which reprograms the home and power button trigger- flags requesting both high and low _level_ interrupts so the IRQs for these 2 GPIOs continuously fire. This combined with the saving of registers during suspend, triggers concurrent GPIO register accesses resulting in saving 0xffffffff as pconf0 value during suspend and then when restoring this on resume the pinmux settings get all messed up, resulting in various I2C busses being stuck, the wifi no longer working and often the tablet simply not coming out of suspend at all.
Fixes: 39ce8150a079 ("pinctrl: baytrail: Serialize all register access") Signed-off-by: Hans de Goede hdegoede@redhat.com Acked-by: Mika Westerberg mika.westerberg@linux.intel.com Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com [bwh: Backported to 3.16: - Drop changes in functions that don't exist here - Delete local pointers to byt_gpio that become unused - Adjust filename, context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/pinctrl/pinctrl-baytrail.c +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -140,13 +140,14 @@ struct byt_gpio { struct gpio_chip chip; struct irq_domain *domain; struct platform_device *pdev; - spinlock_t lock; void __iomem *reg_base; struct pinctrl_gpio_range *range; };
#define to_byt_gpio(c) container_of(c, struct byt_gpio, chip)
+static DEFINE_RAW_SPINLOCK(byt_lock); + static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset, int reg) { @@ -167,11 +168,11 @@ static void byt_gpio_clear_triggering(st unsigned long flags; u32 value;
- spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&byt_lock, flags); value = readl(reg); value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); writel(value, reg); - spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&byt_lock, flags); }
static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset) @@ -196,7 +197,7 @@ static int byt_gpio_request(struct gpio_ u32 value, gpio_mux; unsigned long flags;
- spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&byt_lock, flags);
/* * In most cases, func pin mux 000 means GPIO function. @@ -218,7 +219,7 @@ static int byt_gpio_request(struct gpio_ "pin %u forcibly re-configured as GPIO\n", offset); }
- spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&byt_lock, flags);
pm_runtime_get(&vg->pdev->dev);
@@ -244,7 +245,7 @@ static int byt_irq_type(struct irq_data if (offset >= vg->chip.ngpio) return -EINVAL;
- spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&byt_lock, flags); value = readl(reg);
/* For level trigges the BYT_TRIG_POS and BYT_TRIG_NEG bits @@ -259,7 +260,7 @@ static int byt_irq_type(struct irq_data else if (type & IRQ_TYPE_LEVEL_MASK) __irq_set_handler_locked(d->irq, handle_level_irq);
- spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&byt_lock, flags);
return 0; } @@ -267,25 +268,23 @@ static int byt_irq_type(struct irq_data static int byt_gpio_get(struct gpio_chip *chip, unsigned offset) { void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); - struct byt_gpio *vg = to_byt_gpio(chip); unsigned long flags; u32 val;
- spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&byt_lock, flags); val = readl(reg); - spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&byt_lock, flags);
return val & BYT_LEVEL; }
static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { - struct byt_gpio *vg = to_byt_gpio(chip); void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); unsigned long flags; u32 old_val;
- spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&byt_lock, flags);
old_val = readl(reg);
@@ -294,23 +293,22 @@ static void byt_gpio_set(struct gpio_chi else writel(old_val & ~BYT_LEVEL, reg);
- spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&byt_lock, flags); }
static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { - struct byt_gpio *vg = to_byt_gpio(chip); void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG); unsigned long flags; u32 value;
- spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&byt_lock, flags);
value = readl(reg) | BYT_DIR_MASK; value &= ~BYT_INPUT_EN; /* active low */ writel(value, reg);
- spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&byt_lock, flags);
return 0; } @@ -318,12 +316,11 @@ static int byt_gpio_direction_input(stru static int byt_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) { - struct byt_gpio *vg = to_byt_gpio(chip); void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG); unsigned long flags; u32 reg_val;
- spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&byt_lock, flags);
reg_val = readl(reg) | BYT_DIR_MASK; reg_val &= ~(BYT_OUTPUT_EN | BYT_INPUT_EN); @@ -333,7 +330,7 @@ static int byt_gpio_direction_output(str else writel(reg_val & ~BYT_LEVEL, reg);
- spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&byt_lock, flags);
return 0; } @@ -345,7 +342,7 @@ static void byt_gpio_dbg_show(struct seq unsigned long flags; u32 conf0, val, offs;
- spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&byt_lock, flags);
for (i = 0; i < vg->chip.ngpio; i++) { const char *pull_str = NULL; @@ -406,7 +403,7 @@ static void byt_gpio_dbg_show(struct seq
seq_puts(s, "\n"); } - spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&byt_lock, flags); }
static int byt_gpio_to_irq(struct gpio_chip *chip, unsigned offset) @@ -444,10 +441,10 @@ static void byt_irq_ack(struct irq_data unsigned offset = irqd_to_hwirq(d); void __iomem *reg;
- spin_lock(&vg->lock); + raw_spin_lock(&byt_lock); reg = byt_gpio_reg(&vg->chip, offset, BYT_INT_STAT_REG); writel(BIT(offset % 32), reg); - spin_unlock(&vg->lock); + raw_spin_unlock(&byt_lock); }
static void byt_irq_unmask(struct irq_data *d) @@ -459,7 +456,7 @@ static void byt_irq_unmask(struct irq_da void __iomem *reg; u32 value;
- spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&byt_lock, flags);
reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); value = readl(reg); @@ -482,7 +479,7 @@ static void byt_irq_unmask(struct irq_da
writel(value, reg);
- spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&byt_lock, flags); }
static void byt_irq_mask(struct irq_data *d) @@ -613,8 +610,6 @@ static int byt_gpio_probe(struct platfor if (IS_ERR(vg->reg_base)) return PTR_ERR(vg->reg_base);
- spin_lock_init(&vg->lock); - gc = &vg->chip; gc->label = dev_name(&pdev->dev); gc->owner = THIS_MODULE;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso pablo@netfilter.org
commit 71df14b0ce094be46d105b5a3ededd83b8e779a0 upstream.
Do not assume userspace always sends us NFT_DATA_VALUE for bitwise and cmp expressions. Although NFT_DATA_VERDICT does not make any sense, it is still possible to handcraft a netlink message using this incorrect data type.
Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/netfilter/nft_bitwise.c | 19 ++++++++++++++----- net/netfilter/nft_cmp.c | 12 ++++++++++-- 2 files changed, 24 insertions(+), 7 deletions(-)
--- a/net/netfilter/nft_bitwise.c +++ b/net/netfilter/nft_bitwise.c @@ -86,16 +86,25 @@ static int nft_bitwise_init(const struct err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]); if (err < 0) return err; - if (d1.len != priv->len) - return -EINVAL; + if (d1.len != priv->len) { + err = -EINVAL; + goto err1; + }
err = nft_data_init(NULL, &priv->xor, &d2, tb[NFTA_BITWISE_XOR]); if (err < 0) - return err; - if (d2.len != priv->len) - return -EINVAL; + goto err1; + if (d2.len != priv->len) { + err = -EINVAL; + goto err2; + }
return 0; +err2: + nft_data_uninit(&priv->xor, d2.type); +err1: + nft_data_uninit(&priv->mask, d1.type); + return err; }
static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr) --- a/net/netfilter/nft_cmp.c +++ b/net/netfilter/nft_cmp.c @@ -201,10 +201,18 @@ nft_cmp_select_ops(const struct nft_ctx if (err < 0) return ERR_PTR(err);
+ if (desc.type != NFT_DATA_VALUE) { + err = -EINVAL; + goto err1; + } + if (desc.len <= sizeof(u32) && op == NFT_CMP_EQ) return &nft_cmp_fast_ops; - else - return &nft_cmp_ops; + + return &nft_cmp_ops; +err1: + nft_data_uninit(&data, desc.type); + return ERR_PTR(-EINVAL); }
static struct nft_expr_type nft_cmp_type __read_mostly = {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso pablo@netfilter.org
commit 0d2c96af797ba149e559c5875c0151384ab6dd14 upstream.
Userspace might bogusly sent NFT_DATA_VERDICT in several netlink attributes that assume NFT_DATA_VALUE. Moreover, make sure that error path invokes nft_data_release() to decrement the reference count on the chain object.
Fixes: 96518518cc41 ("netfilter: add nftables") Fixes: 0f3cd9b36977 ("netfilter: nf_tables: add range expression") Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org [bwh: Backported to 3.16: - Drop changes in nft_get_set_elem(), nft_range - Call nft_data_uninit() instead of nft_data_release() - Adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/net/netfilter/nft_bitwise.c +++ b/net/netfilter/nft_bitwise.c @@ -86,7 +86,7 @@ static int nft_bitwise_init(const struct err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]); if (err < 0) return err; - if (d1.len != priv->len) { + if (d1.type != NFT_DATA_VALUE || d1.len != priv->len) { err = -EINVAL; goto err1; } @@ -94,7 +94,7 @@ static int nft_bitwise_init(const struct err = nft_data_init(NULL, &priv->xor, &d2, tb[NFTA_BITWISE_XOR]); if (err < 0) goto err1; - if (d2.len != priv->len) { + if (d2.type != NFT_DATA_VALUE || d2.len != priv->len) { err = -EINVAL; goto err2; } --- a/net/netfilter/nft_cmp.c +++ b/net/netfilter/nft_cmp.c @@ -84,6 +84,12 @@ static int nft_cmp_init(const struct nft if (desc.len > U8_MAX) return -ERANGE;
+ if (desc.type != NFT_DATA_VALUE) { + err = -EINVAL; + nft_data_uninit(&priv->data, desc.type); + return err; + } + priv->len = desc.len; return 0; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet edumazet@google.com
commit 5604285839aaedfb23ebe297799c6e558939334d upstream.
syzbot is kind enough to remind us we need to call skb_may_pull()
BUG: KMSAN: uninit-value in br_nf_forward_arp+0xe61/0x1230 net/bridge/br_netfilter_hooks.c:665 CPU: 1 PID: 11631 Comm: syz-executor.1 Not tainted 5.4.0-rc8-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: <IRQ> __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1c9/0x220 lib/dump_stack.c:118 kmsan_report+0x128/0x220 mm/kmsan/kmsan_report.c:108 __msan_warning+0x64/0xc0 mm/kmsan/kmsan_instr.c:245 br_nf_forward_arp+0xe61/0x1230 net/bridge/br_netfilter_hooks.c:665 nf_hook_entry_hookfn include/linux/netfilter.h:135 [inline] nf_hook_slow+0x18b/0x3f0 net/netfilter/core.c:512 nf_hook include/linux/netfilter.h:260 [inline] NF_HOOK include/linux/netfilter.h:303 [inline] __br_forward+0x78f/0xe30 net/bridge/br_forward.c:109 br_flood+0xef0/0xfe0 net/bridge/br_forward.c:234 br_handle_frame_finish+0x1a77/0x1c20 net/bridge/br_input.c:162 nf_hook_bridge_pre net/bridge/br_input.c:245 [inline] br_handle_frame+0xfb6/0x1eb0 net/bridge/br_input.c:348 __netif_receive_skb_core+0x20b9/0x51a0 net/core/dev.c:4830 __netif_receive_skb_one_core net/core/dev.c:4927 [inline] __netif_receive_skb net/core/dev.c:5043 [inline] process_backlog+0x610/0x13c0 net/core/dev.c:5874 napi_poll net/core/dev.c:6311 [inline] net_rx_action+0x7a6/0x1aa0 net/core/dev.c:6379 __do_softirq+0x4a1/0x83a kernel/softirq.c:293 do_softirq_own_stack+0x49/0x80 arch/x86/entry/entry_64.S:1091 </IRQ> do_softirq kernel/softirq.c:338 [inline] __local_bh_enable_ip+0x184/0x1d0 kernel/softirq.c:190 local_bh_enable+0x36/0x40 include/linux/bottom_half.h:32 rcu_read_unlock_bh include/linux/rcupdate.h:688 [inline] __dev_queue_xmit+0x38e8/0x4200 net/core/dev.c:3819 dev_queue_xmit+0x4b/0x60 net/core/dev.c:3825 packet_snd net/packet/af_packet.c:2959 [inline] packet_sendmsg+0x8234/0x9100 net/packet/af_packet.c:2984 sock_sendmsg_nosec net/socket.c:637 [inline] sock_sendmsg net/socket.c:657 [inline] __sys_sendto+0xc44/0xc70 net/socket.c:1952 __do_sys_sendto net/socket.c:1964 [inline] __se_sys_sendto+0x107/0x130 net/socket.c:1960 __x64_sys_sendto+0x6e/0x90 net/socket.c:1960 do_syscall_64+0xb6/0x160 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x45a679 Code: ad b6 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 7b b6 fb ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007f0a3c9e5c78 EFLAGS: 00000246 ORIG_RAX: 000000000000002c RAX: ffffffffffffffda RBX: 0000000000000006 RCX: 000000000045a679 RDX: 000000000000000e RSI: 0000000020000200 RDI: 0000000000000003 RBP: 000000000075bf20 R08: 00000000200000c0 R09: 0000000000000014 R10: 0000000000000000 R11: 0000000000000246 R12: 00007f0a3c9e66d4 R13: 00000000004c8ec1 R14: 00000000004dfe28 R15: 00000000ffffffff
Uninit was created at: kmsan_save_stack_with_flags mm/kmsan/kmsan.c:149 [inline] kmsan_internal_poison_shadow+0x5c/0x110 mm/kmsan/kmsan.c:132 kmsan_slab_alloc+0x97/0x100 mm/kmsan/kmsan_hooks.c:86 slab_alloc_node mm/slub.c:2773 [inline] __kmalloc_node_track_caller+0xe27/0x11a0 mm/slub.c:4381 __kmalloc_reserve net/core/skbuff.c:141 [inline] __alloc_skb+0x306/0xa10 net/core/skbuff.c:209 alloc_skb include/linux/skbuff.h:1049 [inline] alloc_skb_with_frags+0x18c/0xa80 net/core/skbuff.c:5662 sock_alloc_send_pskb+0xafd/0x10a0 net/core/sock.c:2244 packet_alloc_skb net/packet/af_packet.c:2807 [inline] packet_snd net/packet/af_packet.c:2902 [inline] packet_sendmsg+0x63a6/0x9100 net/packet/af_packet.c:2984 sock_sendmsg_nosec net/socket.c:637 [inline] sock_sendmsg net/socket.c:657 [inline] __sys_sendto+0xc44/0xc70 net/socket.c:1952 __do_sys_sendto net/socket.c:1964 [inline] __se_sys_sendto+0x107/0x130 net/socket.c:1960 __x64_sys_sendto+0x6e/0x90 net/socket.c:1960 do_syscall_64+0xb6/0x160 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x44/0xa9
Fixes: c4e70a87d975 ("netfilter: bridge: rename br_netfilter.c to br_netfilter_hooks.c") Signed-off-by: Eric Dumazet edumazet@google.com Reported-by: syzbot syzkaller@googlegroups.com Reviewed-by: Florian Westphal fw@strlen.de Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/bridge/br_netfilter.c | 3 +++ 1 file changed, 3 insertions(+)
--- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -850,6 +850,9 @@ static unsigned int br_nf_forward_arp(co nf_bridge_pull_encap_header(skb); }
+ if (unlikely(!pskb_may_pull(skb, sizeof(struct arphdr)))) + return NF_DROP; + if (arp_hdr(skb)->ar_pln != 4) { if (IS_VLAN_ARP(skb)) nf_bridge_push_encap_header(skb);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Marcel Holtmann marcel@holtmann.org
commit be54e7461ffdc5809b67d2aeefc1ddc9a91470c7 upstream.
Always return EPOLLOUT from uhid_char_poll to allow polling /dev/uhid for writable state.
Fixes: 1f9dec1e0164 ("HID: uhid: allow poll()'ing on uhid devices") Signed-off-by: Marcel Holtmann marcel@holtmann.org Signed-off-by: Jiri Kosina jkosina@suse.cz [bwh: Backported to 3.16: s/EPOLL/POLL/g] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/hid/uhid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -726,7 +726,7 @@ static unsigned int uhid_char_poll(struc if (uhid->head != uhid->tail) return POLLIN | POLLRDNORM;
- return 0; + return POLLOUT | POLLWRNORM; }
static const struct file_operations uhid_fops = {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven geert+renesas@glider.be
commit d935bd50dd14a7714cbdba9a76435dbb56edb1ae upstream.
When a GPIO offset in a lookup table is out-of-range, the printed error message (1) does not include the actual out-of-range value, and (2) contains an off-by-one error in the upper bound.
Avoid user confusion by also printing the actual GPIO offset, and correcting the upper bound of the range. While at it, use "%u" for unsigned int.
Sample impact:
-requested GPIO 0 is out of range [0..32] for chip e6052000.gpio +requested GPIO 0 (45) is out of range [0..31] for chip e6052000.gpio
Fixes: 2a3cf6a3599e9015 ("gpiolib: return -ENOENT if no GPIO mapping exists") Signed-off-by: Geert Uytterhoeven geert+renesas@glider.be Link: https://lore.kernel.org/r/20191127095919.4214-1-geert+renesas@glider.be Signed-off-by: Linus Walleij linus.walleij@linaro.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/gpio/gpiolib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
--- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2743,8 +2743,9 @@ static struct gpio_desc *gpiod_find(stru
if (chip->ngpio <= p->chip_hwnum) { dev_err(dev, - "requested GPIO %d is out of range [0..%d] for chip %s\n", - idx, chip->ngpio, chip->label); + "requested GPIO %u (%u) is out of range [0..%u] for chip %s\n", + idx, p->chip_hwnum, chip->ngpio - 1, + chip->label); return ERR_PTR(-EINVAL); }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet edumazet@google.com
commit f394722fb0d0f701119368959d7cd0ecbc46363a upstream.
neigh_cleanup() has not been used for seven years, and was a wrong design.
Messing with shared pointer in bond_neigh_init() without proper memory barriers would at least trigger syzbot complains eventually.
It is time to remove this stuff.
Fixes: b63b70d87741 ("IPoIB: Use a private hash table for path lookup in xmit path") Signed-off-by: Eric Dumazet edumazet@google.com Signed-off-by: David S. Miller davem@davemloft.net [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3431,19 +3431,10 @@ static int bond_neigh_init(struct neighb return 0;
parms.neigh_setup = NULL; - parms.neigh_cleanup = NULL; ret = slave_ops->ndo_neigh_setup(slave->dev, &parms); if (ret) return ret;
- /* - * Assign slave's neigh_cleanup to neighbour in case cleanup is called - * after the last slave has been detached. Assumes that all slaves - * utilize the same neigh_cleanup (true at this writing as only user - * is ipoib). - */ - n->parms->neigh_cleanup = parms.neigh_cleanup; - if (!parms.neigh_setup) return 0;
--- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -71,7 +71,6 @@ struct neigh_parms { struct net_device *dev; struct neigh_parms *next; int (*neigh_setup)(struct neighbour *); - void (*neigh_cleanup)(struct neighbour *); struct neigh_table *tbl;
void *sysctl_table; --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -103,9 +103,6 @@ static int neigh_blackhole(struct neighb
static void neigh_cleanup_and_release(struct neighbour *neigh) { - if (neigh->parms->neigh_cleanup) - neigh->parms->neigh_cleanup(neigh); - __neigh_notify(neigh, RTM_DELNEIGH, 0); neigh_release(neigh); }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet edumazet@google.com
commit 9e99bfefdbce2e23ef37487a3bcb4adf90a791d1 upstream.
1) syzbot reported an uninit-value in bond_neigh_setup() [1]
bond_neigh_setup() uses a temporary on-stack 'struct neigh_parms parms', but only clears parms.neigh_setup field.
A stacked bonding device would then enter bond_neigh_setup() and read garbage from parms->dev.
If we get really unlucky and garbage is matching @dev, then we could recurse and eventually crash.
Let's make sure the whole structure is cleared to avoid surprises.
2) bond_neigh_setup() can be called while another cpu manipulates the master device, removing or adding a slave. We need at least rcu protection to prevent use-after-free.
Note: Prior code does not support a stack of bonding devices, this patch does not attempt to fix this, and leave a comment instead.
[1]
BUG: KMSAN: uninit-value in bond_neigh_setup+0xa4/0x110 drivers/net/bonding/bond_main.c:3655 CPU: 0 PID: 11256 Comm: syz-executor.0 Not tainted 5.4.0-rc8-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: <IRQ> __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x1c9/0x220 lib/dump_stack.c:118 kmsan_report+0x128/0x220 mm/kmsan/kmsan_report.c:108 __msan_warning+0x57/0xa0 mm/kmsan/kmsan_instr.c:245 bond_neigh_setup+0xa4/0x110 drivers/net/bonding/bond_main.c:3655 bond_neigh_init+0x216/0x4b0 drivers/net/bonding/bond_main.c:3626 ___neigh_create+0x169e/0x2c40 net/core/neighbour.c:613 __neigh_create+0xbd/0xd0 net/core/neighbour.c:674 ip6_finish_output2+0x149a/0x2670 net/ipv6/ip6_output.c:113 __ip6_finish_output+0x83d/0x8f0 net/ipv6/ip6_output.c:142 ip6_finish_output+0x2db/0x420 net/ipv6/ip6_output.c:152 NF_HOOK_COND include/linux/netfilter.h:294 [inline] ip6_output+0x5d3/0x720 net/ipv6/ip6_output.c:175 dst_output include/net/dst.h:436 [inline] NF_HOOK include/linux/netfilter.h:305 [inline] mld_sendpack+0xebd/0x13d0 net/ipv6/mcast.c:1682 mld_send_cr net/ipv6/mcast.c:1978 [inline] mld_ifc_timer_expire+0x116b/0x1680 net/ipv6/mcast.c:2477 call_timer_fn+0x232/0x530 kernel/time/timer.c:1404 expire_timers kernel/time/timer.c:1449 [inline] __run_timers+0xd60/0x1270 kernel/time/timer.c:1773 run_timer_softirq+0x2d/0x50 kernel/time/timer.c:1786 __do_softirq+0x4a1/0x83a kernel/softirq.c:293 invoke_softirq kernel/softirq.c:375 [inline] irq_exit+0x230/0x280 kernel/softirq.c:416 exiting_irq+0xe/0x10 arch/x86/include/asm/apic.h:536 smp_apic_timer_interrupt+0x48/0x70 arch/x86/kernel/apic/apic.c:1138 apic_timer_interrupt+0x2e/0x40 arch/x86/entry/entry_64.S:835 </IRQ> RIP: 0010:kmsan_free_page+0x18d/0x1c0 mm/kmsan/kmsan_shadow.c:439 Code: 4c 89 ff 44 89 f6 e8 82 0d ee ff 65 ff 0d 9f 26 3b 60 65 8b 05 98 26 3b 60 85 c0 75 24 e8 5b f6 35 ff 4c 89 6d d0 ff 75 d0 9d <48> 83 c4 10 5b 41 5c 41 5d 41 5e 41 5f 5d c3 0f 0b 0f 0b 0f 0b 0f RSP: 0018:ffffb328034af818 EFLAGS: 00000246 ORIG_RAX: ffffffffffffff13 RAX: 0000000000000000 RBX: ffffe2d7471f8360 RCX: 0000000000000000 RDX: ffffffffadea7000 RSI: 0000000000000004 RDI: ffff93496fcda104 RBP: ffffb328034af850 R08: ffff934a47e86d00 R09: ffff93496fc41900 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000001 R13: 0000000000000246 R14: 0000000000000000 R15: ffffe2d7472225c0 free_pages_prepare mm/page_alloc.c:1138 [inline] free_pcp_prepare mm/page_alloc.c:1230 [inline] free_unref_page_prepare+0x1d9/0x770 mm/page_alloc.c:3025 free_unref_page mm/page_alloc.c:3074 [inline] free_the_page mm/page_alloc.c:4832 [inline] __free_pages+0x154/0x230 mm/page_alloc.c:4840 __vunmap+0xdac/0xf20 mm/vmalloc.c:2277 __vfree mm/vmalloc.c:2325 [inline] vfree+0x7c/0x170 mm/vmalloc.c:2355 copy_entries_to_user net/ipv6/netfilter/ip6_tables.c:883 [inline] get_entries net/ipv6/netfilter/ip6_tables.c:1041 [inline] do_ip6t_get_ctl+0xfa4/0x1030 net/ipv6/netfilter/ip6_tables.c:1709 nf_sockopt net/netfilter/nf_sockopt.c:104 [inline] nf_getsockopt+0x481/0x4e0 net/netfilter/nf_sockopt.c:122 ipv6_getsockopt+0x264/0x510 net/ipv6/ipv6_sockglue.c:1400 tcp_getsockopt+0x1c6/0x1f0 net/ipv4/tcp.c:3688 sock_common_getsockopt+0x13f/0x180 net/core/sock.c:3110 __sys_getsockopt+0x533/0x7b0 net/socket.c:2129 __do_sys_getsockopt net/socket.c:2144 [inline] __se_sys_getsockopt+0xe1/0x100 net/socket.c:2141 __x64_sys_getsockopt+0x62/0x80 net/socket.c:2141 do_syscall_64+0xb6/0x160 arch/x86/entry/common.c:291 entry_SYSCALL_64_after_hwframe+0x44/0xa9 RIP: 0033:0x45d20a Code: b8 34 01 00 00 0f 05 48 3d 01 f0 ff ff 0f 83 8d 8b fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 49 89 ca b8 37 00 00 00 0f 05 <48> 3d 01 f0 ff ff 0f 83 6a 8b fb ff c3 66 0f 1f 84 00 00 00 00 00 RSP: 002b:0000000000a6f618 EFLAGS: 00000212 ORIG_RAX: 0000000000000037 RAX: ffffffffffffffda RBX: 0000000000a6f640 RCX: 000000000045d20a RDX: 0000000000000041 RSI: 0000000000000029 RDI: 0000000000000003 RBP: 0000000000717cc0 R08: 0000000000a6f63c R09: 0000000000004000 R10: 0000000000a6f740 R11: 0000000000000212 R12: 0000000000000003 R13: 0000000000000000 R14: 0000000000000029 R15: 0000000000715b00
Local variable description: ----parms@bond_neigh_init Variable was created at: bond_neigh_init+0x8c/0x4b0 drivers/net/bonding/bond_main.c:3617 bond_neigh_init+0x8c/0x4b0 drivers/net/bonding/bond_main.c:3617
Fixes: 9918d5bf329d ("bonding: modify only neigh_parms owned by us") Fixes: 234bcf8a499e ("net/bonding: correctly proxy slave neigh param setup ndo function") Signed-off-by: Eric Dumazet edumazet@google.com Reported-by: syzbot syzkaller@googlegroups.com Cc: Jay Vosburgh j.vosburgh@gmail.com Cc: Veaceslav Falico vfalico@gmail.com Cc: Andy Gospodarek andy@greyhouse.net Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/bonding/bond_main.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-)
--- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3421,24 +3421,35 @@ static int bond_neigh_init(struct neighb const struct net_device_ops *slave_ops; struct neigh_parms parms; struct slave *slave; - int ret; + int ret = 0;
- slave = bond_first_slave(bond); + rcu_read_lock(); + slave = bond_first_slave_rcu(bond); if (!slave) - return 0; + goto out; slave_ops = slave->dev->netdev_ops; if (!slave_ops->ndo_neigh_setup) - return 0; + goto out;
- parms.neigh_setup = NULL; + /* TODO: find another way [1] to implement this. + * Passing a zeroed structure is fragile, + * but at least we do not pass garbage. + * + * [1] One way would be that ndo_neigh_setup() never touch + * struct neigh_parms, but propagate the new neigh_setup() + * back to ___neigh_create() / neigh_parms_alloc() + */ + memset(&parms, 0, sizeof(parms)); ret = slave_ops->ndo_neigh_setup(slave->dev, &parms); - if (ret) - return ret;
- if (!parms.neigh_setup) - return 0; + if (ret) + goto out;
- return parms.neigh_setup(n); + if (parms.neigh_setup) + ret = parms.neigh_setup(n); +out: + rcu_read_unlock(); + return ret; }
/*
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mao Wenan maowenan@huawei.com
commit b43d1f9f7067c6759b1051e8ecb84e82cef569fe upstream.
There is softlockup when using TPACKET_V3: ... NMI watchdog: BUG: soft lockup - CPU#2 stuck for 60010ms! (__irq_svc) from [<c0558a0c>] (_raw_spin_unlock_irqrestore+0x44/0x54) (_raw_spin_unlock_irqrestore) from [<c027b7e8>] (mod_timer+0x210/0x25c) (mod_timer) from [<c0549c30>] (prb_retire_rx_blk_timer_expired+0x68/0x11c) (prb_retire_rx_blk_timer_expired) from [<c027a7ac>] (call_timer_fn+0x90/0x17c) (call_timer_fn) from [<c027ab6c>] (run_timer_softirq+0x2d4/0x2fc) (run_timer_softirq) from [<c021eaf4>] (__do_softirq+0x218/0x318) (__do_softirq) from [<c021eea0>] (irq_exit+0x88/0xac) (irq_exit) from [<c0240130>] (msa_irq_exit+0x11c/0x1d4) (msa_irq_exit) from [<c0209cf0>] (handle_IPI+0x650/0x7f4) (handle_IPI) from [<c02015bc>] (gic_handle_irq+0x108/0x118) (gic_handle_irq) from [<c0558ee4>] (__irq_usr+0x44/0x5c) ...
If __ethtool_get_link_ksettings() is failed in prb_calc_retire_blk_tmo(), msec and tmo will be zero, so tov_in_jiffies is zero and the timer expire for retire_blk_timer is turn to mod_timer(&pkc->retire_blk_timer, jiffies + 0), which will trigger cpu usage of softirq is 100%.
Fixes: f6fb8f100b80 ("af-packet: TPACKET_V3 flexible buffer implementation.") Tested-by: Xiao Jiangfeng xiaojiangfeng@huawei.com Signed-off-by: Mao Wenan maowenan@huawei.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/packet/af_packet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
--- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -608,7 +608,8 @@ static int prb_calc_retire_blk_tmo(struc msec = 1; div = speed / 1000; } - } + } else + return DEFAULT_PRB_RETIRE_TOV;
mbits = (blk_size_in_bytes * 8) / (1024 * 1024);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: "Rafael J. Wysocki" rafael.j.wysocki@intel.com
commit b9ea0bae260f6aae546db224daa6ac1bd9d94b91 upstream.
Certain ACPI-enumerated devices represented as platform devices in Linux, like fans, require special low-level power management handling implemented by their drivers that is not in agreement with the ACPI PM domain behavior. That leads to problems with managing ACPI fans during system-wide suspend and resume.
For this reason, make acpi_dev_pm_attach() skip the affected devices by adding a list of device IDs to avoid to it and putting the IDs of the affected devices into that list.
Fixes: e5cc8ef31267 (ACPI / PM: Provide ACPI PM callback routines for subsystems) Reported-by: Zhang Rui rui.zhang@intel.com Tested-by: Todd Brandt todd.e.brandt@linux.intel.com Signed-off-by: Rafael J. Wysocki rafael.j.wysocki@intel.com [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/acpi/device_pm.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
--- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1041,9 +1041,19 @@ static struct dev_pm_domain acpi_general */ int acpi_dev_pm_attach(struct device *dev, bool power_on) { + /* + * Skip devices whose ACPI companions match the device IDs below, + * because they require special power management handling incompatible + * with the generic ACPI PM domain. + */ + static const struct acpi_device_id special_pm_ids[] = { + {"PNP0C0B", }, /* Generic ACPI fan */ + {"INT3404", }, /* Fan */ + {} + }; struct acpi_device *adev = ACPI_COMPANION(dev);
- if (!adev) + if (!adev || !acpi_match_device_ids(adev, special_pm_ids)) return -ENODEV;
if (dev->pm_domain)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter dan.carpenter@oracle.com
commit fee92f25777789d73e1936b91472e9c4644457c8 upstream.
On this error path we call qla4xxx_mem_free() and then the caller also calls qla4xxx_free_adapter() which calls qla4xxx_mem_free(). It leads to a couple double frees:
drivers/scsi/qla4xxx/ql4_os.c:8856 qla4xxx_probe_adapter() warn: 'ha->chap_dma_pool' double freed drivers/scsi/qla4xxx/ql4_os.c:8856 qla4xxx_probe_adapter() warn: 'ha->fw_ddb_dma_pool' double freed
Fixes: afaf5a2d341d ("[SCSI] Initial Commit of qla4xxx") Link: https://lore.kernel.org/r/20191203094421.hw7ex7qr3j2rbsmx@kili.mountain Signed-off-by: Dan Carpenter dan.carpenter@oracle.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/scsi/qla4xxx/ql4_os.c | 1 - 1 file changed, 1 deletion(-)
--- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -4269,7 +4269,6 @@ static int qla4xxx_mem_alloc(struct scsi return QLA_SUCCESS;
mem_alloc_error_exit: - qla4xxx_mem_free(ha); return QLA_ERROR; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 53f35a39c3860baac1e5ca80bf052751cfb24a99 upstream.
Fix a general protection fault when accessing the endpoint descriptors which could be triggered by a malicious device due to missing sanity checks on the number of endpoints.
Reported-by: syzbot+35b1c403a14f5c89eba7@syzkaller.appspotmail.com Fixes: 07dc1f9f2f80 ("[PATCH] isdn4linux: Siemens Gigaset drivers - M105 USB DECT adapter") Cc: Hansjoerg Lipp hjlipp@web.de Cc: Tilman Schmidt tilman@imap.cc Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20191202085610.12719-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/isdn/gigaset/usb-gigaset.c | 5 +++++ 1 file changed, 5 insertions(+)
--- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -693,6 +693,11 @@ static int gigaset_probe(struct usb_inte return -ENODEV; }
+ if (hostif->desc.bNumEndpoints < 2) { + dev_err(&interface->dev, "missing endpoints\n"); + return -ENODEV; + } + dev_info(&udev->dev, "%s: Device matched ... !\n", __func__);
/* allocate memory for our device state and initialize it */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 84f60ca7b326ed8c08582417493982fe2573a9ad upstream.
The driver failed to initialise its receive-buffer pointer, something which could lead to an illegal free on late probe errors.
Fix this by making sure to clear all driver data at allocation.
Fixes: 2032e2c2309d ("usb_gigaset: code cleanup") Cc: Tilman Schmidt tilman@imap.cc Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20191202085610.12719-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/isdn/gigaset/usb-gigaset.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
--- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -578,8 +578,7 @@ static int gigaset_initcshw(struct cards { struct usb_cardstate *ucs;
- cs->hw.usb = ucs = - kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL); + cs->hw.usb = ucs = kzalloc(sizeof(struct usb_cardstate), GFP_KERNEL); if (!ucs) { pr_err("out of memory\n"); return -ENOMEM; @@ -591,9 +590,6 @@ static int gigaset_initcshw(struct cards ucs->bchars[3] = 0; ucs->bchars[4] = 0x11; ucs->bchars[5] = 0x13; - ucs->bulk_out_buffer = NULL; - ucs->bulk_out_urb = NULL; - ucs->read_urb = NULL; tasklet_init(&cs->write_tasklet, gigaset_modem_fill, (unsigned long) cs);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit ed9ed5a89acba51b82bdff61144d4e4a4245ec8a upstream.
Add missing endpoint-type sanity checks to probe.
This specifically prevents a warning in USB core on URB submission when fuzzing USB descriptors.
Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20191202085610.12719-4-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/isdn/gigaset/usb-gigaset.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
--- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -713,6 +713,12 @@ static int gigaset_probe(struct usb_inte
endpoint = &hostif->endpoint[0].desc;
+ if (!usb_endpoint_is_bulk_out(endpoint)) { + dev_err(&interface->dev, "missing bulk-out endpoint\n"); + retval = -ENODEV; + goto error; + } + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); ucs->bulk_out_size = buffer_size; ucs->bulk_out_endpointAddr = endpoint->bEndpointAddress; @@ -732,6 +738,12 @@ static int gigaset_probe(struct usb_inte
endpoint = &hostif->endpoint[1].desc;
+ if (!usb_endpoint_is_int_in(endpoint)) { + dev_err(&interface->dev, "missing int-in endpoint\n"); + retval = -ENODEV; + goto error; + } + ucs->busy = 0;
ucs->read_urb = usb_alloc_urb(0, GFP_KERNEL);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Emiliano Ingrassia ingrassia@epigenesys.com
commit 1cd17f7f0def31e3695501c4f86cd3faf8489840 upstream.
Explicitly initialize URB structure urb_list field in usb_init_urb(). This field can be potentially accessed uninitialized and its initialization is coherent with the usage of list_del_init() in usb_hcd_unlink_urb_from_ep() and usb_giveback_urb_bh() and its explicit initialization in usb_hcd_submit_urb() error path.
Signed-off-by: Emiliano Ingrassia ingrassia@epigenesys.com Link: https://lore.kernel.org/r/20191127160355.GA27196@ingrassia.epigenesys.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/core/urb.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -40,6 +40,7 @@ void usb_init_urb(struct urb *urb) if (urb) { memset(urb, 0, sizeof(*urb)); kref_init(&urb->kref); + INIT_LIST_HEAD(&urb->urb_list); INIT_LIST_HEAD(&urb->anchor_list); } }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Pete Zaitcev zaitcev@redhat.com
commit 19e6317d24c25ee737c65d1ffb7483bdda4bb54a upstream.
The problem arises because our read() function grabs a lock of the circular buffer, finds something of interest, then invokes copy_to_user() straight from the buffer, which in turn takes mm->mmap_sem. In the same time, the callback mon_bin_vma_fault() is invoked under mm->mmap_sem. It attempts to take the fetch lock and deadlocks.
This patch does away with protecting of our page list with any semaphores, and instead relies on the kernel not close the device while mmap is active in a process.
In addition, we prohibit re-sizing of a buffer while mmap is active. This way, when (now unlocked) fault is processed, it works with the page that is intended to be mapped-in, and not some other random page. Note that this may have an ABI impact, but hopefully no legitimate program is this wrong.
Signed-off-by: Pete Zaitcev zaitcev@redhat.com Reported-by: syzbot+56f9673bb4cdcbeb0e92@syzkaller.appspotmail.com Reviewed-by: Alan Stern stern@rowland.harvard.edu Fixes: 46eb14a6e158 ("USB: fix usbmon BUG trigger") Link: https://lore.kernel.org/r/20191204203941.3503452b@suzdal.zaitcev.lan Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/mon/mon_bin.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-)
--- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1034,12 +1034,18 @@ static long mon_bin_ioctl(struct file *f
mutex_lock(&rp->fetch_lock); spin_lock_irqsave(&rp->b_lock, flags); - mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE); - kfree(rp->b_vec); - rp->b_vec = vec; - rp->b_size = size; - rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0; - rp->cnt_lost = 0; + if (rp->mmap_active) { + mon_free_buff(vec, size/CHUNK_SIZE); + kfree(vec); + ret = -EBUSY; + } else { + mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE); + kfree(rp->b_vec); + rp->b_vec = vec; + rp->b_size = size; + rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0; + rp->cnt_lost = 0; + } spin_unlock_irqrestore(&rp->b_lock, flags); mutex_unlock(&rp->fetch_lock); } @@ -1211,13 +1217,21 @@ mon_bin_poll(struct file *file, struct p static void mon_bin_vma_open(struct vm_area_struct *vma) { struct mon_reader_bin *rp = vma->vm_private_data; + unsigned long flags; + + spin_lock_irqsave(&rp->b_lock, flags); rp->mmap_active++; + spin_unlock_irqrestore(&rp->b_lock, flags); }
static void mon_bin_vma_close(struct vm_area_struct *vma) { + unsigned long flags; + struct mon_reader_bin *rp = vma->vm_private_data; + spin_lock_irqsave(&rp->b_lock, flags); rp->mmap_active--; + spin_unlock_irqrestore(&rp->b_lock, flags); }
/* @@ -1229,16 +1243,12 @@ static int mon_bin_vma_fault(struct vm_a unsigned long offset, chunk_idx; struct page *pageptr;
- mutex_lock(&rp->fetch_lock); offset = vmf->pgoff << PAGE_SHIFT; - if (offset >= rp->b_size) { - mutex_unlock(&rp->fetch_lock); + if (offset >= rp->b_size) return VM_FAULT_SIGBUS; - } chunk_idx = offset / CHUNK_SIZE; pageptr = rp->b_vec[chunk_idx].pg; get_page(pageptr); - mutex_unlock(&rp->fetch_lock); vmf->page = pageptr; return 0; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 7c5a2df3367a2c4984f1300261345817d95b71f8 upstream.
Make sure to use the current alternate setting when looking up the endpoints on epic devices to avoid binding to an invalid interface.
Failing to do so could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on.
Fixes: 6e8cf7751f9f ("USB: add EPIC support to the io_edgeport driver") Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20191210112601.3561-5-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/serial/io_edgeport.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
--- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -2859,16 +2859,18 @@ static int edge_startup(struct usb_seria response = 0;
if (edge_serial->is_epic) { + struct usb_host_interface *alt; + + alt = serial->interface->cur_altsetting; + /* EPIC thing, set up our interrupt polling now and our read * urb, so that the device knows it really is connected. */ interrupt_in_found = bulk_in_found = bulk_out_found = false; - for (i = 0; i < serial->interface->altsetting[0] - .desc.bNumEndpoints; ++i) { + for (i = 0; i < alt->desc.bNumEndpoints; ++i) { struct usb_endpoint_descriptor *endpoint; int buffer_size;
- endpoint = &serial->interface->altsetting[0]. - endpoint[i].desc; + endpoint = &alt->endpoint[i].desc; buffer_size = usb_endpoint_maxp(endpoint); if (!interrupt_in_found && (usb_endpoint_is_int_in(endpoint))) {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 59920635b89d74b9207ea803d5e91498d39e8b69 upstream.
Make sure to use the current alternate setting when verifying the interface descriptors to avoid binding to an invalid interface.
Failing to do so could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20191210112601.3561-4-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/misc/idmouse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -342,7 +342,7 @@ static int idmouse_probe(struct usb_inte int result;
/* check if we have gotten the data or the hid interface */ - iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting; if (iface_desc->desc.bInterfaceClass != 0x0A) return -ENODEV;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 3c11c4bed02b202e278c0f5c319ae435d7fb9815 upstream.
Make sure to use the current alternate setting when verifying the interface descriptors to avoid binding to an invalid interface.
Failing to do so could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on.
Fixes: 03270634e242 ("USB: Add ADU support for Ontrak ADU devices") Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20191210112601.3561-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/misc/adutux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -682,7 +682,7 @@ static int adu_probe(struct usb_interfac init_waitqueue_head(&dev->read_wait); init_waitqueue_head(&dev->write_wait);
- iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting;
/* set up the endpoint information */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 09068c1ad53fb077bdac288869dec2435420bdc4 upstream.
Make sure that the interrupt interface has an endpoint before trying to access its endpoint descriptors to avoid dereferencing a NULL pointer.
The driver binds to the interrupt interface with interface number 0, but must not assume that this interface or its current alternate setting are the first entries in the corresponding configuration arrays.
Fixes: b72458a80c75 ("[PATCH] USB: Eagle and ADI 930 usb adsl modem driver") Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20191210112601.3561-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/atm/ueagle-atm.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
--- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2167,10 +2167,11 @@ resubmit: /* * Start the modem : init the data and start kernel thread */ -static int uea_boot(struct uea_softc *sc) +static int uea_boot(struct uea_softc *sc, struct usb_interface *intf) { - int ret, size; struct intr_pkt *intr; + int ret = -ENOMEM; + int size;
uea_enters(INS_TO_USBDEV(sc));
@@ -2195,6 +2196,11 @@ static int uea_boot(struct uea_softc *sc if (UEA_CHIP_VERSION(sc) == ADI930) load_XILINX_firmware(sc);
+ if (intf->cur_altsetting->desc.bNumEndpoints < 1) { + ret = -ENODEV; + goto err0; + } + intr = kmalloc(size, GFP_KERNEL); if (!intr) { uea_err(INS_TO_USBDEV(sc), @@ -2211,8 +2217,7 @@ static int uea_boot(struct uea_softc *sc usb_fill_int_urb(sc->urb_int, sc->usb_dev, usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE), intr, size, uea_intr, sc, - sc->usb_dev->actconfig->interface[0]->altsetting[0]. - endpoint[0].desc.bInterval); + intf->cur_altsetting->endpoint[0].desc.bInterval);
ret = usb_submit_urb(sc->urb_int, GFP_KERNEL); if (ret < 0) { @@ -2227,6 +2232,7 @@ static int uea_boot(struct uea_softc *sc sc->kthread = kthread_create(uea_kthread, sc, "ueagle-atm"); if (IS_ERR(sc->kthread)) { uea_err(INS_TO_USBDEV(sc), "failed to create thread\n"); + ret = PTR_ERR(sc->kthread); goto err2; }
@@ -2241,7 +2247,7 @@ err1: kfree(intr); err0: uea_leaves(INS_TO_USBDEV(sc)); - return -ENOMEM; + return ret; }
/* @@ -2604,7 +2610,7 @@ static int uea_bind(struct usbatm_data * if (ret < 0) goto error;
- ret = uea_boot(sc); + ret = uea_boot(sc, intf); if (ret < 0) goto error_rm_grp;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 74ca34118a0e05793935d804ccffcedd6eb56596 upstream.
Make sure to use the current alternate setting when verifying the interface descriptors to avoid binding to an invalid interface.
Failing to do so could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on.
Fixes: c2478d39076b ("staging: r8188eu: Add files for new driver - part 20") Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20191210114751.5119-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -141,7 +141,7 @@ static struct dvobj_priv *usb_dvobj_init phost_conf = pusbd->actconfig; pconf_desc = &phost_conf->desc;
- phost_iface = &usb_intf->altsetting[0]; + phost_iface = usb_intf->cur_altsetting; piface_desc = &phost_iface->desc;
pdvobjpriv->NumInterfaces = pconf_desc->bNumInterfaces;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit c724f776f048538ecfdf53a52b7a522309f5c504 upstream.
Make sure to use the current alternate setting when verifying the interface descriptors to avoid binding to an invalid interface.
Failing to do so could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on.
Fixes: 2865d42c78a9 ("staging: r8712u: Add the new driver to the mainline kernel") Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20191210114751.5119-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/staging/rtl8712/usb_intf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -269,7 +269,7 @@ static uint r8712_usb_dvobj_init(struct pdev_desc = &pusbd->descriptor; phost_conf = pusbd->actconfig; pconf_desc = &phost_conf->desc; - phost_iface = &pintf->altsetting[0]; + phost_iface = pintf->cur_altsetting; piface_desc = &phost_iface->desc; pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints; if (pusbd->speed == USB_SPEED_HIGH) {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Russell King rmk+kernel@armlinux.org.uk
commit 256efaea1fdc4e38970489197409a26125ee0aaa upstream.
gpiolib has a corner case with open drain outputs that are emulated. When such outputs are outputting a logic 1, emulation will set the hardware to input mode, which will cause gpiod_get_direction() to report that it is in input mode. This is different from the behaviour with a true open-drain output.
Unify the semantics here.
Suggested-by: Linus Walleij linus.walleij@linaro.org Signed-off-by: Russell King rmk+kernel@armlinux.org.uk Signed-off-by: Bartosz Golaszewski bgolaszewski@baylibre.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/gpio/gpiolib.c | 8 ++++++++ 1 file changed, 8 insertions(+)
--- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -273,6 +273,14 @@ int gpiod_get_direction(const struct gpi chip = gpiod_to_chip(desc); offset = gpio_chip_hwgpio(desc);
+ /* + * Open drain emulation using input mode may incorrectly report + * input here, fix that up. + */ + if (test_bit(FLAG_OPEN_DRAIN, &desc->flags) && + test_bit(FLAG_IS_OUT, &desc->flags)) + return 0; + if (!chip->get_direction) return status;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: David Hildenbrand david@redhat.com
commit 63341ab03706e11a31e3dd8ccc0fbc9beaf723f0 upstream.
In case we have to migrate a ballon page to a newpage of another zone, the managed page count of both zones is wrong. Paired with memory offlining (which will adjust the managed page count), we can trigger kernel crashes and all kinds of different symptoms.
One way to reproduce: 1. Start a QEMU guest with 4GB, no NUMA 2. Hotplug a 1GB DIMM and online the memory to ZONE_NORMAL 3. Inflate the balloon to 1GB 4. Unplug the DIMM (be quick, otherwise unmovable data ends up on it) 5. Observe /proc/zoneinfo Node 0, zone Normal pages free 16810 min 24848885473806 low 18471592959183339 high 36918337032892872 spanned 262144 present 262144 managed 18446744073709533486 6. Do anything that requires some memory (e.g., inflate the balloon some more). The OOM goes crazy and the system crashes [ 238.324946] Out of memory: Killed process 537 (login) total-vm:27584kB, anon-rss:860kB, file-rss:0kB, shmem-rss:00 [ 238.338585] systemd invoked oom-killer: gfp_mask=0x100cca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0 [ 238.339420] CPU: 0 PID: 1 Comm: systemd Tainted: G D W 5.4.0-next-20191204+ #75 [ 238.340139] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu4 [ 238.341121] Call Trace: [ 238.341337] dump_stack+0x8f/0xd0 [ 238.341630] dump_header+0x61/0x5ea [ 238.341942] oom_kill_process.cold+0xb/0x10 [ 238.342299] out_of_memory+0x24d/0x5a0 [ 238.342625] __alloc_pages_slowpath+0xd12/0x1020 [ 238.343024] __alloc_pages_nodemask+0x391/0x410 [ 238.343407] pagecache_get_page+0xc3/0x3a0 [ 238.343757] filemap_fault+0x804/0xc30 [ 238.344083] ? ext4_filemap_fault+0x28/0x42 [ 238.344444] ext4_filemap_fault+0x30/0x42 [ 238.344789] __do_fault+0x37/0x1a0 [ 238.345087] __handle_mm_fault+0x104d/0x1ab0 [ 238.345450] handle_mm_fault+0x169/0x360 [ 238.345790] do_user_addr_fault+0x20d/0x490 [ 238.346154] do_page_fault+0x31/0x210 [ 238.346468] async_page_fault+0x43/0x50 [ 238.346797] RIP: 0033:0x7f47eba4197e [ 238.347110] Code: Bad RIP value. [ 238.347387] RSP: 002b:00007ffd7c0c1890 EFLAGS: 00010293 [ 238.347834] RAX: 0000000000000002 RBX: 000055d196a20a20 RCX: 00007f47eba4197e [ 238.348437] RDX: 0000000000000033 RSI: 00007ffd7c0c18c0 RDI: 0000000000000004 [ 238.349047] RBP: 00007ffd7c0c1c20 R08: 0000000000000000 R09: 0000000000000033 [ 238.349660] R10: 00000000ffffffff R11: 0000000000000293 R12: 0000000000000001 [ 238.350261] R13: ffffffffffffffff R14: 0000000000000000 R15: 00007ffd7c0c18c0 [ 238.350878] Mem-Info: [ 238.351085] active_anon:3121 inactive_anon:51 isolated_anon:0 [ 238.351085] active_file:12 inactive_file:7 isolated_file:0 [ 238.351085] unevictable:0 dirty:0 writeback:0 unstable:0 [ 238.351085] slab_reclaimable:5565 slab_unreclaimable:10170 [ 238.351085] mapped:3 shmem:111 pagetables:155 bounce:0 [ 238.351085] free:720717 free_pcp:2 free_cma:0 [ 238.353757] Node 0 active_anon:12484kB inactive_anon:204kB active_file:48kB inactive_file:28kB unevictable:0kB iss [ 238.355979] Node 0 DMA free:11556kB min:36kB low:48kB high:60kB reserved_highatomic:0KB active_anon:152kB inactivB [ 238.358345] lowmem_reserve[]: 0 2955 2884 2884 2884 [ 238.358761] Node 0 DMA32 free:2677864kB min:7004kB low:10028kB high:13052kB reserved_highatomic:0KB active_anon:0B [ 238.361202] lowmem_reserve[]: 0 0 72057594037927865 72057594037927865 72057594037927865 [ 238.361888] Node 0 Normal free:193448kB min:99395541895224kB low:73886371836733356kB high:147673348131571488kB reB [ 238.364765] lowmem_reserve[]: 0 0 0 0 0 [ 238.365101] Node 0 DMA: 7*4kB (U) 5*8kB (UE) 6*16kB (UME) 2*32kB (UM) 1*64kB (U) 2*128kB (UE) 3*256kB (UME) 2*512B [ 238.366379] Node 0 DMA32: 0*4kB 1*8kB (U) 2*16kB (UM) 2*32kB (UM) 2*64kB (UM) 1*128kB (U) 1*256kB (U) 1*512kB (U)B [ 238.367654] Node 0 Normal: 1985*4kB (UME) 1321*8kB (UME) 844*16kB (UME) 524*32kB (UME) 300*64kB (UME) 138*128kB (B [ 238.369184] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB [ 238.369915] 130 total pagecache pages [ 238.370241] 0 pages in swap cache [ 238.370533] Swap cache stats: add 0, delete 0, find 0/0 [ 238.370981] Free swap = 0kB [ 238.371239] Total swap = 0kB [ 238.371488] 1048445 pages RAM [ 238.371756] 0 pages HighMem/MovableOnly [ 238.372090] 306992 pages reserved [ 238.372376] 0 pages cma reserved [ 238.372661] 0 pages hwpoisoned
In another instance (older kernel), I was able to observe this (negative page count :/): [ 180.896971] Offlined Pages 32768 [ 182.667462] Offlined Pages 32768 [ 184.408117] Offlined Pages 32768 [ 186.026321] Offlined Pages 32768 [ 187.684861] Offlined Pages 32768 [ 189.227013] Offlined Pages 32768 [ 190.830303] Offlined Pages 32768 [ 190.833071] Built 1 zonelists, mobility grouping on. Total pages: -36920272750453009
In another instance (older kernel), I was no longer able to start any process: [root@vm ~]# [ 214.348068] Offlined Pages 32768 [ 215.973009] Offlined Pages 32768 cat /proc/meminfo -bash: fork: Cannot allocate memory [root@vm ~]# cat /proc/meminfo -bash: fork: Cannot allocate memory
Fix it by properly adjusting the managed page count when migrating if the zone changed. The managed page count of the zones now looks after unplug of the DIMM (and after deflating the balloon) just like before inflating the balloon (and plugging+onlining the DIMM).
We'll temporarily modify the totalram page count. If this ever becomes a problem, we can fine tune by providing helpers that don't touch the totalram pages (e.g., adjust_zone_managed_page_count()).
Please note that fixing up the managed page count is only necessary when we adjusted the managed page count when inflating - only if we don't have VIRTIO_BALLOON_F_DEFLATE_ON_OOM. With that feature, the managed page count is not touched when inflating/deflating.
Reported-by: Yumei Huang yuhuang@redhat.com Fixes: 3dcc0571cd64 ("mm: correctly update zone->managed_pages") Cc: "Michael S. Tsirkin" mst@redhat.com Cc: Jason Wang jasowang@redhat.com Cc: Jiang Liu liuj97@gmail.com Cc: Andrew Morton akpm@linux-foundation.org Cc: Igor Mammedov imammedo@redhat.com Cc: virtualization@lists.linux-foundation.org Signed-off-by: David Hildenbrand david@redhat.com Signed-off-by: Michael S. Tsirkin mst@redhat.com [bwh: Backported to 3.16: Deflate-on-OOM is not supported at all so don't check that flag] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -403,6 +403,16 @@ static int virtballoon_migratepage(struc
get_page(newpage); /* balloon reference */
+ /* + * When we migrate a page to a different zone and adjusted the + * managed page count when inflating, we have to fixup the count of + * both involved zones. + */ + if (page_zone(page) != page_zone(newpage)) { + adjust_managed_page_count(page, 1); + adjust_managed_page_count(newpage, -1); + } + /* balloon's page migration 1st step -- inflate "newpage" */ spin_lock_irqsave(&vb_dev_info->pages_lock, flags); balloon_page_insert(newpage, mapping, &vb_dev_info->pages);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Alan Stern stern@rowland.harvard.edu
commit 8ec321e96e056de84022c032ffea253431a83c3c upstream.
The syzbot fuzzer found a slab-out-of-bounds bug in the HID report handler. The bug was caused by a report descriptor which included a field with size 12 bits and count 4899, for a total size of 7349 bytes.
The usbhid driver uses at most a single-page 4-KB buffer for reports. In the test there wasn't any problem about overflowing the buffer, since only one byte was received from the device. Rather, the bug occurred when the HID core tried to extract the data from the report fields, which caused it to try reading data beyond the end of the allocated buffer.
This patch fixes the problem by rejecting any report whose total length exceeds the HID_MAX_BUFFER_SIZE limit (minus one byte to allow for a possible report index). In theory a device could have a report longer than that, but if there was such a thing we wouldn't handle it correctly anyway.
Reported-and-tested-by: syzbot+09ef48aa58261464b621@syzkaller.appspotmail.com Signed-off-by: Alan Stern stern@rowland.harvard.edu Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/hid/hid-core.c | 6 ++++++ 1 file changed, 6 insertions(+)
--- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -248,6 +248,12 @@ static int hid_add_field(struct hid_pars offset = report->size; report->size += parser->global.report_size * parser->global.report_count;
+ /* Total size check: Allow for possible report index byte */ + if (report->size > (HID_MAX_BUFFER_SIZE - 1) << 3) { + hid_err(parser->device, "report is too long\n"); + return -1; + } + if (!parser->local.usage_index) /* Ignore padding fields */ return 0;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mathias Nyman mathias.nyman@linux.intel.com
commit 7ff11162808cc2ec66353fc012c58bb449c892c3 upstream.
xhci driver claims it needs XHCI_TRUST_TX_LENGTH quirk for both Broadcom/Cavium and a Renesas xHC controllers.
The quirk was inteded for handling false "success" complete event for transfers that had data left untransferred. These transfers should complete with "short packet" events instead.
In these two new cases the false "success" completion is reported after a "short packet" if the TD consists of several TRBs. xHCI specs 4.10.1.1.2 say remaining TRBs should report "short packet" as well after the first short packet in a TD, but this issue seems so common it doesn't make sense to add the quirk for all vendors.
Turn these events into short packets automatically instead.
This gets rid of the "The WARN Successful completion on short TX for slot 1 ep 1: needs XHCI_TRUST_TX_LENGTH quirk" warning in many cases.
Reported-by: Eli Billauer eli.billauer@gmail.com Reported-by: Ard Biesheuvel ardb@kernel.org Tested-by: Eli Billauer eli.billauer@gmail.com Tested-by: Ard Biesheuvel ardb@kernel.org Signed-off-by: Mathias Nyman mathias.nyman@linux.intel.com Link: https://lore.kernel.org/r/20191211142007.8847-6-mathias.nyman@linux.intel.co... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/host/xhci-ring.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2345,7 +2345,8 @@ static int handle_tx_event(struct xhci_h case COMP_SUCCESS: if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) break; - if (xhci->quirks & XHCI_TRUST_TX_LENGTH) + if (xhci->quirks & XHCI_TRUST_TX_LENGTH || + ep_ring->last_td_was_short) trb_comp_code = COMP_SHORT_TX; else xhci_warn_ratelimited(xhci,
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mathias Nyman mathias.nyman@linux.intel.com
commit bd82873f23c9a6ad834348f8b83f3b6a5bca2c65 upstream.
spin_unlock_irqrestore() might be called with stale flags after reading port status, possibly restoring interrupts to a incorrect state.
If a usb2 port just finished resuming while the port status is read the spin lock will be temporary released and re-acquired in a separate function. The flags parameter is passed as value instead of a pointer, not updating flags properly before the final spin_unlock_irqrestore() is called.
Fixes: 8b3d45705e54 ("usb: Fix xHCI host issues on remote wakeup.") Signed-off-by: Mathias Nyman mathias.nyman@linux.intel.com Link: https://lore.kernel.org/r/20191211142007.8847-7-mathias.nyman@linux.intel.co... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/host/xhci-hub.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
--- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -580,7 +580,7 @@ static u32 xhci_get_port_status(struct u struct xhci_bus_state *bus_state, __le32 __iomem **port_array, u16 wIndex, u32 raw_port_status, - unsigned long flags) + unsigned long *flags) __releases(&xhci->lock) __acquires(&xhci->lock) { @@ -670,12 +670,12 @@ static u32 xhci_get_port_status(struct u xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0);
- spin_unlock_irqrestore(&xhci->lock, flags); + spin_unlock_irqrestore(&xhci->lock, *flags); time_left = wait_for_completion_timeout( &bus_state->rexit_done[wIndex], msecs_to_jiffies( XHCI_MAX_REXIT_TIMEOUT_MS)); - spin_lock_irqsave(&xhci->lock, flags); + spin_lock_irqsave(&xhci->lock, *flags);
if (time_left) { slot_id = xhci_find_slot_id_by_port(hcd, @@ -834,7 +834,7 @@ int xhci_hub_control(struct usb_hcd *hcd break; } status = xhci_get_port_status(hcd, bus_state, port_array, - wIndex, temp, flags); + wIndex, temp, &flags); if (status == 0xffffffff) goto error;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Alan Cox alan@linux.intel.com
commit 7d643664ea559b36188cae264047ce3c9bfec3a2 upstream.
The device controller is the same but it has different PCI ID. Add this new ID to the driver's list of supported IDs.
Signed-off-by: Alan Cox alan@linux.intel.com Signed-off-by: Mika Westerberg mika.westerberg@linux.intel.com Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Signed-off-by: Felipe Balbi balbi@ti.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 2 ++ 1 file changed, 2 insertions(+)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -30,6 +30,7 @@ #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd #define PCI_DEVICE_ID_INTEL_BYT 0x0f37 #define PCI_DEVICE_ID_INTEL_MRFLD 0x119e +#define PCI_DEVICE_ID_INTEL_BSW 0x22B7
struct dwc3_pci { struct device *dev; @@ -183,6 +184,7 @@ static const struct pci_device_id dwc3_p PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, { } /* Terminating Entry */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Heikki Krogerus heikki.krogerus@linux.intel.com
commit 84a2b61b6eb94036093531cdabc448dddfbae45a upstream.
Add PCI IDs for Intel Sunrise Point PCH.
Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Signed-off-by: Felipe Balbi balbi@ti.com [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 4 ++++ 1 file changed, 4 insertions(+)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -31,6 +31,8 @@ #define PCI_DEVICE_ID_INTEL_BYT 0x0f37 #define PCI_DEVICE_ID_INTEL_MRFLD 0x119e #define PCI_DEVICE_ID_INTEL_BSW 0x22B7 +#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30 +#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
struct dwc3_pci { struct device *dev; @@ -187,6 +189,8 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Heikki Krogerus heikki.krogerus@linux.intel.com
commit b4c580a43d520b7812c0fd064fbab929ce2f1da0 upstream.
PCI IDs for Broxton based platforms.
Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Signed-off-by: Felipe Balbi balbi@ti.com [bwh: Backported to 3.16: adjust context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 4 ++++ 1 file changed, 4 insertions(+)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -33,6 +33,8 @@ #define PCI_DEVICE_ID_INTEL_BSW 0x22B7 #define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30 #define PCI_DEVICE_ID_INTEL_SPTH 0xa130 +#define PCI_DEVICE_ID_INTEL_BXT 0x0aaa +#define PCI_DEVICE_ID_INTEL_APL 0x5aaa
struct dwc3_pci { struct device *dev; @@ -191,6 +193,8 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Heikki Krogerus heikki.krogerus@linux.intel.com
commit 1ffb4d5cc78a3a99109ff0808ce6915de07a0588 upstream.
BXT-M is a Intel Broxton SoC based platform with unique PCI ID.
Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com [bwh: Backported to 3.16: adjust context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 2 ++ 1 file changed, 2 insertions(+)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -34,6 +34,7 @@ #define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30 #define PCI_DEVICE_ID_INTEL_SPTH 0xa130 #define PCI_DEVICE_ID_INTEL_BXT 0x0aaa +#define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa #define PCI_DEVICE_ID_INTEL_APL 0x5aaa
struct dwc3_pci { @@ -194,6 +195,7 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), }, { } /* Terminating Entry */ };
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Heikki Krogerus heikki.krogerus@linux.intel.com
commit 4491ed5042f0419b22a4b08331adb54af31e2caa upstream.
Intel Kabylake PCH has the same DWC3 than Intel Sunrisepoint. Add the new ID to the supported devices.
Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com [bwh: Backported to 3.16: adjust context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 2 ++ 1 file changed, 2 insertions(+)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -36,6 +36,7 @@ #define PCI_DEVICE_ID_INTEL_BXT 0x0aaa #define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa #define PCI_DEVICE_ID_INTEL_APL 0x5aaa +#define PCI_DEVICE_ID_INTEL_KBP 0xa2b0
struct dwc3_pci { struct device *dev; @@ -197,6 +198,7 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Heikki Krogerus heikki.krogerus@linux.intel.com
commit 8f8983a5683623b62b339d159573f95a1fce44f3 upstream.
Intel Gemini Lake SoC has the same DWC3 than Broxton. Add the new ID to the supported Devices.
Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com [bwh: Backported to 3.16: adjust context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 2 ++ 1 file changed, 2 insertions(+)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -37,6 +37,7 @@ #define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa #define PCI_DEVICE_ID_INTEL_APL 0x5aaa #define PCI_DEVICE_ID_INTEL_KBP 0xa2b0 +#define PCI_DEVICE_ID_INTEL_GLK 0x31aa
struct dwc3_pci { struct device *dev; @@ -199,6 +200,7 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Heikki Krogerus heikki.krogerus@linux.intel.com
commit 682179592e48fa66056fbad1a86604be4992f885 upstream.
Intel Cannonlake PCH has the same DWC3 than Intel Sunrisepoint. Add the new IDs to the supported devices.
Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com [bwh: Backported to 3.16: adjust context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 4 ++++ 1 file changed, 4 insertions(+)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -38,6 +38,8 @@ #define PCI_DEVICE_ID_INTEL_APL 0x5aaa #define PCI_DEVICE_ID_INTEL_KBP 0xa2b0 #define PCI_DEVICE_ID_INTEL_GLK 0x31aa +#define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee +#define PCI_DEVICE_ID_INTEL_CNPH 0xa36e
struct dwc3_pci { struct device *dev; @@ -201,6 +203,8 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPLP), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPH), }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Heikki Krogerus heikki.krogerus@linux.intel.com
commit 00908693c481f7298adf8cf4d2ff3dfbea8c375f upstream.
PCI IDs for Intel IceLake.
Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com [bwh: Backported to 3.16: adjust context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 2 ++ 1 file changed, 2 insertions(+)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -40,6 +40,7 @@ #define PCI_DEVICE_ID_INTEL_GLK 0x31aa #define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee #define PCI_DEVICE_ID_INTEL_CNPH 0xa36e +#define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee
struct dwc3_pci { struct device *dev; @@ -205,6 +206,7 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPLP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPH), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICLLP), }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Felipe Balbi felipe.balbi@linux.intel.com
commit 7ae622c978db6b2e28b4fced6ecd2a174492059d upstream.
This patch simply adds a new PCI Device ID
Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com [bwh: Backported to 3.16: - No properties support - Adjust context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 4 ++++ 1 file changed, 4 insertions(+)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -37,6 +37,7 @@ #define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa #define PCI_DEVICE_ID_INTEL_APL 0x5aaa #define PCI_DEVICE_ID_INTEL_KBP 0xa2b0 +#define PCI_DEVICE_ID_INTEL_CMLH 0x02ee #define PCI_DEVICE_ID_INTEL_GLK 0x31aa #define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee #define PCI_DEVICE_ID_INTEL_CNPH 0xa36e @@ -197,6 +198,7 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CMLH), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Felipe Balbi felipe.balbi@linux.intel.com
commit dbb0569de852fb4576d6f62078d515f989a181ca upstream.
This patch simply adds a new PCI Device ID
Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com [bwh: Backported to 3.16: - No properties support - Adjust context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 4 ++++ 1 file changed, 4 insertions(+)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -42,6 +42,7 @@ #define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee #define PCI_DEVICE_ID_INTEL_CNPH 0xa36e #define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee +#define PCI_DEVICE_ID_INTEL_EHLLP 0x4b7e
struct dwc3_pci { struct device *dev; @@ -209,6 +210,7 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPLP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPH), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICLLP), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EHLLP), }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Felipe Balbi felipe.balbi@linux.intel.com
commit b3649dee5fbb0f6585010e6e9313dfcbb075b22b upstream.
This patch adds the necessary PCI ID for TGP-LP devices.
Signed-off-by: Felipe Balbi felipe.balbi@linux.intel.com [bwh: Backported to 3.16: - No properties support - Adjust context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 4 ++++ 1 file changed, 4 insertions(+)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -43,6 +43,7 @@ #define PCI_DEVICE_ID_INTEL_CNPH 0xa36e #define PCI_DEVICE_ID_INTEL_ICLLP 0x34ee #define PCI_DEVICE_ID_INTEL_EHLLP 0x4b7e +#define PCI_DEVICE_ID_INTEL_TGPLP 0xa0ee
struct dwc3_pci { struct device *dev; @@ -211,6 +212,7 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPH), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICLLP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EHLLP), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGPLP), }, { } /* Terminating Entry */ }; MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Heikki Krogerus heikki.krogerus@linux.intel.com
commit 3c3caae4cd6e122472efcf64759ff6392fb6bce2 upstream.
The original ID that was added for Comet Lake PCH was actually for the -LP (low power) variant even though the constant for it said CMLH. Changing that while at it.
Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Acked-by: Felipe Balbi balbi@kernel.org Link: https://lore.kernel.org/r/20191212093713.60614-1-heikki.krogerus@linux.intel... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: - No properties support - Adjust context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/dwc3/dwc3-pci.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -37,7 +37,8 @@ #define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa #define PCI_DEVICE_ID_INTEL_APL 0x5aaa #define PCI_DEVICE_ID_INTEL_KBP 0xa2b0 -#define PCI_DEVICE_ID_INTEL_CMLH 0x02ee +#define PCI_DEVICE_ID_INTEL_CMLLP 0x02ee +#define PCI_DEVICE_ID_INTEL_CMLH 0x06ee #define PCI_DEVICE_ID_INTEL_GLK 0x31aa #define PCI_DEVICE_ID_INTEL_CNPLP 0x9dee #define PCI_DEVICE_ID_INTEL_CNPH 0xa36e @@ -200,6 +201,7 @@ static const struct pci_device_id dwc3_p { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CMLLP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CMLH), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Leo Yan leo.yan@linaro.org
commit 0e4f7f920a5c6bfe5e851e989f27b35a0cc7fb7e upstream.
As the commit 677fe555cbfb ("serial: imx: Fix recursive locking bug") has mentioned the uart driver might cause recursive locking between normal printing and the kernel debugging facilities (e.g. sysrq and oops). In the commit it gave out suggestion for fixing recursive locking issue: "The solution is to avoid locking in the sysrq case and trylock in the oops_in_progress case."
This patch follows the suggestion (also used the exactly same code with other serial drivers, e.g. amba-pl011.c) to fix the recursive locking issue, this can avoid stuck caused by deadlock and print out log for sysrq and oops.
Fixes: 04896a77a97b ("msm_serial: serial driver for MSM7K onboard serial peripheral.") Signed-off-by: Leo Yan leo.yan@linaro.org Reviewed-by: Jeffrey Hugo jeffrey.l.hugo@gmail.com Link: https://lore.kernel.org/r/20191127141544.4277-2-leo.yan@linaro.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/tty/serial/msm_serial.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
--- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -857,6 +857,7 @@ static void msm_console_write(struct con struct msm_port *msm_port; int num_newlines = 0; bool replaced = false; + int locked = 1;
BUG_ON(co->index < 0 || co->index >= UART_NR);
@@ -869,7 +870,13 @@ static void msm_console_write(struct con num_newlines++; count += num_newlines;
- spin_lock(&port->lock); + if (port->sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&port->lock); + else + spin_lock(&port->lock); + if (msm_port->is_uartdm) reset_dm_count(port, count);
@@ -906,7 +913,9 @@ static void msm_console_write(struct con msm_write(port, *bf, msm_port->is_uartdm ? UARTDM_TF : UART_TF); i += num_chars; } - spin_unlock(&port->lock); + + if (locked) + spin_unlock(&port->lock); }
static int __init msm_console_setup(struct console *co, char *options)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Moni Shoua monis@mellanox.com
commit 4bf9715f184969dc703bde7be94919995024a6a9 upstream.
When device is being removed (e.g during VPI port link type change from ETH to IB), tasks for gid table changes should not be executed.
Flush the current queue of tasks and block further tasks from entering the queue.
Signed-off-by: Moni Shoua monis@mellanox.com Signed-off-by: Or Gerlitz ogerlitz@mellanox.com Signed-off-by: Roland Dreier roland@purestorage.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/infiniband/hw/mlx4/main.c | 9 +++++++++ 1 file changed, 9 insertions(+)
--- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -1395,6 +1395,9 @@ static void update_gids_task(struct work int err; struct mlx4_dev *dev = gw->dev->dev;
+ if (!gw->dev->ib_active) + return; + mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) { pr_warn("update gid table failed %ld\n", PTR_ERR(mailbox)); @@ -1425,6 +1428,9 @@ static void reset_gids_task(struct work_ int err; struct mlx4_dev *dev = gw->dev->dev;
+ if (!gw->dev->ib_active) + return; + mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) { pr_warn("reset gid table failed\n"); @@ -2363,6 +2369,9 @@ static void mlx4_ib_remove(struct mlx4_d struct mlx4_ib_dev *ibdev = ibdev_ptr; int p;
+ ibdev->ib_active = false; + flush_workqueue(wq); + mlx4_ib_close_sriov(ibdev); mlx4_ib_mad_cleanup(ibdev); ib_unregister_device(&ibdev->ib_dev);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Parav Pandit parav@mellanox.com
commit 89f988d93c62384758b19323c886db917a80c371 upstream.
Current code device add sequence is:
ib_register_device() ib_mad_init() init_sriov_init() register_netdev_notifier()
Therefore, the remove sequence should be,
unregister_netdev_notifier() close_sriov() mad_cleanup() ib_unregister_device()
However it is not above. Hence, make do above remove sequence.
Fixes: fa417f7b520ee ("IB/mlx4: Add support for IBoE") Signed-off-by: Parav Pandit parav@mellanox.com Reviewed-by: Maor Gottlieb maorg@mellanox.com Signed-off-by: Leon Romanovsky leonro@mellanox.com Link: https://lore.kernel.org/r/20191212091214.315005-3-leon@kernel.org Signed-off-by: Doug Ledford dledford@redhat.com [bwh: Backported to 3.16: No need to call mlx4_ib_diag_cleanup()] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -2372,15 +2372,16 @@ static void mlx4_ib_remove(struct mlx4_d ibdev->ib_active = false; flush_workqueue(wq);
- mlx4_ib_close_sriov(ibdev); - mlx4_ib_mad_cleanup(ibdev); - ib_unregister_device(&ibdev->ib_dev); if (ibdev->iboe.nb.notifier_call) { if (unregister_netdevice_notifier(&ibdev->iboe.nb)) pr_warn("failure unregistering notifier\n"); ibdev->iboe.nb.notifier_call = NULL; }
+ mlx4_ib_close_sriov(ibdev); + mlx4_ib_mad_cleanup(ibdev); + ib_unregister_device(&ibdev->ib_dev); + mlx4_qp_release_range(dev, ibdev->steer_qpn_base, ibdev->steer_qpn_count); kfree(ibdev->ib_uc_qpns_bitmap);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov dmitry.torokhov@gmail.com
commit 4f3882177240a1f55e45a3d241d3121341bead78 upstream.
We should not be leaving half-mapped usages with potentially invalid keycodes, as that may confuse hidinput_find_key() when the key is located by index, which may end up feeding way too large keycode into the VT keyboard handler and cause OOB write there:
BUG: KASAN: global-out-of-bounds in clear_bit include/asm-generic/bitops-instrumented.h:56 [inline] BUG: KASAN: global-out-of-bounds in kbd_keycode drivers/tty/vt/keyboard.c:1411 [inline] BUG: KASAN: global-out-of-bounds in kbd_event+0xe6b/0x3790 drivers/tty/vt/keyboard.c:1495 Write of size 8 at addr ffffffff89a1b2d8 by task syz-executor108/1722 ... kbd_keycode drivers/tty/vt/keyboard.c:1411 [inline] kbd_event+0xe6b/0x3790 drivers/tty/vt/keyboard.c:1495 input_to_handler+0x3b6/0x4c0 drivers/input/input.c:118 input_pass_values.part.0+0x2e3/0x720 drivers/input/input.c:145 input_pass_values drivers/input/input.c:949 [inline] input_set_keycode+0x290/0x320 drivers/input/input.c:954 evdev_handle_set_keycode_v2+0xc4/0x120 drivers/input/evdev.c:882 evdev_do_ioctl drivers/input/evdev.c:1150 [inline]
Reported-by: syzbot+19340dff067c2d3835c0@syzkaller.appspotmail.com Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Tested-by: Benjamin Tissoires benjamin.tissoires@redhat.com Signed-off-by: Jiri Kosina jkosina@suse.cz Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/hid/hid-input.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
--- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -947,9 +947,15 @@ static void hidinput_configure_usage(str }
mapped: - if (device->driver->input_mapped && device->driver->input_mapped(device, - hidinput, field, usage, &bit, &max) < 0) - goto ignore; + if (device->driver->input_mapped && + device->driver->input_mapped(device, hidinput, field, usage, + &bit, &max) < 0) { + /* + * The driver indicated that no further generic handling + * of the usage is desired. + */ + return; + }
set_bit(usage->type, input->evbit);
@@ -1008,9 +1014,11 @@ mapped: set_bit(MSC_SCAN, input->mscbit); }
-ignore: return;
+ignore: + usage->type = 0; + usage->code = 0; }
void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik josef@toxicpanda.com
commit f72ff01df9cf5db25c76674cac16605992d15467 upstream.
Testing with the new fsstress uncovered a pretty nasty deadlock with lookup and snapshot deletion.
Process A unlink -> final iput -> inode_tree_del -> synchronize_srcu(subvol_srcu)
Process B btrfs_lookup <- srcu_read_lock() acquired here -> btrfs_iget -> find inode that has I_FREEING set -> __wait_on_freeing_inode()
We're holding the srcu_read_lock() while doing the iget in order to make sure our fs root doesn't go away, and then we are waiting for the inode to finish freeing. However because the free'ing process is doing a synchronize_srcu() we deadlock.
Fix this by dropping the synchronize_srcu() in inode_tree_del(). We don't need people to stop accessing the fs root at this point, we're only adding our empty root to the dead roots list.
A larger much more invasive fix is forthcoming to address how we deal with fs roots, but this fixes the immediate problem.
Fixes: 76dda93c6ae2 ("Btrfs: add snapshot/subvolume destroy ioctl") Signed-off-by: Josef Bacik josef@toxicpanda.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 3.16: No fs_info variable was used here] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -5140,7 +5140,6 @@ static void inode_tree_del(struct inode spin_unlock(&root->inode_lock);
if (empty && btrfs_root_refs(&root->root_item) == 0) { - synchronize_srcu(&root->fs_info->subvol_srcu); spin_lock(&root->inode_lock); empty = RB_EMPTY_ROOT(&root->inode_tree); spin_unlock(&root->inode_lock);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Filipe Manana fdmanana@suse.com
commit 6609fee8897ac475378388238456c84298bff802 upstream.
When a tree mod log user no longer needs to use the tree it calls btrfs_put_tree_mod_seq() to remove itself from the list of users and delete all no longer used elements of the tree's red black tree, which should be all elements with a sequence number less then our equals to the caller's sequence number. However the logic is broken because it can delete and free elements from the red black tree that have a sequence number greater then the caller's sequence number:
1) At a point in time we have sequence numbers 1, 2, 3 and 4 in the tree mod log;
2) The task which got assigned the sequence number 1 calls btrfs_put_tree_mod_seq();
3) Sequence number 1 is deleted from the list of sequence numbers;
4) The current minimum sequence number is computed to be the sequence number 2;
5) A task using sequence number 2 is at tree_mod_log_rewind() and gets a pointer to one of its elements from the red black tree through a call to tree_mod_log_search();
6) The task with sequence number 1 iterates the red black tree of tree modification elements and deletes (and frees) all elements with a sequence number less then or equals to 2 (the computed minimum sequence number) - it ends up only leaving elements with sequence numbers of 3 and 4;
7) The task with sequence number 2 now uses the pointer to its element, already freed by the other task, at __tree_mod_log_rewind(), resulting in a use-after-free issue. When CONFIG_DEBUG_PAGEALLOC=y it produces a trace like the following:
[16804.546854] general protection fault: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC PTI [16804.547451] CPU: 0 PID: 28257 Comm: pool Tainted: G W 5.4.0-rc8-btrfs-next-51 #1 [16804.548059] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-0-ga698c8995f-prebuilt.qemu.org 04/01/2014 [16804.548666] RIP: 0010:rb_next+0x16/0x50 (...) [16804.550581] RSP: 0018:ffffb948418ef9b0 EFLAGS: 00010202 [16804.551227] RAX: 6b6b6b6b6b6b6b6b RBX: ffff90e0247f6600 RCX: 6b6b6b6b6b6b6b6b [16804.551873] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff90e0247f6600 [16804.552504] RBP: ffff90dffe0d4688 R08: 0000000000000001 R09: 0000000000000000 [16804.553136] R10: ffff90dffa4a0040 R11: 0000000000000000 R12: 000000000000002e [16804.553768] R13: ffff90e0247f6600 R14: 0000000000001663 R15: ffff90dff77862b8 [16804.554399] FS: 00007f4b197ae700(0000) GS:ffff90e036a00000(0000) knlGS:0000000000000000 [16804.555039] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [16804.555683] CR2: 00007f4b10022000 CR3: 00000002060e2004 CR4: 00000000003606f0 [16804.556336] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [16804.556968] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [16804.557583] Call Trace: [16804.558207] __tree_mod_log_rewind+0xbf/0x280 [btrfs] [16804.558835] btrfs_search_old_slot+0x105/0xd00 [btrfs] [16804.559468] resolve_indirect_refs+0x1eb/0xc70 [btrfs] [16804.560087] ? free_extent_buffer.part.19+0x5a/0xc0 [btrfs] [16804.560700] find_parent_nodes+0x388/0x1120 [btrfs] [16804.561310] btrfs_check_shared+0x115/0x1c0 [btrfs] [16804.561916] ? extent_fiemap+0x59d/0x6d0 [btrfs] [16804.562518] extent_fiemap+0x59d/0x6d0 [btrfs] [16804.563112] ? __might_fault+0x11/0x90 [16804.563706] do_vfs_ioctl+0x45a/0x700 [16804.564299] ksys_ioctl+0x70/0x80 [16804.564885] ? trace_hardirqs_off_thunk+0x1a/0x20 [16804.565461] __x64_sys_ioctl+0x16/0x20 [16804.566020] do_syscall_64+0x5c/0x250 [16804.566580] entry_SYSCALL_64_after_hwframe+0x49/0xbe [16804.567153] RIP: 0033:0x7f4b1ba2add7 (...) [16804.568907] RSP: 002b:00007f4b197adc88 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [16804.569513] RAX: ffffffffffffffda RBX: 00007f4b100210d8 RCX: 00007f4b1ba2add7 [16804.570133] RDX: 00007f4b100210d8 RSI: 00000000c020660b RDI: 0000000000000003 [16804.570726] RBP: 000055de05a6cfe0 R08: 0000000000000000 R09: 00007f4b197add44 [16804.571314] R10: 0000000000000000 R11: 0000000000000246 R12: 00007f4b197add48 [16804.571905] R13: 00007f4b197add40 R14: 00007f4b100210d0 R15: 00007f4b197add50 (...) [16804.575623] ---[ end trace 87317359aad4ba50 ]---
Fix this by making btrfs_put_tree_mod_seq() skip deletion of elements that have a sequence number equals to the computed minimum sequence number, and not just elements with a sequence number greater then that minimum.
Fixes: bd989ba359f2ac ("Btrfs: add tree modification log functions") Reviewed-by: Josef Bacik josef@toxicpanda.com Signed-off-by: Filipe Manana fdmanana@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/ctree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -418,7 +418,7 @@ void btrfs_put_tree_mod_seq(struct btrfs for (node = rb_first(tm_root); node; node = next) { next = rb_next(node); tm = container_of(node, struct tree_mod_elem, node); - if (tm->seq > min_seq) + if (tm->seq >= min_seq) continue; rb_erase(node, tm_root); kfree(tm);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik josef@toxicpanda.com
commit c7e54b5102bf3614cadb9ca32d7be73bad6cecf0 upstream.
We can just abort the transaction here, and in fact do that for every other failure in this function except these two cases.
Reviewed-by: Filipe Manana fdmanana@suse.com Reviewed-by: Johannes Thumshirn jthumshirn@suse.de Signed-off-by: Josef Bacik josef@toxicpanda.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 3.16: - Add root as second argument to btrfs_abort_transaction() - Adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/ioctl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
--- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -580,12 +580,18 @@ static noinline int create_subvol(struct
btrfs_i_size_write(dir, dir->i_size + namelen * 2); ret = btrfs_update_inode(trans, root, dir); - BUG_ON(ret); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + goto fail; + }
ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, objectid, root->root_key.objectid, btrfs_ino(dir), index, name, namelen); - BUG_ON(ret); + if (ret) { + btrfs_abort_transaction(trans, root, ret); + goto fail; + }
ret = btrfs_uuid_tree_add(trans, root->fs_info->uuid_root, root_item.uuid, BTRFS_UUID_KEY_SUBVOL,
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik josef@toxicpanda.com
commit 714cd3e8cba6841220dce9063a7388a81de03825 upstream.
If we get an -ENOENT back from btrfs_uuid_iter_rem when iterating the uuid tree we'll just continue and do btrfs_next_item(). However we've done a btrfs_release_path() at this point and no longer have a valid path. So increment the key and go back and do a normal search.
Reviewed-by: Filipe Manana fdmanana@suse.com Reviewed-by: Johannes Thumshirn jthumshirn@suse.de Signed-off-by: Josef Bacik josef@toxicpanda.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/uuid-tree.c | 2 ++ 1 file changed, 2 insertions(+)
--- a/fs/btrfs/uuid-tree.c +++ b/fs/btrfs/uuid-tree.c @@ -333,6 +333,8 @@ again_search_slot: } if (ret < 0 && ret != -ENOENT) goto out; + key.offset++; + goto again_search_slot; } item_size -= sizeof(subid_le); offset += sizeof(subid_le);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik josef@toxicpanda.com
commit 9bc574de590510eff899c3ca8dbaf013566b5efe upstream.
My fsstress modifications coupled with generic/475 uncovered a failure to mount and replay the log if we hit a orphaned root. We do not want to replay the log for an orphan root, but it's completely legitimate to have an orphaned root with a log attached. Fix this by simply skipping replaying the log. We still need to pin it's root node so that we do not overwrite it while replaying other logs, as we re-read the log root at every stage of the replay.
Reviewed-by: Filipe Manana fdmanana@suse.com Signed-off-by: Josef Bacik josef@toxicpanda.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 3.16: - Pass fs_info->extent_root, instead of fs_info, as first argument to btrfs_pin_extent_for_log_replay() - Adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4583,9 +4583,29 @@ again: wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key); if (IS_ERR(wc.replay_dest)) { ret = PTR_ERR(wc.replay_dest); + + /* + * We didn't find the subvol, likely because it was + * deleted. This is ok, simply skip this log and go to + * the next one. + * + * We need to exclude the root because we can't have + * other log replays overwriting this log as we'll read + * it back in a few more times. This will keep our + * block from being modified, and we'll just bail for + * each subsequent pass. + */ + if (ret == -ENOENT) + ret = btrfs_pin_extent_for_log_replay( + fs_info->extent_root, + log->node->start, + log->node->len); free_extent_buffer(log->node); free_extent_buffer(log->commit_root); kfree(log); + + if (!ret) + goto next; btrfs_error(fs_info, ret, "Couldn't read target root " "for tree log recovery."); goto error; @@ -4600,7 +4620,6 @@ again: path); }
- key.offset = found_key.offset - 1; wc.replay_dest->log_root = NULL; free_extent_buffer(log->node); free_extent_buffer(log->commit_root); @@ -4608,9 +4627,10 @@ again:
if (ret) goto error; - +next: if (found_key.offset == 0) break; + key.offset = found_key.offset - 1; } btrfs_release_path(path);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik josef@toxicpanda.com
commit ca1aa2818a53875cfdd175fb5e9a2984e997cce9 upstream.
If we fail to read the fs root corresponding with a reloc root we'll just break out and free the reloc roots. But we remove our current reloc_root from this list higher up, which means we'll leak this reloc_root. Fix this by adding ourselves back to the reloc_roots list so we are properly cleaned up.
Reviewed-by: Filipe Manana fdmanana@suse.com Reviewed-by: Johannes Thumshirn jthumshirn@suse.de Signed-off-by: Josef Bacik josef@toxicpanda.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/relocation.c | 1 + 1 file changed, 1 insertion(+)
--- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c @@ -4449,6 +4449,7 @@ int btrfs_recover_relocation(struct btrf reloc_root->root_key.offset); if (IS_ERR(fs_root)) { err = PTR_ERR(fs_root); + list_add_tail(&reloc_root->root_list, &reloc_roots); goto out_free; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Filipe Manana fdmanana@suse.com
commit de7999afedff02c6631feab3ea726a0e8f8c3d40 upstream.
When starting writeback for a range that covers part of a preallocated extent, due to a race with writeback for another range that also covers another part of the same preallocated extent, we can end up in an infinite loop.
Consider the following example where for inode 280 we have two dirty ranges:
range A, from 294912 to 303103, 8192 bytes range B, from 348160 to 438271, 90112 bytes
and we have the following file extent item layout for our inode:
leaf 38895616 gen 24544 total ptrs 29 free space 13820 owner 5 (...) item 27 key (280 108 200704) itemoff 14598 itemsize 53 extent data disk bytenr 0 nr 0 type 1 (regular) extent data offset 0 nr 94208 ram 94208 item 28 key (280 108 294912) itemoff 14545 itemsize 53 extent data disk bytenr 10433052672 nr 81920 type 2 (prealloc) extent data offset 0 nr 81920 ram 81920
Then the following happens:
1) Writeback starts for range B (from 348160 to 438271), execution of run_delalloc_nocow() starts;
2) The first iteration of run_delalloc_nocow()'s whil loop leaves us at the extent item at slot 28, pointing to the prealloc extent item covering the range from 294912 to 376831. This extent covers part of our range;
3) An ordered extent is created against that extent, covering the file range from 348160 to 376831 (28672 bytes);
4) We adjust 'cur_offset' to 376832 and move on to the next iteration of the while loop;
5) The call to btrfs_lookup_file_extent() leaves us at the same leaf, pointing to slot 29, 1 slot after the last item (the extent item we processed in the previous iteration);
6) Because we are a slot beyond the last item, we call btrfs_next_leaf(), which releases the search path before doing a another search for the last key of the leaf (280 108 294912);
7) Right after btrfs_next_leaf() released the path, and before it did another search for the last key of the leaf, writeback for the range A (from 294912 to 303103) completes (it was previously started at some point);
8) Upon completion of the ordered extent for range A, the prealloc extent we previously found got split into two extent items, one covering the range from 294912 to 303103 (8192 bytes), with a type of regular extent (and no longer prealloc) and another covering the range from 303104 to 376831 (73728 bytes), with a type of prealloc and an offset of 8192 bytes. So our leaf now has the following layout:
leaf 38895616 gen 24544 total ptrs 31 free space 13664 owner 5 (...) item 27 key (280 108 200704) itemoff 14598 itemsize 53 extent data disk bytenr 0 nr 0 type 1 extent data offset 0 nr 8192 ram 94208 item 28 key (280 108 208896) itemoff 14545 itemsize 53 extent data disk bytenr 10433142784 nr 86016 type 1 extent data offset 0 nr 86016 ram 86016 item 29 key (280 108 294912) itemoff 14492 itemsize 53 extent data disk bytenr 10433052672 nr 81920 type 1 extent data offset 0 nr 8192 ram 81920 item 30 key (280 108 303104) itemoff 14439 itemsize 53 extent data disk bytenr 10433052672 nr 81920 type 2 extent data offset 8192 nr 73728 ram 81920
9) After btrfs_next_leaf() returns, we have our path pointing to that same leaf and at slot 30, since it has a key we didn't have before and it's the first key greater then the key that was previously the last key of the leaf (key (280 108 294912));
10) The extent item at slot 30 covers the range from 303104 to 376831 which is in our target range, so we process it, despite having already created an ordered extent against this extent for the file range from 348160 to 376831. This is because we skip to the next extent item only if its end is less than or equals to the start of our delalloc range, and not less than or equals to the current offset ('cur_offset');
11) As a result we compute 'num_bytes' as:
num_bytes = min(end + 1, extent_end) - cur_offset; = min(438271 + 1, 376832) - 376832 = 0
12) We then call create_io_em() for a 0 bytes range starting at offset 376832;
13) Then create_io_em() enters an infinite loop because its calls to btrfs_drop_extent_cache() do nothing due to the 0 length range passed to it. So no existing extent maps that cover the offset 376832 get removed, and therefore calls to add_extent_mapping() return -EEXIST, resulting in an infinite loop. This loop from create_io_em() is the following:
do { btrfs_drop_extent_cache(BTRFS_I(inode), em->start, em->start + em->len - 1, 0); write_lock(&em_tree->lock); ret = add_extent_mapping(em_tree, em, 1); write_unlock(&em_tree->lock); /* * The caller has taken lock_extent(), who could race with us * to add em? */ } while (ret == -EEXIST);
Also, each call to btrfs_drop_extent_cache() triggers a warning because the start offset passed to it (376832) is smaller then the end offset (376832 - 1) passed to it by -1, due to the 0 length:
[258532.052621] ------------[ cut here ]------------ [258532.052643] WARNING: CPU: 0 PID: 9987 at fs/btrfs/file.c:602 btrfs_drop_extent_cache+0x3f4/0x590 [btrfs] (...) [258532.052672] CPU: 0 PID: 9987 Comm: fsx Tainted: G W 5.4.0-rc7-btrfs-next-64 #1 [258532.052673] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-0-ga698c8995f-prebuilt.qemu.org 04/01/2014 [258532.052691] RIP: 0010:btrfs_drop_extent_cache+0x3f4/0x590 [btrfs] (...) [258532.052695] RSP: 0018:ffffb4be0153f860 EFLAGS: 00010287 [258532.052700] RAX: ffff975b445ee360 RBX: ffff975b44eb3e08 RCX: 0000000000000000 [258532.052700] RDX: 0000000000038fff RSI: 0000000000039000 RDI: ffff975b445ee308 [258532.052700] RBP: 0000000000038fff R08: 0000000000000000 R09: 0000000000000001 [258532.052701] R10: ffff975b513c5c10 R11: 00000000e3c0cfa9 R12: 0000000000039000 [258532.052703] R13: ffff975b445ee360 R14: 00000000ffffffef R15: ffff975b445ee308 [258532.052705] FS: 00007f86a821de80(0000) GS:ffff975b76a00000(0000) knlGS:0000000000000000 [258532.052707] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [258532.052708] CR2: 00007fdacf0f3ab4 CR3: 00000001f9d26002 CR4: 00000000003606f0 [258532.052712] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [258532.052717] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [258532.052717] Call Trace: [258532.052718] ? preempt_schedule_common+0x32/0x70 [258532.052722] ? ___preempt_schedule+0x16/0x20 [258532.052741] create_io_em+0xff/0x180 [btrfs] [258532.052767] run_delalloc_nocow+0x942/0xb10 [btrfs] [258532.052791] btrfs_run_delalloc_range+0x30b/0x520 [btrfs] [258532.052812] ? find_lock_delalloc_range+0x221/0x250 [btrfs] [258532.052834] writepage_delalloc+0xe4/0x140 [btrfs] [258532.052855] __extent_writepage+0x110/0x4e0 [btrfs] [258532.052876] extent_write_cache_pages+0x21c/0x480 [btrfs] [258532.052906] extent_writepages+0x52/0xb0 [btrfs] [258532.052911] do_writepages+0x23/0x80 [258532.052915] __filemap_fdatawrite_range+0xd2/0x110 [258532.052938] btrfs_fdatawrite_range+0x1b/0x50 [btrfs] [258532.052954] start_ordered_ops+0x57/0xa0 [btrfs] [258532.052973] ? btrfs_sync_file+0x225/0x490 [btrfs] [258532.052988] btrfs_sync_file+0x225/0x490 [btrfs] [258532.052997] __x64_sys_msync+0x199/0x200 [258532.053004] do_syscall_64+0x5c/0x250 [258532.053007] entry_SYSCALL_64_after_hwframe+0x49/0xbe [258532.053010] RIP: 0033:0x7f86a7dfd760 (...) [258532.053014] RSP: 002b:00007ffd99af0368 EFLAGS: 00000246 ORIG_RAX: 000000000000001a [258532.053016] RAX: ffffffffffffffda RBX: 0000000000000ec9 RCX: 00007f86a7dfd760 [258532.053017] RDX: 0000000000000004 RSI: 000000000000836c RDI: 00007f86a8221000 [258532.053019] RBP: 0000000000021ec9 R08: 0000000000000003 R09: 00007f86a812037c [258532.053020] R10: 0000000000000001 R11: 0000000000000246 R12: 00000000000074a3 [258532.053021] R13: 00007f86a8221000 R14: 000000000000836c R15: 0000000000000001 [258532.053032] irq event stamp: 1653450494 [258532.053035] hardirqs last enabled at (1653450493): [<ffffffff9dec69f9>] _raw_spin_unlock_irq+0x29/0x50 [258532.053037] hardirqs last disabled at (1653450494): [<ffffffff9d4048ea>] trace_hardirqs_off_thunk+0x1a/0x20 [258532.053039] softirqs last enabled at (1653449852): [<ffffffff9e200466>] __do_softirq+0x466/0x6bd [258532.053042] softirqs last disabled at (1653449845): [<ffffffff9d4c8a0c>] irq_exit+0xec/0x120 [258532.053043] ---[ end trace 8476fce13d9ce20a ]---
Which results in flooding dmesg/syslog since btrfs_drop_extent_cache() uses WARN_ON() and not WARN_ON_ONCE().
So fix this issue by changing run_delalloc_nocow()'s loop to move to the next extent item when the current extent item ends at at offset less than or equals to the current offset instead of the start offset.
Fixes: 80ff385665b7fc ("Btrfs: update nodatacow code v2") Reviewed-by: Josef Bacik josef@toxicpanda.com Signed-off-by: Filipe Manana fdmanana@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1283,7 +1283,11 @@ next_slot: btrfs_file_extent_num_bytes(leaf, fi); disk_num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); - if (extent_end <= start) { + /* + * If the extent we got ends before our current offset, + * skip to the next extent. + */ + if (extent_end <= cur_offset) { path->slots[0]++; goto next_slot; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Lu Fengqi lufq.fnst@cn.fujitsu.com
commit 5b7d687ad5913a56b6a8788435d7a53990b4176d upstream.
Although it is safe to call this on already released paths with no locks held or extent buffers, removing the redundant btrfs_release_path is reasonable.
Signed-off-by: Lu Fengqi lufq.fnst@cn.fujitsu.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 3.16 as dependency of commit d49d3287e74f "btrfs: fix invalid removal of root ref"] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/inode.c | 1 - 1 file changed, 1 deletion(-)
--- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4031,7 +4031,6 @@ int btrfs_unlink_subvol(struct btrfs_tra
leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - btrfs_release_path(path); index = key.offset; } btrfs_release_path(path);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik josef@toxicpanda.com
commit 423a716cd7be16fb08690760691befe3be97d3fc upstream.
btrfs_del_root_ref() will simply WARN_ON() if the ref doesn't match in any way, and then continue to delete the reference. This shouldn't happen, we have these values because there's more to the reference than the original root and the sub root. If any of these checks fail, return -ENOENT.
Signed-off-by: Josef Bacik josef@toxicpanda.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/root-tree.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
--- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c @@ -373,11 +373,13 @@ again: leaf = path->nodes[0]; ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); - - WARN_ON(btrfs_root_ref_dirid(leaf, ref) != dirid); - WARN_ON(btrfs_root_ref_name_len(leaf, ref) != name_len); ptr = (unsigned long)(ref + 1); - WARN_ON(memcmp_extent_buffer(leaf, name, ptr, name_len)); + if ((btrfs_root_ref_dirid(leaf, ref) != dirid) || + (btrfs_root_ref_name_len(leaf, ref) != name_len) || + memcmp_extent_buffer(leaf, name, ptr, name_len)) { + err = -ENOENT; + goto out; + } *sequence = btrfs_root_ref_sequence(leaf, ref);
ret = btrfs_del_item(trans, tree_root, path);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Josef Bacik josef@toxicpanda.com
commit b35cf1f0bf1f2b0b193093338414b9bd63b29015 upstream.
The fstest btrfs/154 reports
[ 8675.381709] BTRFS: Transaction aborted (error -28) [ 8675.383302] WARNING: CPU: 1 PID: 31900 at fs/btrfs/block-group.c:2038 btrfs_create_pending_block_groups+0x1e0/0x1f0 [btrfs] [ 8675.390925] CPU: 1 PID: 31900 Comm: btrfs Not tainted 5.5.0-rc6-default+ #935 [ 8675.392780] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba527-rebuilt.opensuse.org 04/01/2014 [ 8675.395452] RIP: 0010:btrfs_create_pending_block_groups+0x1e0/0x1f0 [btrfs] [ 8675.402672] RSP: 0018:ffffb2090888fb00 EFLAGS: 00010286 [ 8675.404413] RAX: 0000000000000000 RBX: ffff92026dfa91c8 RCX: 0000000000000001 [ 8675.406609] RDX: 0000000000000000 RSI: ffffffff8e100899 RDI: ffffffff8e100971 [ 8675.408775] RBP: ffff920247c61660 R08: 0000000000000000 R09: 0000000000000000 [ 8675.410978] R10: 0000000000000000 R11: 0000000000000000 R12: 00000000ffffffe4 [ 8675.412647] R13: ffff92026db74000 R14: ffff920247c616b8 R15: ffff92026dfbc000 [ 8675.413994] FS: 00007fd5e57248c0(0000) GS:ffff92027d800000(0000) knlGS:0000000000000000 [ 8675.416146] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 8675.417833] CR2: 0000564aa51682d8 CR3: 000000006dcbc004 CR4: 0000000000160ee0 [ 8675.419801] Call Trace: [ 8675.420742] btrfs_start_dirty_block_groups+0x355/0x480 [btrfs] [ 8675.422600] btrfs_commit_transaction+0xc8/0xaf0 [btrfs] [ 8675.424335] reset_balance_state+0x14a/0x190 [btrfs] [ 8675.425824] btrfs_balance.cold+0xe7/0x154 [btrfs] [ 8675.427313] ? kmem_cache_alloc_trace+0x235/0x2c0 [ 8675.428663] btrfs_ioctl_balance+0x298/0x350 [btrfs] [ 8675.430285] btrfs_ioctl+0x466/0x2550 [btrfs] [ 8675.431788] ? mem_cgroup_charge_statistics+0x51/0xf0 [ 8675.433487] ? mem_cgroup_commit_charge+0x56/0x400 [ 8675.435122] ? do_raw_spin_unlock+0x4b/0xc0 [ 8675.436618] ? _raw_spin_unlock+0x1f/0x30 [ 8675.438093] ? __handle_mm_fault+0x499/0x740 [ 8675.439619] ? do_vfs_ioctl+0x56e/0x770 [ 8675.441034] do_vfs_ioctl+0x56e/0x770 [ 8675.442411] ksys_ioctl+0x3a/0x70 [ 8675.443718] ? trace_hardirqs_off_thunk+0x1a/0x1c [ 8675.445333] __x64_sys_ioctl+0x16/0x20 [ 8675.446705] do_syscall_64+0x50/0x210 [ 8675.448059] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 8675.479187] BTRFS: error (device vdb) in btrfs_create_pending_block_groups:2038: errno=-28 No space left
We now use btrfs_can_overcommit() to see if we can flip a block group read only. Before this would fail because we weren't taking into account the usable un-allocated space for allocating chunks. With my patches we were allowed to do the balance, which is technically correct.
The test is trying to start balance on degraded mount. So now we're trying to allocate a chunk and cannot because we want to allocate a RAID1 chunk, but there's only 1 device that's available for usage. This results in an ENOSPC.
But we shouldn't even be making it this far, we don't have enough devices to restripe. The problem is we're using btrfs_num_devices(), that also includes missing devices. That's not actually what we want, we need to use rw_devices.
The chunk_mutex is not needed here, rw_devices changes only in device add, remove or replace, all are excluded by EXCL_OP mechanism.
Fixes: e4d8ec0f65b9 ("Btrfs: implement online profile changing") Signed-off-by: Josef Bacik josef@toxicpanda.com Reviewed-by: David Sterba dsterba@suse.com [ add stacktrace, update changelog, drop chunk_mutex ] Signed-off-by: David Sterba dsterba@suse.com [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/btrfs/volumes.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
--- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3248,7 +3248,11 @@ int btrfs_balance(struct btrfs_balance_c } }
- num_devices = fs_info->fs_devices->num_devices; + /* + * rw_devices will not change at the moment, device add/delete/replace + * are excluded by EXCL_OP + */ + num_devices = fs_info->fs_devices->rw_devices; btrfs_dev_replace_lock(&fs_info->dev_replace); if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) { BUG_ON(num_devices < 1);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara jack@suse.cz
commit 109ba779d6cca2d519c5dd624a3276d03e21948e upstream.
ext4_check_dir_entry() currently does not catch a case when a directory entry ends so close to the block end that the header of the next directory entry would not fit in the remaining space. This can lead to directory iteration code trying to access address beyond end of current buffer head leading to oops.
Signed-off-by: Jan Kara jack@suse.cz Link: https://lore.kernel.org/r/20191202170213.4761-3-jack@suse.cz Signed-off-by: Theodore Ts'o tytso@mit.edu Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/ext4/dir.c | 5 +++++ 1 file changed, 5 insertions(+)
--- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -78,6 +78,11 @@ int __ext4_check_dir_entry(const char *f error_msg = "rec_len is too small for name_len"; else if (unlikely(((char *) de - buf) + rlen > size)) error_msg = "directory entry overrun"; + else if (unlikely(((char *) de - buf) + rlen > + size - EXT4_DIR_REC_LEN(1) && + ((char *) de - buf) + rlen != size)) { + error_msg = "directory entry too close to block end"; + } else if (unlikely(le32_to_cpu(de->inode) > le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))) error_msg = "inode out of bounds";
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Christophe Leroy christophe.leroy@c-s.fr
commit 099bc4812f09155da77eeb960a983470249c9ce1 upstream.
Before commit 0366a1c70b89 ("powerpc/irq: Run softirqs off the top of the irq stack"), check_stack_overflow() was called by do_IRQ(), before switching to the irq stack. In that commit, do_IRQ() was renamed __do_irq(), and is now executing on the irq stack, so check_stack_overflow() has just become almost useless.
Move check_stack_overflow() call in do_IRQ() to do the check while still on the current stack.
Fixes: 0366a1c70b89 ("powerpc/irq: Run softirqs off the top of the irq stack") Signed-off-by: Christophe Leroy christophe.leroy@c-s.fr Signed-off-by: Michael Ellerman mpe@ellerman.id.au Link: https://lore.kernel.org/r/e033aa8116ab12b7ca9a9c75189ad0741e3b9b5f.157587234... Signed-off-by: Ben Hutchings ben@decadent.org.uk --- arch/powerpc/kernel/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -471,8 +471,6 @@ void __do_irq(struct pt_regs *regs)
trace_irq_entry(regs);
- check_stack_overflow(); - /* * Query the platform PIC for the interrupt & ack it. * @@ -504,6 +502,8 @@ void do_IRQ(struct pt_regs *regs) irqtp = hardirq_ctx[raw_smp_processor_id()]; sirqtp = softirq_ctx[raw_smp_processor_id()];
+ check_stack_overflow(); + /* Already there ? */ if (unlikely(curtp == irqtp || curtp == sirqtp)) { __do_irq(regs);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet edumazet@google.com
commit 5c9934b6767b16ba60be22ec3cbd4379ad64170d upstream.
We got another syzbot report [1] that tells us we must use write_lock_irq()/write_unlock_irq() to avoid possible deadlock.
[1]
WARNING: inconsistent lock state 5.5.0-rc1-syzkaller #0 Not tainted -------------------------------- inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-R} usage. syz-executor826/9605 [HC1[1]:SC0[0]:HE0:SE1] takes: ffffffff8a128718 (disc_data_lock){+-..}, at: sp_get.isra.0+0x1d/0xf0 drivers/net/ppp/ppp_synctty.c:138 {HARDIRQ-ON-W} state was registered at: lock_acquire+0x190/0x410 kernel/locking/lockdep.c:4485 __raw_write_lock_bh include/linux/rwlock_api_smp.h:203 [inline] _raw_write_lock_bh+0x33/0x50 kernel/locking/spinlock.c:319 sixpack_close+0x1d/0x250 drivers/net/hamradio/6pack.c:657 tty_ldisc_close.isra.0+0x119/0x1a0 drivers/tty/tty_ldisc.c:489 tty_set_ldisc+0x230/0x6b0 drivers/tty/tty_ldisc.c:585 tiocsetd drivers/tty/tty_io.c:2337 [inline] tty_ioctl+0xe8d/0x14f0 drivers/tty/tty_io.c:2597 vfs_ioctl fs/ioctl.c:47 [inline] file_ioctl fs/ioctl.c:545 [inline] do_vfs_ioctl+0x977/0x14e0 fs/ioctl.c:732 ksys_ioctl+0xab/0xd0 fs/ioctl.c:749 __do_sys_ioctl fs/ioctl.c:756 [inline] __se_sys_ioctl fs/ioctl.c:754 [inline] __x64_sys_ioctl+0x73/0xb0 fs/ioctl.c:754 do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 entry_SYSCALL_64_after_hwframe+0x49/0xbe irq event stamp: 3946 hardirqs last enabled at (3945): [<ffffffff87c86e43>] __raw_spin_unlock_irq include/linux/spinlock_api_smp.h:168 [inline] hardirqs last enabled at (3945): [<ffffffff87c86e43>] _raw_spin_unlock_irq+0x23/0x80 kernel/locking/spinlock.c:199 hardirqs last disabled at (3946): [<ffffffff8100675f>] trace_hardirqs_off_thunk+0x1a/0x1c arch/x86/entry/thunk_64.S:42 softirqs last enabled at (2658): [<ffffffff86a8b4df>] spin_unlock_bh include/linux/spinlock.h:383 [inline] softirqs last enabled at (2658): [<ffffffff86a8b4df>] clusterip_netdev_event+0x46f/0x670 net/ipv4/netfilter/ipt_CLUSTERIP.c:222 softirqs last disabled at (2656): [<ffffffff86a8b22b>] spin_lock_bh include/linux/spinlock.h:343 [inline] softirqs last disabled at (2656): [<ffffffff86a8b22b>] clusterip_netdev_event+0x1bb/0x670 net/ipv4/netfilter/ipt_CLUSTERIP.c:196
other info that might help us debug this: Possible unsafe locking scenario:
CPU0 ---- lock(disc_data_lock); <Interrupt> lock(disc_data_lock);
*** DEADLOCK ***
5 locks held by syz-executor826/9605: #0: ffff8880a905e198 (&tty->legacy_mutex){+.+.}, at: tty_lock+0xc7/0x130 drivers/tty/tty_mutex.c:19 #1: ffffffff899a56c0 (rcu_read_lock){....}, at: mutex_spin_on_owner+0x0/0x330 kernel/locking/mutex.c:413 #2: ffff8880a496a2b0 (&(&i->lock)->rlock){-.-.}, at: spin_lock include/linux/spinlock.h:338 [inline] #2: ffff8880a496a2b0 (&(&i->lock)->rlock){-.-.}, at: serial8250_interrupt+0x2d/0x1a0 drivers/tty/serial/8250/8250_core.c:116 #3: ffffffff8c104048 (&port_lock_key){-.-.}, at: serial8250_handle_irq.part.0+0x24/0x330 drivers/tty/serial/8250/8250_port.c:1823 #4: ffff8880a905e090 (&tty->ldisc_sem){++++}, at: tty_ldisc_ref+0x22/0x90 drivers/tty/tty_ldisc.c:288
stack backtrace: CPU: 1 PID: 9605 Comm: syz-executor826 Not tainted 5.5.0-rc1-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: <IRQ> __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x197/0x210 lib/dump_stack.c:118 print_usage_bug.cold+0x327/0x378 kernel/locking/lockdep.c:3101 valid_state kernel/locking/lockdep.c:3112 [inline] mark_lock_irq kernel/locking/lockdep.c:3309 [inline] mark_lock+0xbb4/0x1220 kernel/locking/lockdep.c:3666 mark_usage kernel/locking/lockdep.c:3554 [inline] __lock_acquire+0x1e55/0x4a00 kernel/locking/lockdep.c:3909 lock_acquire+0x190/0x410 kernel/locking/lockdep.c:4485 __raw_read_lock include/linux/rwlock_api_smp.h:149 [inline] _raw_read_lock+0x32/0x50 kernel/locking/spinlock.c:223 sp_get.isra.0+0x1d/0xf0 drivers/net/ppp/ppp_synctty.c:138 sixpack_write_wakeup+0x25/0x340 drivers/net/hamradio/6pack.c:402 tty_wakeup+0xe9/0x120 drivers/tty/tty_io.c:536 tty_port_default_wakeup+0x2b/0x40 drivers/tty/tty_port.c:50 tty_port_tty_wakeup+0x57/0x70 drivers/tty/tty_port.c:387 uart_write_wakeup+0x46/0x70 drivers/tty/serial/serial_core.c:104 serial8250_tx_chars+0x495/0xaf0 drivers/tty/serial/8250/8250_port.c:1761 serial8250_handle_irq.part.0+0x2a2/0x330 drivers/tty/serial/8250/8250_port.c:1834 serial8250_handle_irq drivers/tty/serial/8250/8250_port.c:1820 [inline] serial8250_default_handle_irq+0xc0/0x150 drivers/tty/serial/8250/8250_port.c:1850 serial8250_interrupt+0xf1/0x1a0 drivers/tty/serial/8250/8250_core.c:126 __handle_irq_event_percpu+0x15d/0x970 kernel/irq/handle.c:149 handle_irq_event_percpu+0x74/0x160 kernel/irq/handle.c:189 handle_irq_event+0xa7/0x134 kernel/irq/handle.c:206 handle_edge_irq+0x25e/0x8d0 kernel/irq/chip.c:830 generic_handle_irq_desc include/linux/irqdesc.h:156 [inline] do_IRQ+0xde/0x280 arch/x86/kernel/irq.c:250 common_interrupt+0xf/0xf arch/x86/entry/entry_64.S:607 </IRQ> RIP: 0010:cpu_relax arch/x86/include/asm/processor.h:685 [inline] RIP: 0010:mutex_spin_on_owner+0x247/0x330 kernel/locking/mutex.c:579 Code: c3 be 08 00 00 00 4c 89 e7 e8 e5 06 59 00 4c 89 e0 48 c1 e8 03 42 80 3c 38 00 0f 85 e1 00 00 00 49 8b 04 24 a8 01 75 96 f3 90 <e9> 2f fe ff ff 0f 0b e8 0d 19 09 00 84 c0 0f 85 ff fd ff ff 48 c7 RSP: 0018:ffffc90001eafa20 EFLAGS: 00000246 ORIG_RAX: ffffffffffffffd7 RAX: 0000000000000000 RBX: ffff88809fd9e0c0 RCX: 1ffffffff13266dd RDX: 0000000000000000 RSI: 0000000000000008 RDI: 0000000000000000 RBP: ffffc90001eafa60 R08: 1ffff11013d22898 R09: ffffed1013d22899 R10: ffffed1013d22898 R11: ffff88809e9144c7 R12: ffff8880a905e138 R13: ffff88809e9144c0 R14: 0000000000000000 R15: dffffc0000000000 mutex_optimistic_spin kernel/locking/mutex.c:673 [inline] __mutex_lock_common kernel/locking/mutex.c:962 [inline] __mutex_lock+0x32b/0x13c0 kernel/locking/mutex.c:1106 mutex_lock_nested+0x16/0x20 kernel/locking/mutex.c:1121 tty_lock+0xc7/0x130 drivers/tty/tty_mutex.c:19 tty_release+0xb5/0xe90 drivers/tty/tty_io.c:1665 __fput+0x2ff/0x890 fs/file_table.c:280 ____fput+0x16/0x20 fs/file_table.c:313 task_work_run+0x145/0x1c0 kernel/task_work.c:113 exit_task_work include/linux/task_work.h:22 [inline] do_exit+0x8e7/0x2ef0 kernel/exit.c:797 do_group_exit+0x135/0x360 kernel/exit.c:895 __do_sys_exit_group kernel/exit.c:906 [inline] __se_sys_exit_group kernel/exit.c:904 [inline] __x64_sys_exit_group+0x44/0x50 kernel/exit.c:904 do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x43fef8 Code: Bad RIP value. RSP: 002b:00007ffdb07d2338 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 000000000043fef8 RDX: 0000000000000000 RSI: 000000000000003c RDI: 0000000000000000 RBP: 00000000004bf730 R08: 00000000000000e7 R09: ffffffffffffffd0 R10: 00000000004002c8 R11: 0000000000000246 R12: 0000000000000001 R13: 00000000006d1180 R14: 0000000000000000 R15: 0000000000000000
Fixes: 6e4e2f811bad ("6pack,mkiss: fix lock inconsistency") Signed-off-by: Eric Dumazet edumazet@google.com Reported-by: syzbot syzkaller@googlegroups.com Cc: Arnd Bergmann arnd@arndb.de Signed-off-by: Jakub Kicinski jakub.kicinski@netronome.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/hamradio/6pack.c | 4 ++-- drivers/net/hamradio/mkiss.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
--- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -685,10 +685,10 @@ static void sixpack_close(struct tty_str { struct sixpack *sp;
- write_lock_bh(&disc_data_lock); + write_lock_irq(&disc_data_lock); sp = tty->disc_data; tty->disc_data = NULL; - write_unlock_bh(&disc_data_lock); + write_unlock_irq(&disc_data_lock); if (!sp) return;
--- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -811,10 +811,10 @@ static void mkiss_close(struct tty_struc { struct mkiss *ax;
- write_lock_bh(&disc_data_lock); + write_lock_irq(&disc_data_lock); ax = tty->disc_data; tty->disc_data = NULL; - write_unlock_bh(&disc_data_lock); + write_unlock_irq(&disc_data_lock);
if (!ax) return;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet edumazet@google.com
commit 1f85e6267caca44b30c54711652b0726fadbb131 upstream.
Backport of commit fdfc5c8594c2 ("tcp: remove empty skb from write queue in error cases") in linux-4.14 stable triggered various bugs. One of them has been fixed in commit ba2ddb43f270 ("tcp: Don't dequeue SYN/FIN-segments from write-queue"), but we still have crashes in some occasions.
Root-cause is that when tcp_sendmsg() has allocated a fresh skb and could not append a fragment before being blocked in sk_stream_wait_memory(), tcp_write_xmit() might be called and decide to send this fresh and empty skb.
Sending an empty packet is not only silly, it might have caused many issues we had in the past with tp->packets_out being out of sync.
Fixes: c65f7f00c587 ("[TCP]: Simplify SKB data portion allocation with NETIF_F_SG.") Signed-off-by: Eric Dumazet edumazet@google.com Cc: Christoph Paasch cpaasch@apple.com Acked-by: Neal Cardwell ncardwell@google.com Cc: Jason Baron jbaron@akamai.com Acked-by: Soheil Hassas Yeganeh soheil@google.com Signed-off-by: Jakub Kicinski jakub.kicinski@netronome.com [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/ipv4/tcp_output.c | 8 ++++++++ 1 file changed, 8 insertions(+)
--- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1992,6 +1992,14 @@ static bool tcp_write_xmit(struct sock * unlikely(tso_fragment(sk, skb, limit, mss_now, gfp))) break;
+ /* Argh, we hit an empty skb(), presumably a thread + * is sleeping in sendmsg()/sk_stream_wait_memory(). + * We do not want to send a pure-ack packet and have + * a strange looking rtx queue with empty packet(s). + */ + if (TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) + break; + TCP_SKB_CB(skb)->when = tcp_time_stamp;
if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai tiwai@suse.de
commit add9d56d7b3781532208afbff5509d7382fb6efe upstream.
The current PCM code doesn't initialize explicitly the buffers allocated for PCM streams, hence it might leak some uninitialized kernel data or previous stream contents by mmapping or reading the buffer before actually starting the stream.
Since this is a common problem, this patch simply adds the clearance of the buffer data at hw_params callback. Although this does only zero-clear no matter which format is used, which doesn't mean the silence for some formats, but it should be OK because the intention is just to clear the previous data on the buffer.
Reported-by: Lionel Koenig lionel.koenig@gmail.com Link: https://lore.kernel.org/r/20191211155742.3213-1-tiwai@suse.de Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- sound/core/pcm_native.c | 4 ++++ 1 file changed, 4 insertions(+)
--- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -459,6 +459,10 @@ static int snd_pcm_hw_params(struct snd_ while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) runtime->boundary *= 2;
+ /* clear the buffer for avoiding possible kernel info leaks */ + if (runtime->dma_area) + memset(runtime->dma_area, 0, runtime->dma_bytes); + snd_pcm_timer_resolution_change(substream); snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai tiwai@suse.de
commit cb04fc3b6b076f67d228a0b7d096c69ad486c09c upstream.
Introduce a timeout to dspio_clear_response_queue() so that it won't be caught in an endless loop even if the hardware doesn't respond properly.
Fixes: a73d511c4867 ("ALSA: hda/ca0132: Add unsol handler for DSP and jack detection") Link: https://lore.kernel.org/r/20191213085111.22855-3-tiwai@suse.de Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Ben Hutchings ben@decadent.org.uk --- sound/pci/hda/patch_ca0132.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
--- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -1271,13 +1271,14 @@ struct scp_msg {
static void dspio_clear_response_queue(struct hda_codec *codec) { + unsigned long timeout = jiffies + msecs_to_jiffies(1000); unsigned int dummy = 0; - int status = -1; + int status;
/* clear all from the response queue */ do { status = dspio_read(codec, &dummy); - } while (status == 0); + } while (status == 0 && time_before(jiffies, timeout)); }
static int dspio_get_response_data(struct hda_codec *codec)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang shengjiu.wang@nxp.com
commit 556672d75ff486e0b6786056da624131679e0576 upstream.
According to user manual, it is required that FLL_LAMBDA > 0 in all cases (Integer and Franctional modes).
Fixes: 9a76f1ff6e29 ("ASoC: Add initial WM8962 CODEC driver") Signed-off-by: Shengjiu Wang shengjiu.wang@nxp.com Acked-by: Charles Keepax ckeepax@opensource.cirrus.com Link: https://lore.kernel.org/r/1576065442-19763-1-git-send-email-shengjiu.wang@nx... Signed-off-by: Mark Brown broonie@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- sound/soc/codecs/wm8962.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2795,7 +2795,7 @@ static int fll_factors(struct _fll_div *
if (target % Fref == 0) { fll_div->theta = 0; - fll_div->lambda = 0; + fll_div->lambda = 1; } else { gcd_fll = gcd(target, fratio * Fref);
@@ -2865,7 +2865,7 @@ static int wm8962_set_fll(struct snd_soc return -EINVAL; }
- if (fll_div.theta || fll_div.lambda) + if (fll_div.theta) fll1 |= WM8962_FLL_FRAC;
/* Stop the FLL while we reconfigure */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Sudip Mukherjee sudipm.mukherjee@gmail.com
commit fb2b90014d782d80d7ebf663e50f96d8c507a73c upstream.
There seems to be a race condition in tty drivers and I could see on many boot cycles a NULL pointer dereference as tty_init_dev() tries to do 'tty->port->itty = tty' even though tty->port is NULL. 'tty->port' will be set by the driver and if the driver has not yet done it before we open the tty device we can get to this situation. By adding some extra debug prints, I noticed that:
6.650130: uart_add_one_port 6.663849: register_console 6.664846: tty_open 6.674391: tty_init_dev 6.675456: tty_port_link_device
uart_add_one_port() registers the console, as soon as it registers, the userspace tries to use it and that leads to tty_open() but uart_add_one_port() has not yet done tty_port_link_device() and so tty->port is not yet configured when control reaches tty_init_dev().
Further look into the code and tty_port_link_device() is done by uart_add_one_port(). After registering the console uart_add_one_port() will call tty_port_register_device_attr_serdev() and tty_port_link_device() is called from this.
Call add tty_port_link_device() before uart_configure_port() is done and add a check in tty_port_link_device() so that it only links the port if it has not been done yet.
Suggested-by: Jiri Slaby jslaby@suse.com Signed-off-by: Sudip Mukherjee sudipm.mukherjee@gmail.com Link: https://lore.kernel.org/r/20191212131602.29504-1-sudipm.mukherjee@gmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/tty/serial/serial_core.c | 1 + drivers/tty/tty_port.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-)
--- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2639,6 +2639,7 @@ int uart_add_one_port(struct uart_driver lockdep_set_class(&uport->lock, &port_lock_key); }
+ tty_port_link_device(port, drv->tty_driver, uport->line); uart_configure_port(drv, state, uport);
/* --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -49,7 +49,8 @@ void tty_port_link_device(struct tty_por { if (WARN_ON(index >= driver->num)) return; - driver->ports[index] = port; + if (!driver->ports[index]) + driver->ports[index] = port; } EXPORT_SYMBOL_GPL(tty_port_link_device);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Erkka Talvitie erkka.talvitie@vincit.fi
commit 64cc3f12d1c7dd054a215bc1ff9cc2abcfe35832 upstream.
When disconnecting a USB hub that has some child device(s) connected to it (such as a USB mouse), then the stack tries to clear halt and reset device(s) which are _already_ physically disconnected.
The issue has been reproduced with:
CPU: IMX6D5EYM10AD or MCIMX6D5EYM10AE. SW: U-Boot 2019.07 and kernel 4.19.40.
CPU: HP Proliant Microserver Gen8. SW: Linux version 4.2.3-300.fc23.x86_64
In this situation there will be error bit for MMF active yet the CERR equals EHCI_TUNE_CERR + halt. Existing implementation interprets this as a stall [1] (chapter 8.4.5).
The possible conditions when the MMF will be active + halt can be found from [2] (Table 4-13).
Fix for the issue is to check whether MMF is active and PID Code is IN before checking for the stall. If these conditions are true then it is not a stall.
What happens after the fix is that when disconnecting a hub with attached device(s) the situation is not interpret as a stall.
[1] [https://www.usb.org/document-library/usb-20-specification, usb_20.pdf] [2] [https://www.intel.com/content/dam/www/public/us/en/documents/ technical-specifications/ehci-specification-for-usb.pdf]
Signed-off-by: Erkka Talvitie erkka.talvitie@vincit.fi Reviewed-by: Alan Stern stern@rowland.harvard.edu Link: https://lore.kernel.org/r/ef70941d5f349767f19c0ed26b0dd9eed8ad81bb.157605052... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/host/ehci-q.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
--- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -40,6 +40,10 @@
/*-------------------------------------------------------------------------*/
+/* PID Codes that are used here, from EHCI specification, Table 3-16. */ +#define PID_CODE_IN 1 +#define PID_CODE_SETUP 2 + /* fill a qtd, returning how much of the buffer we were able to queue up */
static int @@ -199,7 +203,7 @@ static int qtd_copy_status ( int status = -EINPROGRESS;
/* count IN/OUT bytes, not SETUP (even short packets) */ - if (likely (QTD_PID (token) != 2)) + if (likely(QTD_PID(token) != PID_CODE_SETUP)) urb->actual_length += length - QTD_LENGTH (token);
/* don't modify error codes */ @@ -215,6 +219,13 @@ static int qtd_copy_status ( if (token & QTD_STS_BABBLE) { /* FIXME "must" disable babbling device's port too */ status = -EOVERFLOW; + /* + * When MMF is active and PID Code is IN, queue is halted. + * EHCI Specification, Table 4-13. + */ + } else if ((token & QTD_STS_MMF) && + (QTD_PID(token) == PID_CODE_IN)) { + status = -EPROTO; /* CERR nonzero + halt --> stall */ } else if (QTD_CERR(token)) { status = -EPIPE;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Suwan Kim suwan.kim027@gmail.com
commit aabb5b833872524eaf28f52187e5987984982264 upstream.
If a transaction error happens in vhci_recv_ret_submit(), event handler closes connection and changes port status to kick hub_event. Then hub tries to flush the endpoint URBs, but that causes infinite loop between usb_hub_flush_endpoint() and vhci_urb_dequeue() because "vhci_priv" in vhci_urb_dequeue() was already released by vhci_recv_ret_submit() before a transmission error occurred. Thus, vhci_urb_dequeue() terminates early and usb_hub_flush_endpoint() continuously calls vhci_urb_dequeue().
The root cause of this issue is that vhci_recv_ret_submit() terminates early without giving back URB when transaction error occurs in vhci_recv_ret_submit(). That causes the error URB to still be linked at endpoint list without “vhci_priv".
So, in the case of transaction error in vhci_recv_ret_submit(), unlink URB from the endpoint, insert proper error code in urb->status and give back URB.
Reported-by: Marek Marczykowski-Górecki marmarek@invisiblethingslab.com Tested-by: Marek Marczykowski-Górecki marmarek@invisiblethingslab.com Signed-off-by: Suwan Kim suwan.kim027@gmail.com Acked-by: Shuah Khan skhan@linuxfoundation.org Link: https://lore.kernel.org/r/20191213023055.19933-3-suwan.kim027@gmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: adjust filename] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/staging/usbip/vhci_rx.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
--- a/drivers/staging/usbip/vhci_rx.c +++ b/drivers/staging/usbip/vhci_rx.c @@ -88,16 +88,21 @@ static void vhci_recv_ret_submit(struct usbip_pack_pdu(pdu, urb, USBIP_RET_SUBMIT, 0);
/* recv transfer buffer */ - if (usbip_recv_xbuff(ud, urb) < 0) - return; + if (usbip_recv_xbuff(ud, urb) < 0) { + urb->status = -EPROTO; + goto error; + }
/* recv iso_packet_descriptor */ - if (usbip_recv_iso(ud, urb) < 0) - return; + if (usbip_recv_iso(ud, urb) < 0) { + urb->status = -EPROTO; + goto error; + }
/* restore the padding in iso packets */ usbip_pad_iso(ud, urb);
+error: if (usbip_dbg_flag_vhci_rx) usbip_dump_urb(urb);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jim Mattson jmattson@google.com
commit 396d2e878f92ec108e4293f1c77ea3bc90b414ff upstream.
The host reports support for the synthetic feature X86_FEATURE_SSBD when any of the three following hardware features are set: CPUID.(EAX=7,ECX=0):EDX.SSBD[bit 31] CPUID.80000008H:EBX.AMD_SSBD[bit 24] CPUID.80000008H:EBX.VIRT_SSBD[bit 25]
Either of the first two hardware features implies the existence of the IA32_SPEC_CTRL MSR, but CPUID.80000008H:EBX.VIRT_SSBD[bit 25] does not. Therefore, CPUID.(EAX=7,ECX=0):EDX.SSBD[bit 31] should only be set in the guest if CPUID.(EAX=7,ECX=0):EDX.SSBD[bit 31] or CPUID.80000008H:EBX.AMD_SSBD[bit 24] is set on the host.
Fixes: 0c54914d0c52a ("KVM: x86: use Intel speculation bugs and features as derived in generic x86 code") Signed-off-by: Jim Mattson jmattson@google.com Reviewed-by: Jacob Xu jacobhxu@google.com Reviewed-by: Peter Shier pshier@google.com Cc: Paolo Bonzini pbonzini@redhat.com Reported-by: Eric Biggers ebiggers@kernel.org Signed-off-by: Paolo Bonzini pbonzini@redhat.com [bwh: Backported to 3.16: adjust indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- arch/x86/kvm/cpuid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
--- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -400,7 +400,8 @@ static inline int __do_cpuid_ent(struct entry->edx |= F(SPEC_CTRL); if (boot_cpu_has(X86_FEATURE_STIBP)) entry->edx |= F(INTEL_STIBP); - if (boot_cpu_has(X86_FEATURE_SSBD)) + if (boot_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) || + boot_cpu_has(X86_FEATURE_AMD_SSBD)) entry->edx |= F(SPEC_CTRL_SSBD); /* * We emulate ARCH_CAPABILITIES in software even
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jose Abreu Jose.Abreu@synopsys.com
commit 8605131747e7e1fd8f6c9f97a00287aae2b2c640 upstream.
The 16KB RX Buffer must also be 16 byte aligned. Fix it.
Fixes: 7ac6653a085b ("stmmac: Move the STMicroelectronics driver") Signed-off-by: Jose Abreu Jose.Abreu@synopsys.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/ethernet/stmicro/stmmac/common.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
--- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -270,9 +270,8 @@ struct dma_features { unsigned int enh_desc; };
-/* GMAC TX FIFO is 8K, Rx FIFO is 16K */ -#define BUF_SIZE_16KiB 16384 -/* RX Buffer size must be < 8191 and multiple of 4/8/16 bytes */ +/* RX Buffer size must be multiple of 4/8/16 bytes */ +#define BUF_SIZE_16KiB 16368 #define BUF_SIZE_8KiB 8188 #define BUF_SIZE_4KiB 4096 #define BUF_SIZE_2KiB 2048
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jose Abreu Jose.Abreu@synopsys.com
commit b2f3a481c4cd62f78391b836b64c0a6e72b503d2 upstream.
XGMAC supports maximum MTU that can go to 16KB. Lets add this check in the calculation of RX buffer size.
Fixes: 7ac6653a085b ("stmmac: Move the STMicroelectronics driver") Signed-off-by: Jose Abreu Jose.Abreu@synopsys.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -904,7 +904,9 @@ static int stmmac_set_bfsize(int mtu, in { int ret = bufsize;
- if (mtu >= BUF_SIZE_4KiB) + if (mtu >= BUF_SIZE_8KiB) + ret = BUF_SIZE_16KiB; + else if (mtu >= BUF_SIZE_4KiB) ret = BUF_SIZE_8KiB; else if (mtu >= BUF_SIZE_2KiB) ret = BUF_SIZE_4KiB;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal fw@strlen.de
commit fc6a5d0601c5ac1d02f283a46f60b87b2033e5ca upstream.
All of these conditions are not fatal and should have been WARN_ONs from the get-go.
Convert them to WARN_ONs and bail out.
Signed-off-by: Florian Westphal fw@strlen.de Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/bridge/netfilter/ebtables.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-)
--- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1603,7 +1603,8 @@ static int compat_match_to_user(struct e int off = ebt_compat_match_offset(match, m->match_size); compat_uint_t msize = m->match_size - off;
- BUG_ON(off >= m->match_size); + if (WARN_ON(off >= m->match_size)) + return -EINVAL;
if (copy_to_user(cm->u.name, match->name, strlen(match->name) + 1) || put_user(msize, &cm->match_size)) @@ -1630,7 +1631,8 @@ static int compat_target_to_user(struct int off = xt_compat_target_offset(target); compat_uint_t tsize = t->target_size - off;
- BUG_ON(off >= t->target_size); + if (WARN_ON(off >= t->target_size)) + return -EINVAL;
if (copy_to_user(cm->u.name, target->name, strlen(target->name) + 1) || put_user(tsize, &cm->match_size)) @@ -1858,7 +1860,8 @@ static int ebt_buf_add(struct ebt_entrie if (state->buf_kern_start == NULL) goto count_only;
- BUG_ON(state->buf_kern_offset + sz > state->buf_kern_len); + if (WARN_ON(state->buf_kern_offset + sz > state->buf_kern_len)) + return -EINVAL;
memcpy(state->buf_kern_start + state->buf_kern_offset, data, sz);
@@ -1871,7 +1874,8 @@ static int ebt_buf_add_pad(struct ebt_en { char *b = state->buf_kern_start;
- BUG_ON(b && state->buf_kern_offset > state->buf_kern_len); + if (WARN_ON(b && state->buf_kern_offset > state->buf_kern_len)) + return -EINVAL;
if (b != NULL && sz > 0) memset(b + state->buf_kern_offset, 0, sz); @@ -1949,8 +1953,10 @@ static int compat_mtw_from_user(struct c pad = XT_ALIGN(size_kern) - size_kern;
if (pad > 0 && dst) { - BUG_ON(state->buf_kern_len <= pad); - BUG_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad); + if (WARN_ON(state->buf_kern_len <= pad)) + return -EINVAL; + if (WARN_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad)) + return -EINVAL; memset(dst + size_kern, 0, pad); } return off + match_size; @@ -2001,7 +2007,8 @@ static int ebt_size_mwt(struct compat_eb if (ret < 0) return ret;
- BUG_ON(ret < match32->match_size); + if (WARN_ON(ret < match32->match_size)) + return -EINVAL; growth += ret - match32->match_size; growth += ebt_compat_entry_padsize();
@@ -2116,7 +2123,8 @@ static int size_entry_mwt(struct ebt_ent
startoff = state->buf_user_offset - startoff;
- BUG_ON(*total < startoff); + if (WARN_ON(*total < startoff)) + return -EINVAL; *total -= startoff; return 0; } @@ -2246,7 +2254,8 @@ static int compat_do_replace(struct net state.buf_kern_len = size64;
ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state); - BUG_ON(ret < 0); /* parses same data again */ + if (WARN_ON(ret < 0)) + goto out_unlock;
vfree(entries_tmp); tmp.entries_size = size64;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal fw@strlen.de
commit e608f631f0ba5f1fc5ee2e260a3a35d13107cbfe upstream.
syzbot reported following splat:
BUG: KASAN: vmalloc-out-of-bounds in size_entry_mwt net/bridge/netfilter/ebtables.c:2063 [inline] BUG: KASAN: vmalloc-out-of-bounds in compat_copy_entries+0x128b/0x1380 net/bridge/netfilter/ebtables.c:2155 Read of size 4 at addr ffffc900004461f4 by task syz-executor267/7937
CPU: 1 PID: 7937 Comm: syz-executor267 Not tainted 5.5.0-rc1-syzkaller #0 size_entry_mwt net/bridge/netfilter/ebtables.c:2063 [inline] compat_copy_entries+0x128b/0x1380 net/bridge/netfilter/ebtables.c:2155 compat_do_replace+0x344/0x720 net/bridge/netfilter/ebtables.c:2249 compat_do_ebt_set_ctl+0x22f/0x27e net/bridge/netfilter/ebtables.c:2333 [..]
Because padding isn't considered during computation of ->buf_user_offset, "total" is decremented by fewer bytes than it should.
Therefore, the first part of
if (*total < sizeof(*entry) || entry->next_offset < sizeof(*entry))
will pass, -- it should not have. This causes oob access: entry->next_offset is past the vmalloced size.
Reject padding and check that computed user offset (sum of ebt_entry structure plus all individual matches/watchers/targets) is same value that userspace gave us as the offset of the next entry.
Reported-by: syzbot+f68108fed972453a0ad4@syzkaller.appspotmail.com Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support") Signed-off-by: Florian Westphal fw@strlen.de Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/bridge/netfilter/ebtables.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-)
--- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1855,7 +1855,7 @@ static int ebt_buf_count(struct ebt_entr }
static int ebt_buf_add(struct ebt_entries_buf_state *state, - void *data, unsigned int sz) + const void *data, unsigned int sz) { if (state->buf_kern_start == NULL) goto count_only; @@ -1889,7 +1889,7 @@ enum compat_mwt { EBT_COMPAT_TARGET, };
-static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, +static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, enum compat_mwt compat_mwt, struct ebt_entries_buf_state *state, const unsigned char *base) @@ -1966,22 +1966,23 @@ static int compat_mtw_from_user(struct c * return size of all matches, watchers or target, including necessary * alignment and padding. */ -static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, +static int ebt_size_mwt(const struct compat_ebt_entry_mwt *match32, unsigned int size_left, enum compat_mwt type, struct ebt_entries_buf_state *state, const void *base) { + const char *buf = (const char *)match32; int growth = 0; - char *buf;
if (size_left == 0) return 0;
- buf = (char *) match32; - - while (size_left >= sizeof(*match32)) { + do { struct ebt_entry_match *match_kern; int ret;
+ if (size_left < sizeof(*match32)) + return -EINVAL; + match_kern = (struct ebt_entry_match *) state->buf_kern_start; if (match_kern) { char *tmp; @@ -2018,22 +2019,18 @@ static int ebt_size_mwt(struct compat_eb if (match_kern) match_kern->match_size = ret;
- /* rule should have no remaining data after target */ - if (type == EBT_COMPAT_TARGET && size_left) - return -EINVAL; - match32 = (struct compat_ebt_entry_mwt *) buf; - } + } while (size_left);
return growth; }
/* called for all ebt_entry structures. */ -static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, +static int size_entry_mwt(const struct ebt_entry *entry, const unsigned char *base, unsigned int *total, struct ebt_entries_buf_state *state) { - unsigned int i, j, startoff, new_offset = 0; + unsigned int i, j, startoff, next_expected_off, new_offset = 0; /* stores match/watchers/targets & offset of next struct ebt_entry: */ unsigned int offsets[4]; unsigned int *offsets_update = NULL; @@ -2121,11 +2118,13 @@ static int size_entry_mwt(struct ebt_ent return ret; }
- startoff = state->buf_user_offset - startoff; + next_expected_off = state->buf_user_offset - startoff; + if (next_expected_off != entry->next_offset) + return -EINVAL;
- if (WARN_ON(*total < startoff)) + if (*total < entry->next_offset) return -EINVAL; - *total -= startoff; + *total -= entry->next_offset; return 0; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Hans de Goede hdegoede@redhat.com
commit 133b2acee3871ae6bf123b8fe34be14464aa3d2c upstream.
At least on the HP Envy x360 15-cp0xxx model the WMI interface for HPWMI_FEATURE2_QUERY requires an outsize of at least 128 bytes, otherwise it fails with an error code 5 (HPWMI_RET_INVALID_PARAMETERS):
Dec 06 00:59:38 kernel: hp_wmi: query 0xd returned error 0x5
We do not care about the contents of the buffer, we just want to know if the HPWMI_FEATURE2_QUERY command is supported.
This commits bumps the buffer size, fixing the error.
Fixes: 8a1513b4932 ("hp-wmi: limit hotkey enable") BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1520703 Signed-off-by: Hans de Goede hdegoede@redhat.com Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/platform/x86/hp-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -309,7 +309,7 @@ static int __init hp_wmi_bios_2008_later
static int __init hp_wmi_bios_2009_later(void) { - int state = 0; + u8 state[128]; int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, 0, &state, sizeof(state), sizeof(state)); if (!ret)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Russell King rmk+kernel@armlinux.org.uk
commit d2ed49cf6c13e379c5819aa5ac20e1f9674ebc89 upstream.
When a PHY is probed, if the top bit is set, we end up requesting a module with the string "mdio:-10101110000000100101000101010001" - the top bit is printed to a signed -1 value. This leads to the module not being loaded.
Fix the module format string and the macro generating the values for it to ensure that we only print unsigned types and the top bit is always 0/1. We correctly end up with "mdio:10101110000000100101000101010001".
Fixes: 8626d3b43280 ("phylib: Support phy module autoloading") Reviewed-by: Andrew Lunn andrew@lunn.ch Signed-off-by: Russell King rmk+kernel@armlinux.org.uk Reviewed-by: Florian Fainelli f.fainelli@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- include/linux/mod_devicetable.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -497,9 +497,9 @@ struct platform_device_id {
#define MDIO_MODULE_PREFIX "mdio:"
-#define MDIO_ID_FMT "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d" +#define MDIO_ID_FMT "%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u" #define MDIO_ID_ARGS(_id) \ - (_id)>>31, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1, \ + ((_id)>>31) & 1, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1, \ ((_id)>>27) & 1, ((_id)>>26) & 1, ((_id)>>25) & 1, ((_id)>>24) & 1, \ ((_id)>>23) & 1, ((_id)>>22) & 1, ((_id)>>21) & 1, ((_id)>>20) & 1, \ ((_id)>>19) & 1, ((_id)>>18) & 1, ((_id)>>17) & 1, ((_id)>>16) & 1, \
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Ard Biesheuvel ardb@kernel.org
commit 4911ee401b7ceff8f38e0ac597cbf503d71e690c upstream.
The EFI mixed mode entry code goes through the ordinary startup_32() routine before jumping into the kernel's EFI boot code in 64-bit mode. The 32-bit startup code must be entered with paging disabled, but this is not documented as a requirement for the EFI handover protocol, and so we should disable paging explicitly when entering the kernel from 32-bit EFI firmware.
Signed-off-by: Ard Biesheuvel ardb@kernel.org Cc: Arvind Sankar nivedita@alum.mit.edu Cc: Hans de Goede hdegoede@redhat.com Cc: Linus Torvalds torvalds@linux-foundation.org Cc: Peter Zijlstra peterz@infradead.org Cc: Thomas Gleixner tglx@linutronix.de Cc: linux-efi@vger.kernel.org Link: https://lkml.kernel.org/r/20191224132909.102540-4-ardb@kernel.org Signed-off-by: Ingo Molnar mingo@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- arch/x86/boot/compressed/head_64.S | 5 +++++ 1 file changed, 5 insertions(+)
--- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -216,6 +216,11 @@ ENTRY(efi32_stub_entry) leal efi32_config(%ebp), %eax movl %eax, efi_config(%ebp)
+ /* Disable paging */ + movl %cr0, %eax + btrl $X86_CR0_PG_BIT, %eax + movl %eax, %cr0 + jmp startup_32 ENDPROC(efi32_stub_entry) #endif
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai tiwai@suse.de
commit 0aec96f5897ac16ad9945f531b4bef9a2edd2ebd upstream.
Jia-Ju Bai reported a possible sleep-in-atomic scenario in the ice1724 driver with Infrasonic Quartet support code: namely, ice->set_rate callback gets called inside ice->reg_lock spinlock, while the callback in quartet.c holds ice->gpio_mutex.
This patch fixes the invalid call: it simply moves the calls of ice->set_rate and ice->set_mclk callbacks outside the spinlock.
Reported-by: Jia-Ju Bai baijiaju1990@gmail.com Link: https://lore.kernel.org/r/5d43135e-73b9-a46a-2155-9e91d0dcdf83@gmail.com Link: https://lore.kernel.org/r/20191218192606.12866-1-tiwai@suse.de Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Ben Hutchings ben@decadent.org.uk --- sound/pci/ice1712/ice1724.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
--- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -663,6 +663,7 @@ static int snd_vt1724_set_pro_rate(struc unsigned long flags; unsigned char mclk_change; unsigned int i, old_rate; + bool call_set_rate = false;
if (rate > ice->hw_rates->list[ice->hw_rates->count - 1]) return -EINVAL; @@ -686,7 +687,7 @@ static int snd_vt1724_set_pro_rate(struc * setting clock rate for internal clock mode */ old_rate = ice->get_rate(ice); if (force || (old_rate != rate)) - ice->set_rate(ice, rate); + call_set_rate = true; else if (rate == ice->cur_rate) { spin_unlock_irqrestore(&ice->reg_lock, flags); return 0; @@ -694,12 +695,14 @@ static int snd_vt1724_set_pro_rate(struc }
ice->cur_rate = rate; + spin_unlock_irqrestore(&ice->reg_lock, flags); + + if (call_set_rate) + ice->set_rate(ice, rate);
/* setting master clock */ mclk_change = ice->set_mclk(ice, rate);
- spin_unlock_irqrestore(&ice->reg_lock, flags); - if (mclk_change && ice->gpio.i2s_mclk_changed) ice->gpio.i2s_mclk_changed(ice); if (ice->gpio.set_pro_rate)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein amir73il@gmail.com
commit 98ca480a8f22fdbd768e3dad07024c8d4856576c upstream.
An ino is unsigned, so display it as such in /proc/locks.
Signed-off-by: Amir Goldstein amir73il@gmail.com Signed-off-by: Jeff Layton jlayton@kernel.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/locks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/fs/locks.c +++ b/fs/locks.c @@ -2488,7 +2488,7 @@ static void lock_get_status(struct seq_f inode->i_sb->s_id, inode->i_ino); #else /* userspace relies on this representation of dev_t ;-( */ - seq_printf(f, "%d %02x:%02x:%ld ", fl_pid, + seq_printf(f, "%d %02x:%02x:%lu ", fl_pid, MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev), inode->i_ino); #endif
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal fw@strlen.de
commit 1b789577f655060d98d20ed0c6f9fbd469d6ba63 upstream.
We get crash when the targets checkentry function tries to make use of the network namespace pointer for arptables.
When the net pointer got added back in 2010, only ip/ip6/ebtables were changed to initialize it, so arptables has this set to NULL.
This isn't a problem for normal arptables because no existing arptables target has a checkentry function that makes use of par->net.
However, direct users of the setsockopt interface can provide any target they want as long as its registered for ARP or UNPSEC protocols.
syzkaller managed to send a semi-valid arptables rule for RATEEST target which is enough to trigger NULL deref:
kasan: GPF could be caused by NULL-ptr deref or user memory access general protection fault: 0000 [#1] PREEMPT SMP KASAN RIP: xt_rateest_tg_checkentry+0x11d/0xb40 net/netfilter/xt_RATEEST.c:109 [..] xt_check_target+0x283/0x690 net/netfilter/x_tables.c:1019 check_target net/ipv4/netfilter/arp_tables.c:399 [inline] find_check_entry net/ipv4/netfilter/arp_tables.c:422 [inline] translate_table+0x1005/0x1d70 net/ipv4/netfilter/arp_tables.c:572 do_replace net/ipv4/netfilter/arp_tables.c:977 [inline] do_arpt_set_ctl+0x310/0x640 net/ipv4/netfilter/arp_tables.c:1456
Fixes: add67461240c1d ("netfilter: add struct net * to target parameters") Reported-by: syzbot+d7358a458d8a81aee898@syzkaller.appspotmail.com Signed-off-by: Florian Westphal fw@strlen.de Acked-by: Cong Wang xiyou.wangcong@gmail.com Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/ipv4/netfilter/arp_tables.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-)
--- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -480,11 +480,12 @@ static int mark_source_chains(const stru return 1; }
-static inline int check_target(struct arpt_entry *e, const char *name) +static int check_target(struct arpt_entry *e, struct net *net, const char *name) { struct xt_entry_target *t = arpt_get_target(e); int ret; struct xt_tgchk_param par = { + .net = net, .table = name, .entryinfo = e, .target = t->u.kernel.target, @@ -502,8 +503,9 @@ static inline int check_target(struct ar return 0; }
-static inline int -find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) +static int +find_check_entry(struct arpt_entry *e, struct net *net, const char *name, + unsigned int size) { struct xt_entry_target *t; struct xt_target *target; @@ -519,7 +521,7 @@ find_check_entry(struct arpt_entry *e, c } t->u.kernel.target = target;
- ret = check_target(e, name); + ret = check_target(e, net, name); if (ret) goto err; return 0; @@ -617,7 +619,9 @@ static inline void cleanup_entry(struct /* Checks and translates the user-supplied table segment (held in * newinfo). */ -static int translate_table(struct xt_table_info *newinfo, void *entry0, +static int translate_table(struct net *net, + struct xt_table_info *newinfo, + void *entry0, const struct arpt_replace *repl) { struct arpt_entry *iter; @@ -692,7 +696,7 @@ static int translate_table(struct xt_tab /* Finally, each sanity check must pass */ i = 0; xt_entry_foreach(iter, entry0, newinfo->size) { - ret = find_check_entry(iter, repl->name, repl->size); + ret = find_check_entry(iter, net, repl->name, repl->size); if (ret != 0) break; ++i; @@ -1100,7 +1104,7 @@ static int do_replace(struct net *net, c goto free_newinfo; }
- ret = translate_table(newinfo, loc_cpu_entry, &tmp); + ret = translate_table(net, newinfo, loc_cpu_entry, &tmp); if (ret != 0) goto free_newinfo;
@@ -1287,7 +1291,8 @@ compat_copy_entry_from_user(struct compa } }
-static int translate_compat_table(struct xt_table_info **pinfo, +static int translate_compat_table(struct net *net, + struct xt_table_info **pinfo, void **pentry0, const struct compat_arpt_replace *compatr) { @@ -1356,7 +1361,7 @@ static int translate_compat_table(struct repl.num_counters = 0; repl.counters = NULL; repl.size = newinfo->size; - ret = translate_table(newinfo, entry1, &repl); + ret = translate_table(net, newinfo, entry1, &repl); if (ret) goto free_newinfo;
@@ -1412,7 +1417,7 @@ static int compat_do_replace(struct net goto free_newinfo; }
- ret = translate_compat_table(&newinfo, &loc_cpu_entry, &tmp); + ret = translate_compat_table(net, &newinfo, &loc_cpu_entry, &tmp); if (ret != 0) goto free_newinfo;
@@ -1685,7 +1690,7 @@ struct xt_table *arpt_register_table(str loc_cpu_entry = newinfo->entries[raw_smp_processor_id()]; memcpy(loc_cpu_entry, repl->entries, repl->size);
- ret = translate_table(newinfo, loc_cpu_entry, repl); + ret = translate_table(net, newinfo, loc_cpu_entry, repl); duprintf("arpt_register_table: translate table gives %d\n", ret); if (ret != 0) goto out_free;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Sudip Mukherjee sudipm.mukherjee@gmail.com
commit 273f632912f1b24b642ba5b7eb5022e43a72f3b5 upstream.
If the serial device is disconnected and reconnected, it re-enumerates properly but does not link it. fwiw, linking means just saving the port index, so allow it always as there is no harm in saving the same value again even if it tries to relink with the same port.
Fixes: fb2b90014d78 ("tty: link tty and port before configuring it as console") Reported-by: Kenneth R. Crudup kenny@panix.com Signed-off-by: Sudip Mukherjee sudipm.mukherjee@gmail.com Link: https://lore.kernel.org/r/20191227174434.12057-1-sudipm.mukherjee@gmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/tty/tty_port.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
--- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -49,8 +49,7 @@ void tty_port_link_device(struct tty_por { if (WARN_ON(index >= driver->num)) return; - if (!driver->ports[index]) - driver->ports[index] = port; + driver->ports[index] = port; } EXPORT_SYMBOL_GPL(tty_port_link_device);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 3e4f8e21c4f27bcf30a48486b9dcc269512b79ff upstream.
Amend the endpoint-descriptor sanity checks to detect all duplicate endpoint addresses in a configuration.
Commit 0a8fd1346254 ("USB: fix problems with duplicate endpoint addresses") added a check for duplicate endpoint addresses within a single alternate setting, but did not look for duplicate addresses in other interfaces.
The current check would also not detect all duplicate addresses when one endpoint is as a (bi-directional) control endpoint.
This specifically avoids overwriting the endpoint entries in struct usb_device when enabling a duplicate endpoint, something which could potentially lead to crashes or leaks, for example, when endpoints are later disabled.
Signed-off-by: Johan Hovold johan@kernel.org Acked-by: Alan Stern stern@rowland.harvard.edu Link: https://lore.kernel.org/r/20191219161016.6695-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/core/config.c | 70 ++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 12 deletions(-)
--- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -169,9 +169,58 @@ static const unsigned short super_speed_ [USB_ENDPOINT_XFER_INT] = 1024, };
-static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, - int asnum, struct usb_host_interface *ifp, int num_ep, - unsigned char *buffer, int size) +static bool endpoint_is_duplicate(struct usb_endpoint_descriptor *e1, + struct usb_endpoint_descriptor *e2) +{ + if (e1->bEndpointAddress == e2->bEndpointAddress) + return true; + + if (usb_endpoint_xfer_control(e1) || usb_endpoint_xfer_control(e2)) { + if (usb_endpoint_num(e1) == usb_endpoint_num(e2)) + return true; + } + + return false; +} + +/* + * Check for duplicate endpoint addresses in other interfaces and in the + * altsetting currently being parsed. + */ +static bool config_endpoint_is_duplicate(struct usb_host_config *config, + int inum, int asnum, struct usb_endpoint_descriptor *d) +{ + struct usb_endpoint_descriptor *epd; + struct usb_interface_cache *intfc; + struct usb_host_interface *alt; + int i, j, k; + + for (i = 0; i < config->desc.bNumInterfaces; ++i) { + intfc = config->intf_cache[i]; + + for (j = 0; j < intfc->num_altsetting; ++j) { + alt = &intfc->altsetting[j]; + + if (alt->desc.bInterfaceNumber == inum && + alt->desc.bAlternateSetting != asnum) + continue; + + for (k = 0; k < alt->desc.bNumEndpoints; ++k) { + epd = &alt->endpoint[k].desc; + + if (endpoint_is_duplicate(epd, d)) + return true; + } + } + } + + return false; +} + +static int usb_parse_endpoint(struct device *ddev, int cfgno, + struct usb_host_config *config, int inum, int asnum, + struct usb_host_interface *ifp, int num_ep, + unsigned char *buffer, int size) { unsigned char *buffer0 = buffer; struct usb_endpoint_descriptor *d; @@ -208,13 +257,10 @@ static int usb_parse_endpoint(struct dev goto skip_to_next_endpoint_or_interface_descriptor;
/* Check for duplicate endpoint addresses */ - for (i = 0; i < ifp->desc.bNumEndpoints; ++i) { - if (ifp->endpoint[i].desc.bEndpointAddress == - d->bEndpointAddress) { - dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", - cfgno, inum, asnum, d->bEndpointAddress); - goto skip_to_next_endpoint_or_interface_descriptor; - } + if (config_endpoint_is_duplicate(config, inum, asnum, d)) { + dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", + cfgno, inum, asnum, d->bEndpointAddress); + goto skip_to_next_endpoint_or_interface_descriptor; }
endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; @@ -481,8 +527,8 @@ static int usb_parse_interface(struct de if (((struct usb_descriptor_header *) buffer)->bDescriptorType == USB_DT_INTERFACE) break; - retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt, - num_ep, buffer, size); + retval = usb_parse_endpoint(ddev, cfgno, config, inum, asnum, + alt, num_ep, buffer, size); if (retval < 0) return retval; ++n;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 73f8bda9b5dc1c69df2bc55c0cbb24461a6391a9 upstream.
Add a new device quirk that can be used to blacklist endpoints.
Since commit 3e4f8e21c4f2 ("USB: core: fix check for duplicate endpoints") USB core ignores any duplicate endpoints found during descriptor parsing.
In order to handle devices where the first interfaces with duplicate endpoints are the ones that should have their endpoints ignored, we need to add a blacklist.
Tested-by: edes edes@gmx.net Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20200203153830.26394-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/core/config.c | 11 +++++++++++ drivers/usb/core/quirks.c | 32 ++++++++++++++++++++++++++++++++ drivers/usb/core/usb.h | 3 +++ include/linux/usb/quirks.h | 3 +++ 4 files changed, 49 insertions(+)
--- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -222,6 +222,7 @@ static int usb_parse_endpoint(struct dev struct usb_host_interface *ifp, int num_ep, unsigned char *buffer, int size) { + struct usb_device *udev = to_usb_device(ddev); unsigned char *buffer0 = buffer; struct usb_endpoint_descriptor *d; struct usb_host_endpoint *endpoint; @@ -263,6 +264,16 @@ static int usb_parse_endpoint(struct dev goto skip_to_next_endpoint_or_interface_descriptor; }
+ /* Ignore blacklisted endpoints */ + if (udev->quirks & USB_QUIRK_ENDPOINT_BLACKLIST) { + if (usb_endpoint_is_blacklisted(udev, ifp, d)) { + dev_warn(ddev, "config %d interface %d altsetting %d has a blacklisted endpoint with address 0x%X, skipping\n", + cfgno, inum, asnum, + d->bEndpointAddress); + goto skip_to_next_endpoint_or_interface_descriptor; + } + } + endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; ++ifp->desc.bNumEndpoints;
--- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -318,6 +318,38 @@ static const struct usb_device_id usb_am { } /* terminating entry must be last */ };
+/* + * Entries for blacklisted endpoints that should be ignored when parsing + * configuration descriptors. + * + * Matched for devices with USB_QUIRK_ENDPOINT_BLACKLIST. + */ +static const struct usb_device_id usb_endpoint_blacklist[] = { + { } +}; + +bool usb_endpoint_is_blacklisted(struct usb_device *udev, + struct usb_host_interface *intf, + struct usb_endpoint_descriptor *epd) +{ + const struct usb_device_id *id; + unsigned int address; + + for (id = usb_endpoint_blacklist; id->match_flags; ++id) { + if (!usb_match_device(udev, id)) + continue; + + if (!usb_match_one_id_intf(udev, intf, id)) + continue; + + address = id->driver_info; + if (address == epd->bEndpointAddress) + return true; + } + + return false; +} + static bool usb_match_any_interface(struct usb_device *udev, const struct usb_device_id *id) { --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -29,6 +29,9 @@ extern int usb_deauthorize_device(struct extern int usb_authorize_device(struct usb_device *); extern void usb_detect_quirks(struct usb_device *udev); extern void usb_detect_interface_quirks(struct usb_device *udev); +extern bool usb_endpoint_is_blacklisted(struct usb_device *udev, + struct usb_host_interface *intf, + struct usb_endpoint_descriptor *epd); extern int usb_remove_device(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev, --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -62,4 +62,7 @@ /* Hub needs extra delay after resetting its port. */ #define USB_QUIRK_HUB_SLOW_RESET BIT(14)
+/* device has blacklisted endpoints */ +#define USB_QUIRK_ENDPOINT_BLACKLIST BIT(15) + #endif /* __LINUX_USB_QUIRKS_H */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit bdd1b147b8026df0e4260b387026b251d888ed01 upstream.
This device has a broken vendor-specific altsetting for interface 1, where endpoint 0x85 is declared as an isochronous endpoint despite being used by interface 2 for audio capture.
Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 239 Miscellaneous Device bDeviceSubClass 2 bDeviceProtocol 1 Interface Association bMaxPacketSize0 64 idVendor 0x0926 idProduct 0x0202 bcdDevice 1.00 iManufacturer 1 Sound Devices iProduct 2 USBPre2 iSerial 3 [...] bNumConfigurations 1
[...]
Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 3 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 5 Transfer Type Isochronous Synch Type Asynchronous Usage Type Data wMaxPacketSize 0x0126 1x 294 bytes bInterval 1
[...]
Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 2 bAlternateSetting 1 bNumEndpoints 1 bInterfaceClass 1 Audio bInterfaceSubClass 2 Streaming bInterfaceProtocol 0 iInterface 0 AudioStreaming Interface Descriptor: bLength 7 bDescriptorType 36 bDescriptorSubtype 1 (AS_GENERAL) bTerminalLink 4 bDelay 1 frames wFormatTag 0x0001 PCM AudioStreaming Interface Descriptor: bLength 26 bDescriptorType 36 bDescriptorSubtype 2 (FORMAT_TYPE) bFormatType 1 (FORMAT_TYPE_I) bNrChannels 2 bSubframeSize 2 bBitResolution 16 bSamFreqType 6 Discrete tSamFreq[ 0] 8000 tSamFreq[ 1] 16000 tSamFreq[ 2] 24000 tSamFreq[ 3] 32000 tSamFreq[ 4] 44100 tSamFreq[ 5] 48000 Endpoint Descriptor: bLength 9 bDescriptorType 5 bEndpointAddress 0x85 EP 5 IN bmAttributes 5 Transfer Type Isochronous Synch Type Asynchronous Usage Type Data wMaxPacketSize 0x0126 1x 294 bytes bInterval 4 bRefresh 0 bSynchAddress 0 AudioStreaming Endpoint Descriptor: bLength 7 bDescriptorType 37 bDescriptorSubtype 1 (EP_GENERAL) bmAttributes 0x01 Sampling Frequency bLockDelayUnits 2 Decoded PCM samples wLockDelay 0x0000
Since commit 3e4f8e21c4f2 ("USB: core: fix check for duplicate endpoints") USB core ignores any duplicate endpoints found during descriptor parsing, but in this case we need to ignore the first instance in order to avoid breaking the audio capture interface.
Fixes: 3e4f8e21c4f2 ("USB: core: fix check for duplicate endpoints") Reported-by: edes edes@gmx.net Tested-by: edes edes@gmx.net Link: https://lore.kernel.org/r/20200201105829.5682c887@acme7.acmenet Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20200203153830.26394-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/core/quirks.c | 5 +++++ 1 file changed, 5 insertions(+)
--- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -206,6 +206,10 @@ static const struct usb_device_id usb_qu { USB_DEVICE(0x0904, 0x6103), .driver_info = USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
+ /* Sound Devices USBPre2 */ + { USB_DEVICE(0x0926, 0x0202), .driver_info = + USB_QUIRK_ENDPOINT_BLACKLIST }, + /* Keytouch QWERTY Panel keyboard */ { USB_DEVICE(0x0926, 0x3333), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, @@ -325,6 +329,7 @@ static const struct usb_device_id usb_am * Matched for devices with USB_QUIRK_ENDPOINT_BLACKLIST. */ static const struct usb_device_id usb_endpoint_blacklist[] = { + { USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0202, 1), .driver_info = 0x85 }, { } };
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Paul Cercueil paul@crapouillou.net
commit c80d0f4426c7fdc7efd6ae8d8b021dcfc89b4254 upstream.
The IRQ handler was passed a pointer to a struct dma_controller, but the argument was then casted to a pointer to a struct musb_dma_controller.
Fixes: 427c4f333474 ("usb: struct device - replace bus_id with dev_name(), dev_set_name()") Signed-off-by: Paul Cercueil paul@crapouillou.net Tested-by: Artur Rojek contact@artur-rojek.eu Signed-off-by: Bin Liu b-liu@ti.com Link: https://lore.kernel.org/r/20191216161844.772-2-b-liu@ti.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/musb/musbhsdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -396,7 +396,7 @@ struct dma_controller *dma_controller_cr controller->controller.channel_abort = dma_channel_abort;
if (request_irq(irq, dma_controller_irq, 0, - dev_name(musb->controller), &controller->controller)) { + dev_name(musb->controller), controller)) { dev_err(dev, "request_irq %d failed!\n", irq); dma_controller_destroy(&controller->controller);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 2f361cd9474ab2c4ab9ac8db20faf81e66c6279b upstream.
Make sure to always use the descriptors of the current alternate setting to avoid future issues when accessing fields that may differ between settings.
Signed-off-by: Johan Hovold johan@kernel.org Fixes: d08e973a77d1 ("can: gs_usb: Added support for the GS_USB CAN devices") Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/can/usb/gs_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -846,7 +846,7 @@ static int gs_usb_probe(struct usb_inter GS_USB_BREQ_HOST_FORMAT, USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, 1, - intf->altsetting[0].desc.bInterfaceNumber, + intf->cur_altsetting->desc.bInterfaceNumber, hconf, sizeof(*hconf), 1000); @@ -869,7 +869,7 @@ static int gs_usb_probe(struct usb_inter GS_USB_BREQ_DEVICE_CONFIG, USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, 1, - intf->altsetting[0].desc.bInterfaceNumber, + intf->cur_altsetting->desc.bInterfaceNumber, dconf, sizeof(*dconf), 1000);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Florian Faber faber@faberman.de
commit 2d77bd61a2927be8f4e00d9478fe6996c47e8d45 upstream.
Under load, the RX side of the mscan driver can get stuck while TX still works. Restarting the interface locks up the system. This behaviour could be reproduced reliably on a MPC5121e based system.
The patch fixes the return value of the NAPI polling function (should be the number of processed packets, not constant 1) and the condition under which IRQs are enabled again after polling is finished.
With this patch, no more lockups were observed over a test period of ten days.
Fixes: afa17a500a36 ("net/can: add driver for mscan family & mpc52xx_mscan") Signed-off-by: Florian Faber faber@faberman.de Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/can/mscan/mscan.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-)
--- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -412,13 +412,12 @@ static int mscan_rx_poll(struct napi_str struct net_device *dev = napi->dev; struct mscan_regs __iomem *regs = priv->reg_base; struct net_device_stats *stats = &dev->stats; - int npackets = 0; - int ret = 1; + int work_done = 0; struct sk_buff *skb; struct can_frame *frame; u8 canrflg;
- while (npackets < quota) { + while (work_done < quota) { canrflg = in_8(®s->canrflg); if (!(canrflg & (MSCAN_RXF | MSCAN_ERR_IF))) break; @@ -439,18 +438,18 @@ static int mscan_rx_poll(struct napi_str
stats->rx_packets++; stats->rx_bytes += frame->can_dlc; - npackets++; + work_done++; netif_receive_skb(skb); }
- if (!(in_8(®s->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) { - napi_complete(&priv->napi); - clear_bit(F_RX_PROGRESS, &priv->flags); - if (priv->can.state < CAN_STATE_BUS_OFF) - out_8(®s->canrier, priv->shadow_canrier); - ret = 0; + if (work_done < quota) { + if (likely(napi_complete_done(&priv->napi, work_done))) { + clear_bit(F_RX_PROGRESS, &priv->flags); + if (priv->can.state < CAN_STATE_BUS_OFF) + out_8(®s->canrier, priv->shadow_canrier); + } } - return ret; + return work_done; }
static irqreturn_t mscan_isr(int irq, void *dev_id)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Pengcheng Yang yangpc@wangsu.com
commit c9655008e7845bcfdaac10a1ed8554ec167aea88 upstream.
When we receive a D-SACK, where the sequence number satisfies: undo_marker <= start_seq < end_seq <= prior_snd_una we consider this is a valid D-SACK and tcp_is_sackblock_valid() returns true, then this D-SACK is discarded as "old stuff", but the variable first_sack_index is not marked as negative in tcp_sacktag_write_queue().
If this D-SACK also carries a SACK that needs to be processed (for example, the previous SACK segment was lost), this SACK will be treated as a D-SACK in the following processing of tcp_sacktag_write_queue(), which will eventually lead to incorrect updates of undo_retrans and reordering.
Fixes: fd6dad616d4f ("[TCP]: Earlier SACK block verification & simplify access to them") Signed-off-by: Pengcheng Yang yangpc@wangsu.com Signed-off-by: Eric Dumazet edumazet@google.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/ipv4/tcp_input.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
--- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1713,8 +1713,11 @@ tcp_sacktag_write_queue(struct sock *sk, }
/* Ignore very old stuff early */ - if (!after(sp[used_sacks].end_seq, prior_snd_una)) + if (!after(sp[used_sacks].end_seq, prior_snd_una)) { + if (i == 0) + first_sack_index = -1; continue; + }
used_sacks++; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Hangbin Liu liuhangbin@gmail.com
commit 71130f29979c7c7956b040673e6b9d5643003176 upstream.
Before ip_tunnel_ecn_encap() and udp_tunnel_xmit_skb() we should filter tos value by RT_TOS() instead of using config tos directly.
vxlan_get_route() would filter the tos to fl4.flowi4_tos but we didn't return it back, as geneve_get_v4_rt() did. So we have to use RT_TOS() directly in function ip_tunnel_ecn_encap().
Fixes: 206aaafcd279 ("VXLAN: Use IP Tunnels tunnel ENC encap API") Fixes: 1400615d64cf ("vxlan: allow setting ipv6 traffic class") Signed-off-by: Hangbin Liu liuhangbin@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/vxlan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1904,7 +1904,7 @@ static void vxlan_xmit_one(struct sk_buf return; }
- tos = ip_tunnel_ecn_encap(tos, old_iph, skb); + tos = ip_tunnel_ecn_encap(RT_TOS(tos), old_iph, skb); ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
err = vxlan_xmit_skb(vxlan->vn_sock, rt, skb,
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: "Steven Rostedt (VMware)" rostedt@goodmis.org
commit b8299d362d0837ae39e87e9019ebe6b736e0f035 upstream.
On some archs with some configurations, MCOUNT_INSN_SIZE is not defined, and this makes the stack tracer fail to compile. Just define it to zero in this case.
Link: https://lore.kernel.org/r/202001020219.zvE3vsty%lkp@intel.com
Fixes: 4df297129f622 ("tracing: Remove most or all of stack tracer stack size from stack_max_size") Reported-by: kbuild test robot lkp@intel.com Signed-off-by: Steven Rostedt (VMware) rostedt@goodmis.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- kernel/trace/trace_stack.c | 5 +++++ 1 file changed, 5 insertions(+)
--- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -182,6 +182,11 @@ check_stack(unsigned long ip, unsigned l local_irq_restore(flags); }
+/* Some archs may not define MCOUNT_INSN_SIZE */ +#ifndef MCOUNT_INSN_SIZE +# define MCOUNT_INSN_SIZE 0 +#endif + static void stack_trace_call(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *op, struct pt_regs *pt_regs)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Wen Yang wenyang@linux.alibaba.com
commit e31f7939c1c27faa5d0e3f14519eaf7c89e8a69d upstream.
The ftrace_profile->counter is unsigned long and do_div truncates it to 32 bits, which means it can test non-zero and be truncated to zero for division. Fix this issue by using div64_ul() instead.
Link: http://lkml.kernel.org/r/20200103030248.14516-1-wenyang@linux.alibaba.com
Fixes: e330b3bcd8319 ("tracing: Show sample std dev in function profiling") Fixes: 34886c8bc590f ("tracing: add average time in function to function profiler") Signed-off-by: Wen Yang wenyang@linux.alibaba.com Signed-off-by: Steven Rostedt (VMware) rostedt@goodmis.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- kernel/trace/ftrace.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
--- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -595,8 +595,7 @@ static int function_stat_show(struct seq
#ifdef CONFIG_FUNCTION_GRAPH_TRACER seq_printf(m, " "); - avg = rec->time; - do_div(avg, rec->counter); + avg = div64_ul(rec->time, rec->counter);
/* Sample standard deviation (s^2) */ if (rec->counter <= 1) @@ -613,7 +612,8 @@ static int function_stat_show(struct seq * Divide only 1000 for ns^2 -> us^2 conversion. * trace_print_graph_duration will divide 1000 again. */ - do_div(stddev, rec->counter * (rec->counter - 1) * 1000); + stddev = div64_ul(stddev, + rec->counter * (rec->counter - 1) * 1000); }
trace_seq_init(&s);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Michael Straube straube.linux@gmail.com
commit 58dcc5bf4030cab548d5c98cd4cd3632a5444d5a upstream.
This device was added to the stand-alone driver on github. Add it to the staging driver as well.
Link: https://github.com/lwfinger/rtl8188eu/commit/b9b537aa25a8 Signed-off-by: Michael Straube straube.linux@gmail.com Link: https://lore.kernel.org/r/20191228143725.24455-1-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/staging/rtl8188eu/os_dep/usb_intf.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -61,6 +61,7 @@ static struct usb_device_id rtw_usb_id_t {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */ {USB_DEVICE(0x2001, 0x331B)}, /* D-Link DWA-121 rev B1 */ {USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */ + {USB_DEVICE(0x2357, 0x0111)}, /* TP-Link TL-WN727N v5.21 */ {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */ {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill RNX-N150NUB */ {} /* Terminating entry */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Kaitao Cheng pilgrimtao@gmail.com
commit 50f9ad607ea891a9308e67b81f774c71736d1098 upstream.
In the function, if register_trace_sched_migrate_task() returns error, sched_switch/sched_wakeup_new/sched_wakeup won't unregister. That is why fail_deprobe_sched_switch was added.
Link: http://lkml.kernel.org/r/20191231133530.2794-1-pilgrimtao@gmail.com
Fixes: 478142c39c8c2 ("tracing: do not grab lock in wakeup latency function tracing") Signed-off-by: Kaitao Cheng pilgrimtao@gmail.com Signed-off-by: Steven Rostedt (VMware) rostedt@goodmis.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- kernel/trace/trace_sched_wakeup.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
--- a/kernel/trace/trace_sched_wakeup.c +++ b/kernel/trace/trace_sched_wakeup.c @@ -567,7 +567,7 @@ static void start_wakeup_tracer(struct t if (ret) { pr_info("wakeup trace: Couldn't activate tracepoint" " probe to kernel_sched_migrate_task\n"); - return; + goto fail_deprobe_sched_switch; }
wakeup_reset(tr); @@ -585,6 +585,8 @@ static void start_wakeup_tracer(struct t printk(KERN_ERR "failed to start wakeup tracer\n");
return; +fail_deprobe_sched_switch: + unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL); fail_deprobe_wake_new: unregister_trace_sched_wakeup_new(probe_wakeup, NULL); fail_deprobe:
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara jack@suse.cz
commit c70c176ff8c3ff0ac6ef9a831cd591ea9a66bd1a upstream.
Make the function available for outside use and fortify it against NULL kobject.
CC: Greg Kroah-Hartman gregkh@linuxfoundation.org Reviewed-by: Bart Van Assche bart.vanassche@sandisk.com Acked-by: Tejun Heo tj@kernel.org Signed-off-by: Jan Kara jack@suse.cz Signed-off-by: Jens Axboe axboe@fb.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- include/linux/kobject.h | 2 ++ lib/kobject.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-)
--- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -107,6 +107,8 @@ extern int __must_check kobject_rename(s extern int __must_check kobject_move(struct kobject *, struct kobject *);
extern struct kobject *kobject_get(struct kobject *kobj); +extern struct kobject * __must_check kobject_get_unless_zero( + struct kobject *kobj); extern void kobject_put(struct kobject *kobj);
extern const void *kobject_namespace(struct kobject *kobj); --- a/lib/kobject.c +++ b/lib/kobject.c @@ -581,12 +581,15 @@ struct kobject *kobject_get(struct kobje return kobj; }
-static struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj) +struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj) { + if (!kobj) + return NULL; if (!kref_get_unless_zero(&kobj->kref)) kobj = NULL; return kobj; } +EXPORT_SYMBOL(kobject_get_unless_zero);
/* * kobject_cleanup - free kobject resources.
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Will Deacon will@kernel.org
commit 68faa679b8be1a74e6663c21c3a9d25d32f1c079 upstream.
'chrdev_open()' calls 'cdev_get()' to obtain a reference to the 'struct cdev *' stashed in the 'i_cdev' field of the target inode structure. If the pointer is NULL, then it is initialised lazily by looking up the kobject in the 'cdev_map' and so the whole procedure is protected by the 'cdev_lock' spinlock to serialise initialisation of the shared pointer.
Unfortunately, it is possible for the initialising thread to fail *after* installing the new pointer, for example if the subsequent '->open()' call on the file fails. In this case, 'cdev_put()' is called, the reference count on the kobject is dropped and, if nobody else has taken a reference, the release function is called which finally clears 'inode->i_cdev' from 'cdev_purge()' before potentially freeing the object. The problem here is that a racing thread can happily take the 'cdev_lock' and see the non-NULL pointer in the inode, which can result in a refcount increment from zero and a warning:
| ------------[ cut here ]------------ | refcount_t: addition on 0; use-after-free. | WARNING: CPU: 2 PID: 6385 at lib/refcount.c:25 refcount_warn_saturate+0x6d/0xf0 | Modules linked in: | CPU: 2 PID: 6385 Comm: repro Not tainted 5.5.0-rc2+ #22 | Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 | RIP: 0010:refcount_warn_saturate+0x6d/0xf0 | Code: 05 55 9a 15 01 01 e8 9d aa c8 ff 0f 0b c3 80 3d 45 9a 15 01 00 75 ce 48 c7 c7 00 9c 62 b3 c6 08 | RSP: 0018:ffffb524c1b9bc70 EFLAGS: 00010282 | RAX: 0000000000000000 RBX: ffff9e9da1f71390 RCX: 0000000000000000 | RDX: ffff9e9dbbd27618 RSI: ffff9e9dbbd18798 RDI: ffff9e9dbbd18798 | RBP: 0000000000000000 R08: 000000000000095f R09: 0000000000000039 | R10: 0000000000000000 R11: ffffb524c1b9bb20 R12: ffff9e9da1e8c700 | R13: ffffffffb25ee8b0 R14: 0000000000000000 R15: ffff9e9da1e8c700 | FS: 00007f3b87d26700(0000) GS:ffff9e9dbbd00000(0000) knlGS:0000000000000000 | CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 | CR2: 00007fc16909c000 CR3: 000000012df9c000 CR4: 00000000000006e0 | DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 | DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 | Call Trace: | kobject_get+0x5c/0x60 | cdev_get+0x2b/0x60 | chrdev_open+0x55/0x220 | ? cdev_put.part.3+0x20/0x20 | do_dentry_open+0x13a/0x390 | path_openat+0x2c8/0x1470 | do_filp_open+0x93/0x100 | ? selinux_file_ioctl+0x17f/0x220 | do_sys_open+0x186/0x220 | do_syscall_64+0x48/0x150 | entry_SYSCALL_64_after_hwframe+0x44/0xa9 | RIP: 0033:0x7f3b87efcd0e | Code: 89 54 24 08 e8 a3 f4 ff ff 8b 74 24 0c 48 8b 3c 24 41 89 c0 44 8b 54 24 08 b8 01 01 00 00 89 f4 | RSP: 002b:00007f3b87d259f0 EFLAGS: 00000293 ORIG_RAX: 0000000000000101 | RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f3b87efcd0e | RDX: 0000000000000000 RSI: 00007f3b87d25a80 RDI: 00000000ffffff9c | RBP: 00007f3b87d25e90 R08: 0000000000000000 R09: 0000000000000000 | R10: 0000000000000000 R11: 0000000000000293 R12: 00007ffe188f504e | R13: 00007ffe188f504f R14: 00007f3b87d26700 R15: 0000000000000000 | ---[ end trace 24f53ca58db8180a ]---
Since 'cdev_get()' can already fail to obtain a reference, simply move it over to use 'kobject_get_unless_zero()' instead of 'kobject_get()', which will cause the racing thread to return -ENXIO if the initialising thread fails unexpectedly.
Cc: Hillf Danton hdanton@sina.com Cc: Andrew Morton akpm@linux-foundation.org Cc: Al Viro viro@zeniv.linux.org.uk Reported-by: syzbot+82defefbbd8527e1c2cb@syzkaller.appspotmail.com Signed-off-by: Will Deacon will@kernel.org Link: https://lore.kernel.org/r/20191219120203.32691-1-will@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/char_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -348,7 +348,7 @@ static struct kobject *cdev_get(struct c
if (owner && !try_module_get(owner)) return NULL; - kobj = kobject_get(&p->kobj); + kobj = kobject_get_unless_zero(&p->kobj); if (!kobj) module_put(owner); return kobj;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long lucien.xin@gmail.com
commit be7a7729207797476b6666f046d765bdf9630407 upstream.
This patch is to fix a memleak caused by no place to free cmd->obj.chunk for the unprocessed SCTP_CMD_REPLY. This issue occurs when failing to process a cmd while there're still SCTP_CMD_REPLY cmds on the cmd seq with an allocated chunk in cmd->obj.chunk.
So fix it by freeing cmd->obj.chunk for each SCTP_CMD_REPLY cmd left on the cmd seq when any cmd returns error. While at it, also remove 'nomem' label.
Reported-by: syzbot+107c4aff5f392bf1517f@syzkaller.appspotmail.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Xin Long lucien.xin@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/sctp/sm_sideeffect.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-)
--- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1327,8 +1327,10 @@ static int sctp_cmd_interpreter(sctp_eve /* Generate an INIT ACK chunk. */ new_obj = sctp_make_init_ack(asoc, chunk, GFP_ATOMIC, 0); - if (!new_obj) - goto nomem; + if (!new_obj) { + error = -ENOMEM; + break; + }
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); @@ -1350,7 +1352,8 @@ static int sctp_cmd_interpreter(sctp_eve if (!new_obj) { if (cmd->obj.chunk) sctp_chunk_free(cmd->obj.chunk); - goto nomem; + error = -ENOMEM; + break; } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); @@ -1397,8 +1400,10 @@ static int sctp_cmd_interpreter(sctp_eve
/* Generate a SHUTDOWN chunk. */ new_obj = sctp_make_shutdown(asoc, chunk); - if (!new_obj) - goto nomem; + if (!new_obj) { + error = -ENOMEM; + break; + } sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(new_obj)); break; @@ -1727,11 +1732,17 @@ static int sctp_cmd_interpreter(sctp_eve break; }
- if (error) + if (error) { + cmd = sctp_next_cmd(commands); + while (cmd) { + if (cmd->verb == SCTP_CMD_REPLY) + sctp_chunk_free(cmd->obj.chunk); + cmd = sctp_next_cmd(commands); + } break; + } }
-out: /* If this is in response to a received chunk, wait until * we are done with the packet to open the queue so that we don't * send multiple packets in response to a single request. @@ -1742,8 +1753,5 @@ out: } else if (local_cork) error = sctp_outq_uncork(&asoc->outqueue); return error; -nomem: - error = -ENOMEM; - goto out; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet edumazet@google.com
commit eb8ef2a3c50092bb018077c047b8dba1ce0e78e3 upstream.
Both vlan_dev_change_flags() and vlan_dev_set_egress_priority() can return an error. vlan_changelink() should not ignore them.
Fixes: 07b5b17e157b ("[VLAN]: Use rtnl_link API") Signed-off-by: Eric Dumazet edumazet@google.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/8021q/vlan_netlink.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
--- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -92,11 +92,13 @@ static int vlan_changelink(struct net_de struct ifla_vlan_flags *flags; struct ifla_vlan_qos_mapping *m; struct nlattr *attr; - int rem; + int rem, err;
if (data[IFLA_VLAN_FLAGS]) { flags = nla_data(data[IFLA_VLAN_FLAGS]); - vlan_dev_change_flags(dev, flags->flags, flags->mask); + err = vlan_dev_change_flags(dev, flags->flags, flags->mask); + if (err) + return err; } if (data[IFLA_VLAN_INGRESS_QOS]) { nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) { @@ -107,7 +109,9 @@ static int vlan_changelink(struct net_de if (data[IFLA_VLAN_EGRESS_QOS]) { nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) { m = nla_data(attr); - vlan_dev_set_egress_priority(dev, m->from, m->to); + err = vlan_dev_set_egress_priority(dev, m->from, m->to); + if (err) + return err; } } return 0;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Chen-Yu Tsai wens@csie.org
commit 52cc73e5404c7ba0cbfc50cb4c265108c84b3d5a upstream.
Allow all the RGMII modes to be used. This would allow us to represent the hardware better in the device tree with RGMII_ID where in most cases the PHY's internal delay for both RX and TX are used.
Fixes: af0bd4e9ba80 ("net: stmmac: sunxi platform extensions for GMAC in Allwinner A20 SoC's") Signed-off-by: Chen-Yu Tsai wens@csie.org Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -78,7 +78,7 @@ static int sun7i_gmac_init(struct platfo * rate, which then uses the auto-reparenting feature of the * clock driver, and enabling/disabling the clock. */ - if (gmac->interface == PHY_INTERFACE_MODE_RGMII) { + if (phy_interface_mode_is_rgmii(gmac->interface)) { clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE); clk_prepare_enable(gmac->tx_clk); gmac->clk_enabled = 1;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Kenneth Klette Jonassen kennetkl@ifi.uio.no
commit 3725a269815ba6dbb415feddc47da5af7d1fac58 upstream.
Configuring fq with quantum 0 hangs the system, presumably because of a non-interruptible infinite loop. Either way quantum 0 does not make sense.
Reproduce with: sudo tc qdisc add dev lo root fq quantum 0 initial_quantum 0 ping 127.0.0.1
Signed-off-by: Kenneth Klette Jonassen kennetkl@ifi.uio.no Acked-by: Eric Dumazet edumazet@google.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/sched/sch_fq.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
--- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -687,8 +687,14 @@ static int fq_change(struct Qdisc *sch, if (tb[TCA_FQ_FLOW_PLIMIT]) q->flow_plimit = nla_get_u32(tb[TCA_FQ_FLOW_PLIMIT]);
- if (tb[TCA_FQ_QUANTUM]) - q->quantum = nla_get_u32(tb[TCA_FQ_QUANTUM]); + if (tb[TCA_FQ_QUANTUM]) { + u32 quantum = nla_get_u32(tb[TCA_FQ_QUANTUM]); + + if (quantum > 0) + q->quantum = quantum; + else + err = -EINVAL; + }
if (tb[TCA_FQ_INITIAL_QUANTUM]) q->initial_quantum = nla_get_u32(tb[TCA_FQ_INITIAL_QUANTUM]);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet edumazet@google.com
commit d9e15a2733067c9328fb56d98fe8e574fa19ec31 upstream.
As diagnosed by Florian :
If TCA_FQ_QUANTUM is set to 0x80000000, fq_deueue() can loop forever in :
if (f->credit <= 0) { f->credit += q->quantum; goto begin; }
... because f->credit is either 0 or -2147483648.
Let's limit TCA_FQ_QUANTUM to no more than 1 << 20 : This max value should limit risks of breaking user setups while fixing this bug.
Fixes: afe4fd062416 ("pkt_sched: fq: Fair Queue packet scheduler") Signed-off-by: Eric Dumazet edumazet@google.com Diagnosed-by: Florian Westphal fw@strlen.de Reported-by: syzbot+dc9071cc5a85950bdfce@syzkaller.appspotmail.com Signed-off-by: David S. Miller davem@davemloft.net [bwh: Backported to 3.16: Drop call to NL_SET_ERR_MSG_MOD() as extack is not supported.] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -690,7 +690,7 @@ static int fq_change(struct Qdisc *sch, if (tb[TCA_FQ_QUANTUM]) { u32 quantum = nla_get_u32(tb[TCA_FQ_QUANTUM]);
- if (quantum > 0) + if (quantum > 0 && quantum <= (1 << 20)) q->quantum = quantum; else err = -EINVAL;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet edumazet@google.com
commit 96cc4b69581db68efc9749ef32e9cf8e0160c509 upstream.
Use of eth_hdr() in tx path is error prone.
Many drivers call skb_reset_mac_header() before using it, but others do not.
Commit 6d1ccff62780 ("net: reset mac header in dev_start_xmit()") attempted to fix this generically, but commit d346a3fae3ff ("packet: introduce PACKET_QDISC_BYPASS socket option") brought back the macvlan bug.
Lets add a new helper, so that tx paths no longer have to call skb_reset_mac_header() only to get a pointer to skb->data.
Hopefully we will be able to revert 6d1ccff62780 ("net: reset mac header in dev_start_xmit()") and save few cycles in transmit fast path.
BUG: KASAN: use-after-free in __get_unaligned_cpu32 include/linux/unaligned/packed_struct.h:19 [inline] BUG: KASAN: use-after-free in mc_hash drivers/net/macvlan.c:251 [inline] BUG: KASAN: use-after-free in macvlan_broadcast+0x547/0x620 drivers/net/macvlan.c:277 Read of size 4 at addr ffff8880a4932401 by task syz-executor947/9579
CPU: 0 PID: 9579 Comm: syz-executor947 Not tainted 5.5.0-rc4-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x197/0x210 lib/dump_stack.c:118 print_address_description.constprop.0.cold+0xd4/0x30b mm/kasan/report.c:374 __kasan_report.cold+0x1b/0x41 mm/kasan/report.c:506 kasan_report+0x12/0x20 mm/kasan/common.c:639 __asan_report_load_n_noabort+0xf/0x20 mm/kasan/generic_report.c:145 __get_unaligned_cpu32 include/linux/unaligned/packed_struct.h:19 [inline] mc_hash drivers/net/macvlan.c:251 [inline] macvlan_broadcast+0x547/0x620 drivers/net/macvlan.c:277 macvlan_queue_xmit drivers/net/macvlan.c:520 [inline] macvlan_start_xmit+0x402/0x77f drivers/net/macvlan.c:559 __netdev_start_xmit include/linux/netdevice.h:4447 [inline] netdev_start_xmit include/linux/netdevice.h:4461 [inline] dev_direct_xmit+0x419/0x630 net/core/dev.c:4079 packet_direct_xmit+0x1a9/0x250 net/packet/af_packet.c:240 packet_snd net/packet/af_packet.c:2966 [inline] packet_sendmsg+0x260d/0x6220 net/packet/af_packet.c:2991 sock_sendmsg_nosec net/socket.c:639 [inline] sock_sendmsg+0xd7/0x130 net/socket.c:659 __sys_sendto+0x262/0x380 net/socket.c:1985 __do_sys_sendto net/socket.c:1997 [inline] __se_sys_sendto net/socket.c:1993 [inline] __x64_sys_sendto+0xe1/0x1a0 net/socket.c:1993 do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x442639 Code: 18 89 d0 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 5b 10 fc ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007ffc13549e08 EFLAGS: 00000246 ORIG_RAX: 000000000000002c RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 0000000000442639 RDX: 000000000000000e RSI: 0000000020000080 RDI: 0000000000000003 RBP: 0000000000000004 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 0000000000403bb0 R14: 0000000000000000 R15: 0000000000000000
Allocated by task 9389: save_stack+0x23/0x90 mm/kasan/common.c:72 set_track mm/kasan/common.c:80 [inline] __kasan_kmalloc mm/kasan/common.c:513 [inline] __kasan_kmalloc.constprop.0+0xcf/0xe0 mm/kasan/common.c:486 kasan_kmalloc+0x9/0x10 mm/kasan/common.c:527 __do_kmalloc mm/slab.c:3656 [inline] __kmalloc+0x163/0x770 mm/slab.c:3665 kmalloc include/linux/slab.h:561 [inline] tomoyo_realpath_from_path+0xc5/0x660 security/tomoyo/realpath.c:252 tomoyo_get_realpath security/tomoyo/file.c:151 [inline] tomoyo_path_perm+0x230/0x430 security/tomoyo/file.c:822 tomoyo_inode_getattr+0x1d/0x30 security/tomoyo/tomoyo.c:129 security_inode_getattr+0xf2/0x150 security/security.c:1222 vfs_getattr+0x25/0x70 fs/stat.c:115 vfs_statx_fd+0x71/0xc0 fs/stat.c:145 vfs_fstat include/linux/fs.h:3265 [inline] __do_sys_newfstat+0x9b/0x120 fs/stat.c:378 __se_sys_newfstat fs/stat.c:375 [inline] __x64_sys_newfstat+0x54/0x80 fs/stat.c:375 do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 entry_SYSCALL_64_after_hwframe+0x49/0xbe
Freed by task 9389: save_stack+0x23/0x90 mm/kasan/common.c:72 set_track mm/kasan/common.c:80 [inline] kasan_set_free_info mm/kasan/common.c:335 [inline] __kasan_slab_free+0x102/0x150 mm/kasan/common.c:474 kasan_slab_free+0xe/0x10 mm/kasan/common.c:483 __cache_free mm/slab.c:3426 [inline] kfree+0x10a/0x2c0 mm/slab.c:3757 tomoyo_realpath_from_path+0x1a7/0x660 security/tomoyo/realpath.c:289 tomoyo_get_realpath security/tomoyo/file.c:151 [inline] tomoyo_path_perm+0x230/0x430 security/tomoyo/file.c:822 tomoyo_inode_getattr+0x1d/0x30 security/tomoyo/tomoyo.c:129 security_inode_getattr+0xf2/0x150 security/security.c:1222 vfs_getattr+0x25/0x70 fs/stat.c:115 vfs_statx_fd+0x71/0xc0 fs/stat.c:145 vfs_fstat include/linux/fs.h:3265 [inline] __do_sys_newfstat+0x9b/0x120 fs/stat.c:378 __se_sys_newfstat fs/stat.c:375 [inline] __x64_sys_newfstat+0x54/0x80 fs/stat.c:375 do_syscall_64+0xfa/0x790 arch/x86/entry/common.c:294 entry_SYSCALL_64_after_hwframe+0x49/0xbe
The buggy address belongs to the object at ffff8880a4932000 which belongs to the cache kmalloc-4k of size 4096 The buggy address is located 1025 bytes inside of 4096-byte region [ffff8880a4932000, ffff8880a4933000) The buggy address belongs to the page: page:ffffea0002924c80 refcount:1 mapcount:0 mapping:ffff8880aa402000 index:0x0 compound_mapcount: 0 raw: 00fffe0000010200 ffffea0002846208 ffffea00028f3888 ffff8880aa402000 raw: 0000000000000000 ffff8880a4932000 0000000100000001 0000000000000000 page dumped because: kasan: bad access detected
Memory state around the buggy address: ffff8880a4932300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff8880a4932380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8880a4932400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^ ffff8880a4932480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff8880a4932500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
Fixes: b863ceb7ddce ("[NET]: Add macvlan driver") Signed-off-by: Eric Dumazet edumazet@google.com Reported-by: syzbot syzkaller@googlegroups.com Signed-off-by: David S. Miller davem@davemloft.net [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/macvlan.c | 2 +- include/linux/if_ether.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-)
--- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -162,7 +162,7 @@ static void macvlan_broadcast(struct sk_ struct net_device *src, enum macvlan_mode mode) { - const struct ethhdr *eth = eth_hdr(skb); + const struct ethhdr *eth = skb_eth_hdr(skb); const struct macvlan_dev *vlan; struct sk_buff *nskb; unsigned int i; --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -28,6 +28,14 @@ static inline struct ethhdr *eth_hdr(con return (struct ethhdr *)skb_mac_header(skb); }
+/* Prefer this version in TX path, instead of + * skb_reset_mac_header() + eth_hdr() + */ +static inline struct ethhdr *skb_eth_hdr(const struct sk_buff *skb) +{ + return (struct ethhdr *)skb->data; +} + int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr);
extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal fw@strlen.de
commit 22dad713b8a5ff488e07b821195270672f486eb2 upstream.
The set uadt functions assume lineno is never NULL, but it is in case of ip_set_utest().
syzkaller managed to generate a netlink message that calls this with LINENO attr present:
general protection fault: 0000 [#1] PREEMPT SMP KASAN RIP: 0010:hash_mac4_uadt+0x1bc/0x470 net/netfilter/ipset/ip_set_hash_mac.c:104 Call Trace: ip_set_utest+0x55b/0x890 net/netfilter/ipset/ip_set_core.c:1867 nfnetlink_rcv_msg+0xcf2/0xfb0 net/netfilter/nfnetlink.c:229 netlink_rcv_skb+0x177/0x450 net/netlink/af_netlink.c:2477 nfnetlink_rcv+0x1ba/0x460 net/netfilter/nfnetlink.c:563
pass a dummy lineno storage, its easier than patching all set implementations.
This seems to be a day-0 bug.
Cc: Jozsef Kadlecsik kadlec@blackhole.kfki.hu Reported-by: syzbot+34bd2369d38707f3f4a7@syzkaller.appspotmail.com Fixes: a7b4f989a6294 ("netfilter: ipset: IP set core support") Signed-off-by: Florian Westphal fw@strlen.de Acked-by: Jozsef Kadlecsik kadlec@blackhole.kfki.hu Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/netfilter/ipset/ip_set_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
--- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1549,6 +1549,7 @@ ip_set_utest(struct sock *ctnl, struct s struct ip_set *set; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; int ret = 0; + u32 lineno;
if (unlikely(protocol_failed(attr) || attr[IPSET_ATTR_SETNAME] == NULL || @@ -1565,7 +1566,7 @@ ip_set_utest(struct sock *ctnl, struct s return -IPSET_ERR_PROTOCOL;
read_lock_bh(&set->lock); - ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0, 0); + ret = set->variant->uadt(set, tb, IPSET_TEST, &lineno, 0, 0); read_unlock_bh(&set->lock); /* Userspace can't trigger element to be re-added */ if (ret == -EAGAIN)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Radoslaw Tyl radoslawx.tyl@intel.com
commit aa604651d523b1493988d0bf6710339f3ee60272 upstream.
Currently, though the FDB entry is added to VF, it does not appear in RAR filters. VF driver only allows to add 10 entries. Attempting to add another causes an error. This patch removes limitation and allows use of all free RAR entries for the FDB if needed.
Fixes: 46ec20ff7d ("ixgbevf: Add macvlan support in the set rx mode op") Signed-off-by: Radoslaw Tyl radoslawx.tyl@intel.com Acked-by: Paul Menzel pmenzel@molgen.mpg.de Signed-off-by: Jeff Kirsher jeffrey.t.kirsher@intel.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 5 ----- 1 file changed, 5 deletions(-)
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -1465,11 +1465,6 @@ static int ixgbevf_write_uc_addr_list(st struct ixgbe_hw *hw = &adapter->hw; int count = 0;
- if ((netdev_uc_count(netdev)) > 10) { - pr_err("Too many unicast filters - No Space\n"); - return -ENOSPC; - } - if (!netdev_uc_empty(netdev)) { struct netdev_hw_addr *ha; netdev_for_each_uc_addr(ha, netdev) {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Chen chenxiang66@hisilicon.com
commit 465f4edaecc6c37f81349233e84d46246bcac11a upstream.
If an attached disk with protection information enabled is reformatted to Type 0 the revalidation code does not clear the original protection type and subsequent accesses will keep setting RDPROTECT/WRPROTECT.
Set the protection type to 0 if the disk reports PROT_EN=0 in READ CAPACITY(16).
[mkp: commit desc]
Fixes: fe542396da73 ("[SCSI] sd: Ensure we correctly disable devices with unknown protection type") Link: https://lore.kernel.org/r/1578532344-101668-1-git-send-email-chenxiang66@his... Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/scsi/sd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
--- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1910,8 +1910,10 @@ static int sd_read_protection_type(struc u8 type; int ret = 0;
- if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) + if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) { + sdkp->protection_type = 0; return ret; + }
type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: James Bottomley James.Bottomley@HansenPartnership.com
commit 529244bd1afc102ab164429d338d310d5d65e60d upstream.
Doing an add/remove/add on a SCSI device in an enclosure leads to an oops caused by poisoned values in the enclosure device list pointers. The reason is because we are keeping the enclosure device across the enclosed device add/remove/add but the current code is doing a device_add/device_del/device_add on it. This is the wrong thing to do in sysfs, so fix it by not doing a device_del on the enclosure device simply because of a hot remove of the drive in the slot.
[mkp: added missing email addresses]
Fixes: 43d8eb9cfd0a ("[SCSI] ses: add support for enclosure component hot removal") Link: https://lore.kernel.org/r/1578532892.3852.10.camel@HansenPartnership.com Signed-off-by: James Bottomley James.Bottomley@HansenPartnership.com Reported-by: Luo Jiaxing luojiaxing@huawei.com Tested-by: John Garry john.garry@huawei.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/misc/enclosure.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
--- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -364,10 +364,9 @@ int enclosure_remove_device(struct enclo cdev = &edev->component[i]; if (cdev->dev == dev) { enclosure_remove_links(cdev); - device_del(&cdev->cdev); put_device(dev); cdev->dev = NULL; - return device_add(&cdev->cdev); + return 0; } } return -ENODEV;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Fabian Henneke fabian.henneke@gmail.com
commit 378b80370aa1fe50f9c48a3ac8af3e416e73b89f upstream.
Always return EPOLLOUT from hidraw_poll when a device is connected. This is safe since writes are always possible (but will always block).
hidraw does not support non-blocking writes and instead always calls blocking backend functions on write requests. Hence, so far, a call to poll never returned EPOLLOUT, which confuses tools like socat.
Signed-off-by: Fabian Henneke fabian.henneke@gmail.com In-reply-to: CA+hv5qkyis03CgYTWeWX9cr0my-d2Oe+aZo+mjmWRXgjrGqyrw@mail.gmail.com Signed-off-by: Jiri Kosina jkosina@suse.cz [bwh: Backported to 3.16: s/EPOLL/POLL/] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/hid/hidraw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -265,7 +265,7 @@ static unsigned int hidraw_poll(struct f
poll_wait(file, &list->hidraw->wait, wait); if (list->head != list->tail) - return POLLIN | POLLRDNORM; + return POLLIN | POLLRDNORM | POLLOUT; if (!list->hidraw->exist) return POLLERR | POLLHUP; return 0;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Marcel Holtmann marcel@holtmann.org
commit 9f3b61dc1dd7b81e99e7ed23776bb64a35f39e1a upstream.
When polling a connected /dev/hidrawX device, it is useful to get the EPOLLOUT when writing is possible. Since writing is possible as soon as the device is connected, always return it.
Right now EPOLLOUT is only returned when there are also input reports are available. This works if devices start sending reports when connected, but some HID devices might need an output report first before sending any input reports. This change will allow using EPOLLOUT here as well.
Fixes: 378b80370aa1 ("hidraw: Return EPOLLOUT from hidraw_poll") Signed-off-by: Marcel Holtmann marcel@holtmann.org Signed-off-by: Jiri Kosina jkosina@suse.cz [bwh: Backported to 3.16: s/EPOLL/POLL/g] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/hid/hidraw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -265,10 +265,10 @@ static unsigned int hidraw_poll(struct f
poll_wait(file, &list->hidraw->wait, wait); if (list->head != list->tail) - return POLLIN | POLLRDNORM | POLLOUT; + return POLLIN | POLLRDNORM; if (!list->hidraw->exist) return POLLERR | POLLHUP; - return 0; + return POLLOUT | POLLWRNORM; }
static int hidraw_open(struct inode *inode, struct file *file)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Kosina jkosina@suse.cz
commit 9e635c2851df6caee651e589fbf937b637973c91 upstream.
hidraw and uhid device nodes are always available for writing so we should always report EPOLLOUT and EPOLLWRNORM bits, not only in the cases when there is nothing to read.
Reported-by: Linus Torvalds torvalds@linux-foundation.org Fixes: be54e7461ffdc ("HID: uhid: Fix returning EPOLLOUT from uhid_char_poll") Fixes: 9f3b61dc1dd7b ("HID: hidraw: Fix returning EPOLLOUT from hidraw_poll") Signed-off-by: Jiri Kosina jkosina@suse.cz [bwh: Backported to 3.16: - Use unsigned int type instead of __poll_t - s/EPOLL/POLL/g] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/hid/hidraw.c | 7 ++++--- drivers/hid/uhid.c | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-)
--- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -262,13 +262,14 @@ out: static unsigned int hidraw_poll(struct file *file, poll_table *wait) { struct hidraw_list *list = file->private_data; + unsigned int mask = POLLOUT | POLLWRNORM; /* hidraw is always writable */
poll_wait(file, &list->hidraw->wait, wait); if (list->head != list->tail) - return POLLIN | POLLRDNORM; + mask |= POLLIN | POLLRDNORM; if (!list->hidraw->exist) - return POLLERR | POLLHUP; - return POLLOUT | POLLWRNORM; + mask |= POLLERR | POLLHUP; + return mask; }
static int hidraw_open(struct inode *inode, struct file *file) --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -720,13 +720,14 @@ unlock: static unsigned int uhid_char_poll(struct file *file, poll_table *wait) { struct uhid_device *uhid = file->private_data; + unsigned int mask = POLLOUT | POLLWRNORM; /* uhid is always writable */
poll_wait(file, &uhid->waitq, wait);
if (uhid->head != uhid->tail) - return POLLIN | POLLRDNORM; + mask |= POLLIN | POLLRDNORM;
- return POLLOUT | POLLWRNORM; + return mask; }
static const struct file_operations uhid_fops = {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 3111491fca4f01764e0c158c5e0f7ced808eef51 upstream.
The driver was checking the number of endpoints of the first alternate setting instead of the current one, something which could lead to the driver binding to an invalid interface.
This in turn could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on.
Fixes: 8e20cf2bce12 ("Input: aiptek - fix crash on detecting device without endpoints") Signed-off-by: Johan Hovold johan@kernel.org Acked-by: Vladis Dronov vdronov@redhat.com Link: https://lore.kernel.org/r/20191210113737.4016-3-johan@kernel.org Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/input/tablet/aiptek.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
--- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -1820,14 +1820,14 @@ aiptek_probe(struct usb_interface *intf, input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);
/* Verify that a device really has an endpoint */ - if (intf->altsetting[0].desc.bNumEndpoints < 1) { + if (intf->cur_altsetting->desc.bNumEndpoints < 1) { dev_err(&intf->dev, "interface has %d endpoints, but must have minimum 1\n", - intf->altsetting[0].desc.bNumEndpoints); + intf->cur_altsetting->desc.bNumEndpoints); err = -EINVAL; goto fail3; } - endpoint = &intf->altsetting[0].endpoint[0].desc; + endpoint = &intf->cur_altsetting->endpoint[0].desc;
/* Go set up our URB, which is called when the tablet receives * input.
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit a8eeb74df5a6bdb214b2b581b14782c5f5a0cf83 upstream.
The driver was checking the number of endpoints of the first alternate setting instead of the current one, something which could lead to the driver binding to an invalid interface.
This in turn could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on.
Fixes: 162f98dea487 ("Input: gtco - fix crash on detecting device without endpoints") Signed-off-by: Johan Hovold johan@kernel.org Acked-by: Vladis Dronov vdronov@redhat.com Link: https://lore.kernel.org/r/20191210113737.4016-5-johan@kernel.org Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/input/tablet/gtco.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
--- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -886,18 +886,14 @@ static int gtco_probe(struct usb_interfa }
/* Sanity check that a device has an endpoint */ - if (usbinterface->altsetting[0].desc.bNumEndpoints < 1) { + if (usbinterface->cur_altsetting->desc.bNumEndpoints < 1) { dev_err(&usbinterface->dev, "Invalid number of endpoints\n"); error = -EINVAL; goto err_free_urb; }
- /* - * The endpoint is always altsetting 0, we know this since we know - * this device only has one interrupt endpoint - */ - endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + endpoint = &usbinterface->cur_altsetting->endpoint[0].desc;
/* Some debug */ dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting); @@ -984,7 +980,7 @@ static int gtco_probe(struct usb_interfa input_dev->dev.parent = &usbinterface->dev;
/* Setup the URB, it will be posted later on open of input device */ - endpoint = &usbinterface->altsetting[0].endpoint[0].desc; + endpoint = &usbinterface->cur_altsetting->endpoint[0].desc;
usb_fill_int_urb(gtco->urbinfo, gtco->usbdev,
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 6b32391ed675827f8425a414abbc6fbd54ea54fe upstream.
Make sure to use the current alternate setting when verifying the interface descriptors to avoid binding to an invalid interface.
This in turn could cause the driver to misbehave or trigger a WARN() in usb_submit_urb() that kernels with panic_on_warn set would choke on.
Fixes: bdb5c57f209c ("Input: add sur40 driver for Samsung SUR40 (aka MS Surface 2.0/Pixelsense)") Signed-off-by: Johan Hovold johan@kernel.org Acked-by: Vladis Dronov vdronov@redhat.com Link: https://lore.kernel.org/r/20191210113737.4016-8-johan@kernel.org Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/input/touchscreen/sur40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -357,7 +357,7 @@ static int sur40_probe(struct usb_interf int error;
/* Check if we really have the right interface. */ - iface_desc = &interface->altsetting[0]; + iface_desc = interface->cur_altsetting; if (iface_desc->desc.bInterfaceClass != 0xFF) return -ENODEV;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jian-Hong Pan jian-hong@endlessm.com
commit 176a7fca81c5090a7240664e3002c106d296bf31 upstream.
Some of ASUS laptops like UX431FL keyboard backlight cannot be set to brightness 0. According to ASUS' information, the brightness should be 0x80 ~ 0x83. This patch fixes it by following the logic.
Fixes: e9809c0b9670 ("asus-wmi: add keyboard backlight support") Signed-off-by: Jian-Hong Pan jian-hong@endlessm.com Reviewed-by: Daniel Drake drake@endlessm.com Signed-off-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/platform/x86/asus-wmi.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
--- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -386,13 +386,7 @@ static void kbd_led_update(struct work_s
asus = container_of(work, struct asus_wmi, kbd_led_work);
- /* - * bits 0-2: level - * bit 7: light on/off - */ - if (asus->kbd_led_wk > 0) - ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); - + ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL); }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Lars Möllendorf lars.moellendorf@plating.de
commit 883f616530692d81cb70f8a32d85c0d2afc05f69 upstream.
Previous versions of `iio_compute_scan_bytes` only aligned each element to its own length (i.e. its own natural alignment). Because multiple consecutive sets of scan elements are buffered this does not work in case the computed scan bytes do not align with the natural alignment of the first scan element in the set.
This commit fixes this by aligning the scan bytes to the natural alignment of the largest scan element in the set.
Fixes: 959d2952d124 ("staging:iio: make iio_sw_buffer_preenable much more general.") Signed-off-by: Lars Möllendorf lars.moellendorf@plating.de Reviewed-by: Lars-Peter Clausen lars@metafoo.de Signed-off-by: Jonathan Cameron Jonathan.Cameron@huawei.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/iio/industrialio-buffer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -478,7 +478,7 @@ static int iio_compute_scan_bytes(struct { const struct iio_chan_spec *ch; unsigned bytes = 0; - int length, i; + int length, i, largest = 0;
/* How much space will the demuxed element take? */ for_each_set_bit(i, mask, @@ -491,6 +491,7 @@ static int iio_compute_scan_bytes(struct length = ch->scan_type.storagebits / 8; bytes = ALIGN(bytes, length); bytes += length; + largest = max(largest, length); } if (timestamp) { ch = iio_find_channel_from_si(indio_dev, @@ -502,7 +503,10 @@ static int iio_compute_scan_bytes(struct length = ch->scan_type.storagebits / 8; bytes = ALIGN(bytes, length); bytes += length; + largest = max(largest, length); } + + bytes = ALIGN(bytes, largest); return bytes; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jerónimo Borque jeronimo@borque.com.ar
commit 260e41ac4dd3e5acb90be624c03ba7f019615b75 upstream.
Add device-ids for the Motorola Solutions TETRA radios MTP3xxx series and MTP85xx series
$ lsusb -vd 0cad:
Bus 001 Device 009: ID 0cad:9015 Motorola CGISS TETRA PEI interface Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0cad Motorola CGISS idProduct 0x9015 bcdDevice 24.16 iManufacturer 1 iProduct 2 iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0037 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 3 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0
Bus 001 Device 010: ID 0cad:9013 Motorola CGISS TETRA PEI interface Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0cad Motorola CGISS idProduct 0x9013 bcdDevice 24.16 iManufacturer 1 iProduct 2 iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x0037 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 3 bmAttributes 0x80 (Bus Powered) MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 255 Vendor Specific Class bInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x02 EP 2 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0200 1x 512 bytes bInterval 0
Signed-off-by: Jerónimo Borque jeronimo@borque.com.ar Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/serial/usb-serial-simple.c | 2 ++ 1 file changed, 2 insertions(+)
--- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -89,6 +89,8 @@ DEVICE(moto_modem, MOTO_IDS); #define MOTOROLA_TETRA_IDS() \ { USB_DEVICE(0x0cad, 0x9011) }, /* Motorola Solutions TETRA PEI */ \ { USB_DEVICE(0x0cad, 0x9012) }, /* MTP6550 */ \ + { USB_DEVICE(0x0cad, 0x9013) }, /* MTP3xxx */ \ + { USB_DEVICE(0x0cad, 0x9015) }, /* MTP85xx */ \ { USB_DEVICE(0x0cad, 0x9016) } /* TPG2200 */ DEVICE(motorola_tetra, MOTOROLA_TETRA_IDS);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Cong Wang xiyou.wangcong@gmail.com
commit c120959387efa51479056fd01dc90adfba7a590c upstream.
map->members is freed by ip_set_free() right before using it in mtype_ext_cleanup() again. So we just have to move it down.
Reported-by: syzbot+4c3cc6dbe7259dbf9054@syzkaller.appspotmail.com Fixes: 40cd63bf33b2 ("netfilter: ipset: Support extensions which need a per data destroy function") Acked-by: Jozsef Kadlecsik kadlec@netfilter.org Signed-off-by: Cong Wang xiyou.wangcong@gmail.com Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/netfilter/ipset/ip_set_bitmap_gen.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/net/netfilter/ipset/ip_set_bitmap_gen.h +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h @@ -66,12 +66,12 @@ mtype_destroy(struct ip_set *set) if (SET_WITH_TIMEOUT(set)) del_timer_sync(&map->gc);
- ip_set_free(map->members); if (set->dsize) { if (set->extensions & IPSET_EXT_DESTROY) mtype_ext_cleanup(set); ip_set_free(map->extensions); } + ip_set_free(map->members); kfree(map);
set->data = NULL;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal fw@strlen.de
commit 212e7f56605ef9688d0846db60c6c6ec06544095 upstream.
An earlier commit (1b789577f655060d98d20e, "netfilter: arp_tables: init netns pointer in xt_tgchk_param struct") fixed missing net initialization for arptables, but turns out it was incomplete. We can get a very similar struct net NULL deref during error unwinding:
general protection fault: 0000 [#1] PREEMPT SMP KASAN RIP: 0010:xt_rateest_put+0xa1/0x440 net/netfilter/xt_RATEEST.c:77 xt_rateest_tg_destroy+0x72/0xa0 net/netfilter/xt_RATEEST.c:175 cleanup_entry net/ipv4/netfilter/arp_tables.c:509 [inline] translate_table+0x11f4/0x1d80 net/ipv4/netfilter/arp_tables.c:587 do_replace net/ipv4/netfilter/arp_tables.c:981 [inline] do_arpt_set_ctl+0x317/0x650 net/ipv4/netfilter/arp_tables.c:1461
Also init the netns pointer in xt_tgdtor_param struct.
Fixes: add67461240c1d ("netfilter: add struct net * to target parameters") Reported-by: syzbot+91bdd8eece0f6629ec8b@syzkaller.appspotmail.com Signed-off-by: Florian Westphal fw@strlen.de Signed-off-by: Pablo Neira Ayuso pablo@netfilter.org [bwh: Backported to 3.16: - __arpt_unregister_table() has not been split out of arpt_unregister_table() - Add "net" parameter to arpt_unregister_table() and update its only caller in arptable_filter.c] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -51,7 +51,7 @@ extern void *arpt_alloc_initial_table(co extern struct xt_table *arpt_register_table(struct net *net, const struct xt_table *table, const struct arpt_replace *repl); -extern void arpt_unregister_table(struct xt_table *table); +extern void arpt_unregister_table(struct net *, struct xt_table *table); extern unsigned int arpt_do_table(struct sk_buff *skb, unsigned int hook, const struct net_device *in, --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -602,12 +602,13 @@ static inline int check_entry_size_and_h return 0; }
-static inline void cleanup_entry(struct arpt_entry *e) +static void cleanup_entry(struct arpt_entry *e, struct net *net) { struct xt_tgdtor_param par; struct xt_entry_target *t;
t = arpt_get_target(e); + par.net = net; par.target = t->u.kernel.target; par.targinfo = t->data; par.family = NFPROTO_ARP; @@ -706,7 +707,7 @@ static int translate_table(struct net *n xt_entry_foreach(iter, entry0, newinfo->size) { if (i-- == 0) break; - cleanup_entry(iter); + cleanup_entry(iter, net); } return ret; } @@ -1051,7 +1052,7 @@ static int __do_replace(struct net *net, /* Decrease module usage counts and free resource */ loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()]; xt_entry_foreach(iter, loc_cpu_old_entry, oldinfo->size) - cleanup_entry(iter); + cleanup_entry(iter, net);
xt_free_table_info(oldinfo); if (copy_to_user(counters_ptr, counters, @@ -1118,7 +1119,7 @@ static int do_replace(struct net *net, c
free_newinfo_untrans: xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) - cleanup_entry(iter); + cleanup_entry(iter, net); free_newinfo: xt_free_table_info(newinfo); return ret; @@ -1431,7 +1432,7 @@ static int compat_do_replace(struct net
free_newinfo_untrans: xt_entry_foreach(iter, loc_cpu_entry, newinfo->size) - cleanup_entry(iter); + cleanup_entry(iter, net); free_newinfo: xt_free_table_info(newinfo); return ret; @@ -1708,7 +1709,7 @@ out: return ERR_PTR(ret); }
-void arpt_unregister_table(struct xt_table *table) +void arpt_unregister_table(struct net *net, struct xt_table *table) { struct xt_table_info *private; void *loc_cpu_entry; @@ -1720,7 +1721,7 @@ void arpt_unregister_table(struct xt_tab /* Decrease module usage counts and free resources */ loc_cpu_entry = private->entries[raw_smp_processor_id()]; xt_entry_foreach(iter, loc_cpu_entry, private->size) - cleanup_entry(iter); + cleanup_entry(iter, net); if (private->number > private->initial_entries) module_put(table_owner); xt_free_table_info(private); --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -54,7 +54,7 @@ static int __net_init arptable_filter_ne
static void __net_exit arptable_filter_net_exit(struct net *net) { - arpt_unregister_table(net->ipv4.arptable_filter); + arpt_unregister_table(net, net->ipv4.arptable_filter); }
static struct pernet_operations arptable_filter_net_ops = {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Alberto Aguirre albaguirre@gmail.com
commit 17f08b0d9aafccdb10038ab6dbd9ddb6433c13e2 upstream.
The Axe-Fx II implicit feedback end point and the data sync endpoint are in different interface descriptors. Add quirk to ensure a sync endpoint is properly configured.
Signed-off-by: Alberto Aguirre albaguirre@gmail.com Signed-off-by: Takashi Iwai tiwai@suse.de [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- sound/usb/pcm.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
--- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -351,6 +351,15 @@ static int set_sync_ep_implicit_fb_quirk
alts = &iface->altsetting[1]; goto add_sync_ep; + case USB_ID(0x2466, 0x8003): + ep = 0x86; + iface = usb_ifnum_to_if(dev, 2); + + if (!iface || iface->num_altsetting == 0) + return -EINVAL; + + alts = &iface->altsetting[1]; + goto add_sync_ep; case USB_ID(0x1397, 0x0002): ep = 0x81; iface = usb_ifnum_to_if(dev, 1); @@ -360,6 +369,7 @@ static int set_sync_ep_implicit_fb_quirk
alts = &iface->altsetting[1]; goto add_sync_ep; + } if (attr == USB_ENDPOINT_SYNC_ASYNC && altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Alberto Aguirre albaguirre@gmail.com
commit 103e9625647ad74d201e26fb74afcd8479142a37 upstream.
Signed-off-by: Alberto Aguirre albaguirre@gmail.com Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Ben Hutchings ben@decadent.org.uk --- sound/usb/pcm.c | 52 +++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 32 deletions(-)
--- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -324,6 +324,7 @@ static int set_sync_ep_implicit_fb_quirk struct usb_host_interface *alts; struct usb_interface *iface; unsigned int ep; + unsigned int ifnum;
/* Implicit feedback sync EPs consumers are always playback EPs */ if (subs->direction != SNDRV_PCM_STREAM_PLAYBACK) @@ -333,44 +334,23 @@ static int set_sync_ep_implicit_fb_quirk case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ ep = 0x81; - iface = usb_ifnum_to_if(dev, 3); - - if (!iface || iface->num_altsetting == 0) - return -EINVAL; - - alts = &iface->altsetting[1]; - goto add_sync_ep; - break; + ifnum = 3; + goto add_sync_ep_from_ifnum; case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ case USB_ID(0x0763, 0x2081): ep = 0x81; - iface = usb_ifnum_to_if(dev, 2); - - if (!iface || iface->num_altsetting == 0) - return -EINVAL; - - alts = &iface->altsetting[1]; - goto add_sync_ep; - case USB_ID(0x2466, 0x8003): + ifnum = 2; + goto add_sync_ep_from_ifnum; + case USB_ID(0x2466, 0x8003): /* Fractal Audio Axe-Fx II */ ep = 0x86; - iface = usb_ifnum_to_if(dev, 2); - - if (!iface || iface->num_altsetting == 0) - return -EINVAL; - - alts = &iface->altsetting[1]; - goto add_sync_ep; - case USB_ID(0x1397, 0x0002): + ifnum = 2; + goto add_sync_ep_from_ifnum; + case USB_ID(0x1397, 0x0002): /* Behringer UFX1204 */ ep = 0x81; - iface = usb_ifnum_to_if(dev, 1); - - if (!iface || iface->num_altsetting == 0) - return -EINVAL; - - alts = &iface->altsetting[1]; - goto add_sync_ep; - + ifnum = 1; + goto add_sync_ep_from_ifnum; } + if (attr == USB_ENDPOINT_SYNC_ASYNC && altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && altsd->bInterfaceProtocol == 2 && @@ -385,6 +365,14 @@ static int set_sync_ep_implicit_fb_quirk /* No quirk */ return 0;
+add_sync_ep_from_ifnum: + iface = usb_ifnum_to_if(dev, ifnum); + + if (!iface || iface->num_altsetting == 0) + return -EINVAL; + + alts = &iface->altsetting[1]; + add_sync_ep: subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, alts, ep, !subs->direction,
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 5d1b71226dc4d44b4b65766fa9d74492f9d4587b upstream.
The altsetting sanity check in set_sync_ep_implicit_fb_quirk() was checking for there to be at least one altsetting but then went on to access the second one, which may not exist.
This could lead to random slab data being used to initialise the sync endpoint in snd_usb_add_endpoint().
Fixes: c75a8a7ae565 ("ALSA: snd-usb: add support for implicit feedback") Fixes: ca10a7ebdff1 ("ALSA: usb-audio: FT C400 sync playback EP to capture EP") Fixes: 5e35dc0338d8 ("ALSA: usb-audio: add implicit fb quirk for Behringer UFX1204") Fixes: 17f08b0d9aaf ("ALSA: usb-audio: add implicit fb quirk for Axe-Fx II") Fixes: 103e9625647a ("ALSA: usb-audio: simplify set_sync_ep_implicit_fb_quirk") Signed-off-by: Johan Hovold johan@kernel.org Link: https://lore.kernel.org/r/20200114083953.1106-1-johan@kernel.org Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Ben Hutchings ben@decadent.org.uk --- sound/usb/pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -368,7 +368,7 @@ static int set_sync_ep_implicit_fb_quirk add_sync_ep_from_ifnum: iface = usb_ifnum_to_if(dev, ifnum);
- if (!iface || iface->num_altsetting == 0) + if (!iface || iface->num_altsetting < 2) return -EINVAL;
alts = &iface->altsetting[1];
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 5e28055f340275a8616eee88ef19186631b4d136 upstream.
The driver was issuing synchronous uninterruptible control requests without using a timeout. This could lead to the driver hanging on open() or tiocmset() due to a malfunctioning (or malicious) device until the device is physically disconnected.
The USB upper limit of five seconds per request should be more than enough.
Fixes: 309a057932ab ("USB: opticon: add rts and cts support") Cc: Martin Jansen martin.jansen@opticon.com Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/serial/opticon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -116,7 +116,7 @@ static int send_control_msg(struct usb_s retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), requesttype, USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, - 0, 0, buffer, 1, 0); + 0, 0, buffer, 1, USB_CTRL_SET_TIMEOUT); kfree(buffer);
if (retval < 0)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 86f3f4cd53707ceeec079b83205c8d3c756eca93 upstream.
Add missing endpoint sanity check to probe in order to prevent a NULL-pointer dereference (or slab out-of-bounds access) when retrieving the interrupt-endpoint bInterval on ndo_open() in case a device lacks the expected endpoints.
Fixes: 40a82917b1d3 ("net/usb/r8152: enable interrupt transfer") Cc: hayeswang hayeswang@realtek.com Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/usb/r8152.c | 3 +++ 1 file changed, 3 insertions(+)
--- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3425,6 +3425,9 @@ static int rtl8152_probe(struct usb_inte return -ENODEV; }
+ if (intf->cur_altsetting->desc.bNumEndpoints < 3) + return -ENODEV; + usb_reset_device(udev); netdev = alloc_etherdev(sizeof(struct r8152)); if (!netdev) {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Keiya Nobuta nobuta.keiya@fujitsu.com
commit 9c06ac4c83df6d6fbdbf7488fbad822b4002ba19 upstream.
If hub_activate() is called before D+ has stabilized after remote wakeup, the following situation might occur:
__ ___________________ / \ / D+ __/ __/
Hub _______________________________ | ^ ^ ^ | | | | Host _____v__|___|___________|______ | | | | | | | -- Interrupt Transfer (*3) | | -- ClearPortFeature (*2) | -- GetPortStatus (*1) -- Host detects remote wakeup
- D+ goes high, Host starts running by remote wakeup - D+ is not stable, goes low - Host requests GetPortStatus at (*1) and gets the following hub status: - Current Connect Status bit is 0 - Connect Status Change bit is 1 - D+ stabilizes, goes high - Host requests ClearPortFeature and thus Connect Status Change bit is cleared at (*2) - After waiting 100 ms, Host starts the Interrupt Transfer at (*3) - Since the Connect Status Change bit is 0, Hub returns NAK.
In this case, port_event() is not called in hub_event() and Host cannot recognize device. To solve this issue, flag change_bits even if only Connect Status Change bit is 1 when got in the first GetPortStatus.
This issue occurs rarely because it only if D+ changes during a very short time between GetPortStatus and ClearPortFeature. However, it is fatal if it occurs in embedded system.
Signed-off-by: Keiya Nobuta nobuta.keiya@fujitsu.com Acked-by: Alan Stern stern@rowland.harvard.edu Link: https://lore.kernel.org/r/20200109051448.28150-1-nobuta.keiya@fujitsu.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/core/hub.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1125,6 +1125,7 @@ static void hub_activate(struct usb_hub * PORT_OVER_CURRENT is not. So check for any of them. */ if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || + (portchange & USB_PORT_STAT_C_CONNECTION) || (portstatus & USB_PORT_STAT_OVERCURRENT) || (portchange & USB_PORT_STAT_C_OVERCURRENT)) set_bit(port1, hub->change_bits);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jari Ruusu jari.ruusu@gmail.com
commit f5ae2ea6347a308cfe91f53b53682ce635497d0d upstream.
Intel Software Developer's Manual, volume 3, chapter 9.11.6 says:
"Note that the microcode update must be aligned on a 16-byte boundary and the size of the microcode update must be 1-KByte granular"
When early-load Intel microcode is loaded from initramfs, userspace tool 'iucode_tool' has already 16-byte aligned those microcode bits in that initramfs image. Image that was created something like this:
iucode_tool --write-earlyfw=FOO.cpio microcode-files...
However, when early-load Intel microcode is loaded from built-in firmware BLOB using CONFIG_EXTRA_FIRMWARE= kernel config option, that 16-byte alignment is not guaranteed.
Fix this by forcing all built-in firmware BLOBs to 16-byte alignment.
[ If we end up having other firmware with much bigger alignment requirements, we might need to introduce some method for the firmware to specify it, this is the minimal "just increase the alignment a bit to account for this one special case" patch - Linus ]
Signed-off-by: Jari Ruusu jari.ruusu@gmail.com Cc: Borislav Petkov bp@alien8.de Cc: Fenghua Yu fenghua.yu@intel.com Cc: Luis Chamberlain mcgrof@kernel.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org [bwh: Backported to 3.16: adjust filename, context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- firmware/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/firmware/Makefile +++ b/firmware/Makefile @@ -156,7 +156,7 @@ quiet_cmd_fwbin = MK_FW $@ PROGBITS=$(if $(CONFIG_ARM),%,@)progbits; \ echo "/* Generated by firmware/Makefile */" > $@;\ echo " .section .rodata" >>$@;\ - echo " .p2align $${ASM_ALIGN}" >>$@;\ + echo " .p2align 4" >>$@;\ echo "_fw_$${FWSTR}_bin:" >>$@;\ echo " .incbin "$(2)"" >>$@;\ echo "_fw_end:" >>$@;\
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai tiwai@suse.de
commit 60adcfde92fa40fcb2dbf7cc52f9b096e0cd109a upstream.
snd_seq_info_timer_read() reads the information of the timer assigned for each queue, but it's done in a racy way which may lead to UAF as spotted by syzkaller.
This patch applies the missing q->timer_mutex lock while accessing the timer object as well as a slight code change to adapt the standard coding style.
Reported-by: syzbot+2b2ef983f973e5c40943@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/20200115203733.26530-1-tiwai@suse.de Signed-off-by: Takashi Iwai tiwai@suse.de Signed-off-by: Ben Hutchings ben@decadent.org.uk --- sound/core/seq/seq_timer.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
--- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -484,15 +484,19 @@ void snd_seq_info_timer_read(struct snd_ q = queueptr(idx); if (q == NULL) continue; - if ((tmr = q->timer) == NULL || - (ti = tmr->timeri) == NULL) { - queuefree(q); - continue; - } + mutex_lock(&q->timer_mutex); + tmr = q->timer; + if (!tmr) + goto unlock; + ti = tmr->timeri; + if (!ti) + goto unlock; snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name); resolution = snd_timer_resolution(ti) * tmr->ticks; snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000); snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base); +unlock: + mutex_unlock(&q->timer_mutex); queuefree(q); } }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Arnd Bergmann arnd@arndb.de
commit 42ec15ceaea74b5f7a621fc6686cbf69ca66c4cf upstream.
gcc -O3 warns that some local variables are not properly initialized:
drivers/scsi/fnic/vnic_dev.c: In function 'fnic_dev_hang_notify': drivers/scsi/fnic/vnic_dev.c:511:16: error: 'a0' is used uninitialized in this function [-Werror=uninitialized] vdev->args[0] = *a0; ~~~~~~~~~~~~~~^~~~~ drivers/scsi/fnic/vnic_dev.c:691:6: note: 'a0' was declared here u64 a0, a1; ^~ drivers/scsi/fnic/vnic_dev.c:512:16: error: 'a1' is used uninitialized in this function [-Werror=uninitialized] vdev->args[1] = *a1; ~~~~~~~~~~~~~~^~~~~ drivers/scsi/fnic/vnic_dev.c:691:10: note: 'a1' was declared here u64 a0, a1; ^~ drivers/scsi/fnic/vnic_dev.c: In function 'fnic_dev_mac_addr': drivers/scsi/fnic/vnic_dev.c:512:16: error: 'a1' is used uninitialized in this function [-Werror=uninitialized] vdev->args[1] = *a1; ~~~~~~~~~~~~~~^~~~~ drivers/scsi/fnic/vnic_dev.c:698:10: note: 'a1' was declared here u64 a0, a1; ^~
Apparently the code relies on the local variables occupying adjacent memory locations in the same order, but this is of course not guaranteed.
Use an array of two u64 variables where needed to make it work correctly.
I suspect there is also an endianness bug here, but have not digged in deep enough to be sure.
Fixes: 5df6d737dd4b ("[SCSI] fnic: Add new Cisco PCI-Express FCoE HBA") Fixes: mmtom ("init/Kconfig: enable -O3 for all arches") Link: https://lore.kernel.org/r/20200107201602.4096790-1-arnd@arndb.de Signed-off-by: Arnd Bergmann arnd@arndb.de Signed-off-by: Martin K. Petersen martin.petersen@oracle.com [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/scsi/fnic/vnic_dev.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
--- a/drivers/scsi/fnic/vnic_dev.c +++ b/drivers/scsi/fnic/vnic_dev.c @@ -445,26 +445,26 @@ int vnic_dev_soft_reset_done(struct vnic
int vnic_dev_hang_notify(struct vnic_dev *vdev) { - u64 a0, a1; + u64 a0 = 0, a1 = 0; int wait = 1000; return vnic_dev_cmd(vdev, CMD_HANG_NOTIFY, &a0, &a1, wait); }
int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr) { - u64 a0, a1; + u64 a[2] = {}; int wait = 1000; int err, i;
for (i = 0; i < ETH_ALEN; i++) mac_addr[i] = 0;
- err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait); + err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a[0], &a[1], wait); if (err) return err;
for (i = 0; i < ETH_ALEN; i++) - mac_addr[i] = ((u8 *)&a0)[i]; + mac_addr[i] = ((u8 *)&a)[i];
return 0; } @@ -489,15 +489,15 @@ void vnic_dev_packet_filter(struct vnic_
void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) { - u64 a0 = 0, a1 = 0; + u64 a[2] = {}; int wait = 1000; int err; int i;
for (i = 0; i < ETH_ALEN; i++) - ((u8 *)&a0)[i] = addr[i]; + ((u8 *)&a)[i] = addr[i];
- err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); + err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a[0], &a[1], wait); if (err) printk(KERN_ERR "Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", @@ -507,15 +507,15 @@ void vnic_dev_add_addr(struct vnic_dev *
void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) { - u64 a0 = 0, a1 = 0; + u64 a[2] = {}; int wait = 1000; int err; int i;
for (i = 0; i < ETH_ALEN; i++) - ((u8 *)&a0)[i] = addr[i]; + ((u8 *)&a)[i] = addr[i];
- err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); + err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a[0], &a[1], wait); if (err) printk(KERN_ERR "Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n",
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka mpatocka@redhat.com
commit ad6bf88a6c19a39fb3b0045d78ea880325dfcf15 upstream.
Logical block size has type unsigned short. That means that it can be at most 32768. However, there are architectures that can run with 64k pages (for example arm64) and on these architectures, it may be possible to create block devices with 64k block size.
For exmaple (run this on an architecture with 64k pages):
Mount will fail with this error because it tries to read the superblock using 2-sector access: device-mapper: writecache: I/O is not aligned, sector 2, size 1024, block size 65536 EXT4-fs (dm-0): unable to read superblock
This patch changes the logical block size from unsigned short to unsigned int to avoid the overflow.
Reviewed-by: Martin K. Petersen martin.petersen@oracle.com Reviewed-by: Ming Lei ming.lei@redhat.com Signed-off-by: Mikulas Patocka mpatocka@redhat.com Signed-off-by: Jens Axboe axboe@kernel.dk [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- block/blk-settings.c | 2 +- drivers/md/dm-snap-persistent.c | 2 +- drivers/md/raid0.c | 2 +- include/linux/blkdev.h | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-)
--- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -373,7 +373,7 @@ EXPORT_SYMBOL(blk_queue_max_segment_size * storage device can address. The default of 512 covers most * hardware. **/ -void blk_queue_logical_block_size(struct request_queue *q, unsigned short size) +void blk_queue_logical_block_size(struct request_queue *q, unsigned int size) { q->limits.logical_block_size = size;
--- a/drivers/md/dm-snap-persistent.c +++ b/drivers/md/dm-snap-persistent.c @@ -16,7 +16,7 @@ #include "dm-bufio.h"
#define DM_MSG_PREFIX "persistent snapshot" -#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32 /* 16KB */ +#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32U /* 16KB */
#define DM_PREFETCH_CHUNKS 12
--- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -88,7 +88,7 @@ static int create_strip_zones(struct mdd char b[BDEVNAME_SIZE]; char b2[BDEVNAME_SIZE]; struct r0conf *conf = kzalloc(sizeof(*conf), GFP_KERNEL); - unsigned short blksize = 512; + unsigned blksize = 512;
if (!conf) return -ENOMEM; --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -284,6 +284,7 @@ struct queue_limits { unsigned int max_sectors; unsigned int max_segment_size; unsigned int physical_block_size; + unsigned int logical_block_size; unsigned int alignment_offset; unsigned int io_min; unsigned int io_opt; @@ -292,7 +293,6 @@ struct queue_limits { unsigned int discard_granularity; unsigned int discard_alignment;
- unsigned short logical_block_size; unsigned short max_segments; unsigned short max_integrity_segments;
@@ -1017,7 +1017,7 @@ extern void blk_queue_max_discard_sector unsigned int max_discard_sectors); extern void blk_queue_max_write_same_sectors(struct request_queue *q, unsigned int max_write_same_sectors); -extern void blk_queue_logical_block_size(struct request_queue *, unsigned short); +extern void blk_queue_logical_block_size(struct request_queue *, unsigned int); extern void blk_queue_physical_block_size(struct request_queue *, unsigned int); extern void blk_queue_alignment_offset(struct request_queue *q, unsigned int alignment); @@ -1232,7 +1232,7 @@ static inline unsigned int queue_max_seg return q->limits.max_segment_size; }
-static inline unsigned short queue_logical_block_size(struct request_queue *q) +static inline unsigned queue_logical_block_size(struct request_queue *q) { int retval = 512;
@@ -1242,7 +1242,7 @@ static inline unsigned short queue_logic return retval; }
-static inline unsigned short bdev_logical_block_size(struct block_device *bdev) +static inline unsigned int bdev_logical_block_size(struct block_device *bdev) { return queue_logical_block_size(bdev_get_queue(bdev)); }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet edumazet@google.com
commit 1712b2fff8c682d145c7889d2290696647d82dab upstream.
I missed the fact that macvlan_broadcast() can be used both in RX and TX.
skb_eth_hdr() makes only sense in TX paths, so we can not use it blindly in macvlan_broadcast()
Fixes: 96cc4b69581d ("macvlan: do not assume mac_header is set in macvlan_broadcast()") Signed-off-by: Eric Dumazet edumazet@google.com Reported-by: Jurgen Van Ham juvanham@gmail.com Tested-by: Matteo Croce mcroce@redhat.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/macvlan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
--- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -162,7 +162,7 @@ static void macvlan_broadcast(struct sk_ struct net_device *src, enum macvlan_mode mode) { - const struct ethhdr *eth = skb_eth_hdr(skb); + const struct ethhdr *eth = eth_hdr(skb); const struct macvlan_dev *vlan; struct sk_buff *nskb; unsigned int i; @@ -345,10 +345,11 @@ static int macvlan_queue_xmit(struct sk_ const struct macvlan_dev *dest;
if (vlan->mode == MACVLAN_MODE_BRIDGE) { - const struct ethhdr *eth = (void *)skb->data; + const struct ethhdr *eth = skb_eth_hdr(skb);
/* send to other bridge ports directly */ if (is_multicast_ether_addr(eth->h_dest)) { + skb_reset_mac_header(skb); macvlan_broadcast(skb, port, dev, MACVLAN_MODE_BRIDGE); goto xmit_world; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit ba9a103f40fc4a3ec7558ec9b0b97d4f92034249 upstream.
The driver was issuing synchronous uninterruptible control requests without using a timeout. This could lead to the driver hanging on probe due to a malfunctioning (or malicious) device until the device is physically disconnected. While sleeping in probe the driver prevents other devices connected to the same hub from being added to (or removed from) the bus.
The USB upper limit of five seconds per request should be more than enough.
Fixes: 99f83c9c9ac9 ("[PATCH] USB: add driver for Keyspan Digital Remote") Signed-off-by: Johan Hovold johan@kernel.org Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Link: https://lore.kernel.org/r/20200113171715.30621-1-johan@kernel.org Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/input/misc/keyspan_remote.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
--- a/drivers/input/misc/keyspan_remote.c +++ b/drivers/input/misc/keyspan_remote.c @@ -344,7 +344,8 @@ static int keyspan_setup(struct usb_devi int retval = 0;
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0); + 0x11, 0x40, 0x5601, 0x0, NULL, 0, + USB_CTRL_SET_TIMEOUT); if (retval) { dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n", __func__, retval); @@ -352,7 +353,8 @@ static int keyspan_setup(struct usb_devi }
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x44, 0x40, 0x0, 0x0, NULL, 0, 0); + 0x44, 0x40, 0x0, 0x0, NULL, 0, + USB_CTRL_SET_TIMEOUT); if (retval) { dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n", __func__, retval); @@ -360,7 +362,8 @@ static int keyspan_setup(struct usb_devi }
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0x22, 0x40, 0x0, 0x0, NULL, 0, 0); + 0x22, 0x40, 0x0, 0x0, NULL, 0, + USB_CTRL_SET_TIMEOUT); if (retval) { dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n", __func__, retval);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit fdb838efa31e1ed9a13ae6ad0b64e30fdbd00570 upstream.
USB-serial drivers must not be unbound from their ports before the corresponding USB driver is unbound from the parent interface so suppress the bind and unbind attributes.
Unbinding a serial driver while it's port is open is a sure way to trigger a crash as any driver state is released on unbind while port hangup is handled on the parent USB interface level. Drivers for multiport devices where ports share a resource such as an interrupt endpoint also generally cannot handle individual ports going away.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/serial/usb-serial.c | 3 +++ 1 file changed, 3 insertions(+)
--- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1337,6 +1337,9 @@ static int usb_serial_register(struct us return -EINVAL; }
+ /* Prevent individual ports from being unbound. */ + driver->driver.suppress_bind_attrs = true; + usb_serial_operations_init(driver);
/* Add this device to our list of devices */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 4d5ef53f75c22d28f490bcc5c771fcc610a9afa4 upstream.
Check for NULL port data in reset_resume() to avoid dereferencing a NULL pointer in case the port device isn't bound to a driver (e.g. after a failed control request at port probe).
Fixes: 1ded7ea47b88 ("USB: ch341 serial: fix port number changed after resume") Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/serial/ch341.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -571,9 +571,13 @@ static int ch341_tiocmget(struct tty_str static int ch341_reset_resume(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; - struct ch341_private *priv = usb_get_serial_port_data(port); + struct ch341_private *priv; int ret;
+ priv = usb_get_serial_port_data(port); + if (!priv) + return 0; + /* reconfigure ch341 serial port after bus-reset */ ch341_configure(serial->dev, priv);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit e37d1aeda737a20b1846a91a3da3f8b0f00cf690 upstream.
Check for NULL port data in the shared interrupt and bulk completion callbacks to avoid dereferencing a NULL pointer in case a device sends data for a port device which isn't bound to a driver (e.g. due to a malicious device having unexpected endpoints or after an allocation failure on port probe).
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Johan Hovold johan@kernel.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/serial/io_edgeport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -638,7 +638,7 @@ static void edge_interrupt_callback(stru if (txCredits) { port = edge_serial->serial->port[portNumber]; edge_port = usb_get_serial_port_data(port); - if (edge_port->open) { + if (edge_port && edge_port->open) { spin_lock(&edge_port->ep_lock); edge_port->txCredits += txCredits; spin_unlock(&edge_port->ep_lock); @@ -1775,7 +1775,7 @@ static void process_rcvd_data(struct edg port = edge_serial->serial->port[ edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); - if (edge_port->open) { + if (edge_port && edge_port->open) { dev_dbg(dev, "%s - Sending %d bytes to TTY for port %d\n", __func__, rxLen, edge_serial->rxPort);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 1568c58d11a7c851bd09341aeefd6a1c308ac40d upstream.
The driver receives the active port number from the device, but never made sure that the port number was valid. This could lead to a NULL-pointer dereference or memory corruption in case a device sends data for an invalid port.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/serial/io_edgeport.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
--- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1666,7 +1666,8 @@ static void edge_break(struct tty_struct static void process_rcvd_data(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength) { - struct device *dev = &edge_serial->serial->dev->dev; + struct usb_serial *serial = edge_serial->serial; + struct device *dev = &serial->dev->dev; struct usb_serial_port *port; struct edgeport_port *edge_port; __u16 lastBufferLength; @@ -1771,9 +1772,8 @@ static void process_rcvd_data(struct edg
/* spit this data back into the tty driver if this port is open */ - if (rxLen) { - port = edge_serial->serial->port[ - edge_serial->rxPort]; + if (rxLen && edge_serial->rxPort < serial->num_ports) { + port = serial->port[edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); if (edge_port && edge_port->open) { dev_dbg(dev, "%s - Sending %d bytes to TTY for port %d\n", @@ -1783,8 +1783,8 @@ static void process_rcvd_data(struct edg rxLen); edge_port->port->icount.rx += rxLen; } - buffer += rxLen; } + buffer += rxLen; break;
case EXPECT_HDR3: /* Expect 3rd byte of status header */ @@ -1819,6 +1819,8 @@ static void process_rcvd_status(struct e __u8 code = edge_serial->rxStatusCode;
/* switch the port pointer to the one being currently talked about */ + if (edge_serial->rxPort >= edge_serial->serial->num_ports) + return; port = edge_serial->serial->port[edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); if (edge_port == NULL) {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 3018dd3fa114b13261e9599ddb5656ef97a1fa17 upstream.
Check for NULL port data in the control URB completion handlers to avoid dereferencing a NULL pointer in the unlikely case where a port device isn't bound to a driver (e.g. after an allocation failure on port probe()).
Fixes: 0ca1268e109a ("USB Serial Keyspan: add support for USA-49WG & USA-28XG") Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/serial/keyspan.c | 4 ++++ 1 file changed, 4 insertions(+)
--- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -962,6 +962,10 @@ static void usa67_glocont_callback(struc for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; p_priv = usb_get_serial_port_data(port); + if (!p_priv) + continue; + if (!p_priv) + continue;
if (p_priv->resend_cont) { dev_dbg(&port->dev, "%s - sending setup\n", __func__);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 9715a43eea77e42678a1002623f2d9a78f5b81a1 upstream.
Check for NULL port data in the modem- and line-status handlers to avoid dereferencing a NULL pointer in the unlikely case where a port device isn't bound to a driver (e.g. after an allocation failure on port probe).
Note that the other (stubbed) event handlers qt2_process_xmit_empty() and qt2_process_flush() would need similar sanity checks in case they are ever implemented.
Fixes: f7a33e608d9a ("USB: serial: add quatech2 usb to serial driver") Reviewed-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/usb/serial/quatech2.c | 6 ++++++ 1 file changed, 6 insertions(+)
--- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -872,7 +872,10 @@ static void qt2_update_msr(struct usb_se u8 newMSR = (u8) *ch; unsigned long flags;
+ /* May be called from qt2_process_read_urb() for an unbound port. */ port_priv = usb_get_serial_port_data(port); + if (!port_priv) + return;
spin_lock_irqsave(&port_priv->lock, flags); port_priv->shadowMSR = newMSR; @@ -900,7 +903,10 @@ static void qt2_update_lsr(struct usb_se unsigned long flags; u8 newLSR = (u8) *ch;
+ /* May be called from qt2_process_read_urb() for an unbound port. */ port_priv = usb_get_serial_port_data(port); + if (!port_priv) + return;
if (newLSR & UART_LSR_BI) newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Luuk Paulussen luuk.paulussen@alliedtelesis.co.nz
commit cf3ca1877574a306c0207cbf7fdf25419d9229df upstream.
reg2volt returns the voltage that matches a given register value. Converting this back the other way with volt2reg didn't return the same register value because it used truncation instead of rounding.
This meant that values read from sysfs could not be written back to sysfs to set back the same register value.
With this change, volt2reg will return the same value for every voltage previously returned by reg2volt (for the set of possible input values)
Signed-off-by: Luuk Paulussen luuk.paulussen@alliedtelesis.co.nz Link: https://lore.kernel.org/r/20191205231659.1301-1-luuk.paulussen@alliedtelesis... Signed-off-by: Guenter Roeck linux@roeck-us.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/hwmon/adt7475.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
--- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -268,9 +268,10 @@ static inline u16 volt2reg(int channel, long reg;
if (bypass_attn & (1 << channel)) - reg = (volt * 1024) / 2250; + reg = DIV_ROUND_CLOSEST(volt * 1024, 2250); else - reg = (volt * r[1] * 1024) / ((r[0] + r[1]) * 2250); + reg = DIV_ROUND_CLOSEST(volt * r[1] * 1024, + (r[0] + r[1]) * 2250); return clamp_val(reg, 0, 1023) & (0xff << 2); }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Alex Sverdlin alexander.sverdlin@nokia.com
commit 927d780ee371d7e121cea4fc7812f6ef2cea461c upstream.
Scenario 1, ARMv7 =================
If code in arch/arm/kernel/ftrace.c would operate on mcount() pointer the following may be generated:
00000230 <prealloc_fixed_plts>: 230: b5f8 push {r3, r4, r5, r6, r7, lr} 232: b500 push {lr} 234: f7ff fffe bl 0 <__gnu_mcount_nc> 234: R_ARM_THM_CALL __gnu_mcount_nc 238: f240 0600 movw r6, #0 238: R_ARM_THM_MOVW_ABS_NC __gnu_mcount_nc 23c: f8d0 1180 ldr.w r1, [r0, #384] ; 0x180
FTRACE currently is not able to deal with it:
WARNING: CPU: 0 PID: 0 at .../kernel/trace/ftrace.c:1979 ftrace_bug+0x1ad/0x230() ... CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.4.116-... #1 ... [<c0314e3d>] (unwind_backtrace) from [<c03115e9>] (show_stack+0x11/0x14) [<c03115e9>] (show_stack) from [<c051a7f1>] (dump_stack+0x81/0xa8) [<c051a7f1>] (dump_stack) from [<c0321c5d>] (warn_slowpath_common+0x69/0x90) [<c0321c5d>] (warn_slowpath_common) from [<c0321cf3>] (warn_slowpath_null+0x17/0x1c) [<c0321cf3>] (warn_slowpath_null) from [<c038ee9d>] (ftrace_bug+0x1ad/0x230) [<c038ee9d>] (ftrace_bug) from [<c038f1f9>] (ftrace_process_locs+0x27d/0x444) [<c038f1f9>] (ftrace_process_locs) from [<c08915bd>] (ftrace_init+0x91/0xe8) [<c08915bd>] (ftrace_init) from [<c0885a67>] (start_kernel+0x34b/0x358) [<c0885a67>] (start_kernel) from [<00308095>] (0x308095) ---[ end trace cb88537fdc8fa200 ]--- ftrace failed to modify [<c031266c>] prealloc_fixed_plts+0x8/0x60 actual: 44:f2:e1:36 ftrace record flags: 0 (0) expected tramp: c03143e9
Scenario 2, ARMv4T ==================
ftrace: allocating 14435 entries in 43 pages ------------[ cut here ]------------ WARNING: CPU: 0 PID: 0 at kernel/trace/ftrace.c:2029 ftrace_bug+0x204/0x310 CPU: 0 PID: 0 Comm: swapper Not tainted 4.19.5 #1 Hardware name: Cirrus Logic EDB9302 Evaluation Board [<c0010a24>] (unwind_backtrace) from [<c000ecb0>] (show_stack+0x20/0x2c) [<c000ecb0>] (show_stack) from [<c03c72e8>] (dump_stack+0x20/0x30) [<c03c72e8>] (dump_stack) from [<c0021c18>] (__warn+0xdc/0x104) [<c0021c18>] (__warn) from [<c0021d7c>] (warn_slowpath_null+0x4c/0x5c) [<c0021d7c>] (warn_slowpath_null) from [<c0095360>] (ftrace_bug+0x204/0x310) [<c0095360>] (ftrace_bug) from [<c04dabac>] (ftrace_init+0x3b4/0x4d4) [<c04dabac>] (ftrace_init) from [<c04cef4c>] (start_kernel+0x20c/0x410) [<c04cef4c>] (start_kernel) from [<00000000>] ( (null)) ---[ end trace 0506a2f5dae6b341 ]--- ftrace failed to modify [<c000c350>] perf_trace_sys_exit+0x5c/0xe8 actual: 1e:ff:2f:e1 Initializing ftrace call sites ftrace record flags: 0 (0) expected tramp: c000fb24
The analysis for this problem has been already performed previously, refer to the link below.
Fix the above problems by allowing only selected reloc types in __mcount_loc. The list itself comes from the legacy recordmcount.pl script.
Link: https://lore.kernel.org/lkml/56961010.6000806@pengutronix.de/ Fixes: ed60453fa8f8 ("ARM: 6511/1: ftrace: add ARM support for C version of recordmcount") Signed-off-by: Alexander Sverdlin alexander.sverdlin@nokia.com Acked-by: Steven Rostedt (VMware) rostedt@goodmis.org Signed-off-by: Russell King rmk+kernel@armlinux.org.uk Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- scripts/recordmcount.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
--- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -52,6 +52,10 @@ #define R_AARCH64_ABS64 257 #endif
+#define R_ARM_PC24 1 +#define R_ARM_THM_CALL 10 +#define R_ARM_CALL 28 + static int fd_map; /* File descriptor for file being modified. */ static int mmap_failed; /* Boolean flag. */ static char gpfx; /* prefix for global symbol name (sometimes '_') */ @@ -355,6 +359,18 @@ is_mcounted_section_name(char const *con #define RECORD_MCOUNT_64 #include "recordmcount.h"
+static int arm_is_fake_mcount(Elf32_Rel const *rp) +{ + switch (ELF32_R_TYPE(w(rp->r_info))) { + case R_ARM_THM_CALL: + case R_ARM_CALL: + case R_ARM_PC24: + return 0; + } + + return 1; +} + /* 64-bit EM_MIPS has weird ELF64_Rela.r_info. * http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.p... * We interpret Table 29 Relocation Operation (Elf64_Rel, Elf64_Rela) [p.40] @@ -443,6 +459,7 @@ do_file(char const *const fname) break; case EM_ARM: reltype = R_ARM_ABS32; altmcount = "__gnu_mcount_nc"; + is_fake_mcount32 = arm_is_fake_mcount; break; case EM_AARCH64: reltype = R_AARCH64_ABS64; gpfx = '_'; break;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Michał Mirosław mirq-linux@rere.qmqm.pl
commit 2a187d03352086e300daa2044051db00044cd171 upstream.
For SDHCIv3+ with programmable clock mode, minimal clock frequency is still base clock / max(divider). Minimal programmable clock frequency is always greater than minimal divided clock frequency. Without this patch, SDHCI uses out-of-spec initial frequency when multiplier is big enough:
mmc1: mmc_rescan_try_freq: trying to init card at 468750 Hz [for 480 MHz source clock divided by 1024]
The code in sdhci_calc_clk() already chooses a correct SDCLK clock mode.
Fixes: c3ed3877625f ("mmc: sdhci: add support for programmable clock mode") Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl Acked-by: Adrian Hunter adrian.hunter@intel.com Link: https://lore.kernel.org/r/ffb489519a446caffe7a0a05c4b9372bd52397bb.157908203... Signed-off-by: Ulf Hansson ulf.hansson@linaro.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/mmc/host/sdhci.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
--- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2945,11 +2945,13 @@ int sdhci_add_host(struct sdhci_host *ho if (host->ops->get_min_clock) mmc->f_min = host->ops->get_min_clock(host); else if (host->version >= SDHCI_SPEC_300) { - if (host->clk_mul) { - mmc->f_min = (host->max_clk * host->clk_mul) / 1024; + if (host->clk_mul) mmc->f_max = host->max_clk * host->clk_mul; - } else - mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; + /* + * Divided Clock Mode minimum clock rate is always less than + * Programmable Clock Mode minimum clock rate. + */ + mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; } else mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Richard Palethorpe rpalethorpe@suse.com
commit 0ace17d56824165c7f4c68785d6b58971db954dd upstream.
write_wakeup can happen in parallel with close/hangup where tty->disc_data is set to NULL and the netdevice is freed thus also freeing disc_data. write_wakeup accesses disc_data so we must prevent close from freeing the netdev while write_wakeup has a non-NULL view of tty->disc_data.
We also need to make sure that accesses to disc_data are atomic. Which can all be done with RCU.
This problem was found by Syzkaller on SLCAN, but the same issue is reproducible with the SLIP line discipline using an LTP test based on the Syzkaller reproducer.
A fix which didn't use RCU was posted by Hillf Danton.
Fixes: 661f7fda21b1 ("slip: Fix deadlock in write_wakeup") Fixes: a8e83b17536a ("slcan: Port write_wakeup deadlock fix from slip") Reported-by: syzbot+017e491ae13c0068598a@syzkaller.appspotmail.com Signed-off-by: Richard Palethorpe rpalethorpe@suse.com Cc: Wolfgang Grandegger wg@grandegger.com Cc: Marc Kleine-Budde mkl@pengutronix.de Cc: "David S. Miller" davem@davemloft.net Cc: Tyler Hall tylerwhall@gmail.com Cc: linux-can@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: syzkaller@googlegroups.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/can/slcan.c | 12 ++++++++++-- drivers/net/slip/slip.c | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-)
--- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -346,9 +346,16 @@ static void slcan_transmit(struct work_s */ static void slcan_write_wakeup(struct tty_struct *tty) { - struct slcan *sl = tty->disc_data; + struct slcan *sl; + + rcu_read_lock(); + sl = rcu_dereference(tty->disc_data); + if (!sl) + goto out;
schedule_work(&sl->tx_work); +out: + rcu_read_unlock(); }
/* Send a can_frame to a TTY queue. */ @@ -640,10 +647,11 @@ static void slcan_close(struct tty_struc return;
spin_lock_bh(&sl->lock); - tty->disc_data = NULL; + rcu_assign_pointer(tty->disc_data, NULL); sl->tty = NULL; spin_unlock_bh(&sl->lock);
+ synchronize_rcu(); flush_work(&sl->tx_work);
/* Flush network side */ --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -452,9 +452,16 @@ static void slip_transmit(struct work_st */ static void slip_write_wakeup(struct tty_struct *tty) { - struct slip *sl = tty->disc_data; + struct slip *sl; + + rcu_read_lock(); + sl = rcu_dereference(tty->disc_data); + if (!sl) + goto out;
schedule_work(&sl->tx_work); +out: + rcu_read_unlock(); }
static void sl_tx_timeout(struct net_device *dev) @@ -885,10 +892,11 @@ static void slip_close(struct tty_struct return;
spin_lock_bh(&sl->lock); - tty->disc_data = NULL; + rcu_assign_pointer(tty->disc_data, NULL); sl->tty = NULL; spin_unlock_bh(&sl->lock);
+ synchronize_rcu(); flush_work(&sl->tx_work);
/* VSV = very important to remove timers */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mao Wenan maowenan@huawei.com
commit 6e1cdedcf0362fed3aedfe051d46bd7ee2a85fe1 upstream.
NETDEV_TX_BUSY really should only be used by drivers that call netif_tx_stop_queue() at the wrong moment. If dma_map_single() is failed to map tx DMA buffer, it might trigger an infinite loop. This patch use NETDEV_TX_OK instead of NETDEV_TX_BUSY, and change printk to pr_err_ratelimited.
Fixes: d9fb9f384292 ("*sonic/natsemi/ns83829: Move the National Semi-conductor drivers") Signed-off-by: Mao Wenan maowenan@huawei.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/ethernet/natsemi/sonic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -221,9 +221,9 @@ static int sonic_send_packet(struct sk_b
laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE); if (!laddr) { - printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name); + pr_err_ratelimited("%s: failed to map tx DMA buffer.\n", dev->name); dev_kfree_skb(skb); - return NETDEV_TX_BUSY; + return NETDEV_TX_OK; }
sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Finn Thain fthain@telegraphics.com.au
commit 865ad2f2201dc18685ba2686f13217f8b3a9c52c upstream.
The netif_stop_queue() call in sonic_send_packet() races with the netif_wake_queue() call in sonic_interrupt(). This causes issues like "NETDEV WATCHDOG: eth0 (macsonic): transmit queue 0 timed out". Fix this by disabling interrupts when accessing tx_skb[] and next_tx. Update a comment to clarify the synchronization properties.
Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update") Tested-by: Stan Johnson userm57@yahoo.com Signed-off-by: Finn Thain fthain@telegraphics.com.au Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/ethernet/natsemi/sonic.c | 49 ++++++++++++++++++++-------- drivers/net/ethernet/natsemi/sonic.h | 1 + 2 files changed, 36 insertions(+), 14 deletions(-)
--- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -50,6 +50,8 @@ static int sonic_open(struct net_device if (sonic_debug > 2) printk("sonic_open: initializing sonic driver.\n");
+ spin_lock_init(&lp->lock); + for (i = 0; i < SONIC_NUM_RRS; i++) { struct sk_buff *skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2); if (skb == NULL) { @@ -194,8 +196,6 @@ static void sonic_tx_timeout(struct net_ * wake the tx queue * Concurrently with all of this, the SONIC is potentially writing to * the status flags of the TDs. - * Until some mutual exclusion is added, this code will not work with SMP. However, - * MIPS Jazz machines and m68k Macs were all uni-processor machines. */
static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) @@ -203,7 +203,8 @@ static int sonic_send_packet(struct sk_b struct sonic_local *lp = netdev_priv(dev); dma_addr_t laddr; int length; - int entry = lp->next_tx; + int entry; + unsigned long flags;
if (sonic_debug > 2) printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev); @@ -226,6 +227,10 @@ static int sonic_send_packet(struct sk_b return NETDEV_TX_OK; }
+ spin_lock_irqsave(&lp->lock, flags); + + entry = lp->next_tx; + sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */ sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */ sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */ @@ -235,10 +240,6 @@ static int sonic_send_packet(struct sk_b sonic_tda_put(dev, entry, SONIC_TD_LINK, sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL);
- /* - * Must set tx_skb[entry] only after clearing status, and - * before clearing EOL and before stopping queue - */ wmb(); lp->tx_len[entry] = length; lp->tx_laddr[entry] = laddr; @@ -263,6 +264,8 @@ static int sonic_send_packet(struct sk_b
SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
+ spin_unlock_irqrestore(&lp->lock, flags); + return NETDEV_TX_OK; }
@@ -275,9 +278,21 @@ static irqreturn_t sonic_interrupt(int i struct net_device *dev = dev_id; struct sonic_local *lp = netdev_priv(dev); int status; + unsigned long flags; + + /* The lock has two purposes. Firstly, it synchronizes sonic_interrupt() + * with sonic_send_packet() so that the two functions can share state. + * Secondly, it makes sonic_interrupt() re-entrant, as that is required + * by macsonic which must use two IRQs with different priority levels. + */ + spin_lock_irqsave(&lp->lock, flags); + + status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT; + if (!status) { + spin_unlock_irqrestore(&lp->lock, flags);
- if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)) return IRQ_NONE; + }
do { if (status & SONIC_INT_PKTRX) { @@ -292,11 +307,12 @@ static irqreturn_t sonic_interrupt(int i int td_status; int freed_some = 0;
- /* At this point, cur_tx is the index of a TD that is one of: - * unallocated/freed (status set & tx_skb[entry] clear) - * allocated and sent (status set & tx_skb[entry] set ) - * allocated and not yet sent (status clear & tx_skb[entry] set ) - * still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear) + /* The state of a Transmit Descriptor may be inferred + * from { tx_skb[entry], td_status } as follows. + * { clear, clear } => the TD has never been used + * { set, clear } => the TD was handed to SONIC + * { set, set } => the TD was handed back + * { clear, set } => the TD is available for re-use */
if (sonic_debug > 2) @@ -398,7 +414,12 @@ static irqreturn_t sonic_interrupt(int i /* load CAM done */ if (status & SONIC_INT_LCD) SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */ - } while((status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)); + + status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT; + } while (status); + + spin_unlock_irqrestore(&lp->lock, flags); + return IRQ_HANDLED; }
--- a/drivers/net/ethernet/natsemi/sonic.h +++ b/drivers/net/ethernet/natsemi/sonic.h @@ -320,6 +320,7 @@ struct sonic_local { unsigned int next_tx; /* next free TD */ struct device *device; /* generic device */ struct net_device_stats stats; + spinlock_t lock; };
#define TX_TIMEOUT (3 * HZ)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Finn Thain fthain@telegraphics.com.au
commit e3885f576196ddfc670b3d53e745de96ffcb49ab upstream.
The driver accesses descriptor memory which is simultaneously accessed by the chip, so the compiler must not be allowed to re-order CPU accesses. sonic_buf_get() used 'volatile' to prevent that. sonic_buf_put() should have done so too but was overlooked.
Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update") Tested-by: Stan Johnson userm57@yahoo.com Signed-off-by: Finn Thain fthain@telegraphics.com.au Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/ethernet/natsemi/sonic.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
--- a/drivers/net/ethernet/natsemi/sonic.h +++ b/drivers/net/ethernet/natsemi/sonic.h @@ -342,30 +342,30 @@ static void sonic_tx_timeout(struct net_ as far as we can tell. */ /* OpenBSD calls this "SWO". I'd like to think that sonic_buf_put() is a much better name. */ -static inline void sonic_buf_put(void* base, int bitmode, +static inline void sonic_buf_put(u16 *base, int bitmode, int offset, __u16 val) { if (bitmode) #ifdef __BIG_ENDIAN - ((__u16 *) base + (offset*2))[1] = val; + __raw_writew(val, base + (offset * 2) + 1); #else - ((__u16 *) base + (offset*2))[0] = val; + __raw_writew(val, base + (offset * 2) + 0); #endif else - ((__u16 *) base)[offset] = val; + __raw_writew(val, base + (offset * 1) + 0); }
-static inline __u16 sonic_buf_get(void* base, int bitmode, +static inline __u16 sonic_buf_get(u16 *base, int bitmode, int offset) { if (bitmode) #ifdef __BIG_ENDIAN - return ((volatile __u16 *) base + (offset*2))[1]; + return __raw_readw(base + (offset * 2) + 1); #else - return ((volatile __u16 *) base + (offset*2))[0]; + return __raw_readw(base + (offset * 2) + 0); #endif else - return ((volatile __u16 *) base)[offset]; + return __raw_readw(base + (offset * 1) + 0); }
/* Inlines that you should actually use for reading/writing DMA buffers */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Finn Thain fthain@telegraphics.com.au
commit 9e311820f67e740f4fb8dcb82b4c4b5b05bdd1a5 upstream.
The SONIC can sometimes advance its rx buffer pointer (RRP register) without advancing its rx descriptor pointer (CRDA register). As a result the index of the current rx descriptor may not equal that of the current rx buffer. The driver mistakenly assumes that they are always equal. This assumption leads to incorrect packet lengths and possible packet duplication. Avoid this by calling a new function to locate the buffer corresponding to a given descriptor.
Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update") Tested-by: Stan Johnson userm57@yahoo.com Signed-off-by: Finn Thain fthain@telegraphics.com.au Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/ethernet/natsemi/sonic.c | 35 ++++++++++++++++++++++++---- drivers/net/ethernet/natsemi/sonic.h | 5 ++-- 2 files changed, 33 insertions(+), 7 deletions(-)
--- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -423,6 +423,21 @@ static irqreturn_t sonic_interrupt(int i return IRQ_HANDLED; }
+/* Return the array index corresponding to a given Receive Buffer pointer. */ +static int index_from_addr(struct sonic_local *lp, dma_addr_t addr, + unsigned int last) +{ + unsigned int i = last; + + do { + i = (i + 1) & SONIC_RRS_MASK; + if (addr == lp->rx_laddr[i]) + return i; + } while (i != last); + + return -ENOENT; +} + /* * We have a good packet(s), pass it/them up the network stack. */ @@ -442,6 +457,16 @@ static void sonic_rx(struct net_device *
status = sonic_rda_get(dev, entry, SONIC_RD_STATUS); if (status & SONIC_RCR_PRX) { + u32 addr = (sonic_rda_get(dev, entry, + SONIC_RD_PKTPTR_H) << 16) | + sonic_rda_get(dev, entry, SONIC_RD_PKTPTR_L); + int i = index_from_addr(lp, addr, entry); + + if (i < 0) { + WARN_ONCE(1, "failed to find buffer!\n"); + break; + } + /* Malloc up new buffer. */ new_skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2); if (new_skb == NULL) { @@ -463,7 +488,7 @@ static void sonic_rx(struct net_device *
/* now we have a new skb to replace it, pass the used one up the stack */ dma_unmap_single(lp->device, lp->rx_laddr[entry], SONIC_RBSIZE, DMA_FROM_DEVICE); - used_skb = lp->rx_skb[entry]; + used_skb = lp->rx_skb[i]; pkt_len = sonic_rda_get(dev, entry, SONIC_RD_PKTLEN); skb_trim(used_skb, pkt_len); used_skb->protocol = eth_type_trans(used_skb, dev); @@ -472,13 +497,13 @@ static void sonic_rx(struct net_device * lp->stats.rx_bytes += pkt_len;
/* and insert the new skb */ - lp->rx_laddr[entry] = new_laddr; - lp->rx_skb[entry] = new_skb; + lp->rx_laddr[i] = new_laddr; + lp->rx_skb[i] = new_skb;
bufadr_l = (unsigned long)new_laddr & 0xffff; bufadr_h = (unsigned long)new_laddr >> 16; - sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, bufadr_l); - sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, bufadr_h); + sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l); + sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h); } else { /* This should only happen, if we enable accepting broken packets. */ lp->stats.rx_errors++; --- a/drivers/net/ethernet/natsemi/sonic.h +++ b/drivers/net/ethernet/natsemi/sonic.h @@ -273,8 +273,9 @@ #define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */ #define SONIC_NUM_TDS 16 /* number of transmit descriptors */
-#define SONIC_RDS_MASK (SONIC_NUM_RDS-1) -#define SONIC_TDS_MASK (SONIC_NUM_TDS-1) +#define SONIC_RRS_MASK (SONIC_NUM_RRS - 1) +#define SONIC_RDS_MASK (SONIC_NUM_RDS - 1) +#define SONIC_TDS_MASK (SONIC_NUM_TDS - 1)
#define SONIC_RBSIZE 1520 /* size of one resource buffer */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Finn Thain fthain@telegraphics.com.au
commit 3f4b7e6a2be982fd8820a2b54d46dd9c351db899 upstream.
Make sure the SONIC's DMA engine is idle before altering the transmit and receive descriptors. Add a helper for this as it will be needed again.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Tested-by: Stan Johnson userm57@yahoo.com Signed-off-by: Finn Thain fthain@telegraphics.com.au Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/ethernet/natsemi/sonic.c | 25 +++++++++++++++++++++++++ drivers/net/ethernet/natsemi/sonic.h | 3 +++ 2 files changed, 28 insertions(+)
--- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -103,6 +103,24 @@ static int sonic_open(struct net_device return 0; }
+/* Wait for the SONIC to become idle. */ +static void sonic_quiesce(struct net_device *dev, u16 mask) +{ + struct sonic_local * __maybe_unused lp = netdev_priv(dev); + int i; + u16 bits; + + for (i = 0; i < 1000; ++i) { + bits = SONIC_READ(SONIC_CMD) & mask; + if (!bits) + return; + if (irqs_disabled() || in_interrupt()) + udelay(20); + else + usleep_range(100, 200); + } + WARN_ONCE(1, "command deadline expired! 0x%04x\n", bits); +}
/* * Close the SONIC device @@ -120,6 +138,9 @@ static int sonic_close(struct net_device /* * stop the SONIC, disable interrupts */ + SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); + sonic_quiesce(dev, SONIC_CR_ALL); + SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); @@ -159,6 +180,9 @@ static void sonic_tx_timeout(struct net_ * put the Sonic into software-reset mode and * disable all interrupts before releasing DMA buffers */ + SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); + sonic_quiesce(dev, SONIC_CR_ALL); + SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); @@ -638,6 +662,7 @@ static int sonic_init(struct net_device */ SONIC_WRITE(SONIC_CMD, 0); SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS); + sonic_quiesce(dev, SONIC_CR_ALL);
/* * initialize the receive resource area --- a/drivers/net/ethernet/natsemi/sonic.h +++ b/drivers/net/ethernet/natsemi/sonic.h @@ -109,6 +109,9 @@ #define SONIC_CR_TXP 0x0002 #define SONIC_CR_HTX 0x0001
+#define SONIC_CR_ALL (SONIC_CR_LCAM | SONIC_CR_RRRA | \ + SONIC_CR_RXEN | SONIC_CR_TXP) + /* * SONIC data configuration bits */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Cong Wang xiyou.wangcong@gmail.com
commit 61678d28d4a45ef376f5d02a839cc37509ae9281 upstream.
syzbot reported an out-of-bound access in em_nbyte. As initially analyzed by Eric, this is because em_nbyte sets its own em->datalen in em_nbyte_change() other than the one specified by user, but this value gets overwritten later by its caller tcf_em_validate(). We should leave em->datalen untouched to respect their choices.
I audit all the in-tree ematch users, all of those implement ->change() set em->datalen, so we can just avoid setting it twice in this case.
Reported-and-tested-by: syzbot+5af9a90dad568aa9f611@syzkaller.appspotmail.com Reported-by: syzbot+2f07903a5b05e7f36410@syzkaller.appspotmail.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: Eric Dumazet eric.dumazet@gmail.com Signed-off-by: Cong Wang xiyou.wangcong@gmail.com Reviewed-by: Eric Dumazet edumazet@google.com Signed-off-by: David S. Miller davem@davemloft.net [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- net/sched/ematch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -266,12 +266,12 @@ static int tcf_em_validate(struct tcf_pr } em->data = (unsigned long) v; } + em->datalen = data_len; } }
em->matchid = em_hdr->matchid; em->flags = em_hdr->flags; - em->datalen = data_len;
err = 0; errout:
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Salvatore Mesoraca s.mesoraca16@gmail.com
commit 30aba6656f61ed44cba445a3c0d38b296fa9e8f5 upstream.
Disallows open of FIFOs or regular files not owned by the user in world writable sticky directories, unless the owner is the same as that of the directory or the file is opened without the O_CREAT flag. The purpose is to make data spoofing attacks harder. This protection can be turned on and off separately for FIFOs and regular files via sysctl, just like the symlinks/hardlinks protection. This patch is based on Openwall's "HARDEN_FIFO" feature by Solar Designer.
This is a brief list of old vulnerabilities that could have been prevented by this feature, some of them even allow for privilege escalation:
CVE-2000-1134 CVE-2007-3852 CVE-2008-0525 CVE-2009-0416 CVE-2011-4834 CVE-2015-1838 CVE-2015-7442 CVE-2016-7489
This list is not meant to be complete. It's difficult to track down all vulnerabilities of this kind because they were often reported without any mention of this particular attack vector. In fact, before hardlinks/symlinks restrictions, fifos/regular files weren't the favorite vehicle to exploit them.
[s.mesoraca16@gmail.com: fix bug reported by Dan Carpenter] Link: https://lkml.kernel.org/r/20180426081456.GA7060@mwanda Link: http://lkml.kernel.org/r/1524829819-11275-1-git-send-email-s.mesoraca16@gmai... [keescook@chromium.org: drop pr_warn_ratelimited() in favor of audit changes in the future] [keescook@chromium.org: adjust commit subjet] Link: http://lkml.kernel.org/r/20180416175918.GA13494@beast Signed-off-by: Salvatore Mesoraca s.mesoraca16@gmail.com Signed-off-by: Kees Cook keescook@chromium.org Suggested-by: Solar Designer solar@openwall.com Suggested-by: Kees Cook keescook@chromium.org Cc: Al Viro viro@zeniv.linux.org.uk Cc: Dan Carpenter dan.carpenter@oracle.com Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- Documentation/sysctl/fs.txt | 36 +++++++++++++++++++++++++ fs/namei.c | 53 ++++++++++++++++++++++++++++++++++--- include/linux/fs.h | 2 ++ kernel/sysctl.c | 18 +++++++++++++ 4 files changed, 106 insertions(+), 3 deletions(-)
--- a/Documentation/sysctl/fs.txt +++ b/Documentation/sysctl/fs.txt @@ -34,7 +34,9 @@ Currently, these files are in /proc/sys/ - overflowgid - pipe-user-pages-hard - pipe-user-pages-soft +- protected_fifos - protected_hardlinks +- protected_regular - protected_symlinks - suid_dumpable - super-max @@ -182,6 +184,24 @@ applied.
==============================================================
+protected_fifos: + +The intent of this protection is to avoid unintentional writes to +an attacker-controlled FIFO, where a program expected to create a regular +file. + +When set to "0", writing to FIFOs is unrestricted. + +When set to "1" don't allow O_CREAT open on FIFOs that we don't own +in world writable sticky directories, unless they are owned by the +owner of the directory. + +When set to "2" it also applies to group writable sticky directories. + +This protection is based on the restrictions in Openwall. + +============================================================== + protected_hardlinks:
A long-standing class of security issues is the hardlink-based @@ -202,6 +222,22 @@ This protection is based on the restrict
==============================================================
+protected_regular: + +This protection is similar to protected_fifos, but it +avoids writes to an attacker-controlled regular file, where a program +expected to create one. + +When set to "0", writing to regular files is unrestricted. + +When set to "1" don't allow O_CREAT open on regular files that we +don't own in world writable sticky directories, unless they are +owned by the owner of the directory. + +When set to "2" it also applies to group writable sticky directories. + +============================================================== + protected_symlinks:
A long-standing class of security issues is the symlink-based --- a/fs/namei.c +++ b/fs/namei.c @@ -723,6 +723,8 @@ static inline void put_link(struct namei
int sysctl_protected_symlinks __read_mostly = 0; int sysctl_protected_hardlinks __read_mostly = 0; +int sysctl_protected_fifos __read_mostly; +int sysctl_protected_regular __read_mostly;
/** * may_follow_link - Check symlink following for unsafe situations @@ -837,6 +839,45 @@ static int may_linkat(struct path *link) return -EPERM; }
+/** + * may_create_in_sticky - Check whether an O_CREAT open in a sticky directory + * should be allowed, or not, on files that already + * exist. + * @dir: the sticky parent directory + * @inode: the inode of the file to open + * + * Block an O_CREAT open of a FIFO (or a regular file) when: + * - sysctl_protected_fifos (or sysctl_protected_regular) is enabled + * - the file already exists + * - we are in a sticky directory + * - we don't own the file + * - the owner of the directory doesn't own the file + * - the directory is world writable + * If the sysctl_protected_fifos (or sysctl_protected_regular) is set to 2 + * the directory doesn't have to be world writable: being group writable will + * be enough. + * + * Returns 0 if the open is allowed, -ve on error. + */ +static int may_create_in_sticky(struct dentry * const dir, + struct inode * const inode) +{ + if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) || + (!sysctl_protected_regular && S_ISREG(inode->i_mode)) || + likely(!(dir->d_inode->i_mode & S_ISVTX)) || + uid_eq(inode->i_uid, dir->d_inode->i_uid) || + uid_eq(current_fsuid(), inode->i_uid)) + return 0; + + if (likely(dir->d_inode->i_mode & 0002) || + (dir->d_inode->i_mode & 0020 && + ((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) || + (sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) { + return -EACCES; + } + return 0; +} + static __always_inline int follow_link(struct path *link, struct nameidata *nd, void **p) { @@ -3057,9 +3098,15 @@ finish_open: return error; } audit_inode(name, nd->path.dentry, 0); - error = -EISDIR; - if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry)) - goto out; + if (open_flag & O_CREAT) { + error = -EISDIR; + if (d_is_dir(nd->path.dentry)) + goto out; + error = may_create_in_sticky(dir, + d_backing_inode(nd->path.dentry)); + if (unlikely(error)) + goto out; + } error = -ENOTDIR; if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) goto out; --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -61,6 +61,8 @@ extern struct inodes_stat_t inodes_stat; extern int leases_enable, lease_break_time; extern int sysctl_protected_symlinks; extern int sysctl_protected_hardlinks; +extern int sysctl_protected_fifos; +extern int sysctl_protected_regular;
struct buffer_head; typedef int (get_block_t)(struct inode *inode, sector_t iblock, --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1653,6 +1653,24 @@ static struct ctl_table fs_table[] = { .extra2 = &one, }, { + .procname = "protected_fifos", + .data = &sysctl_protected_fifos, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &two, + }, + { + .procname = "protected_regular", + .data = &sysctl_protected_regular, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &two, + }, + { .procname = "suid_dumpable", .data = &suid_dumpable, .maxlen = sizeof(int),
On Fri, Apr 24, 2020 at 12:07:15AM +0100, Ben Hutchings wrote:
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
I do. This patch is currently known-buggy, see this thread:
https://www.openwall.com/lists/oss-security/2020/01/28/2
It is (partially) fixed with these newer commits in 5.5 and 5.5.2:
commit d0cb50185ae942b03c4327be322055d622dc79f6 Author: Al Viro viro@zeniv.linux.org.uk Date: Sun Jan 26 09:29:34 2020 -0500
do_last(): fetch directory ->i_mode and ->i_uid before it's too late
may_create_in_sticky() call is done when we already have dropped the reference to dir.
Fixes: 30aba6656f61e (namei: allow restricted O_CREAT of FIFOs and regular files) Signed-off-by: Al Viro viro@zeniv.linux.org.uk
commit d76341d93dedbcf6ed5a08dfc8bce82d3e9a772b Author: Al Viro viro@zeniv.linux.org.uk Date: Sat Feb 1 16:26:45 2020 +0000
vfs: fix do_last() regression
commit 6404674acd596de41fd3ad5f267b4525494a891a upstream.
Brown paperbag time: fetching ->i_uid/->i_mode really should've been done from nd->inode. I even suggested that, but the reason for that has slipped through the cracks and I went for dir->d_inode instead - made for more "obvious" patch.
Analysis:
- at the entry into do_last() and all the way to step_into(): dir (aka nd->path.dentry) is known not to have been freed; so's nd->inode and it's equal to dir->d_inode unless we are already doomed to -ECHILD. inode of the file to get opened is not known.
- after step_into(): inode of the file to get opened is known; dir might be pointing to freed memory/be negative/etc.
- at the call of may_create_in_sticky(): guaranteed to be out of RCU mode; inode of the file to get opened is known and pinned; dir might be garbage.
The last was the reason for the original patch. Except that at the do_last() entry we can be in RCU mode and it is possible that nd->path.dentry->d_inode has already changed under us.
In that case we are going to fail with -ECHILD, but we need to be careful; nd->inode is pointing to valid struct inode and it's the same as nd->path.dentry->d_inode in "won't fail with -ECHILD" case, so we should use that.
Reported-by: "Rantala, Tommi T. (Nokia - FI/Espoo)" tommi.t.rantala@nokia.com Reported-by: syzbot+190005201ced78a74ad6@syzkaller.appspotmail.com Wearing-brown-paperbag: Al Viro viro@zeniv.linux.org.uk Cc: stable@kernel.org Fixes: d0cb50185ae9 ("do_last(): fetch directory ->i_mode and ->i_uid before it's too late") Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
At least inclusion of the above fixes is mandatory for any backports.
Also, I think no one has fixed the logic of may_create_in_sticky() so that it wouldn't unintentionally apply the "protection" when the file is neither a FIFO nor a regular file (something I found and mentioned in the oss-security posting above).
+/**
- may_create_in_sticky - Check whether an O_CREAT open in a sticky directory
should be allowed, or not, on files that already
exist.
- @dir: the sticky parent directory
- @inode: the inode of the file to open
- Block an O_CREAT open of a FIFO (or a regular file) when:
- sysctl_protected_fifos (or sysctl_protected_regular) is enabled
- the file already exists
- we are in a sticky directory
- we don't own the file
- the owner of the directory doesn't own the file
- the directory is world writable
- If the sysctl_protected_fifos (or sysctl_protected_regular) is set to 2
- the directory doesn't have to be world writable: being group writable will
- be enough.
- Returns 0 if the open is allowed, -ve on error.
- */
+static int may_create_in_sticky(struct dentry * const dir,
struct inode * const inode)
+{
- if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) ||
(!sysctl_protected_regular && S_ISREG(inode->i_mode)) ||
likely(!(dir->d_inode->i_mode & S_ISVTX)) ||
uid_eq(inode->i_uid, dir->d_inode->i_uid) ||
uid_eq(current_fsuid(), inode->i_uid))
return 0;
- if (likely(dir->d_inode->i_mode & 0002) ||
(dir->d_inode->i_mode & 0020 &&
((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) ||
(sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) {
return -EACCES;
- }
- return 0;
+}
I think the implementation of may_create_in_sticky() should be rewritten such that it'd directly correspond to the textual description in the comment above. As we've seen, trying to write the code "more optimally" resulted in its logic actually being different from the description.
Meanwhile, I think backporting known-so-buggy code is a bad idea.
Alexander
On Fri, 2020-04-24 at 15:52 +0200, Solar Designer wrote:
On Fri, Apr 24, 2020 at 12:07:15AM +0100, Ben Hutchings wrote:
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
I do. This patch is currently known-buggy, see this thread:
https://www.openwall.com/lists/oss-security/2020/01/28/2
It is (partially) fixed with these newer commits in 5.5 and 5.5.2:
commit d0cb50185ae942b03c4327be322055d622dc79f6 Author: Al Viro viro@zeniv.linux.org.uk Date: Sun Jan 26 09:29:34 2020 -0500
do_last(): fetch directory ->i_mode and ->i_uid before it's too late
may_create_in_sticky() call is done when we already have dropped the reference to dir. Fixes: 30aba6656f61e (namei: allow restricted O_CREAT of FIFOs and regular files) Signed-off-by: Al Viro viro@zeniv.linux.org.uk
commit d76341d93dedbcf6ed5a08dfc8bce82d3e9a772b Author: Al Viro viro@zeniv.linux.org.uk Date: Sat Feb 1 16:26:45 2020 +0000
vfs: fix do_last() regression
commit 6404674acd596de41fd3ad5f267b4525494a891a upstream.
[...]
At least inclusion of the above fixes is mandatory for any backports.
I know, and those are the next 2 patches in the series.
Also, I think no one has fixed the logic of may_create_in_sticky() so that it wouldn't unintentionally apply the "protection" when the file is neither a FIFO nor a regular file (something I found and mentioned in the oss-security posting above).
[...]
I think the implementation of may_create_in_sticky() should be rewritten such that it'd directly correspond to the textual description in the comment above. As we've seen, trying to write the code "more optimally" resulted in its logic actually being different from the description.
Meanwhile, I think backporting known-so-buggy code is a bad idea.
I can see that it's not quite right, but does it matter in practice? Directories and symlinks are handled separately; sockets can't be opened anyway; block and character devices wonn't normally appear in a sticky directory.
Ben.
On Fri, Apr 24, 2020 at 04:13:22PM +0100, Ben Hutchings wrote:
On Fri, 2020-04-24 at 15:52 +0200, Solar Designer wrote:
On Fri, Apr 24, 2020 at 12:07:15AM +0100, Ben Hutchings wrote:
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
I do. This patch is currently known-buggy, see this thread:
https://www.openwall.com/lists/oss-security/2020/01/28/2
It is (partially) fixed with these newer commits in 5.5 and 5.5.2:
commit d0cb50185ae942b03c4327be322055d622dc79f6 Author: Al Viro viro@zeniv.linux.org.uk Date: Sun Jan 26 09:29:34 2020 -0500
do_last(): fetch directory ->i_mode and ->i_uid before it's too late
may_create_in_sticky() call is done when we already have dropped the reference to dir. Fixes: 30aba6656f61e (namei: allow restricted O_CREAT of FIFOs and regular files) Signed-off-by: Al Viro viro@zeniv.linux.org.uk
commit d76341d93dedbcf6ed5a08dfc8bce82d3e9a772b Author: Al Viro viro@zeniv.linux.org.uk Date: Sat Feb 1 16:26:45 2020 +0000
vfs: fix do_last() regression
commit 6404674acd596de41fd3ad5f267b4525494a891a upstream.
[...]
At least inclusion of the above fixes is mandatory for any backports.
I know, and those are the next 2 patches in the series.
Ah, then no objections from me.
Also, I think no one has fixed the logic of may_create_in_sticky() so that it wouldn't unintentionally apply the "protection" when the file is neither a FIFO nor a regular file (something I found and mentioned in the oss-security posting above).
[...]
I think the implementation of may_create_in_sticky() should be rewritten such that it'd directly correspond to the textual description in the comment above. As we've seen, trying to write the code "more optimally" resulted in its logic actually being different from the description.
Meanwhile, I think backporting known-so-buggy code is a bad idea.
I can see that it's not quite right, but does it matter in practice? Directories and symlinks are handled separately; sockets can't be opened anyway; block and character devices wonn't normally appear in a sticky directory.
Clearly, it doesn't matter all that much in practice - I'm not aware of anyone having complained about it causing issues on their system.
I think it primarily mattered as an attack vector on the issue fixed with Al's commits above.
I think we should nevertheless fix the code to match its intent and the comment, but meanwhile this isn't a blocker for the backport.
Alexander
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Al Viro viro@zeniv.linux.org.uk
commit d0cb50185ae942b03c4327be322055d622dc79f6 upstream.
may_create_in_sticky() call is done when we already have dropped the reference to dir.
Fixes: 30aba6656f61e (namei: allow restricted O_CREAT of FIFOs and regular files) Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/namei.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
--- a/fs/namei.c +++ b/fs/namei.c @@ -843,7 +843,8 @@ static int may_linkat(struct path *link) * may_create_in_sticky - Check whether an O_CREAT open in a sticky directory * should be allowed, or not, on files that already * exist. - * @dir: the sticky parent directory + * @dir_mode: mode bits of directory + * @dir_uid: owner of directory * @inode: the inode of the file to open * * Block an O_CREAT open of a FIFO (or a regular file) when: @@ -859,18 +860,18 @@ static int may_linkat(struct path *link) * * Returns 0 if the open is allowed, -ve on error. */ -static int may_create_in_sticky(struct dentry * const dir, +static int may_create_in_sticky(umode_t dir_mode, kuid_t dir_uid, struct inode * const inode) { if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) || (!sysctl_protected_regular && S_ISREG(inode->i_mode)) || - likely(!(dir->d_inode->i_mode & S_ISVTX)) || - uid_eq(inode->i_uid, dir->d_inode->i_uid) || + likely(!(dir_mode & S_ISVTX)) || + uid_eq(inode->i_uid, dir_uid) || uid_eq(current_fsuid(), inode->i_uid)) return 0;
- if (likely(dir->d_inode->i_mode & 0002) || - (dir->d_inode->i_mode & 0020 && + if (likely(dir_mode & 0002) || + (dir_mode & 0020 && ((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) || (sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) { return -EACCES; @@ -2944,6 +2945,8 @@ static int do_last(struct nameidata *nd, int *opened, struct filename *name) { struct dentry *dir = nd->path.dentry; + kuid_t dir_uid = dir->d_inode->i_uid; + umode_t dir_mode = dir->d_inode->i_mode; int open_flag = op->open_flag; bool will_truncate = (open_flag & O_TRUNC) != 0; bool got_write = false; @@ -3102,7 +3105,7 @@ finish_open: error = -EISDIR; if (d_is_dir(nd->path.dentry)) goto out; - error = may_create_in_sticky(dir, + error = may_create_in_sticky(dir_mode, dir_uid, d_backing_inode(nd->path.dentry)); if (unlikely(error)) goto out;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Al Viro viro@zeniv.linux.org.uk
commit 6404674acd596de41fd3ad5f267b4525494a891a upstream.
Brown paperbag time: fetching ->i_uid/->i_mode really should've been done from nd->inode. I even suggested that, but the reason for that has slipped through the cracks and I went for dir->d_inode instead - made for more "obvious" patch.
Analysis:
- at the entry into do_last() and all the way to step_into(): dir (aka nd->path.dentry) is known not to have been freed; so's nd->inode and it's equal to dir->d_inode unless we are already doomed to -ECHILD. inode of the file to get opened is not known.
- after step_into(): inode of the file to get opened is known; dir might be pointing to freed memory/be negative/etc.
- at the call of may_create_in_sticky(): guaranteed to be out of RCU mode; inode of the file to get opened is known and pinned; dir might be garbage.
The last was the reason for the original patch. Except that at the do_last() entry we can be in RCU mode and it is possible that nd->path.dentry->d_inode has already changed under us.
In that case we are going to fail with -ECHILD, but we need to be careful; nd->inode is pointing to valid struct inode and it's the same as nd->path.dentry->d_inode in "won't fail with -ECHILD" case, so we should use that.
Reported-by: "Rantala, Tommi T. (Nokia - FI/Espoo)" tommi.t.rantala@nokia.com Reported-by: syzbot+190005201ced78a74ad6@syzkaller.appspotmail.com Wearing-brown-paperbag: Al Viro viro@zeniv.linux.org.uk Fixes: d0cb50185ae9 ("do_last(): fetch directory ->i_mode and ->i_uid before it's too late") Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/namei.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/fs/namei.c +++ b/fs/namei.c @@ -2945,8 +2945,8 @@ static int do_last(struct nameidata *nd, int *opened, struct filename *name) { struct dentry *dir = nd->path.dentry; - kuid_t dir_uid = dir->d_inode->i_uid; - umode_t dir_mode = dir->d_inode->i_mode; + kuid_t dir_uid = nd->inode->i_uid; + umode_t dir_mode = nd->inode->i_mode; int open_flag = op->open_flag; bool will_truncate = (open_flag & O_TRUNC) != 0; bool got_write = false;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Davidlohr Bueso dave@stgolabs.ne
commit cdea01b2bf98affb7e9c44530108a4a28535eee8 upstream.
This is really about simplifying the double xchg patterns into a single cmpxchg, with the same logic. Other than the immediate cleanup, there are some subtleties this change deals with:
(i) While the load of the old bt is fully ordered wrt everything, ie:
old_bt = xchg(&q->blk_trace, bt); [barrier] if (old_bt) (void) xchg(&q->blk_trace, old_bt); [barrier]
blk_trace could still be changed between the xchg and the old_bt load. Note that this description is merely theoretical and afaict very small, but doing everything in a single context with cmpxchg closes this potential race.
(ii) Ordering guarantees are obviously kept with cmpxchg.
(iii) Gets rid of the hacky-by-nature (void)xchg pattern.
Signed-off-by: Davidlohr Bueso dbueso@suse.de eviewed-by: Jeff Moyer jmoyer@redhat.com Signed-off-by: Jens Axboe axboe@fb.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- kernel/trace/blktrace.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-)
--- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -448,7 +448,7 @@ int do_blk_trace_setup(struct request_qu struct block_device *bdev, struct blk_user_trace_setup *buts) { - struct blk_trace *old_bt, *bt = NULL; + struct blk_trace *bt = NULL; struct dentry *dir = NULL; int ret, i;
@@ -532,11 +532,8 @@ int do_blk_trace_setup(struct request_qu bt->trace_state = Blktrace_setup;
ret = -EBUSY; - old_bt = xchg(&q->blk_trace, bt); - if (old_bt) { - (void) xchg(&q->blk_trace, old_bt); + if (cmpxchg(&q->blk_trace, NULL, bt)) goto err; - }
if (atomic_inc_return(&blk_probes_ref) == 1) blk_register_tracepoints(); @@ -1550,7 +1547,7 @@ static int blk_trace_remove_queue(struct static int blk_trace_setup_queue(struct request_queue *q, struct block_device *bdev) { - struct blk_trace *old_bt, *bt = NULL; + struct blk_trace *bt = NULL; int ret = -ENOMEM;
bt = kzalloc(sizeof(*bt), GFP_KERNEL); @@ -1566,12 +1563,9 @@ static int blk_trace_setup_queue(struct
blk_trace_setup_lba(bt, bdev);
- old_bt = xchg(&q->blk_trace, bt); - if (old_bt != NULL) { - (void)xchg(&q->blk_trace, old_bt); - ret = -EBUSY; + ret = -EBUSY; + if (cmpxchg(&q->blk_trace, NULL, bt)) goto free_bt; - }
if (atomic_inc_return(&blk_probes_ref) == 1) blk_register_tracepoints();
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jan Kara jack@suse.cz
commit c780e86dd48ef6467a1146cf7d0fe1e05a635039 upstream.
KASAN is reporting that __blk_add_trace() has a use-after-free issue when accessing q->blk_trace. Indeed the switching of block tracing (and thus eventual freeing of q->blk_trace) is completely unsynchronized with the currently running tracing and thus it can happen that the blk_trace structure is being freed just while __blk_add_trace() works on it. Protect accesses to q->blk_trace by RCU during tracing and make sure we wait for the end of RCU grace period when shutting down tracing. Luckily that is rare enough event that we can afford that. Note that postponing the freeing of blk_trace to an RCU callback should better be avoided as it could have unexpected user visible side-effects as debugfs files would be still existing for a short while block tracing has been shut down.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=205711 Reviewed-by: Chaitanya Kulkarni chaitanya.kulkarni@wdc.com Reviewed-by: Ming Lei ming.lei@redhat.com Tested-by: Ming Lei ming.lei@redhat.com Reviewed-by: Bart Van Assche bvanassche@acm.org Reported-by: Tristan Madani tristmd@gmail.com Signed-off-by: Jan Kara jack@suse.cz Signed-off-by: Jens Axboe axboe@kernel.dk [bwh: Backported to 3.16: - Drop changes in blk_trace_note_message_enabled(), blk_trace_bio_get_cgid() - Adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -447,7 +447,7 @@ struct request_queue { unsigned int sg_reserved_size; int node; #ifdef CONFIG_BLK_DEV_IO_TRACE - struct blk_trace *blk_trace; + struct blk_trace __rcu *blk_trace; struct mutex blk_trace_mutex; #endif /* --- a/include/linux/blktrace_api.h +++ b/include/linux/blktrace_api.h @@ -51,9 +51,13 @@ void __trace_note_message(struct blk_tra **/ #define blk_add_trace_msg(q, fmt, ...) \ do { \ - struct blk_trace *bt = (q)->blk_trace; \ + struct blk_trace *bt; \ + \ + rcu_read_lock(); \ + bt = rcu_dereference((q)->blk_trace); \ if (unlikely(bt)) \ __trace_note_message(bt, fmt, ##__VA_ARGS__); \ + rcu_read_unlock(); \ } while (0) #define BLK_TN_MAX_MSG 128
--- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -302,6 +302,7 @@ static void blk_trace_free(struct blk_tr
static void blk_trace_cleanup(struct blk_trace *bt) { + synchronize_rcu(); blk_trace_free(bt); if (atomic_dec_and_test(&blk_probes_ref)) blk_unregister_tracepoints(); @@ -616,8 +617,10 @@ static int compat_blk_trace_setup(struct static int __blk_trace_startstop(struct request_queue *q, int start) { int ret; - struct blk_trace *bt = q->blk_trace; + struct blk_trace *bt;
+ bt = rcu_dereference_protected(q->blk_trace, + lockdep_is_held(&q->blk_trace_mutex)); if (bt == NULL) return -EINVAL;
@@ -726,8 +729,8 @@ int blk_trace_ioctl(struct block_device void blk_trace_shutdown(struct request_queue *q) { mutex_lock(&q->blk_trace_mutex); - - if (q->blk_trace) { + if (rcu_dereference_protected(q->blk_trace, + lockdep_is_held(&q->blk_trace_mutex))) { __blk_trace_startstop(q, 0); __blk_trace_remove(q); } @@ -753,10 +756,14 @@ void blk_trace_shutdown(struct request_q static void blk_add_trace_rq(struct request_queue *q, struct request *rq, unsigned int nr_bytes, u32 what) { - struct blk_trace *bt = q->blk_trace; + struct blk_trace *bt;
- if (likely(!bt)) + rcu_read_lock(); + bt = rcu_dereference(q->blk_trace); + if (likely(!bt)) { + rcu_read_unlock(); return; + }
if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { what |= BLK_TC_ACT(BLK_TC_PC); @@ -767,6 +774,7 @@ static void blk_add_trace_rq(struct requ __blk_add_trace(bt, blk_rq_pos(rq), nr_bytes, rq->cmd_flags, what, rq->errors, 0, NULL); } + rcu_read_unlock(); }
static void blk_add_trace_rq_abort(void *ignore, @@ -816,16 +824,21 @@ static void blk_add_trace_rq_complete(vo static void blk_add_trace_bio(struct request_queue *q, struct bio *bio, u32 what, int error) { - struct blk_trace *bt = q->blk_trace; + struct blk_trace *bt;
- if (likely(!bt)) + rcu_read_lock(); + bt = rcu_dereference(q->blk_trace); + if (likely(!bt)) { + rcu_read_unlock(); return; + }
if (!error && !bio_flagged(bio, BIO_UPTODATE)) error = EIO;
__blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, bio->bi_rw, what, error, 0, NULL); + rcu_read_unlock(); }
static void blk_add_trace_bio_bounce(void *ignore, @@ -870,10 +883,13 @@ static void blk_add_trace_getrq(void *ig if (bio) blk_add_trace_bio(q, bio, BLK_TA_GETRQ, 0); else { - struct blk_trace *bt = q->blk_trace; + struct blk_trace *bt;
+ rcu_read_lock(); + bt = rcu_dereference(q->blk_trace); if (bt) __blk_add_trace(bt, 0, 0, rw, BLK_TA_GETRQ, 0, 0, NULL); + rcu_read_unlock(); } }
@@ -885,27 +901,35 @@ static void blk_add_trace_sleeprq(void * if (bio) blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ, 0); else { - struct blk_trace *bt = q->blk_trace; + struct blk_trace *bt;
+ rcu_read_lock(); + bt = rcu_dereference(q->blk_trace); if (bt) __blk_add_trace(bt, 0, 0, rw, BLK_TA_SLEEPRQ, 0, 0, NULL); + rcu_read_unlock(); } }
static void blk_add_trace_plug(void *ignore, struct request_queue *q) { - struct blk_trace *bt = q->blk_trace; + struct blk_trace *bt;
+ rcu_read_lock(); + bt = rcu_dereference(q->blk_trace); if (bt) __blk_add_trace(bt, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL); + rcu_read_unlock(); }
static void blk_add_trace_unplug(void *ignore, struct request_queue *q, unsigned int depth, bool explicit) { - struct blk_trace *bt = q->blk_trace; + struct blk_trace *bt;
+ rcu_read_lock(); + bt = rcu_dereference(q->blk_trace); if (bt) { __be64 rpdu = cpu_to_be64(depth); u32 what; @@ -917,14 +941,17 @@ static void blk_add_trace_unplug(void *i
__blk_add_trace(bt, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu); } + rcu_read_unlock(); }
static void blk_add_trace_split(void *ignore, struct request_queue *q, struct bio *bio, unsigned int pdu) { - struct blk_trace *bt = q->blk_trace; + struct blk_trace *bt;
+ rcu_read_lock(); + bt = rcu_dereference(q->blk_trace); if (bt) { __be64 rpdu = cpu_to_be64(pdu);
@@ -933,6 +960,7 @@ static void blk_add_trace_split(void *ig !bio_flagged(bio, BIO_UPTODATE), sizeof(rpdu), &rpdu); } + rcu_read_unlock(); }
/** @@ -952,11 +980,15 @@ static void blk_add_trace_bio_remap(void struct request_queue *q, struct bio *bio, dev_t dev, sector_t from) { - struct blk_trace *bt = q->blk_trace; + struct blk_trace *bt; struct blk_io_trace_remap r;
- if (likely(!bt)) + rcu_read_lock(); + bt = rcu_dereference(q->blk_trace); + if (likely(!bt)) { + rcu_read_unlock(); return; + }
r.device_from = cpu_to_be32(dev); r.device_to = cpu_to_be32(bio->bi_bdev->bd_dev); @@ -965,6 +997,7 @@ static void blk_add_trace_bio_remap(void __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, bio->bi_rw, BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r); + rcu_read_unlock(); }
/** @@ -985,11 +1018,15 @@ static void blk_add_trace_rq_remap(void struct request *rq, dev_t dev, sector_t from) { - struct blk_trace *bt = q->blk_trace; + struct blk_trace *bt; struct blk_io_trace_remap r;
- if (likely(!bt)) + rcu_read_lock(); + bt = rcu_dereference(q->blk_trace); + if (likely(!bt)) { + rcu_read_unlock(); return; + }
r.device_from = cpu_to_be32(dev); r.device_to = cpu_to_be32(disk_devt(rq->rq_disk)); @@ -998,6 +1035,7 @@ static void blk_add_trace_rq_remap(void __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), rq_data_dir(rq), BLK_TA_REMAP, !!rq->errors, sizeof(r), &r); + rcu_read_unlock(); }
/** @@ -1015,10 +1053,14 @@ void blk_add_driver_data(struct request_ struct request *rq, void *data, size_t len) { - struct blk_trace *bt = q->blk_trace; + struct blk_trace *bt;
- if (likely(!bt)) + rcu_read_lock(); + bt = rcu_dereference(q->blk_trace); + if (likely(!bt)) { + rcu_read_unlock(); return; + }
if (rq->cmd_type == REQ_TYPE_BLOCK_PC) __blk_add_trace(bt, 0, blk_rq_bytes(rq), 0, @@ -1026,6 +1068,7 @@ void blk_add_driver_data(struct request_ else __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq), 0, BLK_TA_DRV_DATA, rq->errors, len, data); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(blk_add_driver_data);
@@ -1537,6 +1580,7 @@ static int blk_trace_remove_queue(struct spin_lock_irq(&running_trace_lock); list_del(&bt->running_list); spin_unlock_irq(&running_trace_lock); + synchronize_rcu(); blk_trace_free(bt); return 0; } @@ -1698,6 +1742,7 @@ static ssize_t sysfs_blk_trace_attr_show struct hd_struct *p = dev_to_part(dev); struct request_queue *q; struct block_device *bdev; + struct blk_trace *bt; ssize_t ret = -ENXIO;
bdev = bdget(part_devt(p)); @@ -1710,21 +1755,23 @@ static ssize_t sysfs_blk_trace_attr_show
mutex_lock(&q->blk_trace_mutex);
+ bt = rcu_dereference_protected(q->blk_trace, + lockdep_is_held(&q->blk_trace_mutex)); if (attr == &dev_attr_enable) { - ret = sprintf(buf, "%u\n", !!q->blk_trace); + ret = sprintf(buf, "%u\n", !!bt); goto out_unlock_bdev; }
- if (q->blk_trace == NULL) + if (bt == NULL) ret = sprintf(buf, "disabled\n"); else if (attr == &dev_attr_act_mask) - ret = blk_trace_mask2str(buf, q->blk_trace->act_mask); + ret = blk_trace_mask2str(buf, bt->act_mask); else if (attr == &dev_attr_pid) - ret = sprintf(buf, "%u\n", q->blk_trace->pid); + ret = sprintf(buf, "%u\n", bt->pid); else if (attr == &dev_attr_start_lba) - ret = sprintf(buf, "%llu\n", q->blk_trace->start_lba); + ret = sprintf(buf, "%llu\n", bt->start_lba); else if (attr == &dev_attr_end_lba) - ret = sprintf(buf, "%llu\n", q->blk_trace->end_lba); + ret = sprintf(buf, "%llu\n", bt->end_lba);
out_unlock_bdev: mutex_unlock(&q->blk_trace_mutex); @@ -1741,6 +1788,7 @@ static ssize_t sysfs_blk_trace_attr_stor struct block_device *bdev; struct request_queue *q; struct hd_struct *p; + struct blk_trace *bt; u64 value; ssize_t ret = -EINVAL;
@@ -1771,8 +1819,10 @@ static ssize_t sysfs_blk_trace_attr_stor
mutex_lock(&q->blk_trace_mutex);
+ bt = rcu_dereference_protected(q->blk_trace, + lockdep_is_held(&q->blk_trace_mutex)); if (attr == &dev_attr_enable) { - if (!!value == !!q->blk_trace) { + if (!!value == !!bt) { ret = 0; goto out_unlock_bdev; } @@ -1784,18 +1834,18 @@ static ssize_t sysfs_blk_trace_attr_stor }
ret = 0; - if (q->blk_trace == NULL) + if (bt == NULL) ret = blk_trace_setup_queue(q, bdev);
if (ret == 0) { if (attr == &dev_attr_act_mask) - q->blk_trace->act_mask = value; + bt->act_mask = value; else if (attr == &dev_attr_pid) - q->blk_trace->pid = value; + bt->pid = value; else if (attr == &dev_attr_start_lba) - q->blk_trace->start_lba = value; + bt->start_lba = value; else if (attr == &dev_attr_end_lba) - q->blk_trace->end_lba = value; + bt->end_lba = value; }
out_unlock_bdev:
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Cengiz Can cengiz@kernel.wtf
commit 153031a301bb07194e9c37466cfce8eacb977621 upstream.
There was a recent change in blktrace.c that added a RCU protection to `q->blk_trace` in order to fix a use-after-free issue during access.
However the change missed an edge case that can lead to dereferencing of `bt` pointer even when it's NULL:
Coverity static analyzer marked this as a FORWARD_NULL issue with CID 1460458.
``` /kernel/trace/blktrace.c: 1904 in sysfs_blk_trace_attr_store() 1898 ret = 0; 1899 if (bt == NULL) 1900 ret = blk_trace_setup_queue(q, bdev); 1901 1902 if (ret == 0) { 1903 if (attr == &dev_attr_act_mask)
CID 1460458: Null pointer dereferences (FORWARD_NULL) Dereferencing null pointer "bt".
1904 bt->act_mask = value; 1905 else if (attr == &dev_attr_pid) 1906 bt->pid = value; 1907 else if (attr == &dev_attr_start_lba) 1908 bt->start_lba = value; 1909 else if (attr == &dev_attr_end_lba) ```
Added a reassignment with RCU annotation to fix the issue.
Fixes: c780e86dd48 ("blktrace: Protect q->blk_trace with RCU") Reviewed-by: Ming Lei ming.lei@redhat.com Reviewed-by: Bob Liu bob.liu@oracle.com Reviewed-by: Steven Rostedt (VMware) rostedt@goodmis.org Signed-off-by: Cengiz Can cengiz@kernel.wtf Signed-off-by: Jens Axboe axboe@kernel.dk Signed-off-by: Ben Hutchings ben@decadent.org.uk --- kernel/trace/blktrace.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
--- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -1834,8 +1834,11 @@ static ssize_t sysfs_blk_trace_attr_stor }
ret = 0; - if (bt == NULL) + if (bt == NULL) { ret = blk_trace_setup_queue(q, bdev); + bt = rcu_dereference_protected(q->blk_trace, + lockdep_is_held(&q->blk_trace_mutex)); + }
if (ret == 0) { if (attr == &dev_attr_act_mask)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov dmitry.torokhov@gmail.com
commit cb222aed03d798fc074be55e59d9a112338ee784 upstream.
If we happen to have a garbage in input device's keycode table with values too big we'll end up doing clear_bit() with offset way outside of our bitmaps, damaging other objects within an input device or even outside of it. Let's add sanity checks to the returned old keycodes.
Reported-by: syzbot+c769968809f9359b07aa@syzkaller.appspotmail.com Reported-by: syzbot+76f3a30e88d256644c78@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/20191207212757.GA245964@dtor-ws Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/input/input.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
--- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -841,16 +841,18 @@ static int input_default_setkeycode(stru } }
- __clear_bit(*old_keycode, dev->keybit); - __set_bit(ke->keycode, dev->keybit); - - for (i = 0; i < dev->keycodemax; i++) { - if (input_fetch_keycode(dev, i) == *old_keycode) { - __set_bit(*old_keycode, dev->keybit); - break; /* Setting the bit twice is useless, so break */ + if (*old_keycode <= KEY_MAX) { + __clear_bit(*old_keycode, dev->keybit); + for (i = 0; i < dev->keycodemax; i++) { + if (input_fetch_keycode(dev, i) == *old_keycode) { + __set_bit(*old_keycode, dev->keybit); + /* Setting the bit twice is useless, so break */ + break; + } } }
+ __set_bit(ke->keycode, dev->keybit); return 0; }
@@ -906,9 +908,13 @@ int input_set_keycode(struct input_dev * * Simulate keyup event if keycode is not present * in the keymap anymore */ - if (test_bit(EV_KEY, dev->evbit) && - !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && - __test_and_clear_bit(old_keycode, dev->key)) { + if (old_keycode > KEY_MAX) { + dev_warn(dev->dev.parent ?: &dev->dev, + "%s: got too big old keycode %#x\n", + __func__, old_keycode); + } else if (test_bit(EV_KEY, dev->evbit) && + !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && + __test_and_clear_bit(old_keycode, dev->key)) { struct input_value vals[] = { { EV_KEY, old_keycode, 0 }, input_value_sync
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Suren Baghdasaryan surenb@google.com
commit 6d67b0290b4b84c477e6a2fc6e005e174d3c7786 upstream.
When ashmem file is mmapped, the resulting vma->vm_file points to the backing shmem file with the generic fops that do not check ashmem permissions like fops of ashmem do. If an mremap is done on the ashmem region, then the permission checks will be skipped. Fix that by disallowing mapping operation on the backing shmem file.
Reported-by: Jann Horn jannh@google.com Signed-off-by: Suren Baghdasaryan surenb@google.com Signed-off-by: Todd Kjos tkjos@google.com Reviewed-by: Joel Fernandes (Google) joel@joelfernandes.org Link: https://lore.kernel.org/r/20200127235616.48920-1-tkjos@google.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/staging/android/ashmem.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
--- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -351,8 +351,23 @@ static inline vm_flags_t calc_vm_may_fla _calc_vm_trans(prot, PROT_EXEC, VM_MAYEXEC); }
+static int ashmem_vmfile_mmap(struct file *file, struct vm_area_struct *vma) +{ + /* do not allow to mmap ashmem backing shmem file directly */ + return -EPERM; +} + +static unsigned long +ashmem_vmfile_get_unmapped_area(struct file *file, unsigned long addr, + unsigned long len, unsigned long pgoff, + unsigned long flags) +{ + return current->mm->get_unmapped_area(file, addr, len, pgoff, flags); +} + static int ashmem_mmap(struct file *file, struct vm_area_struct *vma) { + static struct file_operations vmfile_fops; struct ashmem_area *asma = file->private_data; int ret = 0;
@@ -386,6 +401,19 @@ static int ashmem_mmap(struct file *file goto out; } asma->file = vmfile; + /* + * override mmap operation of the vmfile so that it can't be + * remapped which would lead to creation of a new vma with no + * asma permission checks. Have to override get_unmapped_area + * as well to prevent VM_BUG_ON check for f_ops modification. + */ + if (!vmfile_fops.mmap) { + vmfile_fops = *vmfile->f_op; + vmfile_fops.mmap = ashmem_vmfile_mmap; + vmfile_fops.get_unmapped_area = + ashmem_vmfile_get_unmapped_area; + } + vmfile->f_op = &vmfile_fops; } get_file(asma->file);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Sabrina Dubroca sd@queasysnail.net
commit 6c8991f41546c3c472503dff1ea9daaddf9331c2 upstream.
ipv6_stub uses the ip6_dst_lookup function to allow other modules to perform IPv6 lookups. However, this function skips the XFRM layer entirely.
All users of ipv6_stub->ip6_dst_lookup use ip_route_output_flow (via the ip_route_output_key and ip_route_output helpers) for their IPv4 lookups, which calls xfrm_lookup_route(). This patch fixes this inconsistent behavior by switching the stub to ip6_dst_lookup_flow, which also calls xfrm_lookup_route().
This requires some changes in all the callers, as these two functions take different arguments and have different return types.
Fixes: 5f81bd2e5d80 ("ipv6: export a stub for IPv6 symbols used by vxlan") Reported-by: Xiumei Mu xmu@redhat.com Signed-off-by: Sabrina Dubroca sd@queasysnail.net Signed-off-by: David S. Miller davem@davemloft.net [bwh: Backported to 3.16: - Only vxlan uses this operation - Neither ip6_dst_lookup() nor ip6_dst_lookup_flow() takes a struct net pointer argument here - Adjust filename, context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1929,7 +1929,8 @@ static void vxlan_xmit_one(struct sk_buf fl6.saddr = vxlan->saddr.sin6.sin6_addr; fl6.flowi6_proto = IPPROTO_UDP;
- if (ipv6_stub->ipv6_dst_lookup(sk, &ndst, &fl6)) { + ndst = ipv6_stub->ipv6_dst_lookup_flow(sk, &fl6, NULL); + if (unlikely(IS_ERR(ndst))) { netdev_dbg(dev, "no route to %pI6\n", &dst->sin6.sin6_addr); dev->stats.tx_carrier_errors++; --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -156,8 +156,9 @@ struct ipv6_stub { const struct in6_addr *addr); int (*ipv6_sock_mc_drop)(struct sock *sk, int ifindex, const struct in6_addr *addr); - int (*ipv6_dst_lookup)(struct sock *sk, struct dst_entry **dst, - struct flowi6 *fl6); + struct dst_entry *(*ipv6_dst_lookup_flow)(struct sock *sk, + struct flowi6 *fl6, + const struct in6_addr *final_dst); void (*udpv6_encap_enable)(void); void (*ndisc_send_na)(struct net_device *dev, struct neighbour *neigh, const struct in6_addr *daddr, --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -820,7 +820,7 @@ static struct pernet_operations inet6_ne static const struct ipv6_stub ipv6_stub_impl = { .ipv6_sock_mc_join = ipv6_sock_mc_join, .ipv6_sock_mc_drop = ipv6_sock_mc_drop, - .ipv6_dst_lookup = ip6_dst_lookup, + .ipv6_dst_lookup_flow = ip6_dst_lookup_flow, .udpv6_encap_enable = udpv6_encap_enable, .ndisc_send_na = ndisc_send_na, .nd_tbl = &nd_tbl,
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Bonzini pbonzini@redhat.com
commit 07721feee46b4b248402133228235318199b05ec upstream.
vmx_check_intercept is not yet fully implemented. To avoid emulating instructions disallowed by the L1 hypervisor, refuse to emulate instructions by default.
[Made commit, added commit msg - Oliver] Signed-off-by: Oliver Upton oupton@google.com Signed-off-by: Paolo Bonzini pbonzini@redhat.com [bwh: Backported to 3.16: adjust filename, context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- arch/x86/kvm/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -8938,7 +8938,7 @@ static int vmx_check_intercept(struct kv struct x86_instruction_info *info, enum x86_intercept_stage stage) { - return X86EMUL_CONTINUE; + return X86EMUL_UNHANDLEABLE; }
static struct kvm_x86_ops vmx_x86_ops = {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Xiaoxu zhangxiaoxu5@huawei.com
commit 513dc792d6060d5ef572e43852683097a8420f56 upstream.
When syzkaller tests, there is a UAF: BUG: KASan: use after free in vgacon_invert_region+0x9d/0x110 at addr ffff880000100000 Read of size 2 by task syz-executor.1/16489 page:ffffea0000004000 count:0 mapcount:-127 mapping: (null) index:0x0 page flags: 0xfffff00000000() page dumped because: kasan: bad access detected CPU: 1 PID: 16489 Comm: syz-executor.1 Not tainted Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.9.3-0-ge2fc41e-prebuilt.qemu-project.org 04/01/2014 Call Trace: [<ffffffffb119f309>] dump_stack+0x1e/0x20 [<ffffffffb04af957>] kasan_report+0x577/0x950 [<ffffffffb04ae652>] __asan_load2+0x62/0x80 [<ffffffffb090f26d>] vgacon_invert_region+0x9d/0x110 [<ffffffffb0a39d95>] invert_screen+0xe5/0x470 [<ffffffffb0a21dcb>] set_selection+0x44b/0x12f0 [<ffffffffb0a3bfae>] tioclinux+0xee/0x490 [<ffffffffb0a1d114>] vt_ioctl+0xff4/0x2670 [<ffffffffb0a0089a>] tty_ioctl+0x46a/0x1a10 [<ffffffffb052db3d>] do_vfs_ioctl+0x5bd/0xc40 [<ffffffffb052e2f2>] SyS_ioctl+0x132/0x170 [<ffffffffb11c9b1b>] system_call_fastpath+0x22/0x27 Memory state around the buggy address: ffff8800000fff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffff8800000fff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ffff880000100000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
It can be reproduce in the linux mainline by the program: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <linux/vt.h>
struct tiocl_selection { unsigned short xs; /* X start */ unsigned short ys; /* Y start */ unsigned short xe; /* X end */ unsigned short ye; /* Y end */ unsigned short sel_mode; /* selection mode */ };
#define TIOCL_SETSEL 2 struct tiocl { unsigned char type; unsigned char pad; struct tiocl_selection sel; };
int main() { int fd = 0; const char *dev = "/dev/char/4:1";
struct vt_consize v = {0}; struct tiocl tioc = {0};
fd = open(dev, O_RDWR, 0);
v.v_rows = 3346; ioctl(fd, VT_RESIZEX, &v);
tioc.type = TIOCL_SETSEL; ioctl(fd, TIOCLINUX, &tioc);
return 0; }
When resize the screen, update the 'vc->vc_size_row' to the new_row_size, but when 'set_origin' in 'vgacon_set_origin', vgacon use 'vga_vram_base' for 'vc_origin' and 'vc_visible_origin', not 'vc_screenbuf'. It maybe smaller than 'vc_screenbuf'. When TIOCLINUX, use the new_row_size to calc the offset, it maybe larger than the vga_vram_size in vgacon driver, then bad access. Also, if set an larger screenbuf firstly, then set an more larger screenbuf, when copy old_origin to new_origin, a bad access may happen.
So, If the screen size larger than vga_vram, resize screen should be failed. This alse fix CVE-2020-8649 and CVE-2020-8647.
Linus pointed out that overflow checking seems absent. We're saved by the existing bounds checks in vc_do_resize() with rather strict limits:
if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW) return -EINVAL;
Fixes: 0aec4867dca14 ("[PATCH] SVGATextMode fix") Reference: CVE-2020-8647 and CVE-2020-8649 Reported-by: Hulk Robot hulkci@huawei.com Signed-off-by: Zhang Xiaoxu zhangxiaoxu5@huawei.com [danvet: augment commit message to point out overflow safety] Signed-off-by: Daniel Vetter daniel.vetter@ffwll.ch Link: https://patchwork.freedesktop.org/patch/msgid/20200304022429.37738-1-zhangxi... Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/video/console/vgacon.c | 3 +++ 1 file changed, 3 insertions(+)
--- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1312,6 +1312,9 @@ static int vgacon_font_get(struct vc_dat static int vgacon_resize(struct vc_data *c, unsigned int width, unsigned int height, unsigned int user) { + if ((width << 1) * height > vga_vram_size) + return -EINVAL; + if (width % 2 || width > screen_info.orig_video_cols || height > (screen_info.orig_video_lines * vga_default_font_height)/ c->vc_font.height)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Peter Hurley peter@hurleysoftware.com
commit 61e86cc90af49cecef9c54ccea1f572fbcb695ac upstream.
Pasting text with gpm on a VC produced warning [1]. Reset task state to TASK_RUNNING in the paste_selection() loop, if the loop did not sleep.
[1] WARNING: CPU: 6 PID: 1960 at /home/peter/src/kernels/mainline/kernel/sched/core.c:7286 __might_sleep+0x7f/0x90() do not call blocking ops when !TASK_RUNNING; state=1 set at [<ffffffff8151805e>] paste_selection+0x9e/0x1a0 Modules linked in: btrfs xor raid6_pq ufs qnx4 hfsplus hfs minix ntfs msdos jfs xfs libcrc32c ..... CPU: 6 PID: 1960 Comm: gpm Not tainted 4.1.0-rc7+tty-xeon+debug #rc7+tty Hardware name: Dell Inc. Precision WorkStation T5400 /0RW203, BIOS A11 04/30/2012 ffffffff81c9c0a0 ffff8802b0fd3ac8 ffffffff8185778a 0000000000000001 ffff8802b0fd3b18 ffff8802b0fd3b08 ffffffff8108039a ffffffff82ae8510 ffffffff81c9ce00 0000000000000015 0000000000000000 0000000000000000 Call Trace: [<ffffffff8185778a>] dump_stack+0x4f/0x7b [<ffffffff8108039a>] warn_slowpath_common+0x8a/0xc0 [<ffffffff81080416>] warn_slowpath_fmt+0x46/0x50 [<ffffffff810ddced>] ? __lock_acquire+0xe2d/0x13a0 [<ffffffff8151805e>] ? paste_selection+0x9e/0x1a0 [<ffffffff8151805e>] ? paste_selection+0x9e/0x1a0 [<ffffffff810ad4ff>] __might_sleep+0x7f/0x90 [<ffffffff8185f76a>] down_read+0x2a/0xa0 [<ffffffff810bb1d8>] ? sched_clock_cpu+0xb8/0xe0 [<ffffffff8150d1dc>] n_tty_receive_buf_common+0x4c/0xba0 [<ffffffff810dc875>] ? mark_held_locks+0x75/0xa0 [<ffffffff81861c95>] ? _raw_spin_unlock_irqrestore+0x65/0x80 [<ffffffff810b49a1>] ? get_parent_ip+0x11/0x50 [<ffffffff8150dd44>] n_tty_receive_buf2+0x14/0x20 [<ffffffff81518117>] paste_selection+0x157/0x1a0 [<ffffffff810b77b0>] ? wake_up_state+0x20/0x20 [<ffffffff815203f8>] tioclinux+0xb8/0x2c0 [<ffffffff81515bfe>] vt_ioctl+0xaee/0x11a0 [<ffffffff810baf75>] ? sched_clock_local+0x25/0x90 [<ffffffff810bbe11>] ? vtime_account_user+0x91/0xa0 [<ffffffff8150810c>] tty_ioctl+0x20c/0xe20 [<ffffffff810bbe11>] ? vtime_account_user+0x91/0xa0 [<ffffffff810b49a1>] ? get_parent_ip+0x11/0x50 [<ffffffff810b4a69>] ? preempt_count_sub+0x49/0x50 [<ffffffff811ab71c>] ? context_tracking_exit+0x5c/0x290 [<ffffffff811ab71c>] ? context_tracking_exit+0x5c/0x290 [<ffffffff81248b98>] do_vfs_ioctl+0x318/0x570 [<ffffffff810dca8d>] ? trace_hardirqs_on+0xd/0x10 [<ffffffff810dc9b5>] ? trace_hardirqs_on_caller+0x115/0x1e0 [<ffffffff81254acc>] ? __fget_light+0x6c/0xa0 [<ffffffff81248e71>] SyS_ioctl+0x81/0xa0 [<ffffffff81862832>] system_call_fastpath+0x16/0x7a
Signed-off-by: Peter Hurley peter@hurleysoftware.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/tty/vt/selection.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -356,6 +356,7 @@ int paste_selection(struct tty_struct *t schedule(); continue; } + __set_current_state(TASK_RUNNING); count = sel_buffer_lth - pasted; count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL, count);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Slaby jslaby@suse.cz
commit 687bff0cd08f790d540cfb7b2349f0d876cdddec upstream.
When pasting a selection to a vt, the task is set as INTERRUPTIBLE while waiting for a tty to unthrottle. But signals are not handled at all. Normally, this is not a problem as tty_ldisc_receive_buf receives all the goods and a user has no reason to interrupt the task.
There are two scenarios where this matters: 1) when the tty is throttled and a signal is sent to the process, it spins on a CPU until the tty is unthrottled. schedule() does not really echedule, but returns immediately, of course. 2) when the sel_buffer becomes invalid, KASAN prevents any reads from it and the loop simply does not proceed and spins forever (causing the tty to throttle, but the code never sleeps, the same as above). This sometimes happens as there is a race in the sel_buffer handling code.
So add signal handling to this ioctl (TIOCL_PASTESEL) and return -EINTR in case a signal is pending.
Signed-off-by: Jiri Slaby jslaby@suse.cz Link: https://lore.kernel.org/r/20200210081131.23572-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: - No need to include <linux/sched/signal.h> - Adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -341,6 +341,7 @@ int paste_selection(struct tty_struct *t unsigned int count; struct tty_ldisc *ld; DECLARE_WAITQUEUE(wait, current); + int ret = 0;
console_lock(); poke_blanked_console(); @@ -352,6 +353,10 @@ int paste_selection(struct tty_struct *t add_wait_queue(&vc->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); + if (signal_pending(current)) { + ret = -EINTR; + break; + } if (test_bit(TTY_THROTTLED, &tty->flags)) { schedule(); continue; @@ -367,5 +372,5 @@ int paste_selection(struct tty_struct *t
tty_buffer_unlock_exclusive(&vc->port); tty_ldisc_deref(ld); - return 0; + return ret; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Slaby jslaby@suse.cz
commit 07e6124a1a46b4b5a9b3cacc0c306b50da87abf5 upstream.
syzkaller reported this UAF: BUG: KASAN: use-after-free in n_tty_receive_buf_common+0x2481/0x2940 drivers/tty/n_tty.c:1741 Read of size 1 at addr ffff8880089e40e9 by task syz-executor.1/13184
CPU: 0 PID: 13184 Comm: syz-executor.1 Not tainted 5.4.7 #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 Call Trace: ... kasan_report+0xe/0x20 mm/kasan/common.c:634 n_tty_receive_buf_common+0x2481/0x2940 drivers/tty/n_tty.c:1741 tty_ldisc_receive_buf+0xac/0x190 drivers/tty/tty_buffer.c:461 paste_selection+0x297/0x400 drivers/tty/vt/selection.c:372 tioclinux+0x20d/0x4e0 drivers/tty/vt/vt.c:3044 vt_ioctl+0x1bcf/0x28d0 drivers/tty/vt/vt_ioctl.c:364 tty_ioctl+0x525/0x15a0 drivers/tty/tty_io.c:2657 vfs_ioctl fs/ioctl.c:47 [inline]
It is due to a race between parallel paste_selection (TIOCL_PASTESEL) and set_selection_user (TIOCL_SETSEL) invocations. One uses sel_buffer, while the other frees it and reallocates a new one for another selection. Add a mutex to close this race.
The mutex takes care properly of sel_buffer and sel_buffer_lth only. The other selection global variables (like sel_start, sel_end, and sel_cons) are protected only in set_selection_user. The other functions need quite some more work to close the races of the variables there. This is going to happen later.
This likely fixes (I am unsure as there is no reproducer provided) bug 206361 too. It was marked as CVE-2020-8648.
Signed-off-by: Jiri Slaby jslaby@suse.cz Reported-by: syzbot+59997e8d5cbdc486e6f6@syzkaller.appspotmail.com References: https://bugzilla.kernel.org/show_bug.cgi?id=206361 Link: https://lore.kernel.org/r/20200210081131.23572-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/tty/vt/selection.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-)
--- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -13,6 +13,7 @@ #include <linux/tty.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/mutex.h> #include <linux/slab.h> #include <linux/types.h>
@@ -40,6 +41,7 @@ static volatile int sel_start = -1; /* static int sel_end; static int sel_buffer_lth; static char *sel_buffer; +static DEFINE_MUTEX(sel_lock);
/* clear_selection, highlight and highlight_pointer can be called from interrupt (via scrollback/front) */ @@ -163,7 +165,7 @@ int set_selection(const struct tiocl_sel char *bp, *obp; int i, ps, pe, multiplier; u16 c; - int mode; + int mode, ret = 0;
poke_blanked_console();
@@ -203,6 +205,7 @@ int set_selection(const struct tiocl_sel pe = tmp; }
+ mutex_lock(&sel_lock); if (sel_cons != vc_cons[fg_console].d) { clear_selection(); sel_cons = vc_cons[fg_console].d; @@ -248,9 +251,10 @@ int set_selection(const struct tiocl_sel break; case TIOCL_SELPOINTER: highlight_pointer(pe); - return 0; + goto unlock; default: - return -EINVAL; + ret = -EINVAL; + goto unlock; }
/* remove the pointer */ @@ -272,7 +276,7 @@ int set_selection(const struct tiocl_sel else if (new_sel_start == sel_start) { if (new_sel_end == sel_end) /* no action required */ - return 0; + goto unlock; else if (new_sel_end > sel_end) /* extend to right */ highlight(sel_end + 2, new_sel_end); else /* contract from right */ @@ -299,7 +303,8 @@ int set_selection(const struct tiocl_sel if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); clear_selection(); - return -ENOMEM; + ret = -ENOMEM; + goto unlock; } kfree(sel_buffer); sel_buffer = bp; @@ -324,7 +329,9 @@ int set_selection(const struct tiocl_sel } } sel_buffer_lth = bp - sel_buffer; - return 0; +unlock: + mutex_unlock(&sel_lock); + return ret; }
/* Insert the contents of the selection buffer into the @@ -351,6 +358,7 @@ int paste_selection(struct tty_struct *t tty_buffer_lock_exclusive(&vc->port);
add_wait_queue(&vc->paste_wait, &wait); + mutex_lock(&sel_lock); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) { @@ -358,7 +366,9 @@ int paste_selection(struct tty_struct *t break; } if (test_bit(TTY_THROTTLED, &tty->flags)) { + mutex_unlock(&sel_lock); schedule(); + mutex_lock(&sel_lock); continue; } __set_current_state(TASK_RUNNING); @@ -367,6 +377,7 @@ int paste_selection(struct tty_struct *t count); pasted += count; } + mutex_unlock(&sel_lock); remove_wait_queue(&vc->paste_wait, &wait); __set_current_state(TASK_RUNNING);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Slaby jslaby@suse.cz
commit 4b70dd57a15d2f4685ac6e38056bad93e81e982f upstream.
We need to nest the console lock in sel_lock, so we have to push it down a bit. Fortunately, the callers of set_selection_* just lock the console lock around the function call. So moving it down is easy.
In the next patch, we switch the order.
Signed-off-by: Jiri Slaby jslaby@suse.cz Fixes: 07e6124a1a46 ("vt: selection, close sel_buffer race") Link: https://lore.kernel.org/r/20200228115406.5735-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/tty/vt/selection.c | 13 ++++++++++++- drivers/tty/vt/vt.c | 2 -- 2 files changed, 12 insertions(+), 3 deletions(-)
--- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -158,7 +158,7 @@ static int store_utf8(u16 c, char *p) * The entire selection process is managed under the console_lock. It's * a lot under the lock but its hardly a performance path */ -int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) +static int __set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) { struct vc_data *vc = vc_cons[fg_console].d; int sel_mode, new_sel_start, new_sel_end, spc; @@ -334,6 +334,17 @@ unlock: return ret; }
+int set_selection(const struct tiocl_selection __user *v, struct tty_struct *tty) +{ + int ret; + + console_lock(); + ret = __set_selection(v, tty); + console_unlock(); + + return ret; +} + /* Insert the contents of the selection buffer into the * queue of the tty associated with the current console. * Invoked by ioctl(). --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2670,9 +2670,7 @@ int tioclinux(struct tty_struct *tty, un switch (type) { case TIOCL_SETSEL: - console_lock(); ret = set_selection((struct tiocl_selection __user *)(p+1), tty); - console_unlock(); break; case TIOCL_PASTESEL: ret = paste_selection(tty);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Jiri Slaby jslaby@suse.cz
commit e8c75a30a23c6ba63f4ef6895cbf41fd42f21aa2 upstream.
sel_lock cannot nest in the console lock. Thanks to syzkaller, the kernel states firmly:
WARNING: possible circular locking dependency detected 5.6.0-rc3-syzkaller #0 Not tainted
syz-executor.4/20336 is trying to acquire lock: ffff8880a2e952a0 (&tty->termios_rwsem){++++}, at: tty_unthrottle+0x22/0x100 drivers/tty/tty_ioctl.c:136
but task is already holding lock: ffffffff89462e70 (sel_lock){+.+.}, at: paste_selection+0x118/0x470 drivers/tty/vt/selection.c:374
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #2 (sel_lock){+.+.}: mutex_lock_nested+0x1b/0x30 kernel/locking/mutex.c:1118 set_selection_kernel+0x3b8/0x18a0 drivers/tty/vt/selection.c:217 set_selection_user+0x63/0x80 drivers/tty/vt/selection.c:181 tioclinux+0x103/0x530 drivers/tty/vt/vt.c:3050 vt_ioctl+0x3f1/0x3a30 drivers/tty/vt/vt_ioctl.c:364
This is ioctl(TIOCL_SETSEL). Locks held on the path: console_lock -> sel_lock
-> #1 (console_lock){+.+.}: console_lock+0x46/0x70 kernel/printk/printk.c:2289 con_flush_chars+0x50/0x650 drivers/tty/vt/vt.c:3223 n_tty_write+0xeae/0x1200 drivers/tty/n_tty.c:2350 do_tty_write drivers/tty/tty_io.c:962 [inline] tty_write+0x5a1/0x950 drivers/tty/tty_io.c:1046
This is write(). Locks held on the path: termios_rwsem -> console_lock
-> #0 (&tty->termios_rwsem){++++}: down_write+0x57/0x140 kernel/locking/rwsem.c:1534 tty_unthrottle+0x22/0x100 drivers/tty/tty_ioctl.c:136 mkiss_receive_buf+0x12aa/0x1340 drivers/net/hamradio/mkiss.c:902 tty_ldisc_receive_buf+0x12f/0x170 drivers/tty/tty_buffer.c:465 paste_selection+0x346/0x470 drivers/tty/vt/selection.c:389 tioclinux+0x121/0x530 drivers/tty/vt/vt.c:3055 vt_ioctl+0x3f1/0x3a30 drivers/tty/vt/vt_ioctl.c:364
This is ioctl(TIOCL_PASTESEL). Locks held on the path: sel_lock -> termios_rwsem
other info that might help us debug this:
Chain exists of: &tty->termios_rwsem --> console_lock --> sel_lock
Clearly. From the above, we have: console_lock -> sel_lock sel_lock -> termios_rwsem termios_rwsem -> console_lock
Fix this by reversing the console_lock -> sel_lock dependency in ioctl(TIOCL_SETSEL). First, lock sel_lock, then console_lock.
Signed-off-by: Jiri Slaby jslaby@suse.cz Reported-by: syzbot+26183d9746e62da329b8@syzkaller.appspotmail.com Fixes: 07e6124a1a46 ("vt: selection, close sel_buffer race") Link: https://lore.kernel.org/r/20200228115406.5735-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/tty/vt/selection.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-)
--- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -205,7 +205,6 @@ static int __set_selection(const struct pe = tmp; }
- mutex_lock(&sel_lock); if (sel_cons != vc_cons[fg_console].d) { clear_selection(); sel_cons = vc_cons[fg_console].d; @@ -251,10 +250,9 @@ static int __set_selection(const struct break; case TIOCL_SELPOINTER: highlight_pointer(pe); - goto unlock; + return 0; default: - ret = -EINVAL; - goto unlock; + return -EINVAL; }
/* remove the pointer */ @@ -276,7 +274,7 @@ static int __set_selection(const struct else if (new_sel_start == sel_start) { if (new_sel_end == sel_end) /* no action required */ - goto unlock; + return 0; else if (new_sel_end > sel_end) /* extend to right */ highlight(sel_end + 2, new_sel_end); else /* contract from right */ @@ -303,8 +301,7 @@ static int __set_selection(const struct if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); clear_selection(); - ret = -ENOMEM; - goto unlock; + return -ENOMEM; } kfree(sel_buffer); sel_buffer = bp; @@ -329,8 +326,7 @@ static int __set_selection(const struct } } sel_buffer_lth = bp - sel_buffer; -unlock: - mutex_unlock(&sel_lock); + return ret; }
@@ -338,9 +334,11 @@ int set_selection(const struct tiocl_sel { int ret;
+ mutex_lock(&sel_lock); console_lock(); ret = __set_selection(v, tty); console_unlock(); + mutex_unlock(&sel_lock);
return ret; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Linus Torvalds torvalds@linux-foundation.org
commit 2e90ca68b0d2f5548804f22f0dd61145516171e3 upstream.
Jordy Zomer reported a KASAN out-of-bounds read in the floppy driver in wait_til_ready().
Which on the face of it can't happen, since as Willy Tarreau points out, the function does no particular memory access. Except through the FDCS macro, which just indexes a static allocation through teh current fdc, which is always checked against N_FDC.
Except the checking happens after we've already assigned the value.
The floppy driver is a disgrace (a lot of it going back to my original horrd "design"), and has no real maintainer. Nobody has the hardware, and nobody really cares. But it still gets used in virtual environment because it's one of those things that everybody supports.
The whole thing should be re-written, or at least parts of it should be seriously cleaned up. The 'current fdc' index, which is used by the FDCS macro, and which is often shadowed by a local 'fdc' variable, is a prime example of how not to write code.
But because nobody has the hardware or the motivation, let's just fix up the immediate problem with a nasty band-aid: test the fdc index before actually assigning it to the static 'fdc' variable.
Reported-by: Jordy Zomer jordy@simplyhacker.com Cc: Willy Tarreau w@1wt.eu Cc: Dan Carpenter dan.carpenter@oracle.com Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/block/floppy.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
--- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -847,14 +847,17 @@ static void reset_fdc_info(int mode) /* selects the fdc and drive, and enables the fdc's input/dma. */ static void set_fdc(int drive) { + unsigned int new_fdc = fdc; + if (drive >= 0 && drive < N_DRIVE) { - fdc = FDC(drive); + new_fdc = FDC(drive); current_drive = drive; } - if (fdc != 1 && fdc != 0) { + if (new_fdc >= N_FDC) { pr_info("bad fdc value\n"); return; } + fdc = new_fdc; set_dor(fdc, ~0, 8); #if N_FDC > 1 set_dor(1 - fdc, ~8, 0);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Eugenio Pérez eperezma@redhat.com
commit 42d84c8490f9f0931786f1623191fcab397c3d64 upstream.
Doing so, we save one call to get data we already have in the struct.
Also, since there is no guarantee that getname use sockaddr_ll parameter beyond its size, we add a little bit of security here. It should do not do beyond MAX_ADDR_LEN, but syzbot found that ax25_getname writes more (72 bytes, the size of full_sockaddr_ax25, versus 20 + 32 bytes of sockaddr_ll + MAX_ADDR_LEN in syzbot repro).
Fixes: 3a4d5c94e9593 ("vhost_net: a kernel-level virtio server") Reported-by: syzbot+f2a62d07a5198c819c7b@syzkaller.appspotmail.com Signed-off-by: Eugenio Pérez eperezma@redhat.com Acked-by: Michael S. Tsirkin mst@redhat.com Signed-off-by: David S. Miller davem@davemloft.net [bwh: Backported to 3.16: Also delete "uaddr_len" variable] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -843,11 +843,7 @@ static int vhost_net_release(struct inod
static struct socket *get_raw_socket(int fd) { - struct { - struct sockaddr_ll sa; - char buf[MAX_ADDR_LEN]; - } uaddr; - int uaddr_len = sizeof uaddr, r; + int r; struct socket *sock = sockfd_lookup(fd, &r);
if (!sock) @@ -859,12 +855,7 @@ static struct socket *get_raw_socket(int goto err; }
- r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa, - &uaddr_len, 0); - if (r) - goto err; - - if (uaddr.sa.sll_family != AF_PACKET) { + if (sock->sk->sk_family != AF_PACKET) { r = -EPFNOSUPPORT; goto err; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Randy Dunlap rdunlap@infradead.org
commit aa9f7d5172fac9bf1f09e678c35e287a40a7b7dd upstream.
Using an empty (malformed) nodelist that is not caught during mount option parsing leads to a stack-out-of-bounds access.
The option string that was used was: "mpol=prefer:,". However, MPOL_PREFERRED requires a single node number, which is not being provided here.
Add a check that 'nodes' is not empty after parsing for MPOL_PREFERRED's nodeid.
Fixes: 095f1fc4ebf3 ("mempolicy: rework shmem mpol parsing and display") Reported-by: Entropy Moe 3ntr0py1337@gmail.com Reported-by: syzbot+b055b1a6b2b958707a21@syzkaller.appspotmail.com Signed-off-by: Randy Dunlap rdunlap@infradead.org Signed-off-by: Andrew Morton akpm@linux-foundation.org Tested-by: syzbot+b055b1a6b2b958707a21@syzkaller.appspotmail.com Cc: Lee Schermerhorn lee.schermerhorn@hp.com Link: http://lkml.kernel.org/r/89526377-7eb6-b662-e1d8-4430928abde9@infradead.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- mm/mempolicy.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
--- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -2711,7 +2711,9 @@ int mpol_parse_str(char *str, struct mem switch (mode) { case MPOL_PREFERRED: /* - * Insist on a nodelist of one node only + * Insist on a nodelist of one node only, although later + * we use first_node(nodes) to grab a single node, so here + * nodelist (or nodes) cannot be empty. */ if (nodelist) { char *rest = nodelist; @@ -2719,6 +2721,8 @@ int mpol_parse_str(char *str, struct mem rest++; if (*rest) goto out; + if (nodes_empty(nodes)) + goto out; } break; case MPOL_INTERLEAVE:
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 998912346c0da53a6dbb71fab3a138586b596b30 upstream.
Make sure to check that we have at least one endpoint before accessing the endpoint array to avoid dereferencing a NULL-pointer on stream start.
Note that these sanity checks are not redundant as the driver is mixing looking up altsettings by index and by number, which need not coincide.
Fixes: 1876bb923c98 ("V4L/DVB (12079): gspca_ov519: add support for the ov511 bridge") Fixes: b282d87332f5 ("V4L/DVB (12080): gspca_ov519: Fix ov518+ with OV7620AE (Trust spacecam 320)") Cc: Hans de Goede hdegoede@redhat.com Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Mauro Carvalho Chehab mchehab+huawei@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/media/usb/gspca/ov519.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
--- a/drivers/media/usb/gspca/ov519.c +++ b/drivers/media/usb/gspca/ov519.c @@ -3497,6 +3497,11 @@ static void ov511_mode_init_regs(struct return; }
+ if (alt->desc.bNumEndpoints < 1) { + sd->gspca_dev.usb_err = -ENODEV; + return; + } + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5);
@@ -3622,6 +3627,11 @@ static void ov518_mode_init_regs(struct return; }
+ if (alt->desc.bNumEndpoints < 1) { + sd->gspca_dev.usb_err = -ENODEV; + return; + } + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit 485b06aadb933190f4bc44e006076bc27a23f205 upstream.
Make sure to check that we have two alternate settings and at least one endpoint before accessing the second altsetting structure and dereferencing the endpoint arrays.
This specifically avoids dereferencing NULL-pointers or corrupting memory when a device does not have the expected descriptors.
Note that the sanity checks in stv06xx_start() and pb0100_start() are not redundant as the driver is mixing looking up altsettings by index and by number, which may not coincide.
Fixes: 8668d504d72c ("V4L/DVB (12082): gspca_stv06xx: Add support for st6422 bridge and sensor") Fixes: c0b33bdc5b8d ("[media] gspca-stv06xx: support bandwidth changing") Cc: Hans de Goede hdegoede@redhat.com Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Mauro Carvalho Chehab mchehab+huawei@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/media/usb/gspca/stv06xx/stv06xx.c | 19 ++++++++++++++++++- .../media/usb/gspca/stv06xx/stv06xx_pb0100.c | 4 ++++ 2 files changed, 22 insertions(+), 1 deletion(-)
--- a/drivers/media/usb/gspca/stv06xx/stv06xx.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c @@ -293,6 +293,9 @@ static int stv06xx_start(struct gspca_de return -EIO; }
+ if (alt->desc.bNumEndpoints < 1) + return -ENODEV; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size); if (err < 0) @@ -317,11 +320,21 @@ out:
static int stv06xx_isoc_init(struct gspca_dev *gspca_dev) { + struct usb_interface_cache *intfc; struct usb_host_interface *alt; struct sd *sd = (struct sd *) gspca_dev;
+ intfc = gspca_dev->dev->actconfig->intf_cache[0]; + + if (intfc->num_altsetting < 2) + return -ENODEV; + + alt = &intfc->altsetting[1]; + + if (alt->desc.bNumEndpoints < 1) + return -ENODEV; + /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ - alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]);
@@ -334,6 +347,10 @@ static int stv06xx_isoc_nego(struct gspc struct usb_host_interface *alt; struct sd *sd = (struct sd *) gspca_dev;
+ /* + * Existence of altsetting and endpoint was verified in + * stv06xx_isoc_init() + */ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode]; --- a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c @@ -198,6 +198,10 @@ static int pb0100_start(struct sd *sd) alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) return -ENODEV; + + if (alt->desc.bNumEndpoints < 1) + return -ENODEV; + packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
/* If we don't have enough bandwidth use a lower framerate */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold johan@kernel.org
commit a246b4d547708f33ff4d4b9a7a5dbac741dc89d8 upstream.
Make sure to check that we have two alternate settings and at least one endpoint before accessing the second altsetting structure and dereferencing the endpoint arrays.
This specifically avoids dereferencing NULL-pointers or corrupting memory when a device does not have the expected descriptors.
Note that the sanity check in cit_get_packet_size() is not redundant as the driver is mixing looking up altsettings by index and by number, which may not coincide.
Fixes: 659fefa0eb17 ("V4L/DVB: gspca_xirlink_cit: Add support for camera with a bcd version of 0.01") Fixes: 59f8b0bf3c12 ("V4L/DVB: gspca_xirlink_cit: support bandwidth changing for devices with 1 alt setting") Cc: Hans de Goede hdegoede@redhat.com Signed-off-by: Johan Hovold johan@kernel.org Signed-off-by: Hans Verkuil hverkuil-cisco@xs4all.nl Signed-off-by: Mauro Carvalho Chehab mchehab+huawei@kernel.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/media/usb/gspca/xirlink_cit.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
--- a/drivers/media/usb/gspca/xirlink_cit.c +++ b/drivers/media/usb/gspca/xirlink_cit.c @@ -1455,6 +1455,9 @@ static int cit_get_packet_size(struct gs return -EIO; }
+ if (alt->desc.bNumEndpoints < 1) + return -ENODEV; + return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); }
@@ -2632,6 +2635,7 @@ static int sd_start(struct gspca_dev *gs
static int sd_isoc_init(struct gspca_dev *gspca_dev) { + struct usb_interface_cache *intfc; struct usb_host_interface *alt; int max_packet_size;
@@ -2647,8 +2651,17 @@ static int sd_isoc_init(struct gspca_dev break; }
+ intfc = gspca_dev->dev->actconfig->intf_cache[0]; + + if (intfc->num_altsetting < 2) + return -ENODEV; + + alt = &intfc->altsetting[1]; + + if (alt->desc.bNumEndpoints < 1) + return -ENODEV; + /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ - alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size);
return 0; @@ -2671,6 +2684,9 @@ static int sd_isoc_nego(struct gspca_dev break; }
+ /* + * Existence of altsetting and endpoint was verified in sd_isoc_init() + */ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); if (packet_size <= min_packet_size)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov dmitry.torokhov@gmail.com
commit 882f312dc0751c973db26478f07f082c584d16aa upstream.
We do not need explicitly call dev_set_drvdata(), as it is done for us by device_create().
Acked-by: Richard Cochran richardcochran@gmail.com Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/ptp/ptp_clock.c | 2 -- 1 file changed, 2 deletions(-)
--- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -216,8 +216,6 @@ struct ptp_clock *ptp_clock_register(str if (IS_ERR(ptp->dev)) goto no_device;
- dev_set_drvdata(ptp->dev, ptp); - err = ptp_populate_sysfs(ptp); if (err) goto no_sysfs;
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov dmitry.torokhov@gmail.com
commit af59e717d5ff9c8dbf9bcc581c0dfb3b2a9c9030 upstream.
Instead of creating selected attributes after the device is created (and after userspace potentially seen uevent), lets use attribute group is_visible() method to control which attributes are shown. This will allow us to create all attributes (except "pins" group, which will be taken care of later) before userspace gets notified about new ptp class device.
Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/ptp/ptp_sysfs.c | 125 ++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 70 deletions(-)
--- a/drivers/ptp/ptp_sysfs.c +++ b/drivers/ptp/ptp_sysfs.c @@ -46,27 +46,6 @@ PTP_SHOW_INT(n_periodic_outputs, n_per_o PTP_SHOW_INT(n_programmable_pins, n_pins); PTP_SHOW_INT(pps_available, pps);
-static struct attribute *ptp_attrs[] = { - &dev_attr_clock_name.attr, - &dev_attr_max_adjustment.attr, - &dev_attr_n_alarms.attr, - &dev_attr_n_external_timestamps.attr, - &dev_attr_n_periodic_outputs.attr, - &dev_attr_n_programmable_pins.attr, - &dev_attr_pps_available.attr, - NULL, -}; - -static const struct attribute_group ptp_group = { - .attrs = ptp_attrs, -}; - -const struct attribute_group *ptp_groups[] = { - &ptp_group, - NULL, -}; - - static ssize_t extts_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -91,6 +70,7 @@ static ssize_t extts_enable_store(struct out: return err; } +static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
static ssize_t extts_fifo_show(struct device *dev, struct device_attribute *attr, char *page) @@ -124,6 +104,7 @@ out: mutex_unlock(&ptp->tsevq_mux); return cnt; } +static DEVICE_ATTR(fifo, 0444, extts_fifo_show, NULL);
static ssize_t period_store(struct device *dev, struct device_attribute *attr, @@ -151,6 +132,7 @@ static ssize_t period_store(struct devic out: return err; } +static DEVICE_ATTR(period, 0220, NULL, period_store);
static ssize_t pps_enable_store(struct device *dev, struct device_attribute *attr, @@ -177,6 +159,57 @@ static ssize_t pps_enable_store(struct d out: return err; } +static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store); + +static struct attribute *ptp_attrs[] = { + &dev_attr_clock_name.attr, + + &dev_attr_max_adjustment.attr, + &dev_attr_n_alarms.attr, + &dev_attr_n_external_timestamps.attr, + &dev_attr_n_periodic_outputs.attr, + &dev_attr_n_programmable_pins.attr, + &dev_attr_pps_available.attr, + + &dev_attr_extts_enable.attr, + &dev_attr_fifo.attr, + &dev_attr_period.attr, + &dev_attr_pps_enable.attr, + NULL +}; + +static umode_t ptp_is_attribute_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = kobj_to_dev(kobj); + struct ptp_clock *ptp = dev_get_drvdata(dev); + struct ptp_clock_info *info = ptp->info; + umode_t mode = attr->mode; + + if (attr == &dev_attr_extts_enable.attr || + attr == &dev_attr_fifo.attr) { + if (!info->n_ext_ts) + mode = 0; + } else if (attr == &dev_attr_period.attr) { + if (!info->n_per_out) + mode = 0; + } else if (attr == &dev_attr_pps_enable.attr) { + if (!info->pps) + mode = 0; + } + + return mode; +} + +static const struct attribute_group ptp_group = { + .is_visible = ptp_is_attribute_visible, + .attrs = ptp_attrs, +}; + +const struct attribute_group *ptp_groups[] = { + &ptp_group, + NULL +};
static int ptp_pin_name2index(struct ptp_clock *ptp, const char *name) { @@ -235,26 +268,11 @@ static ssize_t ptp_pin_store(struct devi return count; }
-static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store); -static DEVICE_ATTR(fifo, 0444, extts_fifo_show, NULL); -static DEVICE_ATTR(period, 0220, NULL, period_store); -static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store); - int ptp_cleanup_sysfs(struct ptp_clock *ptp) { struct device *dev = ptp->dev; struct ptp_clock_info *info = ptp->info;
- if (info->n_ext_ts) { - device_remove_file(dev, &dev_attr_extts_enable); - device_remove_file(dev, &dev_attr_fifo); - } - if (info->n_per_out) - device_remove_file(dev, &dev_attr_period); - - if (info->pps) - device_remove_file(dev, &dev_attr_pps_enable); - if (info->n_pins) { sysfs_remove_group(&dev->kobj, &ptp->pin_attr_group); kfree(ptp->pin_attr); @@ -307,46 +325,13 @@ no_dev_attr:
int ptp_populate_sysfs(struct ptp_clock *ptp) { - struct device *dev = ptp->dev; struct ptp_clock_info *info = ptp->info; int err;
- if (info->n_ext_ts) { - err = device_create_file(dev, &dev_attr_extts_enable); - if (err) - goto out1; - err = device_create_file(dev, &dev_attr_fifo); - if (err) - goto out2; - } - if (info->n_per_out) { - err = device_create_file(dev, &dev_attr_period); - if (err) - goto out3; - } - if (info->pps) { - err = device_create_file(dev, &dev_attr_pps_enable); - if (err) - goto out4; - } if (info->n_pins) { err = ptp_populate_pins(ptp); if (err) - goto out5; + return err; } return 0; -out5: - if (info->pps) - device_remove_file(dev, &dev_attr_pps_enable); -out4: - if (info->n_per_out) - device_remove_file(dev, &dev_attr_period); -out3: - if (info->n_ext_ts) - device_remove_file(dev, &dev_attr_fifo); -out2: - if (info->n_ext_ts) - device_remove_file(dev, &dev_attr_extts_enable); -out1: - return err; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov dmitry.torokhov@gmail.com
commit 85a66e55019583da1e0f18706b7a8281c9f6de5b upstream.
Let's switch to using device_create_with_groups(), which will allow us to create "pins" attribute group together with the rest of ptp device attributes, and before userspace gets notified about ptp device creation.
Signed-off-by: Dmitry Torokhov dmitry.torokhov@gmail.com Signed-off-by: David S. Miller davem@davemloft.net [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/ptp/ptp_clock.c | 20 +++++++++++--------- drivers/ptp/ptp_private.h | 7 ++++--- drivers/ptp/ptp_sysfs.c | 39 +++++++++------------------------------ 3 files changed, 24 insertions(+), 42 deletions(-)
--- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -210,16 +210,17 @@ struct ptp_clock *ptp_clock_register(str mutex_init(&ptp->pincfg_mux); init_waitqueue_head(&ptp->tsev_wq);
+ err = ptp_populate_pin_groups(ptp); + if (err) + goto no_pin_groups; + /* Create a new device in our class. */ - ptp->dev = device_create(ptp_class, parent, ptp->devid, ptp, - "ptp%d", ptp->index); + ptp->dev = device_create_with_groups(ptp_class, parent, ptp->devid, + ptp, ptp->pin_attr_groups, + "ptp%d", ptp->index); if (IS_ERR(ptp->dev)) goto no_device;
- err = ptp_populate_sysfs(ptp); - if (err) - goto no_sysfs; - /* Register a new PPS source. */ if (info->pps) { struct pps_source_info pps; @@ -247,10 +248,10 @@ no_clock: if (ptp->pps_source) pps_unregister_source(ptp->pps_source); no_pps: - ptp_cleanup_sysfs(ptp); -no_sysfs: device_destroy(ptp_class, ptp->devid); no_device: + ptp_cleanup_pin_groups(ptp); +no_pin_groups: mutex_destroy(&ptp->tsevq_mux); mutex_destroy(&ptp->pincfg_mux); no_slot: @@ -268,8 +269,9 @@ int ptp_clock_unregister(struct ptp_cloc /* Release the clock's resources. */ if (ptp->pps_source) pps_unregister_source(ptp->pps_source); - ptp_cleanup_sysfs(ptp); + device_destroy(ptp_class, ptp->devid); + ptp_cleanup_pin_groups(ptp);
posix_clock_unregister(&ptp->clock); return 0; --- a/drivers/ptp/ptp_private.h +++ b/drivers/ptp/ptp_private.h @@ -54,6 +54,8 @@ struct ptp_clock { struct device_attribute *pin_dev_attr; struct attribute **pin_attr; struct attribute_group pin_attr_group; + /* 1st entry is a pointer to the real group, 2nd is NULL terminator */ + const struct attribute_group *pin_attr_groups[2]; };
/* @@ -94,8 +96,7 @@ uint ptp_poll(struct posix_clock *pc,
extern const struct attribute_group *ptp_groups[];
-int ptp_cleanup_sysfs(struct ptp_clock *ptp); - -int ptp_populate_sysfs(struct ptp_clock *ptp); +int ptp_populate_pin_groups(struct ptp_clock *ptp); +void ptp_cleanup_pin_groups(struct ptp_clock *ptp);
#endif --- a/drivers/ptp/ptp_sysfs.c +++ b/drivers/ptp/ptp_sysfs.c @@ -268,25 +268,14 @@ static ssize_t ptp_pin_store(struct devi return count; }
-int ptp_cleanup_sysfs(struct ptp_clock *ptp) +int ptp_populate_pin_groups(struct ptp_clock *ptp) { - struct device *dev = ptp->dev; - struct ptp_clock_info *info = ptp->info; - - if (info->n_pins) { - sysfs_remove_group(&dev->kobj, &ptp->pin_attr_group); - kfree(ptp->pin_attr); - kfree(ptp->pin_dev_attr); - } - return 0; -} - -static int ptp_populate_pins(struct ptp_clock *ptp) -{ - struct device *dev = ptp->dev; struct ptp_clock_info *info = ptp->info; int err = -ENOMEM, i, n_pins = info->n_pins;
+ if (!n_pins) + return 0; + ptp->pin_dev_attr = kzalloc(n_pins * sizeof(*ptp->pin_dev_attr), GFP_KERNEL); if (!ptp->pin_dev_attr) @@ -310,28 +299,18 @@ static int ptp_populate_pins(struct ptp_ ptp->pin_attr_group.name = "pins"; ptp->pin_attr_group.attrs = ptp->pin_attr;
- err = sysfs_create_group(&dev->kobj, &ptp->pin_attr_group); - if (err) - goto no_group; + ptp->pin_attr_groups[0] = &ptp->pin_attr_group; + return 0;
-no_group: - kfree(ptp->pin_attr); no_pin_attr: kfree(ptp->pin_dev_attr); no_dev_attr: return err; }
-int ptp_populate_sysfs(struct ptp_clock *ptp) +void ptp_cleanup_pin_groups(struct ptp_clock *ptp) { - struct ptp_clock_info *info = ptp->info; - int err; - - if (info->n_pins) { - err = ptp_populate_pins(ptp); - if (err) - return err; - } - return 0; + kfree(ptp->pin_attr); + kfree(ptp->pin_dev_attr); }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Logan Gunthorpe logang@deltatee.com
commit 233ed09d7fdacf592ee91e6c97ce5f4364fbe7c0 upstream.
Credit for this patch goes is shared with Dan Williams [1]. I've taken things one step further to make the helper function more useful and clean up calling code.
There's a common pattern in the kernel whereby a struct cdev is placed in a structure along side a struct device which manages the life-cycle of both. In the naive approach, the reference counting is broken and the struct device can free everything before the chardev code is entirely released.
Many developers have solved this problem by linking the internal kobjs in this fashion:
cdev.kobj.parent = &parent_dev.kobj;
The cdev code explicitly gets and puts a reference to it's kobj parent. So this seems like it was intended to be used this way. Dmitrty Torokhov first put this in place in 2012 with this commit:
2f0157f char_dev: pin parent kobject
and the first instance of the fix was then done in the input subsystem in the following commit:
4a215aa Input: fix use-after-free introduced with dynamic minor changes
Subsequently over the years, however, this issue seems to have tripped up multiple developers independently. For example, see these commits:
0d5b7da iio: Prevent race between IIO chardev opening and IIO device (by Lars-Peter Clausen in 2013)
ba0ef85 tpm: Fix initialization of the cdev (by Jason Gunthorpe in 2015)
5b28dde [media] media: fix use-after-free in cdev_put() when app exits after driver unbind (by Shauh Khan in 2016)
This technique is similarly done in at least 15 places within the kernel and probably should have been done so in another, at least, 5 places. The kobj line also looks very suspect in that one would not expect drivers to have to mess with kobject internals in this way. Even highly experienced kernel developers can be surprised by this code, as seen in [2].
To help alleviate this situation, and hopefully prevent future wasted effort on this problem, this patch introduces a helper function to register a char device along with its parent struct device. This creates a more regular API for tying a char device to its parent without the developer having to set members in the underlying kobject.
This patch introduce cdev_device_add and cdev_device_del which replaces a common pattern including setting the kobj parent, calling cdev_add and then calling device_add. It also introduces cdev_set_parent for the few cases that set the kobject parent without using device_add.
[1] https://lkml.org/lkml/2017/2/13/700 [2] https://lkml.org/lkml/2017/2/10/370
Signed-off-by: Logan Gunthorpe logang@deltatee.com Signed-off-by: Dan Williams dan.j.williams@intel.com Reviewed-by: Hans Verkuil hans.verkuil@cisco.com Reviewed-by: Alexandre Belloni alexandre.belloni@free-electrons.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/char_dev.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/cdev.h | 5 +++ 2 files changed, 91 insertions(+)
--- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -488,6 +488,85 @@ int cdev_add(struct cdev *p, dev_t dev, return 0; }
+/** + * cdev_set_parent() - set the parent kobject for a char device + * @p: the cdev structure + * @kobj: the kobject to take a reference to + * + * cdev_set_parent() sets a parent kobject which will be referenced + * appropriately so the parent is not freed before the cdev. This + * should be called before cdev_add. + */ +void cdev_set_parent(struct cdev *p, struct kobject *kobj) +{ + WARN_ON(!kobj->state_initialized); + p->kobj.parent = kobj; +} + +/** + * cdev_device_add() - add a char device and it's corresponding + * struct device, linkink + * @dev: the device structure + * @cdev: the cdev structure + * + * cdev_device_add() adds the char device represented by @cdev to the system, + * just as cdev_add does. It then adds @dev to the system using device_add + * The dev_t for the char device will be taken from the struct device which + * needs to be initialized first. This helper function correctly takes a + * reference to the parent device so the parent will not get released until + * all references to the cdev are released. + * + * This helper uses dev->devt for the device number. If it is not set + * it will not add the cdev and it will be equivalent to device_add. + * + * This function should be used whenever the struct cdev and the + * struct device are members of the same structure whose lifetime is + * managed by the struct device. + * + * NOTE: Callers must assume that userspace was able to open the cdev and + * can call cdev fops callbacks at any time, even if this function fails. + */ +int cdev_device_add(struct cdev *cdev, struct device *dev) +{ + int rc = 0; + + if (dev->devt) { + cdev_set_parent(cdev, &dev->kobj); + + rc = cdev_add(cdev, dev->devt, 1); + if (rc) + return rc; + } + + rc = device_add(dev); + if (rc) + cdev_del(cdev); + + return rc; +} + +/** + * cdev_device_del() - inverse of cdev_device_add + * @dev: the device structure + * @cdev: the cdev structure + * + * cdev_device_del() is a helper function to call cdev_del and device_del. + * It should be used whenever cdev_device_add is used. + * + * If dev->devt is not set it will not remove the cdev and will be equivalent + * to device_del. + * + * NOTE: This guarantees that associated sysfs callbacks are not running + * or runnable, however any cdevs already open will remain and their fops + * will still be callable even after this function returns. + */ +void cdev_device_del(struct cdev *cdev, struct device *dev) +{ + device_del(dev); + if (dev->devt) + cdev_del(cdev); +} + static void cdev_unmap(dev_t dev, unsigned count) { kobj_unmap(cdev_map, dev, count); @@ -499,6 +578,10 @@ static void cdev_unmap(dev_t dev, unsign * * cdev_del() removes @p from the system, possibly freeing the structure * itself. + * + * NOTE: This guarantees that cdev device will no longer be able to be + * opened, however any cdevs already open will remain and their fops will + * still be callable even after cdev_del returns. */ void cdev_del(struct cdev *p) { @@ -589,6 +672,9 @@ EXPORT_SYMBOL(cdev_init); EXPORT_SYMBOL(cdev_alloc); EXPORT_SYMBOL(cdev_del); EXPORT_SYMBOL(cdev_add); +EXPORT_SYMBOL(cdev_set_parent); +EXPORT_SYMBOL(cdev_device_add); +EXPORT_SYMBOL(cdev_device_del); EXPORT_SYMBOL(__register_chrdev); EXPORT_SYMBOL(__unregister_chrdev); EXPORT_SYMBOL(directly_mappable_cdev_bdi); --- a/include/linux/cdev.h +++ b/include/linux/cdev.h @@ -4,6 +4,7 @@ #include <linux/kobject.h> #include <linux/kdev_t.h> #include <linux/list.h> +#include <linux/device.h>
struct file_operations; struct inode; @@ -26,6 +27,10 @@ void cdev_put(struct cdev *p);
int cdev_add(struct cdev *, dev_t, unsigned);
+void cdev_set_parent(struct cdev *p, struct kobject *kobj); +int cdev_device_add(struct cdev *cdev, struct device *dev); +void cdev_device_del(struct cdev *cdev, struct device *dev); + void cdev_del(struct cdev *);
void cd_forget(struct inode *);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: YueHaibing yuehaibing@huawei.com
commit aea0a897af9e44c258e8ab9296fad417f1bc063a upstream.
Fix smatch warning:
drivers/ptp/ptp_clock.c:298 ptp_clock_register() warn: passing zero to 'ERR_PTR'
'err' should be set while device_create_with_groups and pps_register_source fails
Fixes: 85a66e550195 ("ptp: create "pins" together with the rest of attributes") Signed-off-by: YueHaibing yuehaibing@huawei.com Acked-by: Richard Cochran richardcochran@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/ptp/ptp_clock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
--- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -218,8 +218,10 @@ struct ptp_clock *ptp_clock_register(str ptp->dev = device_create_with_groups(ptp_class, parent, ptp->devid, ptp, ptp->pin_attr_groups, "ptp%d", ptp->index); - if (IS_ERR(ptp->dev)) + if (IS_ERR(ptp->dev)) { + err = PTR_ERR(ptp->dev); goto no_device; + }
/* Register a new PPS source. */ if (info->pps) { @@ -230,6 +232,7 @@ struct ptp_clock *ptp_clock_register(str pps.owner = info->owner; ptp->pps_source = pps_register_source(&pps, PTP_PPS_DEFAULTS); if (!ptp->pps_source) { + err = -EINVAL; pr_err("failed to register pps source\n"); goto no_pps; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Vladis Dronov vdronov@redhat.com
commit a33121e5487b424339636b25c35d3a180eaa5f5e upstream.
In a case when a ptp chardev (like /dev/ptp0) is open but an underlying device is removed, closing this file leads to a race. This reproduces easily in a kvm virtual machine:
ts# cat openptp0.c int main() { ... fp = fopen("/dev/ptp0", "r"); ... sleep(10); } ts# uname -r 5.5.0-rc3-46cf053e ts# cat /proc/cmdline ... slub_debug=FZP ts# modprobe ptp_kvm ts# ./openptp0 & [1] 670 opened /dev/ptp0, sleeping 10s... ts# rmmod ptp_kvm ts# ls /dev/ptp* ls: cannot access '/dev/ptp*': No such file or directory ts# ...woken up [ 48.010809] general protection fault: 0000 [#1] SMP [ 48.012502] CPU: 6 PID: 658 Comm: openptp0 Not tainted 5.5.0-rc3-46cf053e #25 [ 48.014624] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), ... [ 48.016270] RIP: 0010:module_put.part.0+0x7/0x80 [ 48.017939] RSP: 0018:ffffb3850073be00 EFLAGS: 00010202 [ 48.018339] RAX: 000000006b6b6b6b RBX: 6b6b6b6b6b6b6b6b RCX: ffff89a476c00ad0 [ 48.018936] RDX: fffff65a08d3ea08 RSI: 0000000000000247 RDI: 6b6b6b6b6b6b6b6b [ 48.019470] ... ^^^ a slub poison [ 48.023854] Call Trace: [ 48.024050] __fput+0x21f/0x240 [ 48.024288] task_work_run+0x79/0x90 [ 48.024555] do_exit+0x2af/0xab0 [ 48.024799] ? vfs_write+0x16a/0x190 [ 48.025082] do_group_exit+0x35/0x90 [ 48.025387] __x64_sys_exit_group+0xf/0x10 [ 48.025737] do_syscall_64+0x3d/0x130 [ 48.026056] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 48.026479] RIP: 0033:0x7f53b12082f6 [ 48.026792] ... [ 48.030945] Modules linked in: ptp i6300esb watchdog [last unloaded: ptp_kvm] [ 48.045001] Fixing recursive fault but reboot is needed!
This happens in:
static void __fput(struct file *file) { ... if (file->f_op->release) file->f_op->release(inode, file); <<< cdev is kfree'd here if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL && !(mode & FMODE_PATH))) { cdev_put(inode->i_cdev); <<< cdev fields are accessed here
Namely:
__fput() posix_clock_release() kref_put(&clk->kref, delete_clock) <<< the last reference delete_clock() delete_ptp_clock() kfree(ptp) <<< cdev is embedded in ptp cdev_put module_put(p->owner) <<< *p is kfree'd, bang!
Here cdev is embedded in posix_clock which is embedded in ptp_clock. The race happens because ptp_clock's lifetime is controlled by two refcounts: kref and cdev.kobj in posix_clock. This is wrong.
Make ptp_clock's sysfs device a parent of cdev with cdev_device_add() created especially for such cases. This way the parent device with its ptp_clock is not released until all references to the cdev are released. This adds a requirement that an initialized but not exposed struct device should be provided to posix_clock_register() by a caller instead of a simple dev_t.
This approach was adopted from the commit 72139dfa2464 ("watchdog: Fix the race between the release of watchdog_core_data and cdev"). See details of the implementation in the commit 233ed09d7fda ("chardev: add helper function to register char devs with a struct device").
Link: https://lore.kernel.org/linux-fsdevel/20191125125342.6189-1-vdronov@redhat.c... Analyzed-by: Stephen Johnston sjohnsto@redhat.com Analyzed-by: Vern Lovejoy vlovejoy@redhat.com Signed-off-by: Vladis Dronov vdronov@redhat.com Acked-by: Richard Cochran richardcochran@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/ptp/ptp_clock.c | 31 ++++++++++++++----------------- drivers/ptp/ptp_private.h | 2 +- include/linux/posix-clock.h | 19 +++++++++++-------- kernel/time/posix-clock.c | 31 +++++++++++++------------------ 4 files changed, 39 insertions(+), 44 deletions(-)
--- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -167,9 +167,9 @@ static struct posix_clock_operations ptp .read = ptp_read, };
-static void delete_ptp_clock(struct posix_clock *pc) +static void ptp_clock_release(struct device *dev) { - struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); + struct ptp_clock *ptp = container_of(dev, struct ptp_clock, dev);
mutex_destroy(&ptp->tsevq_mux); mutex_destroy(&ptp->pincfg_mux); @@ -201,7 +201,6 @@ struct ptp_clock *ptp_clock_register(str }
ptp->clock.ops = ptp_clock_ops; - ptp->clock.release = delete_ptp_clock; ptp->info = info; ptp->devid = MKDEV(major, index); ptp->index = index; @@ -214,15 +213,6 @@ struct ptp_clock *ptp_clock_register(str if (err) goto no_pin_groups;
- /* Create a new device in our class. */ - ptp->dev = device_create_with_groups(ptp_class, parent, ptp->devid, - ptp, ptp->pin_attr_groups, - "ptp%d", ptp->index); - if (IS_ERR(ptp->dev)) { - err = PTR_ERR(ptp->dev); - goto no_device; - } - /* Register a new PPS source. */ if (info->pps) { struct pps_source_info pps; @@ -238,8 +228,18 @@ struct ptp_clock *ptp_clock_register(str } }
- /* Create a posix clock. */ - err = posix_clock_register(&ptp->clock, ptp->devid); + /* Initialize a new device of our class in our clock structure. */ + device_initialize(&ptp->dev); + ptp->dev.devt = ptp->devid; + ptp->dev.class = ptp_class; + ptp->dev.parent = parent; + ptp->dev.groups = ptp->pin_attr_groups; + ptp->dev.release = ptp_clock_release; + dev_set_drvdata(&ptp->dev, ptp); + dev_set_name(&ptp->dev, "ptp%d", ptp->index); + + /* Create a posix clock and link it to the device. */ + err = posix_clock_register(&ptp->clock, &ptp->dev); if (err) { pr_err("failed to create posix clock\n"); goto no_clock; @@ -251,8 +251,6 @@ no_clock: if (ptp->pps_source) pps_unregister_source(ptp->pps_source); no_pps: - device_destroy(ptp_class, ptp->devid); -no_device: ptp_cleanup_pin_groups(ptp); no_pin_groups: mutex_destroy(&ptp->tsevq_mux); @@ -273,7 +271,6 @@ int ptp_clock_unregister(struct ptp_cloc if (ptp->pps_source) pps_unregister_source(ptp->pps_source);
- device_destroy(ptp_class, ptp->devid); ptp_cleanup_pin_groups(ptp);
posix_clock_unregister(&ptp->clock); --- a/drivers/ptp/ptp_private.h +++ b/drivers/ptp/ptp_private.h @@ -40,7 +40,7 @@ struct timestamp_event_queue {
struct ptp_clock { struct posix_clock clock; - struct device *dev; + struct device dev; struct ptp_clock_info *info; dev_t devid; int index; /* index into clocks.map */ --- a/include/linux/posix-clock.h +++ b/include/linux/posix-clock.h @@ -104,29 +104,32 @@ struct posix_clock_operations { * * @ops: Functional interface to the clock * @cdev: Character device instance for this clock - * @kref: Reference count. + * @dev: Pointer to the clock's device. * @rwsem: Protects the 'zombie' field from concurrent access. * @zombie: If 'zombie' is true, then the hardware has disappeared. - * @release: A function to free the structure when the reference count reaches - * zero. May be NULL if structure is statically allocated. * * Drivers should embed their struct posix_clock within a private * structure, obtaining a reference to it during callbacks using * container_of(). + * + * Drivers should supply an initialized but not exposed struct device + * to posix_clock_register(). It is used to manage lifetime of the + * driver's private structure. It's 'release' field should be set to + * a release function for this private structure. */ struct posix_clock { struct posix_clock_operations ops; struct cdev cdev; - struct kref kref; + struct device *dev; struct rw_semaphore rwsem; bool zombie; - void (*release)(struct posix_clock *clk); };
/** * posix_clock_register() - register a new clock - * @clk: Pointer to the clock. Caller must provide 'ops' and 'release' - * @devid: Allocated device id + * @clk: Pointer to the clock. Caller must provide 'ops' field + * @dev: Pointer to the initialized device. Caller must provide + * 'release' field * * A clock driver calls this function to register itself with the * clock device subsystem. If 'clk' points to dynamically allocated @@ -135,7 +138,7 @@ struct posix_clock { * * Returns zero on success, non-zero otherwise. */ -int posix_clock_register(struct posix_clock *clk, dev_t devid); +int posix_clock_register(struct posix_clock *clk, struct device *dev);
/** * posix_clock_unregister() - unregister a clock --- a/kernel/time/posix-clock.c +++ b/kernel/time/posix-clock.c @@ -25,8 +25,6 @@ #include <linux/syscalls.h> #include <linux/uaccess.h>
-static void delete_clock(struct kref *kref); - /* * Returns NULL if the posix_clock instance attached to 'fp' is old and stale. */ @@ -168,7 +166,7 @@ static int posix_clock_open(struct inode err = 0;
if (!err) { - kref_get(&clk->kref); + get_device(clk->dev); fp->private_data = clk; } out: @@ -184,7 +182,7 @@ static int posix_clock_release(struct in if (clk->ops.release) err = clk->ops.release(clk);
- kref_put(&clk->kref, delete_clock); + put_device(clk->dev);
fp->private_data = NULL;
@@ -206,38 +204,35 @@ static const struct file_operations posi #endif };
-int posix_clock_register(struct posix_clock *clk, dev_t devid) +int posix_clock_register(struct posix_clock *clk, struct device *dev) { int err;
- kref_init(&clk->kref); init_rwsem(&clk->rwsem);
cdev_init(&clk->cdev, &posix_clock_file_operations); + err = cdev_device_add(&clk->cdev, dev); + if (err) { + pr_err("%s unable to add device %d:%d\n", + dev_name(dev), MAJOR(dev->devt), MINOR(dev->devt)); + return err; + } clk->cdev.owner = clk->ops.owner; - err = cdev_add(&clk->cdev, devid, 1); + clk->dev = dev;
- return err; + return 0; } EXPORT_SYMBOL_GPL(posix_clock_register);
-static void delete_clock(struct kref *kref) -{ - struct posix_clock *clk = container_of(kref, struct posix_clock, kref); - - if (clk->release) - clk->release(clk); -} - void posix_clock_unregister(struct posix_clock *clk) { - cdev_del(&clk->cdev); + cdev_device_del(&clk->cdev, clk->dev);
down_write(&clk->rwsem); clk->zombie = true; up_write(&clk->rwsem);
- kref_put(&clk->kref, delete_clock); + put_device(clk->dev); } EXPORT_SYMBOL_GPL(posix_clock_unregister);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Vladis Dronov vdronov@redhat.com
commit 75718584cb3c64e6269109d4d54f888ac5a5fd15 upstream.
There is a bug in ptp_clock_unregister(), where ptp_cleanup_pin_groups() first frees ptp->pin_{,dev_}attr, but then posix_clock_unregister() needs them to destroy a related sysfs device.
These functions can not be just swapped, as posix_clock_unregister() frees ptp which is needed in the ptp_cleanup_pin_groups(). Fix this by calling ptp_cleanup_pin_groups() in ptp_clock_release(), right before ptp is freed.
This makes this patch fix an UAF bug in a patch which fixes an UAF bug.
Reported-by: Antti Laakso antti.laakso@intel.com Fixes: a33121e5487b ("ptp: fix the race between the release of ptp_clock and cdev") Link: https://lore.kernel.org/netdev/3d2bd09735dbdaf003585ca376b7c1e5b69a19bd.came... Signed-off-by: Vladis Dronov vdronov@redhat.com Acked-by: Richard Cochran richardcochran@gmail.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/ptp/ptp_clock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -171,6 +171,7 @@ static void ptp_clock_release(struct dev { struct ptp_clock *ptp = container_of(dev, struct ptp_clock, dev);
+ ptp_cleanup_pin_groups(ptp); mutex_destroy(&ptp->tsevq_mux); mutex_destroy(&ptp->pincfg_mux); ida_simple_remove(&ptp_clocks_map, ptp->index); @@ -271,9 +272,8 @@ int ptp_clock_unregister(struct ptp_cloc if (ptp->pps_source) pps_unregister_source(ptp->pps_source);
- ptp_cleanup_pin_groups(ptp); - posix_clock_unregister(&ptp->clock); + return 0; } EXPORT_SYMBOL(ptp_clock_unregister);
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mauro Carvalho Chehab m.chehab@samsung.com
commit 8b37c6455fc8f43e0e95db2847284e618db6a4f8 upstream.
Instead of allocating a var to store 0 and just return it, change the code to return 0 directly.
Signed-off-by: Mauro Carvalho Chehab m.chehab@samsung.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/media/media-devnode.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
--- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -192,7 +192,6 @@ static int media_open(struct inode *inod static int media_release(struct inode *inode, struct file *filp) { struct media_devnode *mdev = media_devnode_data(filp); - int ret = 0;
if (mdev->fops->release) mdev->fops->release(filp); @@ -201,7 +200,7 @@ static int media_release(struct inode *i return value is ignored. */ put_device(&mdev->dev); filp->private_data = NULL; - return ret; + return 0; }
static const struct file_operations media_devnode_fops = {
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Shuah Khan shuahkh@osg.samsung.com
commit d40ec6fdb0b03b7be4c7923a3da0e46bf943740a upstream.
Fix media_open() to clear filp->private_data when file open fails.
Signed-off-by: Shuah Khan shuahkh@osg.samsung.com Acked-by: Sakari Ailus sakari.ailus@linux.intel.com Signed-off-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/media/media-devnode.c | 1 + 1 file changed, 1 insertion(+)
--- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -181,6 +181,7 @@ static int media_open(struct inode *inod ret = mdev->fops->open(filp); if (ret) { put_device(&mdev->dev); + filp->private_data = NULL; return ret; } }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann max@duempel.org
commit bf244f665d76d20312c80524689b32a752888838 upstream.
Callbacks invoked from put_device() may free the struct media_devnode pointer, so any cleanup needs to be done before put_device().
Signed-off-by: Max Kellermann max@duempel.org Signed-off-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/media/media-devnode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -197,10 +197,11 @@ static int media_release(struct inode *i if (mdev->fops->release) mdev->fops->release(filp);
+ filp->private_data = NULL; + /* decrease the refcount unconditionally since the release() return value is ignored. */ put_device(&mdev->dev); - filp->private_data = NULL; return 0; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Max Kellermann max@duempel.org
commit 88336e174645948da269e1812f138f727cd2896b upstream.
We should protect the device unregister patch too, at the error condition.
Signed-off-by: Max Kellermann max@duempel.org Signed-off-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/media/media-devnode.c | 3 +++ 1 file changed, 3 insertions(+)
--- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -282,8 +282,11 @@ int __must_check media_devnode_register( return 0;
error: + mutex_lock(&media_devnode_lock); cdev_del(&mdev->cdev); clear_bit(mdev->minor, media_devnode_nums); + mutex_unlock(&media_devnode_lock); + return ret; }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mauro Carvalho Chehab mchehab@osg.samsung.com
commit 163f1e93e995048b894c5fc86a6034d16beed740 upstream.
Along all media controller code, "mdev" is used to represent a pointer to struct media_device, and "devnode" for a pointer to struct media_devnode.
However, inside media-devnode.[ch], "mdev" is used to represent a pointer to struct media_devnode.
This is very confusing and may lead to development errors.
So, let's change all occurrences at media-devnode.[ch] to also use "devnode" for such pointers.
This patch doesn't make any functional changes.
Signed-off-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com [bwh: Backported to 3.16: adjust filename, context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/media/media-devnode.c | 110 +++++++++++++++++----------------- include/media/media-devnode.h | 16 ++--- 2 files changed, 63 insertions(+), 63 deletions(-)
--- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -59,21 +59,21 @@ static DECLARE_BITMAP(media_devnode_nums /* Called when the last user of the media device exits. */ static void media_devnode_release(struct device *cd) { - struct media_devnode *mdev = to_media_devnode(cd); + struct media_devnode *devnode = to_media_devnode(cd);
mutex_lock(&media_devnode_lock);
/* Delete the cdev on this minor as well */ - cdev_del(&mdev->cdev); + cdev_del(&devnode->cdev);
/* Mark device node number as free */ - clear_bit(mdev->minor, media_devnode_nums); + clear_bit(devnode->minor, media_devnode_nums);
mutex_unlock(&media_devnode_lock);
/* Release media_devnode and perform other cleanups as needed. */ - if (mdev->release) - mdev->release(mdev); + if (devnode->release) + devnode->release(devnode); }
static struct bus_type media_bus_type = { @@ -83,37 +83,37 @@ static struct bus_type media_bus_type = static ssize_t media_read(struct file *filp, char __user *buf, size_t sz, loff_t *off) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp);
- if (!mdev->fops->read) + if (!devnode->fops->read) return -EINVAL; - if (!media_devnode_is_registered(mdev)) + if (!media_devnode_is_registered(devnode)) return -EIO; - return mdev->fops->read(filp, buf, sz, off); + return devnode->fops->read(filp, buf, sz, off); }
static ssize_t media_write(struct file *filp, const char __user *buf, size_t sz, loff_t *off) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp);
- if (!mdev->fops->write) + if (!devnode->fops->write) return -EINVAL; - if (!media_devnode_is_registered(mdev)) + if (!media_devnode_is_registered(devnode)) return -EIO; - return mdev->fops->write(filp, buf, sz, off); + return devnode->fops->write(filp, buf, sz, off); }
static unsigned int media_poll(struct file *filp, struct poll_table_struct *poll) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp);
- if (!media_devnode_is_registered(mdev)) + if (!media_devnode_is_registered(devnode)) return POLLERR | POLLHUP; - if (!mdev->fops->poll) + if (!devnode->fops->poll) return DEFAULT_POLLMASK; - return mdev->fops->poll(filp, poll); + return devnode->fops->poll(filp, poll); }
static long @@ -121,12 +121,12 @@ __media_ioctl(struct file *filp, unsigne long (*ioctl_func)(struct file *filp, unsigned int cmd, unsigned long arg)) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp);
if (!ioctl_func) return -ENOTTY;
- if (!media_devnode_is_registered(mdev)) + if (!media_devnode_is_registered(devnode)) return -EIO;
return ioctl_func(filp, cmd, arg); @@ -134,9 +134,9 @@ __media_ioctl(struct file *filp, unsigne
static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp);
- return __media_ioctl(filp, cmd, arg, mdev->fops->ioctl); + return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl); }
#ifdef CONFIG_COMPAT @@ -144,9 +144,9 @@ static long media_ioctl(struct file *fil static long media_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp);
- return __media_ioctl(filp, cmd, arg, mdev->fops->compat_ioctl); + return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl); }
#endif /* CONFIG_COMPAT */ @@ -154,7 +154,7 @@ static long media_compat_ioctl(struct fi /* Override for the open function */ static int media_open(struct inode *inode, struct file *filp) { - struct media_devnode *mdev; + struct media_devnode *devnode; int ret;
/* Check if the media device is available. This needs to be done with @@ -164,23 +164,23 @@ static int media_open(struct inode *inod * a crash. */ mutex_lock(&media_devnode_lock); - mdev = container_of(inode->i_cdev, struct media_devnode, cdev); + devnode = container_of(inode->i_cdev, struct media_devnode, cdev); /* return ENXIO if the media device has been removed already or if it is not registered anymore. */ - if (!media_devnode_is_registered(mdev)) { + if (!media_devnode_is_registered(devnode)) { mutex_unlock(&media_devnode_lock); return -ENXIO; } /* and increase the device refcount */ - get_device(&mdev->dev); + get_device(&devnode->dev); mutex_unlock(&media_devnode_lock);
- filp->private_data = mdev; + filp->private_data = devnode;
- if (mdev->fops->open) { - ret = mdev->fops->open(filp); + if (devnode->fops->open) { + ret = devnode->fops->open(filp); if (ret) { - put_device(&mdev->dev); + put_device(&devnode->dev); filp->private_data = NULL; return ret; } @@ -192,16 +192,16 @@ static int media_open(struct inode *inod /* Override for the release function */ static int media_release(struct inode *inode, struct file *filp) { - struct media_devnode *mdev = media_devnode_data(filp); + struct media_devnode *devnode = media_devnode_data(filp);
- if (mdev->fops->release) - mdev->fops->release(filp); + if (devnode->fops->release) + devnode->fops->release(filp);
filp->private_data = NULL;
/* decrease the refcount unconditionally since the release() return value is ignored. */ - put_device(&mdev->dev); + put_device(&devnode->dev); return 0; }
@@ -221,7 +221,7 @@ static const struct file_operations medi
/** * media_devnode_register - register a media device node - * @mdev: media device node structure we want to register + * @devnode: media device node structure we want to register * * The registration code assigns minor numbers and registers the new device node * with the kernel. An error is returned if no free minor number can be found, @@ -233,7 +233,7 @@ static const struct file_operations medi * the media_devnode structure is *not* called, so the caller is responsible for * freeing any data. */ -int __must_check media_devnode_register(struct media_devnode *mdev, +int __must_check media_devnode_register(struct media_devnode *devnode, struct module *owner) { int minor; @@ -251,40 +251,40 @@ int __must_check media_devnode_register( set_bit(minor, media_devnode_nums); mutex_unlock(&media_devnode_lock);
- mdev->minor = minor; + devnode->minor = minor;
/* Part 2: Initialize and register the character device */ - cdev_init(&mdev->cdev, &media_devnode_fops); - mdev->cdev.owner = owner; + cdev_init(&devnode->cdev, &media_devnode_fops); + devnode->cdev.owner = owner;
- ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1); + ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1); if (ret < 0) { pr_err("%s: cdev_add failed\n", __func__); goto error; }
/* Part 3: Register the media device */ - mdev->dev.bus = &media_bus_type; - mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor); - mdev->dev.release = media_devnode_release; - if (mdev->parent) - mdev->dev.parent = mdev->parent; - dev_set_name(&mdev->dev, "media%d", mdev->minor); - ret = device_register(&mdev->dev); + devnode->dev.bus = &media_bus_type; + devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor); + devnode->dev.release = media_devnode_release; + if (devnode->parent) + devnode->dev.parent = devnode->parent; + dev_set_name(&devnode->dev, "media%d", devnode->minor); + ret = device_register(&devnode->dev); if (ret < 0) { pr_err("%s: device_register failed\n", __func__); goto error; }
/* Part 4: Activate this minor. The char device can now be used. */ - set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); + set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
return 0;
error: mutex_lock(&media_devnode_lock); - cdev_del(&mdev->cdev); - clear_bit(mdev->minor, media_devnode_nums); + cdev_del(&devnode->cdev); + clear_bit(devnode->minor, media_devnode_nums); mutex_unlock(&media_devnode_lock);
return ret; @@ -292,7 +292,7 @@ error:
/** * media_devnode_unregister - unregister a media device node - * @mdev: the device node to unregister + * @devnode: the device node to unregister * * This unregisters the passed device. Future open calls will be met with * errors. @@ -300,16 +300,16 @@ error: * This function can safely be called if the device node has never been * registered or has already been unregistered. */ -void media_devnode_unregister(struct media_devnode *mdev) +void media_devnode_unregister(struct media_devnode *devnode) { - /* Check if mdev was ever registered at all */ - if (!media_devnode_is_registered(mdev)) + /* Check if devnode was ever registered at all */ + if (!media_devnode_is_registered(devnode)) return;
mutex_lock(&media_devnode_lock); - clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); + clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); mutex_unlock(&media_devnode_lock); - device_unregister(&mdev->dev); + device_unregister(&devnode->dev); }
/* --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -76,24 +76,24 @@ struct media_devnode { unsigned long flags; /* Use bitops to access flags */
/* callbacks */ - void (*release)(struct media_devnode *mdev); + void (*release)(struct media_devnode *devnode); };
/* dev to media_devnode */ #define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
-int __must_check media_devnode_register(struct media_devnode *mdev, +int __must_check media_devnode_register(struct media_devnode *devnode, struct module *owner); -void media_devnode_unregister(struct media_devnode *mdev); +void media_devnode_unregister(struct media_devnode *devnode);
static inline struct media_devnode *media_devnode_data(struct file *filp) { return filp->private_data; }
-static inline int media_devnode_is_registered(struct media_devnode *mdev) +static inline int media_devnode_is_registered(struct media_devnode *devnode) { - return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); + return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); }
#endif /* _MEDIA_DEVNODE_H */
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mauro Carvalho Chehab mchehab@osg.samsung.com
commit a087ce704b802becbb4b0f2a20f2cb3f6911802e upstream.
struct media_devnode is currently embedded at struct media_device.
While this works fine during normal usage, it leads to a race condition during devnode unregister. the problem is that drivers assume that, after calling media_device_unregister(), the struct that contains media_device can be freed. This is not true, as it can't be freed until userspace closes all opened /dev/media devnodes.
In other words, if the media devnode is still open, and media_device gets freed, any call to an ioctl will make the core to try to access struct media_device, with will cause an use-after-free and even GPF.
Fix this by dynamically allocating the struct media_devnode and only freeing it when it is safe.
Signed-off-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com [bwh: Backported to 3.16: - Drop change in au0828 - Include <linux/slab.h> in media-device.c - Adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -24,6 +24,7 @@ #include <linux/export.h> #include <linux/ioctl.h> #include <linux/media.h> +#include <linux/slab.h> #include <linux/types.h>
#include <media/media-device.h> @@ -236,7 +237,7 @@ static long media_device_ioctl(struct fi unsigned long arg) { struct media_devnode *devnode = media_devnode_data(filp); - struct media_device *dev = to_media_device(devnode); + struct media_device *dev = devnode->media_dev; long ret;
switch (cmd) { @@ -305,7 +306,7 @@ static long media_device_compat_ioctl(st unsigned long arg) { struct media_devnode *devnode = media_devnode_data(filp); - struct media_device *dev = to_media_device(devnode); + struct media_device *dev = devnode->media_dev; long ret;
switch (cmd) { @@ -346,7 +347,8 @@ static const struct media_file_operation static ssize_t show_model(struct device *cd, struct device_attribute *attr, char *buf) { - struct media_device *mdev = to_media_device(to_media_devnode(cd)); + struct media_devnode *devnode = to_media_devnode(cd); + struct media_device *mdev = devnode->media_dev;
return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); } @@ -374,6 +376,7 @@ static void media_device_release(struct int __must_check __media_device_register(struct media_device *mdev, struct module *owner) { + struct media_devnode *devnode; int ret;
if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0)) @@ -384,17 +387,27 @@ int __must_check __media_device_register spin_lock_init(&mdev->lock); mutex_init(&mdev->graph_mutex);
+ devnode = kzalloc(sizeof(*devnode), GFP_KERNEL); + if (!devnode) + return -ENOMEM; + /* Register the device node. */ - mdev->devnode.fops = &media_device_fops; - mdev->devnode.parent = mdev->dev; - mdev->devnode.release = media_device_release; - ret = media_devnode_register(&mdev->devnode, owner); - if (ret < 0) + mdev->devnode = devnode; + devnode->fops = &media_device_fops; + devnode->parent = mdev->dev; + devnode->release = media_device_release; + ret = media_devnode_register(mdev, devnode, owner); + if (ret < 0) { + mdev->devnode = NULL; + kfree(devnode); return ret; + }
- ret = device_create_file(&mdev->devnode.dev, &dev_attr_model); + ret = device_create_file(&devnode->dev, &dev_attr_model); if (ret < 0) { - media_devnode_unregister(&mdev->devnode); + mdev->devnode = NULL; + media_devnode_unregister(devnode); + kfree(devnode); return ret; }
@@ -415,8 +428,11 @@ void media_device_unregister(struct medi list_for_each_entry_safe(entity, next, &mdev->entities, list) media_device_unregister_entity(entity);
- device_remove_file(&mdev->devnode.dev, &dev_attr_model); - media_devnode_unregister(&mdev->devnode); + /* Check if mdev devnode was registered */ + if (media_devnode_is_registered(mdev->devnode)) { + device_remove_file(&mdev->devnode->dev, &dev_attr_model); + media_devnode_unregister(mdev->devnode); + } } EXPORT_SYMBOL_GPL(media_device_unregister);
--- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -44,6 +44,7 @@ #include <linux/uaccess.h>
#include <media/media-devnode.h> +#include <media/media-device.h>
#define MEDIA_NUM_DEVICES 256 #define MEDIA_NAME "media" @@ -74,6 +75,8 @@ static void media_devnode_release(struct /* Release media_devnode and perform other cleanups as needed. */ if (devnode->release) devnode->release(devnode); + + kfree(devnode); }
static struct bus_type media_bus_type = { @@ -221,6 +224,7 @@ static const struct file_operations medi
/** * media_devnode_register - register a media device node + * @media_dev: struct media_device we want to register a device node * @devnode: media device node structure we want to register * * The registration code assigns minor numbers and registers the new device node @@ -233,7 +237,8 @@ static const struct file_operations medi * the media_devnode structure is *not* called, so the caller is responsible for * freeing any data. */ -int __must_check media_devnode_register(struct media_devnode *devnode, +int __must_check media_devnode_register(struct media_device *mdev, + struct media_devnode *devnode, struct module *owner) { int minor; @@ -252,6 +257,7 @@ int __must_check media_devnode_register( mutex_unlock(&media_devnode_lock);
devnode->minor = minor; + devnode->media_dev = mdev;
/* Part 2: Initialize and register the character device */ cdev_init(&devnode->cdev, &media_devnode_fops); --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -60,7 +60,7 @@ struct device; struct media_device { /* dev->driver_data points to this struct. */ struct device *dev; - struct media_devnode devnode; + struct media_devnode *devnode;
char model[32]; char serial[40]; @@ -84,9 +84,6 @@ struct media_device { #define MEDIA_DEV_NOTIFY_PRE_LINK_CH 0 #define MEDIA_DEV_NOTIFY_POST_LINK_CH 1
-/* media_devnode to media_device */ -#define to_media_device(node) container_of(node, struct media_device, devnode) - int __must_check __media_device_register(struct media_device *mdev, struct module *owner); #define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE) --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1640,7 +1640,7 @@ static void uvc_delete(struct uvc_device if (dev->vdev.dev) v4l2_device_unregister(&dev->vdev); #ifdef CONFIG_MEDIA_CONTROLLER - if (media_devnode_is_registered(&dev->mdev.devnode)) + if (media_devnode_is_registered(dev->mdev.devnode)) media_device_unregister(&dev->mdev); #endif
--- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -33,6 +33,8 @@ #include <linux/device.h> #include <linux/cdev.h>
+struct media_device; + /* * Flag to mark the media_devnode struct as registered. Drivers must not touch * this flag directly, it will be set and cleared by media_devnode_register and @@ -63,6 +65,8 @@ struct media_file_operations { * before registering the node. */ struct media_devnode { + struct media_device *media_dev; + /* device ops */ const struct media_file_operations *fops;
@@ -82,7 +86,8 @@ struct media_devnode { /* dev to media_devnode */ #define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
-int __must_check media_devnode_register(struct media_devnode *devnode, +int __must_check media_devnode_register(struct media_device *mdev, + struct media_devnode *devnode, struct module *owner); void media_devnode_unregister(struct media_devnode *devnode);
@@ -93,6 +98,9 @@ static inline struct media_devnode *medi
static inline int media_devnode_is_registered(struct media_devnode *devnode) { + if (!devnode) + return false; + return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); }
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Shuah Khan shuahkh@osg.samsung.com
commit 5b28dde51d0ccc54cee70756e1800d70bed7114a upstream.
When driver unbinds while media_ioctl is in progress, cdev_put() fails with when app exits after driver unbinds.
Add devnode struct device kobj as the cdev parent kobject. cdev_add() gets a reference to it and releases it in cdev_del() ensuring that the devnode is not deallocated as long as the application has the device file open.
media_devnode_register() initializes the struct device kobj before calling cdev_add(). media_devnode_unregister() does cdev_del() and then deletes the device. devnode is released when the last reference to the struct device is gone.
This problem is found on uvcvideo, em28xx, and au0828 drivers and fix has been tested on all three.
kernel: [ 193.599736] BUG: KASAN: use-after-free in cdev_put+0x4e/0x50 kernel: [ 193.599745] Read of size 8 by task media_device_te/1851 kernel: [ 193.599792] INFO: Allocated in __media_device_register+0x54 kernel: [ 193.599951] INFO: Freed in media_devnode_release+0xa4/0xc0
kernel: [ 193.601083] Call Trace: kernel: [ 193.601093] [<ffffffff81aecac3>] dump_stack+0x67/0x94 kernel: [ 193.601102] [<ffffffff815359b2>] print_trailer+0x112/0x1a0 kernel: [ 193.601111] [<ffffffff8153b5e4>] object_err+0x34/0x40 kernel: [ 193.601119] [<ffffffff8153d9d4>] kasan_report_error+0x224/0x530 kernel: [ 193.601128] [<ffffffff814a2c3d>] ? kzfree+0x2d/0x40 kernel: [ 193.601137] [<ffffffff81539d72>] ? kfree+0x1d2/0x1f0 kernel: [ 193.601154] [<ffffffff8157ca7e>] ? cdev_put+0x4e/0x50 kernel: [ 193.601162] [<ffffffff8157ca7e>] cdev_put+0x4e/0x50 kernel: [ 193.601170] [<ffffffff815767eb>] __fput+0x52b/0x6c0 kernel: [ 193.601179] [<ffffffff8117743a>] ? switch_task_namespaces+0x2a kernel: [ 193.601188] [<ffffffff815769ee>] ____fput+0xe/0x10 kernel: [ 193.601196] [<ffffffff81170023>] task_work_run+0x133/0x1f0 kernel: [ 193.601204] [<ffffffff8117746e>] ? switch_task_namespaces+0x5e kernel: [ 193.601213] [<ffffffff8111b50c>] do_exit+0x72c/0x2c20 kernel: [ 193.601224] [<ffffffff8111ade0>] ? release_task+0x1250/0x1250 - - - kernel: [ 193.601360] [<ffffffff81003587>] ? exit_to_usermode_loop+0xe7 kernel: [ 193.601368] [<ffffffff810035c0>] exit_to_usermode_loop+0x120 kernel: [ 193.601376] [<ffffffff810061da>] syscall_return_slowpath+0x16a kernel: [ 193.601386] [<ffffffff82848b33>] entry_SYSCALL_64_fastpath+0xa6
Signed-off-by: Shuah Khan shuahkh@osg.samsung.com Tested-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/media/media-device.c | 6 +++-- drivers/media/media-devnode.c | 48 +++++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 21 deletions(-)
--- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -398,16 +398,16 @@ int __must_check __media_device_register devnode->release = media_device_release; ret = media_devnode_register(mdev, devnode, owner); if (ret < 0) { + /* devnode free is handled in media_devnode_*() */ mdev->devnode = NULL; - kfree(devnode); return ret; }
ret = device_create_file(&devnode->dev, &dev_attr_model); if (ret < 0) { + /* devnode free is handled in media_devnode_*() */ mdev->devnode = NULL; media_devnode_unregister(devnode); - kfree(devnode); return ret; }
@@ -432,6 +432,8 @@ void media_device_unregister(struct medi if (media_devnode_is_registered(mdev->devnode)) { device_remove_file(&mdev->devnode->dev, &dev_attr_model); media_devnode_unregister(mdev->devnode); + /* devnode free is handled in media_devnode_*() */ + mdev->devnode = NULL; } } EXPORT_SYMBOL_GPL(media_device_unregister); --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -63,13 +63,8 @@ static void media_devnode_release(struct struct media_devnode *devnode = to_media_devnode(cd);
mutex_lock(&media_devnode_lock); - - /* Delete the cdev on this minor as well */ - cdev_del(&devnode->cdev); - /* Mark device node number as free */ clear_bit(devnode->minor, media_devnode_nums); - mutex_unlock(&media_devnode_lock);
/* Release media_devnode and perform other cleanups as needed. */ @@ -77,6 +72,7 @@ static void media_devnode_release(struct devnode->release(devnode);
kfree(devnode); + pr_debug("%s: Media Devnode Deallocated\n", __func__); }
static struct bus_type media_bus_type = { @@ -205,6 +201,8 @@ static int media_release(struct inode *i /* decrease the refcount unconditionally since the release() return value is ignored. */ put_device(&devnode->dev); + + pr_debug("%s: Media Release\n", __func__); return 0; }
@@ -250,6 +248,7 @@ int __must_check media_devnode_register( if (minor == MEDIA_NUM_DEVICES) { mutex_unlock(&media_devnode_lock); pr_err("could not get a free minor\n"); + kfree(devnode); return -ENFILE; }
@@ -259,27 +258,31 @@ int __must_check media_devnode_register( devnode->minor = minor; devnode->media_dev = mdev;
+ /* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */ + devnode->dev.bus = &media_bus_type; + devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor); + devnode->dev.release = media_devnode_release; + if (devnode->parent) + devnode->dev.parent = devnode->parent; + dev_set_name(&devnode->dev, "media%d", devnode->minor); + device_initialize(&devnode->dev); + /* Part 2: Initialize and register the character device */ cdev_init(&devnode->cdev, &media_devnode_fops); devnode->cdev.owner = owner; + devnode->cdev.kobj.parent = &devnode->dev.kobj;
ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1); if (ret < 0) { pr_err("%s: cdev_add failed\n", __func__); - goto error; + goto cdev_add_error; }
- /* Part 3: Register the media device */ - devnode->dev.bus = &media_bus_type; - devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor); - devnode->dev.release = media_devnode_release; - if (devnode->parent) - devnode->dev.parent = devnode->parent; - dev_set_name(&devnode->dev, "media%d", devnode->minor); - ret = device_register(&devnode->dev); + /* Part 3: Add the media device */ + ret = device_add(&devnode->dev); if (ret < 0) { - pr_err("%s: device_register failed\n", __func__); - goto error; + pr_err("%s: device_add failed\n", __func__); + goto device_add_error; }
/* Part 4: Activate this minor. The char device can now be used. */ @@ -287,12 +290,15 @@ int __must_check media_devnode_register(
return 0;
-error: - mutex_lock(&media_devnode_lock); +device_add_error: cdev_del(&devnode->cdev); +cdev_add_error: + mutex_lock(&media_devnode_lock); clear_bit(devnode->minor, media_devnode_nums); + devnode->media_dev = NULL; mutex_unlock(&media_devnode_lock);
+ put_device(&devnode->dev); return ret; }
@@ -314,8 +320,12 @@ void media_devnode_unregister(struct med
mutex_lock(&media_devnode_lock); clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); + /* Delete the cdev on this minor as well */ + cdev_del(&devnode->cdev); mutex_unlock(&media_devnode_lock); - device_unregister(&devnode->dev); + device_del(&devnode->dev); + devnode->media_dev = NULL; + put_device(&devnode->dev); }
/*
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Shuah Khan shuahkh@osg.samsung.com
commit 6f0dd24a084a17f9984dd49dffbf7055bf123993 upstream.
Media devnode open/ioctl could be in progress when media device unregister is initiated. System calls and ioctls check media device registered status at the beginning, however, there is a window where unregister could be in progress without changing the media devnode status to unregistered.
process 1 process 2 fd = open(/dev/media0) media_devnode_is_registered() (returns true here)
media_device_unregister() (unregister is in progress and devnode isn't unregistered yet) ... ioctl(fd, ...) __media_ioctl() media_devnode_is_registered() (returns true here) ... media_devnode_unregister() ... (driver releases the media device memory)
media_device_ioctl() (By this point devnode->media_dev does not point to allocated memory. use-after free in in mutex_lock_nested)
BUG: KASAN: use-after-free in mutex_lock_nested+0x79c/0x800 at addr ffff8801ebe914f0
Fix it by clearing register bit when unregister starts to avoid the race.
process 1 process 2 fd = open(/dev/media0) media_devnode_is_registered() (could return true here)
media_device_unregister() (clear the register bit, then start unregister.) ... ioctl(fd, ...) __media_ioctl() media_devnode_is_registered() (return false here, ioctl returns I/O error, and will not access media device memory) ... media_devnode_unregister() ... (driver releases the media device memory)
Signed-off-by: Shuah Khan shuahkh@osg.samsung.com Suggested-by: Sakari Ailus sakari.ailus@linux.intel.com Reported-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Tested-by: Mauro Carvalho Chehab mchehab@osg.samsung.com Signed-off-by: Mauro Carvalho Chehab mchehab@s-opensource.com [bwh: Backported to 3.16: adjut filename, context] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -407,6 +407,7 @@ int __must_check __media_device_register if (ret < 0) { /* devnode free is handled in media_devnode_*() */ mdev->devnode = NULL; + media_devnode_unregister_prepare(devnode); media_devnode_unregister(devnode); return ret; } @@ -425,16 +426,16 @@ void media_device_unregister(struct medi struct media_entity *entity; struct media_entity *next;
+ /* Clear the devnode register bit to avoid races with media dev open */ + media_devnode_unregister_prepare(mdev->devnode); + list_for_each_entry_safe(entity, next, &mdev->entities, list) media_device_unregister_entity(entity);
- /* Check if mdev devnode was registered */ - if (media_devnode_is_registered(mdev->devnode)) { - device_remove_file(&mdev->devnode->dev, &dev_attr_model); - media_devnode_unregister(mdev->devnode); - /* devnode free is handled in media_devnode_*() */ - mdev->devnode = NULL; - } + device_remove_file(&mdev->devnode->dev, &dev_attr_model); + media_devnode_unregister(mdev->devnode); + /* devnode free is handled in media_devnode_*() */ + mdev->devnode = NULL; } EXPORT_SYMBOL_GPL(media_device_unregister);
--- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -302,6 +302,17 @@ cdev_add_error: return ret; }
+void media_devnode_unregister_prepare(struct media_devnode *devnode) +{ + /* Check if devnode was ever registered at all */ + if (!media_devnode_is_registered(devnode)) + return; + + mutex_lock(&media_devnode_lock); + clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); + mutex_unlock(&media_devnode_lock); +} + /** * media_devnode_unregister - unregister a media device node * @devnode: the device node to unregister @@ -309,17 +320,11 @@ cdev_add_error: * This unregisters the passed device. Future open calls will be met with * errors. * - * This function can safely be called if the device node has never been - * registered or has already been unregistered. + * Should be called after media_devnode_unregister_prepare() */ void media_devnode_unregister(struct media_devnode *devnode) { - /* Check if devnode was ever registered at all */ - if (!media_devnode_is_registered(devnode)) - return; - mutex_lock(&media_devnode_lock); - clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); /* Delete the cdev on this minor as well */ cdev_del(&devnode->cdev); mutex_unlock(&media_devnode_lock); --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -89,6 +89,20 @@ struct media_devnode { int __must_check media_devnode_register(struct media_device *mdev, struct media_devnode *devnode, struct module *owner); + +/** + * media_devnode_unregister_prepare - clear the media device node register bit + * @devnode: the device node to prepare for unregister + * + * This clears the passed device register bit. Future open calls will be met + * with errors. Should be called before media_devnode_unregister() to avoid + * races with unregister and device file open calls. + * + * This function can safely be called if the device node has never been + * registered or has already been unregistered. + */ +void media_devnode_unregister_prepare(struct media_devnode *devnode); + void media_devnode_unregister(struct media_devnode *devnode);
static inline struct media_devnode *media_devnode_data(struct file *filp)
3.16.83-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Richard Palethorpe rpalethorpe@suse.com
commit b9258a2cece4ec1f020715fe3554bc2e360f6264 upstream.
struct can_frame contains some padding which is not explicitly zeroed in slc_bump. This uninitialized data will then be transmitted if the stack initialization hardening feature is not enabled (CONFIG_INIT_STACK_ALL).
This commit just zeroes the whole struct including the padding.
Signed-off-by: Richard Palethorpe rpalethorpe@suse.com Fixes: a1044e36e457 ("can: add slcan driver for serial/USB-serial CAN adapters") Reviewed-by: Kees Cook keescook@chromium.org Cc: linux-can@vger.kernel.org Cc: netdev@vger.kernel.org Cc: security@kernel.org Cc: wg@grandegger.com Cc: mkl@pengutronix.de Cc: davem@davemloft.net Acked-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Ben Hutchings ben@decadent.org.uk --- drivers/net/can/slcan.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
--- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -150,7 +150,7 @@ static void slc_bump(struct slcan *sl) u32 tmpid; char *cmd = sl->rbuff;
- cf.can_id = 0; + memset(&cf, 0, sizeof(cf));
switch (*cmd) { case 'r': @@ -189,8 +189,6 @@ static void slc_bump(struct slcan *sl) else return;
- *(u64 *) (&cf.data) = 0; /* clear payload */ - /* RTR frames may have a dlc > 0 but they never have any data bytes */ if (!(cf.can_id & CAN_RTR_FLAG)) { for (i = 0; i < cf.can_dlc; i++) {
On Fri, Apr 24, 2020 at 1:03 AM Ben Hutchings ben@decadent.org.uk wrote:
This is the start of the stable review cycle for the 3.16.83 release. There are 245 patches in this series, which will be posted as responses to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Tue Apr 28 18:00:00 UTC 2020. Anything received after that time might be too late.
Can you please add backports of the following patches? I asked for that in https://lore.kernel.org/stable/CAG48ez29d-JJOw8XMp1Z=7sDj8Kvmt+9KXC9-ux-0OBhUP02Xg@mail.gmail.com/, but I guess that fell through the cracks somehow.
8019ad13ef7f64be44d4f892af9c840179009254 "futex: Fix inode life-time issue" 8d67743653dce5a0e7aa500fcccb237cde7ad88e "futex: Unbreak futex hashing"
Can those still go into 3.16.83, or is it too late for that now?
On Fri, 2020-04-24 at 01:59 +0200, Jann Horn wrote:
On Fri, Apr 24, 2020 at 1:03 AM Ben Hutchings ben@decadent.org.uk wrote:
This is the start of the stable review cycle for the 3.16.83 release. There are 245 patches in this series, which will be posted as responses to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Tue Apr 28 18:00:00 UTC 2020. Anything received after that time might be too late.
Can you please add backports of the following patches? I asked for that in https://lore.kernel.org/stable/CAG48ez29d-JJOw8XMp1Z=7sDj8Kvmt+9KXC9-ux-0OBhUP02Xg@mail.gmail.com/;, but I guess that fell through the cracks somehow.
Sorry I forgot about this,
8019ad13ef7f64be44d4f892af9c840179009254 "futex: Fix inode life-time issue" 8d67743653dce5a0e7aa500fcccb237cde7ad88e "futex: Unbreak futex hashing"
Can those still go into 3.16.83, or is it too late for that now?
I'll add them and send an -rc2.
Ben.
On 4/23/20 4:03 PM, Ben Hutchings wrote:
This is the start of the stable review cycle for the 3.16.83 release. There are 245 patches in this series, which will be posted as responses to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Tue Apr 28 18:00:00 UTC 2020. Anything received after that time might be too late.
For v3.16.82-245-g6e963df:
Build results: total: 135 pass: 135 fail: 0 Qemu test results: total: 233 pass: 233 fail: 0
Guenter
On Fri, 2020-04-24 at 07:49 -0700, Guenter Roeck wrote:
On 4/23/20 4:03 PM, Ben Hutchings wrote:
This is the start of the stable review cycle for the 3.16.83 release. There are 245 patches in this series, which will be posted as responses to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Tue Apr 28 18:00:00 UTC 2020. Anything received after that time might be too late.
For v3.16.82-245-g6e963df:
Build results: total: 135 pass: 135 fail: 0 Qemu test results: total: 233 pass: 233 fail: 0
Thanks for checking,
Ben.
This is the start of the stable review cycle for the 3.16.83 release. There are 247 patches in this series, which will be posted as responses to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Tue Apr 28 18:00:00 UTC 2020. Anything received after that time might be too late.
All the patches have also been committed to the linux-3.16.y-rc branch of https://git.kernel.org/pub/scm/linux/kernel/git/bwh/linux-stable-rc.git . A shortlog and diffstat can be found below.
Ben.
-------------
Al Viro (2): do_last(): fetch directory ->i_mode and ->i_uid before it's too late [d0cb50185ae942b03c4327be322055d622dc79f6] vfs: fix do_last() regression [6404674acd596de41fd3ad5f267b4525494a891a]
Alan Cox (1): usb: dwc3: pci: Add PCI ID for Intel Braswell [7d643664ea559b36188cae264047ce3c9bfec3a2]
Alan Stern (1): HID: Fix slab-out-of-bounds read in hid_field_extract [8ec321e96e056de84022c032ffea253431a83c3c]
Alberto Aguirre (2): ALSA: usb-audio: add implicit fb quirk for Axe-Fx II [17f08b0d9aafccdb10038ab6dbd9ddb6433c13e2] ALSA: usb-audio: simplify set_sync_ep_implicit_fb_quirk [103e9625647ad74d201e26fb74afcd8479142a37]
Alex Sverdlin (1): ARM: 8950/1: ftrace/recordmcount: filter relocation types [927d780ee371d7e121cea4fc7812f6ef2cea461c]
Amir Goldstein (1): locks: print unsigned ino in /proc/locks [98ca480a8f22fdbd768e3dad07024c8d4856576c]
Ard Biesheuvel (1): x86/efistub: Disable paging at mixed mode entry [4911ee401b7ceff8f38e0ac597cbf503d71e690c]
Arnd Bergmann (2): btrfs: tree-checker: use %zu format string for size_t [7cfad65297bfe0aa2996cd72d21c898aa84436d9] scsi: fnic: fix invalid stack access [42ec15ceaea74b5f7a621fc6686cbf69ca66c4cf]
Avinash Patil (1): mwifiex: fix probable memory corruption while processing TDLS frame [3c99832d74777c9ec5545a92450fac5d37b0d0e1]
Brian Norris (1): mwifiex: fix unbalanced locking in mwifiex_process_country_ie() [65b1aae0d9d5962faccc06bdb8e91a2a0b09451c]
Cengiz Can (1): blktrace: fix dereference after null check [153031a301bb07194e9c37466cfce8eacb977621]
Chao Yu (1): quota: fix wrong condition in is_quota_modification() [6565c182094f69e4ffdece337d395eb7ec760efc]
Chen-Yu Tsai (1): net: stmmac: dwmac-sunxi: Allow all RGMII modes [52cc73e5404c7ba0cbfc50cb4c265108c84b3d5a]
Christian Brauner (1): taskstats: fix data-race [0b8d616fb5a8ffa307b1d3af37f55c15dae14f28]
Christophe Leroy (1): powerpc/irq: fix stack overflow verification [099bc4812f09155da77eeb960a983470249c9ce1]
Cong Wang (2): net_sched: fix datalen for ematch [61678d28d4a45ef376f5d02a839cc37509ae9281] netfilter: fix a use-after-free in mtype_destroy() [c120959387efa51479056fd01dc90adfba7a590c]
Dan Carpenter (1): scsi: iscsi: qla4xxx: fix double free in probe [fee92f25777789d73e1936b91472e9c4644457c8]
David Hildenbrand (1): virtio-balloon: fix managed page counts when migrating pages between zones [63341ab03706e11a31e3dd8ccc0fbc9beaf723f0]
David Sterba (6): btrfs: add more checks to btrfs_read_sys_array [e3540eab29e1b2260bc4b9b3979a49a00e3e3af8] btrfs: cleanup, rename a few variables in btrfs_read_sys_array [1ffb22cf8c322bbfea6b35fe23d025841b49fede] btrfs: handle invalid num_stripes in sys_array [f5cdedd73fa71b74dcc42f2a11a5735d89ce7c4f] btrfs: kill extent_buffer_page helper [fb85fc9a675738ee2746b51c3aedde944b18ca02] btrfs: new define for the inline extent data start [7ec20afbcb7b257aec82ea5d66e6b0b7499abaca] btrfs: tree-check: reduce stack consumption in check_dir_item [e2683fc9d219430f5b78889b50cde7f40efeba7b]
Davidlohr Bueso (1): blktrace: re-write setting q->blk_trace [cdea01b2bf98affb7e9c44530108a4a28535eee8]
Dedy Lansky (1): cfg80211/mac80211: make ieee80211_send_layer2_update a public function [30ca1aa536211f5ac3de0173513a7a99a98a97f3]
Dmitry Torokhov (5): HID: hid-input: clear unmapped usages [4f3882177240a1f55e45a3d241d3121341bead78] Input: add safety guards to input_set_keycode() [cb222aed03d798fc074be55e59d9a112338ee784] ptp: create "pins" together with the rest of attributes [85a66e55019583da1e0f18706b7a8281c9f6de5b] ptp: do not explicitly set drvdata in ptp_clock_register() [882f312dc0751c973db26478f07f082c584d16aa] ptp: use is_visible method to hide unused attributes [af59e717d5ff9c8dbf9bcc581c0dfb3b2a9c9030]
Emiliano Ingrassia (1): usb: core: urb: fix URB structure initialization function [1cd17f7f0def31e3695501c4f86cd3faf8489840]
Eric Dumazet (9): 6pack,mkiss: fix possible deadlock [5c9934b6767b16ba60be22ec3cbd4379ad64170d] bonding: fix bond_neigh_init() [9e99bfefdbce2e23ef37487a3bcb4adf90a791d1] macvlan: do not assume mac_header is set in macvlan_broadcast() [96cc4b69581db68efc9749ef32e9cf8e0160c509] macvlan: use skb_reset_mac_header() in macvlan_queue_xmit() [1712b2fff8c682d145c7889d2290696647d82dab] neighbour: remove neigh_cleanup() method [f394722fb0d0f701119368959d7cd0ecbc46363a] netfilter: bridge: make sure to pull arp header in br_nf_forward_arp() [5604285839aaedfb23ebe297799c6e558939334d] pkt_sched: fq: do not accept silly TCA_FQ_QUANTUM [d9e15a2733067c9328fb56d98fe8e574fa19ec31] tcp: do not send empty skb from tcp_write_xmit() [1f85e6267caca44b30c54711652b0726fadbb131] vlan: vlan_changelink() should propagate errors [eb8ef2a3c50092bb018077c047b8dba1ce0e78e3]
Erkka Talvitie (1): USB: EHCI: Do not return -EPIPE when hub is disconnected [64cc3f12d1c7dd054a215bc1ff9cc2abcfe35832]
Eryu Guan (1): ext4: update c/mtime on truncate up [911af577de4e444622d46500c1f9a37ab4335d3a]
Eugenio Pérez (1): vhost: Check docket sk_family instead of call getname [42d84c8490f9f0931786f1623191fcab397c3d64]
Fabian Henneke (1): hidraw: Return EPOLLOUT from hidraw_poll [378b80370aa1fe50f9c48a3ac8af3e416e73b89f]
Felipe Balbi (3): usb: dwc3: pci: Add Support for Intel Elkhart Lake Devices [dbb0569de852fb4576d6f62078d515f989a181ca] usb: dwc3: pci: add support for Comet Lake PCH ID [7ae622c978db6b2e28b4fced6ecd2a174492059d] usb: dwc3: pci: add support for TigerLake Devices [b3649dee5fbb0f6585010e6e9313dfcbb075b22b]
Filipe Manana (3): Btrfs: fix emptiness check for dirtied extent buffers at check_leaf() [f177d73949bf758542ca15a1c1945bd2e802cc65] Btrfs: fix infinite loop during nocow writeback due to race [de7999afedff02c6631feab3ea726a0e8f8c3d40] Btrfs: fix removal logic of the tree mod log that leads to use-after-free issues [6609fee8897ac475378388238456c84298bff802]
Finn Thain (4): net/sonic: Add mutual exclusion for accessing shared state [865ad2f2201dc18685ba2686f13217f8b3a9c52c] net/sonic: Fix receive buffer handling [9e311820f67e740f4fb8dcb82b4c4b5b05bdd1a5] net/sonic: Quiesce SONIC before re-initializing descriptor memory [3f4b7e6a2be982fd8820a2b54d46dd9c351db899] net/sonic: Use MMIO accessors [e3885f576196ddfc670b3d53e745de96ffcb49ab]
Florian Faber (1): can: mscan: mscan_rx_poll(): fix rx path lockup when returning from polling to irq mode [2d77bd61a2927be8f4e00d9478fe6996c47e8d45]
Florian Westphal (6): netfilter: arp_tables: init netns pointer in xt_tgchk_param struct [1b789577f655060d98d20ed0c6f9fbd469d6ba63] netfilter: arp_tables: init netns pointer in xt_tgdtor_param struct [212e7f56605ef9688d0846db60c6c6ec06544095] netfilter: ctnetlink: netns exit must wait for callbacks [18a110b022a5c02e7dc9f6109d0bd93e58ac6ebb] netfilter: ebtables: compat: reject all padding in matches/watchers [e608f631f0ba5f1fc5ee2e260a3a35d13107cbfe] netfilter: ebtables: convert BUG_ONs to WARN_ONs [fc6a5d0601c5ac1d02f283a46f60b87b2033e5ca] netfilter: ipset: avoid null deref when IPSET_ATTR_LINENO is present [22dad713b8a5ff488e07b821195270672f486eb2]
Geert Uytterhoeven (1): gpio: Fix error message on out-of-range GPIO in lookup table [d935bd50dd14a7714cbdba9a76435dbb56edb1ae]
Goldwyn Rodrigues (1): dm flakey: check for null arg_name in parse_features() [7690e25302dc7d0cd42b349e746fe44b44a94f2b]
Gu Jinxiang (1): btrfs: validate type when reading a chunk [315409b0098fb2651d86553f0436b70502b29bb2]
Hangbin Liu (1): vxlan: fix tos value before xmit [71130f29979c7c7956b040673e6b9d5643003176]
Hans de Goede (2): pinctrl: baytrail: Really serialize all register accesses [40ecab551232972a39cdd8b6f17ede54a3fdb296] platform/x86: hp-wmi: Make buffer for HPWMI_FEATURE2_QUERY 128 bytes [133b2acee3871ae6bf123b8fe34be14464aa3d2c]
Heikki Krogerus (8): usb: dwc3: pci: add ID for one more Intel Broxton platform [1ffb4d5cc78a3a99109ff0808ce6915de07a0588] usb: dwc3: pci: add ID for the Intel Comet Lake -H variant [3c3caae4cd6e122472efcf64759ff6392fb6bce2] usb: dwc3: pci: add Intel Cannonlake PCI IDs [682179592e48fa66056fbad1a86604be4992f885] usb: dwc3: pci: add Intel Gemini Lake PCI ID [8f8983a5683623b62b339d159573f95a1fce44f3] usb: dwc3: pci: add Intel Kabylake PCI ID [4491ed5042f0419b22a4b08331adb54af31e2caa] usb: dwc3: pci: add support for Intel Broxton SOC [b4c580a43d520b7812c0fd064fbab929ce2f1da0] usb: dwc3: pci: add support for Intel IceLake [00908693c481f7298adf8cf4d2ff3dfbea8c375f] usb: dwc3: pci: add support for Intel Sunrise Point PCH [84a2b61b6eb94036093531cdabc448dddfbae45a]
Hou Tao (1): dm btree: increase rebalance threshold in __rebalance2() [474e559567fa631dea8fb8407ab1b6090c903755]
James Bottomley (1): scsi: enclosure: Fix stale device oops with hot replug [529244bd1afc102ab164429d338d310d5d65e60d]
Jan Kara (7): blktrace: Protect q->blk_trace with RCU [c780e86dd48ef6467a1146cf7d0fe1e05a635039] ext4: check for directory entries too close to block end [109ba779d6cca2d519c5dd624a3276d03e21948e] ext4: fix races between buffered IO and collapse / insert range [32ebffd3bbb4162da5ff88f9a35dd32d0a28ea70] ext4: fix races between page faults and hole punching [ea3d7209ca01da209cda6f0dea8be9cc4b7a933b] ext4: fix races of writeback with punch hole and zero range [011278485ecc3cd2a3954b5d4c73101d919bf1fa] ext4: move unlocked dio protection from ext4_alloc_file_blocks() [17048e8a083fec7ad841d88ef0812707fbc7e39f] kobject: Export kobject_get_unless_zero() [c70c176ff8c3ff0ac6ef9a831cd591ea9a66bd1a]
Jari Ruusu (1): Fix built-in early-load Intel microcode alignment [f5ae2ea6347a308cfe91f53b53682ce635497d0d]
Jeff Mahoney (2): btrfs: cleanup, stop casting for extent_map->lookup everywhere [95617d69326ce386c95e33db7aeb832b45ee9f8f] btrfs: struct-funcs, constify readers [1cbb1f454e5321e47fc1e6b233066c7ccc979d15]
Jerónimo Borque (1): USB: serial: simple: Add Motorola Solutions TETRA MTP3xxx and MTP85xx [260e41ac4dd3e5acb90be624c03ba7f019615b75]
Jian-Hong Pan (1): platform/x86: asus-wmi: Fix keyboard brightness cannot be set to 0 [176a7fca81c5090a7240664e3002c106d296bf31]
Jim Mattson (1): kvm: x86: Host feature SSBD doesn't imply guest feature SPEC_CTRL_SSBD [396d2e878f92ec108e4293f1c77ea3bc90b414ff]
Jiri Kosina (1): HID: hidraw, uhid: Always report EPOLLOUT [9e635c2851df6caee651e589fbf937b637973c91]
Jiri Slaby (4): vt: selection, close sel_buffer race [07e6124a1a46b4b5a9b3cacc0c306b50da87abf5] vt: selection, handle pending signals in paste_selection [687bff0cd08f790d540cfb7b2349f0d876cdddec] vt: selection, push console lock down [4b70dd57a15d2f4685ac6e38056bad93e81e982f] vt: selection, push sel_lock up [e8c75a30a23c6ba63f4ef6895cbf41fd42f21aa2]
Johan Hovold (29): ALSA: usb-audio: fix sync-ep altsetting sanity check [5d1b71226dc4d44b4b65766fa9d74492f9d4587b] Input: aiptek - fix endpoint sanity check [3111491fca4f01764e0c158c5e0f7ced808eef51] Input: gtco - fix endpoint sanity check [a8eeb74df5a6bdb214b2b581b14782c5f5a0cf83] Input: keyspan-remote - fix control-message timeouts [ba9a103f40fc4a3ec7558ec9b0b97d4f92034249] Input: sur40 - fix interface sanity checks [6b32391ed675827f8425a414abbc6fbd54ea54fe] USB: adutux: fix interface sanity check [3c11c4bed02b202e278c0f5c319ae435d7fb9815] USB: atm: ueagle-atm: add missing endpoint check [09068c1ad53fb077bdac288869dec2435420bdc4] USB: core: add endpoint-blacklist quirk [73f8bda9b5dc1c69df2bc55c0cbb24461a6391a9] USB: core: fix check for duplicate endpoints [3e4f8e21c4f27bcf30a48486b9dcc269512b79ff] USB: idmouse: fix interface sanity checks [59920635b89d74b9207ea803d5e91498d39e8b69] USB: quirks: blacklist duplicate ep on Sound Devices USBPre2 [bdd1b147b8026df0e4260b387026b251d888ed01] USB: serial: ch341: handle unbound port at reset_resume [4d5ef53f75c22d28f490bcc5c771fcc610a9afa4] USB: serial: io_edgeport: add missing active-port sanity check [1568c58d11a7c851bd09341aeefd6a1c308ac40d] USB: serial: io_edgeport: fix epic endpoint lookup [7c5a2df3367a2c4984f1300261345817d95b71f8] USB: serial: io_edgeport: handle unbound ports on URB completion [e37d1aeda737a20b1846a91a3da3f8b0f00cf690] USB: serial: keyspan: handle unbound ports [3018dd3fa114b13261e9599ddb5656ef97a1fa17] USB: serial: opticon: fix control-message timeouts [5e28055f340275a8616eee88ef19186631b4d136] USB: serial: quatech2: handle unbound ports [9715a43eea77e42678a1002623f2d9a78f5b81a1] USB: serial: suppress driver bind attributes [fdb838efa31e1ed9a13ae6ad0b64e30fdbd00570] can: gs_usb: gs_usb_probe(): use descriptors of current altsetting [2f361cd9474ab2c4ab9ac8db20faf81e66c6279b] media: ov519: add missing endpoint sanity checks [998912346c0da53a6dbb71fab3a138586b596b30] media: stv06xx: add missing descriptor sanity checks [485b06aadb933190f4bc44e006076bc27a23f205] media: xirlink_cit: add missing descriptor sanity checks [a246b4d547708f33ff4d4b9a7a5dbac741dc89d8] r8152: add missing endpoint sanity check [86f3f4cd53707ceeec079b83205c8d3c756eca93] staging: gigaset: add endpoint-type sanity check [ed9ed5a89acba51b82bdff61144d4e4a4245ec8a] staging: gigaset: fix general protection fault on probe [53f35a39c3860baac1e5ca80bf052751cfb24a99] staging: gigaset: fix illegal free on probe errors [84f60ca7b326ed8c08582417493982fe2573a9ad] staging: rtl8188eu: fix interface sanity check [74ca34118a0e05793935d804ccffcedd6eb56596] staging: rtl8712: fix interface sanity check [c724f776f048538ecfdf53a52b7a522309f5c504]
Johannes Thumshirn (1): btrfs: ensure that a DUP or RAID1 block group has exactly two stripes [349ae63f40638a28c6fce52e8447c2d14b84cc0c]
Jose Abreu (2): net: stmmac: 16KB buffer must be 16 byte aligned [8605131747e7e1fd8f6c9f97a00287aae2b2c640] net: stmmac: Enable 16KB buffer size [b2f3a481c4cd62f78391b836b64c0a6e72b503d2]
Josef Bacik (9): Btrfs: fix em leak in find_first_block_group [187ee58c62c1d0d238d3dc4835869d33e1869906] btrfs: abort transaction after failed inode updates in create_subvol [c7e54b5102bf3614cadb9ca32d7be73bad6cecf0] btrfs: check rw_devices, not num_devices for balance [b35cf1f0bf1f2b0b193093338414b9bd63b29015] btrfs: do not call synchronize_srcu() in inode_tree_del [f72ff01df9cf5db25c76674cac16605992d15467] btrfs: do not delete mismatched root refs [423a716cd7be16fb08690760691befe3be97d3fc] btrfs: do not leak reloc root if we fail to read the fs root [ca1aa2818a53875cfdd175fb5e9a2984e997cce9] btrfs: handle ENOENT in btrfs_uuid_tree_iterate [714cd3e8cba6841220dce9063a7388a81de03825] btrfs: skip log replay on orphaned roots [9bc574de590510eff899c3ca8dbaf013566b5efe] ext4: only call ext4_truncate when size <= isize [3da40c7b089810ac9cf2bb1e59633f619f3a7312]
Jouni Malinen (1): mac80211: Do not send Layer 2 Update frame before authorization [3e493173b7841259a08c5c8e5cbe90adb349da7e]
Kaitao Cheng (1): kernel/trace: Fix do not unregister tracepoints when register sched_migrate_task fail [50f9ad607ea891a9308e67b81f774c71736d1098]
Keiya Nobuta (1): usb: core: hub: Improved device recognition on remote wakeup [9c06ac4c83df6d6fbdbf7488fbad822b4002ba19]
Kenneth Klette Jonassen (1): pkt_sched: fq: avoid hang when quantum 0 [3725a269815ba6dbb415feddc47da5af7d1fac58]
Lars Möllendorf (1): iio: buffer: align the size of scan bytes to size of the largest element [883f616530692d81cb70f8a32d85c0d2afc05f69]
Leo Yan (1): tty: serial: msm_serial: Fix lockup for sysrq and oops [0e4f7f920a5c6bfe5e851e989f27b35a0cc7fb7e]
Linus Torvalds (1): floppy: check FDC index for errors before assigning it [2e90ca68b0d2f5548804f22f0dd61145516171e3]
Liu Bo (9): Btrfs: add validadtion checks for chunk loading [e06cd3dd7cea50e87663a88acdfdb7ac1c53a5ca] Btrfs: check btree node's nritems [053ab70f0604224c7893b43f9d9d5efa283580d6] Btrfs: check inconsistence between chunk and block group [6fb37b756acce6d6e045f79c3764206033f617b4] Btrfs: detect corruption when non-root leaf has zero item [1ba98d086fe3a14d6a31f2f66dbab70c45d00f63] Btrfs: fix BUG_ON in btrfs_mark_buffer_dirty [ef85b25e982b5bba1530b936e283ef129f02ab9d] Btrfs: improve check_node to avoid reading corrupted nodes [6b722c1747d533ac6d4df110dc8233db46918b65] Btrfs: kill BUG_ON in run_delayed_tree_ref [02794222c4132ac003e7281fb71f4ec1645ffc87] Btrfs: memset to avoid stale content in btree leaf [851cd173f06045816528176001cf82948282029c] Btrfs: memset to avoid stale content in btree node block [3eb548ee3a8042d95ad81be254e67a5222c24e03]
Logan Gunthorpe (1): chardev: add helper function to register char devs with a struct device [233ed09d7fdacf592ee91e6c97ce5f4364fbe7c0]
Lu Fengqi (1): btrfs: Remove redundant btrfs_release_path from btrfs_unlink_subvol [5b7d687ad5913a56b6a8788435d7a53990b4176d]
Lukas Czerner (1): ext4: wait for existing dio workers in ext4_alloc_file_blocks() [0d306dcf86e8f065dff42a4a934ae9d99af35ba5]
Luuk Paulussen (1): hwmon: (adt7475) Make volt2reg return same reg as reg2volt input [cf3ca1877574a306c0207cbf7fdf25419d9229df]
Mao Wenan (2): af_packet: set defaule value for tmo [b43d1f9f7067c6759b1051e8ecb84e82cef569fe] net: sonic: return NETDEV_TX_OK if failed to map buffer [6e1cdedcf0362fed3aedfe051d46bd7ee2a85fe1]
Marcel Holtmann (2): HID: hidraw: Fix returning EPOLLOUT from hidraw_poll [9f3b61dc1dd7b81e99e7ed23776bb64a35f39e1a] HID: uhid: Fix returning EPOLLOUT from uhid_char_poll [be54e7461ffdc5809b67d2aeefc1ddc9a91470c7]
Mathias Nyman (2): xhci: handle some XHCI_TRUST_TX_LENGTH quirks cases as default behaviour. [7ff11162808cc2ec66353fc012c58bb449c892c3] xhci: make sure interrupts are restored to correct state [bd82873f23c9a6ad834348f8b83f3b6a5bca2c65]
Mauro Carvalho Chehab (3): [media] media-device: dynamically allocate struct media_devnode [a087ce704b802becbb4b0f2a20f2cb3f6911802e] [media] media-devnode: fix namespace mess [163f1e93e995048b894c5fc86a6034d16beed740] [media] media-devnode: just return 0 instead of using a var [8b37c6455fc8f43e0e95db2847284e618db6a4f8]
Max Kellermann (2): [media] drivers/media/media-devnode: clear private_data before put_device() [bf244f665d76d20312c80524689b32a752888838] [media] media-devnode: add missing mutex lock in error handler [88336e174645948da269e1812f138f727cd2896b]
Michael Straube (1): staging: rtl8188eu: Add device code for TP-Link TL-WN727N v5.21 [58dcc5bf4030cab548d5c98cd4cd3632a5444d5a]
Michał Mirosław (1): mmc: sdhci: fix minimum clock rate for v3 controller [2a187d03352086e300daa2044051db00044cd171]
Mika Westerberg (4): pinctrl: baytrail: Clear interrupt triggering from pins that are in GPIO mode [95f0972c7e4cbf3fc68160131c5ac2f033481d00] pinctrl: baytrail: Relax GPIO request rules [f8323b6bb2cc7d26941d4838dd4375952980a88a] pinctrl: baytrail: Rework interrupt handling [31e4329f99062a06dca5a493bb4495a63b2dc6ba] pinctrl: baytrail: Serialize all register access [39ce8150a079e3ae6ed9abf26d7918a558ef7c19]
Mike Snitzer (1): dm flakey: fix reads to be issued if drop_writes configured [299f6230bc6d0ccd5f95bb0fb865d80a9c7d5ccc]
Mikulas Patocka (1): block: fix an integer overflow in logical block size [ad6bf88a6c19a39fb3b0045d78ea880325dfcf15]
Moni Shoua (1): IB/mlx4: Avoid executing gid task when device is being removed [4bf9715f184969dc703bde7be94919995024a6a9]
Nicolai Stange (2): libertas: don't exit from lbs_ibss_join_existing() with RCU read lock held [c7bf1fb7ddca331780b9a733ae308737b39f1ad4] libertas: make lbs_ibss_join_existing() return error code on rates overflow [1754c4f60aaf1e17d886afefee97e94d7f27b4cb]
Nikos Tsironis (1): dm thin metadata: Add support for a pre-commit callback [ecda7c0280e6b3398459dc589b9a41c1adb45529]
Pablo Neira Ayuso (2): netfilter: nf_tables: missing sanitization in data from userspace [71df14b0ce094be46d105b5a3ededd83b8e779a0] netfilter: nf_tables: validate NFT_DATA_VALUE after nft_data_init() [0d2c96af797ba149e559c5875c0151384ab6dd14]
Paolo Bonzini (1): KVM: nVMX: Don't emulate instructions in guest mode [07721feee46b4b248402133228235318199b05ec]
Parav Pandit (1): IB/mlx4: Follow mirror sequence of device add during device removal [89f988d93c62384758b19323c886db917a80c371]
Paul Cercueil (1): usb: musb: dma: Correct parameter passed to IRQ handler [c80d0f4426c7fdc7efd6ae8d8b021dcfc89b4254]
Pavel Tatashin (1): x86/pti/efi: broken conversion from efi to kernel page table [not upstream; fixes a bug specific to KAISER]
Pengcheng Yang (1): tcp: fix "old stuff" D-SACK causing SACK to be treated as D-SACK [c9655008e7845bcfdaac10a1ed8554ec167aea88]
Pete Zaitcev (1): usb: mon: Fix a deadlock in usbmon between mmap and read [19e6317d24c25ee737c65d1ffb7483bdda4bb54a]
Peter Hurley (1): tty: vt: Fix !TASK_RUNNING diagnostic warning from paste_selection() [61e86cc90af49cecef9c54ccea1f572fbcb695ac]
Peter Zijlstra (1): futex: Fix inode life-time issue [8019ad13ef7f64be44d4f892af9c840179009254]
Qize Wang (1): mwifiex: Fix heap overflow in mmwifiex_process_tdls_action_frame() [1e58252e334dc3f3756f424a157d1b7484464c40]
Qu Wenruo (14): btrfs: Add checker for EXTENT_CSUM [4b865cab96fe2a30ed512cf667b354bd291b3b0a] btrfs: Add sanity check for EXTENT_DATA when reading out leaf [40c3c40947324d9f40bf47830c92c59a9bbadf4a] btrfs: Check if item pointer overlaps with the item itself [7f43d4affb2a254d421ab20b0cf65ac2569909fb] btrfs: Check that each block group has corresponding chunk at mount time [514c7dca85a0bf40be984dab0b477403a6db901f] btrfs: Enhance chunk validation check [f04b772bfc17f502703794f4d100d12155c1a1a9] btrfs: Move leaf and node validation checker to tree-checker.c [557ea5dd003d371536f6b4e8f7c8209a2b6fd4e3] btrfs: Refactor check_leaf function for later expansion [c3267bbaa9cae09b62960eafe33ad19196803285] btrfs: Verify that every chunk has corresponding block group at mount time [7ef49515fa6727cb4b6f2f5b0ffbc5fc20a9f8c6] btrfs: tree-checker: Add checker for dir item [ad7b0368f33cffe67fecd302028915926e50ef7e] btrfs: tree-checker: Check level for leaves and nodes [f556faa46eb4e96d0d0772e74ecf66781e132f72] btrfs: tree-checker: Detect invalid and empty essential trees [ba480dd4db9f1798541eb2d1c423fc95feee8d36] btrfs: tree-checker: Enhance btrfs_check_node output [bba4f29896c986c4cec17bc0f19f2ce644fceae1] btrfs: tree-checker: Fix false panic for sanity test [69fc6cbbac542c349b3d350d10f6e394c253c81d] btrfs: tree-checker: Verify block_group_item [fce466eab7ac6baa9d2dcd88abcf945be3d4a089]
Radoslaw Tyl (1): ixgbevf: Remove limit of 10 entries for unicast filter list [aa604651d523b1493988d0bf6710339f3ee60272]
Rafael J. Wysocki (1): ACPI: PM: Avoid attaching ACPI PM domain to certain devices [b9ea0bae260f6aae546db224daa6ac1bd9d94b91]
Randy Dunlap (1): mm: mempolicy: require at least one nodeid for MPOL_PREFERRED [aa9f7d5172fac9bf1f09e678c35e287a40a7b7dd]
Richard Palethorpe (2): can, slip: Protect tty->disc_data in write_wakeup and close with RCU [0ace17d56824165c7f4c68785d6b58971db954dd] slcan: Don't transmit uninitialized stack data in padding [b9258a2cece4ec1f020715fe3554bc2e360f6264]
Russell King (2): gpiolib: fix up emulated open drain outputs [256efaea1fdc4e38970489197409a26125ee0aaa] mod_devicetable: fix PHY module format [d2ed49cf6c13e379c5819aa5ac20e1f9674ebc89]
Sabrina Dubroca (1): net: ipv6_stub: use ip6_dst_lookup_flow instead of ip6_dst_lookup [6c8991f41546c3c472503dff1ea9daaddf9331c2]
Salvatore Mesoraca (1): namei: allow restricted O_CREAT of FIFOs and regular files [30aba6656f61ed44cba445a3c0d38b296fa9e8f5]
Shaokun Zhang (1): btrfs: tree-checker: Fix misleading group system information [761333f2f50ccc887aa9957ae829300262c0d15b]
Shengjiu Wang (1): ASoC: wm8962: fix lambda value [556672d75ff486e0b6786056da624131679e0576]
Shuah Khan (3): [media] media: Fix media_open() to clear filp->private_data in error leg [d40ec6fdb0b03b7be4c7923a3da0e46bf943740a] [media] media: fix media devnode ioctl/syscall and unregister race [6f0dd24a084a17f9984dd49dffbf7055bf123993] [media] media: fix use-after-free in cdev_put() when app exits after driver unbind [5b28dde51d0ccc54cee70756e1800d70bed7114a]
Steven Rostedt (1): tracing: Have stack tracer compile when MCOUNT_INSN_SIZE is not defined [b8299d362d0837ae39e87e9019ebe6b736e0f035]
Sudip Mukherjee (2): tty: always relink the port [273f632912f1b24b642ba5b7eb5022e43a72f3b5] tty: link tty and port before configuring it as console [fb2b90014d782d80d7ebf663e50f96d8c507a73c]
Suren Baghdasaryan (1): staging: android: ashmem: Disallow ashmem memory from being remapped [6d67b0290b4b84c477e6a2fc6e005e174d3c7786]
Suwan Kim (1): usbip: Fix error path of vhci_recv_ret_submit() [aabb5b833872524eaf28f52187e5987984982264]
Sven Eckelmann (1): batman-adv: Fix DAT candidate selection on little endian systems [4cc4a1708903f404d2ca0dfde30e71e052c6cbc9]
Takashi Iwai (4): ALSA: hda/ca0132 - Avoid endless loop [cb04fc3b6b076f67d228a0b7d096c69ad486c09c] ALSA: ice1724: Fix sleep-in-atomic in Infrasonic Quartet support code [0aec96f5897ac16ad9945f531b4bef9a2edd2ebd] ALSA: pcm: Avoid possible info leaks from PCM stream buffers [add9d56d7b3781532208afbff5509d7382fb6efe] ALSA: seq: Fix racy access for queue timer in proc read [60adcfde92fa40fcb2dbf7cc52f9b096e0cd109a]
Thomas Gleixner (1): futex: Unbreak futex hashing [8d67743653dce5a0e7aa500fcccb237cde7ad88e]
Tom Lendacky (1): x86/microcode/AMD: Add support for fam17h microcode loading [f4e9b7af0cd58dd039a0fb2cd67d57cea4889abf]
Vivek Goyal (1): dm: do not override error code returned from dm_get_device() [e80d1c805a3b2f0ad2081369be5dc5deedd5ee59]
Vladis Dronov (2): ptp: fix the race between the release of ptp_clock and cdev [a33121e5487b424339636b25c35d3a180eaa5f5e] ptp: free ptp device pin descriptors properly [75718584cb3c64e6269109d4d54f888ac5a5fd15]
Wang Shilong (1): Btrfs: fix wrong max inline data size limit [c01a5c074c0f6f85a3b02e39432b9e5576ab51de]
Wei Yongjun (1): dm flakey: return -EINVAL on interval bounds error in flakey_ctr() [bff7e067ee518f9ed7e1cbc63e4c9e01670d0b71]
Wen Huang (1): libertas: Fix two buffer overflows at parsing bss descriptor [e5e884b42639c74b5b57dc277909915c0aefc8bb]
Wen Yang (1): ftrace: Avoid potential division by zero in function profiler [e31f7939c1c27faa5d0e3f14519eaf7c89e8a69d]
Will Deacon (1): chardev: Avoid potential use-after-free in 'chrdev_open()' [68faa679b8be1a74e6663c21c3a9d25d32f1c079]
Xiang Chen (1): scsi: sd: Clear sdkp->protection_type if disk is reformatted without PI [465f4edaecc6c37f81349233e84d46246bcac11a]
Xin Long (1): sctp: free cmd->obj.chunk for the unprocessed SCTP_CMD_REPLY [be7a7729207797476b6666f046d765bdf9630407]
YueHaibing (1): ptp: Fix pass zero to ERR_PTR() in ptp_clock_register [aea0a897af9e44c258e8ab9296fad417f1bc063a]
Zhang Xiaoxu (1): vgacon: Fix a UAF in vgacon_invert_region [513dc792d6060d5ef572e43852683097a8420f56]
Documentation/sysctl/fs.txt | 36 ++ Makefile | 4 +- arch/powerpc/kernel/irq.c | 4 +- arch/x86/boot/compressed/head_64.S | 5 + arch/x86/include/asm/kaiser.h | 10 + arch/x86/kernel/cpu/microcode/amd.c | 4 + arch/x86/kvm/cpuid.c | 3 +- arch/x86/kvm/vmx.c | 2 +- arch/x86/realmode/init.c | 4 +- arch/x86/realmode/rm/trampoline_64.S | 3 +- block/blk-settings.c | 2 +- drivers/acpi/device_pm.c | 12 +- drivers/block/floppy.c | 7 +- drivers/gpio/gpiolib.c | 13 +- drivers/hid/hid-core.c | 6 + drivers/hid/hid-input.c | 16 +- drivers/hid/hidraw.c | 7 +- drivers/hid/uhid.c | 5 +- drivers/hwmon/adt7475.c | 5 +- drivers/iio/industrialio-buffer.c | 6 +- drivers/infiniband/hw/mlx4/main.c | 16 +- drivers/input/input.c | 26 +- drivers/input/misc/keyspan_remote.c | 9 +- drivers/input/tablet/aiptek.c | 6 +- drivers/input/tablet/gtco.c | 10 +- drivers/input/touchscreen/sur40.c | 2 +- drivers/isdn/gigaset/usb-gigaset.c | 23 +- drivers/md/dm-crypt.c | 4 +- drivers/md/dm-delay.c | 16 +- drivers/md/dm-flakey.c | 40 +- drivers/md/dm-linear.c | 7 +- drivers/md/dm-raid1.c | 8 +- drivers/md/dm-snap-persistent.c | 2 +- drivers/md/dm-stripe.c | 8 +- drivers/md/dm-thin-metadata.c | 29 + drivers/md/dm-thin-metadata.h | 7 + drivers/md/persistent-data/dm-btree-remove.c | 8 +- drivers/md/raid0.c | 2 +- drivers/media/media-device.c | 43 +- drivers/media/media-devnode.c | 171 +++--- drivers/media/usb/gspca/ov519.c | 10 + drivers/media/usb/gspca/stv06xx/stv06xx.c | 19 +- drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c | 4 + drivers/media/usb/gspca/xirlink_cit.c | 18 +- drivers/media/usb/uvc/uvc_driver.c | 2 +- drivers/misc/enclosure.c | 3 +- drivers/mmc/host/sdhci.c | 10 +- drivers/net/bonding/bond_main.c | 40 +- drivers/net/can/mscan/mscan.c | 21 +- drivers/net/can/slcan.c | 16 +- drivers/net/can/usb/gs_usb.c | 4 +- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 5 - drivers/net/ethernet/natsemi/sonic.c | 113 +++- drivers/net/ethernet/natsemi/sonic.h | 25 +- drivers/net/ethernet/stmicro/stmmac/common.h | 5 +- drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +- drivers/net/hamradio/6pack.c | 4 +- drivers/net/hamradio/mkiss.c | 4 +- drivers/net/macvlan.c | 3 +- drivers/net/slip/slip.c | 12 +- drivers/net/usb/r8152.c | 3 + drivers/net/vxlan.c | 5 +- drivers/net/wireless/libertas/cfg.c | 18 +- drivers/net/wireless/mwifiex/sta_ioctl.c | 1 + drivers/net/wireless/mwifiex/tdls.c | 74 ++- drivers/pinctrl/pinctrl-baytrail.c | 212 ++++--- drivers/platform/x86/asus-wmi.c | 8 +- drivers/platform/x86/hp-wmi.c | 2 +- drivers/ptp/ptp_clock.c | 42 +- drivers/ptp/ptp_private.h | 9 +- drivers/ptp/ptp_sysfs.c | 162 +++--- drivers/scsi/fnic/vnic_dev.c | 20 +- drivers/scsi/qla4xxx/ql4_os.c | 1 - drivers/scsi/sd.c | 4 +- drivers/staging/android/ashmem.c | 28 + drivers/staging/rtl8188eu/os_dep/usb_intf.c | 3 +- drivers/staging/rtl8712/usb_intf.c | 2 +- drivers/staging/usbip/vhci_rx.c | 13 +- drivers/tty/serial/msm_serial.c | 13 +- drivers/tty/serial/serial_core.c | 1 + drivers/tty/vt/selection.c | 34 +- drivers/tty/vt/vt.c | 2 - drivers/usb/atm/ueagle-atm.c | 18 +- drivers/usb/core/config.c | 77 ++- drivers/usb/core/hub.c | 1 + drivers/usb/core/quirks.c | 37 ++ drivers/usb/core/urb.c | 1 + drivers/usb/core/usb.h | 3 + drivers/usb/dwc3/dwc3-pci.c | 30 + drivers/usb/host/ehci-q.c | 13 +- drivers/usb/host/xhci-hub.c | 8 +- drivers/usb/host/xhci-ring.c | 3 +- drivers/usb/misc/adutux.c | 2 +- drivers/usb/misc/idmouse.c | 2 +- drivers/usb/mon/mon_bin.c | 32 +- drivers/usb/musb/musbhsdma.c | 2 +- drivers/usb/serial/ch341.c | 6 +- drivers/usb/serial/io_edgeport.c | 26 +- drivers/usb/serial/keyspan.c | 4 + drivers/usb/serial/opticon.c | 2 +- drivers/usb/serial/quatech2.c | 6 + drivers/usb/serial/usb-serial-simple.c | 2 + drivers/usb/serial/usb-serial.c | 3 + drivers/vhost/net.c | 13 +- drivers/video/console/vgacon.c | 3 + drivers/virtio/virtio_balloon.c | 10 + firmware/Makefile | 2 +- fs/btrfs/Makefile | 2 +- fs/btrfs/ctree.c | 19 +- fs/btrfs/ctree.h | 157 +++--- fs/btrfs/dev-replace.c | 2 +- fs/btrfs/disk-io.c | 80 +-- fs/btrfs/extent-tree.c | 110 +++- fs/btrfs/extent_io.c | 98 ++-- fs/btrfs/extent_io.h | 25 +- fs/btrfs/extent_map.c | 2 +- fs/btrfs/extent_map.h | 10 +- fs/btrfs/inode.c | 8 +- fs/btrfs/ioctl.c | 10 +- fs/btrfs/relocation.c | 1 + fs/btrfs/root-tree.c | 10 +- fs/btrfs/scrub.c | 2 +- fs/btrfs/struct-funcs.c | 9 +- fs/btrfs/tree-checker.c | 649 ++++++++++++++++++++++ fs/btrfs/tree-checker.h | 38 ++ fs/btrfs/tree-log.c | 24 +- fs/btrfs/uuid-tree.c | 2 + fs/btrfs/volumes.c | 206 +++++-- fs/btrfs/volumes.h | 2 + fs/char_dev.c | 88 ++- fs/ext4/dir.c | 5 + fs/ext4/ext4.h | 13 + fs/ext4/extents.c | 89 +-- fs/ext4/file.c | 2 +- fs/ext4/inode.c | 117 +++- fs/ext4/super.c | 1 + fs/ext4/truncate.h | 2 + fs/inode.c | 1 + fs/locks.c | 2 +- fs/namei.c | 56 +- include/linux/blkdev.h | 10 +- include/linux/blktrace_api.h | 6 +- include/linux/cdev.h | 5 + include/linux/fs.h | 3 + include/linux/futex.h | 17 +- include/linux/if_ether.h | 8 + include/linux/kobject.h | 2 + include/linux/mod_devicetable.h | 4 +- include/linux/netfilter_arp/arp_tables.h | 2 +- include/linux/posix-clock.h | 19 +- include/linux/quotaops.h | 2 +- include/linux/usb/quirks.h | 3 + include/media/media-device.h | 5 +- include/media/media-devnode.h | 32 +- include/net/addrconf.h | 5 +- include/net/cfg80211.h | 11 + include/net/neighbour.h | 1 - kernel/futex.c | 93 ++-- kernel/sysctl.c | 18 + kernel/taskstats.c | 30 +- kernel/time/posix-clock.c | 31 +- kernel/trace/blktrace.c | 129 +++-- kernel/trace/ftrace.c | 6 +- kernel/trace/trace_sched_wakeup.c | 4 +- kernel/trace/trace_stack.c | 5 + lib/kobject.c | 5 +- mm/mempolicy.c | 6 +- net/8021q/vlan_netlink.c | 10 +- net/batman-adv/distributed-arp-table.c | 4 +- net/bridge/br_netfilter.c | 3 + net/bridge/netfilter/ebtables.c | 58 +- net/core/neighbour.c | 3 - net/ipv4/netfilter/arp_tables.c | 42 +- net/ipv4/netfilter/arptable_filter.c | 2 +- net/ipv4/tcp_input.c | 5 +- net/ipv4/tcp_output.c | 8 + net/ipv6/af_inet6.c | 2 +- net/mac80211/cfg.c | 55 +- net/mac80211/sta_info.c | 4 + net/netfilter/ipset/ip_set_bitmap_gen.h | 2 +- net/netfilter/ipset/ip_set_core.c | 3 +- net/netfilter/nf_conntrack_netlink.c | 3 + net/netfilter/nft_bitwise.c | 19 +- net/netfilter/nft_cmp.c | 18 +- net/packet/af_packet.c | 3 +- net/sched/ematch.c | 2 +- net/sched/sch_fq.c | 10 +- net/sctp/sm_sideeffect.c | 28 +- net/wireless/util.c | 45 ++ scripts/recordmcount.c | 17 + sound/core/pcm_native.c | 4 + sound/core/seq/seq_timer.c | 14 +- sound/pci/hda/patch_ca0132.c | 5 +- sound/pci/ice1712/ice1724.c | 9 +- sound/soc/codecs/wm8962.c | 4 +- sound/usb/pcm.c | 44 +- 197 files changed, 3378 insertions(+), 1230 deletions(-)
3.16.83-rc2 review patch. If anyone has any objections, please let me know.
------------------
From: Peter Zijlstra peterz@infradead.org
commit 8019ad13ef7f64be44d4f892af9c840179009254 upstream.
As reported by Jann, ihold() does not in fact guarantee inode persistence. And instead of making it so, replace the usage of inode pointers with a per boot, machine wide, unique inode identifier.
This sequence number is global, but shared (file backed) futexes are rare enough that this should not become a performance issue.
Reported-by: Jann Horn jannh@google.com Suggested-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Peter Zijlstra (Intel) peterz@infradead.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org [bwh: Backported to 3.16: Use atomic64_cmpxchg() instead of the _relaxed() variant which we don't have] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/inode.c | 1 + include/linux/fs.h | 1 + include/linux/futex.h | 17 +++++---- kernel/futex.c | 89 ++++++++++++++++++++++++++----------------- 4 files changed, 65 insertions(+), 43 deletions(-)
--- a/fs/inode.c +++ b/fs/inode.c @@ -131,6 +131,7 @@ int inode_init_always(struct super_block inode->i_sb = sb; inode->i_blkbits = sb->s_blocksize_bits; inode->i_flags = 0; + atomic64_set(&inode->i_sequence, 0); atomic_set(&inode->i_count, 1); inode->i_op = &empty_iops; inode->i_fop = &empty_fops; --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -570,6 +570,7 @@ struct inode { struct rcu_head i_rcu; }; u64 i_version; + atomic64_t i_sequence; /* see futex */ atomic_t i_count; atomic_t i_dio_count; atomic_t i_writecount; --- a/include/linux/futex.h +++ b/include/linux/futex.h @@ -39,23 +39,26 @@ handle_futex_death(u32 __user *uaddr, st
union futex_key { struct { + u64 i_seq; unsigned long pgoff; - struct inode *inode; - int offset; + unsigned int offset; } shared; struct { + union { + struct mm_struct *mm; + u64 __tmp; + }; unsigned long address; - struct mm_struct *mm; - int offset; + unsigned int offset; } private; struct { + u64 ptr; unsigned long word; - void *ptr; - int offset; + unsigned int offset; } both; };
-#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = NULL } } +#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = 0ULL } }
#ifdef CONFIG_FUTEX extern void exit_robust_list(struct task_struct *curr); --- a/kernel/futex.c +++ b/kernel/futex.c @@ -338,7 +338,7 @@ static void get_futex_key_refs(union fut
switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) { case FUT_OFF_INODE: - ihold(key->shared.inode); /* implies MB (B) */ + smp_mb(); /* explicit smp_mb(); (B) */ break; case FUT_OFF_MMSHARED: futex_get_mm(key); /* implies MB (B) */ @@ -362,7 +362,6 @@ static void drop_futex_key_refs(union fu
switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) { case FUT_OFF_INODE: - iput(key->shared.inode); break; case FUT_OFF_MMSHARED: mmdrop(key->private.mm); @@ -370,6 +369,46 @@ static void drop_futex_key_refs(union fu } }
+/* + * Generate a machine wide unique identifier for this inode. + * + * This relies on u64 not wrapping in the life-time of the machine; which with + * 1ns resolution means almost 585 years. + * + * This further relies on the fact that a well formed program will not unmap + * the file while it has a (shared) futex waiting on it. This mapping will have + * a file reference which pins the mount and inode. + * + * If for some reason an inode gets evicted and read back in again, it will get + * a new sequence number and will _NOT_ match, even though it is the exact same + * file. + * + * It is important that match_futex() will never have a false-positive, esp. + * for PI futexes that can mess up the state. The above argues that false-negatives + * are only possible for malformed programs. + */ +static u64 get_inode_sequence_number(struct inode *inode) +{ + static atomic64_t i_seq; + u64 old; + + /* Does the inode already have a sequence number? */ + old = atomic64_read(&inode->i_sequence); + if (likely(old)) + return old; + + for (;;) { + u64 new = atomic64_add_return(1, &i_seq); + if (WARN_ON_ONCE(!new)) + continue; + + old = atomic64_cmpxchg(&inode->i_sequence, 0, new); + if (old) + return old; + return new; + } +} + /** * get_futex_key() - Get parameters which are the keys for a futex * @uaddr: virtual address of the futex @@ -382,9 +421,15 @@ static void drop_futex_key_refs(union fu * * The key words are stored in *key on success. * - * For shared mappings, it's (page->index, file_inode(vma->vm_file), - * offset_within_page). For private mappings, it's (uaddr, current->mm). - * We can usually work out the index without swapping in the page. + * For shared mappings (when @fshared), the key is: + * ( inode->i_sequence, page->index, offset_within_page ) + * [ also see get_inode_sequence_number() ] + * + * For private mappings (or when !@fshared), the key is: + * ( current->mm, address, 0 ) + * + * This allows (cross process, where applicable) identification of the futex + * without keeping the page pinned for the duration of the FUTEX_WAIT. * * lock_page() might sleep, the caller should not hold a spinlock. */ @@ -545,8 +590,6 @@ again: key->private.mm = mm; key->private.address = address;
- get_futex_key_refs(key); /* implies smp_mb(); (B) */ - } else { struct inode *inode;
@@ -578,40 +621,14 @@ again: goto again; }
- /* - * Take a reference unless it is about to be freed. Previously - * this reference was taken by ihold under the page lock - * pinning the inode in place so i_lock was unnecessary. The - * only way for this check to fail is if the inode was - * truncated in parallel which is almost certainly an - * application bug. In such a case, just retry. - * - * We are not calling into get_futex_key_refs() in file-backed - * cases, therefore a successful atomic_inc return below will - * guarantee that get_futex_key() will still imply smp_mb(); (B). - */ - if (!atomic_inc_not_zero(&inode->i_count)) { - rcu_read_unlock(); - put_page(page_head); - - goto again; - } - - /* Should be impossible but lets be paranoid for now */ - if (WARN_ON_ONCE(inode->i_mapping != mapping)) { - err = -EFAULT; - rcu_read_unlock(); - iput(inode); - - goto out; - } - key->both.offset |= FUT_OFF_INODE; /* inode-based key */ - key->shared.inode = inode; + key->shared.i_seq = get_inode_sequence_number(inode); key->shared.pgoff = basepage_index(page); rcu_read_unlock(); }
+ get_futex_key_refs(key); /* implies smp_mb(); (B) */ + out: put_page(page_head); return err;
On Fri, Apr 24, 2020 at 04:51:31PM +0100, Ben Hutchings wrote:
3.16.83-rc2 review patch. If anyone has any objections, please let me know.
From: Peter Zijlstra peterz@infradead.org
commit 8019ad13ef7f64be44d4f892af9c840179009254 upstream.
Please do not forget:
8d67743653dc ("futex: Unbreak futex hashing")
which fixes this fix.
On Fri, 2020-04-24 at 17:56 +0200, Peter Zijlstra wrote:
On Fri, Apr 24, 2020 at 04:51:31PM +0100, Ben Hutchings wrote:
3.16.83-rc2 review patch. If anyone has any objections, please let me know.
From: Peter Zijlstra peterz@infradead.org
commit 8019ad13ef7f64be44d4f892af9c840179009254 upstream.
Please do not forget:
8d67743653dc ("futex: Unbreak futex hashing")
which fixes this fix.
I didn't, Jann reminded me to include both of them.
Ben.
3.16.83-rc2 review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner tglx@linutronix.de
commit 8d67743653dce5a0e7aa500fcccb237cde7ad88e upstream.
The recent futex inode life time fix changed the ordering of the futex key union struct members, but forgot to adjust the hash function accordingly,
As a result the hashing omits the leading 64bit and even hashes beyond the futex key causing a bad hash distribution which led to a ~100% performance regression.
Hand in the futex key pointer instead of a random struct member and make the size calculation based of the struct offset.
Fixes: 8019ad13ef7f ("futex: Fix inode life-time issue") Reported-by: Rong Chen rong.a.chen@intel.com Decoded-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Thomas Gleixner tglx@linutronix.de Tested-by: Rong Chen rong.a.chen@intel.com Link: https://lkml.kernel.org/r/87h7yy90ve.fsf@nanos.tec.linutronix.de Signed-off-by: Ben Hutchings ben@decadent.org.uk Cc: Jann Horn jannh@google.com --- kernel/futex.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/kernel/futex.c +++ b/kernel/futex.c @@ -309,9 +309,9 @@ static inline int hb_waiters_pending(str */ static struct futex_hash_bucket *hash_futex(union futex_key *key) { - u32 hash = jhash2((u32*)&key->both.word, - (sizeof(key->both.word)+sizeof(key->both.ptr))/4, + u32 hash = jhash2((u32 *)key, offsetof(typeof(*key), both.offset) / 4, key->both.offset); + return &futex_queues[hash & (futex_hashsize - 1)]; }
On 4/24/20 8:47 AM, Ben Hutchings wrote:
This is the start of the stable review cycle for the 3.16.83 release. There are 247 patches in this series, which will be posted as responses to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Tue Apr 28 18:00:00 UTC 2020. Anything received after that time might be too late.
For v3.16.82-247-gffbdbb4fe113:
Build results: total: 135 pass: 135 fail: 0 Qemu test results: total: 233 pass: 233 fail: 0
Guenter
On Fri, 2020-04-24 at 10:48 -0700, Guenter Roeck wrote:
On 4/24/20 8:47 AM, Ben Hutchings wrote:
This is the start of the stable review cycle for the 3.16.83 release. There are 247 patches in this series, which will be posted as responses to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Tue Apr 28 18:00:00 UTC 2020. Anything received after that time might be too late.
For v3.16.82-247-gffbdbb4fe113:
Build results: total: 135 pass: 135 fail: 0 Qemu test results: total: 233 pass: 233 fail: 0
Great, thanks for testing again.
Ben.
linux-stable-mirror@lists.linaro.org