How to call system open from bash script - bash

I've hooked the system call to typedef int (*orig_open_f_type)(const char *__file, int __oflag, ...); and thus, whenever a file gets opened, my code gets the event before it is passed on to the system. I created a dynamic library that overrides the open call and inject this library using DYLD_INSERT_LIBRARIES - working on a Mac machine and using XCode. It is a standard step that enables me to hook calls.
Now, I have bash script in which I have some files that I want to open. I have tried xdg-open , cat, exec - but they are not triggering the system call to open the file.
How should I invoke this open call in my bash script?
Please note that I have tested my open call hook, by opening files in C code.

I believe you're running foul of Apple's SIP (System Integrity Protection) which is designed to stop people doing things like that with system-provided executables. SIP was added to Mac OS X El Capitan (10.11) and continues in macOS Sierra (10.12).
To demonstrate whether this is the problem, consider copying /bin/cat to /usr/local/bin/cat and then try hooking (running) the local copy. You might get away with it there. This 'workaround' is purely for demonstration purposes. Basically, if I'm right, SIP is Apple's way of saying "don't go messing with our software".
You can follow links from Can Mac OS X El Capitan run software compiled for Yosemite that expects libraries in /usr/gnu/lib? to find out more about SIP. Following links via What is the "rootless" feature in El Capitan, really? on Ask Different to a blog article on System Integrity Protection, it says explicitly:
Runtime protection
SIP’s protections are not limited to protecting the system from filesystem changes. There are also system calls which are now restricted in their functionality.
task_for_pid() / processor_set_tasks() fail with EPERM
Mach special ports are reset on exec(2)
dyld environment variables are ignored
DTrace probes unavailable
However, SIP does not block inspection by the developer of their own applications while they’re being developed. Xcode’s tools will continue to allow apps to be inspected and debugged during the development process.
For more details on this, I recommend taking a look at Apple’s developer documentation for SIP.
Emphasis added
Basically, this means that you won't be able to hook calls to the open() system call for Apple-supplied software installed in the system directories. You will need to rethink what you are trying to do.

Running any normal command -- like cat -- that processes a file will cause the file to be opened. You can also open a file (and immediately close it) using the shell syntax:
: < /path/to/file
If your system call hook isn't getting called, something must be wrong with your hook -- there's no way these commands are working without opening the file. Alas, you haven't explained how you implemented your hook, so we have no way of debugging that.

The file command opens the file to look at its contents.
$ file /path/to/file
I have suggested this because it eventually leads to having the system call open which can be confirmed using strace.
$ strace file /path/to/file 2>&1 | grep open
I thought one of the good things about using file is that it opens the file in read only mode. In comparison to other ideas, unlike cat, it will not have to run through the entire file, just part of it, so the time complexity using file may be constant. Unlike vim, which someone has suggested, file will return when finished and not block like a text editor would.

Related

Why does running a clang compiled executable on a network drive, hang all subsequent executions of compiled executables?

I'm perplexed by this one and not sure what's relevant so will include all context:
MacBook Pro with an M1 Pro running macOS 12.6.
Apple clang version 14.0.0, freshly installed by deleting DeveloperTools folder and running xcode-select --install.
Using zsh in Terminal.
Network share mounted using no-configuration Finder method (seems to use standard SMB, but authenticates with my Apple ID)
Network share is my home directory on a iMac with a Core i5 running macOS 11.6.8.
Update: also tried root directory and using the tmp directory, to eliminate one category of doubt. Same result.
The minimum repeatable example of the issue I've managed to find is:
Use gcc from Apple's Developer Tools to compile a “Hello World” C application (originally discovered using ghc to compile Haskell - effect is the same).
Run the compiled executable. No surprises.
cd to the mounted network drive.
Do the same thing there - compiled executable hangs! First surprise, but relatively minor.
Return to the local machine. Original compiled executable still runs fine.
Use the DeveloperTools to compile anything, including the original source - compiled executable on local machine now hangs!
I've created an asciinema recording of the MRE. You can see the key part of the transcript in this still:
I’ve tried killing processes, checking lsof, unmounting the drive, logging in and out, checking the PATH, etc. Nothing gets me back to a working state short of a reboot.
Some more troubleshooting data:
gcc -v is identical for both executables, except for -fdebug-compilation-dir (set to cwd) and the name of the object file (randomly generated).
Just performing the compilation doesn't trigger the issue - running the networked executable does.
Trawling through the voluminous Console log reveals nothing relevant.
system.log shows no entries around the time of the issue.
lsof and ps -axww show reams and reams of output that is hard to spot patterns in, but I'm pretty sure there is no significant before/after differences.
I left the hung process running on the local machine overnight, and there's no change the next day.
Have I triggered some sandboxing or security fault and am being protected from disastrous consequences? Or this some clang/llvm related quirk I'm not familiar with? Or, given that ghc using its native code generator seems to have the same result, is this a bug in the way stdout is provided to executables? I'm at a loss!
Oh boy, avoiding Apple ID authentication of the network share fixed this for me.
I forced Finder to not use it’s magic no-configuration Apple ID login method, by opening the Location in Finder, clicking the "Disconnect" button and then clicking the "Connect As..." button that appears in its place. If I choose "Registered User" and use my username and password, I can then execute exactly the same commands (since the mount name ends up being the same) and execution works without an issue. I can continue to compile and execute to my heart's content.
That the Apple ID method is being used in the first place is not obvious (in true minimal design fashion), but subtly indicated at the top of the Finder window as "Connected as ". The only obvious difference this makes, is the username shown in mount:
Apple ID:
//com.apple.idms.appleid.prd.<UUID>#<HOSTNAME>._smb._tcp.local/<SHARE> on /Volumes/<SHARE> (smbfs, nodev, nosuid, mounted by <USERNAME>)
"Registered User":
//<USERNAME>#<HOSTNAME>._smb._tcp.local/<SHARE> on /Volumes/<SHARE> (smbfs, nodev, nosuid, mounted by <USERNAME>)
Obviously something far more significant is different, given the fundamental impact, but it's not at all clear to me what that is. So at this stage, this answer is just a workaround to a nasty bug.

How can a native macOS app programmatically run a shortcut from Apple's Shortcuts app?

Given the name of a shortcut in Apple's Shortcuts app, or some other way of identifying a shortcut, how can a native macOS app run it?
This would be the equivalent of executing the following shell command:
shortcuts run "Shortcut name here"
Granted executing a shell command is a possible way of doing this, but I'm hoping that using an API function will be better since they generally allow for better control and error handling. For example, the shell command doesn't provide any easily obtained error code for the calling process when something goes wrong, but rather displays a system notification with the error code.
edit: So far searching online and Apple's docs, as well as looking at the external symbols in Apple's shortcuts command line utility, suggests there is currently no public API for this. If so then then executing a shell command is probably the only way to do this. I'll leave this question open in case this is incorrect or it eventually changes.

Scripting Bridge and Apple Mail

I'm am getting ready to attempt to implement Scripting Bridge for the first time, specifically to allow my program to construct and send emails to individual (or all) members of an opt-in email database.
Unfortunately, I'm already stuck on the first step... creating the Mail.h file.
According to Apple's documentation:
To create a header file, you need to run two command-line tools—sdef and sdp—together, with the output from one piped to the other. This is the recommended syntax:
sdef /path/to/application.app | sdp -fh --basename applicationName
However, when I attempt to execute this, I receive the following errors:
-bash: sdef: command not found
-bash: sdp: command not found
My guess is that I'm trying to execute programs that are (clearly) not installed on my system, which is a MacBook Pro running Lion (10.7.4)
A quick google search turned up an older version of sdef for v10.4, but I'm now wondering: Is this process still the recommended procedure, or is there another way I should be generating a Mail.h header file? Apple's documentation is rather vague on this point.
Any help would be appreciated.
After some additional research and experimentation, I was able to get everything working by allowing XCODE to create the header files, rather than doing it manually from the command line.
XCODE also uses the sdp and sdef commands, but had no problem accessing them. I am still not entirely certain why I could not run the commands in the bash shell, but I suspect they must be run from the root user perhaps?
In any event, here is a link to the Apple Documentation which outlines the steps I took to get everything working correctly:
https://developer.apple.com/library/mac/#samplecode/SBSystemPrefs/Listings/ReadMe_txt.html
You should be able to use sdef and sdp after installing the command line tools. These are an optional install since XCode 4.3.
http://developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/WhatsNewXcode/Articles/xcode_4_3.html#//apple_ref/doc/uid/1006-SW2

fork within Cocoa application

My problem is not the best scenario for fork(). However, this is the best func I can get.
I am working on a Firefox plugin on Mac OSX. To make it robust, I need to create a new process to run my plugin. The problem is, when I forked a new process, much like this:
if (fork() == 0) exit(other_main());
However, since the state is not cleaned, I cannot properly initialized my new process (call NSApplicationLoad etc.). Any ideas? BTW, I certainly don't want create a new binary and exec it.
In general, you need to exec() after fork() on Mac OS X.
From the fork(2) man page:
There are limits to what you can do in the child process. To be totally safe you should restrict your-self to only executing async-signal safe operations until such time as one of the exec functions is called. All APIs, including global data symbols, in any framework or library should be assumed to be unsafe after a fork() unless explicitly documented to be safe or async-signal safe. If you need to use these frameworks in the child process, you must exec. In this situation it is reasonable to exec yourself.
TN2083 also comments on this subject:
Many Mac OS X frameworks do not work reliably if you call fork but do not call exec. The only exception is the System framework and, even there, the POSIX standard places severe constraints on what you can do between a fork and an exec.
IMPORTANT: In fact, in Mac OS X 10.5 and later, Core Foundation will detect this situation and print the warning message shown in Listing 13.
Listing 13: Core Foundation complaining about fork-without-exec
The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().
Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.
fork without exec is basically entirely unsafe on OSX. You will end up with stale mach ports for example.
I'm writing the FreeWRL plugin for Firefox (Linux at the moment, Mac & Windows soon).
http://freewrl.sourceforge.net/
It's based on fork+exec to launch FreeWRL and swallow its window into Firefox.
You'll have to use a pipe to correctly handle the possible failure of fork+exec or the failure of your child process :
How to handle execvp(...) errors after fork()?
Cheers,
C

What is a "Symbolication warning"?

I've got a user reporting crashes in my Mac OS X application, and their console logs report the following:
Symbolication warning: error parsing FDE at 0x100052649 in:\n
Does anyone have any insight into what this might be? I assume that somehow the symbols have been stripped from my app in a way that gets in the way of Mac OS X's crash reporter, but I've not seen it before.
I can honestly say that I have never seen this one before. I have seen a number of other dynamic linking problems just not this one. If the user is amenable to helping you with this defect, you might want to write a shell script to enable some dynamic linking environment variables and then launch your application.
#! /bin/bash
export DYLD_PRINT_LIBRARIES=1
export DYLD_PRINT_LIBRARIES_POST_LAUNCH=1
export DYLD_PRINT_APIS=1
export DYLD_PRINT_BINDINGS=1
export DYLD_PRINT_DOFS=1
open -a Console.app > /tmp/link-log 2>&1
The output log might provide some hint as to what is going on. You could also capture the output of otool and other command line utilities to check for unexpected libraries and what not.
You might want to google Symbolication to get a better handle of what is going on here. I came across an interesting chunk of code from Darwin that points this to a dynamic symbol lookup warning. There is also a utility called Shark that may be of interest as well.
Good luck...
I just found this topic via Google because I'm having the same problem. The StarCraft installer crashes immediately. It points to /usr/libexec/oah/translate, which seems to work perfectly well. My guess is this has something to do with the fact the computer it doesn't work on runs iDeneb 1.3 (aka Mac OS X 86 for use on non-Apple hardware), whereas the computer that can run the application just fine has a genuine version of Leopard.

Resources