• Robbie Ko's avatar
    Btrfs: send, fix invalid leaf accesses due to incorrect utimes operations · 764433a1
    Robbie Ko authored
    During an incremental send, if we have delayed rename operations for inodes
    that were children of directories which were removed in the send snapshot,
    we can end up accessing incorrect items in a leaf or accessing beyond the
    last item of the leaf due to issuing utimes operations for the removed
    inodes. Consider the following example:
    
      Parent snapshot:
      .                                                             (ino 256)
      |--- a/                                                       (ino 257)
      |    |--- c/                                                  (ino 262)
      |
      |--- b/                                                       (ino 258)
      |    |--- d/                                                  (ino 263)
      |
      |--- del/                                                     (ino 261)
            |--- x/                                                 (ino 259)
            |--- y/                                                 (ino 260)
    
      Send snapshot:
    
      .                                                             (ino 256)
      |--- a/                                                       (ino 257)
      |
      |--- b/                                                       (ino 258)
      |
      |--- c/                                                       (ino 262)
      |    |--- y/                                                  (ino 260)
      |
      |--- d/                                                       (ino 263)
           |--- x/                                                  (ino 259)
    
    1) When processing inodes 259 and 260, we end up delaying their rename
       operations because their parents, inodes 263 and 262 respectively, were
       not yet processed and therefore not yet renamed;
    
    2) When processing inode 262, its rename operation is issued and right
       after the rename operation for inode 260 is issued. However right after
       issuing the rename operation for inode 260, at send.c:apply_dir_move(),
       we issue utimes operations for all current and past parents of inode
       260. This means we try to send a utimes operation for its old parent,
       inode 261 (deleted in the send snapshot), which does not cause any
       immediate and deterministic failure, because when the target inode is
       not found in the send snapshot, the send.c:send_utimes() function
       ignores it and uses the leaf region pointed to by path->slots[0],
       which can be any unrelated item (belonging to other inode) or it can
       be a region outside the leaf boundaries, if the leaf is full and
       path->slots[0] matches the number of items in the leaf. So we end
       up either successfully sending a utimes operation, which is fine
       and irrelevant because the old parent (inode 261) will end up being
       deleted later, or we end up doing an invalid memory access tha
       crashes the kernel.
    
    So fix this by making apply_dir_move() issue utimes operations only for
    parents that still exist in the send snapshot. In a separate patch we
    will make send_utimes() return an error (-ENOENT) if the given inode
    does not exists in the send snapshot.
    Signed-off-by: default avatarRobbie Ko <robbieko@synology.com>
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    [Rewrote change log to be more detailed and better organized]
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    764433a1
send.c 149 KB