How can I find a specific GID within proc stats using grep and PCRE

74 views Asked by At

I am trying to fix a problematic polkit rule that checks to see if the process that is asking for permission is running with specific group ID.

The way its being done in the script (not mine) is using a pcre regex to scrape the GID out of the /proc/####/status.

The original regex is written as such;

"^Groups:.+?\\\s990[\\\s\\\0]";

However when I run this snippet of code using grep -Po "^Groups:.+?\\\s990[\\\s\\\0]" /proc/2457/status I get nothing returned. After messing around with the pattern being matched I was able to determine the reason its not being matched is its expecting the Groups: line to only have one entry. Mine has 2, since the user running the process has 2 groups (990, 992).

This is what the output the regex needs to find the match in looks like.

Name:   python
Umask:  0022
State:  S (sleeping)
Tgid:   3479
Ngid:   0
Pid:    3479
PPid:   1
TracerPid:      0
Uid:    990     990     990     990
Gid:    990     990     990     990
FDSize: 128
Groups: 990 992
NStgid: 3479
NSpid:  3479
NSpgid: 3479

My problem is I am not sure how to build the right pattern to match. The issue being while on this system the GID 990 is listed first so I could just do a match anything up to the 2nd space character. What do I do about matching the same GID if its somewhere else in the line, say its the second or possibly 3 line.

My perl regex skills are rusty, is there a way to do this easily? I don't think I could do this by tokenizing the match since grep is just providing a true or false reply.

Here is the snippet from the polkit rules I am working with.

        var regex = "^Groups:.+?\\\s990[\\\s\\\0]";;
        var cmdpath = "/proc/" + subject.pid.toString() + "/status";

        try {
            polkit.spawn(["grep", "-Po", regex, cmdpath]);
            return polkit.Result.YES;
        } catch (error) {
            return polkit.Result.NOT_HANDLED;
        }

2

There are 2 answers

0
The fourth bird On

There seems to be only digits and spaces following Groups: If you are using pcre you might use:

^Groups:\h[\h\d]*\b990\b

Explanation

  • ^ Start of string
  • Groups:\h Match Groups: followed by a horizontal whitespace char
  • [\h\d]* Match optional horizontal whitespace chars or digitgs
  • \b990\b Match 990 between word boundaries

See a regex101 demo.

Example using grep with -P for Perl-compatible regular expressions:

grep -P "^Groups:\h[\h\d]*\b990\b" file
1
Julio On

Any chance you are adding an extra backslash to the regex?

Besides that, you may want to use this regex:

^Groups:.*?\s990\b

See https://regex101.com/r/XkpzGF/1

echo "Groups: 990 991 992" | grep -P "^Groups:.*?\\s990\b"
Groups: 990 991 992
echo "Groups: 991 990 992" | grep -P "^Groups:.*?\\s990\b"
Groups: 991 990 992
echo "Groups: 991 992 990" | grep -P "^Groups:.*?\\s990\b"
Groups: 991 992 990

I think it is simpler to use a bareword at the end instead of the character class.

Also, if you plan to match the space before the s990, the quantifier should be changed from + to *, If not, even if the quantifier is lazy, it will match at least one character, consumpting the space, and thus making the regex unable to match the following mandatory space \s