Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

block: fine-granular CAP_SYS_ADMIN for Persistent Reservation

Allow of unprivileged Persistent Reservation operations on devices
if the write permission check on the device node has passed.

brw-rw---- 1 root disk 259, 0 Jun 13 07:09 /dev/nvme0n1

In the example above, the "disk" group of nvme0n1 is also allowed to
make reservations on the device even without CAP_SYS_ADMIN.

Signed-off-by: Jingbo Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20230613084008.93795-3-jefflexu@linux.alibaba.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Jingbo Xu and committed by
Jens Axboe
9a72a024 12629621

+22 -19
+22 -19
block/ioctl.c
··· 254 254 EXPORT_SYMBOL(blkdev_compat_ptr_ioctl); 255 255 #endif 256 256 257 - static bool blkdev_pr_allowed(struct block_device *bdev) 257 + static bool blkdev_pr_allowed(struct block_device *bdev, blk_mode_t mode) 258 258 { 259 259 /* no sense to make reservations for partitions */ 260 260 if (bdev_is_partition(bdev)) ··· 262 262 263 263 if (capable(CAP_SYS_ADMIN)) 264 264 return true; 265 - 266 - return false; 265 + /* 266 + * Only allow unprivileged reservations if the file descriptor is open 267 + * for writing. 268 + */ 269 + return mode & BLK_OPEN_WRITE; 267 270 } 268 271 269 - static int blkdev_pr_register(struct block_device *bdev, 272 + static int blkdev_pr_register(struct block_device *bdev, blk_mode_t mode, 270 273 struct pr_registration __user *arg) 271 274 { 272 275 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; 273 276 struct pr_registration reg; 274 277 275 - if (!blkdev_pr_allowed(bdev)) 278 + if (!blkdev_pr_allowed(bdev, mode)) 276 279 return -EPERM; 277 280 if (!ops || !ops->pr_register) 278 281 return -EOPNOTSUPP; ··· 287 284 return ops->pr_register(bdev, reg.old_key, reg.new_key, reg.flags); 288 285 } 289 286 290 - static int blkdev_pr_reserve(struct block_device *bdev, 287 + static int blkdev_pr_reserve(struct block_device *bdev, blk_mode_t mode, 291 288 struct pr_reservation __user *arg) 292 289 { 293 290 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; 294 291 struct pr_reservation rsv; 295 292 296 - if (!blkdev_pr_allowed(bdev)) 293 + if (!blkdev_pr_allowed(bdev, mode)) 297 294 return -EPERM; 298 295 if (!ops || !ops->pr_reserve) 299 296 return -EOPNOTSUPP; ··· 305 302 return ops->pr_reserve(bdev, rsv.key, rsv.type, rsv.flags); 306 303 } 307 304 308 - static int blkdev_pr_release(struct block_device *bdev, 305 + static int blkdev_pr_release(struct block_device *bdev, blk_mode_t mode, 309 306 struct pr_reservation __user *arg) 310 307 { 311 308 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; 312 309 struct pr_reservation rsv; 313 310 314 - if (!blkdev_pr_allowed(bdev)) 311 + if (!blkdev_pr_allowed(bdev, mode)) 315 312 return -EPERM; 316 313 if (!ops || !ops->pr_release) 317 314 return -EOPNOTSUPP; ··· 323 320 return ops->pr_release(bdev, rsv.key, rsv.type); 324 321 } 325 322 326 - static int blkdev_pr_preempt(struct block_device *bdev, 323 + static int blkdev_pr_preempt(struct block_device *bdev, blk_mode_t mode, 327 324 struct pr_preempt __user *arg, bool abort) 328 325 { 329 326 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; 330 327 struct pr_preempt p; 331 328 332 - if (!blkdev_pr_allowed(bdev)) 329 + if (!blkdev_pr_allowed(bdev, mode)) 333 330 return -EPERM; 334 331 if (!ops || !ops->pr_preempt) 335 332 return -EOPNOTSUPP; ··· 341 338 return ops->pr_preempt(bdev, p.old_key, p.new_key, p.type, abort); 342 339 } 343 340 344 - static int blkdev_pr_clear(struct block_device *bdev, 341 + static int blkdev_pr_clear(struct block_device *bdev, blk_mode_t mode, 345 342 struct pr_clear __user *arg) 346 343 { 347 344 const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; 348 345 struct pr_clear c; 349 346 350 - if (!blkdev_pr_allowed(bdev)) 347 + if (!blkdev_pr_allowed(bdev, mode)) 351 348 return -EPERM; 352 349 if (!ops || !ops->pr_clear) 353 350 return -EOPNOTSUPP; ··· 549 546 case BLKTRACETEARDOWN: 550 547 return blk_trace_ioctl(bdev, cmd, argp); 551 548 case IOC_PR_REGISTER: 552 - return blkdev_pr_register(bdev, argp); 549 + return blkdev_pr_register(bdev, mode, argp); 553 550 case IOC_PR_RESERVE: 554 - return blkdev_pr_reserve(bdev, argp); 551 + return blkdev_pr_reserve(bdev, mode, argp); 555 552 case IOC_PR_RELEASE: 556 - return blkdev_pr_release(bdev, argp); 553 + return blkdev_pr_release(bdev, mode, argp); 557 554 case IOC_PR_PREEMPT: 558 - return blkdev_pr_preempt(bdev, argp, false); 555 + return blkdev_pr_preempt(bdev, mode, argp, false); 559 556 case IOC_PR_PREEMPT_ABORT: 560 - return blkdev_pr_preempt(bdev, argp, true); 557 + return blkdev_pr_preempt(bdev, mode, argp, true); 561 558 case IOC_PR_CLEAR: 562 - return blkdev_pr_clear(bdev, argp); 559 + return blkdev_pr_clear(bdev, mode, argp); 563 560 default: 564 561 return -ENOIOCTLCMD; 565 562 }