diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/firejail.h | 3 | ||||
-rw-r--r-- | src/firejail/profile.c | 140 |
2 files changed, 143 insertions, 0 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 |
452 | void profile_add(char *str); | 452 | void profile_add(char *str); |
453 | void profile_add_ignore(const char *str); | 453 | void profile_add_ignore(const char *str); |
454 | char *profile_list_normalize(char *list); | ||
455 | char *profile_list_compress(char *list); | ||
456 | void profile_list_augment(char **list, const char *items); | ||
454 | 457 | ||
455 | // list.c | 458 | // list.c |
456 | void list(void); | 459 | void list(void); |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 9339228f4..7b5fbfedf 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -1773,3 +1773,143 @@ void profile_read(const char *fname) { | |||
1773 | } | 1773 | } |
1774 | fclose(fp); | 1774 | fclose(fp); |
1775 | } | 1775 | } |
1776 | |||
1777 | char *profile_list_normalize(char *list) | ||
1778 | { | ||
1779 | /* Remove redundant commas. | ||
1780 | * | ||
1781 | * As result is always shorter than original, | ||
1782 | * in-place copying can be used. | ||
1783 | */ | ||
1784 | size_t i = 0; | ||
1785 | size_t j = 0; | ||
1786 | int c; | ||
1787 | while (list[i] == ',') | ||
1788 | ++i; | ||
1789 | while ((c = list[i++])) { | ||
1790 | if (c == ',') { | ||
1791 | while (list[i] == ',') | ||
1792 | ++i; | ||
1793 | if (list[i] == 0) | ||
1794 | break; | ||
1795 | } | ||
1796 | list[j++] = c; | ||
1797 | } | ||
1798 | list[j] = 0; | ||
1799 | return list; | ||
1800 | } | ||
1801 | |||
1802 | char *profile_list_compress(char *list) | ||
1803 | { | ||
1804 | size_t i; | ||
1805 | |||
1806 | /* Comma separated list is processed so that: | ||
1807 | * "item" -> adds item to list | ||
1808 | * "-item" -> removes item from list | ||
1809 | * "+item" -> adds item to list | ||
1810 | * "=item" -> clear list, add item | ||
1811 | * | ||
1812 | * For example: | ||
1813 | * ,a,,,b,,,c, -> a,b,c | ||
1814 | * a,,b,,,c,a -> a,b,c | ||
1815 | * a,b,c,-a -> b,c | ||
1816 | * a,b,c,-a,a -> b,c,a | ||
1817 | * a,+b,c -> a,b,c | ||
1818 | * a,b,=c,d -> c,d | ||
1819 | * a,b,c,= -> | ||
1820 | */ | ||
1821 | profile_list_normalize(list); | ||
1822 | |||
1823 | /* Count items: comma count + 1 */ | ||
1824 | size_t count = 1; | ||
1825 | for (i = 0; list[i]; ++i) { | ||
1826 | if (list[i] == ',') | ||
1827 | ++count; | ||
1828 | } | ||
1829 | |||
1830 | /* Collect items in an array */ | ||
1831 | char *in[count]; | ||
1832 | count = 0; | ||
1833 | in[count++] = list; | ||
1834 | for (i = 0; list[i]; ++i) { | ||
1835 | if (list[i] != ',') | ||
1836 | continue; | ||
1837 | list[i] = 0; | ||
1838 | in[count++] = list + i + 1; | ||
1839 | } | ||
1840 | |||
1841 | /* Filter array: add, remove, reset, filter out duplicates */ | ||
1842 | for (i = 0; i < count; ++i) { | ||
1843 | char *item = in[i]; | ||
1844 | assert(item); | ||
1845 | |||
1846 | size_t k; | ||
1847 | switch (*item) { | ||
1848 | case '-': | ||
1849 | ++item; | ||
1850 | /* Do not include this item */ | ||
1851 | in[i] = 0; | ||
1852 | /* Remove if already included */ | ||
1853 | for (k = 0; k < i; ++k) { | ||
1854 | if (in[k] && !strcmp(in[k], item)) { | ||
1855 | in[k] = 0; | ||
1856 | break; | ||
1857 | } | ||
1858 | } | ||
1859 | break; | ||
1860 | case '+': | ||
1861 | /* Allow +/- symmetry */ | ||
1862 | in[i] = ++item; | ||
1863 | /* FALLTHRU */ | ||
1864 | default: | ||
1865 | /* Adding empty item is a NOP */ | ||
1866 | if (!*item) { | ||
1867 | in[i] = 0; | ||
1868 | break; | ||
1869 | } | ||
1870 | /* Include item unless it is already included */ | ||
1871 | for (k = 0; k < i; ++k) { | ||
1872 | if (in[k] && !strcmp(in[k], item)) { | ||
1873 | in[i] = 0; | ||
1874 | break; | ||
1875 | } | ||
1876 | } | ||
1877 | break; | ||
1878 | case '=': | ||
1879 | in[i] = ++item; | ||
1880 | /* Include non-empty item */ | ||
1881 | if (!*item) | ||
1882 | in[i] = 0; | ||
1883 | /* Remove all allready included items */ | ||
1884 | for (k = 0; k < i; ++k) | ||
1885 | in[k] = 0; | ||
1886 | break; | ||
1887 | } | ||
1888 | } | ||
1889 | |||
1890 | /* Copying back using in-place data works because the | ||
1891 | * original order is retained and no item gets longer | ||
1892 | * than what it used to be. | ||
1893 | */ | ||
1894 | char *pos = list; | ||
1895 | for (i = 0; i < count; ++i) { | ||
1896 | char *item = in[i]; | ||
1897 | if (!item) | ||
1898 | continue; | ||
1899 | if (pos > list) | ||
1900 | *pos++ = ','; | ||
1901 | while (*item) | ||
1902 | *pos++ = *item++; | ||
1903 | } | ||
1904 | *pos = 0; | ||
1905 | return list; | ||
1906 | } | ||
1907 | |||
1908 | void profile_list_augment(char **list, const char *items) | ||
1909 | { | ||
1910 | char *tmp = 0; | ||
1911 | if (asprintf(&tmp, "%s,%s", *list ?: "", items ?: "") < 0) | ||
1912 | errExit("asprintf"); | ||
1913 | free(*list); | ||
1914 | *list = profile_list_compress(tmp); | ||
1915 | } | ||