Skip to content

Commit 0f77f88

Browse files
authored
Merge pull request #265 from Lind-Project/vlad_ioctl
ioctl_syscall updates
2 parents be794a8 + b859c09 commit 0f77f88

File tree

2 files changed

+110
-29
lines changed

2 files changed

+110
-29
lines changed

src/safeposix/syscalls/fs_calls.rs

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,39 +2041,92 @@ impl Cage {
20412041
}
20422042
}
20432043

2044-
//------------------------------------IOCTL SYSCALL------------------------------------
2044+
/// ### Description
2045+
///
2046+
/// The `ioctl_syscall()` manipulates the underlying device parameters of special files. In particular, it is used as a way
2047+
/// for user-space applications to interface with device drivers.
2048+
///
2049+
/// ### Arguments
2050+
///
2051+
/// The `ioctl_syscall()` accepts three arguments:
2052+
/// * `fd` - an open file descriptor that refers to a device.
2053+
/// * `request` - the control function to be performed. The set of valid request values depends entirely on the device
2054+
/// being addressed. MEDIA_IOC_DEVICE_INFO is an example of an ioctl control function to query device
2055+
/// information that all media devices must support.
2056+
/// * `ptrunion` - additional information needed by the addressed device to perform the selected control function.
2057+
/// In the example of MEDIA_IOC_DEVICE_INFO request, a valid ptrunion value is a pointer to a struct
2058+
/// media_device_info, from which the device information is obtained.
2059+
///
2060+
/// ### Returns
2061+
///
2062+
/// Upon successful completion, a value other than -1 that depends on the selected control function is returned.
2063+
/// In case of a failure, -1 is returned with errno set to a particular value, like EBADF, EINVAL, etc.
2064+
///
2065+
/// ### Errors and Panics
2066+
///
2067+
/// * `EBADF` - fd is not a valid file descriptor
2068+
/// * `EFAULT` - ptrunion references an inaccessible memory area
2069+
/// * `EINVAL` - request or ptrunion is not valid
2070+
/// * `ENOTTY` - fd is not associated with a character special device
2071+
/// When `ioctl_syscall() is called on a Socket with `FIONBIO` control function, an underlying call to `libc::fcntl()` is made,
2072+
/// which can return with an error. For a complete list of possible erorrs, see
2073+
/// [fcntl(2)](https://linux.die.net/man/2/fcntl)
2074+
///
2075+
/// A panic occurs either when a provided file descriptor is out of bounds or when
2076+
/// an underlying call to `libc::fcntl()` for Socket type is returned with an unknown error.
2077+
///
2078+
/// To learn more about the syscall, control functions applicable to all the devices, and possible error values, see
2079+
/// [ioctl(2)](https://man.openbsd.org/ioctl)
20452080
20462081
pub fn ioctl_syscall(&self, fd: i32, request: u32, ptrunion: IoctlPtrUnion) -> i32 {
2082+
//BUG
2083+
//if the provided file descriptor is out of bounds, 'get_filedescriptor' returns Err(),
2084+
//unwrapping on which produces a 'panic!'
2085+
//otherwise, file descriptor table entry is stored in 'checkedfd'
20472086
let checkedfd = self.get_filedescriptor(fd).unwrap();
20482087
let mut unlocked_fd = checkedfd.write();
2088+
//if a table descriptor entry is non-empty, a valid request is performed
20492089
if let Some(filedesc_enum) = &mut *unlocked_fd {
2090+
//For now, the only implemented control function is FIONBIO command used with sockets
20502091
match request {
2092+
//for FIONBIO, 'ptrunion' stores a pointer to an integer. If the integer is 0, the socket's
2093+
//nonblocking I/O is cleared. Otherwise, the socket is set for nonblocking I/O
20512094
FIONBIO => {
2095+
//if 'ptrunion' stores a Null pointer, a 'Bad address' error is returned
2096+
//otheriwse, the integer value stored in that address is returned and saved into 'arg_result'
20522097
let arg_result = interface::get_ioctl_int(ptrunion);
2053-
//matching the tuple and passing in filedesc_enum
20542098
match (arg_result, filedesc_enum) {
20552099
(Err(arg_result), ..)=> {
2056-
return arg_result; //syscall_error
2100+
return arg_result;
20572101
}
2102+
//since FIONBIO command is used with sockets, we need to make sure that the provided
2103+
//file descriptor addresses a socket
2104+
//otherwise, a 'Not a typewriter' error designating that the specified command
2105+
//is only applicable to sockets is returned
20582106
(Ok(arg_result), Socket(ref mut sockfdobj)) => {
20592107
let sock_tmp = sockfdobj.handle.clone();
20602108
let mut sockhandle = sock_tmp.write();
2061-
20622109
let flags = &mut sockfdobj.flags;
20632110
let arg: i32 = arg_result;
20642111
let mut ioctlret = 0;
2065-
2066-
if arg == 0 { //clear non-blocking I/O
2112+
//clearing nonblocking I/O on the socket if the integer is 0
2113+
if arg == 0 {
20672114
*flags &= !O_NONBLOCK;
2115+
//libc::fcntl is called under the hood with F_SETFL command and 0 as an argument
2116+
//to set blocking I/O, and the result of the call is stored in ioctlret
20682117
if let Some(ins) = &mut sockhandle.innersocket {
2118+
20692119
ioctlret = ins.set_blocking();
20702120
}
2071-
} else { //set for non-blocking I/O
2121+
} else {
20722122
*flags |= O_NONBLOCK;
2123+
//libc::fcntl is called under the hood with F_SETFL command ans O_NONBLOCK as an argument
2124+
//to set nonblocking I/O, and the result of the call is stored in ioctlret
20732125
if let Some(ins) = &mut sockhandle.innersocket {
20742126
ioctlret = ins.set_nonblocking();
20752127
}
20762128
}
2129+
//if ioctlret is negative, it means that the call to fcntl returned with an error
20772130
if ioctlret < 0 {
20782131
match Errno::from_discriminant(interface::get_errno()) {
20792132
Ok(i) => {return syscall_error(i, "ioctl", "The libc call to ioctl failed!");},

src/tests/fs_tests.rs

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ pub mod fs_tests {
2323
ut_lind_fs_fcntl_valid_args();
2424
ut_lind_fs_fcntl_invalid_args();
2525
ut_lind_fs_fcntl_dup();
26-
ut_lind_fs_ioctl();
26+
ut_lind_fs_ioctl_valid_args();
27+
ut_lind_fs_ioctl_invalid_args();
2728
ut_lind_fs_fdflags();
2829
ut_lind_fs_file_link_unlink();
2930
ut_lind_fs_file_lseek_past_end();
@@ -525,48 +526,75 @@ pub mod fs_tests {
525526
}
526527

527528

528-
pub fn ut_lind_fs_ioctl() {
529+
pub fn ut_lind_fs_ioctl_valid_args() {
529530
lindrustinit(0);
530531
let cage = interface::cagetable_getref(1);
531532

533+
//setting up two integer values (a zero value to test clearing nonblocking I/O behavior
534+
//and a non-zero value to test setting nonblocking I/O behavior)
532535
let mut arg0: i32 = 0;
533536
let mut arg1: i32 = 1;
534537

538+
//ioctl requires a pointer to an integer to be passed with FIONBIO command
535539
let union0: IoctlPtrUnion = IoctlPtrUnion { int_ptr: &mut arg0 };
536540
let union1: IoctlPtrUnion = IoctlPtrUnion { int_ptr: &mut arg1 };
537541

538542
let sockfd = cage.socket_syscall(AF_INET, SOCK_STREAM, 0);
539-
let filefd = cage.open_syscall("/ioctl_file", O_CREAT | O_EXCL, S_IRWXA);
540-
541-
//try to use FIONBIO for a non-socket
542-
assert_eq!(
543-
cage.ioctl_syscall(filefd, FIONBIO, union0),
544-
-(Errno::ENOTTY as i32)
545-
);
546543

547-
//clear the O_NONBLOCK flag
544+
//calling ioctl with FIONBIO command and a pointer to a zero-valued integer
545+
//to clear the socket's nonblocking I/O, and checking if the flag was correctly set
548546
assert_eq!(cage.ioctl_syscall(sockfd, FIONBIO, union0), 0);
549-
550-
//checking to see if the flag was updated
551547
assert_eq!(cage.fcntl_syscall(sockfd, F_GETFL, 0) & O_NONBLOCK, 0);
552548

553-
//set the O_NONBLOCK flag
549+
//calling ioctl with FIONBIO command and a pointer to a non-zero-valued integer
550+
//to set the socket's nonblocking I/O, and checking if the flag was correctly set
554551
assert_eq!(cage.ioctl_syscall(sockfd, FIONBIO, union1), 0);
552+
assert_eq!(cage.fcntl_syscall(sockfd, F_GETFL, 0) & O_NONBLOCK, O_NONBLOCK);
555553

556-
//checking to see if the flag was updated
557-
assert_eq!(
558-
cage.fcntl_syscall(sockfd, F_GETFL, 0) & O_NONBLOCK,
559-
O_NONBLOCK
560-
);
554+
assert_eq!(cage.close_syscall(sockfd), 0);
561555

562-
//clear the O_NONBLOCK flag
563-
assert_eq!(cage.ioctl_syscall(sockfd, FIONBIO, union0), 0);
556+
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
557+
lindrustfinalize();
558+
}
564559

565-
//checking to see if the flag was updated
566-
assert_eq!(cage.fcntl_syscall(sockfd, F_GETFL, 0) & O_NONBLOCK, 0);
560+
pub fn ut_lind_fs_ioctl_invalid_args() {
561+
lindrustinit(0);
562+
let cage = interface::cagetable_getref(1);
563+
564+
//setting up two integer values (a zero value to test clearing nonblocking I/O behavior on
565+
//non-socket type and a non-zero value to test setting nonblocking I/O behavior
566+
//on non-socket type)
567+
let mut arg0: i32 = 0;
568+
let mut arg1: i32 = 1;
569+
570+
//ioctl requires a pointer to an integer to be passed with FIONBIO command
571+
let union0: IoctlPtrUnion = IoctlPtrUnion { int_ptr: &mut arg0 };
572+
let union1: IoctlPtrUnion = IoctlPtrUnion { int_ptr: &mut arg1 };
567573

574+
let sockfd = cage.socket_syscall(AF_INET, SOCK_STREAM, 0);
575+
let filefd = cage.open_syscall("/ioctl_file", O_CREAT | O_EXCL, S_IRWXA);
576+
577+
//trying to use FIONBIO command on a non-socket type (the file type in this case)
578+
//for any 'ptrunion' value should throw a 'Not a typewriter' error
579+
assert_eq!(cage.ioctl_syscall(filefd, FIONBIO, union0), -(Errno::ENOTTY as i32));
580+
assert_eq!(cage.ioctl_syscall(filefd, FIONBIO, union1), -(Errno::ENOTTY as i32));
568581
assert_eq!(cage.close_syscall(filefd), 0);
582+
583+
//calling 'ioctl' with a control function that is not implemented yet should
584+
//return an 'Invalid argument' error
585+
//21600 is an arbitrary integer that does not correspond to any implemented
586+
//control functions for ioctl syscall
587+
assert_eq!(cage.ioctl_syscall(sockfd, 21600, union0), -(Errno::EINVAL as i32));
588+
589+
//calling ioctl with FIONBIO command and a null pointer
590+
//should return a 'Bad address' error
591+
let null_ptr: *mut i32 = std::ptr::null_mut();
592+
let union_null: IoctlPtrUnion = IoctlPtrUnion { int_ptr: null_ptr };
593+
assert_eq!(cage.ioctl_syscall(sockfd, FIONBIO, union_null),-(Errno::EFAULT as i32));
594+
595+
//calling ioctl on a closed file descriptor should throw a 'Bad file number' error
569596
assert_eq!(cage.close_syscall(sockfd), 0);
597+
assert_eq!(cage.fcntl_syscall(sockfd, F_GETFL, 0), -(Errno::EBADF as i32));
570598

571599
assert_eq!(cage.exit_syscall(EXIT_SUCCESS), EXIT_SUCCESS);
572600
lindrustfinalize();

0 commit comments

Comments
 (0)