Skip to content

Commit

Permalink
Implement template addition for replacing keys in profile files
Browse files Browse the repository at this point in the history
Implement template addition to pass templates as key value pairs as cmd
line parameters to replace the keys in read profile file lines to allow
more customization and flexibility. This adds a new file called
template.c which contains all the functionality.

Motivation for this is to have the possibility to create profile files
where a specific key exists that can be customized per application that
us being run with firejail. For example, application name can be used in
a D-Bus name that is requested to be owned to avoid collision with other
applications requiring the same base name. This can be passed directly
then to firejail as a cmd line parameter when starting the application.

All templates are to be given via cmd line parameters in format:
 --template=KEY:VALUE

The keys and values are stored in a single linked list within template.c,
which is free'd when the keys in all read profile file (including
included profiles) lines have been replaced.

Each key can exist only once, existing hardcoded macros in addition to
XDG cannot be overwritten. In any of these is violated firejail exits.
Key cannot start with a digit and must contain alphanumeric chars only.

Each value must conform to following rules:
 - length is < 255 (D-Bus name length)
 - can contain alphabetical (a-zA-Z), integer (0-9) and '_./' chars but
   no '..'

In order to use the same DBUS_MAX_NAME_LENGTH it is moved from dbus.c to
firejail.h.

When processing the profile file lines the template keys are expected to
be written as other macros, ${TEMPLATE_KEY}. Template cannot be in the
beginning of the line. If the read line contains other internal macros
they are not replaced as they are processed later with more strict and
specific checks. It is known that using strtok_r() and doing the
tokenization in two steps, first by '$' and then by '{}' invalid
definitions such as ${{TEMPLATE_KEY2}} will pass the checks. The process
of replacing the keys can be described as follows to ease the
understanding of the code:

1. "whitelist ${HOME}/${key1}/path/to/${key2}.somewhere" tokens are:
    a: whitelist
    b: {HOME}/
    c: {key1}/path/to/
    d: {key2}.somewhere
2. Keys in the first token 'a' are ignored, it is the start of new str
3. Tokens 'b', 'c' and 'd' are passed to process_key_value
4. Each of the template keys are replaced with corresponding values, as
${HOME} is internal macro it is not replaced but added as is. Only the
first items in tokens, 'key1' and 'key2' are considered as proper keys to
have the values replaced, the remains are just added to the str.
5. Resulting string would be then:
   "whitelist ${HOME}/value1/path/to/value2.somewhere"

In order to avoid unnecessary duplication of each read profile line the
line is first checked to have at least one template key. If the template
key is not found firejail will exit with an error.
  • Loading branch information
LaakkonenJussi committed May 19, 2021
1 parent 9fbc787 commit af73b1e
Show file tree
Hide file tree
Showing 5 changed files with 545 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/firejail/dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
#define DBUS_USER_DIR_FORMAT RUN_FIREJAIL_DBUS_DIR "/%d"
#define DBUS_USER_PROXY_SOCKET_FORMAT DBUS_USER_DIR_FORMAT "/%d-user"
#define DBUS_SYSTEM_PROXY_SOCKET_FORMAT DBUS_USER_DIR_FORMAT "/%d-system"
#define DBUS_MAX_NAME_LENGTH 255
// moved to firejail.h - #define DBUS_MAX_NAME_LENGTH 255
// moved to include/common.h - #define XDG_DBUS_PROXY_PATH "/usr/bin/xdg-dbus-proxy"

static pid_t dbus_proxy_pid = 0;
Expand Down Expand Up @@ -561,4 +561,4 @@ void dbus_apply_policy(void) {

fwarning("An abstract unix socket for session D-BUS might still be available. Use --net or remove unix from --protocol set.\n");
}
#endif // HAVE_DBUSPROXY
#endif // HAVE_DBUSPROXY
8 changes: 8 additions & 0 deletions src/firejail/firejail.h
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,8 @@ void set_x11_run_file(pid_t pid, int display);
void set_profile_run_file(pid_t pid, const char *fname);

// dbus.c
#define DBUS_MAX_NAME_LENGTH 255

int dbus_check_name(const char *name);
int dbus_check_call_rule(const char *name);
void dbus_check_profile(void);
Expand All @@ -881,4 +883,10 @@ void dhcp_start(void);
// selinux.c
void selinux_relabel_path(const char *path, const char *inside_path);

// template.c
void check_template(char *arg);
int template_requires_expansion(char *arg);
char *template_replace_keys(char *arg);
void template_print_all();
void template_cleanup();
#endif
11 changes: 11 additions & 0 deletions src/firejail/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2598,6 +2598,11 @@ int main(int argc, char **argv, char **envp) {
exit_err_feature("networking");
}
#endif
else if (strncmp(argv[i], "--template=", 11) == 0) {
char *arg = strdup(argv[i] + 11); // Parse key in check_template()
check_template(arg);
free(arg);
}
//*************************************
// command
//*************************************
Expand Down Expand Up @@ -2733,6 +2738,9 @@ int main(int argc, char **argv, char **envp) {
}
}

// Prints templates only if arg_debug is set
template_print_all();

profile_read_file_list();

EUID_ASSERT();
Expand Down Expand Up @@ -2852,6 +2860,9 @@ int main(int argc, char **argv, char **envp) {
}
EUID_ASSERT();

// Templates are no longer needed as profile files are read
template_cleanup();

// block X11 sockets
if (arg_x11_block)
x11_block();
Expand Down
34 changes: 34 additions & 0 deletions src/firejail/profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1778,6 +1778,40 @@ void profile_read(const char *fname) {
msg_printed = 1;
}

// Replace all template keys on line if at least one non-
// hardcoded or not internally used is found. Since templates
// can be used anywhere process the keys before include.
char *ptr_expanded;

switch (template_requires_expansion(ptr)) {
case -EINVAL:
fprintf(stderr, "Ignoring line \"%s\", as it "
"contains invalid template keys\n",
ptr);
free(ptr);
continue;
case 0:
break;
case 1:
ptr_expanded = template_replace_keys(ptr);
if (ptr_expanded == NULL) {
fprintf(stderr, "Ignoring line \"%s\"\n", ptr);
free(ptr);
continue;
}

if (arg_debug)
printf("template keys expanded: \"%s\"\n",
ptr_expanded);

free(ptr);
ptr = ptr_expanded;

break;
default:
break;
}

// process include
if (strncmp(ptr, "include ", 8) == 0 && !is_in_ignore_list(ptr)) {
include_level++;
Expand Down
Loading

0 comments on commit af73b1e

Please sign in to comment.