|
5 | 5 |
|
6 | 6 | import os |
7 | 7 | import ctypes |
| 8 | +import struct |
8 | 9 | from typing import Callable |
9 | 10 |
|
10 | 11 | from qiling import Qiling |
@@ -1044,15 +1045,17 @@ def transform_path(ql: Qiling, dirfd: int, path: int): |
1044 | 1045 | then the target file is the one referred to by the file descriptor dirfd. |
1045 | 1046 | """ |
1046 | 1047 |
|
| 1048 | + dirfd = ql.unpacks(ql.pack(dirfd)) |
1047 | 1049 | path = ql.os.utils.read_cstring(path) |
1048 | | - |
| 1050 | + |
1049 | 1051 | if path.startswith('/'): |
1050 | | - return None, ql.os.path.transform_to_relative_path(path) |
| 1052 | + return None, os.path.join(ql.rootfs, path) |
1051 | 1053 |
|
1052 | 1054 | if dirfd == AT_FDCWD: |
1053 | | - return -100, ql.os.path.transform_to_relative_path(os.path.join(ql.os.path.cwd, path)) |
| 1055 | + return None, ql.os.path.transform_to_real_path(path) |
1054 | 1056 |
|
1055 | | - return dirfd, path |
| 1057 | + if 0 < dirfd < NR_OPEN: |
| 1058 | + return ql.os.fd[dirfd].fileno(), path |
1056 | 1059 |
|
1057 | 1060 |
|
1058 | 1061 | def ql_syscall_chmod(ql: Qiling, filename: int, mode: int): |
@@ -1143,10 +1146,145 @@ def ql_syscall_stat(ql: Qiling, path: int, buf_ptr: int): |
1143 | 1146 | def ql_syscall_stat64(ql: Qiling, path: int, buf_ptr: int): |
1144 | 1147 | return statFamily(ql, path, buf_ptr, "stat64", Stat, pack_stat64_struct) |
1145 | 1148 |
|
| 1149 | +class StatxTimestamp32(ctypes.Structure): |
| 1150 | + _fields_ = [ |
| 1151 | + ('tv_sec', ctypes.c_int32), |
| 1152 | + ('tv_nsec', ctypes.c_uint32), |
| 1153 | + ('__statx_timestamp_pad1', ctypes.c_int32) |
| 1154 | + ] |
| 1155 | + |
| 1156 | +class Statx32(ctypes.Structure): |
| 1157 | + """ |
| 1158 | + Reference: |
| 1159 | + - https://man7.org/linux/man-pages/man2/statx.2.html |
| 1160 | + - https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/statx.c.html |
| 1161 | +
|
| 1162 | + """ |
| 1163 | + _fields_ = [ |
| 1164 | + ('stx_mask', ctypes.c_uint32), |
| 1165 | + ('stx_blksize', ctypes.c_uint32), |
| 1166 | + ('stx_attributes', ctypes.c_uint32), |
| 1167 | + ('stx_nlink', ctypes.c_uint32), |
| 1168 | + ('stx_uid', ctypes.c_uint32), |
| 1169 | + ('stx_gid', ctypes.c_uint32), |
| 1170 | + ('stx_mode', ctypes.c_uint16), |
| 1171 | + ('__statx_pad1', ctypes.c_uint16), |
| 1172 | + ('stx_ino', ctypes.c_uint32), |
| 1173 | + ('stx_size', ctypes.c_uint32), |
| 1174 | + ('stx_blocks', ctypes.c_uint32), |
| 1175 | + ('stx_attributes_mask', ctypes.c_uint32), |
| 1176 | + ('stx_atime', StatxTimestamp32), |
| 1177 | + ('stx_btime', StatxTimestamp32), |
| 1178 | + ('stx_ctime', StatxTimestamp32), |
| 1179 | + ('stx_mtime', StatxTimestamp32), |
| 1180 | + ('stx_rdev_major', ctypes.c_uint32), |
| 1181 | + ('stx_rdev_minor', ctypes.c_uint32), |
| 1182 | + ('stx_dev_major', ctypes.c_uint32), |
| 1183 | + ('stx_dev_minor', ctypes.c_uint32), |
| 1184 | + ('__statx_pad2', ctypes.c_uint32 * 14), |
| 1185 | + ] |
| 1186 | + |
| 1187 | + _pack_ = 8 |
| 1188 | + |
| 1189 | +class StatxTimestamp64(ctypes.Structure): |
| 1190 | + _fields_ = [ |
| 1191 | + ('tv_sec', ctypes.c_int64), |
| 1192 | + ('tv_nsec', ctypes.c_uint32), |
| 1193 | + ('__statx_timestamp_pad1', ctypes.c_int32) |
| 1194 | + ] |
| 1195 | + |
| 1196 | +class Statx64(ctypes.Structure): |
| 1197 | + """ |
| 1198 | + Reference: |
| 1199 | + - https://man7.org/linux/man-pages/man2/statx.2.html |
| 1200 | + - https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/statx.c.html |
| 1201 | +
|
| 1202 | + """ |
| 1203 | + _fields_ = [ |
| 1204 | + ('stx_mask', ctypes.c_uint32), |
| 1205 | + ('stx_blksize', ctypes.c_uint32), |
| 1206 | + ('stx_attributes', ctypes.c_uint64), |
| 1207 | + ('stx_nlink', ctypes.c_uint32), |
| 1208 | + ('stx_uid', ctypes.c_uint32), |
| 1209 | + ('stx_gid', ctypes.c_uint32), |
| 1210 | + ('stx_mode', ctypes.c_uint16), |
| 1211 | + ('__statx_pad1', ctypes.c_uint16), |
| 1212 | + ('stx_ino', ctypes.c_uint64), |
| 1213 | + ('stx_size', ctypes.c_uint64), |
| 1214 | + ('stx_blocks', ctypes.c_uint64), |
| 1215 | + ('stx_attributes_mask', ctypes.c_uint64), |
| 1216 | + ('stx_atime', StatxTimestamp64), |
| 1217 | + ('stx_btime', StatxTimestamp64), |
| 1218 | + ('stx_ctime', StatxTimestamp64), |
| 1219 | + ('stx_mtime', StatxTimestamp64), |
| 1220 | + ('stx_rdev_major', ctypes.c_uint32), |
| 1221 | + ('stx_rdev_minor', ctypes.c_uint32), |
| 1222 | + ('stx_dev_major', ctypes.c_uint32), |
| 1223 | + ('stx_dev_minor', ctypes.c_uint32), |
| 1224 | + ('__statx_pad2', ctypes.c_uint64 * 14), |
| 1225 | + ] |
| 1226 | + |
| 1227 | + _pack_ = 4 |
| 1228 | + |
1146 | 1229 | # int statx(int dirfd, const char *restrict pathname, int flags, |
1147 | 1230 | # unsigned int mask, struct statx *restrict statxbuf); |
1148 | | -def ql_syscall_statx(ql: Qiling, dirfd: int, path: int, flags: int, mask: int, statxbuf: int): |
1149 | | - return 0 |
| 1231 | +def ql_syscall_statx(ql: Qiling, dirfd: int, path: int, flags: int, mask: int, buf_ptr: int): |
| 1232 | + def statx_convert_timestamp(tv_sec, tv_nsec): |
| 1233 | + tv_sec = struct.unpack('i', struct.pack('f', tv_sec))[0] |
| 1234 | + tv_nsec = struct.unpack('i', struct.pack('f', tv_nsec))[0] |
| 1235 | + |
| 1236 | + if ql.archbit == 32: |
| 1237 | + return StatxTimestamp32(tv_sec=tv_sec, tv_nsec=tv_nsec) |
| 1238 | + else: |
| 1239 | + return StatxTimestamp64(tv_sec=tv_sec, tv_nsec=tv_nsec) |
| 1240 | + |
| 1241 | + |
| 1242 | + def major(dev): |
| 1243 | + return ((dev >> 8) & 0xfff) | ((dev >> 32) & ~0xfff) |
| 1244 | + |
| 1245 | + def minor(dev): |
| 1246 | + return (dev & 0xff) | ((dev >> 12) & ~0xff) |
| 1247 | + |
| 1248 | + fd, real_path = transform_path(ql, dirfd, path) |
| 1249 | + |
| 1250 | + try: |
| 1251 | + if len(real_path) == 0: |
| 1252 | + st = ql.os.fd[dirfd].fstat() |
| 1253 | + else: |
| 1254 | + st = Stat(real_path, fd) |
| 1255 | + |
| 1256 | + if ql.archbit == 32: |
| 1257 | + Statx = Statx32 |
| 1258 | + else: |
| 1259 | + Statx = Statx64 |
| 1260 | + |
| 1261 | + stx = Statx( |
| 1262 | + stx_mask = 0x07ff, # STATX_BASIC_STATS |
| 1263 | + stx_blksize = st.st_blksize, |
| 1264 | + stx_nlink = st.st_nlink, |
| 1265 | + stx_uid = st.st_uid, |
| 1266 | + stx_gid = st.st_gid, |
| 1267 | + stx_mode = st.st_mode, |
| 1268 | + stx_ino = st.st_ino, |
| 1269 | + stx_size = st.st_size, |
| 1270 | + stx_blocks = st.st_blocks, |
| 1271 | + stx_atime = statx_convert_timestamp(st.st_atime, st.st_atime_ns), |
| 1272 | + stx_ctime = statx_convert_timestamp(st.st_ctime, st.st_ctime_ns), |
| 1273 | + stx_mtime = statx_convert_timestamp(st.st_mtime, st.st_mtime_ns), |
| 1274 | + stx_rdev_major = major(st.st_rdev), |
| 1275 | + stx_rdev_minor = minor(st.st_rdev), |
| 1276 | + stx_dev_major = major(st.st_dev), |
| 1277 | + stx_dev_minor = minor(st.st_dev), |
| 1278 | + ) |
| 1279 | + |
| 1280 | + ql.mem.write(buf_ptr, bytes(stx)) |
| 1281 | + |
| 1282 | + regreturn = 0 |
| 1283 | + |
| 1284 | + except Exception as e: |
| 1285 | + regreturn = -1 |
| 1286 | + |
| 1287 | + return regreturn |
1150 | 1288 |
|
1151 | 1289 | def ql_syscall_lstat(ql: Qiling, path: int, buf_ptr: int): |
1152 | 1290 | return statFamily(ql, path, buf_ptr, "lstat", Lstat, pack_stat64_struct) |
|
0 commit comments