Skip to content

Commit

Permalink
Merge pull request #4009 from Tomin1/protocol_list_improvements
Browse files Browse the repository at this point in the history
Allow changing protocol list after initial set
  • Loading branch information
netblue30 committed Feb 26, 2021
2 parents 74a0f27 + 5ffd928 commit 5d88ee8
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 18 deletions.
3 changes: 3 additions & 0 deletions src/firejail/firejail.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,9 @@ int profile_check_line(char *ptr, int lineno, const char *fname);
// add a profile entry in cfg.profile list; use str to populate the list
void profile_add(char *str);
void profile_add_ignore(const char *str);
char *profile_list_normalize(char *list);
char *profile_list_compress(char *list);
void profile_list_augment(char **list, const char *items);

// list.c
void list(void);
Expand Down
13 changes: 4 additions & 9 deletions src/firejail/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1285,15 +1285,10 @@ int main(int argc, char **argv, char **envp) {
#endif
else if (strncmp(argv[i], "--protocol=", 11) == 0) {
if (checkcfg(CFG_SECCOMP)) {
if (cfg.protocol) {
fwarning("more than one protocol list is present, \"%s\" will be installed\n", cfg.protocol);
}
else {
// store list
cfg.protocol = strdup(argv[i] + 11);
if (!cfg.protocol)
errExit("strdup");
}
const char *add = argv[i] + 11;
profile_list_augment(&cfg.protocol, add);
if (arg_debug)
fprintf(stderr, "[option] combined protocol list: \"%s\"\n", cfg.protocol);
}
else
exit_err_feature("seccomp");
Expand Down
153 changes: 144 additions & 9 deletions src/firejail/profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -911,15 +911,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {

if (strncmp(ptr, "protocol ", 9) == 0) {
if (checkcfg(CFG_SECCOMP)) {
if (cfg.protocol) {
fwarning("more than one protocol list is present, \"%s\" will be installed\n", cfg.protocol);
return 0;
}

// store list
cfg.protocol = strdup(ptr + 9);
if (!cfg.protocol)
errExit("strdup");
const char *add = ptr + 9;
profile_list_augment(&cfg.protocol, add);
if (arg_debug)
fprintf(stderr, "[profile] combined protocol list: \"%s\"\n", cfg.protocol);
}
else
warning_feature_disabled("seccomp");
Expand Down Expand Up @@ -1773,3 +1768,143 @@ void profile_read(const char *fname) {
}
fclose(fp);
}

char *profile_list_normalize(char *list)
{
/* Remove redundant commas.
*
* As result is always shorter than original,
* in-place copying can be used.
*/
size_t i = 0;
size_t j = 0;
int c;
while (list[i] == ',')
++i;
while ((c = list[i++])) {
if (c == ',') {
while (list[i] == ',')
++i;
if (list[i] == 0)
break;
}
list[j++] = c;
}
list[j] = 0;
return list;
}

char *profile_list_compress(char *list)
{
size_t i;

/* Comma separated list is processed so that:
* "item" -> adds item to list
* "-item" -> removes item from list
* "+item" -> adds item to list
* "=item" -> clear list, add item
*
* For example:
* ,a,,,b,,,c, -> a,b,c
* a,,b,,,c,a -> a,b,c
* a,b,c,-a -> b,c
* a,b,c,-a,a -> b,c,a
* a,+b,c -> a,b,c
* a,b,=c,d -> c,d
* a,b,c,= ->
*/
profile_list_normalize(list);

/* Count items: comma count + 1 */
size_t count = 1;
for (i = 0; list[i]; ++i) {
if (list[i] == ',')
++count;
}

/* Collect items in an array */
char *in[count];
count = 0;
in[count++] = list;
for (i = 0; list[i]; ++i) {
if (list[i] != ',')
continue;
list[i] = 0;
in[count++] = list + i + 1;
}

/* Filter array: add, remove, reset, filter out duplicates */
for (i = 0; i < count; ++i) {
char *item = in[i];
assert(item);

size_t k;
switch (*item) {
case '-':
++item;
/* Do not include this item */
in[i] = 0;
/* Remove if already included */
for (k = 0; k < i; ++k) {
if (in[k] && !strcmp(in[k], item)) {
in[k] = 0;
break;
}
}
break;
case '+':
/* Allow +/- symmetry */
in[i] = ++item;
/* FALLTHRU */
default:
/* Adding empty item is a NOP */
if (!*item) {
in[i] = 0;
break;
}
/* Include item unless it is already included */
for (k = 0; k < i; ++k) {
if (in[k] && !strcmp(in[k], item)) {
in[i] = 0;
break;
}
}
break;
case '=':
in[i] = ++item;
/* Include non-empty item */
if (!*item)
in[i] = 0;
/* Remove all allready included items */
for (k = 0; k < i; ++k)
in[k] = 0;
break;
}
}

/* Copying back using in-place data works because the
* original order is retained and no item gets longer
* than what it used to be.
*/
char *pos = list;
for (i = 0; i < count; ++i) {
char *item = in[i];
if (!item)
continue;
if (pos > list)
*pos++ = ',';
while (*item)
*pos++ = *item++;
}
*pos = 0;
return list;
}

void profile_list_augment(char **list, const char *items)
{
char *tmp = 0;
if (asprintf(&tmp, "%s,%s", *list ?: "", items ?: "") < 0)
errExit("asprintf");
free(*list);
*list = profile_list_compress(tmp);
}

0 comments on commit 5d88ee8

Please sign in to comment.