Skip to content

Commit

Permalink
Enable shell-like glob escaping in %files
Browse files Browse the repository at this point in the history
This was already partially implemented using rpmIsGlob() which
interprets the backslash as an escape character, we just need to make
sure any such characters are discarded as soon as they've been consumed,
i.e. before the file name is passed to lstat(2) via addFile().

Support for literal (i.e. escaped) backslash is included.

Note that, while rpmGlob() understands escapes too, they're only
applicable to spaces and quotes during string tokenization, not to
globs, and changing its behavior would break the API, so we need to
handle glob escapes separately.  For this reason, we also need to have
an rpmIsGlob() check when processing special directories like %doc, so
add that.

Fixes: rpm-software-management#1749
  • Loading branch information
dmnks committed Apr 20, 2022
1 parent 4f34fa9 commit b5bd313
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 6 deletions.
22 changes: 17 additions & 5 deletions build/files.c
Original file line number Diff line number Diff line change
Expand Up @@ -2152,13 +2152,14 @@ static int generateBuildIDs(FileList fl, ARGV_t *files)
* Add a file to a binary package.
* @param pkg
* @param fl package file tree walk data
* @param fileName file to add
* @param fn file to add
* @return RPMRC_OK on success
*/
static rpmRC processBinaryFile(Package pkg, FileList fl, const char * fileName)
static rpmRC processBinaryFile(Package pkg, FileList fl, const char *fn)
{
int quote = 1; /* XXX permit quoted glob characters. */
int doGlob;
char *fileName = xstrdup(fn);
char *diskPath = NULL;
rpmRC rc = RPMRC_OK;
size_t fnlen = strlen(fileName);
Expand All @@ -2168,7 +2169,8 @@ static rpmRC processBinaryFile(Package pkg, FileList fl, const char * fileName)
if (trailing_slash && !fl->cur.isDir)
fl->cur.isDir = -1;

doGlob = rpmIsGlob(fileName, quote);
if (!(doGlob = rpmIsGlob(fileName, quote)))
rpmUnescape(fileName, NULL);

/* Check that file starts with leading "/" */
if (*fileName != '/') {
Expand Down Expand Up @@ -2220,6 +2222,7 @@ static rpmRC processBinaryFile(Package pkg, FileList fl, const char * fileName)
}

exit:
free(fileName);
free(diskPath);
if (rc) {
fl->processingFailed = 1;
Expand Down Expand Up @@ -2416,7 +2419,7 @@ static void processSpecialDir(rpmSpec spec, Package pkg, FileList fl,
fi = 0;
while (*files != NULL) {
char *origfile = rpmGenPath(basepath, *files, NULL);
char *eorigfile = rpmEscapeSpaces(origfile);
char *eorigfile = NULL;
ARGV_t globFiles;
int globFilesCount, i;
char *newfile;
Expand All @@ -2426,7 +2429,17 @@ static void processSpecialDir(rpmSpec spec, Package pkg, FileList fl,
copyFileEntry(&sd->entries[fi].curEntry, &fl->cur);
copyFileEntry(&sd->entries[fi].defEntry, &fl->def);
fi++;
files++;

if (!rpmIsGlob(origfile, 1)) {
rasprintf(&newfile, "%s/%s", sd->dirname, basename(origfile));
processBinaryFile(pkg, fl, newfile);
free(newfile);
free(origfile);
continue;
}

eorigfile = rpmEscapeSpaces(origfile);
if (rpmGlob(eorigfile, &globFilesCount, &globFiles) == 0) {
for (i = 0; i < globFilesCount; i++) {
rasprintf(&newfile, "%s/%s", sd->dirname, basename(globFiles[i]));
Expand All @@ -2440,7 +2453,6 @@ static void processSpecialDir(rpmSpec spec, Package pkg, FileList fl,
}
free(eorigfile);
free(origfile);
files++;
}
free(basepath);

Expand Down
7 changes: 7 additions & 0 deletions include/rpm/rpmfileutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ int rpmGlob(const char * patterns, int * argcPtr, ARGV_t * argvPtr);
*/
char * rpmEscapeSpaces(const char * s);

/** \ingroup rpmfileutil
* Unescape each char listed in accept by removing a backslash preceding it.
* @param s string
* @param accept chars to escape (NULL for all)
*/
void rpmUnescape(char *s, const char *accept);

/** \ingroup rpmfileutil
* Return type of compression used in file.
* @param file name of file
Expand Down
16 changes: 16 additions & 0 deletions rpmio/rpmfileutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,22 @@ char * rpmEscapeSpaces(const char * s)
return t;
}

void rpmUnescape(char *s, const char *accept)
{
char *p, *q;
int esc = 0;
p = q = s;
while (*q != '\0') {
*p = *q++;
esc = (*p == '\\') && \
(accept == NULL || ((*q != '\0') && strchr(accept, *q))) && \
!esc;
if (!esc)
p++;
}
*p = '\0';
}

int rpmFileHasSuffix(const char *path, const char *suffix)
{
size_t plen = strlen(path);
Expand Down
3 changes: 2 additions & 1 deletion tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ EXTRA_DIST += data/SPECS/hello2-suid.spec
EXTRA_DIST += data/SPECS/hello-g3.spec
EXTRA_DIST += data/SPECS/foo.spec
EXTRA_DIST += data/SPECS/globtest.spec
EXTRA_DIST += data/SPECS/globesctest.spec
EXTRA_DIST += data/SPECS/versiontest.spec
EXTRA_DIST += data/SPECS/conflicttest.spec
EXTRA_DIST += data/SPECS/configtest.spec
Expand Down Expand Up @@ -192,7 +193,7 @@ populate_testing: $(check_DATA)
for d in dev etc magic tmp var; do if [ ! -d testing/$${d} ]; then mkdir testing/$${d}; fi; done
for node in urandom stdin stderr stdout null full; do ln -s /dev/$${node} testing/dev/$${node}; done
for cf in hosts resolv.conf passwd shadow group gshadow mtab ; do [ -f /etc/$${cf} ] && ln -s /etc/$${cf} testing/etc/$${cf}; done
for prog in gzip cat patch tar sh ln chmod rm mkdir uname grep sed find file ionice mktemp nice cut sort diff touch install wc coreutils xargs; do p=`which $${prog}`; if [ "$${p}" != "" ]; then ln -s $${p} testing/$(bindir)/; fi; done
for prog in gzip cat cp patch tar sh ln chmod rm mkdir uname grep sed find file ionice mktemp nice cut sort diff touch install wc coreutils xargs; do p=`which $${prog}`; if [ "$${p}" != "" ]; then ln -s $${p} testing/$(bindir)/; fi; done
for d in /proc /sys /selinux /etc/selinux; do if [ -d $${d} ]; then ln -s $${d} testing/$${d}; fi; done
(cd testing/magic && file -C)
chmod -R u-w testing/
Expand Down
68 changes: 68 additions & 0 deletions tests/data/SPECS/globesctest.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# We need to hardcode the install prefix so that we can compare the %%doc
# filenames in the resulting package (with "rpm -qpl") against a static list in
# tests/rpmbuild.at.
%global _prefix /opt

Name: globesctest
Version: 1.0
Release: 1
Summary: Testing file glob escape behavior
Group: Testing
License: GPL
BuildArch: noarch

%description
%{summary}.


%build
touch 'foo[bar]' bar baz 'foo bar'

%install
mkdir -p %{buildroot}/opt

# Glob escaping
touch '%{buildroot}/opt/foo[bar]'
touch '%{buildroot}/opt/foo[bar baz]'
touch '%{buildroot}/opt/foo\[bar\]'
touch '%{buildroot}/opt/foo*'
touch '%{buildroot}/opt/foo\bar'
touch %{buildroot}/opt/foo\\
touch '%{buildroot}/opt/foo?bar'

# Regression checks
touch '%{buildroot}/opt/foo-bar1'
touch '%{buildroot}/opt/foo-bar2'
touch '%{buildroot}/opt/fooxbarybaz'
touch "%{buildroot}/opt/foo'baz"
touch '%{buildroot}/opt/foobar'
touch '%{buildroot}/opt/foobaz'
touch '%{buildroot}/opt/foobara'
touch '%{buildroot}/opt/foobarb'
touch '%{buildroot}/opt/foobaza'
touch '%{buildroot}/opt/foobazb'
touch '%{buildroot}/opt/foobaya'
touch '%{buildroot}/opt/foobayb'
touch '%{buildroot}/opt/foobawa'
touch '%{buildroot}/opt/foobawb'

%files

%doc foo\[bar\] ba* "foo bar"

# Glob escaping
/opt/foo\[bar\]
"/opt/foo\[bar baz\]"
/opt/foo\\\[bar\\\]
/opt/foo\*
/opt/foo\\bar
/opt/foo\\
/opt/foo\?bar

# Regression checks
/opt/foo-bar*
/opt/foo?bar?baz
/opt/foo'baz
/opt/foo{bar,baz}
/opt/foo{bar{a,b},baz{a,b}}
/opt/foo{bay*,baw*}
40 changes: 40 additions & 0 deletions tests/rpmbuild.at
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,46 @@ warning: absolute symlink: /opt/globtest/linkgood -> /opt/globtest/zab
])
AT_CLEANUP

AT_SETUP([rpmbuild glob escape])
AT_KEYWORDS([build])
AT_CHECK([
RPMDB_INIT

runroot rpmbuild -bb --quiet /data/SPECS/globesctest.spec
runroot rpm -qpl /build/RPMS/noarch/globesctest-1.0-1.noarch.rpm
],
[0],
[/opt/foo'baz
/opt/foo*
/opt/foo-bar1
/opt/foo-bar2
/opt/foo?bar
/opt/foo[[bar baz]]
/opt/foo[[bar]]
/opt/foo\
/opt/foo\[[bar\]]
/opt/foo\bar
/opt/foobar
/opt/foobara
/opt/foobarb
/opt/foobawa
/opt/foobawb
/opt/foobaya
/opt/foobayb
/opt/foobaz
/opt/foobaza
/opt/foobazb
/opt/fooxbarybaz
/opt/share/doc/globesctest-1.0
/opt/share/doc/globesctest-1.0/bar
/opt/share/doc/globesctest-1.0/baz
/opt/share/doc/globesctest-1.0/foo bar
/opt/share/doc/globesctest-1.0/foo[[bar]]
],
[],
)
AT_CLEANUP

AT_SETUP([rpmbuild prefixpostfix])
AT_KEYWORDS([build])
AT_CHECK([
Expand Down

0 comments on commit b5bd313

Please sign in to comment.