# 命令行工具查看文件扩展属性 起因是在学习文件扩展属性的时候问chatgpt推荐的命令行工具: ``` Q: 有什么命令可以直接查看文件的扩展属性 ChatGPT: 在 Linux 系统中,可以使用以下命令直接查看文件的扩展属性(Extended Attributes, xattrs): 1. getfattr getfattr 是一个专门用来获取文件扩展属性的命令。你可以用它查看文件的所有扩展属性。 查看文件的扩展属性: getfattr -d -d 或 --dump 参数用于显示扩展属性的名称和值。 是你想查看扩展属性的文件路径。 示例: getfattr -d example.txt 输出示例: # file: example.txt user.comment="This is a test file." 如果文件没有扩展属性,getfattr 会显示类似于: example.txt: no attributes 只显示属性名: 如果你只想查看扩展属性的名称,而不显示值,可以使用 -n 参数: getfattr -n 2. lsattr lsattr 是另一个命令,用于列出文件的属性,但它并不显示 getfattr 命令中的扩展属性,而是显示文件系统的某些特定属性。对于 xattrs,getfattr 更为合适。 3. attr 有时系统上也可以使用 attr 命令查看扩展属性: attr -l 这个命令列出文件的扩展属性,但与 getfattr 命令相比不如它常用。 总结 getfattr 是最常用的工具,用来查看文件的扩展属性,包括名称和值。 attr 和 lsattr 可以用于其他文件属性,但 getfattr 是针对扩展属性的最佳选择。 如果文件没有扩展属性,这些工具通常会显示“no attributes” 或类似的信息。 ``` 因为麒麟的kysec 执行文件保护也是用文件扩展属性实现的,因此想用gpt推荐的工具试一下。kysec自带`kysec_get`、`kysec_set`命令查看和设置执行文件保护标记: ```bash test@test-virtual-machine:~$ cat 1.sh echo "hello" test@test-virtual-machine:~$ kysec_get 1.sh 1.sh:none:none:unknown test@test-virtual-machine::~$ ./1.sh bash: :./1.sh:权限不够 test@test-virtual-machine:~$ kysec set -n exectl -v original ./1.sh test@test-virtual-machine:~$ kysec_get 1.sh 1.sh:none:none:original test@test-virtual-machine:~$ ./1.sh hello ``` 但使用`getfattr -d` 命令无回显,`attr -l`正常显示属性: ```bash test@test-VMware-Virtual-Platform:~$ sudo getfattr -d ./1.sh test@test-VMware-Virtual-Platform:~$ sudo attr -l ./1.sh 属性"kysec"有 17字节值于./1.sh 属性"boxadm"有 8字节值于./1.sh ``` 但无法通过当前key获取文件扩展属性值: ```bash test@test-VMware-Virtual-Platform:~$ sudo attr -g kysec ./1.sh attr_get: 没有可用的数据 无法获取 "kysec" 于 ./1.sh: ``` 使用gdb调试一下kysec获取文件扩展属性的程序,该程序本质上就是打包了`lgetxattr`函数: ```bash test@test-VMware-Virtual-Platform:~$ gdb --args kysec_get ./1.sh ... [ Legend: Modified register | Code | Heap | Stack | String ] ───────────────────────────────────────────────────────────────── registers ──── $rax : 0x0055555555a400 → 0x0000000000000000 $rbx : 0x007fffffffdf88 → 0x0055555555a400 → 0x0000000000000000 $rcx : 0xff $rdx : 0x0055555555a400 → 0x0000000000000000 $rsp : 0x007fffffffdf58 → 0x007ffff7fa8950 → mov r12d, eax $rbp : 0x007fffffffe48e → 0x530068732e312f2e ("./1.sh"?) $rsi : 0x007ffff7fab0d2 → "security.kysec" $rdi : 0x007fffffffe48e → 0x530068732e312f2e ("./1.sh"?) $rip : 0x007ffff7ecc010 → endbr64 $r8 : 0x0055555555a400 → 0x0000000000000000 $r9 : 0x0 $r10 : 0xfffffffffffffe46 $r11 : 0x007ffff7ecc010 → endbr64 $r12 : 0x007fffffffe48e → 0x530068732e312f2e ("./1.sh"?) $r13 : 0x61 $r14 : 0x007fffffffe48e → 0x530068732e312f2e ("./1.sh"?) $r15 : 0xffffffff $eflags: [zero carry parity adjust sign trap INTERRUPT direction overflow resume virtualx86 identification] $cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00 ───────────────────────────────────────────────────────────────────── stack ──── 0x007fffffffdf58│+0x0000: 0x007ffff7fa8950 → mov r12d, eax ← $rsp 0x007fffffffdf60│+0x0008: 0x0000000000000002 0x007fffffffdf68│+0x0010: 0x0000000000000001 0x007fffffffdf70│+0x0018: 0x007fffffffe48e → 0x530068732e312f2e ("./1.sh"?) 0x007fffffffdf78│+0x0020: 0x00555555555965 → movsxd rbx, eax 0x007fffffffdf80│+0x0028: 0x00000000202dfc8c 0x007fffffffdf88│+0x0030: 0x0055555555a400 → 0x0000000000000000 ← $rbx 0x007fffffffdf90│+0x0038: 0x0000000000000000 ─────────────────────────────────────────────────────────────── code:x86:64 ──── 0x7ffff7ecc004 ret 0x7ffff7ecc005 nop WORD PTR cs:[rax+rax*1+0x0] 0x7ffff7ecc00f nop → 0x7ffff7ecc010 endbr64 0x7ffff7ecc014 mov r10, rcx 0x7ffff7ecc017 mov eax, 0xc0 0x7ffff7ecc01c syscall 0x7ffff7ecc01e cmp rax, 0xfffffffffffff001 0x7ffff7ecc024 jae 0x7ffff7ecc027 ─────────────────────────────────────────────────────────────────── threads ──── [#0] Id 1, Name: "kysec_get", stopped 0x7ffff7ecc010 in lgetxattr (), reason: BREAKPOINT ───────────────────────────────────────────────────────────────────── trace ──── [#0] 0x7ffff7ecc010 → lgetxattr() [#1] 0x7ffff7fa8950 → kysec_label_get() [#2] 0x555555555965 → movsxd rbx, eax [#3] 0x5555555556c2 → mov ebx, eax [#4] 0x7ffff7dd30b3 → __libc_start_main() [#5] 0x55555555585e → hlt ──────────────────────────────────────────────────────────────────────────────── gef➤bt #0 0x00007ffff7ecc010 in lgetxattr () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x00007ffff7fa8950 in kysec_label_get () from /lib/x86_64-linux-gnu/libkysec.so.0 #2 0x0000555555555965 in ?? () #3 0x00005555555556c2 in ?? () #4 0x00007ffff7dd30b3 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6 #5 0x000055555555585e in ?? () ``` 可见完整key值为`security.kysec`。再使用正确的key试一下: ```bash test@test-VMware-Virtual-Platform:~$ sudo getfattr -n security.kysec ./1.sh # file: 1.sh security.kysec="none:none:unknown" test@test-VMware-Virtual-Platform:~$ sudo attr -g security.kysec ./1.sh attr_get: 没有可用的数据 无法获取 "security.kysec" 于 ./1.sh: ``` 这回`getfattr`能正常显示文件扩展属性值,但`attr`不可以。 strace看一下: ```bash test@test-VMware-Virtual-Platform:~$ sudo strace -- attr -g security.kysec ./1.sh ... lgetxattr("./1.sh", "user.security.kysec", 0x555be378b470, 65536) = -1 ENODATA (没有可用的数据) lgetxattr("./1.sh", "user.security.kysec", 0x555be378b470, 65536) = -1 ENODATA (没有可用的数据) ... ``` 可见`attr`默认只查看`user`命名空间下的key,查看man手册可见需要添加 -S 参数更改查询security命名空间: ```bash test@test-VMware-Virtual-Platform:~$ sudo attr -Sg kysec ./1.sh 属性"kysec" 有 17 字节到 ./1.sh: none:none:unknown ``` 那么`getfattr -d`为什么没有搜索到security命名空间中的key值呢?查看man手册可见: ``` -m pattern, --match=pattern Only include attributes with names matching the regular expression pattern. The default value for pattern is "^user\\.", which includes all the attributes in the user namespace. Specify "-" for including all attributes. Refer to xattr(7) for a more detailed discussion of namespaces. ``` ```bash test@test-VMware-Virtual-Platform:~$ getfattr -m - -d ./1.sh # file: 1.sh security.boxadm=0sAAAAAAAAAAA= security.kysec="none:none:unknown" ``` 加上正确的参数后两个命令行参数都显示正常了,`getfattr` 遍历的时候默认只搜索`user`命名空间但查找特定key时是搜索所有命名空间,而`attr`正好相反。而这些信息在`--help`里面并没有详细说明,以后在使用新工具之前还是要养成先看手册文档的好习惯。 https://man7.org/linux/man-pages/man1/getfattr.1.html