generic: posix acl extended attribute memory corruption test
[xfstests-dev.git] / src / t_attr_corruption.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2019 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <darrick.wong@oracle.com>
5  *
6  * Test program to tickle a use-after-free bug in xfs.
7  *
8  * XFS had a use-after-free bug when xfs_xattr_put_listent runs out of
9  * listxattr buffer space while trying to store the name
10  * "system.posix_acl_access" and then corrupts memory by not checking the
11  * seen_enough state and then trying to shove "trusted.SGI_ACL_FILE" into the
12  * buffer as well.
13  *
14  * In order to tickle the bug in a user visible way we must have already put a
15  * name in the buffer, so we take advantage of the fact that "security.evm"
16  * sorts before "system.posix_acl_access" to make sure this happens.
17  *
18  * If we trigger the bug, the program will print the garbled string
19  * "rusted.SGI_ACL_FILE".  If the bug is fixed, the flistxattr call returns
20  * ERANGE.
21  */
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdint.h>
29 #include <unistd.h>
30 #include <attr/xattr.h>
31
32 void die(const char *msg)
33 {
34         perror(msg);
35         exit(1);
36 }
37
38 struct entry {
39         uint16_t        a;
40         uint16_t        b;
41         uint32_t        c;
42 };
43
44 struct myacl {
45         uint32_t        d;
46         struct entry    e[4];
47 };
48
49 int main(int argc, char *argv[])
50 {
51         struct myacl acl = {
52                 .d = 2,
53                 .e = {
54                         {1, 0, 0},
55                         {4, 0, 0},
56                         {0x10, 0, 0},
57                         {0x20, 0, 0},
58                 },
59         };
60         char buf[64];
61         ssize_t sz;
62         int fd;
63         int ret;
64
65         if (argc > 1) {
66                 ret = chdir(argv[1]);
67                 if (ret)
68                         die(argv[1]);
69         }
70
71         fd = creat("file0", 0644);
72         if (fd < 0)
73                 die("create");
74
75         ret = fsetxattr(fd, "system.posix_acl_access", &acl, sizeof(acl), 0);
76         if (ret)
77                 die("set posix acl");
78
79         ret = fsetxattr(fd, "security.evm", buf, 1, 1);
80         if (ret)
81                 die("set evm");
82
83         sz = flistxattr(fd, buf, 30);
84         if (sz < 0)
85                 die("list attr");
86
87         printf("%s\n", buf);
88
89         return 0;
90
91 #if 0
92         /* original syzkaller reproducer */
93
94         syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
95
96         memcpy((void*)0x20000180, "./file0", 8);
97         syscall(__NR_creat, 0x20000180, 0);
98         memcpy((void*)0x20000000, "./file0", 8);
99         memcpy((void*)0x20000040, "system.posix_acl_access", 24);
100         *(uint32_t*)0x20000680 = 2;
101         *(uint16_t*)0x20000684 = 1;
102         *(uint16_t*)0x20000686 = 0;
103         *(uint32_t*)0x20000688 = 0;
104         *(uint16_t*)0x2000068c = 4;
105         *(uint16_t*)0x2000068e = 0;
106         *(uint32_t*)0x20000690 = 0;
107         *(uint16_t*)0x20000694 = 0x10;
108         *(uint16_t*)0x20000696 = 0;
109         *(uint32_t*)0x20000698 = 0;
110         *(uint16_t*)0x2000069c = 0x20;
111         *(uint16_t*)0x2000069e = 0;
112         *(uint32_t*)0x200006a0 = 0;
113         syscall(__NR_setxattr, 0x20000000, 0x20000040, 0x20000680, 0x24, 0);
114         memcpy((void*)0x20000080, "./file0", 8);
115         memcpy((void*)0x200000c0, "security.evm", 13);
116         memcpy((void*)0x20000100, "\x03\x00\x00\x00\x57", 5);
117         syscall(__NR_lsetxattr, 0x20000080, 0x200000c0, 0x20000100, 1, 1);
118         memcpy((void*)0x20000300, "./file0", 8);
119         syscall(__NR_listxattr, 0x20000300, 0x200002c0, 0x1e);
120         return 0;
121 #endif
122 }