aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@protonmail.com>2021-02-26 07:06:39 -0500
committerLibravatar GitHub <noreply@github.com>2021-02-26 07:06:39 -0500
commit5d88ee8957dc38a52c36f71b91c786dbec9d4ec9 (patch)
tree4b8058048ba99de070f46af382dd45b98820d476
parentMerge pull request #4010 from Tomin1/mkdir_and_mkfile_options (diff)
parentAllow changing "protocol" list after initial set (diff)
downloadfirejail-5d88ee8957dc38a52c36f71b91c786dbec9d4ec9.tar.gz
firejail-5d88ee8957dc38a52c36f71b91c786dbec9d4ec9.tar.zst
firejail-5d88ee8957dc38a52c36f71b91c786dbec9d4ec9.zip
Merge pull request #4009 from Tomin1/protocol_list_improvements
Allow changing protocol list after initial set
-rw-r--r--src/firejail/firejail.h3
-rw-r--r--src/firejail/main.c13
-rw-r--r--src/firejail/profile.c153
3 files changed, 151 insertions, 18 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 36340ff2c..c8080f778 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -451,6 +451,9 @@ int profile_check_line(char *ptr, int lineno, const char *fname);
451// add a profile entry in cfg.profile list; use str to populate the list 451// add a profile entry in cfg.profile list; use str to populate the list
452void profile_add(char *str); 452void profile_add(char *str);
453void profile_add_ignore(const char *str); 453void profile_add_ignore(const char *str);
454char *profile_list_normalize(char *list);
455char *profile_list_compress(char *list);
456void profile_list_augment(char **list, const char *items);
454 457
455// list.c 458// list.c
456void list(void); 459void list(void);
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 3c8667829..9b4f2bc60 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -1285,15 +1285,10 @@ int main(int argc, char **argv, char **envp) {
1285#endif 1285#endif
1286 else if (strncmp(argv[i], "--protocol=", 11) == 0) { 1286 else if (strncmp(argv[i], "--protocol=", 11) == 0) {
1287 if (checkcfg(CFG_SECCOMP)) { 1287 if (checkcfg(CFG_SECCOMP)) {
1288 if (cfg.protocol) { 1288 const char *add = argv[i] + 11;
1289 fwarning("more than one protocol list is present, \"%s\" will be installed\n", cfg.protocol); 1289 profile_list_augment(&cfg.protocol, add);
1290 } 1290 if (arg_debug)
1291 else { 1291 fprintf(stderr, "[option] combined protocol list: \"%s\"\n", cfg.protocol);
1292 // store list
1293 cfg.protocol = strdup(argv[i] + 11);
1294 if (!cfg.protocol)
1295 errExit("strdup");
1296 }
1297 } 1292 }
1298 else 1293 else
1299 exit_err_feature("seccomp"); 1294 exit_err_feature("seccomp");
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 9339228f4..f3266c23e 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -911,15 +911,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
911 911
912 if (strncmp(ptr, "protocol ", 9) == 0) { 912 if (strncmp(ptr, "protocol ", 9) == 0) {
913 if (checkcfg(CFG_SECCOMP)) { 913 if (checkcfg(CFG_SECCOMP)) {
914 if (cfg.protocol) { 914 const char *add = ptr + 9;
915 fwarning("more than one protocol list is present, \"%s\" will be installed\n", cfg.protocol); 915 profile_list_augment(&cfg.protocol, add);
916 return 0; 916 if (arg_debug)
917 } 917 fprintf(stderr, "[profile] combined protocol list: \"%s\"\n", cfg.protocol);
918
919 // store list
920 cfg.protocol = strdup(ptr + 9);
921 if (!cfg.protocol)
922 errExit("strdup");
923 } 918 }
924 else 919 else
925 warning_feature_disabled("seccomp"); 920 warning_feature_disabled("seccomp");
@@ -1773,3 +1768,143 @@ void profile_read(const char *fname) {
1773 } 1768 }
1774 fclose(fp); 1769 fclose(fp);
1775} 1770}
1771
1772char *profile_list_normalize(char *list)
1773{
1774 /* Remove redundant commas.
1775 *
1776 * As result is always shorter than original,
1777 * in-place copying can be used.
1778 */
1779 size_t i = 0;
1780 size_t j = 0;
1781 int c;
1782 while (list[i] == ',')
1783 ++i;
1784 while ((c = list[i++])) {
1785 if (c == ',') {
1786 while (list[i] == ',')
1787 ++i;
1788 if (list[i] == 0)
1789 break;
1790 }
1791 list[j++] = c;
1792 }
1793 list[j] = 0;
1794 return list;
1795}
1796
1797char *profile_list_compress(char *list)
1798{
1799 size_t i;
1800
1801 /* Comma separated list is processed so that:
1802 * "item" -> adds item to list
1803 * "-item" -> removes item from list
1804 * "+item" -> adds item to list
1805 * "=item" -> clear list, add item
1806 *
1807 * For example:
1808 * ,a,,,b,,,c, -> a,b,c
1809 * a,,b,,,c,a -> a,b,c
1810 * a,b,c,-a -> b,c
1811 * a,b,c,-a,a -> b,c,a
1812 * a,+b,c -> a,b,c
1813 * a,b,=c,d -> c,d
1814 * a,b,c,= ->
1815 */
1816 profile_list_normalize(list);
1817
1818 /* Count items: comma count + 1 */
1819 size_t count = 1;
1820 for (i = 0; list[i]; ++i) {
1821 if (list[i] == ',')
1822 ++count;
1823 }
1824
1825 /* Collect items in an array */
1826 char *in[count];
1827 count = 0;
1828 in[count++] = list;
1829 for (i = 0; list[i]; ++i) {
1830 if (list[i] != ',')
1831 continue;
1832 list[i] = 0;
1833 in[count++] = list + i + 1;
1834 }
1835
1836 /* Filter array: add, remove, reset, filter out duplicates */
1837 for (i = 0; i < count; ++i) {
1838 char *item = in[i];
1839 assert(item);
1840
1841 size_t k;
1842 switch (*item) {
1843 case '-':
1844 ++item;
1845 /* Do not include this item */
1846 in[i] = 0;
1847 /* Remove if already included */
1848 for (k = 0; k < i; ++k) {
1849 if (in[k] && !strcmp(in[k], item)) {
1850 in[k] = 0;
1851 break;
1852 }
1853 }
1854 break;
1855 case '+':
1856 /* Allow +/- symmetry */
1857 in[i] = ++item;
1858 /* FALLTHRU */
1859 default:
1860 /* Adding empty item is a NOP */
1861 if (!*item) {
1862 in[i] = 0;
1863 break;
1864 }
1865 /* Include item unless it is already included */
1866 for (k = 0; k < i; ++k) {
1867 if (in[k] && !strcmp(in[k], item)) {
1868 in[i] = 0;
1869 break;
1870 }
1871 }
1872 break;
1873 case '=':
1874 in[i] = ++item;
1875 /* Include non-empty item */
1876 if (!*item)
1877 in[i] = 0;
1878 /* Remove all allready included items */
1879 for (k = 0; k < i; ++k)
1880 in[k] = 0;
1881 break;
1882 }
1883 }
1884
1885 /* Copying back using in-place data works because the
1886 * original order is retained and no item gets longer
1887 * than what it used to be.
1888 */
1889 char *pos = list;
1890 for (i = 0; i < count; ++i) {
1891 char *item = in[i];
1892 if (!item)
1893 continue;
1894 if (pos > list)
1895 *pos++ = ',';
1896 while (*item)
1897 *pos++ = *item++;
1898 }
1899 *pos = 0;
1900 return list;
1901}
1902
1903void profile_list_augment(char **list, const char *items)
1904{
1905 char *tmp = 0;
1906 if (asprintf(&tmp, "%s,%s", *list ?: "", items ?: "") < 0)
1907 errExit("asprintf");
1908 free(*list);
1909 *list = profile_list_compress(tmp);
1910}