how to fix "Operation not permitted" when i use launchctl in macos catalina

Question:

I’m setting up a launchctl server to run a python file regularly. So I write a.plist file , auto.sh file and it works well.
However, after I installed Macos Catalina, it failed.
I write “ls -l” in auto.sh to check file permission,
log shows that:

ls: .: Operation not permitted
python3: can't open file 'auto.py': [Errno 1] Operation not permitted 

How can I do to fix it? Thank you so much.

here is my code:

auto.sh:

#!/bin/bash
. ~/.bash_profile
conda activate base
cd /Users/gassy/Documents/
ls -l
python3 auto.py

I put such .plist file in /Users/gassy/Library/LaunchAgents/com.gassy.fangzhou.plist

    ...
    <key>Program</key>
    <string>/Users/gassy/auto/launch.sh</string>
    ...
Asked By: Lucas

||

Answers:

I think the problem you have is not with Python, but with the file permissions on auto.py or the path leading up to it. What user account is used to run the script? Does that user have the necessary permissions on both those executables and the parent directory? Reason I suspect directory permissions is that ls is failing along with auto.py.

You might have some luck if you move everything out of /Users/gassy/Documents and to another location, perhaps under /opt or /var or similar, and then make sure that the permissions are sane. I know that macos treats some of those directores under /Users/<user> special, sometimes in a less-than-helpful way…

Answered By: Z4-tier

Change the permissions of the file by using the chmod command in your bash script, before running python3 auto.py.

chmox +x auto.py should do, however I would recommend you to read more about it and be specific on your use case.

Answered By: Apoorv Goyal

Finally figure it out…

It’s a problem related to Catalina new permission system, the /bin/bash need to have the [full disk access].

enter image description here

Answered By: mingxin

A modification of @mingxin’s solution worked for me: Basically the same steps but instead of giving full disk access to bash in Security & Privacy, give full access to python3 (which on my Big Sur macOS system is in /usr/bin).

Answered By: vegashacker

In the spirit of the principle of least privilege:

If you don’t want to give bash Full Disk Access you can create a binary wrapper.

Create a C source code file launch.c.

#include <stdlib.h>
int main(void) {
  int status = system("/path/to/launch.sh");
  int ret = WEXITSTATUS(status);
  return ret;
}

Then compile it to launch.

gcc -Wall -o launch launch.c

Grant it Full Disk Access add it to the launchd Property List File.

Answered By: Stefan Schmidt

With the help of ChatGPT, I have written a generic binary wrapper that can be used to execute other programs through it. After compiling it and granting it full disk access permissions, it is ready to use.

C source file full-disk-access.c:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char const *argv[]) {
    if (argc < 2) {
        return 0;
    }

    // The type of array length is size_t/unsigned long
    size_t len = 0;
    // ChatGPT says that i == 0 corresponds to the current program name
    for (size_t i = 1; i < argc; i++) {
        len += strlen(argv[i]);
    }
    char *input = (char *) malloc((len + argc - 1) * sizeof(char));
    // ChatGPT says that setting the first character to '' ensures that input is recognized as a string
    input[0] = '';

    for (size_t i = 1; i < argc; i++) {
        strcat(input, argv[i]);
        if (i < argc - 1) {
            strcat(input, " ");
        }
    }
    printf("%s: %sn", argv[0], input);
    int status = system(input);

    free(input);
    // ChatGPT says that if the status value is less than 0, it indicates an error in system() execution, and we need to return directly.
    if (status < 0) {
        return 1;
    }
    return WEXITSTATUS(status);
}

Compile it to full-disk-access:

gcc full-disk-access.c -o full-disk-access
Answered By: ipcjs
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.