Time out when using Spin/Promela - timeout

If someone could explain to me why I am getting a timeout with the following code that would be great. I understand, or at least I think I do, the idea of a timeout, but with the do loops I thought this would stop this. Any advice is appreciated.
mtype wantp = false;
mtype wantq = false;
mtype turn = 1;
active proctype p()
{
do
:: printf ("non critical section for p\n");
wantp = true;
(wantq ==true);
if
:: (turn == 2)->
wantp = false;
/* wait for turn ==1*/
(turn ==1);
wantp = true;
fi;
printf("CRITICAL SECTION for P\n");
turn = 2;
wantp = false;
od
}
active proctype q()
{
do
:: printf("non critical section for q\n");
wantq = true;
(wantp ==true);
if
:: (turn == 1)->
wantq = false;
(turn ==2);
wantq = true;
fi;
printf("CRITICAL SECTION for Q\n");
turn = 1;
wantq = false;
od
}

When you perform a SPIN verification and a problem arises, such as a 'timeout', you have what is known as a 'trail' file. The trail file shows you the exact path through the program execution that leads to the problem.
Assuming the above file is called test.pml. You perform the following:
$ spin -a test.pml
$ gcc -o pan pan.c
$ ./pan
# info about verification, shows timeout
# view the detailed trail file
$ spin -p -t test.pml
Then, look at the details printed out to figure out how the timeout happened.

Related

How can I get a kernel variable 'cs_flags' from normal machine in ios?

struct proc *p;
p = current_proc();
/* CS_KILL triggers a kill signal, and no you can't have the page. Nothing else. */
if (p->p_csflags & CS_KILL) {
p->p_csflags |= CS_KILLED;
cs_procs_killed++;
send_kill = 1;
retval = 1;
}
cs_flags looks like a kernel variable, how can I get it in normal machine(not jailbreak) in ios? Is it possible?

Why do builds for various projects fail with ‘Operation not permitted’ using iOS on-device compiler/toolchain?

I am an intermediately skilled Linux/Unix user trying to compile software for an iPad on a (jailbroken) iPad.
Many builds (for example, make and tex-live) fail with some Operation not permitted error. This will either look like Can't exec "blah": Operation not permitted or execvp: blah: Operation not permitted where blah is aclocal, a configure script, libtool, or just about anything. Curiously, finding the offending line in a Makefile or configure script and prefixing it with sudo -u mobile -E will solve the error for that line, only for it to reappear for on a later line or in another file. Since I am running the build scripts as mobile, I do not understand how this could possibly fix the issue, yet it does. I have confirmed that making these changes does actually allow for the script to work successfully up to that point. Running the build script with sudo or sudo -u mobile -E and/or running the entire build as root does not solve the issue; with either, I still must edit build scripts to add sudo’s.
I would like to know why this is happening, and if possible how I could address the issue without editing build scripts. Any information about these types of errors would be interesting to me even if they do not solve my problem. I am aware that the permissions/security/entitlements system is unusual on iOS and would like to learn more about how it works.
I am using an iPad Pro 4 on jailbroken iOS 13.5 with the build tools from sbingner’s and MCApollo’s repos (repo.bingner.com and mcapollo.github.io/Public). In particular, I am using a build of LLVM 5 (manually installed from sbingner’s old debs), Clang 10, Darwin CC tools 927 and GNU Make 4.2.1. I have set CC, CXX, CFLAGS, etc. to point to clang-10 and my iOS 13.5 SDK with -isysroot and have confirmed that these settings are working. I would like to replace these with updated versions, but I cannot yet build these tools for myself due to this issue and a few others. I do have access to a Mac for cross-compilation if necessary, but I would rather use only my iPad because I like the challenge.
I can attach any logs necessary or provide more information if that would be useful; I do not know enough about this issue to know what information is useful. Thanks in advance for helping me!
For anyone who ends up needing to address this issue on a jailbreak that does not have a fix for this issue, I have written (pasted below) a userland hook based on the posix_spawn implementation from the source of Apple’s xnu kernel.
Compile it with Theos, and inject it into all processes spawned by your shell by setting environment variable DYLD_INSERT_LIBRARIES to the path of the resulting dylib. Note: some tweak injectors (namely libhooker, see here) reset DYLD_INSERT_LIBRARIES, so if you notice this behavior, be sure to inject only your library.
Because the implementation of the exec syscalls in iOS call out to posix_spawn, this hook fixes all of the exec-related issue’s I’ve run into so far.
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <spawn.h>
// Copied from bsd/kern/kern_exec.c
#define IS_WHITESPACE(ch) ((ch == ' ') || (ch == '\t'))
#define IS_EOL(ch) ((ch == '#') || (ch == '\n'))
// Copied from bsd/sys/imgact.h
#define IMG_SHSIZE 512
// Here, we provide an alternate implementation of posix_spawn which correctly handles #!.
// This is based on the implementation of posix_spawn in bsd/kern/kern_exec.c from Apple's xnu source.
// Thus, I am fairly confident that this posix_spawn has correct behavior relative to macOS.
%hookf(int, posix_spawn, pid_t *pid, const char *orig_path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const orig_argv[], char *const envp[]) {
// Call orig before checking for anything.
// This mirrors the standard implementation of posix_spawn because it first checks if we are spawning a binary.
int err = %orig;
// %orig returns EPERM when spawning a script.
// Thus, if err is anything other than EPERM, we can just return like normal.
if (err != EPERM)
return err;
// At this point, we do not need to check for exec permissions or anything like that.
// because posix_spawn would have returned that error instead of EPERM.
// Now we open the file for reading so that we can check if it's a script.
// If it turns out not to be a script, the EPERM must be from something else
// so we just return err.
FILE *file = fopen(orig_path, "r");
if (file == NULL) {
return err;
}
if (fseek(file, 0, SEEK_SET)) {
return err;
}
// In exec_activate_image, the data buffer is filled with the first PAGE_SIZE bytes of the file.
// However, in exec_shell_imgact, only the first IMG_SHSIZE bytes are used.
// Thus, we read IMG_SHSIZE bytes out of our file.
// The buffer is filled with newlines so that if the file is not IMG_SHSIZE bytes,
// the logic reads an IS_EOL.
char vdata[IMG_SHSIZE] = {'\n'};
if (fread(vdata, 1, IMG_SHSIZE, file) < 2) { // If we couldn't read at least two bytes, it's not a script.
fclose(file);
return err;
}
// Now that we've filled the buffer, we don't need the file anymore.
fclose(file);
// Now we follow exec_shell_imgact.
// The point of this is to confirm we have a script
// and extract the usable part of the interpreter+arg string.
// Where they return -1, we don't have a shell script, so we return err.
// Where they return an error, we return that same error.
// We don't bother doing any SUID stuff because SUID scripts should be disabled anyway.
char *ihp;
char *line_startp, *line_endp;
// Make sure we have a shell script.
if (vdata[0] != '#' || vdata[1] != '!') {
return err;
}
// Try to find the first non-whitespace character
for (ihp = &vdata[2]; ihp < &vdata[IMG_SHSIZE]; ihp++) {
if (IS_EOL(*ihp)) {
// Did not find interpreter, "#!\n"
return ENOEXEC;
} else if (IS_WHITESPACE(*ihp)) {
// Whitespace, like "#! /bin/sh\n", keep going.
} else {
// Found start of interpreter
break;
}
}
if (ihp == &vdata[IMG_SHSIZE]) {
// All whitespace, like "#! "
return ENOEXEC;
}
line_startp = ihp;
// Try to find the end of the interpreter+args string
for (; ihp < &vdata[IMG_SHSIZE]; ihp++) {
if (IS_EOL(*ihp)) {
// Got it
break;
} else {
// Still part of interpreter or args
}
}
if (ihp == &vdata[IMG_SHSIZE]) {
// A long line, like "#! blah blah blah" without end
return ENOEXEC;
}
// Backtrack until we find the last non-whitespace
while (IS_EOL(*ihp) || IS_WHITESPACE(*ihp)) {
ihp--;
}
// The character after the last non-whitespace is our logical end of line
line_endp = ihp + 1;
/*
* Now we have pointers to the usable part of:
*
* "#! /usr/bin/int first second third \n"
* ^ line_startp ^ line_endp
*/
// Now, exec_shell_imgact copies the interpreter into another buffer and then null-terminates it.
// Then, it copies the entire interpreter+args into another buffer and null-terminates it for later processing into argv.
// This processing is done in exec_extract_strings, which goes through and null-terminates each argument.
// We will just do this all at once since that's much easier.
// Keep track of how many arguments we have.
int i_argc = 0;
ihp = line_startp;
while (true) {
// ihp is on the start of an argument.
i_argc++;
// Scan to the end of the argument.
for (; ihp < line_endp; ihp++) {
if (IS_WHITESPACE(*ihp)) {
// Found the end of the argument
break;
} else {
// Keep going
}
}
// Null terminate the argument
*ihp = '\0';
// Scan to the beginning of the next argument.
for (; ihp < line_endp; ihp++) {
if (!IS_WHITESPACE(*ihp)) {
// Found the next argument
break;
} else {
// Keep going
}
}
if (ihp == line_endp) {
// We've reached the end of the arg string
break;
}
// If we are here, ihp is the start of an argument.
}
// Now line_startp is a bunch of null-terminated arguments possibly padded by whitespace.
// i_argc is now the count of the interpreter arguments.
// Our new argv should look like i_argv[0], i_argv[1], i_argv[2], ..., orig_path, orig_argv[1], orig_argv[2], ..., NULL
// where i_argv is the arguments to be extracted from line_startp;
// To allocate our new argv, we need to know orig_argc.
int orig_argc = 0;
while (orig_argv[orig_argc] != NULL) {
orig_argc++;
}
// We need space for i_argc + 1 + (orig_argc - 1) + 1 char*'s
char *argv[i_argc + orig_argc + 1];
// Copy i_argv into argv
int i = 0;
ihp = line_startp;
for (; i < i_argc; i++) {
// ihp is on the start of an argument
argv[i] = ihp;
// Scan to the next null-terminator
for (; ihp < line_endp; ihp++) {
if (*ihp == '\0') {
// Found it
break;
} else {
// Keep going
}
}
// Go to the next character
ihp++;
// Then scan to the next argument.
// There must be another argument because we already counted i_argc.
for (; ihp < line_endp; ihp++) {
if (!IS_WHITESPACE(*ihp)) {
// Found it
break;
} else {
// Keep going
}
}
// ihp is on the start of an argument.
}
// Then, copy orig_path into into argv.
// We need to make a copy of orig_path to avoid issues with const.
char orig_path_copy[strlen(orig_path)+1];
strcpy(orig_path_copy, orig_path);
argv[i] = orig_path_copy;
i++;
// Now, copy orig_argv[1...] into argv.
for (int j = 1; j < orig_argc; i++, j++) {
argv[i] = orig_argv[j];
}
// Finally, add the null.
argv[i] = NULL;
// Now, our argv is setup correctly.
// Now, we can call out to posix_spawn again.
// The interpeter is in argv[0], so we use that for the path.
return %orig(pid, argv[0], file_actions, attrp, argv, envp);
}

Decoding binary data using 'protoc --decode' fails with error "Type not defined"

I'm using google's protocol-buffers for communication in my project, and I'm trying to use their command line tool protoc to manually decode some binary data (in hex format). This is the command I'm using:
echo 08015a325a300a0d313932 | xxd -r -p | protoc --decode=WiFiConfigPayload wifi_config.proto
I get the following error from this command, as well as any other type that I specify for "--decode":
Type not defined: WiFiConfigPayload
This is the main .proto file that I'm using (it was created by espressif, for use with their esp32 chip). There are other .proto files that this one imports, and can be found here if anyone thinks its relevant.
syntax = "proto3";
package espressif;
import "constants.proto";
import "wifi_constants.proto";
message CmdGetStatus {
}
message RespGetStatus {
Status status = 1;
WifiStationState sta_state = 2;
oneof state {
WifiConnectFailedReason fail_reason = 10;
WifiConnectedState connected = 11;
}
}
message CmdSetConfig {
bytes ssid = 1;
bytes passphrase = 2;
bytes bssid = 3;
int32 channel = 4;
}
message RespSetConfig {
Status status = 1;
}
message CmdApplyConfig {
}
message RespApplyConfig {
Status status = 1;
}
enum WiFiConfigMsgType {
TypeCmdGetStatus = 0;
TypeRespGetStatus = 1;
TypeCmdSetConfig = 2;
TypeRespSetConfig = 3;
TypeCmdApplyConfig = 4;
TypeRespApplyConfig = 5;
}
message WiFiConfigPayload {
WiFiConfigMsgType msg = 1;
oneof payload {
CmdGetStatus cmd_get_status = 10;
RespGetStatus resp_get_status = 11;
CmdSetConfig cmd_set_config = 12;
RespSetConfig resp_set_config = 13;
CmdApplyConfig cmd_apply_config = 14;
RespApplyConfig resp_apply_config = 15;
}
}
Any ideas as to why the command is failing to parse WifiConfigPayload type (or any type for that matter) from the .protoc file?
I just ran in to this issue as well and I think you missed the actual bug. protoc was likely complaining because you didnt reference the message by the package.
protoc --decode=<PackageName>.MessageName
Where PackageName in your case is espressif
echo 08015a325a300a0d313932 | xxd -r -p | protoc --decode=espressif.WiFiConfigPayload wifi_config.proto
I solved the issue myself, soon after posting of course.
The problem is the line "package espressif;", which is included in all of their .proto files. XCode seems to require it for the project to build, but the protoc tool isn't expecting that line.
When I remove this line from this file, and all of its imported .proto files, the parsing is successful.

iOS Mach-O – Make __TEXT segment temporarily writable

I've tried a lot to finally get this working, but it still doesn't work yet.
Im trying to change some variables in the __TEXT section, which is read-only by default, like changing the cryptid (and other stuff)
It kind of worked a while ago, back on 32 bit devices. But somehow, it always fails after I used the 64bit commands.
It currently crashes if I hit the following lines:
tseg->maxprot = tseg->initprot = VM_PROT_READ | VM_PROT_EXECUTE
or
crypt->cryptid = 1.
struct mach_header_64* mach = (struct mach_header_64*) _dyld_get_image_header(0);
uint64_t header_size = 0;
struct encryption_info_command_64 *crypt;
struct segment_command_64 *tseg;
struct dylib_command *protector_cmd;
// clean up some commands
void *curloc = (void *)mach + sizeof(struct mach_header);
for (int i=0;i<mach->ncmds;i++) {
struct load_command *lcmd = curloc;
if (lcmd->cmd == LC_ENCRYPTION_INFO_64) {
// save crypt cmd
crypt = curloc;
} else if (lcmd->cmd == LC_SEGMENT_64) {
struct segment_command_64 *seg = curloc;
if (seg->fileoff == 0 && seg->filesize != 0) {
header_size = seg->vmsize;
tseg = curloc;
}
}
if(i == mach->ncmds-1){
protector_cmd = curloc;
}
curloc += lcmd->cmdsize;
}
kern_return_t err;
// make __TEXT temporarily writable
err = vm_protect(mach_task_self(), (vm_address_t)mach, (vm_size_t)header_size, false, VM_PROT_ALL);
if (err != KERN_SUCCESS) exit(1);
// modify the load commands
// change protection of __TEXT segment
tseg->maxprot = tseg->initprot = VM_PROT_READ | VM_PROT_EXECUTE;
// change cryptid
crypt->cryptid = 1;
There's no point in changing the load command. The load commands were already processed when the program was loaded (which must be before this code of yours can run). They have no further effect on the protection of pages.
You're apparently already aware of the vm_protect() function. So why aren't you using that to make the text segment itself writable rather than trying to make the load commands writable?
And it's surely simpler to use getsegmentdata() to locate the segment in memory than looking at the load commands (to which you'd have to add the slide).
Beyond that, I would be surprised if iOS lets you do that. There's a general prohibition against run-time modifiable code (with very narrow exceptions).

Why is RB interrupt routine running twice?

I have some code below that has a slight bug that I don't know how to fix. Essentially what is happening is my high ISR is running twice after the the flag is set. It only runs twice and is consistent. The subroutine should run only once because the flag is set when the input on RB changes, and the routine runs twice after one change to RB's input. The testing was conducted in MPLAB v8.6 using the workbook feature.
#include <p18f4550.h>
#include <stdio.h>
void init(void)
{
RCONbits.IPEN =1; //allows priority
INTCONbits.GIE = 1; //allows interrupts
INTCONbits.PEIE = 1; //allows peripheral interrupts
INTCONbits.RBIF = 0; //sets flag to not on
INTCONbits.RBIE = 1; //enables RB interrupts
INTCON2bits.RBPU = 1; //enable pull up resistors
INTCON2bits.RBIP = 1; //RB interrupts is high priority
PORTB = 0x00;
TRISBbits.RB7 = 1; //enable RB7 as an input so we can throw interrupts when it changes.
}
#pragma code
#pragma interrupt high_isr
void high_isr(void)
{
if(INTCONbits.RBIF == 1)
{
INTCONbits.RBIF = 0;
//stuff
}
}
#pragma code
#pragma code high_isr_entry = 0x08
void high_isr_entry(void)
{_asm goto high_isr _endasm}
void main(void)
{
init();
while(1);
}
The RB7 interrupt flag is set based on a compare of the last latched value and the current state of the pin. In the datasheet it says "The pins are compared with the old value latched on the last read of PORTB. The 'mismatch' outputs of RB7:RB4 are ORed together to generate the RB Port Change Interrupt with Flag bit."
To clear the mismatch condition the datasheet goes on to say "Any read or write of PORTB (except with the
MOVFF (ANY), PORTB instruction). This will end the mismatch condition."
You then wait one Tcy (execute a nop instruction) and then clear the flag. This is documented on page 116 of the datasheet.
So the simplest fix in this scenario is in the interrupt routine declare a dummy variable and set it to RB7 like this:
#pragma interrupt high_isr
void high_isr(void)
{
unsigned short dummy;
if(INTCONbits.RBIF == 1)
{
dummy = PORTBbits.RB7; // Perform read before clearing flag
Nop();
INTCONbits.RBIF = 0;
// rest of your routine here
// ...

Resources