Propagate correct error from more POSIX syscalls

This commit is contained in:
elicn
2024-07-02 21:01:44 +03:00
committed by Eli
parent 9196ea019e
commit 712201a54a
7 changed files with 56 additions and 55 deletions
+2 -2
View File
@@ -107,7 +107,7 @@ def ql_syscall_fcntl(ql: Qiling, fd: int, cmd: int, arg: int):
f = get_opened_fd(ql.os, fd)
if f is None:
return -1
return -EBADF
if cmd == F_DUPFD:
if arg not in range(NR_OPEN):
@@ -137,7 +137,7 @@ def ql_syscall_fcntl(ql: Qiling, fd: int, cmd: int, arg: int):
regreturn = 0
else:
regreturn = -1
regreturn = -EINVAL
return regreturn
+5 -5
View File
@@ -129,7 +129,7 @@ def syscall_mmap_impl(ql: Qiling, addr: int, length: int, prot: int, flags: int,
if flags & (mmap_flags.MAP_FIXED | mmap_flags.MAP_FIXED_NOREPLACE):
# on non-QNX systems, base must be aligned to page boundary
if addr & (pagesize - 1) and ql.os.type != QL_OS.QNX:
return -1 # errno: EINVAL
return -EINVAL
# if not, use the base address as a hint but always above or equal to
# the value specified in /proc/sys/vm/mmap_min_addr (here: mmap_address)
@@ -146,7 +146,7 @@ def syscall_mmap_impl(ql: Qiling, addr: int, length: int, prot: int, flags: int,
if flags & mmap_flags.MAP_FIXED_NOREPLACE:
if not ql.mem.is_available(lbound, mapping_size):
return -1 # errno: EEXIST
return -EEXIST
elif flags & mmap_flags.MAP_FIXED:
ql.log.debug(f'{api_name}: unmapping memory between {lbound:#x}-{ubound:#x} to make room for fixed mapping')
@@ -164,12 +164,12 @@ def syscall_mmap_impl(ql: Qiling, addr: int, length: int, prot: int, flags: int,
fd = ql.unpacks(ql.pack(fd))
if fd not in range(NR_OPEN):
return -1 # errno: EBADF
return -EBADF
f: Optional[ql_file] = ql.os.fd[fd]
if f is None:
return -1 # errno: EBADF
return -EBADF
# set mapping properties for future unmap
f._is_map_shared = bool(flags & mmap_flags.MAP_SHARED)
@@ -193,7 +193,7 @@ def syscall_mmap_impl(ql: Qiling, addr: int, length: int, prot: int, flags: int,
ql.mem.map(lbound, mapping_size, info=label)
except QlMemoryMappedError:
ql.log.debug(f'{api_name}: out of memory')
return -1 # errono: ENOMEM
return -ENOMEM
else:
if data:
ql.mem.write(addr, data)
+14 -14
View File
@@ -40,7 +40,7 @@ def __perms(ql: Qiling, msq: QlMsqId, flag: int) -> int:
# is there some bit set in requested_mode but not in granted_mode?
if request_mode & ~granted_mode & 0o007:
return -1 # EACCES
return -EACCES
return 0
@@ -53,7 +53,7 @@ def ql_syscall_msgget(ql: Qiling, key: int, msgflg: int):
"""
if len(ql.os.msq) >= MSGMNI:
return -1 # ENOSPC
return -ENOSPC
mode = flags & ((1 << 9) - 1)
@@ -77,16 +77,16 @@ def ql_syscall_msgget(ql: Qiling, key: int, msgflg: int):
msqid = __create_msq(key, msgflg)
else:
return -1 # ENOENT
return -ENOENT
# a message queue with the specified key exists
else:
# the user asked to create a new one?
if msgflg & (IPC_CREAT | IPC_EXCL):
return -1 # EEXIST
return -EEXIST
if __perms(ql, msq, msgflg):
return -1 # EACCES
return -EACCES
return msqid
@@ -95,11 +95,11 @@ def ql_syscall_msgsnd(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgflg: int
msq = ql.os.msq.get_by_id(msqid)
if msq is None:
return -1 # EINVAL
return -EINVAL
# Check if the user has write permissions for the message queue
if __perms(ql, msq, 0o222): # S_IWUGO
return -1 # EACCES
return -EACCES
msg_type = ql.mem.read_ptr(msgp)
msg_text = ql.mem.read(msgp + ql.arch.pointersize, msgsz)
@@ -109,7 +109,7 @@ def ql_syscall_msgsnd(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgflg: int
break
if msgflg & IPC_NOWAIT:
return -1 # EAGAIN
return -EAGAIN
msq.queue.append(QlMsgBuf(msg_type, bytes(msg_text)))
@@ -120,15 +120,15 @@ def ql_syscall_msgrcv(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgtyp: int
msq = ql.os.msq.get_by_id(msqid)
if msq is None:
return -1 # EINVAL
return -EINVAL
if msgflg & MSG_COPY:
if msgflg & MSG_EXCEPT or not (msgflg & IPC_NOWAIT):
return -1 # EINVAL
return -EINVAL
# Check if the user has read permissions for the message queue
if __perms(ql, msq, 0o444): # S_IRUGO
return -1 # EACCES
return -EACCES
while True:
msg = __find_msg(msq, msgtyp, msgflg)
@@ -137,17 +137,17 @@ def ql_syscall_msgrcv(ql: Qiling, msqid: int, msgp: int, msgsz: int, msgtyp: int
break
if msgflg & MSG_COPY:
return -1 # ENOMSG
return -ENOMSG
if msgflg & IPC_NOWAIT:
return -1 # ENOMSG
return -ENOMSG
if not (msgflg & MSG_COPY):
msq.queue.remove(msg)
if msgsz < len(msg.mtext):
if not (msgflg & MSG_NOERROR):
return -1 # E2BIG
return -E2BIG
else:
sz = msgsz
else:
+2 -1
View File
@@ -5,6 +5,7 @@
from qiling import Qiling
from qiling.arch.x86_const import IA32_FS_BASE_MSR, IA32_GS_BASE_MSR
from qiling.os.posix.const import EINVAL
def ql_syscall_arch_prctl(ql: Qiling, code: int, addr: int):
@@ -29,7 +30,7 @@ def ql_syscall_arch_prctl(ql: Qiling, code: int, addr: int):
if code not in handlers:
ql.log.debug(f'prctl code {code:#x} not implemented')
return -1 # EINVAL
return -EINVAL
handlers[code]()
+10 -10
View File
@@ -21,7 +21,7 @@ def ql_syscall_shmget(ql: Qiling, key: int, size: int, shmflg: int):
"""
if len(ql.os.shm) >= SHMMNI:
return -1 # ENOSPC
return -ENOSPC
mode = flags & ((1 << 9) - 1)
@@ -54,13 +54,13 @@ def ql_syscall_shmget(ql: Qiling, key: int, size: int, shmflg: int):
shmid = __create_shm(key, size, shmflg)
else:
return -1 # ENOENT
return -ENOENT
# a shm with the specified key exists
else:
# the user asked to create a new one?
if shmflg & (IPC_CREAT | IPC_EXCL):
return -1 # EEXIST
return -EEXIST
# check whether the user has permissions to access this shm
# FIXME: should probably use ql.os.cuid instead, but we don't support it yet
@@ -68,7 +68,7 @@ def ql_syscall_shmget(ql: Qiling, key: int, size: int, shmflg: int):
return shmid
else:
return -1 # EACCES
return -EACCES
return shmid
@@ -78,7 +78,7 @@ def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int):
# a shm with the specified key does not exist
if shm is None:
return -1 # EINVAL
return -EINVAL
if shmaddr == 0:
# system may choose any suitable page-aligned address
@@ -100,7 +100,7 @@ def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int):
else:
# shmaddr is expected to be aligned
if shmaddr & (ql.mem.pagesize - 1):
return -1 # EINVAL
return -EINVAL
attaddr = shmaddr
@@ -114,11 +114,11 @@ def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int):
# user asked to attached the seg as readable; is it allowed?
if (perms & UC_PROT_READ) and not (shm.mode & SHM_R):
return -1 # EACCES
return -EACCES
# user asked to attached the seg as writable; is it allowed?
if (perms & UC_PROT_WRITE) and not (shm.mode & SHM_W):
return -1 # EACCES
return -EACCES
# TODO: if segment is already attached, there is no need to map another memory for it.
# if we do, data changes will not be reflected between the segment attachments. we could
@@ -129,7 +129,7 @@ def ql_syscall_shmat(ql: Qiling, shmid: int, shmaddr: int, shmflg: int):
# attach the segment at shmaddr
ql.mem.map(attaddr, shm.segsz, perms, '[shm]')
except QlMemoryMappedError:
return -1 # EINVAL
return -EINVAL
# track attachment
shm.attach.append(attaddr)
@@ -143,7 +143,7 @@ def ql_syscall_shmdt(ql: Qiling, shmaddr: int):
shm = ql.os.shm.get_by_attaddr(shmaddr)
if shm is None:
return -1 # EINVAL
return -EINVAL
shm.attach.remove(shmaddr)
+5 -5
View File
@@ -19,7 +19,7 @@ def ql_syscall_ipc(ql: Qiling, call: int, first: int, second: int, third: int, p
def __call_shmat(*args: int) -> int:
if version == 1:
return -1 # EINVAL
return -EINVAL
return ql_syscall_shmat(ql, args[0], args[3], args[1])
@@ -28,17 +28,17 @@ def ql_syscall_ipc(ql: Qiling, call: int, first: int, second: int, third: int, p
def __call_shmget(*args: int) -> int:
return ql_syscall_shmget(ql, args[0], args[1], args[2])
def __call_msgget(*args: int) -> int:
return ql_syscall_msgget(ql, args[0], args[1])
def __call_msgsnd(*args: int) -> int:
return ql_syscall_msgsnd(ql, args[0], args[3], args[1], args[2])
def __call_msgrcv(*args: int) -> int:
if version == 0:
if args[3] == 0:
return -1 # EINVAL
return -EINVAL
msgp = ql.mem.read_ptr(args[3])
msgtyp = ql.mem.read_ptr(args[3] + ql.arch.pointersize)
@@ -59,7 +59,7 @@ def ql_syscall_ipc(ql: Qiling, call: int, first: int, second: int, third: int, p
}
if call not in ipc_call:
return -1 # ENOSYS
return -ENOSYS
return ipc_call[call](first, second, third, ptr, fifth)
+18 -18
View File
@@ -173,7 +173,7 @@ def ql_syscall_fsync(ql: Qiling, fd: int):
f = get_opened_fd(ql.os, fd)
if f is None:
regreturn = -1
regreturn = -EBADF
else:
try:
@@ -257,7 +257,7 @@ def ql_syscall_faccessat(ql: Qiling, dirfd: int, filename: int, mode: int):
if not ql.os.path.is_safe_host_path(hpath):
raise PermissionError(f'unsafe path: {hpath}')
regreturn = 0 if os.path.exists(hpath) else -1
regreturn = 0 if os.path.exists(hpath) else -ENOENT
ql.log.debug(f'faccessat({dirfd:d}, "{vpath}", {mode:d}) = {regreturn}')
@@ -270,7 +270,7 @@ def ql_syscall_lseek(ql: Qiling, fd: int, offset: int, origin: int):
f = get_opened_fd(ql.os, fd)
if f is None:
regreturn = -1
regreturn = -EBADF
else:
try:
@@ -290,7 +290,7 @@ def ql_syscall__llseek(ql: Qiling, fd: int, offset_high: int, offset_low: int, r
f = get_opened_fd(ql.os, fd)
if f is None:
regreturn = -1
regreturn = -EBADF
else:
try:
@@ -331,7 +331,7 @@ def ql_syscall_access(ql: Qiling, path: int, mode: int):
if not ql.os.path.is_safe_host_path(hpath):
raise PermissionError(f'unsafe path: {hpath}')
regreturn = 0 if os.path.exists(hpath) else -1
regreturn = 0 if os.path.exists(hpath) else -ENOENT
ql.log.debug(f'access("{vpath}", 0{mode:o}) = {regreturn}')
@@ -342,7 +342,7 @@ def ql_syscall_close(ql: Qiling, fd: int):
f = get_opened_fd(ql.os, fd)
if f is None:
regreturn = -1
regreturn = -EBADF
else:
f.close()
@@ -358,7 +358,7 @@ def ql_syscall_pread64(ql: Qiling, fd: int, buf: int, length: int, offt: int):
f = get_opened_fd(ql.os, fd)
if f is None:
regreturn = -1
return -EBADF
else:
# https://chromium.googlesource.com/linux-syscall-support/+/2c73abf02fd8af961e38024882b9ce0df6b4d19b
@@ -386,7 +386,7 @@ def ql_syscall_read(ql: Qiling, fd, buf: int, length: int):
f = get_opened_fd(ql.os, fd)
if f is None:
return -1
return -EBADF
try:
data = f.read(length)
@@ -404,7 +404,7 @@ def ql_syscall_write(ql: Qiling, fd: int, buf: int, count: int):
f = get_opened_fd(ql.os, fd)
if f is None:
return -1
return -EBADF
try:
data = ql.mem.read(buf, count)
@@ -449,7 +449,7 @@ def __do_readlink(ql: Qiling, absvpath: str, outbuf: int) -> int:
target = ''
if target is None:
return -1
return -ENOENT
cstr = target.encode('utf-8')
@@ -507,7 +507,7 @@ def ql_syscall_chdir(ql: Qiling, path_name: int):
regreturn = 0
else:
regreturn = -1
regreturn = -ENOENT
ql.log.debug(f'chdir("{absvpath}") = {regreturn}')
@@ -634,7 +634,7 @@ def ql_syscall_dup(ql: Qiling, oldfd: int):
f = get_opened_fd(ql.os, oldfd)
if f is None:
return -1
return -EBADF
newfd = next((i for i in range(NR_OPEN) if ql.os.fd[i] is None), -1)
@@ -652,10 +652,10 @@ def ql_syscall_dup2(ql: Qiling, oldfd: int, newfd: int):
f = get_opened_fd(ql.os, oldfd)
if f is None:
return -1
return -EBADF
if newfd not in range(NR_OPEN):
return -1
return -EBADF
newslot = ql.os.fd[newfd]
@@ -675,10 +675,10 @@ def ql_syscall_dup3(ql: Qiling, oldfd: int, newfd: int, flags: int):
f = get_opened_fd(ql.os, oldfd)
if f is None:
return -1
return -EBADF
if newfd not in range(NR_OPEN):
return -1
return -EBADF
newslot = ql.os.fd[newfd]
@@ -714,7 +714,7 @@ def ql_syscall_pipe(ql: Qiling, pipefd: int):
idx2 = next(unpopulated_fd, -1)
if (idx1 == -1) or (idx2 == -1):
return -1
return -EMFILE
ql.os.fd[idx1] = rd
ql.os.fd[idx2] = wd
@@ -769,7 +769,7 @@ def ql_syscall_truncate(ql: Qiling, path: int, length: int):
def ql_syscall_ftruncate(ql: Qiling, fd: int, length: int):
f = get_opened_fd(ql.os, fd)
regreturn = -1 if f is None else __do_truncate(ql, f.name, length)
regreturn = -EBADF if f is None else __do_truncate(ql, f.name, length)
ql.log.debug(f'ftruncate({fd}, {length:#x}) = {regreturn}')