-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use execl instead of popen in RADIUS NSS code to fix vulnerability. #15512
Conversation
@adyeung @seiferteric @shdasari The semgrep flagged failure appears to be a false +ve. The compiler cannot optimize that particular memset, since the target of the memset is modified inside the function, and returned from the function, and used else where. I recommend merging this patch. There are some minor enhancements (replace integer constants with macros which could be done). But, I recommend merging this patch. Please let me know if anything else needs to be done from my side. thank you |
can you check the semgrep failure? |
"%s -U -G %s -c \"%s\" -d \"/home/%s\" -m -s %s \"%s\"", | ||
USERADD, rnm->groups, unconfirmed ? buf : user, user, | ||
rnm->shell, user); | ||
memset(buf, 0, sizeof(buf)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This memset seems redundant? snprintf() Man Page: "The functions snprintf() and vsnprintf() write at most size bytes (including the terminating null byte ('\0')) to str." semgrep appears to complain about it.
Updated memset to memset_s to handle semgrep failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
semgrep run passes.
/azpw run Azure.sonic-buildimage |
/AzurePipelines run Azure.sonic-buildimage |
Azure Pipelines successfully started running 1 pipeline(s). |
@lguohan pls check if you are ok with the vulnerability fix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a couple minor comments, but otherwise looks good to me.
@@ -167,6 +168,109 @@ static void init_rnm(RADIUS_NSS_CONF_B * conf) { | |||
|
|||
} | |||
|
|||
static int user_add(const char* cmd, const char* name, char* gid, char* sec_grp, char* gecos, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of accepting cmd as first argument if you have one function for each command (user_add, user_del, user_mod)?
|
||
} else if(pid == 0) { | ||
|
||
return execl(cmd, cmd, "-G", sec_grp, "-c", name, name, NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can add log in case of execl failure.
@adyeung , i see some comments, as soon as eric sign off, i can get it merged. |
int wstatus; | ||
char cmd[64]; | ||
|
||
snprintf(cmd, 63, "%s", USERADD); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed? Or can you use USERADD etc. directly in the execl call? Secondly, looking in nss_radius_common.h (https://github.com/shdasari/sonic-buildimage/blob/radius_execl_fix/src/radius/nss/libnss-radius/nss_radius_common.h#L69) I see this:
#define USERADD "/usr/sbin/useradd"
#define USERMOD "/usr/sbin/usermod"
#define USERDEL "/usr/sbin/userdel"
...
#undef USERADD
#define USERADD "/bin/echo"
#undef USERMOD
#define USERMOD "/bin/echo"
#undef USERDEL
#define USERDEL "/bin/echo"
Why is this being done? Have you tested if it is correctly set to /usr/bin/useradd
etc. instead of /bin/echo
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes have been tested and the user is added as expected. Note that the #define code is existing code and not added as a part of this code review. We can get rid of the defines and use the command directly however.
|
||
} else { | ||
snprintf(buf, sizeof(buf), "Unconfirmed-%ld", time(NULL)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we use sizeof(buf)-1 to leave a null termination place for the buf?
…ability. (sonic-net#15512) Why I did it sonic-net#15284 fixes a case of shell escape exploit for TACACS+. This applies to RADIUS as well. RADIUS creates an unconfirmed user locally on the switch while attempting authentication. popen() is used to execute useradd,usermod and userdel commands. This exposes a vulnerability where a tactically designed username (which could contain explicit linux commands) can lead to getting executed as root. An example of such a username could be "asd";echo>remoteRCE2;#". This leads to remoteRCE2 getting created in "/". How I did it All calls to popen() used to execute useradd, usermod and userdel are replaced with fork()/execl(). How to verify it Prior to the fix, following is the behavior: [s@i vm] ssh "asd";echo>remoteRCE2;#"@1.1.1.1 asd";echo>remoteRCE2;#@1.1.1.1's password: Permission denied, please try again. On the SONiC switch, root@sonic:/# ls accton_as7816_monitor.log home lib64 remoteRCE2 sys bin host libx32 root tmp boot initrd.img media run usr cache.tgz initrd.img.old mnt sbin var dev lib opt sonic vmlinuz etc lib32 proc srv vmlinuz.old root@sonic:/# ls -l With the fix: [s@i vm] ssh "asd";echo>remoteRCE2;#"@1.1.1.1 asd";echo>remoteRCE2;#@1.1.1.1's password: Permission denied, please try again. root@sonic:/# ls accton_as7816_monitor.log etc lib mnt sbin usr bin home lib32 opt sonic var boot host lib64 proc srv vmlinuz cache.tgz initrd.img libx32 root sys vmlinuz.old dev initrd.img.old media run tmp Verified that RADIUS authentication works as expected for valid users as well.
Why I did it
#15284 fixes a case of shell escape exploit for TACACS+. This applies to RADIUS as well. RADIUS creates an unconfirmed user locally on the switch while attempting authentication. popen() is used to execute useradd,usermod and userdel commands. This exposes a vulnerability where a tactically designed username (which could contain explicit linux commands) can lead to getting executed as root.
An example of such a username could be "asd";echo>remoteRCE2;#". This leads to remoteRCE2 getting created in "/".
Work item tracking
How I did it
All calls to popen() used to execute useradd, usermod and userdel are replaced with fork()/execl().
How to verify it
Prior to the fix, following is the behavior:
[s@i vm] ssh "asd";echo>remoteRCE2;#"@1.1.1.1
asd";echo>remoteRCE2;#@1.1.1.1's password:
Permission denied, please try again.
On the SONiC switch,
root@sonic:/# ls
accton_as7816_monitor.log home lib64 remoteRCE2 sys
bin host libx32 root tmp
boot initrd.img media run usr
cache.tgz initrd.img.old mnt sbin var
dev lib opt sonic vmlinuz
etc lib32 proc srv vmlinuz.old
root@sonic:/# ls -l
With the fix:
[s@i vm] ssh "asd";echo>remoteRCE2;#"@1.1.1.1
asd";echo>remoteRCE2;#@1.1.1.1's password:
Permission denied, please try again.
root@sonic:/# ls
accton_as7816_monitor.log etc lib mnt sbin usr
bin home lib32 opt sonic var
boot host lib64 proc srv vmlinuz
cache.tgz initrd.img libx32 root sys vmlinuz.old
dev initrd.img.old media run tmp
Verified that RADIUS authentication works as expected for valid users as well.