This fixes a kernel oops when reading ceph snapshot directories (.snap), for example by simply running `ls /mnt/my_ceph/.snap`. The variable str is guarded by __free(kfree), but advanced by one for skipping the initial '_' in snapshot names. Thus, kfree() is called with an invalid pointer. This patch removes the need for advancing the pointer so kfree() is called with correct memory pointer. Steps to reproduce: 1. Create snapshots on a cephfs volume (I've 63 snaps in my testcase) 2. Add cephfs mount to fstab $ echo "samba-fileserver@.files=/volumes/datapool/stuff/3461082b-ecc9-4e82-8549-3fd2590d3fb6 /mnt/test/stuff ceph acl,noatime,_netdev 0 0" >> /etc/fstab 3. Reboot the system $ systemctl reboot 4. Check if it's really mounted $ mount | grep stuff 5. List snapshots (expected 63 snapshots on my system) $ ls /mnt/test/stuff/.snap Now ls hangs forever and the kernel log shows the oops.
Unified · Split
| @@ -166,12 +166,13 @@ static struct inode *parse_longname(const struct inode *parent, · 165 unmodified lines | |||
| 166 | struct ceph_vino vino = { .snap = CEPH_NOSNAP }; | 166 | struct ceph_vino vino = { .snap = CEPH_NOSNAP }; |
| 167 | char *name_end, *inode_number; | 167 | char *name_end, *inode_number; |
| 168 | int ret = -EIO; | 168 | int ret = -EIO; |
| 169 | /* NUL-terminate */ | 169 | /* Snapshot name must start with an underscore */ |
| 170 | char *str __free(kfree) = kmemdup_nul(name, *name_len, GFP_KERNEL); | 170 | if (*name_len <= 0 || name[0] != '_') |
| 171 | return ERR_PTR(-EIO); | ||
| 172 | /* Skip initial '_' and NUL-terminate */ | ||
| 173 | char *str __free(kfree) = kmemdup_nul(name + 1, *name_len - 1, GFP_KERNEL); | ||
| 171 | if (!str) | 174 | if (!str) |
| 172 | return ERR_PTR(-ENOMEM); | 175 | return ERR_PTR(-ENOMEM); |
| 173 | /* Skip initial '_' */ | ||
| 174 | str++; | ||
| 175 | name_end = strrchr(str, '_'); | 176 | name_end = strrchr(str, '_'); |
| 176 | if (!name_end) { | 177 | if (!name_end) { |
| 177 | doutc(cl, "failed to parse long snapshot name: %s\n", str); | 178 | doutc(cl, "failed to parse long snapshot name: %s\n", str); |