Background on what the code is trying to achieve: "Various parameters of the new process (e.g., euid, egid, argument list, environment, filename, etc.) that are subsequently passed to other functions are, for the sake of simplicity, combined into a structure of type linux_binprm. prepare_binprm is used to supply a number of parent process values (above all, the effective UID and GID); the remaining data — the argument list — are then copied manually into the structure. Note that prepare_binprm also takes care of handling the SUID and SGID bits:"
fs/exec.c
int prepare_binprm(struct linux_binprm *bprm)
{
...
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) {
/* Set-uid? */
if (mode & S_ISUID) {
bprm->e_uid = inode->i_uid;
}
/* Set-gid? */
/*
* If setgid is set but no group execute bit then this
* is a candidate for mandatory locking, not a setgid
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
bprm->e_gid = inode->i_gid;
}
}
...
}
Here, the bitwise AND (&) is being used in the if-statement to analyze the flags. But what does this achieve? As in, what is the condition its checking and how is it evaluated?
Source: Linux Kernel Architecture
CodePudding user response:
The result of bitwise and expression a & b
is a number with value 1 at every bit that is set in both a
and b
, and value 0 at all other bits. If that result is exactly equal to b
(for example) then it must be the case that every bit that is set in b
is also set in a
. If the result is unequal to b
then there must be at least one bit set in b
that is not set in a
.
In your particular example, mode
is a file mode bitmask, S_ISGID
is a macro representing the set-group-id bit of such a mask, and S_IXGRP
is a macro representing the group-executable bit of such a mask. The condition then evaluates whether both the S_ISGID
bit and the S_IXGRP
bit are set in mode
. If a regular file has a mode for which that is the case then that file is a setgid executable.