Skip to content

Commit 64c8d4a

Browse files
committed
file-lock: fix type confusion in broken lease restore
When restoring a breaking lease, CRIU needs to first restore the pre-breaking state of the lease and then trigger the break again. Previously, restore_lease_prebreaking_state() was incorrectly using the file descriptor type (e.g., FD_TYPES__REG) instead of the lease type to determine which lease to set. This caused it to use O_RDONLY/O_WRONLY logic on a value that wasn't an open flag. Fix this by: 1. Passing the target lease type (with the LEASE_BREAKING bit cleared) to restore_lease_prebreaking_state(). 2. Updating set_file_lease() to optionally suppress error messages when a lease cannot be set (EWOULDBLOCK), which happens when we try to guess the original lease type. 3. In restore_lease_prebreaking_state(), try to set a read lease first if the target type is F_UNLCK. If it fails, or if the target type is F_RDLCK, try a write lease. This ensures that we correctly attempt to restore the original lease type even though it's not explicitly stored in the image when it's in the process of being broken. Reported-by: Prateek Singh Rathour <rathourprateek8@gmail.com> Signed-off-by: Andrei Vagin <avagin@google.com>
1 parent 33e340b commit 64c8d4a

File tree

1 file changed

+24
-10
lines changed

1 file changed

+24
-10
lines changed

criu/file-lock.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -495,9 +495,9 @@ static int break_lease(int lease_type, struct file_desc *desc)
495495
return open_path(desc, open_break_cb, (void *)&break_flags);
496496
}
497497

498-
static int set_file_lease(int fd, int type)
498+
static int set_file_lease(int fd, int type, bool can_fail)
499499
{
500-
int old_fsuid, ret;
500+
int saved_errno, old_fsuid, ret;
501501
struct stat st;
502502

503503
if (fstat(fd, &st)) {
@@ -512,19 +512,33 @@ static int set_file_lease(int fd, int type)
512512
old_fsuid = setfsuid(st.st_uid);
513513

514514
ret = fcntl(fd, F_SETLEASE, type);
515-
if (ret < 0)
516-
pr_perror("Can't set lease");
515+
saved_errno = errno;
516+
if (ret < 0) {
517+
if (!can_fail || errno != EWOULDBLOCK)
518+
pr_perror("Can't set lease");
519+
else
520+
pr_debug("The requested lease isn't available\n");
521+
}
517522

518523
setfsuid(old_fsuid);
524+
errno = saved_errno;
519525
return ret;
520526
}
521527

522-
static int restore_lease_prebreaking_state(int fd, int fd_type)
528+
static int restore_lease_prebreaking_state(int fd, int target_lease_type)
523529
{
524-
int access_flags = fd_type & O_ACCMODE;
525-
int lease_type = (access_flags == O_RDONLY) ? F_RDLCK : F_WRLCK;
530+
int lease_type = (target_lease_type == F_UNLCK) ? F_RDLCK : F_WRLCK;
526531

527-
return set_file_lease(fd, lease_type);
532+
/*
533+
* The origin lease type is unknown. Let's try the read one
534+
* then the write one.
535+
*/
536+
if (set_file_lease(fd, lease_type, /* can_fail = */ true)) {
537+
if (lease_type == F_WRLCK)
538+
return -1;
539+
return set_file_lease(fd, F_WRLCK, false);
540+
}
541+
return 0;
528542
}
529543

530544
static struct fdinfo_list_entry *find_fd_unordered(struct pstree_item *task, int fd)
@@ -550,7 +564,7 @@ static int restore_breaking_file_lease(FileLockEntry *fle)
550564
return -1;
551565
}
552566

553-
ret = restore_lease_prebreaking_state(fle->fd, fdle->desc->ops->type);
567+
ret = restore_lease_prebreaking_state(fle->fd, fle->type & (~LEASE_BREAKING));
554568
if (ret)
555569
return ret;
556570

@@ -594,7 +608,7 @@ static int restore_file_lease(FileLockEntry *fle)
594608
}
595609
return ret;
596610
} else {
597-
ret = set_file_lease(fle->fd, fle->type);
611+
ret = set_file_lease(fle->fd, fle->type, /* can_fail = */ false);
598612
if (ret < 0)
599613
pr_perror("Can't restore non breaking lease");
600614
return ret;

0 commit comments

Comments
 (0)