Bug 216213

Summary: UBIFS: In encrypted directories, truncate operation causes ubifs to be read-only.
Product: File System Reporter: wangzhaolong1
Component: OtherAssignee: fs_other
Status: NEW ---    
Severity: high    
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 5.19.0 -rc5 Subsystem:
Regression: No Bisected commit-id:
Attachments: In the truncate_data_node() function, the length of the compressed data after truncation may be greater than the length of the compressed data before truncation.

Description wangzhaolong1 2022-07-07 09:15:58 UTC
[kernel config]:
CONFIG_MTD_NAND_NANDSIM=m
CONFIG_MTD_UBI=m
CONFIG_UBIFS_FS=m
CONFIG_UBIFS_FS_ADVANCED_COMPR=y
CONFIG_UBIFS_FS_LZO=y
CONFIG_UBIFS_FS_ZLIB=y
CONFIG_UBIFS_FS_ZSTD=y
CONFIG_UBIFS_ATIME_SUPPORT=y
CONFIG_UBIFS_FS_XATTR=y
CONFIG_UBIFS_FS_SECURITY=y
CONFIG_UBIFS_FS_AUTHENTICATION=y

[tool]:
fscryptctl - https://github.com/google/fscryptctl

[shell script to reproduce the problem]:
~~~shell
#/bin/bash

trap "remove_ubifs > /dev/null 2>&1" EXIT INT
function init_ubifs()
{
    mount_point=/mnt
    encrypt_dir=/mnt/dir
    ID="0x20,0xaa,0x00,0x15"

    remove_ubifs
    modprobe nandsim id_bytes=$ID
    modprobe ubi mtd=0
    flash_erase /dev/mtd0 0 0
    ubiattach -m0 #2>/dev/null
    modprobe ubifs
    ubimkvol -N vol_a -m -n 0 /dev/ubi0
    #mkfs.ubifs /dev/ubi0_0
    dmesg -C
    mount -t ubifs /dev/ubi0_0 /mnt -o sync,compr=lzo
}

function remove_ubifs()
{
    if mountpoint -q $mount_point;then
        umount $mount_point
    fi
    ubidetach -p /dev/mtd0 2>/dev/null
    modprobe -r ubifs 2>/dev/null
    modprobe -r ubi 2>/dev/null
    modprobe -r nandsim 2>/dev/null
}

function encrypt_mountpoint()
{

    head -c 64 /dev/urandom > /tmp/test_key
    # Add an Encryption Key
    key_id=$(fscryptctl add_key /mnt < /tmp/test_key)
    # set encrypt policy
    fscryptctl set_policy $key_id /mnt 
    fscryptctl get_policy /mnt
}

# truncation size less than 128 byte
# When simple data is generated, the compression ratio of the data is very high. The compressed data size is less than 128 bytes.
# In this case, the data is truncated to a size that is not compressed.
function case1()
{
    echo “--case 1 :truncation size less than 128 byte---”
    init_ubifs
    encrypt_mountpoint
    dmesg -C
    dd if=/dev/zero bs=1 count=1024 of=/mnt/file
    truncate -s 127 /mnt/file
    dmesg -c
    echo foo > /mnt/foo.txt
    test $? -ne 0 && echo "case 1 success!"
    remove_ubifs #> /dev/null 2>&1
}

function case2()
{
    echo “--case 2 :truncation size great than 128 byte---”
    init_ubifs
    encrypt_mountpoint
    dmesg -C
    # Constructing data for lzo compressor
xxd -r -ps > /mnt/file0 << EOF
df 3f df 4f df c4 df 77 df ab df 46 df af df 86 df b6 df 39 df 29 df 5c df 5f df 83 df 4e df 77
df df df f2 df 6d df a1 df cb df b5 df 54 df c7 df 1e df 40 df 1c df 4b df 76 df 95 df 7e df 67
df 2d df bb df 76 df 1c df c3 df 15 df b7 df a9 df f6 df d9 df 7a df e9 df 42 df 4b df 0d df fa
df a1 df dc df b4 df f6 df aa df e2 df da df 26 df 67 df bb df 2e df 6c df e3 df 70 df 6d df 5a
df d0 df 86 df 81 df fc df ef df e9 df 69 df 11 df 58 df 93 df ce df 5d df 3c df f5 df 66 df 3c
df 00 df 1f df aa df 1e df ee df df df 14 df bb df 66 df 18 df 99 df 8a df 60 df ec df f8 df 52
df b8 df de df 11 df 7b df cb df 0e df c2 df 54 df 1b df f4 df af df c8 df 54 df d7 df 3b df fd
df d3 df b9 df a5 df 7b df dc df 45 df d1 df 5f df 61 df f0 df 99 df 2d df 63 df ae df bd df cb
df e7 df 43 df 98 df e8 df 3b df 28 df fe df 03 df 9b df c4 df 72 df 5c df 73 df b8 df 27 df 48
df 98 df 22 df 2c df 17 df 96 df 0d df 6c df 18 df d7 df ad df 62 df 07 df 66 df a6 df 33 df 12
df 53 df 6b df ff df 88 df 73 df 99 df 09 df dd df f9 df ac df d2 df 84 df f1 df 7e df 8a df 95
df 03 df 9d df 3b df 26 df 3b df 6e df 94 df ca df 2d df b7 df 01 df bd df f2 df 38 df 4c df ee
df a5 df 4e df 0d df 91 df 44 df d1 df 1c df 78 df f7 df 5e df 40 df 1c df 72 df 0e df 36 df 2e
df a5 df 8f df 04 df 2a df b9 df b5 df 34 df 0b df 12 df 13 df 31 df 4d df a3 df 6e df 08 df 93
df 64 df 51 df b2 df 06 df 1b df cc df b6 df bc df 1d df 91 df 66 df a9 df 5e df 36 df 41 df 6d
df 13 df c3 df 81 df 2c df 1a df ba df b2 df f0 df 47 df b8 df ff df f8 df 19 df 70 df 7a df af
df d5 df 19 df 6d df ce df 6e df 39 df 51 df 63 df 90 df ed df 84 df 1b df 78 df 65 df 11 df 70
df 25 df f7 df c5 df 24 df 67 df d3 df 89 df 54 df 34 df ad df 2f df ed df d0 df d2 df 86 df 65
df d9 df 22 df 45 df 2e df 99 df 45 df 13 df 6c df c7 df 41 df ea df aa df e5 df ae df df df a7
df f1 df af df 6c df 69 df 4d df 8a df e3 df ad df ad df 52 df f1 df a0 df 44 df ed df 99 df db
df a1 df 16 df 75 df 4e df 73 df b2 df 99 df 4a df b3 df f5 df ba df d4 df 3c df b0 df 55 df ad
df f8 df 92 df a5 df 9f df df df 96 df 2d df 77 df ea df 45 df 58 df b0 df de df e3 df 58 df 4a
df 8d df 50 df 0a df fe df 1c df 87 df 9b df bf df 5b df 34 df 72 df 07 df 9c df 7a df 71 df 4c
df 2f df ca df de df 17 df e1 df e8 df f0 df 1e df 75 df f3 df 9f df 01 df 16 df 79 df 4b df 97
df b0 df 1b df b1 df a7 df dc df f9 df fd df 9f df 35 df d6 df c8 df c8 df 50 df 05 df eb df c7
df ca df 08 df da df 40 df e2 df d5 df 2b df 38 df b8 df a7 df 8b df da df 6b df 33 df 11 df 4a
df 2e df a8 df f3 df 69 df 41 df aa df fa df c8 df 1f df 94 df e9 df ea df 79 df 15 df b6 df 0f
df bc df 3b df fb df 74 df db df b8 df 6e df ba df cc df b6 df ce df d2 df 9a df 7c df 23 df 43
df 75 df d2 df 66 df 05 df b9 df ea df 2e df ef df fb df 7f df a2 df cd df f6 df 2b df d0 df 1d
df d8 df 7b df 0c df 19 df 80 df 95 df a2 df 61 df ef df 2f df d9 df 21 df 38 df 20 df 2f df e1
df 64 df 18 df ed df a3 df 5d df a6 df ce df 85 df d5 df 57 df 13 df 41 df 22 df a5 df 6a df f4
df 2d df f8 df 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
EOF
    truncate -s 1086 /mnt/file0
    dmesg -c
    echo foo > /mnt/foo.txt
    test $? -ne 0 && echo "case 2 success!"
    remove_ubifs # /dev/null 2>&1
}

case1
case2
echo "done"
~~~
------------------------------------------------------------------------------

Run the script to obtain the following result:

~~~shell
[15015.478139] UBIFS error (ubi0:0 pid 9907): ubifs_assert_failed [ubifs]: UBIFS assert failed: pad_len <= *out_len, in fs/ubifs/crypto.c:35
[15015.480282] UBIFS warning (ubi0:0 pid 9907): ubifs_ro_mode [ubifs]: switched to read-only mode, error -22
[15015.481905] CPU: 3 PID: 9907 Comm: truncate Not tainted 5.10.0-13346-g79fd47be422e #8
[15015.483150] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ?-20190727_073836-buildvm-ppc64le-16.ppc.fedoraproject.org-3.fc31 04/01/2014
[15015.485324] Call Trace:
[15015.485726]  ? dump_stack+0xa6/0xd5
[15015.486299]  ? ubifs_ro_mode+0x54/0x60 [ubifs]
[15015.487014]  ? ubifs_assert_failed+0x4b/0x80 [ubifs]
[15015.487732]  ? ubifs_encrypt+0x145/0x170 [ubifs]
[15015.488359]  ? ubifs_jnl_truncate+0xc0f/0xda0 [ubifs]
[15015.489050]  ? put_object+0x3b/0x80
[15015.489550]  ? __delete_object+0x4d/0xa0
[15015.490123]  ? __cond_resched+0x1d/0x50
[15015.490683]  ? down_write+0x16/0x70
[15015.491161]  ? __cond_resched+0x1d/0x50
[15015.491690]  ? pagecache_get_page+0x4ab/0x990
[15015.492302]  ? ubifs_setattr+0x4f9/0x8c0 [ubifs]
[15015.492952]  ? selinux_inode_setattr+0xae/0x180
[15015.493589]  ? notify_change+0x3eb/0x760
[15015.494121]  ? do_truncate+0x98/0x130
[15015.494627]  ? do_truncate+0x98/0x130
[15015.495155]  ? do_sys_ftruncate+0x1c4/0x2f0
[15015.495751]  ? __x64_sys_ftruncate+0x1f/0x30
[15015.496361]  ? do_syscall_64+0x45/0x70
[15015.496912]  ? entry_SYSCALL_64_after_hwframe+0x44/0xa9
[15015.497790] UBIFS error (ubi0:0 pid 9907): make_reservation [ubifs]: cannot reserve 392 bytes in jhead 1, error -30
test10000.sh: line 53: /mnt/foo.txt: Read-only file system
case 1 success
“--case 2 :truncate size great than 128 byte---”
Erasing 128 Kibyte @ ffe0000 -- 100 % complete 
ubiattach: error!: cannot attach mtd0
           error 17 (File exists)
Set volume size to 258306048
Volume ID 0, size 2002 LEBs (258306048 bytes, 246.3 MiB), LEB size 129024 bytes (126.0 KiB), dynamic, name "vol_a", alignment 1
Encryption policy for /mnt:
	Policy version: 2
	Master key identifier: 9e4ad472027d47f284511bbac5b6b388
	Contents encryption mode: AES-256-XTS
	Filenames encryption mode: AES-256-CTS
	Flags: PAD_32
truncate: failed to truncate '/mnt/file0' at 1086 bytes: Read-only file system
[15016.202489] UBIFS error (ubi0:0 pid 9972): ubifs_assert_failed [ubifs]: UBIFS assert failed: pad_len <= *out_len, in fs/ubifs/crypto.c:35
[15016.204280] UBIFS warning (ubi0:0 pid 9972): ubifs_ro_mode [ubifs]: switched to read-only mode, error -22
[15016.205644] CPU: 0 PID: 9972 Comm: truncate Not tainted 5.10.0-13346-g79fd47be422e #8
[15016.206736] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS ?-20190727_073836-buildvm-ppc64le-16.ppc.fedoraproject.org-3.fc31 04/01/2014
[15016.208638] Call Trace:
[15016.209016]  ? dump_stack+0xa6/0xd5
[15016.209555]  ? ubifs_ro_mode+0x54/0x60 [ubifs]
[15016.210231]  ? ubifs_assert_failed+0x4b/0x80 [ubifs]
[15016.211006]  ? ubifs_encrypt+0x145/0x170 [ubifs]
[15016.211737]  ? ubifs_jnl_truncate+0xc0f/0xda0 [ubifs]
[15016.212501]  ? put_object+0x3b/0x80
[15016.213021]  ? __delete_object+0x4d/0xa0
[15016.213617]  ? __cond_resched+0x1d/0x50
[15016.214197]  ? down_write+0x16/0x70
[15016.214718]  ? __cond_resched+0x1d/0x50
[15016.215294]  ? pagecache_get_page+0x4ab/0x990
[15016.215954]  ? ubifs_setattr+0x4f9/0x8c0 [ubifs]
[15016.216639]  ? selinux_inode_setattr+0xae/0x180
[15016.217318]  ? notify_change+0x3eb/0x760
[15016.217910]  ? do_truncate+0x98/0x130
[15016.218468]  ? do_truncate+0x98/0x130
[15016.218957]  ? do_sys_ftruncate+0x1c4/0x2f0
[15016.219518]  ? __x64_sys_ftruncate+0x1f/0x30
[15016.220089]  ? do_syscall_64+0x45/0x70
[15016.220581]  ? entry_SYSCALL_64_after_hwframe+0x44/0xa9
[15016.221326] UBIFS error (ubi0:0 pid 9972): make_reservation [ubifs]: cannot reserve 1352 bytes in jhead 1, error -30
test10000.sh: line 196: /mnt/foo.txt: Read-only file system
case 2 success!
~~~
Comment 1 wangzhaolong1 2022-07-07 11:42:51 UTC
Created attachment 301356 [details]
In the truncate_data_node() function, the length of the compressed data after truncation may be greater than the length of the compressed data before truncation.

The ubifs_compress() function of the UBIFS checks the data to be compressed and the compression result. If the data length is short than 128 bytes or the compressed data length is not ideal, the UBIFS does not compress the data.

void ubifs_compress(const struct ubifs_info *c, const void *in_buf,                          
            int in_len, void *out_buf, int *out_len, int *compr_type)
{
        ......
        if (*compr_type == UBIFS_COMPR_NONE)
                goto no_compr;
        ......
        err = crypto_comp_compress(compr->cc, in_buf, in_len, out_buf,
                       (unsigned int *)out_len);
        ......
        if (in_len - *out_len < UBIFS_MIN_COMPRESS_DIFF)
                goto no_compr;
        ......
        return;

no_compr:
        memcpy(out_buf, in_buf, in_len);
        *out_len = in_len;
        *compr_type = UBIFS_COMPR_NONE;
}
Therefore, in the truncatation process the compressed length of the truncated data may be greater than the compressed length of the raw data read from the flash memory.
When the length of the truncated data is greater than the length of the compressed raw data, truncate_data_node() calls the ubifs_encrypt() function and it will triggers assert. This will cause the file system to become read-only.

static int truncate_data_node(const struct ubifs_info *c, const struct inode *inode,
                              unsigned int block, struct ubifs_data_node *dn,
                              int *new_len)
{
        void *buf;
        int err, dlen, compr_type, out_len, old_dlen;

        out_len = le32_to_cpu(dn->size);
        ......
                err = ubifs_decrypt(inode, dn, &dlen, block);
        ......
                err = ubifs_decompress(c, &dn->data, dlen, buf, &out_len, compr_type);
                if (err)
                        goto out;

                ubifs_compress(c, buf, *new_len, &dn->data, &out_len, &compr_type);

        if (IS_ENCRYPTED(inode)) {
                err = ubifs_encrypt(inode, dn, out_len, &old_dlen, block);
        ......
}

After ubifs_compress() is called, "out_len" may be greater than "old_dlen".The out len is the compressed length of the truncated data, the old_dlen is the length of compressed raw data read from the flash memory.

When "out_len" greater than "old_dlen", the ubifs_compress() function will trigger assert.

int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
{
        ......
        unsigned int pad_len = round_up(in_len, UBIFS_CIPHER_BLOCK_SIZE);
        ......
        ubifs_assert(c, pad_len <= *out_len);
        ......
}
When "out_len" is nearly close to "old_len", it is also possible that the ubifs_compress() function will trigger an assert() because of round_up() option.

Assert triggered by this improper check can cause the file system to become read, which is a serious problem.
Comment 2 wangzhaolong1 2022-07-07 12:36:05 UTC
> When "out_len" greater than "old_dlen", the ubifs_encrypt() function will
> ubifs_encrypt() function will trigger an assert() because of round_up()
Comment 3 wangzhaolong1 2022-07-07 12:42:58 UTC
> 
> When "out_len" greater than "old_dlen", the ubifs_compress() function will
> trigger assert.
> 
> int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
> {
>         ......
>         unsigned int pad_len = round_up(in_len, UBIFS_CIPHER_BLOCK_SIZE);
>         ......
>         ubifs_assert(c, pad_len <= *out_len);
>         ......
> }
> When "out_len" is nearly close to "old_len", it is also possible that the
> ubifs_compress() function will trigger an assert() because of round_up()
> option.
> 
> Assert triggered by this improper check can cause the file system to become
> read, which is a serious problem.

Correct some clerical errors, ubifs_compress() here should be ubifs_encrypt()
 
When "out_len" greater than "old_dlen", the ubifs_encrypt() function will
trigger assert.

int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
{
        ......
        unsigned int pad_len = round_up(in_len, UBIFS_CIPHER_BLOCK_SIZE);
        ......
        ubifs_assert(c, pad_len <= *out_len);
        ......
}
When "out_len" is nearly close to "old_len", it is also possible that the
ubifs_encrypt() function will trigger an assert() because of round_up()
option.

Assert triggered by this improper check can cause the file system to become
read, which is a serious problem.
Comment 4 wangzhaolong1 2022-07-14 12:18:37 UTC
(In reply to wangzhaolong1 from comment #0)
> [kernel config]:
> CONFIG_MTD_NAND_NANDSIM=m
> CONFIG_MTD_UBI=m
> CONFIG_UBIFS_FS=m
> CONFIG_UBIFS_FS_ADVANCED_COMPR=y
> CONFIG_UBIFS_FS_LZO=y
> CONFIG_UBIFS_FS_ZLIB=y
> CONFIG_UBIFS_FS_ZSTD=y
> CONFIG_UBIFS_ATIME_SUPPORT=y
> CONFIG_UBIFS_FS_XATTR=y
> CONFIG_UBIFS_FS_SECURITY=y
> CONFIG_UBIFS_FS_AUTHENTICATION=y
CONFIG_FS_ENCRYPTION=y